Shopify + Odoo ERP Integration: The Complete Guide

Comprehensive guide to integrating Shopify with Odoo ERP — inventory sync, order management, customer data, financial reporting, and automation workflows.

E
ECOSIRE Research and Development Team
|2026年3月19日6 分钟阅读1.2k 字数|

属于我们的eCommerce Integration系列

阅读完整指南

Shopify + Odoo ERP 集成:完整指南

随着 Shopify 商店规模的扩大,Shopify 本地处理的内容与企业卓越运营实际需要的内容之间的差距成为一个重大限制。跨多个仓库的库存管理、多币种会计、Shopify 销售触发的制造订单、具有完整客户历史记录的复杂 CRM 以及自动供应商补货 - 这些都需要 ERP,而 Odoo 越来越成为中端市场电子商务企业的首选系统。

Shopify + Odoo 不是即插即用的集成。它需要仔细的架构决策,确定哪个系统拥有哪些数据、哪些数据在哪个方向同步,以及如何处理部分发货、退货处理和变体映射等边缘情况。本指南涵盖了从集成架构到特定实施模式的所有内容。

要点

  • Odoo 是库存、客户和会计的真实来源; Shopify 是电子商务交易的真实来源
  • 双向库存同步(Shopify → Odoo 用于订单,Odoo → Shopify 用于库存水平)是核心集成要求
  • 产品目录管理应位于 Odoo 中并同步到 Shopify - 而不是相反
  • 使用电子邮件作为唯一标识符在系统之间合并客户记录
  • 订单生命周期:Shopify 创建订单 → Odoo 接收订单 → Odoo 创建交货 → 履行更新 Shopify
  • 退货处理需要协调:Shopify 发起退货 → Odoo 处理收货 → 两个系统更新
  • Shopify的Webhook API提供实时订单事件; Odoo 通过连接器中间件接收这些
  • 存在直接 Odoo-Shopify 连接器(Syncee、OdooConnector),但通过 REST API 进行自定义集成可提供更多控制

了解集成架构

在实施之前,先定义各个数据域的权威体系:

数据类型权威系统同步方向频率
产品目录奥杜Odoo → Shopify关于产品变更
库存水平奥杜Odoo → Shopify实时
订单店铺主页 个人中心 关注我们 线下门店 店铺信息Shopify → Odoo实时(网络钩子)
客户记录Odoo(合并)双向(电子邮件密钥)订购
定价奥杜Odoo → Shopify关于价格变动
运费店铺主页 个人中心 关注我们 线下门店 店铺信息仅限 Shopify不适用
付款店铺主页 个人中心 关注我们 线下门店 店铺信息Shopify → Odoo(会计)关于结算
返回Shopify 发起Shopify → Odoo关于创作回归

为什么 Odoo 拥有库存

Shopify 的库存跟踪功能正常,但仅限于多仓库、多渠道运营。 Odoo 的库存模块处理:批次和序列号跟踪、多地点仓库管理、自动补货规则、制造集成(成品减少组件库存)以及条形码驱动的履行操作。 Shopify 必须反映 Odoo 的库存现实,而不是相反。

为什么 Shopify 是商务层

Shopify 的结账、付款处理、运费计算、税收和面向客户的体验都是一流的。 Odoo 的 B2C 电子商务(Odoo 网站)可以正常运行,但无法达到 Shopify 的 DTC 商务级别。最佳架构将 Shopify 作为商务界面,将 Odoo 作为运营支柱。


集成方法:连接器应用程序与自定义 API

选项 1:预构建连接器应用程序

多个 Shopify 和 Odoo 市场应用程序提供预构建的集成:

连接器方法每月费用优点缺点
扎皮特 + 奥杜中间件来自 Zapier50-200 美元快速设置定制有限,单点故障
同步会议直接连接器29-99 美元目录同步订单处理有限
OdooConnector.com专门打造200-500 美元综合需要 Odoo 专业知识
Eshop+(Odoo 应用程序)Odoo 原生社区免费Odoo 原生基本 Shopify 支持
Shopify OdooWebkul专门打造定制全生命周期复杂配置

预构建的连接器适用于:标准产品目录和订单同步,适用于简单的业务模型,无需复杂的变体结构、多个仓库或制造依赖性。

选项 2:通过 API 进行自定义集成

对于复杂的业务需求,使用 Shopify 的 REST/GraphQL API 和 Odoo 的 JSON-RPC/REST API 进行自定义集成可提供最大程度的控制和可靠性。

定制集成架构:

Shopify (Commerce Layer)
│
│ Webhooks (orders/create, orders/updated, refunds/create, inventory_levels/update)
│
▼
Integration Service (Node.js / Python middleware)
│
│ Event processing, transformation, error handling, retry logic
│
▼
Odoo (ERP Layer)
│
│ Odoo JSON-RPC API (sales orders, inventory, customers, accounting)
│
└── Inventory updates → Shopify Admin API

定制集成的技术堆栈

  • 中间件:Node.js(用于 Shopify 生态系统协调)或 Python(用于 Odoo 生态系统协调)
  • 队列:Redis 或 RabbitMQ 用于可靠的事件处理
  • 数据库:PostgreSQL 用于集成状态、幂等键、错误日志
  • 托管:AWS Lambda 或类似的 webhook 处理程序(随着 Shopify 流量峰值自动扩展)

订单同步:Shopify → Odoo

订单同步是最关键的集成路径。每个 Shopify 订单都必须创建相应的 Odoo 销售订单,以触发履行并更新财务记录。

订单事件的 Shopify Webhook 设置

// Register webhooks via Shopify API
const webhooks = [
  {
    topic: 'orders/create',
    address: 'https://your-integration.com/webhooks/shopify/orders',
    format: 'json'
  },
  {
    topic: 'orders/updated',
    address: 'https://your-integration.com/webhooks/shopify/orders/updated',
    format: 'json'
  },
  {
    topic: 'orders/fulfilled',
    address: 'https://your-integration.com/webhooks/shopify/orders/fulfilled',
    format: 'json'
  },
  {
    topic: 'refunds/create',
    address: 'https://your-integration.com/webhooks/shopify/refunds',
    format: 'json'
  }
];

将 Shopify 订单转换为 Odoo 销售订单

def shopify_order_to_odoo_sale_order(shopify_order: dict) -> dict:
    """Transform Shopify order payload to Odoo sale.order format"""

    # Find or create Odoo partner (customer)
    partner_id = find_or_create_odoo_partner(
        email=shopify_order['email'],
        name=shopify_order['customer']['first_name'] + ' ' + shopify_order['customer']['last_name'],
        phone=shopify_order['customer'].get('phone'),
        shipping_address=shopify_order['shipping_address']
    )

    # Map line items
    order_lines = []
    for item in shopify_order['line_items']:
        odoo_product_id = get_odoo_product_from_shopify_variant(
            item['variant_id']
        )
        order_lines.append({
            'product_id': odoo_product_id,
            'product_uom_qty': item['quantity'],
            'price_unit': float(item['price']),
            'name': item['name'],
            'shopify_line_id': item['id'],  # Custom field for traceability
        })

    # Add shipping as a service product line
    if float(shopify_order.get('shipping_lines', [{}])[0].get('price', 0)) > 0:
        order_lines.append({
            'product_id': SHIPPING_PRODUCT_ID,  # Configured in settings
            'product_uom_qty': 1,
            'price_unit': float(shopify_order['shipping_lines'][0]['price']),
            'name': shopify_order['shipping_lines'][0]['title'],
        })

    return {
        'partner_id': partner_id,
        'order_line': [(0, 0, line) for line in order_lines],
        'shopify_order_id': shopify_order['id'],  # Custom field
        'shopify_order_name': shopify_order['name'],  # e.g., #1001
        'note': shopify_order.get('note', ''),
        'state': 'sale',  # Confirm order automatically
    }

幂等性处理

Shopify 可能会多次传递相同的 Webhook 事件(网络重试)。您的集成必须妥善处理重复事件:

def process_shopify_order_webhook(payload: dict):
    shopify_order_id = str(payload['id'])

    # Check if already processed
    if OrderSyncLog.objects.filter(
        shopify_order_id=shopify_order_id,
        status='completed'
    ).exists():
        logger.info(f"Order {shopify_order_id} already processed, skipping")
        return

    # Process and log
    try:
        odoo_order_id = create_odoo_sale_order(payload)
        OrderSyncLog.objects.create(
            shopify_order_id=shopify_order_id,
            odoo_order_id=odoo_order_id,
            status='completed'
        )
    except Exception as e:
        OrderSyncLog.objects.create(
            shopify_order_id=shopify_order_id,
            status='failed',
            error=str(e)
        )
        raise

库存同步:Odoo → Shopify

库存水平必须实时(或接近实时)反映 Odoo 在 Shopify 中的实际情况,以防止超售。

基于触发器的库存同步

最可靠的方法是事件驱动同步:当 Odoo 中的库存发生变化(销售、采购收据、制造完成、库存调整)时,Odoo 会将更新的数量推送到 Shopify。

# In Odoo (using automated actions or override)
def _post_write_sync_to_shopify(self):
    """Called after inventory level changes in Odoo"""
    for move_line in self:
        product = move_line.product_id
        location = move_line.location_id

        if location.is_shopify_sync_location:
            shopify_variant_id = product.shopify_variant_id
            if shopify_variant_id:
                new_quantity = product.with_context(
                    location=location.id
                ).qty_available

                sync_inventory_to_shopify(
                    shopify_variant_id=shopify_variant_id,
                    quantity=int(new_quantity)
                )

def sync_inventory_to_shopify(shopify_variant_id: str, quantity: int):
    """Push inventory update to Shopify via Admin API"""
    inventory_item_id = get_inventory_item_id(shopify_variant_id)
    location_id = get_shopify_location_id()  # Primary Shopify location

    shopify.InventoryLevel.set(
        inventory_item_id=inventory_item_id,
        location_id=location_id,
        available=quantity
    )

计划库存调节

即使使用事件驱动的同步,也可以安排每日完整库存对账:

  1. 从指定的 Shopify 同步位置导出所有 Odoo 产品数量
  2. 与当前 Shopify 库存水平进行比较 3.更新任何差异(可能由于同步事件失败、手动调整而发生)
  3. 记录核对结果以供审计之用

这种协调可以防止因累积的小同步失败而导致库存漂移。


产品目录同步:Odoo → Shopify

对于在 Odoo 中管理产品目录(具有多货币定价、详细规格和复杂变体矩阵)的企业来说,将目录同步到 Shopify 可以消除手动重复输入。

产品映射架构

Odoo Product (product.template)
├── Shopify Product (via shopify_product_id field on Odoo template)
│
└── Odoo Product Variants (product.product)
    └── Shopify Variants (via shopify_variant_id field on Odoo product.product)

从 Odoo 同步到 Shopify 的内容

  • 产品名称(Odoo 的销售描述)
  • 产品描述(长 HTML 描述)
  • 图片(产品.模板图片)
  • 价格(使用配置的 Shopify 价目表)
  • SKU(Odoo 的内部参考)
  • 条形码(来自 Odoo 的 EAN/UPC)
  • 重量(用于运输计算)
  • 活动/存档状态(Odoo 产品存档时在 Shopify 中取消发布)
  • 库存(来自指定的同步位置)

不应该从 Odoo 同步到 Shopify 的内容

  • Shopify 特定的 SEO 元数据(标题标签、元描述 - 在 Shopify 中管理)
  • Shopify 产品标签(在 Shopify 中管理)
  • Shopify 集合/类别(在 Shopify 中管理)
  • Shopify 特定内容(页面构建器部分、针对 Shopify 格式化的丰富描述)

客户数据管理

同时存在于 Shopify(来自其店面帐户)和 Odoo(作为联系人/合作伙伴)的客户需要仔细合并以创建一个统一的个人资料。

使用电子邮件的重复数据删除策略

def find_or_create_odoo_partner(email: str, name: str, **kwargs) -> int:
    """Find existing Odoo partner by email or create new one"""
    existing = Partner.search([
        ('email', '=', email)
    ], limit=1)

    if existing:
        # Update with latest data from Shopify
        existing.write({
            'phone': kwargs.get('phone', existing.phone),
        })
        return existing.id
    else:
        # Create new partner
        partner = Partner.create({
            'name': name,
            'email': email,
            'phone': kwargs.get('phone'),
            'type': 'contact',
            'customer_rank': 1,
            'shopify_customer_id': kwargs.get('shopify_customer_id'),
        })
        return partner.id

Shopify 客户 ID 存储在 Odoo 中

将自定义字段 shopify_customer_id 添加到 Odoo 的 res.partner 模型。这可以实现双向查找:从 Shopify ID 查找 Odoo 合作伙伴,从 Odoo 合作伙伴查找 Shopify 客户。


履行循环:Odoo → Shopify

当 Odoo 处理交货(拣货 + 验证)时,订单即得到履行。必须通知 Shopify:

  • 将订单标记为已完成
  • 向客户发送发货确认电子邮件
  • 记录追踪号码
def sync_fulfillment_to_shopify(odoo_picking: StockPicking):
    """Called after Odoo delivery is validated"""
    shopify_order_name = odoo_picking.sale_id.shopify_order_name
    tracking_number = odoo_picking.carrier_tracking_ref

    # Find Shopify order
    shopify_orders = shopify.Order.find(name=shopify_order_name)
    if not shopify_orders:
        return

    shopify_order = shopify_orders[0]

    # Create fulfillment in Shopify
    fulfillment = shopify.Fulfillment.create({
        'order_id': shopify_order.id,
        'tracking_number': tracking_number,
        'tracking_company': odoo_picking.carrier_id.name,
        'notify_customer': True,  # Sends Shopify's shipping email
        'line_items': [
            {'id': line.shopify_line_id}
            for line in odoo_picking.sale_id.order_line
            if line.shopify_line_id
        ]
    })

会计集成:Shopify 销售 → Odoo Financials

每笔 Shopify 销售最终都必须作为已发布的销售条目出现在 Odoo 的会计模块中。

会计整合方法

选项 1 — 订单级会计:每个 Shopify 订单都会创建一张 Odoo 发票(或者 Odoo 销售订单在履行时会生成一张发票)。 Shopify 中记录的付款会触发 Odoo 中的付款注册。

选项 2 — 结算级会计:Shopify Payments 结算(每日或每周银行存款)在 Odoo 中记录为日记账分录,与银行交易进行核对。这更容易维护,但提供的统计粒度较小。

对于大多数中端市场商家来说,结算级会计(选项 2)就足够了,并且实施和维护的复杂性明显降低。

Shopify 付款数据 → Odoo 日记条目

def process_shopify_payout(payout_data: dict):
    """Create Odoo journal entry for Shopify Payments payout"""
    journal = ShopifyJournal.get_or_create()  # Shopify clearing account

    entry = AccountMove.create({
        'journal_id': journal.id,
        'date': payout_data['date'],
        'ref': f"Shopify Payout {payout_data['id']}",
        'line_ids': [
            (0, 0, {
                'account_id': SHOPIFY_CLEARING_ACCOUNT_ID,
                'credit': payout_data['amount'],
                'name': f"Shopify sales - {payout_data['period']}",
            }),
            (0, 0, {
                'account_id': SHOPIFY_FEES_ACCOUNT_ID,
                'debit': payout_data['fees'],
                'name': 'Shopify Payments fees',
            }),
            (0, 0, {
                'account_id': BANK_ACCOUNT_ID,
                'debit': payout_data['amount'] - payout_data['fees'],
                'name': f"Bank deposit - Shopify payout {payout_data['id']}",
            }),
        ]
    })
    entry.action_post()

常见问题

Shopify-Odoo 集成需要多长时间才能实施?

使用预构建连接器的基本集成(订单同步、库存同步、客户同步)需要 2-4 周的时间,包括配置、测试和数据迁移。涵盖整个生命周期(订单、库存、履行同步、退货、会计)的自定义集成需要 8-16 周,具体取决于业务复杂性。复杂的场景(多仓库、制造、多货币、多公司 Odoo)会额外增加 4-8 周的时间。持续维护预算:当 Shopify 或 Odoo 发布 API 发生更改时,集成需要更新。

我应该在 Shopify 还是 Odoo 中管理产品?

对于简单的产品目录:在 Shopify 中进行管理并手动更新 Odoo 以用于制造/采购目的。对于复杂的目录(许多变体、多货币定价、技术规格、制造 BOM):在 Odoo 中管理并同步到 Shopify。关键因素是您的产品团队实际工作的地方。如果您的销售团队位于 Shopify,则强迫他们在 Odoo 中工作会产生摩擦。如果您的运营团队在 Odoo 中管理产品以进行制造和采购,Shopify 同步是正确的方法。

集成上线后,现有 Shopify 订单会发生什么情况?

历史订单不需要迁移到 Odoo。该集成处理自上线之日起的新订单。对于历史数据(客户记录、产品目录、库存基线),在集成上线之前执行一次性数据迁移:将历史客户数据导入 Odoo,导入产品目录,并在 Odoo 中设置库存基线以匹配当前的 Shopify 数量。

如何处理 Odoo 中不存在的产品的 Shopify 订单?

这种边缘情况打破了简单的集成。构建后备方案:当 Shopify 订单包含未映射到 Odoo 产品的变体 ID 时,请在 Odoo 中使用占位符“未知产品”产品创建订单,并提醒您的集成团队。定义带有通知的错误队列:操作人员查看未映射的产品、创建 Odoo 产品并重新处理失败的订单。这比静默失败或在等待映射修复时阻止所有订单更好。

此集成可以支持多个 Shopify 商店(例如不同的市场商店)吗?

是的,但会增加复杂性。每个 Shopify 商店都是一个单独的 API 连接。一个 Odoo 实例可以接收来自多个 Shopify 商店的订单,并通过自定义字段跟踪商店来源。商店之间的库存分配需要额外的逻辑:共享库存池(Odoo 根据订单需求跨商店分配)或位置隔离库存(每个商店都有指定的 Odoo 位置)。多商店集成使测试范围和持续维护负担加倍。


后续步骤

实施良好的 Shopify-Odoo 集成可以提高运营效率:消除手动数据输入、防止超售、实现复杂的报告以及将电子商务销售与制造、采购和财务流程连接起来。

ECOSIRE 为中端市场商家构建 ShopifyOdoo ERP 集成 — 涵盖架构设计、定制开发、数据迁移、测试和持续支持。我们的集成团队已为不同产品类别的 30 多家商家实施了 Shopify-Odoo 连接。

联系我们的集成团队 设计您的 Shopify-Odoo 集成架构。

E

作者

ECOSIRE Research and Development Team

在 ECOSIRE 构建企业级数字产品。分享关于 Odoo 集成、电商自动化和 AI 驱动商业解决方案的洞见。

通过 WhatsApp 聊天