订单履约业务与技术流程梳理
本文只沉淀前面讨论过的业务和技术内容,覆盖订单履约主链路、订单/履约单状态流转、配货与锁库存、派单流程、申请运单流程、Temu 平台履约流程,以及对应的一致性风险。 订单履约不是单纯的订单状态变化,而是一条跨履约、物流、库存、仓库、平台的长
本文只沉淀前面讨论过的业务和技术内容,覆盖订单履约主链路、订单/履约单状态流转、配货与锁库存、派单流程、申请运单流程、Temu 平台履约流程,以及对应的一致性风险。
1. 核心业务名词
| 业务名词 | 业务含义 | 代码定位名词 |
|---|---|---|
| 平台订单 | 从 eBay、Amazon、速卖通、Temu、TikTok 等平台同步进来的原始销售订单 | 订单(Order) |
| 履约单/包裹 | ERP 内部真正用于仓库、物流、发货处理的业务单据,一个平台订单可能拆成多个履约单 | 履约单(Package) |
| 订单明细 | 平台订单中的商品行 | 订单商品明细(OrderItem) |
| 履约商品 | 履约单中实际要出库的商品,包含组合品拆解后的 SKU | 履约商品(PackageProduct) |
| 物流系统运单 | 物流服务内部创建的系统单据,还不一定代表已向承运商申请成功 | 物流系统运单(LogisticsOrder) |
| 运单号 | 物流商/平台物流返回的正式运单号 | 运单号(waybillNumber) |
| 追踪号 | 用于平台标发、买家追踪物流轨迹的号码 | 追踪号(trackingNumber) |
| 出库单 | 库存服务/仓库侧用于拣货、出库、推送 WMS 的单据 | 库存出库单(OutboundOrder) |
| 配货 | 给履约单确定发货仓、物流渠道、具体使用哪些库存,并生成库存出库单 | 履约单分仓分物流与出库创建(submitInventory / saveAllocatePack) |
| 可用库存 | 当前还可以继续分配给订单的库存 | 可用库存数量(availableQuantity) |
| 待发库存 | 已经被出库单占用、等待仓库发出的库存,业务上就是被锁住的库存 | 待发库存数量(pendQuantity) |
| 标签 | 履约单上的异常、处理中、业务状态标识,例如派单中、生成运单失败、申请运单失败 | 履约标签(LabelEnum) |
| 标发 | 将运单号/追踪号回传到销售平台,告诉平台订单已发货 | 标记发货(markship) |
| Temu 父订单 | Temu 平台的一张买家订单,下面可能有多个子订单 | Temu 父订单号(parentOrderSn / orderId) |
| Temu 子订单 | Temu 平台用于履约拆分的商品级订单,ERP 用它绑定订单明细和包裹明细 | Temu 子订单号(orderSn / lineItemId) |
| Temu 卖家履约 | 由卖家侧 ERP、仓库、物流负责发货的 Temu 子订单,需要进入本系统履约 | 卖家履约类型(FULFILL_BY_SELLER) |
| Temu 合作仓履约 | 由 Temu 合作仓体系处理的子订单,本系统不按普通卖家订单履约 | 合作仓履约类型(FULFILL_BY_COOPERATIVE_WAREHOUSE) |
| Temu Y2 预售订单 | Temu 的预售订单标签,进入 ERP 后会继续传递到履约单/包裹 | Y2 预售标签(Y2_advance_sale / Y2_ORDER / Y2_ORDER_PACK) |
| Temu 线上物流 | Temu 平台物流商处理的物流链路,系统里有专门的运单和标发判断 | Temu 物流商(LOGISTICS_PROVIDER_TEMU) |
2. 订单履约主链路
订单履约不是单纯的订单状态变化,而是一条跨履约、物流、库存、仓库、平台的长链路。主流程如下:
flowchart TD
A["平台订单同步进 ERP"] --> B["履约服务保存订单和订单明细"]
B --> C["订单审核/补全基础信息"]
C --> D["生成履约单"]
D --> E["分仓、分物流、匹配库存"]
E --> F["创建物流系统运单"]
E --> G["创建库存出库单/库存占用"]
F --> H{"物流系统运单创建成功?"}
H -- "否" --> H1["履约单打生成运单失败标签"]
H -- "是" --> I["履约单进入待配货/配货处理中"]
G --> I
I --> J["配货完成"]
J --> K["派单给仓库/WMS"]
K --> L["仓库确认并开始处理"]
L --> M["仓库出库/回传物流信息"]
M --> N["履约单更新运单号/追踪号"]
N --> O["平台标记发货"]
O --> P["订单/履约单完成发货"]
关键理解:
- 订单状态是粗粒度的销售订单视角,主要告诉业务这张平台订单是否还需要处理。
- 履约单状态是履约执行视角,后半段仓库、物流、派单、出库基本都围绕履约单推进。
- 物流系统运单和库存出库单是两个并行业务结果:一个负责物流承运商申请,一个负责仓库出库执行。
3. 订单状态流转
订单状态主要描述平台订单在履约系统里的整体处理结果。
| 业务状态 | 业务含义 | 代码值 |
|---|---|---|
| 待审核 | 订单进入系统后,等待审核或业务校验 | examining |
| 待发货 | 订单审核完成,等待履约执行 | unship |
| 部分发货 | 订单下部分履约单已经发货,仍有剩余未完成 | partship |
| 已发货 | 订单下履约单均已完成发货 | shipped |
| 已取消 | 订单取消,不再走正常履约 | cancelled |
| 未知货主 | 订单归属识别失败,需要人工处理 | unknown |
| 不需要处理 | 订单被判定无需履约 | notDealWith |
| 发货异常 | 发货链路出现异常,需要人工介入 | shippedException |
| 缺少平台入库单 | 半托管/全托管等场景缺少平台侧采购或入库凭证 | lackPurchaseOrder |
| 待完善收货人信息 | 地址/收件人信息不完整,无法继续履约 | improve_recipient_info |
订单状态的主流转:
stateDiagram-v2
[*] --> 待审核
待审核 --> 待发货: 审核通过
待发货 --> 部分发货: 部分履约单发货
部分发货 --> 已发货: 剩余履约单发货
待发货 --> 已发货: 全部履约单发货
待审核 --> 已取消: 订单取消
待发货 --> 已取消: 订单取消/拦截取消
待审核 --> 未知货主: 货主识别失败
待审核 --> 不需要处理: 规则判定无需处理
待发货 --> 发货异常: 发货链路异常
待发货 --> 缺少平台入库单: 平台托管资料缺失
待审核 --> 待完善收货人信息: 地址信息不完整
4. 履约单状态流转
履约单状态才是订单履约后半程的核心状态机。
| 业务状态 | 业务含义 | 代码值 |
|---|---|---|
| 待配货 | 履约单已生成,等待仓库、物流、库存等履约要素确认 | Package Confirmation |
| 已配货 | 库存/出库单已准备好,具备派单基础 | Already distributed |
| 待仓库确认 | 派单后等待仓库或 WMS 确认接单 | Wait Warehouse Confirm |
| 仓库处理中 | 仓库已接单,正在拣货、打包、出库 | Warehouse Processing |
| 已发货 | 仓库出库完成,履约单完成发货 | Shipped |
| 拦截 | 履约单进入拦截流程 | Intercept |
| 已取消 | 履约单取消,不再出库 | Cancelled |
| 异常类状态 | 缺货、退款、发货失败等非主流程状态 | Out of Stock / Refunded / Exception / Shipped Failed |
履约单主流转:
stateDiagram-v2
[*] --> 待配货
待配货 --> 已配货: 配货完成
已配货 --> 派单中: 发起派单
派单中 --> 待仓库确认: 仓库接单回传
待仓库确认 --> 仓库处理中: 仓库开始处理
仓库处理中 --> 已发货: 出库完成
待配货 --> 已取消: 取消/拦截成功
已配货 --> 已取消: 取消/拦截成功
已配货 --> 派单失败: 推送仓库失败
待配货 --> 生成运单失败: 创建物流系统运单失败
已配货 --> 申请运单失败: 物流商申请运单失败
注意:派单中、派单失败、生成运单失败、申请运单失败更像履约标签,不完全等同履约单主状态。这个项目里状态和标签混用比较多,业务上看得懂,技术上要小心别把标签当主状态乱改。
5. 配货与锁库存
5.1 配货的业务含义
配货不是仓库开始拣货,而是 ERP 在仓库真正干活之前,先把这张履约单的履约资源确定下来:
- 从哪些候选仓里选一个发货仓。
- 根据发货仓、平台、店铺、站点等条件匹配物流渠道。
- 按商品需要数量,分配具体货物库存。
- 创建库存出库单,把可用库存转成待发库存。
- 配货成功后,履约单从待配货变为已配货,后续才具备派单基础。
所以业务上可以这么理解:配货完成时,库存已经被占住了;派单只是把已经占好库存的出库任务推给仓库执行。
5.2 锁库存发生在哪个节点
锁库存发生在配货链路里,但不是“提交配货”按钮一按就马上扣库存。
准确节点是:配货任务执行到创建库存出库单时,由库存服务完成库存锁定和库存数量变更。
flowchart TD
A["履约单待配货"] --> B["提交配货"]
B --> C["打配货中标签并进入异步队列"]
C --> D["执行分仓分物流"]
D --> E["校验物理仓可用库存"]
E --> F["分配具体货物库存"]
F --> G["校验/分配逻辑仓库存"]
G --> H["创建物流系统运单"]
G --> I["创建库存出库单"]
I --> J["库存服务获取库存维度锁"]
J --> K["可用库存减少"]
J --> L["待发库存增加"]
K --> M["履约单更新为已配货"]
L --> M
这里要区分两个动作:
- 履约服务做的是“预分配”:查询库存、判断候选仓是否满足、计算使用哪些货物库存。
- 库存服务做的是“最终占用”:创建出库单时拿库存锁,在事务里把可用库存扣掉,把待发库存加上。
5.3 新版配货锁库存实现
新版配货流程里,履约服务先做业务决策:
- 提交配货时,履约服务保存“配货中”标签并启动异步任务。
- 配货任务会校验履约单是否仍处于待配货,是否有取消、退回、拆合单等不能配货的情况。
- 系统按候选仓循环尝试配货,先校验物理仓库存是否足够。
- 系统按库存明细分配具体货物,避免同一单内重复使用同一批可用库存。
- 如果启用了逻辑仓,还会校验逻辑库存;专有逻辑仓不足时,会构造逻辑仓调配明细。
- 匹配物流渠道,必要时创建物流系统运单。
- 调用库存服务创建出库单。
- 出库单创建成功后,履约单更新为已配货,并保存出库单号、仓库、物流等信息。
库存服务接到创建出库单请求后,才执行真正锁库存:
- 按发货仓和货物库存记录生成库存锁。
- 在锁内开启本地事务。
- 创建出库单主单和出库明细。
- 对外部来源单据执行库存占用:可用库存减少,待发库存增加。
- 写库存变更日志。
- 如果库存扣完会小于 0,直接抛库存不足异常,配货失败。
对应代码定位时,要先说业务名词再说代码名词:
- 提交配货入口:把履约单放入配货队列(
PackageServiceImpl.submitInventory)。 - 执行分仓分物流配货:给履约单选择仓库、物流和库存(
AllocateWarehouseLogisticsHandle.saveAllocatePack)。 - 新版配货主流程:按候选仓尝试完成配货(
saveAllocatePackV2)。 - 单仓配货过程:校验库存、分配货物、创建出库单、更新履约单(
allocatePackage)。 - 履约侧构造出库明细:确定使用哪些货物库存(
PackageAllocateServiceImpl.buildOutboundStockDetail)。 - 履约侧创建出库单:调用库存服务占用库存(
PackageAllocateServiceImpl.createOutboundOrder)。 - 库存侧创建出库单:获取库存锁并执行出库单创建(
OutboundOrderServiceV2Impl.createOutboundOrder)。 - 库存侧锁定库存:可用库存减少、待发库存增加(
InvOutboundOrderServiceImpl.buildDeductAvailableAndAddPendQuantityCmdAndExecute)。 - 库存变更执行器:统一执行库存数量变更并校验不能小于 0(
InventoryOperationServiceImpl.executeInventoryOperation)。
5.4 老版配货锁库存实现
老版流程也是在创建出库单时锁库存,只是实现更直接:
- 先根据出库明细找到相关库存记录,组合品还会把子货物库存一起纳入锁范围。
- 获取库存锁后,在事务里筛选有库存的货物。
- 创建出库单和出库明细。
- 直接把库存汇总记录里的待发库存增加、可用库存减少。
- 保存库存变更日志。
对应业务定位:
- 老版库存出库创建入口:创建出库单前先锁相关库存(
ConnectOutboundServiceImpl.createOutboundOrder)。 - 老版锁内创建与扣减:筛选库存、建出库单、更新库存数量(
ConnectOutboundServiceImpl.lockAndCreate)。 - 老版库存占用变更:增加待发库存、减少可用库存(
ConnectOutboundServiceImpl.buildInventoryChangeLog)。
5.5 并发与一致性风险
配货锁库存这段的并发控制分两层:
- 履约侧用“配货中”标签和锁,防止同一履约单重复提交配货。
- 库存侧用库存记录维度的锁,防止多个履约单同时抢同一仓同一货物导致超卖。
但这里仍然不是纯强一致单体事务,因为履约服务、库存服务、物流服务都参与了链路。
主要风险:
- 履约服务查询库存和库存服务最终锁库存之间有时间差,库存可能被别的订单抢走,所以履约侧校验只能算预校验,最终以库存服务创建出库单为准。
- 创建物流系统运单和创建库存出库单属于两个业务结果,如果其中一个成功、另一个失败,需要靠失败标签、重试或人工处理兜底。
- 履约侧配货方法使用全局事务包住跨服务调用,但外部物流或后续异步动作不能简单依赖数据库事务回滚。
- 库存锁只保护库存数量变更,不代表整个履约链路强一致。
面试时可以这样回答:这个系统把锁库存放在配货阶段,但最终锁点在库存服务创建出库单。履约侧只做库存预分配和业务编排,库存服务在库存维度加锁,并在事务里将可用库存转成待发库存。这样既避免履约服务直接改库存,也能把防超卖能力收敛到库存服务。
6. 派单流程
6.1 派单的业务含义
派单就是:履约单已经完成配货后,把对应的出库任务正式推给仓库或 WMS,让仓库开始接单、拣货、打包和出库。
它不是申请运单,也不是平台标发。它解决的是“仓库是否开始处理这张履约单”的问题。
6.2 派单前置条件
派单前通常需要满足:
- 履约单存在。
- 履约单已配货。
- 履约单没有正在派单的处理中标签。
- 履约单没有等待退回、等待取消等不应继续出库的标签。
- 已经具备仓库、物流渠道、出库单等履约基础信息。
6.3 派单主流程
flowchart TD
A["运营/系统选择已配货履约单"] --> B["履约服务校验是否允许派单"]
B --> C{"校验通过?"}
C -- "否" --> C1["返回失败原因"]
C -- "是" --> D["履约服务组装出库推送请求"]
D --> E["调用库存服务推送出库单"]
E --> F["履约单打派单中标签并写操作日志"]
E --> G["库存服务记录推送任务"]
G --> H["库存服务异步推送仓库/WMS"]
H --> I["库存服务收到仓库/WMS处理结果"]
I --> J["库存服务发出出库状态回调消息"]
J --> K["履约服务消费回调"]
K --> L{"仓库接单成功?"}
L -- "是" --> M["移除派单中标签,履约单进入待仓库确认,记录派单时间"]
L -- "否" --> N["移除派单中标签,打派单失败标签,记录失败原因"]
6.4 派单相关技术点
- 履约侧派单入口是“派单给仓库”的接口(
/dispatchWarehouse),核心动作在“执行履约单派单”的服务逻辑里(dispatchWarehouse/doPackageDispatch)。 - 库存侧会创建“出库单推送记录”,然后异步唤醒仓库/WMS 推送任务。
- 仓库处理结果不是同步返回给履约服务,而是经库存服务回调,再由履约服务更新履约单状态和标签。
6.5 派单的一致性风险
派单链路存在分布式事务问题,不能理解成一个强一致事务。
主要原因:
- 履约服务虽然使用了全局事务包住部分远程调用,但库存服务创建推送记录后,会异步推送仓库/WMS。
- 仓库/WMS 是外部系统,已经发出去的请求无法被数据库事务回滚。
- Kafka 回调、异步任务、WMS 接口调用都在数据库事务之外,最终只能靠幂等、补偿、重试、人工处理兜底。
具体风险:
- 履约侧回滚了,但库存侧可能已经产生推送记录,甚至仓库已经收到出库任务。
- 库存侧推送成功了,但履约侧消费回调失败,会出现仓库已处理、履约单仍停留在旧状态。
- 履约侧处理派单结果时,如果发现履约单还被派单锁占用,可能跳过这次回调;如果消息已经确认,存在状态丢失风险。
- 派单前对“等待退回/等待取消”的标签校验实现疑似有复制粘贴问题:业务上应该读取等待退回/等待取消标签,代码里疑似把集合来源误用了派单中标签集合。
建议的治理方向:
- 派单请求和仓库推送之间使用明确的“本地消息表/任务表”承接,不要假装外部 WMS 能参与事务。
- 出库推送、回调消费、履约状态更新都必须幂等。
- 派单失败、回调丢失、长时间派单中要有定时补偿任务。
- 派单中标签不要只作为展示字段,也要能支撑恢复和补偿判断。
7. 申请运单流程
7.1 申请运单的业务含义
申请运单是物流系统拿着履约单的地址、商品、仓库、物流渠道等信息,向物流商或平台物流申请正式运单,拿回运单号、追踪号、面单。
申请运单解决的是“物流商是否接收这票货、是否给了正式物流凭证”的问题。
它和派单的区别:
| 动作 | 业务目的 | 对接对象 | 结果 |
|---|---|---|---|
| 申请运单 | 向物流商/平台物流下单,获取运单号、追踪号、面单 | 物流商、平台物流 API | 运单号、追踪号、面单 |
| 派单 | 把出库任务推给仓库/WMS,让仓库开始处理 | 仓库、WMS | 仓库接单、出库处理 |
| 标发 | 把物流信息回传销售平台 | 销售平台 API | 平台订单显示已发货 |
7.2 生成运单失败与申请运单失败
这两个标签业务含义不同,不能混着看。
| 失败类型 | 失败发生点 | 业务含义 | 标签 |
|---|---|---|---|
| 生成运单失败 | 履约服务调用物流服务创建系统运单时失败 | 物流系统内部单据都没创建成功 | CREATEWAYBILLFAIL |
| 申请运单失败 | 物流服务已有系统运单,但向物流商申请正式运单失败 | 物流商/平台物流没有成功返回正式运单 | APPLYWAYBILLFAIL |
7.3 申请运单主流程
flowchart TD
A["履约单完成分仓分物流"] --> B["履约服务创建物流系统运单"]
B --> C{"系统运单创建成功?"}
C -- "否" --> C1["履约单打生成运单失败标签"]
C -- "是" --> D["物流系统运单进入待申请"]
D --> E["运营/系统触发申请运单"]
E --> F["物流服务校验运单是否允许申请"]
F --> G{"允许申请?"}
G -- "否" --> G1["返回失败原因"]
G -- "是" --> H["物流服务标记申请中"]
H --> I["异步调用物流商策略"]
I --> J["物流商/平台物流接口返回"]
J --> K{"申请成功?"}
K -- "成功" --> L["物流服务保存运单号、追踪号、面单"]
L --> M["物流系统运单进入待交运"]
M --> N["发送物流信息消息"]
N --> O["履约服务更新履约单物流信息并移除申请失败标签"]
N --> P["库存服务更新出库单物流信息"]
O --> Q["触发平台标发"]
K -- "失败" --> R["物流服务记录申请失败原因"]
R --> S["回调履约服务"]
S --> T["履约单打申请运单失败标签"]
T --> U["运营修复履约信息后重新提交物流"]
U --> V["物流系统运单重置为待申请"]
7.4 申请运单状态
物流系统运单有两层状态:
| 状态类型 | 业务状态 | 业务含义 | 代码值 |
|---|---|---|---|
| 运单主状态 | 待申请 | 系统运单已创建,等待向物流商申请 | APPLY |
| 运单主状态 | 待交运 | 已拿到运单,等待交运/仓库处理 | SHIPPING |
| 运单主状态 | 已交运 | 已完成交运 | SHIPPED |
| 申请状态 | 待申请 | 尚未发起物流商申请 | NOT_APPLIED |
| 申请状态 | 申请中 | 已发起申请,正在等待物流商结果 | APPLYING |
| 申请状态 | 申请失败 | 物流商申请失败,需要修复后重试 | FAILED |
| 申请状态 | 申请成功 | 物流商申请成功 | SUCCESS |
| 申请状态 | 退回待申请 | 从待交运退回,可重新申请 | RETURN |
追踪号还有单独状态:
| 追踪号状态 | 业务含义 | 代码值 |
|---|---|---|
| 已产生跟踪号 | 已拿到真实追踪号 | DONE |
| 等待后续更新 | 运单已申请成功,但追踪号需要后续定时获取 | WAIT |
| 不需要跟踪号 | 渠道无需追踪号 | NONE |
| 超过时限未获取 | 等待太久仍未拿到追踪号 | LONGWAIT |
| 获取失败 | 追踪号获取失败 | FAIL |
7.5 申请运单成功后的回写
申请成功后,物流服务不是直接同步把所有结果返回履约服务,而是发送物流信息消息,履约服务和库存服务分别消费。
履约服务收到消息后:
- 更新履约单运单号。
- 更新履约单追踪号。
- 更新履约单是否已有面单。
- 设置申请运单时间。
- 清空失败原因。
- 移除申请运单失败标签。
- 如果本次确实更新了运单号/追踪号,则触发平台标发消息。
库存服务收到消息后:
- 更新库存出库单的运单号和追踪号。
- 对自营仓、百世、万邑通等不同仓库类型做差异处理。
- 必要时继续推送仓库或生成货物标签。
7.6 申请运单失败后的修复
申请失败后:
- 物流服务记录申请失败原因。
- 物流服务回调履约服务。
- 履约服务给履约单打申请运单失败标签。
- 运营在履约侧修复地址、商品申报、物流渠道等问题。
- 运营点击“已修复/重新提交物流”。
- 履约服务重新组装物流信息,提交给物流服务修复系统运单。
- 物流系统运单被重置为待申请,后续可以重新申请运单。
8. 申请运单的一致性风险
申请运单链路同样是最终一致,不是强分布式事务。
主要原因:
- 物流商接口调用是外部副作用,无法跟本地数据库事务一起回滚。
- 成功结果通过 Kafka 通知履约和库存,消息发送和消费都有失败可能。
- 失败结果通过 Feign 回调履约,回调失败时可能造成物流侧失败、履约侧未打失败标签。
- 有些物流商先返回运单号,追踪号需要后续定时任务获取,业务上天然分阶段。
典型风险:
- 物流商已经成功创建运单,但物流服务保存失败,可能造成外部运单存在、系统无记录。
- 物流服务保存成功,但 Kafka 发送失败,履约单和库存出库单拿不到最新运单信息。
- Kafka 发送成功,但履约服务消费失败,履约单不更新,后续标发无法触发。
- 申请失败回调履约失败,履约页面可能看不到申请失败标签。
- 商品申报信息缺失导致申请失败时,物流服务会记录失败;但如果没有同步打到履约标签,运营入口可能不明显。
建议的治理方向:
- 物流商申请请求要有业务幂等键,至少用物流系统运单号或履约单号防重复。
- 运单申请结果要落本地结果表,Kafka 只做结果通知。
- 物流成功消息、失败回调都要有补偿任务,按物流系统运单状态反查并补发。
- 履约服务消费物流消息要幂等,重复消息不能覆盖掉较新的运单/面单信息。
- 对“申请中”超时的运单设置定时扫描,避免长期挂死。
9. Temu 平台订单履约流程
9.1 Temu 履约总览
Temu 平台的履约流程不是“平台订单进来就全量发货”这么粗暴。它先按 Temu 父订单拉取订单,再按 Temu 子订单判断履约类型:只有卖家履约的子订单进入 ERP 履约;合作仓履约的子订单不走普通卖家履约链路。
整体流程如下:
flowchart TD
A["Temu 平台订单更新"] --> B["同步服务拉取父订单和子订单"]
B --> C["补全订单详情和收货人信息"]
C --> D{"父订单待发货且存在卖家履约子订单?"}
D -- "否" --> D1["不发送履约消息"]
D -- "是" --> E["发送订单池消息和履约消息"]
E --> F["履约服务消费 Temu 订单"]
F --> G{"ERP 是否已有同平台订单?"}
G -- "没有" --> H["创建 ERP 订单和订单明细"]
G -- "已有" --> I["只追加新出现的卖家履约子订单"]
H --> J["订单待审核"]
I --> J
J --> K["审核通过生成履约单/包裹"]
K --> L["分仓:确定发货仓"]
L --> M["分物流:确定物流商和渠道"]
M --> N["配货:创建出库单并锁库存"]
N --> O["必要时创建物流系统运单"]
N --> P["派单给仓库/WMS"]
P --> Q["仓库处理并出库"]
Q --> R["回写运单号/追踪号"]
R --> S{"是否 Temu 线上物流?"}
S -- "是" --> S1["线上物流无需普通标发"]
S -- "否" --> T["按子订单/包裹/追踪号向 Temu 标发"]
T --> U["同步 Temu 平台发货/取消状态"]
S1 --> U
业务上可以把 Temu 分成三段看:
- 接单段:同步 Temu 父订单和子订单,只把待发货、卖家履约的订单送入履约服务。
- 执行段:进入 ERP 后复用通用履约链路,也就是审核、生成履约单、分仓、分物流、配货锁库存、派单、出库。
- 平台回传段:出库后不是简单按 ERP 订单整体标发,而是按 Temu 子订单、履约单包裹、追踪号组织标发数据,并回查平台状态。
9.2 Temu 接单与过滤规则
Temu 拉单服务会先筛选具备订单履行授权的店铺,再按更新时间窗口拉取订单列表。拉单时会同时关注卖家履约和合作仓履约两类子订单,但真正发送到履约服务前有几层过滤:
- 父订单必须是 Temu 待发货状态。
- 子订单列表里必须至少存在一个卖家履约子订单。
- 订单日期要晚于业务配置的启用日期,当前代码里对应 2025-05-12 之后的卖家履约订单。
- 合作仓履约子订单不会进入普通卖家履约;如果一个父订单下全是合作仓履约,连收货人信息都不再额外拉取。
- 收货人信息只在父订单待发货时拉取,优先走 Temu 解密收货人接口,失败后再走普通收货信息接口补偿。
对应业务定位:
- Temu 拉单任务:按店铺拉取 Temu 父订单和子订单(
SyncOrderTaskJob.syncStoreOrder)。 - Temu 收货信息补全:待发货且非纯合作仓履约时补全买家收货地址(
SyncOrderTaskJob.getOrderRecipient/requestTemuGetShippingInfo)。 - Temu 履约消息发送:只发送待发货且存在卖家履约子订单的订单(
MessageProducer.sendOrderFulfillmentMessage)。
9.3 Temu 订单落 ERP
履约服务收到 Temu 履约消息后,会先按 Temu 父订单号和平台查询 ERP 内是否已有订单。
如果没有已有订单,就创建新的 ERP 订单;如果已有订单,就看是否还有待审核或未知货主状态的订单可以追加明细。Temu 这里有个很关键的业务点:子订单履约类型可能后续变化,合作仓履约转成卖家履约后,ERP 需要能追加新子订单,甚至创建新的待审核订单。
ERP 落单规则:
- ERP 订单的初始状态是待审核。
- Temu 父订单号作为平台订单号。
- Temu 子订单号作为订单明细的业务行号,后续标发也靠它关联平台子订单。
- 只转换卖家履约子订单;合作仓履约子订单直接跳过。
- 如果是人工导入过的 Temu 订单,系统判断这类订单可能已经履约过,不再重复按同步订单处理。
- 商品匹配按店铺、平台 SKU、卖家 SKU 查 ERP 商品;查不到商品时,订单明细仍会保存,但货主、商品编码等内部履约信息可能缺失,后续审核或配货会暴露问题。
- 如果子订单带 Temu Y2 预售标签,ERP 会给订单打 Y2 预售标识,生成履约单时再传递到包裹。
对应业务定位:
- Temu 履约消息消费:接收 Temu 同步订单并进入履约处理(
TemuOrderConsumer.process)。 - Temu ERP 订单创建/追加:按已有订单情况创建订单或追加子订单明细(
TemuOrderConsumer.processOrder)。 - Temu 订单主信息转换:把 Temu 父订单转换成 ERP 待审核订单(
TemuOrderConsumer.convertOrder)。 - Temu 子订单明细转换:只把卖家履约子订单转换成 ERP 订单明细(
TemuOrderConsumer.convertOrderItem)。 - Temu Y2 预售订单识别:识别 Temu 预售标签并写入 ERP 订单标签(
TemuOrderConsumer.markY2OrderLabel)。
9.4 Temu 的分仓、分物流、配货
Temu 订单进入 ERP 后,核心履约执行仍然复用通用链路,但要把三个节点分清楚:
| 节点 | Temu 场景下的业务含义 | 关键点 |
|---|---|---|
| 分仓 | 从候选仓中确定 Temu 履约单由哪个仓发货 | 本质仍是 ERP 配货规则选择发货仓;如果分到万邑通仓,后续是否需要创建物流系统运单会看物流商类型 |
| 分物流 | 根据仓库、平台、站点、店铺等条件匹配物流商和物流渠道 | 如果物流商是 Temu 平台物流商,系统会按 Temu 线上物流逻辑处理;Y2 预售订单有“应使用 Temu 物流”的辅助校验能力 |
| 配货 | 按履约单商品分配库存并创建库存出库单 | 锁库存仍发生在库存服务创建出库单时,Temu 没有单独绕开库存锁逻辑 |
分仓到万邑通仓时,是否创建物流系统运单有 Temu 特殊判断:
- 非万邑通仓发货:通常需要创建物流系统运单。
- 万邑通仓发货且万邑通 3PL 渠道:需要创建物流系统运单。
- 万邑通仓发货且物流商是 Temu 或 TikTokShop:也需要创建物流系统运单。
- 其他万邑通场景:不一定创建物流系统运单。
创建库存出库单时,Temu 物流商还有一个细节:如果是 Temu 线上物流并且仓库能匹配到万邑通仓,系统会把平台物流渠道映射成仓库侧需要的发货方式;如果不是万邑通仓,则不需要这个仓库发货方式。
对应业务定位:
- Temu/平台物流是否创建系统运单:判断万邑通仓和 Temu 物流商是否需要生成物流系统运单(
AllocateWarehouseLogisticsHandle.isPushLogistics)。 - Temu 物流系统运单创建:配货时向物流服务创建物流系统运单(
AllocateWarehouseLogisticsHandle.createLogisticsOrder)。 - Temu 出库单物流方式映射:给库存出库单补充仓库侧发货方式(
InventoryBizServiceImpl.obtainDeliveryWayId)。 - Temu Y2 预售物流辅助校验:判断 Y2 预售订单是否没有使用 Temu 物流商(
TemuPackHelper.checkTemuY2OrderNotUseTemuLogistics)。
注意:Y2 预售“必须选择 Temu 物流”的辅助校验代码是存在的,但在当前看到的主配货流程里调用处有注释痕迹。也就是说,业务规则有这个口子,实际是否强制生效要以当前部署版本和配置为准,别在面试里把注释掉的逻辑吹成铁律,容易翻车。
9.5 Temu 标发流程
Temu 标发和普通平台最大的差异是:它不是只拿 ERP 订单号和一个追踪号去平台打一枪,而是要把 ERP 订单明细、履约单包裹、包裹明细和历史标发记录拼成一张“可标发表”。
Temu 标发主流程:
flowchart TD
A["触发 Temu 标发"] --> B["按订单加标发锁"]
B --> C["校验是否允许标发"]
C --> D{"Temu 线上物流或人工导入?"}
D -- "是" --> D1["不走普通 Temu 标发"]
D -- "否" --> E["读取订单明细、履约包裹、包裹明细、历史标发记录"]
E --> F["构造 Temu 可标发表"]
F --> G["按追踪号分组"]
G --> H["匹配 Temu 承运商和店铺发货仓"]
H --> I["组装 Temu 发货确认请求"]
I --> J["调用 Temu 发货确认接口"]
J --> K{"平台返回成功?"}
K -- "否" --> K1["记录标发失败原因"]
K -- "是" --> L["标记本次成功项"]
L --> M["保存本地标发记录"]
M --> N["更新 ERP 订单标发结果"]
标发的关键业务规则:
- Temu 线上物流业务无需普通标发,系统会直接拦住这类订单。
- 人工导入的 Temu 订单如果缺少 Temu 子订单号,也不做普通标发。
- 标发表按 Temu 子订单号和 ERP 包裹关联,一个子订单拆成多个包裹、多个子订单合并一个追踪号,都能表达。
- 请求 Temu 时按追踪号分组,一个追踪号对应一个发货包裹,包裹里包含多个 Temu 子订单发货明细。
- 发货类型会区分:单子订单单包裹、单子订单拆多个运单、多个子订单合并发货。
- 标发成功后会保存本地标发记录,后续重复标发时通过历史记录判断哪些包裹已经标过。
对应业务定位:
- Temu 平台标发入口:Temu 发货信息回传入口(
OrderApi.markShipTemu,路径/markship/temu)。 - Temu 标发加锁与前置校验:避免同一订单并发标发,并过滤线上物流/人工导入订单(
TemuShipServiceImpl.markShip/markNotSupportOrder)。 - Temu 可标发表构造:把订单明细、履约包裹、包裹明细、历史标发记录拼成可标发表(
TemuTrackingFinderImpl.find/TemuMarkTable.of)。 - Temu 发货确认调用:按追踪号分组并调用 Temu 发货确认接口(
TemuOrderShipApiAdapter.markShip/execMarkShip)。 - Temu 标发记录保存:保存本次成功标发的包裹、追踪号、发货类型(
TemuShipServiceImpl.saveShipments)。
9.6 Temu 平台状态同步与取消处理
Temu 平台状态回流主要靠重新查询 Temu 源订单状态来判断:
- 如果平台订单已发货,ERP 可以把订单推进到已发货,或接受“已标发”的标签结果。
- 如果平台订单已取消,ERP 可以把订单推进到已取消,或触发取消回调。
- 如果下单用户在 Temu 平台取消订单,系统处理原则仍然和通用取消一致:越早取消成本越低,越晚取消越要走拦截、释放库存、通知仓库或人工处理。
Temu 取消要结合履约阶段判断:
| 取消发生时点 | 系统处理思路 |
|---|---|
| 还没生成履约单/还在待审核 | 同步到平台取消状态后,ERP 订单可以直接取消,不再继续履约 |
| 已生成履约单但未配货 | 取消履约单和订单,通常不涉及库存释放 |
| 已配货但未派单 | 需要取消履约单,并释放已经由出库单占用的待发库存 |
| 已派单/仓库处理中 | 需要走仓库拦截;仓库如果已经处理,可能只能等待回调或人工处理 |
| 已出库/已标发 | ERP 侧通常不能按普通取消处理,需要进入售后、退货或异常处理 |
对应业务定位:
- Temu 平台发货状态回查:查询 Temu 源订单并判断是否已发货(
TemuSyncPlatformStrategy.orderIsShipped)。 - Temu 平台取消状态回查:查询 Temu 源订单并触发取消处理(
TemuSyncPlatformStrategy.orderIsCancelled)。
9.7 Temu 全托管/发货单数据同步补充
还有一条容易和卖家履约混淆的线:Temu 发货单/包裹同步。它主要面向全托管店铺,按最近发货时间窗口拉取 Temu 发货单和包裹信息并落库。这条线更像平台侧发货数据沉淀,不是普通卖家履约订单从 ERP 配货、派单、出库的主链路。
对应业务定位:
- Temu 发货单包裹同步:同步 Temu 发货单和包裹信息(
SyncShipOrderTask.syncShipOrder/syncShipOrderPackage)。
9.8 Temu 流程面试答法
面试时可以这样讲:
Temu 订单进入系统后,首先由同步服务拉取父订单和子订单。系统只把父订单待发货、且存在卖家履约子订单的订单发送到履约服务;合作仓履约子订单不会走普通卖家履约。履约服务消费后,会按 Temu 父订单号查 ERP 已有订单,首次同步创建待审核订单,后续同步只追加新出现的卖家履约子订单。审核后进入通用履约链路,完成分仓、分物流、配货锁库存、派单和出库。库存占用仍然在库存服务创建出库单时完成。出库后 Temu 标发按子订单、包裹、追踪号组织数据,支持部分发货、拆包、合并发货;Temu 线上物流和人工导入订单不走普通标发。平台状态再通过回查 Temu 源订单同步已发货或已取消状态。
10. 关键代码定位
以下代码名词只用于定位,业务理解以前文为准。
| 业务动作 | 代码定位 |
|---|---|
| 履约侧创建物流系统运单 | creeks-fulfillment-server/.../AllocateWarehouseLogisticsHandle.java#createLogisticsOrder |
| 履约侧生成运单失败打标 | creeks-fulfillment-server/.../AllocateWarehouseLogisticsHandle.java#pushLogistics |
| 履约侧提交配货 | creeks-fulfillment-server/.../PackageServiceImpl.java#submitInventory |
| 履约侧执行分仓分物流配货 | creeks-fulfillment-server/.../AllocateWarehouseLogisticsHandle.java#saveAllocatePack |
| 履约侧新版配货主流程 | creeks-fulfillment-server/.../AllocateWarehouseLogisticsHandle.java#saveAllocatePackV2 |
| 履约侧单仓配货过程 | creeks-fulfillment-server/.../AllocateWarehouseLogisticsHandle.java#allocatePackage |
| 履约侧分配具体货物库存 | creeks-fulfillment-server/.../PackageAllocateServiceImpl.java#buildOutboundStockDetail |
| 履约侧调用库存服务创建出库单 | creeks-fulfillment-server/.../PackageAllocateServiceImpl.java#createOutboundOrder |
| 库存侧创建出库单并获取库存锁 | creeks-inventory-server/.../OutboundOrderServiceV2Impl.java#createOutboundOrder |
| 库存侧新版锁库存库存变更 | creeks-inventory-server/.../InvOutboundOrderServiceImpl.java#buildDeductAvailableAndAddPendQuantityCmdAndExecute |
| 库存侧执行库存数量变更 | creeks-inventory-server/.../InventoryOperationServiceImpl.java#executeInventoryOperation |
| 库存侧老版锁库存入口 | creeks-inventory-server/.../ConnectOutboundServiceImpl.java#createOutboundOrder |
| 履约侧派单入口 | creeks-fulfillment-server/.../PackageApi.java#/dispatchWarehouse |
| 履约侧执行派单 | creeks-fulfillment-server/.../PackageServiceImpl.java#dispatchWarehouse、#doPackageDispatch |
| 库存侧接收出库单推送 | creeks-inventory-server/.../OutboundOrderServiceImpl.java#pushOrders |
| 库存侧异步推送仓库 | creeks-inventory-server/.../OutboundJobServiceImpl.java#processPushOutbound |
| 履约侧处理派单结果 | creeks-fulfillment-server/.../PackageOrderServiceImpl.java#processPackageDispatchResult |
| 物流侧创建系统运单 | creeks-logistics-server/.../LogisticsOrderServiceImpl.java#createLogisticsOrder |
| 物流侧申请运单入口 | creeks-logistics-server/.../LogisticsOrderServiceV1.java#/applyWaybillNumber |
| 物流侧申请运单校验和转申请中 | creeks-logistics-server/.../LogisticsOrderServiceImpl.java#applyWaybillNumber |
| 物流侧异步调用物流商 | creeks-logistics-server/.../LogisticsAsyncServiceImpl.java#applyWaybillNumber |
| 物流商策略入口 | creeks-logistics-server/.../strategy/LogisticsProviderServiceImpl.java#applyWaybillNumber |
| 物流成功消息发送 | creeks-logistics-server/.../LogisticsPushServiceImpl.java#sendLogisticsOrderResp |
| 履约侧消费物流成功消息 | creeks-fulfillment-server/.../LogisticsTrackingListener.java#process |
| 履约侧更新履约单物流信息 | creeks-fulfillment-server/.../PackageItemServiceImpl.java#updateTracking |
| 履约侧处理申请运单失败 | creeks-fulfillment-server/.../PackageServiceImpl.java#logisticsApplyTrackingFailure |
| 履约侧修复后重新提交物流 | creeks-fulfillment-server/.../PackageServiceImpl.java#packageSubmitLogistics |
| Temu 拉单任务 | esync-temu/.../SyncOrderTaskJob.java#syncStoreOrder |
| Temu 收货信息补全 | esync-temu/.../SyncOrderTaskJob.java#getOrderRecipient、#requestTemuGetShippingInfo |
| Temu 履约消息发送 | esync-temu/.../MessageProducer.java#sendOrderFulfillmentMessage |
| Temu 履约消息消费 | creeks-fulfillment-server/.../TemuOrderConsumer.java#process |
| Temu ERP 订单创建/追加 | creeks-fulfillment-server/.../TemuOrderConsumer.java#processOrder |
| Temu 子订单明细转换 | creeks-fulfillment-server/.../TemuOrderConsumer.java#convertOrderItem |
| Temu Y2 预售订单识别 | creeks-fulfillment-server/.../TemuOrderConsumer.java#markY2OrderLabel |
| Temu Y2 订单/包裹标签传递 | creeks-fulfillment-server/.../OrderPackHelp.java#buildOrderTags、#buildTemuPackageTags |
| Temu Y2 预售物流辅助校验 | creeks-fulfillment-server/.../TemuPackHelper.java#checkTemuY2OrderNotUseTemuLogistics |
| Temu/平台物流是否创建系统运单 | creeks-fulfillment-server/.../AllocateWarehouseLogisticsHandle.java#isPushLogistics |
| Temu 出库单物流方式映射 | creeks-fulfillment-server/.../InventoryBizServiceImpl.java#obtainDeliveryWayId |
| Temu 平台标发入口 | creeks-fulfillment-server/.../OrderApi.java#/markship/temu |
| Temu 标发服务 | creeks-fulfillment-server/.../TemuShipServiceImpl.java#markShip |
| Temu 可标发表构造 | creeks-fulfillment-server/.../TemuTrackingFinderImpl.java#find、TemuMarkTable.java#of |
| Temu 发货确认接口调用 | creeks-fulfillment-server/.../TemuOrderShipApiAdapter.java#markShip、#execMarkShip |
| Temu 平台状态同步 | creeks-fulfillment-server/.../TemuSyncPlatformStrategy.java#orderIsShipped、#orderIsCancelled |
| Temu 发货单包裹同步 | esync-temu/.../SyncShipOrderTask.java#syncShipOrder、#syncShipOrderPackage |
11. 面试化提炼
11.1 面试官常问的问题
| 面试问题 | 建议回答重点 |
|---|---|
| 你们的订单履约主流程是什么? | 平台订单同步后生成履约单,履约单完成分仓、分物流、配货锁库存,再派单给仓库/WMS,仓库出库后回写物流信息,最后向平台标发。 |
| 订单状态和履约单状态有什么区别? | 订单状态是销售订单视角,粒度粗;履约单状态是执行视角,仓库、物流、出库都围绕履约单推进。 |
| 配货、派单、申请运单分别是什么? | 配货负责确定仓、物流和库存并生成出库单;派单负责把出库任务推给仓库;申请运单负责向物流商拿正式运单号、追踪号、面单。 |
| 库存是在什么时候锁的? | 业务上在配货阶段锁,技术上在库存服务创建出库单时锁;库存服务把可用库存减少、待发库存增加。 |
| 为什么履约服务不直接扣库存? | 库存一致性和防超卖应该收敛到库存服务,履约服务只做业务编排和预分配,最终库存变更由库存服务统一加锁和落库。 |
| 派单有没有分布式事务问题? | 有。履约、库存、WMS、Kafka 回调都参与,外部 WMS 不能跟数据库事务一起回滚,只能靠幂等、补偿、重试和人工处理保证最终一致。 |
| 申请运单为什么也不是强一致? | 物流商接口是外部副作用,成功/失败结果通过消息或回调异步同步,链路天然是最终一致。 |
| 取消订单怎么处理? | 如果还没配货,可以直接取消;如果已配货或已派单,需要走拦截/释放库存/通知仓库等补偿链路,越靠后成本越高。 |
| Temu 订单为什么只处理卖家履约? | Temu 子订单有卖家履约和合作仓履约两类,ERP 普通履约链路只负责卖家履约;合作仓履约不是由卖家仓配发货,不能硬塞进同一套流程。 |
| Temu 后续同步为什么还会追加子订单? | Temu 子订单履约类型可能变化,原来合作仓履约的子订单可能变成卖家履约,所以后续同步要识别新增卖家履约子订单并追加到待审核订单或新订单。 |
| Temu 标发和普通平台有什么不同? | Temu 标发按子订单、履约包裹、追踪号组织数据,支持部分发货、拆包和合并发货;不是订单级一个追踪号直接标完整单。 |
| Temu 线上物流为什么无需普通标发? | Temu 线上物流由平台物流链路承接,系统会识别 Temu 物流商并跳过普通标发,避免重复向平台声明发货。 |
11.2 一分钟项目表达
可以这样讲:
我们的履约链路是围绕履约单推进的。平台订单进来后先生成履约单,履约单在配货阶段完成分仓、分物流和库存占用。库存占用不是履约服务直接扣库存,而是履约服务创建库存出库单,由库存服务在库存维度加锁,把可用库存转成待发库存。配货完成后履约单进入已配货,再派单给仓库或 WMS。运单申请由物流服务向物流商异步申请,成功后通过消息回写履约和库存,并触发平台标发。整个链路不是强一致事务,核心靠库存服务集中防超卖、各环节幂等、异步补偿和失败标签兜底。
如果面试官追问 Temu,可以接着补一句:
Temu 的特殊点在接单过滤和标发。接单时只处理待发货且存在卖家履约子订单的订单,合作仓履约不走普通 ERP 履约。标发时按 Temu 子订单、ERP 包裹、追踪号构造发货请求,能处理部分发货、拆包、多子订单合并发货;Temu 线上物流和人工导入订单不走普通标发。
11.3 技术亮点
- 状态拆分清楚:订单状态管销售侧结果,履约单状态管执行过程,标签承载异常和处理中状态。
- 库存职责收敛:履约服务不直接改库存,最终库存占用由库存服务统一加锁、统一扣减、统一记账。
- 防超卖设计:履约侧先预校验,库存侧最终加锁扣减,扣成负数会失败回滚。
- 异步最终一致:派单、申请运单、仓库回调、平台标发都不假装强事务,靠消息、补偿和幂等推进。
- 失败可运营:生成运单失败、申请运单失败、派单失败都通过标签暴露给运营处理。
- 平台差异可扩展:Temu 把卖家履约过滤、Y2 预售标签、线上物流、子订单级标发收敛在平台专属策略里,通用履约链路继续保持稳定。
11.4 容易被追问的坑
- “配货中”标签只是防重复处理和页面状态,不等于库存已经锁住。
- 履约侧查到有库存不代表最终一定能配成功,最终以库存服务创建出库单的锁内校验为准。
- 待发库存就是业务上的锁定库存,不是已经物理出库;真正出库后才会进一步扣待发和总库存。
- 全局事务不能解决 WMS、物流商、Kafka 这类外部副作用,别在面试里吹成强一致。
- 标签和主状态混用是这个项目的复杂点,改状态机时必须先区分主状态、异常标签、处理中标签。
- Temu 合作仓履约不要讲成 ERP 发货;系统普通履约只吃卖家履约子订单。
- Temu Y2 预售物流校验的辅助能力存在,但当前主流程调用处有注释痕迹,实际强制程度要看部署版本。
- Temu 线上物流无需普通标发,别拿普通平台的“出库后统一标发”套死 Temu。
12. 一句话结论
这套订单履约链路本质上是“订单粗状态 + 履约单执行状态 + 标签异常状态 + 跨服务异步回调”组合出来的状态机。配货负责确认仓库、物流和库存,并在创建库存出库单时完成库存占用;派单负责让仓库干活;申请运单负责让物流商给正式物流凭证;标发负责告诉平台订单已发货。Temu 在这条主链路上多了卖家履约子订单过滤、Y2 预售标签、线上物流判断和子订单级标发。系统不是强一致架构,关键链路必须靠幂等、补偿、重试和人工异常处理兜底,否则状态一旦断在 Kafka、Feign 或外部 WMS/物流商接口上,就会变成页面看着没动、外部系统已经跑飞的烂账。