保持库存准确和最新对于任何高销量零售商来说都是至关重要的。对于 Wellcare 和 Raf Pharmacy ——这两家在卡塔尔领先的药房连锁店,拥有超过 10,000 SKUs 、 100+ 家实体店 以及在 Shopify 网店 、 移动应用 和 POS 系统 上的活跃销售——我们构建了一个强大的实时 ERP 到 Shopify 库存更新解决方案。下面,我们分享我们的端到端架构、代码片段和性能结果。
- 项目范围与挑战
- 1. 初步方法:Shopify REST API
- 2. Migrate to Shopify GraphQL API
- 3. Architecture Overview
- 4. 通过 GraphQL 获取当前库存
- 5. 通过 GraphQL 调整库存
- 6. Optimization Highlights
- 7. Performance Comparison
- 8. Technology and Tools
- 9. Wellcare 和 Raf Pharmacy 的好处
- 10. 常见问题
项目范围与挑战
- 客户: 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,解锁了:
- 批量更新 使用
inventoryAdjustQuantitiesmutation - 基于成本的节流 (比REST更灵活)
- 通过仅请求所需字段 来降低网络开销
- 基于Delta的调整 (仅在股票实际变动时更新)
3. 架构概述
- ERP → 中间件
- INNSOF ERP 通过 HTTP POST 向我们的
StockController发送 JSON 负载。
- INNSOF ERP 通过 HTTP POST 向我们的
- 丰富与日志记录
- 我们解析、验证并在本地数据库中记录请求(
api_request_log)。 - 我们为每个SKU添加
location_id和inventory_item_id(来自缓存表)。
- 我们解析、验证并在本地数据库中记录请求(
- 获取当前库存
- 通过 GraphQL 获取现有库存水平(按位置和 SKU)。
- 计算增量
- 比较ERP库存与Shopify库存以确定
增量。
- 比较ERP库存与Shopify库存以确定
- 调整库存
- 每批发送一个 GraphQL 变更(最多 100 个 SKU)。
- 响应处理
- 记录成功/失败并将更新状态推送回ERP。
- 重试与回退
- 自动化的定时任务会重试失败的批次;如有必要,回退到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 API | GraphQL 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. 常见问题解答
- 为什么在更新之前获取当前库存?
确保我们计算正确的增量,防止意外覆盖或重复调整。 - GraphQL 每批可以处理多少个 SKU?
每次变更最多 100 个 SKU,每次查询最多 60 个 SKU,具体可根据商店计划进行配置。 - 我可以混合使用REST和GraphQL吗?
可以。当GraphQL受到限制时,我们保留REST作为关键更新的后备。 - 多地点库存有效吗?
绝对有效。我们使用locationId查询和更新每个地点的库存水平。 - 这种方法可以适应其他ERP吗?
可以。我们的模块化设计可以与Odoo、SAP、Oracle 6i等进行集成。
为什么选择Seamedia电子商务解决方案?
在Seamedia,我们结合深厚的Shopify专业知识与强大的ERP集成能力,提供量身定制的高性能解决方案,以推动真正的商业成果。我们的团队由经验丰富的顾问领导,如 Prajosh VM,他们理解多地点库存、高SKU数量和全渠道零售的复杂性。我们设计可扩展的、基于API的工作流程,确保您的库存准确、客户满意、运营顺畅。无论您是快速增长的药房连锁、全国零售商还是企业制造商,Seamedia都提供端到端开发、无缝的ERP连接和24/7支持。
准备好简化您的库存并提升销售吗?
今天就联系我们,邮箱是 hello@seamedia.in 或访问 www.seamedia.in 讨论我们如何为您的业务构建定制的实时库存同步解决方案。