14 KiB
订单与出库
约定见 00-conventions.md。库存变化见 40-inventory.md。Phase 1 锁定。订单与出库单在 Phase 10 写迁移,波次、拣货、打包、发货在 Phase 11 写迁移。
订单是统一需求模型。表内没有平台专有字段。上游平台、店铺、ERP 只通过 channel、source_code、external_no 表达。平台报文的转换放在 Connector,不进这些表。
wms_order_line 对应领域模型里的 order item。
承运商主数据在 Phase 12。发货单上的 carrier_code、tracking_no 先作为普通字符串保存。
wms_order 订单
用途:出库需求。手工单、API、ERP、电商平台都落这张表。
| 字段 | 类型 | 可空 | 默认 | 说明 |
|---|---|---|---|---|
| id | BIGINT UNSIGNED | N | AUTO_INCREMENT | 内部主键 |
| tenant_code | VARCHAR(32) | N | 租户编码 | |
| order_no | VARCHAR(64) | N | 系统订单号 | |
| warehouse_code | VARCHAR(32) | N | 发货仓库 | |
| customer_code | VARCHAR(64) | N | 货主 | |
| channel | VARCHAR(32) | N | 来源通道 | |
| source_code | VARCHAR(64) | Y | 来源实例,如店铺或 ERP 连接编码;手工单为空 | |
| external_no | VARCHAR(64) | Y | 上游单号;手工单为空 | |
| status | VARCHAR(32) | N | draft | 状态 |
| version | INT UNSIGNED | N | 0 | 乐观锁 |
| remark | VARCHAR(500) | Y | ||
| created_at | TIMESTAMP | Y | ||
| updated_at | TIMESTAMP | Y |
索引:
| 名称 | 类型 | 字段 | 支撑的查询 |
|---|---|---|---|
| uk_tenant_order_no | UNIQUE | (tenant_code, order_no) | 按订单号查找 |
| uk_tenant_source_external | UNIQUE | (tenant_code, source_code, external_no) | 上游单去重 |
| idx_tenant_status_created | INDEX | (tenant_code, status, created_at) | 列表 |
channel:manual、api、erp、marketplace。
channel = manual 时 source_code 与 external_no 必须为 NULL。其他通道两者必填。MySQL 唯一索引对 NULL 不判重,因此多张手工单可以并存。
状态:
draft → confirmed → processing → shipped → completed
draft → cancelled
confirmed → cancelled
processing → cancelled (关联出库单尚未 shipped)
completed、cancelled 为终态。出库单进入 shipped 时,订单改为 shipped。不软删除。
wms_order_line 订单明细
用途:订单要发的 SKU 与数量。
| 字段 | 类型 | 可空 | 默认 | 说明 |
|---|---|---|---|---|
| id | BIGINT UNSIGNED | N | AUTO_INCREMENT | 内部主键 |
| tenant_code | VARCHAR(32) | N | 租户编码 | |
| order_no | VARCHAR(64) | N | 订单号 | |
| line_no | INT UNSIGNED | N | 行号 | |
| sku_code | VARCHAR(64) | N | SKU | |
| qty | DECIMAL(16,4) | N | 需求数量,大于 0 | |
| allocated_qty | DECIMAL(16,4) | N | 0 | 已分配,由出库分配回写 |
| created_at | TIMESTAMP | Y | ||
| updated_at | TIMESTAMP | Y |
索引:
| 名称 | 类型 | 字段 | 支撑的查询 |
|---|---|---|---|
| uk_tenant_order_line | UNIQUE | (tenant_code, order_no, line_no) | 定位明细 |
关联:wms_order。allocated_qty <= qty。
wms_outbound 出库单
用途:仓库执行单。第一阶段业务上一单一张出库单;表允许同一 order_no 对应多张出库单。无订单的手工出库 order_no 为空。
| 字段 | 类型 | 可空 | 默认 | 说明 |
|---|---|---|---|---|
| id | BIGINT UNSIGNED | N | AUTO_INCREMENT | 内部主键 |
| tenant_code | VARCHAR(32) | N | 租户编码 | |
| outbound_no | VARCHAR(64) | N | 出库单号 | |
| order_no | VARCHAR(64) | Y | 订单号 | |
| warehouse_code | VARCHAR(32) | N | 仓库 | |
| customer_code | VARCHAR(64) | N | 货主 | |
| status | VARCHAR(32) | N | draft | 状态 |
| version | INT UNSIGNED | N | 0 | 乐观锁 |
| created_at | TIMESTAMP | Y | ||
| updated_at | TIMESTAMP | Y |
索引:
| 名称 | 类型 | 字段 | 支撑的查询 |
|---|---|---|---|
| uk_tenant_outbound_no | UNIQUE | (tenant_code, outbound_no) | 按出库单号查找 |
| idx_tenant_order | INDEX | (tenant_code, order_no) | 订单下的出库单 |
| idx_tenant_status_created | INDEX | (tenant_code, status, created_at) | 列表 |
状态(与领域模型一致,并补上取消):
draft → allocated → picking → picked → packing → packed → shipped → completed
draft → cancelled
allocated → cancelled (必须释放预占)
completed、cancelled 为终态。禁止跳步。picking 之后取消不在本阶段打开,避免已拣库存没有回退规则。状态变更写 wms_status_log,biz_type = outbound。
短拣不新增头状态。行上的已拣数量可以小于需求数量,头状态仍按上面的路径走;是否允许短拣完成,在 Phase 11 做业务校验。
wms_outbound_line 出库明细
用途:出库单的 SKU 行。
| 字段 | 类型 | 可空 | 默认 | 说明 |
|---|---|---|---|---|
| id | BIGINT UNSIGNED | N | AUTO_INCREMENT | 内部主键 |
| tenant_code | VARCHAR(32) | N | 租户编码 | |
| outbound_no | VARCHAR(64) | N | 出库单号 | |
| line_no | INT UNSIGNED | N | 行号 | |
| order_line_no | INT UNSIGNED | Y | 对应订单行,无订单时为空 | |
| sku_code | VARCHAR(64) | N | SKU | |
| qty | DECIMAL(16,4) | N | 需求数量,大于 0 | |
| allocated_qty | DECIMAL(16,4) | N | 0 | 已分配 |
| picked_qty | DECIMAL(16,4) | N | 0 | 已拣 |
| packed_qty | DECIMAL(16,4) | N | 0 | 已打包 |
| shipped_qty | DECIMAL(16,4) | N | 0 | 已发 |
| created_at | TIMESTAMP | Y | ||
| updated_at | TIMESTAMP | Y |
索引:
| 名称 | 类型 | 字段 | 支撑的查询 |
|---|---|---|---|
| uk_tenant_outbound_line | UNIQUE | (tenant_code, outbound_no, line_no) | 定位明细 |
关联:数量由分配、拣货、打包、发货事务回写。shipped_qty <= packed_qty <= picked_qty <= allocated_qty <= qty。
wms_outbound_allocation 库存分配
用途:出库行占住的具体库位与批次。分配成功才把可用转为预占。
| 字段 | 类型 | 可空 | 默认 | 说明 |
|---|---|---|---|---|
| id | BIGINT UNSIGNED | N | AUTO_INCREMENT | 内部主键 |
| tenant_code | VARCHAR(32) | N | 租户编码 | |
| allocation_no | VARCHAR(64) | N | 分配号 | |
| outbound_no | VARCHAR(64) | N | 出库单号 | |
| line_no | INT UNSIGNED | N | 出库行号 | |
| sku_code | VARCHAR(64) | N | SKU | |
| location_code | VARCHAR(64) | N | 库位,不能是在途空库位 | |
| batch_no | VARCHAR(64) | N | '' | 批次 |
| qty | DECIMAL(16,4) | N | 分配数量,大于 0 | |
| status | VARCHAR(32) | N | allocated | 状态 |
| created_at | TIMESTAMP | Y | ||
| updated_at | TIMESTAMP | Y |
索引:
| 名称 | 类型 | 字段 | 支撑的查询 |
|---|---|---|---|
| uk_tenant_allocation_no | UNIQUE | (tenant_code, allocation_no) | 按分配号查找 |
| idx_tenant_outbound_line | INDEX | (tenant_code, outbound_no, line_no) | 某行的分配 |
状态:allocated → picked,allocated → cancelled。
创建时原子更新库存(可用减、预占加),流水 biz_type = reserve,biz_no = outbound_no。取消时反向,biz_type = release。拣货确认时预占减、已拣加,biz_type = pick,本行改为 picked。
全部需求行 allocated_qty = qty 后,出库单才从 draft 到 allocated。库存不足则整单分配回滚,不产生部分成功的预占。
wms_wave 波次
用途:把多张出库单放进一次拣货。不使用波次时,拣货任务的 wave_no 为空,按单拣货。
| 字段 | 类型 | 可空 | 默认 | 说明 |
|---|---|---|---|---|
| id | BIGINT UNSIGNED | N | AUTO_INCREMENT | 内部主键 |
| tenant_code | VARCHAR(32) | N | 租户编码 | |
| wave_no | VARCHAR(64) | N | 波次号 | |
| warehouse_code | VARCHAR(32) | N | 仓库 | |
| status | VARCHAR(32) | N | draft | 状态 |
| version | INT UNSIGNED | N | 0 | 乐观锁 |
| created_at | TIMESTAMP | Y | ||
| updated_at | TIMESTAMP | Y |
索引:
| 名称 | 类型 | 字段 | 支撑的查询 |
|---|---|---|---|
| uk_tenant_wave_no | UNIQUE | (tenant_code, wave_no) | 按波次号查找 |
| idx_tenant_wh_status | INDEX | (tenant_code, warehouse_code, status) | 仓库内的波次 |
状态:draft → released → picking → completed,draft → cancelled。释放波次时,关联出库单从 allocated 进入 picking。
wms_wave_outbound 波次与出库单
用途:波次包含哪些出库单。一张出库单同时只属于一个未取消的波次。
| 字段 | 类型 | 可空 | 默认 | 说明 |
|---|---|---|---|---|
| id | BIGINT UNSIGNED | N | AUTO_INCREMENT | 内部主键 |
| tenant_code | VARCHAR(32) | N | 租户编码 | |
| wave_no | VARCHAR(64) | N | 波次号 | |
| outbound_no | VARCHAR(64) | N | 出库单号 | |
| created_at | TIMESTAMP | Y | ||
| updated_at | TIMESTAMP | Y |
索引:
| 名称 | 类型 | 字段 | 支撑的查询 |
|---|---|---|---|
| uk_tenant_wave_outbound | UNIQUE | (tenant_code, wave_no, outbound_no) | 防止重复加入同一波次 |
| idx_tenant_outbound | INDEX | (tenant_code, outbound_no) | 查出库单所在波次 |
一张出库单同时只能属于一个未取消波次,由应用在加入时检查,不靠删除行来腾出唯一约束。波次取消后这些行保留,出库单回到 allocated。不软删除。
wms_pick_task 拣货任务
用途:拣货执行行。由分配生成。
| 字段 | 类型 | 可空 | 默认 | 说明 |
|---|---|---|---|---|
| id | BIGINT UNSIGNED | N | AUTO_INCREMENT | 内部主键 |
| tenant_code | VARCHAR(32) | N | 租户编码 | |
| picking_no | VARCHAR(64) | N | 拣货任务号 | |
| wave_no | VARCHAR(64) | Y | 波次,按单拣货时为空 | |
| outbound_no | VARCHAR(64) | N | 出库单号 | |
| allocation_no | VARCHAR(64) | N | 分配号 | |
| sku_code | VARCHAR(64) | N | SKU | |
| location_code | VARCHAR(64) | N | 拣货库位 | |
| batch_no | VARCHAR(64) | N | '' | 批次 |
| qty | DECIMAL(16,4) | N | 应拣数量 | |
| picked_qty | DECIMAL(16,4) | N | 0 | 实拣数量 |
| status | VARCHAR(32) | N | pending | 状态 |
| created_at | TIMESTAMP | Y | ||
| updated_at | TIMESTAMP | Y |
索引:
| 名称 | 类型 | 字段 | 支撑的查询 |
|---|---|---|---|
| uk_tenant_picking_no | UNIQUE | (tenant_code, picking_no) | 按任务号查找 |
| uk_tenant_allocation | UNIQUE | (tenant_code, allocation_no) | 一条分配一个任务 |
| idx_tenant_outbound | INDEX | (tenant_code, outbound_no, status) | 出库单的拣货任务 |
状态:pending → picked。确认拣货时 picked_qty 等于 qty(短拣规则 Phase 11 再放开),并完成分配行的库存桶转换。该出库单全部分配都已 picked 后,出库单才到 picked。
wms_package 包裹
用途:复核打包结果。一张出库单可有多个包裹。
| 字段 | 类型 | 可空 | 默认 | 说明 |
|---|---|---|---|---|
| id | BIGINT UNSIGNED | N | AUTO_INCREMENT | 内部主键 |
| tenant_code | VARCHAR(32) | N | 租户编码 | |
| package_no | VARCHAR(64) | N | 包裹号 | |
| outbound_no | VARCHAR(64) | N | 出库单号 | |
| status | VARCHAR(32) | N | open | 状态 |
| created_at | TIMESTAMP | Y | ||
| updated_at | TIMESTAMP | Y |
索引:
| 名称 | 类型 | 字段 | 支撑的查询 |
|---|---|---|---|
| uk_tenant_package_no | UNIQUE | (tenant_code, package_no) | 按包裹号查找 |
| idx_tenant_outbound | INDEX | (tenant_code, outbound_no) | 出库单的包裹 |
状态:open → sealed。全部应发数量进入已封箱包裹后,出库单从 packing 到 packed。打包不改变库存桶,只增加明细 packed_qty。
wms_package_line 包裹明细
用途:包裹里的 SKU 数量。
| 字段 | 类型 | 可空 | 默认 | 说明 |
|---|---|---|---|---|
| id | BIGINT UNSIGNED | N | AUTO_INCREMENT | 内部主键 |
| tenant_code | VARCHAR(32) | N | 租户编码 | |
| package_no | VARCHAR(64) | N | 包裹号 | |
| line_no | INT UNSIGNED | N | 行号 | |
| sku_code | VARCHAR(64) | N | SKU | |
| qty | DECIMAL(16,4) | N | 数量,大于 0 | |
| created_at | TIMESTAMP | Y | ||
| updated_at | TIMESTAMP | Y |
索引:
| 名称 | 类型 | 字段 | 支撑的查询 |
|---|---|---|---|
| uk_tenant_package_line | UNIQUE | (tenant_code, package_no, line_no) | 定位明细 |
关联:wms_package。封箱后不改行。
wms_shipment 发货
用途:出库单发出的记录。物流渠道主数据尚未建表,承运商与运单号先记在这里。
| 字段 | 类型 | 可空 | 默认 | 说明 |
|---|---|---|---|---|
| id | BIGINT UNSIGNED | N | AUTO_INCREMENT | 内部主键 |
| tenant_code | VARCHAR(32) | N | 租户编码 | |
| shipment_no | VARCHAR(64) | N | 发货单号 | |
| outbound_no | VARCHAR(64) | N | 出库单号 | |
| package_no | VARCHAR(64) | Y | 包裹号,整单发货可空 | |
| carrier_code | VARCHAR(64) | Y | 承运商编码,Phase 12 再约束到主数据 | |
| tracking_no | VARCHAR(64) | Y | 运单号 | |
| status | VARCHAR(32) | N | shipped | 状态 |
| shipped_at | TIMESTAMP | Y | 发货时间 | |
| created_at | TIMESTAMP | Y | ||
| updated_at | TIMESTAMP | Y |
索引:
| 名称 | 类型 | 字段 | 支撑的查询 |
|---|---|---|---|
| uk_tenant_shipment_no | UNIQUE | (tenant_code, shipment_no) | 按发货单号查找 |
| idx_tenant_outbound | INDEX | (tenant_code, outbound_no) | 出库单的发货记录 |
| idx_tenant_tracking | INDEX | (tenant_code, tracking_no) | 按运单号查 |
状态:shipped。本阶段发货即终态。同一事务把已拣数量减掉(离开仓库),流水 biz_type = ship,并回写出库明细 shipped_qty。出库单改为 shipped,若有订单则订单改为 shipped。之后出库单再进入 completed 只表示作业关闭,不再改库存。