保持库存准确和最新对于任何高销量零售商来说都是至关重要的。对于 Wellcare 和 Raf Pharmacy ——这两家在卡塔尔领先的药房连锁店,拥有超过 10,000 SKUs 、 100+ 家实体店 以及在 Shopify 网店 、 移动应用 和 POS 系统 上的活跃销售——我们构建了一个强大的实时 ERP 到 Shopify 库存更新解决方案。下面,我们分享我们的端到端架构、代码片段和性能结果。

项目范围与挑战

  • 客户: Wellcare Pharmacy 和 Raf Pharmacy,卡塔尔
  • 目录大小: 10,000+ SKU
  • 销售渠道: Shopify 店面,无头移动应用,100+ 实体店铺
  • ERP: INNSOF ERP 推送库存更新
  • 要求:
    • 实时同步以防止超卖
    • 可扩展以应对高更新量
    • 最小的API延迟和错误
    • 准确的多地点库存管理

1. 初始方法:Shopify REST API

我们首先使用了 Shopify 的 REST Admin API 端点 /admin/api/2024‑01/inventory_levels/set.json 来推送库存更新。

// Sample REST payload
$payload = [
  'location_id'      => $locationId,
  'inventory_item_id'=> $inventoryItemId,
  'available'        => $newStock
];
$response = $this->shopifyService->restRequest('POST', "/inventory_levels/set.json", $payload);

REST API 限制

  • 不支持批量更新: 每个请求一个SKU
  • 严格的速率限制: 每个商店约~2次调用/秒 → 对数千个SKU的瓶颈
  • 高延迟: 每个请求 50–100 毫秒,延迟累积
  • 易出错: 在负载下频繁出现速率限制错误

2. 迁移到 Shopify GraphQL API

为了克服REST的限制,我们切换到了 Shopify的 GraphQL Admin API,解锁了:

  • 批量更新 使用 inventoryAdjustQuantities mutation
  • 基于成本的节流 (比REST更灵活)
  • 通过仅请求所需字段 来降低网络开销
  • 基于Delta的调整 (仅在股票实际变动时更新)

3. 架构概述

  1. ERP → 中间件
    • INNSOF ERP 通过 HTTP POST 向我们的 StockController 发送 JSON 负载。
  2. 丰富与日志记录
    • 我们解析、验证并在本地数据库中记录请求(api_request_log)。
    • 我们为每个SKU添加 location_id 和 inventory_item_id (来自缓存表)。
  3. 获取当前库存
    • 通过 GraphQL 获取现有库存水平(按位置和 SKU)。
  4. 计算增量
    • 比较ERP库存与Shopify库存以确定 增量
  5. 调整库存
    • 每批发送一个 GraphQL 变更(最多 100 个 SKU)。
  6. 响应处理
    • 记录成功/失败并将更新状态推送回ERP。
  7. 重试与回退
    • 自动化的定时任务会重试失败的批次;如有必要,回退到REST。

4. 通过 GraphQL 获取当前股票

准确的增量计算始于检索现有数量。我们每个查询批量处理最多 60 项 :

query inventoryItems {
  item1: inventoryItem(id: "gid://shopify/InventoryItem/123456789") {
    id
    tracked
    sku
    inventoryLevels(first: 10) {
      edges {
        node {
          location { id name }
          quantities(names: "available") {
            quantity
          }
        }
      }
    }
  }
  # item2, item3… up to 60
}

我们的 PHP 方法将这些收集到一个数组中:

private function getCurrentStock(array $products): array {
    $batches = array_chunk($products, 60);
    $results = [];
    foreach ($batches as $batch) {
        // Build GraphQL query dynamically…
        $response = $this->shopifyService->executeGraphQl($query, []);
        // Parse `$response['data']` into $results[]
    }
    return $results;  // [ ['inventory_item_id'=>…, 'location_id'=>…, 'quantity'=>…], … ]
}

5. 通过 GraphQL 调整库存

一旦我们知道当前的库存,我们准备 delta 更新负载:

突变模板

mutation AdjustMultipleInventoryQuantities($input: InventoryAdjustQuantitiesInput!) {
  inventoryAdjustQuantities(input: $input) {
    inventoryAdjustmentGroup {
      createdAt
      changes { name delta }
    }
    userErrors { field message }
  }
}

PHP 变量格式

$changes = [];
foreach ($updatedProducts as $p) {
    $changes[] = [
      'inventoryItemId'=> "gid://shopify/InventoryItem/{$p['inventory_item_id']}",
      'locationId'     => "gid://shopify/Location/{$p['location_id']}",
      'delta'          => $p['erp_stock'] - $p['current_stock']
    ];
}

$variables = [
  'input' => [
    'reason'               => 'correction',
    'name'                 => 'available',
    'referenceDocumentUri' => 'logistics://erp/batch-2025-07-29',
    'changes'              => $changes
  ]
];

$response = $this->shopifyService->executeGraphQl($mutation, $variables);

此单次调用可以 一次更新多达 100 个 SKU ,显著减少网络噪音。

6. 优化亮点

  • 批处理与分块: 读取时每查询60个项目;写入时每次变更100个项目。
  • 本地缓存: 将 inventory_item_id 和 location_id 存储在 MySQL 中,以避免重复查找。
  • Delta Logic: 仅更新当前库存与ERP库存不同的SKU。
  • 速率限制意识: 战略性地插入 sleep()/usleep() 并在紧急重试时回退到REST。
  • 强大的日志记录: 每个请求和响应都记录在 api_request_log 和 stock_update_log 表中。

7. 性能比较

公制REST APIGraphQL API
批量更新支持❌✅
每100个SKU的平均时间~60秒~5 秒
速率限制错误(在负载下)频繁稀有
实时准确性适度
ERP反馈集成部分完整,已记录

8. 技术与工具

  • Shopify GraphQL 管理 API
  • PHP (StockController) 与 ShopifyService、 LogManager、 DBOps、 ApiService
  • MySQL 用于本地缓存和日志
  • INNSOF ERP 网络钩子
  • 定时任务 用于重试和ERP回调

9. Wellcare 和 Raf Pharmacy 的好处

  • 🔄 实时库存准确性 覆盖100多个商店和渠道
  • 🚫 零超卖 和无缝的客户体验
  • ⚡ 高吞吐量: 每小时数千个SKU更新
  • 🔍 详细审计跟踪 用于合规性和调试
  • 📈 改善了网页和移动商店的SEO和用户体验 

10. 常见问题解答

  1. 为什么在更新之前获取当前库存?
    确保我们计算正确的增量,防止意外覆盖或重复调整。
  2. GraphQL 每批可以处理多少个 SKU?
    每次变更最多 100 个 SKU,每次查询最多 60 个 SKU,具体可根据商店计划进行配置。
  3. 我可以混合使用REST和GraphQL吗?
    可以。当GraphQL受到限制时,我们保留REST作为关键更新的后备。
  4. 多地点库存有效吗?
    绝对有效。我们使用 locationId 查询和更新每个地点的库存水平。
  5. 这种方法可以适应其他ERP吗?
    可以。我们的模块化设计可以与Odoo、SAP、Oracle 6i等进行集成。

为什么选择Seamedia电子商务解决方案?
在Seamedia,我们结合深厚的Shopify专业知识与强大的ERP集成能力,提供量身定制的高性能解决方案,以推动真正的商业成果。我们的团队由经验丰富的顾问领导,如 Prajosh VM,他们理解多地点库存、高SKU数量和全渠道零售的复杂性。我们设计可扩展的、基于API的工作流程,确保您的库存准确、客户满意、运营顺畅。无论您是快速增长的药房连锁、全国零售商还是企业制造商,Seamedia都提供端到端开发、无缝的ERP连接和24/7支持。

准备好简化您的库存并提升销售吗?
今天就联系我们,邮箱是 hello@seamedia.in 或访问 www.seamedia.in 讨论我们如何为您的业务构建定制的实时库存同步解决方案。