inventory-tracking

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Inventory Tracking

库存追踪

Overview

概述

Real-time inventory tracking prevents overselling by reserving stock when customers add items to their cart and decrementing it on order fulfillment. Every major e-commerce platform has this built in. Platform-native inventory tracking is almost always the right starting point — only build custom inventory logic if you have requirements that platforms cannot meet (complex multi-warehouse routing, custom reservation windows, or external WMS integration).
实时库存追踪通过在顾客将商品加入购物车时预留库存,并在订单履行时扣减库存来防止超卖。所有主流电商平台都内置了此功能。平台原生的库存追踪几乎总是最佳起点——只有当平台无法满足你的需求(如复杂的多仓库路由、自定义预留窗口期或外部WMS集成)时,才需要构建自定义库存逻辑。

When to Use This Skill

何时使用此技能

  • When overselling is occurring and orders are being placed for out-of-stock items
  • When implementing multi-warehouse inventory with per-location stock levels
  • When building backorder or pre-order functionality for out-of-stock products
  • When a flash sale or product launch will create high-concurrency checkout attempts for limited-stock items
  • 当出现超卖情况,顾客订购了缺货商品时
  • 当实现带有各地点库存水平的多仓库库存管理时
  • 当为缺货商品构建缺货预订或预购功能时
  • 当闪购或新品发布将引发针对限量库存商品的高并发结账请求时

Core Instructions

核心操作指南

Step 1: Determine platform and enable inventory tracking

步骤1:确定平台并启用库存追踪

PlatformBuilt-in InventoryRecommended Extension
ShopifyNative per-variant inventory tracking with location supportStocky (free, by Shopify) for purchase orders and demand forecasting
WooCommerceNative stock management with backorder supportATUM Inventory Management for advanced multi-warehouse and supplier POs
BigCommerceNative per-SKU inventory tracking with low-stock alertsMulti-Location Inventory app for warehouse routing
Custom / HeadlessBuild atomic reservation with optimistic lockingRequired for custom platforms without native inventory management

平台内置库存功能推荐扩展
Shopify支持按变体、按地点的原生库存追踪Stocky(Shopify官方免费工具),用于采购订单和需求预测
WooCommerce支持缺货预订的原生库存管理ATUM Inventory Management,用于高级多仓库和供应商采购订单管理
BigCommerce支持按SKU的原生库存追踪及低库存提醒Multi-Location Inventory应用,用于仓库路由
自定义/无头平台使用乐观锁构建原子化库存预留无原生库存管理的自定义平台必备

Step 2: Platform-specific setup

步骤2:平台专属设置



Shopify

Shopify

Shopify tracks inventory per variant, per location, natively.
Enable inventory tracking:
  1. Go to Admin → Products → [Product] → [Variant]
  2. Under Inventory, check Track quantity
  3. Enter your quantity per location
  4. For "Continue selling when out of stock" — only check this if you allow backorders for this product
Set up locations:
  1. Go to Settings → Locations
  2. Add each warehouse, store, or fulfillment center as a location
  3. When editing a product variant, set the quantity at each location independently
Backorders:
  • Enable per variant: check Continue selling when out of stock on the variant
  • Or use a backorder app like Pre-Order Now or Back In Stock for more control (notify customers when available, collect pre-orders, etc.)
Oversell prevention during high traffic:
Shopify's checkout system holds inventory during the checkout process to prevent two customers from purchasing the last item simultaneously. For flash sales, use Shopify Scripts (Plus) or the Inventory Planner app to set purchase limits.
Inventory sync with physical locations:
  • Install Stocky (free, by Shopify) for purchase orders and receiving
  • Stocky automatically updates Shopify inventory when you receive a PO
  • Use the Shopify POS app to sync inventory between your online store and physical retail locations

Shopify原生支持按变体、按地点追踪库存。
启用库存追踪:
  1. 进入 Admin → Products → [对应商品] → [对应变体]
  2. Inventory 下方勾选 Track quantity
  3. 输入各地点的库存数量
  4. 关于“Continue selling when out of stock”——仅当允许该商品缺货预订时才勾选此选项
设置库存地点:
  1. 进入 Settings → Locations
  2. 将每个仓库、门店或履约中心添加为一个地点
  3. 编辑商品变体时,独立设置每个地点的库存数量
缺货预订:
  • 按变体启用:在变体页面勾选 Continue selling when out of stock
  • 或使用如 Pre-Order NowBack In Stock 的缺货预订应用以获得更多控制权(如库存到货时通知顾客、收集预购订单等)
高流量期间的超卖防护:
Shopify的结账系统会在结账过程中锁定库存,防止两名顾客同时购买最后一件商品。对于闪购活动,使用 Shopify Scripts(Plus版专属)或 Inventory Planner 应用设置购买限额。
与实体地点的库存同步:
  • 安装 Stocky(Shopify官方免费工具)用于采购订单和收货管理
  • 当你收到采购订单时,Stocky会自动更新Shopify库存
  • 使用 Shopify POS 应用同步线上店铺与实体零售店的库存

WooCommerce

WooCommerce

WooCommerce has built-in stock management.
Enable inventory tracking:
  1. Go to WooCommerce → Settings → Products → Inventory
  2. Check Enable stock management
  3. Set Hold stock (minutes) — this is the inventory reservation window during checkout (default: 60 minutes)
Per-product settings:
  1. Go to WooCommerce → Products → [Product] → Inventory tab
  2. Enable Manage stock?
  3. Enter Stock quantity
  4. Set Backorders: "Do not allow" / "Allow, but notify customer" / "Allow"
  5. Set a Low stock threshold for this product
Advanced inventory management with ATUM:
  1. Install ATUM Inventory Management for WooCommerce (free core, paid advanced features)
  2. ATUM provides a central inventory dashboard showing stock levels across all products
  3. Add purchase orders through ATUM → Purchase Orders → Add PO
  4. Receiving a PO in ATUM automatically increments WooCommerce stock
  5. For multi-warehouse: ATUM's Multi-Inventory add-on ($) assigns stock per location and routes fulfillment

WooCommerce内置库存管理功能。
启用库存追踪:
  1. 进入 WooCommerce → Settings → Products → Inventory
  2. 勾选 Enable stock management
  3. 设置 Hold stock (minutes)——这是结账过程中的库存预留窗口期(默认:60分钟)
商品专属设置:
  1. 进入 WooCommerce → Products → [对应商品] → Inventory tab
  2. 启用 Manage stock?
  3. 输入 Stock quantity
  4. 设置 Backorders:"Do not allow" / "Allow, but notify customer" / "Allow"
  5. 为该商品设置 Low stock threshold(低库存阈值)
使用ATUM进行高级库存管理:
  1. 安装 ATUM Inventory Management for WooCommerce(免费核心版,付费高级功能)
  2. ATUM提供中央库存仪表盘,展示所有商品的库存水平
  3. 通过 ATUM → Purchase Orders → Add PO 添加采购订单
  4. 在ATUM中确认收货后,会自动增加WooCommerce库存
  5. 多仓库管理:ATUM的Multi-Inventory附加组件(付费)可按地点分配库存并设置履约路由规则

BigCommerce

BigCommerce

BigCommerce tracks inventory per SKU natively.
Enable inventory tracking:
  1. Go to Products → [Product] → Inventory tab
  2. Set Inventory tracking to "By product" or "By option" (for variants)
  3. Enter the current stock level
  4. Set a Low stock level for alerts
Multi-location inventory:
  • Install the Multi-Location Inventory app from the BigCommerce App Marketplace
  • Assign stock quantities per location
  • Set fulfillment routing rules (ship from closest, ship from cheapest, etc.)
Backorders:
  • BigCommerce handles this natively — set Allow backorders on products you want to continue selling when out of stock
  • The product page shows "Ships in X days" when on backorder

BigCommerce原生支持按SKU追踪库存。
启用库存追踪:
  1. 进入 Products → [对应商品] → Inventory tab
  2. Inventory tracking 设置为"By product"或"By option"(用于变体)
  3. 输入当前库存水平
  4. 设置 Low stock level(低库存水平)以接收提醒
多地点库存:
  • 从BigCommerce应用市场安装 Multi-Location Inventory 应用
  • 按地点分配库存数量
  • 设置履约路由规则(如从最近地点发货、从成本最低地点发货等)
缺货预订:
  • BigCommerce原生支持此功能——在允许缺货预订的商品上设置 Allow backorders
  • 当商品处于缺货预订状态时,商品页面会显示“X天后发货”

Custom / Headless

自定义/无头平台

For custom platforms, implement atomic inventory reservation using optimistic concurrency control to prevent overselling under high load:
typescript
// lib/inventory.ts
const MAX_RETRIES = 3;

// Reserve inventory atomically — handles concurrent requests safely
export async function reserveInventory({
  variantId, locationId, quantity, referenceId
}: { variantId: string; locationId: string; quantity: number; referenceId: string }) {
  for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
    const level = await db.inventoryLevels.findUnique({
      where: { variantId_locationId: { variantId, locationId } },
    });

    if (!level) throw new Error(`Inventory not found: ${variantId}`);

    const available = level.onHand - level.reserved;
    if (available < quantity && !level.backorderAllowed) {
      throw new Error(`Insufficient stock: ${available} available, ${quantity} requested`);
    }

    // Optimistic update — only succeeds if version hasn't changed (no concurrent modifications)
    const updated = await db.inventoryLevels.updateMany({
      where: { variantId_locationId: { variantId, locationId }, version: level.version },
      data: { reserved: level.reserved + quantity, version: level.version + 1 },
    });

    if (updated.count === 0) {
      // Another process modified inventory concurrently; retry
      await new Promise(r => setTimeout(r, 50 * (attempt + 1)));
      continue;
    }

    // Log the transaction for audit trail
    await db.inventoryTransactions.create({
      data: { variantId, locationId, type: 'reserve', quantity: -quantity, referenceId },
    });

    return { success: true, remaining: available - quantity };
  }
  throw new Error(`Failed to reserve inventory after ${MAX_RETRIES} retries`);
}

// Release reservation when cart expires or order is cancelled
export async function releaseReservation({
  variantId, locationId, quantity, referenceId
}: { variantId: string; locationId: string; quantity: number; referenceId: string }) {
  // Idempotency check — don't release twice
  const existing = await db.inventoryTransactions.findFirst({
    where: { type: 'release', referenceId, variantId },
  });
  if (existing) return;

  await db.$transaction([
    db.inventoryLevels.update({
      where: { variantId_locationId: { variantId, locationId } },
      data: { reserved: { decrement: quantity } },
    }),
    db.inventoryTransactions.create({
      data: { variantId, locationId, type: 'release', quantity: +quantity, referenceId },
    }),
  ]);
}

// Expire stale cart reservations — run every 5-10 minutes via cron
export async function expireStaleCartReservations() {
  const TTL_MINUTES = 30;
  const cutoff = new Date(Date.now() - TTL_MINUTES * 60 * 1000);

  const staleCarts = await db.carts.findMany({
    where: { status: 'active', updatedAt: { lt: cutoff }, reservedAt: { not: null } },
    include: { items: true },
  });

  for (const cart of staleCarts) {
    for (const item of cart.items) {
      await releaseReservation({ variantId: item.variantId, locationId: item.locationId, quantity: item.quantity, referenceId: cart.id });
    }
  }
}

对于自定义平台,使用乐观并发控制实现原子化库存预留,以防止高负载下的超卖:
typescript
// lib/inventory.ts
const MAX_RETRIES = 3;

// Reserve inventory atomically — handles concurrent requests safely
export async function reserveInventory({
  variantId, locationId, quantity, referenceId
}: { variantId: string; locationId: string; quantity: number; referenceId: string }) {
  for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
    const level = await db.inventoryLevels.findUnique({
      where: { variantId_locationId: { variantId, locationId } },
    });

    if (!level) throw new Error(`Inventory not found: ${variantId}`);

    const available = level.onHand - level.reserved;
    if (available < quantity && !level.backorderAllowed) {
      throw new Error(`Insufficient stock: ${available} available, ${quantity} requested`);
    }

    // Optimistic update — only succeeds if version hasn't changed (no concurrent modifications)
    const updated = await db.inventoryLevels.updateMany({
      where: { variantId_locationId: { variantId, locationId }, version: level.version },
      data: { reserved: level.reserved + quantity, version: level.version + 1 },
    });

    if (updated.count === 0) {
      // Another process modified inventory concurrently; retry
      await new Promise(r => setTimeout(r, 50 * (attempt + 1)));
      continue;
    }

    // Log the transaction for audit trail
    await db.inventoryTransactions.create({
      data: { variantId, locationId, type: 'reserve', quantity: -quantity, referenceId },
    });

    return { success: true, remaining: available - quantity };
  }
  throw new Error(`Failed to reserve inventory after ${MAX_RETRIES} retries`);
}

// Release reservation when cart expires or order is cancelled
export async function releaseReservation({
  variantId, locationId, quantity, referenceId
}: { variantId: string; locationId: string; quantity: number; referenceId: string }) {
  // Idempotency check — don't release twice
  const existing = await db.inventoryTransactions.findFirst({
    where: { type: 'release', referenceId, variantId },
  });
  if (existing) return;

  await db.$transaction([
    db.inventoryLevels.update({
      where: { variantId_locationId: { variantId, locationId } },
      data: { reserved: { decrement: quantity } },
    }),
    db.inventoryTransactions.create({
      data: { variantId, locationId, type: 'release', quantity: +quantity, referenceId },
    }),
  ]);
}

// Expire stale cart reservations — run every 5-10 minutes via cron
export async function expireStaleCartReservations() {
  const TTL_MINUTES = 30;
  const cutoff = new Date(Date.now() - TTL_MINUTES * 60 * 1000);

  const staleCarts = await db.carts.findMany({
    where: { status: 'active', updatedAt: { lt: cutoff }, reservedAt: { not: null } },
    include: { items: true },
  });

  for (const cart of staleCarts) {
    for (const item of cart.items) {
      await releaseReservation({ variantId: item.variantId, locationId: item.locationId, quantity: item.quantity, referenceId: cart.id });
    }
  }
}

Step 3: Configure backorder behavior

步骤3:配置缺货预订行为

Backorders allow customers to purchase even when stock is at zero, with a clear expectation of a delayed delivery.
When to allow backorders:
  • Products with reliable supplier lead times (7–14 days)
  • Made-to-order products
  • Pre-order campaigns for upcoming products
When to block backorders:
  • Products with unreliable supply
  • Third-party fulfilled items where you don't control restock
Communication best practices:
  • Show "Ships in 7–10 days" on the product page when stock is 0 and backorders are enabled
  • Include expected ship date in the order confirmation email
  • Notify customers proactively if the expected date changes

缺货预订允许顾客在库存为零时仍可购买商品,并明确告知其配送延迟的预期。
何时允许缺货预订:
  • 供应商交货期可靠的商品(7–14天)
  • 定制商品
  • 即将上市商品的预购活动
何时禁止缺货预订:
  • 供应不稳定的商品
  • 第三方履约且无法控制补货的商品
沟通最佳实践:
  • 当库存为零且启用缺货预订时,在商品页面显示“7–10天后发货”
  • 在订单确认邮件中包含预计发货日期
  • 若预计日期变更,主动通知顾客

Step 4: Set up inventory alerts

步骤4:设置库存提醒

Pair inventory tracking with low-stock alerts — see the @low-stock-alerts skill for full setup. Quick summary:
  • Shopify: Go to Admin → Products — Shopify shows a low stock indicator; use Stocky for email alerts
  • WooCommerce: Go to WooCommerce → Settings → Products → Inventory → Low stock threshold — WooCommerce emails the store admin when stock crosses this threshold
  • BigCommerce: Go to Products → [Product] → Inventory → Low stock level — BigCommerce sends email notifications automatically
将库存追踪与低库存提醒结合使用——完整设置请参考 @low-stock-alerts 技能。快速总结:
  • Shopify:进入 Admin → Products——Shopify会显示低库存标识;使用 Stocky 获取邮件提醒
  • WooCommerce:进入 WooCommerce → Settings → Products → Inventory → Low stock threshold——当库存低于此阈值时,WooCommerce会向店铺管理员发送邮件
  • BigCommerce:进入 Products → [对应商品] → Inventory → Low stock level——BigCommerce会自动发送邮件通知

Best Practices

最佳实践

  • Enable inventory tracking on every SKU — products without tracking can be oversold silently; only disable tracking for digital products or items with unlimited supply
  • Set a reservation window for in-progress checkouts — WooCommerce's "Hold stock" setting (default 60 min) prevents inventory from being held indefinitely by abandoned carts
  • Test your oversell protection — during a flash sale setup, manually verify that the last unit cannot be purchased twice by simulating two simultaneous checkouts
  • Log every inventory change — platforms log this natively; for custom builds, an immutable
    inventory_transactions
    table is essential for diagnosing discrepancies
  • Use the platform's built-in multi-location inventory before buying a third-party app — Shopify, WooCommerce, and BigCommerce all handle multiple locations natively
  • 为每个SKU启用库存追踪——未启用追踪的商品可能会被静默超卖;仅对数字商品或供应无限的商品禁用追踪
  • 为进行中的结账设置预留窗口期——WooCommerce的“Hold stock”设置(默认60分钟)可防止库存被废弃购物车无限占用
  • 测试超卖防护功能——在闪购设置期间,手动模拟两次同时结账,验证最后一件商品不会被重复购买
  • 记录每一次库存变更——平台会原生记录这些变更;对于自定义构建,不可变的
    inventory_transactions
    表是诊断差异的关键
  • 在购买第三方应用前使用平台内置的多地点库存功能——Shopify、WooCommerce和BigCommerce都原生支持多地点管理

Common Pitfalls

常见问题与解决方案

ProblemSolution
Overselling during flash sales on ShopifyShopify's checkout holds inventory during the checkout flow; for very high-concurrency launches, set purchase limits using Shopify Scripts (Plus) or use a waitlist app
WooCommerce inventory not decremented after orderCheck that stock management is enabled on the product AND globally in WooCommerce settings; both must be on
Inventory released immediately when order is cancelled before fulfillmentThis is correct behavior for physical goods — released inventory becomes available for other customers; only delay release for backordered items
Negative inventory after manual adjustmentAdd validation in WooCommerce (ATUM) or set a DB check constraint on custom builds;
reserved >= 0
and
on_hand >= 0
Shopify location not receiving inventory updates from POSEnsure POS is connected to the correct Shopify location in Settings → Locations → POS channel
问题解决方案
Shopify闪购期间出现超卖Shopify的结账流程会在结账过程中锁定库存;对于极高并发的发布活动,使用Shopify Scripts(Plus版)设置购买限额,或使用等待列表应用
WooCommerce订单完成后库存未扣减检查商品和WooCommerce全局设置中是否都启用了库存管理;两者必须同时开启
订单在履约前取消,库存立即释放对于实物商品,这是正确的行为——释放的库存可供其他顾客购买;仅对缺货预订商品延迟释放
手动调整后出现负库存在WooCommerce(ATUM)中添加验证,或在自定义构建中设置数据库检查约束;确保
reserved >= 0
on_hand >= 0
Shopify地点未收到POS的库存更新确保POS在Settings → Locations → POS channel中连接到正确的Shopify地点

Related Skills

相关技能

  • @multi-warehouse
  • @low-stock-alerts
  • @variant-matrix
  • @multi-warehouse
  • @low-stock-alerts
  • @variant-matrix