Files
docs/头程到尾程分阶段流程/阶段六-海外排车出库派送与回写.md
T

313 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 阶段六:海外排车、出库、派送与最终回写
> 对应全景流程: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。清单仍按具体派送单保留,最终上线前需要用业务柜次逐项复核。
- [ ] 排车候选来自真实、可用且未被其他业务占用的库存
- [ ] 草稿锁、正式锁和取消/完成释放均可追溯
- [ ] 排车路线由实际目的地生成
- [ ] 转派送只发生一次且早于发车
- [ ] 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`