Files

313 lines
15 KiB
Markdown
Raw Permalink Normal View History

2026-09-18 16:48:32 +08:00
# 阶段六:海外排车、出库、派送与最终回写
> 对应全景流程:F34~F40。
> 阶段起点:尾程订单已经 `INBOUND_COMPLETED`,存在可用库存且没有阻断本次履约的暂扣或库存锁。
> 阶段终点:派送完成并带签收证据,跨区回写国内;对应国内入库单为 `DELIVERED`,同一 Order 全部有效入库单完成后 Order 为 `COMPLETED`。
> 出库、排车、派送和异常是独立子状态,不覆盖尾程主状态。
## 1. 阶段目标和边界
本阶段完成海外仓最后一段实物与数据闭环:
1. 从真实库存生成智能预排和正式排车;
2. 发车前将排车转换为车辆级出库单和按目的地拆分的派送单;
3. PDA 按托盘拣货、扣减库存并在满足组合门禁后发车;
4. 执行一件代发、换标、转运、退货等独立出库任务;
5. 上传签收资料并自动完成派送;
6. 对派送异常执行来源受控的退回入仓;
7. 保存客户回访并将完成事实回写国内订单。
“扫码拣货”“出库”“发车”“开始派送”“签收完成”是不同节点。库存只在成功的 PDA 拣货/出库事务按契约扣减,发车不能再次扣库存。
## 2. 角色和终端
| 角色 | 终端 | 主要操作 |
|---|---|---|
| 海外调度 | Admin | 智能预排、排车编辑/取消、转派送、维护车辆与预约 |
| 海外仓 PDA 操作员 | 海外 PDA | 排车拣货、独立出库拣货、完成任务、发车 |
| 派送运营 | Admin | 开始派送、维护允许状态、上传 BOL/签收资料 |
| 企业成员 | Client | 查看本企业派送单、状态和允许下载的签收资料 |
| 异常处理员 | Admin | 创建异常、选择原出库事实、处理退回入仓 |
| 客服 | Admin | 客户回访、记录结果和附件 |
| Lastleg | 后端 | 排车、出库、派送、异常、库存命令和完成 Outbox 权威 |
| Firstleg/Order | 国内后端 | 幂等消费完成事件,推进 `DELIVERED/COMPLETED` |
PDA 只调用 `/api/pda/**` 专用接口,客户和仓库由 Token、Gateway 和服务端解析;派送与客户回访由 Admin/Client 承载,不进入 PDA。
## 3. 出库资格前置检查
- 尾程订单已 `INBOUND_COMPLETED`;
- 实际海外仓、目的仓和客户归属明确;
- 库存余额、位置、托盘组成和可用箱数一致;
- 无有效暂扣;
- 换标需要客户确认的,已完成确认;
- 转运、退货或废弃的库存锁与本次出库不冲突;
- 一件代发箱唛/SKU 状态为可用;
- 实物托盘和库位版本仍有效;
- 车辆、车队和目的地使用有效主数据。
任何不确定的库存、锁或归属查询都应失败关闭,不能通过前端勾选强行出库。
## 4. F34 智能预排和排车维护
### 4.1 候选和草稿锁
入口:Admin → 海外仓 → 排车管理/智能预排。
候选来自真实入仓计划、已收托盘或具备资格的换标库存。平台可跨客户查看候选,但创建时服务端从所选托盘解析并校验唯一客户范围和唯一海外仓。
1. 创建随机草稿;
2. 搜索并选择托盘;
3. 托盘加入草稿时立即按操作人和草稿标识加锁;
4. 移除托盘或关闭草稿时释放;
5. 草稿超时后锁自动失效;
6. 其他草稿/正式排车不能重复占用同一库存。
### 4.2 预排创建
1. 选择车型;
2. 核对托位、箱数、重量、目的 FBA 仓或私人地址;
3. 查看服务端汇总路线;
4. 点击预排;
5. 服务端重查托盘、库存、锁和客户范围;
6. 草稿锁原子转换为正式排车锁;
7. 生成排车单,初始为 `PENDING_DEPARTURE`。
路线由已排托盘目的仓编码去重并稳定排序生成,预排和普通编辑都不接收人工路线文本。
### 4.3 排车编辑和取消
可维护:车牌、司机、电话、车队、预计发车/到达、FBA 预约和车辆预约。普通编辑不能修改排车状态。
未执行、未产生不可逆拣货事实的排车可取消并释放正式锁。开始拣货后不能用取消恢复库存或抹掉作业历史。
## 5. F35 排车转派送
允许状态:`PENDING_DEPARTURE`、`PICKING`、`READY_TO_DEPART`,且必须早于发车。
入口:Admin → 排车详情 → 转派送。
1. 填写预计派送时间;
2. 选择派送方式、提货/装车类型;
3. 选择车队/快递、车辆和预约;
4. 维护费用来源和必要备注;
5. 核对所有托盘都已经真实入仓且仍由本排车锁定;
6. 二次确认后提交。
服务端幂等生成:
- 一张车辆级 `WAIT_OUTBOUND` 出库单;
- 按目的 FBA 仓或私人地址拆分的一张或多张 `WAIT_DELIVERY` 派送单;
- 派送费用只发布一次;
- BOL 和签收资料绑定拆分后的单仓派送单。
相同排车重放返回既有单据,不重复生成出库、派送或费用。
## 6. F36 排车 PDA 拣货和发车
### 6.1 打开任务
入口:海外 PDA → 排车拣货。
1. 查看当前 Token 仓库的任务;
2. 打开排车单,核对排车号、车辆、目的地、托盘和计划箱数;
3. 页面使用服务端返回的状态和版本,不按本地草稿推断可操作性。
### 6.2 扫托盘拣货
1. 扫描托盘业务码;
2. 服务端校验托盘属于本排车、当前仓库和有效库存位置;
3. 校验计划箱数和托盘组成;
4. 在成功事务中完成库存分配、拣货和相应出库扣减;
5. 写库存流水、任务进度和幂等记录;
6. 重复同一命令返回原结果,不再次扣减。
部分出库若不能整托核平,应先通过合法拆托或组成明细处理,不能按 FIFO 猜测某票来源。
### 6.3 完成拣货
全部托盘和箱数核平后,PDA 任务进入 `COMPLETED`,排车进入 `READY_TO_DEPART`。存在漏托、数量差异、暂扣或库存版本冲突时不能完成。
### 6.4 发车门禁
PDA 只使用详情返回的 `canDepart` 和 `departBlockReason`。服务端至少校验:
- 车辆信息完整;
- 拣货任务完成且箱数核平;
- 排车为 `READY_TO_DEPART`;
- 平台已经转派送;
- 关联出库单仍为 `WAIT_OUTBOUND`。
发车成功后排车进入 `DEPARTED`,出库单进入 `OUTBOUNDED`,释放相应托盘锁。发车只推进履约事实,不再次扣库存。
## 7. F37 独立出库任务
### 7.1 通用生命周期
独立出库通常按 `WAIT_PICK → PICKING → PICKED → OUTBOUNDED` 推进。只有尚未开始的 `WAIT_PICK/WAIT_OUTBOUND` 可以取消;作业开始后不能通过取消自动恢复库存。
PDA 操作:打开本仓任务 → 扫箱/托盘 → 核对来源 → 幂等提交 → 数量核平 → 完成出库。
### 7.2 一件代发出库
- 候选必须已完成入仓,仍有可用箱唛、SKU 和库存位置;
- 创建时必须解析为唯一客户和唯一仓,禁止跨客户/跨仓一单;
- 可逐箱扫描;
- 扫 `DP` 托盘码时原子拣取当前任务内该托全部剩余箱件和 SKU;
- 任一库存明细失败时整托回滚;
- 完成后箱唛、SKU 汇总、库存位置和流水必须核平。
### 7.3 换标、转运和退货出库
| 类型 | 前置 | 作业依据 | 结果 |
|---|---|---|---|
| 换标出库 | 仓库作业完成且客户确认 | 换标后箱唛、托盘和改绑快照 | 换标单完成、出库 `OUTBOUNDED` |
| 仓储转运 | 申请审核通过 | 冻结来源托盘和箱数 | 转运出库完成 |
| 退货出库 | 退货箱/SKU 可用 | 冻结退货库存 | 退货库存扣减、出库完成 |
退货出库不能与派送异常退回库存恢复混用;前者消费退货库存,后者恢复原出库来源库存。
## 8. F38 派送和签收
派送单状态:`WAIT_DELIVERY → DELIVERING → DELIVERED`,异常情况下可为 `REJECTED/CANCELLED/RETURNED`。
### 8.1 查看和开始派送
Admin/Client 按权限查看拆分后的单仓派送单、目的地、车辆/快递、预约、BOL 和状态历史。客户只能查看本企业。
平台核对实际出库后开始派送,使单据进入 `DELIVERING`。不能仅因排车发车就把所有拆分派送单自动视为签收。
### 8.2 上传签收资料并完成
1. 打开具体派送单;
2. 上传该目的仓对应的签收文件/照片;
3. 核对文件归属、类型和有效性;
4. 保存签收资料;
5. 系统在同一业务流程自动将该派送单推进为 `DELIVERED`;
6. 按关联 `sourceInboundId` 写 `OVERSEAS_DELIVERY_COMPLETED` Outbox。
不提供脱离签收资料的人工“完成派送”按钮。同车不同 FBA 仓的派送单互不代完成。
## 9. F39 派送异常退回
入口:Admin → 异常订单。
1. 从原派送单创建异常,状态为 `PENDING`;
2. 退回明细只能从原出库拣货事实选择,不能自由填写 SKU 或数量;
3. 开始处理后进入 `PROCESSING`;
4. 选择服务端校验的真实退回仓、托盘和库位;
5. 上传 `OVERSEAS_EXCEPTION_EVIDENCE`;
6. 现场确认退回实收;
7. 服务端按原出库来源恢复库存并写 `RETURN_STOCK_IN` 流水;
8. 同事务完成异常并将派送置为 `RETURNED`。
只有待处理异常可以取消。库存恢复、异常完成和派送退回任一步失败时整体回滚,不留下“派送已退回但库存未恢复”的半套结果。
## 10. F40 客户回访和国内最终回写
### 10.1 客户回访
入口:Admin → 客户回访。
客服选择已完成或需跟进的业务单,记录联系时间、方式、结果、问题、后续动作和附件。回访是服务闭环资料,不替代签收、异常或库存事实。
### 10.2 跨区完成事件
每张实际完成的派送单在业务事务内写 Outbox。Event Bridge 跨区投递后,Firstleg:
1. 校验内部身份、事件版本、ID 和 Payload 哈希;
2. 校验来源订单、来源入仓单、入仓码和 FBA 目的仓;
3. 防止同车其他目的仓事件误完成本票;
4. 将对应国内入库单从 `LOADED` 推进为 `DELIVERED`;
5. 写状态历史和事件消费记录。
### 10.3 Order 最终完成
Firstleg 检查同一 Order 的全部有效入库单。只有全部都为 `DELIVERED` 时,才调用 Order 推进交易状态为 `COMPLETED`。
部分装载形成的余量子单、另一柜或另一目的仓尚未完成时,Order 不能提前完成。重复事件不得重复推进、重复写历史或重复生成费用。
## 11. 状态和数据流
```text
INBOUND_COMPLETED + 可用库存
→ 草稿锁 → 正式排车锁 → PENDING_DEPARTURE
→ 转派送:车辆级 WAIT_OUTBOUND + 目的地级 WAIT_DELIVERY
→ PDA 扫托扣库存 → READY_TO_DEPART
→ 发车:DEPARTED + OUTBOUNDED
→ 派送:DELIVERING → 签收资料 → DELIVERED
→ OVERSEAS_DELIVERY_COMPLETED
→ 国内入库单 DELIVERED
→ 同一 Order 全部完成后 COMPLETED
```
尾程主状态保持 `INBOUND_COMPLETED`,排车、出库、派送和异常精确状态分别保存在各自单据并汇总到 `sub_order_status`。
## 12. 异常与恢复
| 场景 | 处理方式 |
|---|---|
| 托盘被其他草稿锁定 | 不可选择,等待释放或超时 |
| 预排时库存变化 | 服务端拒绝,刷新候选重排 |
| 排车已开始仍取消 | 拒绝,走对应异常流程 |
| 未转派送就发车 | `canDepart=false`,Admin 先完成转派送 |
| PDA 扫错托盘 | 拒绝且库存不变 |
| 扫码超时 | 保留幂等键,查询服务端任务后重试 |
| 整托一项失败 | 整托回滚,不部分扣库存 |
| 车辆资料缺失 | `departBlockReason` 明示缺项 |
| 签收资料上传失败 | 派送保持未完成,重新上传 |
| 一车多目的地仅一单签收 | 只完成对应派送单 |
| 异常退回数量超原拣货 | 拒绝,不允许自由扩量 |
| 退回库存事务失败 | 异常/派送状态同步回滚 |
| 国内消费暂时失败 | 保留 Outbox/Inbox 受控重试,不手工完成国内单 |
| 完成事件重复 | 返回既有结果,不重复历史或费用 |
## 13. 全流程最终完成判定
测试环境综合证据 `baiyue-firstleg/reports/admin-full-postdeploy-66c2651b.json` 已覆盖 `phase4-overseas-dispatch`、`phase5-terminal-drayage`、`phase5-overseas-fulfillment`、客户服务和跨区回写模块,相关模块失败数均为 0。清单仍按具体派送单保留,最终上线前需要用业务柜次逐项复核。
2026-09-18 16:48:32 +08:00
- [ ] 排车候选来自真实、可用且未被其他业务占用的库存
- [ ] 草稿锁、正式锁和取消/完成释放均可追溯
- [ ] 排车路线由实际目的地生成
- [ ] 转派送只发生一次且早于发车
- [ ] PDA 拣货数量、托盘组成、库存扣减和流水一致
- [ ] 发车时服务端 `canDepart=true`
- [ ] 发车没有重复扣库存
- [ ] 每个目的地拥有独立派送单和签收资料
- [ ] 派送完成只由有效签收资料触发
- [ ] 异常退回时原出库来源、恢复库存和证据完整
- [ ] 完成事件按来源入仓单跨区幂等回写
- [ ] 国内入库单为 `DELIVERED`
- [ ] 同一 Order 全部有效入库单完成后才为 `COMPLETED`
- [ ] 客户可查询本企业最终状态和允许的签收资料
## 14. 易用性与数据流评审问题
1. 智能预排候选是否应直接显示不可选原因、锁定人和锁过期时间?
2. 车型、托位、箱数、重量和目的仓能否提供装载风险提示?
3. 转派送为何必须早于发车,页面是否在拣货阶段持续提示?
4. 排车、出库、派送三个编号和状态是否需要统一时间线和相互跳转?
5. PDA 扫码即扣库存的关键动作是否需要更强确认和撤销边界说明?
6. `canDepart/departBlockReason` 能否直接跳转到车辆、拣货或转派送缺项?
7. 一件代发逐箱与整托两种模式如何防止操作员重复选择?
8. 一车多目的仓时,签收资料上传如何降低绑错派送单的风险?
9. 派送异常是否需要标准原因、责任方、时限和赔付关联?
10. 退回入仓是否需要 PDA 专用入口,而不是只依赖后台操作?
11. 跨区回写延迟时,海外“已签收”和国内“未完成”如何向客服解释?
12. Order `COMPLETED` 前是否需要展示仍未完成的具体子入库单/柜次/目的仓?
## 15. 事实来源
- `docs/海外仓业务/README.md`
- `docs/海外仓业务/虫虫出海全流程人工验收手册.md`
- `apps/pda-overseas-uniapp/AGENTS.md`
- `apps/pda-overseas-uniapp/src/pages/dispatch/dispatch.vue`
- `apps/pda-overseas-uniapp/src/pages/outbound/outbound.vue`
- `baiyue-firstleg/lastleg-service/AGENTS.md`
- `baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/`
- `baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/`
- `baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/exceptionorder/`
- `baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/customervisit/`
- `baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/OverseasDeliveryCompletedConsumer.java`
- `baiyue-firstleg/order/AGENTS.md`