4. 数据模型:采购订单、到货通知单与验收单的数据结构设计
在采购到货验收流程中,采购订单(PO)、到货通知单(ASN)与验收单(GRN)是三个核心数据载体。三者之间的数据结构设计直接决定了接口调用的复杂度、数据一致性以及异常处理的效率。本节将逐一拆解三张单据的核心字段、状态机与关联关系。
4.1 采购订单(PO)数据结构
采购订单是流程的起点,其数据结构需同时承载业务语义与履约跟踪能力。以下为精简后的核心字段模型:
| 字段组 | 字段名 | 类型 | 说明 |
|---|---|---|---|
| 头信息 | po_id | string(32) | 采购订单号,全局唯一 |
| supplier_code | string(20) | 供应商编码 | |
| po_status | int | 状态:10-待确认,20-已确认,30-部分到货,40-全部到货,50-已关闭 | |
| 行项目 | line_no | int | 行号,从1递增 |
| material_code | string(30) | 物料编码 | |
| order_qty | decimal(18,3) | 订购数量 | |
| received_qty | decimal(18,3) | 累计已收数量(冗余字段,用于快速校验) | |
| unit_price | decimal(18,4) | 含税单价 |
设计要点:累计已收数量(received_qty)属于反范式设计,目的是在查询PO剩余可收量时避免实时汇总验收单,提升接口响应速度。每次验收单确认后,需通过事务或最终一致性机制同步更新该字段。
4.2 到货通知单(ASN)数据结构
到货通知单由供应商或物流方提前发送,用于告知仓库即将到达的货物明细。ASN 的核心价值在于预知与预分配,其数据结构需与 PO 行项目严格对应。
| 字段组 | 字段名 | 类型 | 说明 |
|---|---|---|---|
| 头信息 | asn_id | string(32) | 到货通知单号 |
| po_id | string(32) | 关联采购订单号 | |
| asn_status | int | 状态:10-已创建,20-已到货,30-已取消 | |
| expected_arrival_time | datetime | 预计到货时间 | |
| 行项目 | line_no | int | 行号,与PO行号对应 |
| material_code | string(30) | 物料编码 | |
| asn_qty | decimal(18,3) | 通知到货数量 | |
| package_count | int | 包裹/托盘数 |
常见陷阱:ASN 行项目数量不能超过 PO 对应行项目的剩余可收量(order_qty - received_qty)。接口设计时必须在 ASN 创建接口中做此校验,否则会导致超收。
4.3 验收单(GRN)数据结构
验收单是实物入库的最终凭证,记录实际清点、质检结果。其数据结构需要同时支持合格入库、拒收退货与部分合格三种场景。
| 字段组 | 字段名 | 类型 | 说明 |
|---|---|---|---|
| 头信息 | grn_id | string(32) | 验收单号 |
| asn_id | string(32) | 关联到货通知单号 | |
| grn_status | int | 状态:10-待质检,20-部分入库,30-全部入库,40-已退货 | |
| 行项目 | line_no | int | 行号 |
| material_code | string(30) | 物料编码 | |
| accept_qty | decimal(18,3) | 合格入库数量 | |
| reject_qty | decimal(18,3) | 拒收数量 | |
| reject_reason | string(200) | 拒收原因代码或文本 | |
| warehouse_location | string(20) | 上架库位 |
4.4 三单关联关系与数据流转
三张单据通过外键与行号形成严格的链式引用:PO → ASN → GRN。以下 SVG 图展示了核心数据流转与状态变更路径:
4.5 接口调用中的字段映射清单
在动态调整场景中,接口调用方需要明确三单之间的字段映射关系,避免数据错位。以下为关键映射表:
| 源单据 | 源字段 | 目标单据 | 目标字段 | 映射规则 |
|---|---|---|---|---|
| PO | po_id | ASN | po_id | 直接复制 |
| PO | line_no + material_code | ASN | line_no + material_code | 按行号一一对应 |
| PO | order_qty - received_qty | ASN | asn_qty | 校验:asn_qty ≤ 剩余可收量 |
| ASN | asn_id | GRN | asn_id | 直接复制 |
| ASN | line_no + material_code | GRN | line_no + material_code | 按行号一一对应 |
| GRN | accept_qty | PO | received_qty | 累加:PO.received_qty += GRN.accept_qty |
4.6 动态调整场景下的数据一致性策略
当采购计划发生动态调整(如紧急加单、部分取消、到货日期变更)时,三单数据结构需要支持以下一致性保障:
- 乐观锁机制:PO 头信息与行项目增加 version 字段,更新 received_qty 时校验版本号,防止并发超收。
- 最终一致性回写:GRN 确认后通过异步消息(如 RocketMQ / Kafka)回写 PO.received_qty,允许秒级延迟,但需保证不丢失、不重复。
- 状态机防跳转:PO 状态从“已确认”不能直接跳转到“已关闭”,必须经过“部分到货”或“全部到货”中间态。
- 冗余校验字段:ASN 行项目增加 po_line_remaining_qty 快照字段,在创建时锁定剩余可收量,避免后续 PO 变更导致 ASN 失效。
实战建议:在接口设计文档中,将三单的数据结构定义放在同一章节,并使用统一的命名规范(如所有日期字段统一为 yyyy-MM-dd HH:mm:ss,所有金额字段统一保留4位小数)。这能显著降低联调阶段的沟通成本。