order-management-system
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOrder Management System
订单管理系统
Overview
概述
An Order Management System (OMS) handles the full order lifecycle from placement to delivery: routing orders to the right fulfillment source (own warehouse, 3PL, or dropship supplier), splitting orders when items must ship from multiple locations, handling backorders, and maintaining a complete audit trail. For most merchants, platform-native features plus a shipping app cover 80–90% of OMS needs. A custom OMS is warranted when you have multiple fulfillment locations, complex routing rules, or are building a platform for other brands.
订单管理系统(OMS)负责处理从下单到交付的完整订单生命周期:将订单分配至合适的履约渠道(自有仓库、3PL或代发货供应商),当商品需从多个地点发货时拆分订单,处理缺货订单,并维护完整的审计追踪记录。对于大多数商家而言,平台原生功能搭配物流应用即可满足80%-90%的OMS需求。当您拥有多个履约地点、复杂的分配规则,或是为其他品牌搭建平台时,定制化OMS则是必要选择。
When to Use This Skill
何时使用该方案
- When your order volume has outgrown a single-warehouse workflow and you need multi-location routing
- When orders that mix in-stock and out-of-stock items need to ship in separate shipments without blocking fulfillment
- When integrating multiple fulfillment sources (own warehouse, 3PLs, dropship suppliers) into a unified routing engine
- When building the core order processing pipeline for a new platform that will support high order volume
- When you need a complete audit trail of every order state change for customer service and finance
- 当您的订单量超出单仓库工作流,需要多地点订单分配时
- 当订单同时包含有货和缺货商品,需分开发货且不阻碍履约时
- 当需要将多个履约渠道(自有仓库、3PL、代发货供应商)整合至统一分配引擎时
- 当为新平台搭建核心订单处理流程以支持高订单量时
- 当需要完整的订单状态变更审计追踪记录,用于客服和财务工作时
Core Instructions
核心操作指南
Step 1: Determine your platform and choose the right OMS approach
步骤1:确定平台并选择合适的OMS方案
| Scenario | Recommended Approach | Why |
|---|---|---|
| Single warehouse, Shopify | Shopify + ShipStation | ShipStation handles order management, label creation, and tracking natively |
| Multi-location, Shopify | Shopify Locations + ShipStation or Shopify Fulfillment Network | Shopify supports up to 10 locations; ShipStation routes to the right location based on rules |
| 3PL integration | ShipBob, Whiplash, or Flexport + your platform's app | Each 3PL has native apps for Shopify, WooCommerce, and BigCommerce |
| Complex routing + backorders | Skubana (Extensiv), Linnworks, or ShipHero | These purpose-built OMS tools handle multi-warehouse routing, backorder queues, and split shipments |
| Custom / Headless | Build an OMS state machine + integrate Shippo/EasyPost for labels | Full control over routing rules, state transitions, and audit trail |
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 单仓库,Shopify | Shopify + ShipStation | ShipStation原生支持订单管理、面单创建和物流追踪 |
| 多地点,Shopify | Shopify Locations + ShipStation 或 Shopify Fulfillment Network | Shopify标准版支持最多10个地点;ShipStation可根据规则将订单分配至合适地点 |
| 3PL集成 | ShipBob、Whiplash或Flexport + 平台对应应用 | 每个3PL都有适用于Shopify、WooCommerce和BigCommerce的原生应用 |
| 复杂分配规则 + 缺货订单 | Skubana(Extensiv)、Linnworks或ShipHero | 这些专用OMS工具可处理多仓库分配、缺货订单队列和拆分发货 |
| 定制化 / 无头架构 | 搭建OMS状态机 + 集成Shippo/EasyPost生成面单 | 可完全控制分配规则、状态转换和审计追踪记录 |
Step 2: Set up multi-location order routing
步骤2:设置多地点订单分配
Shopify
Shopify
Shopify Locations (up to 10 locations on standard plans):
- Go to Settings → Locations → Add location for each warehouse or fulfillment center
- In Settings → Shipping and delivery → Fulfill orders from, set your fulfillment priority:
- Shopify will automatically route orders to the location closest to the customer with available stock
- For each product variant, set which locations stock that item: go to Products → [Product] → Inventory → Check each location's stock level
- When an order is placed, Shopify selects the optimal fulfillment location automatically based on your priority rules
For 3PL integration:
- Install the 3PL's native Shopify app (ShipBob, Whiplash, Flexport all have Shopify apps)
- Configure which products are fulfilled by the 3PL vs. your own warehouse in the app settings
- The 3PL app creates an additional "location" in Shopify and receives order notifications automatically
For split shipments:
- Shopify automatically creates separate fulfillments when an order ships from multiple locations
- Each fulfillment gets its own tracking number and triggers its own shipping notification to the customer
Shopify Locations(标准版最多支持10个地点):
- 进入设置 → 地点 → 添加地点,为每个仓库或履约中心添加信息
- 在设置 → 配送和交付 → 从以下地点履约订单中设置履约优先级:
- Shopify会自动将订单分配给距离客户最近且有库存的地点
- 为每个商品变体设置库存地点:进入产品 → [对应产品] → 库存 → 勾选各地点的库存水平
- 下单后,Shopify会根据您设置的优先级规则自动选择最优履约地点
3PL集成:
- 安装3PL的Shopify原生应用(ShipBob、Whiplash、Flexport均有Shopify应用)
- 在应用设置中配置哪些商品由3PL履约,哪些由自有仓库履约
- 3PL应用会在Shopify中创建一个额外的「地点」,并自动接收订单通知
拆分发货:
- 当订单从多个地点发货时,Shopify会自动创建独立的履约记录
- 每个履约记录会生成单独的追踪号,并向客户发送对应的发货通知
WooCommerce
WooCommerce
Using ATUM Inventory Management:
- Install ATUM Inventory Management (free/premium, WordPress.org)
- ATUM adds multi-location inventory tracking to WooCommerce
- Configure fulfillment priority in ATUM → Settings → Multi-inventory
- Orders are routed to the location with available stock based on your priority rules
For 3PL integration:
- ShipBob has a WooCommerce plugin; install it and configure which products ship from ShipBob
- ShipStation's WooCommerce plugin connects to multiple carriers and warehouses; configure routing rules in ShipStation → Automation → Rules
使用ATUM Inventory Management:
- 安装ATUM Inventory Management(免费/付费版,可从WordPress.org获取)
- ATUM为WooCommerce添加多地点库存追踪功能
- 在ATUM → 设置 → 多库存中配置履约优先级
- 系统会根据您设置的优先级规则,将订单分配至有库存的地点
3PL集成:
- ShipBob有WooCommerce插件;安装后配置哪些商品由ShipBob发货
- ShipStation的WooCommerce插件可连接多个承运商和仓库;在ShipStation → 自动化 → 规则中配置分配规则
BigCommerce
BigCommerce
- Go to Inventory → Locations to add multiple fulfillment locations (available on Plus and above)
- Set inventory levels per location for each product
- BigCommerce routes orders to the location with stock closest to the customer based on your settings
- For 3PL integration: ShipBob, Whiplash, and ShipStation all have native BigCommerce integrations via the App Marketplace
- 进入库存 → 地点添加多个履约地点(Plus及以上版本可用)
- 为每个商品设置各地点的库存水平
- BigCommerce会根据您的设置,将订单分配至距离客户最近且有库存的地点
- 3PL集成:ShipBob、Whiplash和ShipStation均通过应用市场提供BigCommerce原生集成
Step 3: Handle backorders
步骤3:处理缺货订单
A backorder occurs when an order is placed for an item that is out of stock. The customer still wants the item; you need to fulfill it when stock arrives.
缺货订单指客户下单时商品无库存,但客户仍希望在补货后收到商品的订单。
Shopify
Shopify
Enable backorders:
- Go to Products → [Product] → Variants → [Variant]
- Set inventory tracking: check "Continue selling when out of stock" — this allows orders to come in even when stock = 0
- Be transparent: show a "Ships in 2–3 weeks" message on the product page when stock is 0
Communicate backorders:
- When a product is backordered, Shopify's standard order confirmation doesn't flag this automatically
- Use Klaviyo or Shopify Email to create a trigger: when order has a line item with quantity > available stock → send a "Backordered" email with the estimated restock date
Fulfilling backordered orders:
- When stock arrives (you receive a shipment): manually fulfill the backordered orders in Shopify → Orders → filter by "Unfulfilled" and sort by order date
- For automatic backorder fulfillment: use Shopify Flow (Plus) or a webhook to trigger fulfillment when inventory is replenished
启用缺货订单功能:
- 进入产品 → [对应产品] → 变体 → [对应变体]
- 设置库存追踪:勾选「库存为0时继续销售」—— 即使库存为0也可接收订单
- 保持透明:当库存为0时,在商品页面显示「2-3周后发货」的提示
缺货订单通知:
- 当商品缺货时,Shopify的标准订单确认邮件不会自动标记该状态
- 使用Klaviyo或Shopify Email创建触发规则:当订单中存在商品数量大于可用库存的订单项时,发送包含预计补货日期的「缺货订单」邮件
履约缺货订单:
- 补货后(收到库存):在Shopify → 订单中手动履约缺货订单,筛选「未履约」并按下单日期排序
- 自动履约缺货订单:使用Shopify Flow(Plus版)或webhook,在库存补充时触发履约
WooCommerce
WooCommerce
- Go to WooCommerce → Settings → Products → Inventory
- Enable "Allow backorders" at the global level, or set per product: Products → [Product] → Inventory → Allow Backorders
- Options: "Do not allow", "Allow but notify customer", "Allow without notification"
- Recommend: "Allow but notify customer" — WooCommerce adds a "On backorder" badge and notifies the customer at checkout
- Backordered orders appear in WooCommerce → Orders with status "On Hold" or "Processing" depending on your payment flow
- 进入WooCommerce → 设置 → 产品 → 库存
- 在全局层面启用「允许缺货订单」,或按商品设置:产品 → [对应产品] → 库存 → 允许缺货订单
- 选项:「不允许」、「允许但通知客户」、「允许不通知客户」
- 推荐选择「允许但通知客户」—— WooCommerce会添加「缺货预订」标识,并在结账时通知客户
- 缺货订单会显示在WooCommerce → 订单中,状态为「待处理」或「处理中」,具体取决于支付流程
BigCommerce
BigCommerce
- Go to Products → [Product] → Inventory
- Enable "Allow Purchasing Out of Stock" — BigCommerce shows the product as "Available for Pre-Order" automatically when stock = 0
- Set "Back Ordering" message text in Store Setup → Store Settings → Product Settings
- 进入产品 → [对应产品] → 库存
- 启用「允许库存为0时购买」—— 当库存为0时,BigCommerce会自动将商品标记为「可预订」
- 在店铺设置 → 店铺设置 → 产品设置中设置「缺货订单」提示文本
Step 4: Maintain an order audit trail
步骤4:维护订单审计追踪记录
Every order status change should be logged with who made the change and when. This is essential for customer service and fraud investigation.
所有订单状态变更都应记录变更人及变更时间,这对客服和欺诈调查至关重要。
Shopify
Shopify
- Shopify automatically logs all order status changes in Orders → [Order] → Timeline
- The Timeline shows every event: payment confirmed, fulfillment created, shipping label purchased, tracking updated, etc.
- Add manual notes to the Timeline (visible to staff only) for any manual actions taken
- Shopify会自动在订单 → [对应订单] → 时间线中记录所有订单状态变更
- 时间线会显示所有事件:支付确认、履约创建、面单购买、追踪信息更新等
- 可在时间线中添加仅员工可见的手动备注,记录所有手动操作
WooCommerce
WooCommerce
- WooCommerce logs order notes in each order's Order Notes section
- Status changes are logged automatically ("Order status changed from Processing to Completed")
- For more comprehensive audit logging: install WooCommerce Order Status Manager or Activity Log plugin
- WooCommerce会在每个订单的订单备注部分记录订单备注
- 状态变更会自动记录(如「订单状态从处理中变更为已完成」)
- 如需更全面的审计日志:安装WooCommerce Order Status Manager或Activity Log插件
BigCommerce
BigCommerce
- BigCommerce logs order status changes in the Order Activity section of each order
- The activity log shows all status changes, notes added, and system actions
- BigCommerce会在每个订单的订单活动部分记录订单状态变更
- 活动日志会显示所有状态变更、添加的备注和系统操作
Custom / Headless — order state machine with event log
定制化 / 无头架构 —— 带事件日志的订单状态机
typescript
// Order status state machine with full audit trail
type OrderStatus =
| 'pending'
| 'payment_processing'
| 'paid'
| 'awaiting_fulfillment'
| 'partially_fulfilled'
| 'fulfilled'
| 'delivered'
| 'cancelled'
| 'refunded';
const VALID_TRANSITIONS: Partial<Record<OrderStatus, OrderStatus[]>> = {
pending: ['payment_processing', 'cancelled'],
payment_processing: ['paid', 'cancelled'],
paid: ['awaiting_fulfillment', 'cancelled'],
awaiting_fulfillment: ['partially_fulfilled', 'fulfilled', 'cancelled'],
partially_fulfilled: ['fulfilled'],
fulfilled: ['delivered', 'refunded'],
delivered: ['refunded'],
};
async function transitionOrder(params: {
orderId: string;
newStatus: OrderStatus;
actorId: string;
note?: string;
}): Promise<void> {
const order = await db.orders.findById(params.orderId);
const allowed = VALID_TRANSITIONS[order.status] ?? [];
if (!allowed.includes(params.newStatus)) {
throw new Error(`Invalid transition: ${order.status} → ${params.newStatus}`);
}
await db.transaction(async tx => {
await tx.orders.update(params.orderId, { status: params.newStatus, updated_at: new Date() });
// Every transition is recorded — this IS the audit trail
await tx.orderEvents.insert({
order_id: params.orderId,
from_status: order.status,
to_status: params.newStatus,
actor_id: params.actorId,
note: params.note ?? null,
occurred_at: new Date(),
});
});
}
// Route an order to the right fulfillment source
async function routeOrder(orderId: string): Promise<void> {
const order = await db.orders.findById(orderId);
const lines = await db.orderLines.findByOrderId(orderId);
for (const line of lines) {
// Check own warehouse first
const warehouseStock = await db.inventory.findAvailable(line.sku, line.quantity);
if (warehouseStock) {
await db.fulfillmentLines.insert({
order_id: orderId,
order_line_id: line.id,
source: 'warehouse',
source_id: warehouseStock.location_id,
status: 'pending',
});
continue;
}
// Fall back to dropship supplier
const supplier = await db.supplierProducts.findBestSupplier(line.product_id, line.quantity);
if (supplier) {
await db.fulfillmentLines.insert({
order_id: orderId,
order_line_id: line.id,
source: 'dropship',
source_id: supplier.supplier_id,
status: 'pending',
});
continue;
}
// No source available — create a backorder
await db.backorders.insert({
order_id: orderId,
order_line_id: line.id,
product_id: line.product_id,
quantity: line.quantity,
status: 'pending',
});
// Notify customer about the backorder
}
}typescript
// Order status state machine with full audit trail
type OrderStatus =
| 'pending'
| 'payment_processing'
| 'paid'
| 'awaiting_fulfillment'
| 'partially_fulfilled'
| 'fulfilled'
| 'delivered'
| 'cancelled'
| 'refunded';
const VALID_TRANSITIONS: Partial<Record<OrderStatus, OrderStatus[]>> = {
pending: ['payment_processing', 'cancelled'],
payment_processing: ['paid', 'cancelled'],
paid: ['awaiting_fulfillment', 'cancelled'],
awaiting_fulfillment: ['partially_fulfilled', 'fulfilled', 'cancelled'],
partially_fulfilled: ['fulfilled'],
fulfilled: ['delivered', 'refunded'],
delivered: ['refunded'],
};
async function transitionOrder(params: {
orderId: string;
newStatus: OrderStatus;
actorId: string;
note?: string;
}): Promise<void> {
const order = await db.orders.findById(params.orderId);
const allowed = VALID_TRANSITIONS[order.status] ?? [];
if (!allowed.includes(params.newStatus)) {
throw new Error(`Invalid transition: ${order.status} → ${params.newStatus}`);
}
await db.transaction(async tx => {
await tx.orders.update(params.orderId, { status: params.newStatus, updated_at: new Date() });
// Every transition is recorded — this IS the audit trail
await tx.orderEvents.insert({
order_id: params.orderId,
from_status: order.status,
to_status: params.newStatus,
actor_id: params.actorId,
note: params.note ?? null,
occurred_at: new Date(),
});
});
}
// Route an order to the right fulfillment source
async function routeOrder(orderId: string): Promise<void> {
const order = await db.orders.findById(orderId);
const lines = await db.orderLines.findByOrderId(orderId);
for (const line of lines) {
// Check own warehouse first
const warehouseStock = await db.inventory.findAvailable(line.sku, line.quantity);
if (warehouseStock) {
await db.fulfillmentLines.insert({
order_id: orderId,
order_line_id: line.id,
source: 'warehouse',
source_id: warehouseStock.location_id,
status: 'pending',
});
continue;
}
// Fall back to dropship supplier
const supplier = await db.supplierProducts.findBestSupplier(line.product_id, line.quantity);
if (supplier) {
await db.fulfillmentLines.insert({
order_id: orderId,
order_line_id: line.id,
source: 'dropship',
source_id: supplier.supplier_id,
status: 'pending',
});
continue;
}
// No source available — create a backorder
await db.backorders.insert({
order_id: orderId,
order_line_id: line.id,
product_id: line.product_id,
quantity: line.quantity,
status: 'pending',
});
// Notify customer about the backorder
}
}Best Practices
最佳实践
- Use a purpose-built OMS before building custom — Skubana/Extensiv ($500+/month) or Linnworks handles multi-warehouse routing, backorders, and split shipments with proven reliability; custom development should only start when these tools can't meet your specific needs
- Keep orders and fulfillments as separate entities — an order is a financial contract with the customer; fulfillments are physical shipments; one order can generate multiple fulfillments
- Queue fulfillment planning asynchronously — don't route orders synchronously during checkout; enqueue routing immediately after payment confirmation and process in a background worker
- Never silently drop backordered lines — always notify the customer and give them the option to wait or cancel; silent backorders erode trust when the customer discovers weeks later
- Alert on orders stuck in "awaiting fulfillment" for 24+ hours — set up a daily alert for orders that haven't moved to fulfillment; these usually indicate a routing error or system issue
- 优先使用专用OMS而非定制开发 —— Skubana/Extensiv(每月500美元起)或Linnworks可可靠处理多仓库分配、缺货订单和拆分发货;只有当这些工具无法满足特定需求时,才考虑定制开发
- 将订单与履约记录分开管理 —— 订单是与客户的财务契约;履约记录是实际发货记录;一个订单可生成多个履约记录
- 异步处理履约规划 —— 不要在结账时同步分配订单;支付确认后立即将分配任务加入队列,由后台worker处理
- 切勿静默处理缺货订单项 —— 务必通知客户,并提供等待或取消的选项;静默缺货订单会在客户数周后发现时损害信任
- 对「等待履约」状态超过24小时的订单发出警报 —— 设置每日警报,提醒未进入履约流程的订单;这类订单通常意味着分配错误或系统问题
Common Pitfalls
常见问题及解决方案
| Problem | Solution |
|---|---|
| Order splits into multiple shipments unexpectedly | Pre-warn customers at checkout if an order will ship from multiple locations; show estimated delivery per shipment separately |
| Backorder never fulfilled after stock arrives | Set up an automatic trigger: when inventory is replenished above the backorder quantity, trigger fulfillment for the oldest pending backorder (FIFO) |
| Partial cancellation leaves the order in a broken state | Implement partial cancellation — cancel only lines that haven't been picked; issue a refund for cancelled lines; update the order total |
| Shopify shows "partially fulfilled" but customer thinks full shipment is coming | Send a clear email explaining each shipment as it ships, with the items in that specific shipment and the remaining items to follow |
| 问题 | 解决方案 |
|---|---|
| 订单意外拆分为多个发货 | 结账前提前告知客户订单将从多个地点发货;分别显示每个发货的预计送达时间 |
| 补货后缺货订单未履约 | 设置自动触发规则:当库存补充量超过缺货订单数量时,触发最早的待处理缺货订单履约(先进先出) |
| 部分取消导致订单状态异常 | 实现部分取消功能 —— 仅取消未拣货的订单项;为取消的订单项退款;更新订单总额 |
| Shopify显示「部分履约」但客户认为是完整发货 | 每次发货时发送清晰的邮件,说明该次发货的商品及剩余待发货商品 |
Related Skills
相关方案
- @order-fulfillment-workflow
- @returns-management
- @multi-channel-selling
- @dropshipping-integration
- @demand-forecasting
- @order-fulfillment-workflow
- @returns-management
- @multi-channel-selling
- @dropshipping-integration
- @demand-forecasting