Files
docs/海外仓业务/海外仓PDA拆柜收货改造方案评审稿.md
T

183 lines
22 KiB
Markdown
Raw Normal View History

2026-09-10 19:27:11 +08:00
# 海外仓 PDA 拆柜收货设计复核:现场效率优先
日期:2026-09-10。状态:业务设计评审稿,仅修改本文档,尚未实施业务代码。
本稿根据用户确认的真实操作及合并后的工作区代码复核,修正前序讨论中的不合理设计。后端读取基于 `5ffd6c01`,海外 PDA 基于 `cb1dfc5`;工作区同时存在其他未提交修改。代码引用证明检查时的实现,不代表测试环境已部署或真机已验收。
## 1. 已确认需求与评审结论
用户已确认:
- 一件代发在国内打好托;一个实物托盘只贴一个统一 DP 托盘码,每箱各有箱码。扫 DP 或托盘内任一箱码,都必须带出整个托盘,按整托收货。
- 同一个托盘允许包含多个客户的货。客户归属由后台处理,不能成为仓库扫码或混托的操作障碍。
- 普通 FBA 国内散货装柜,海外拆柜时按 FBA 目的仓打托。扫某一箱,带出当前柜该 FBA 的总箱数及全部相关入仓码;之后连续扫托盘,录入各托箱数。
- 一件代发、普通 FBA、海外仓中转均不展示客户名称、编号、客户数,不提供客户选择或绑定操作。
- 少货、超收暂时只记录差异,不建设完整异常处理流程。
- 一台 PDA 操作。当前任务是 review 和编写设计,不改业务代码。
评审结论:主方向可行,正常路径应收敛为“一件代发一次扫码收一托;FBA 一次扫箱选组,每托扫码加数量回车”。实现前必须处理跨客户托盘的下游约束,并明确 FBA 数量分摊的事实边界。以下推荐项尚未等同于用户逐项确认。
| 前序方案中的问题 | 本次推荐修正 | 对现场效率的作用 |
|---|---|---|
| 一件代发每托解析后再点确认 | 收货模式下扫即保存整托实收,成功音、最近记录、撤销 | 正常路径不点击屏幕 |
| FBA 每托开托、校验、提交、封托多次操作 | 扫托盘后输入本托总箱数,回车一次保存 | 一托只确认一次数量 |
| 每次提交清空当前入仓码/目的仓,再扫箱重新定位 | 持续保留 FBA 目的仓组,下一托直接扫码 | 同一 FBA 只需首次扫箱 |
| 整柜扫描结果只存在设备,最后统一保存 | 每笔在服务端保存收货事实,整柜结束时统一完成入库 | 退出、重试不必重新扫描整柜 |
| 自动分摊视作准确箱货位置,少货默认落最后一票 | 标明计划分摊;未知差异保留在目的仓组 | 避免把后续找货错误归咎于仓库 |
| DP 被定义为柜级对象,混托要求改整套客户事件 | DP 独立存在,封托后整托分柜;先定义清单完整性再选事件方案 | 国内打托不必等分柜,减少改造范围 |
## 2. 推荐现场流程
### 2.1 共用入口
选柜、现有签收照片完成后,进入一个持续可扫码的收货页面。由服务端根据当前柜、真实码映射、货物履约方式判定操作;不要求操作员先选客户、入仓单或 FBA/一件代发模式,不只用码前缀或目的仓类型猜业务。
页面首屏只保留当前柜、作业模式、当前目的仓/DP、总量/已收/待收、当前托盘、最近操作。入仓码列表可展开。SKU 和箱货详情供需要时查询,不让操作员逐项确认。DP 按“已收托数”显示进度,FBA 按“已收箱数+实际托数”显示进度。
查询功能保持只读;收货页面明确提示“扫描 DP 或一件代发箱码将接收整托”。异常提示使用仓库能处理的对象,例如“此码不属于当前柜”“该托已收”“托盘目的仓不匹配”,不显示客户选择提示。
### 2.2 一件代发:DP/箱码两个入口,一次扫码接收一托
```text
扫 DP ─────────┐
├→ 解析同一份已封托清单 → 保存整托实收 → 成功音 → 等待下一码
扫托内任意箱码 ┘
```
- 扫箱是定位整托,不能额外累计一箱;扫描成功后显示“DP…,本托45箱,已收”。
- 只接收当前柜内、完整清单已到齐、已封托且符合当前收货条件的 DP。查不到箱到托关系时提示,不能靠入仓码前缀推测它属于哪一托。
- 同一 DP 的多个箱码连续被扫,或 DP 与箱码交替扫描,都只产生一次有效整托实收。重复扫描提示“已收”,不弹阻塞对话框,不重复入账,也不把重复当作撤销。
- 成功后记录保存到服务端;“撤销最近一托/调整记录”是独立低频动作,整柜完成前允许,必须有反向记录和汇总更新。仅删除页面记录不算撤销。
- 扫码确认的是“按国内清单整托接收”,不能声称已在海外逐箱验货。发现破托、少箱时,选该托标记差异;只知道少几箱时不猜具体 SKU/客户。
- 国内已确认 DP 对应实物且清单完整时,海外资源由后台建立关联。正常路径不要求重新贴另一张业务托盘码或再扫一个海外码;若实际换托,则记录显式换托关系。
### 2.3 普通 FBA:一箱选组,每托扫码加箱数
```text
扫任意 FBA 箱码 → 显示当前柜 ONT8:100箱、3个入仓码
↓ 保留该目的仓上下文
扫托盘 P1 → 输入40 → 回车保存 → 等待下一托盘
扫托盘 P2 → 输入35 → 回车保存 → 等待下一托盘
扫托盘 P3 → 输入25 → 回车保存 → ONT8 已收100箱
```
- 首次扫箱只选择分组,不自动增加实收一箱,不要求每个入仓码都再扫一次。
- 分组包含当前来源柜、实际收货仓、普通 FBA 作业模式、稳定 FBA 目的仓身份;同目的地的一件代发不进入散货组,不跨柜聚合。
- 后台一次返回本组完整入仓码清单及箱数,不受订单列表分页限制。显示 `总箱数100 / 已收75 / 待收25`,入仓码核对默认展开与否按设备可读性确定,不新增逐票确认。
- 托盘扫描后直接聚焦数字键盘;校验融入扫码/保存请求,移除额外“校验托盘”“开托”“封托”按钮。回车是一次明确保存,不能仅靠扫描下一码隐式提交未确认数量。
- 数量字段明确为“本托累计实收箱数”。再次扫已收托盘显示现有数量,修改后替换原总量并按差额更新,不把改成45误解成再增加45。
- 保存后保留 FBA 组,清空当前托盘与数量。末托可预填剩余数,仍需回车确认,不能自动将计划剩余数算作实收。
- 切换到另一 FBA 或 DP 前,如果当前托盘有未保存数量,先保留并处理该笔;不能静默清空或把数量提交到新组。
- 沿用已生成的 FBA 托盘标签与后台资源准备。已有“柜号+FBA仓标识+序号”只表示标签/计划位置,不能宣称国内已形成实装托盘明细。跨入仓码混托不能受标签原先归属某客户/计划的限制。
- 计划托数用于资源和标签准备。100箱实际打3托,不因预生成4张标签而要求扫满4托。未用标签/预留资源由后台处理;需要额外托盘时提供一次补充动作,不重新给各入仓码建计划。
### 2.4 海外仓中转:先减少重复操作,再按交接粒度优化
已确认的是客户信息隐藏。前序答复把所有“海外仓中转”一概要求逐箱收货,依据不足;`destinationType=OVERSEAS` 是现有代码行为,不能据此认定所有中转业务都需要同一种颗粒度。
推荐本轮设计保留当前逐箱能力,同时使其“扫一次目标托盘,持续扫箱即绑定”,换托时才再扫托盘,不逐箱要求重复扫托或点确认。有可靠来源整托清单的货物可使用整托接收。纯散货中转若只按目的仓数量交接,可以另行采用 FBA 类似的计数操作;该变化需先明确后续是否按箱/订单挑货,当前不直接删除箱级追踪。
## 3. FBA 最关键的事实边界
假设入仓码 A、B、C 分别为30、40、30箱。仓库只提交 P1=40、P2=35、P3=25,可以确定目的仓共收100箱以及各托总箱数;无法确定 P1 内实际有多少 A/B/C,更不能确定各托具体 SKU。
若系统计算 P1=A30+B10,这只能是计划分摊。另一种真实摆放可能是 P1=A10+C30,同样满足已提交的数量。增加排序、算法或幂等机制都不能补出没有采集的事实。
推荐保留用户要的快速操作,后台明确区分:
| 数据 | 可以表达的含义 | 不得冒充的事实 |
|---|---|---|
| 每托实收箱数 | 海外现场记录的实物数量 | 每客户/入仓码/SKU的精确落托位置 |
| 国内 DP 箱货清单 | 已扫描、已封托的箱到托关系 | 海外已逐箱开箱复核 |
| FBA 完整组按计划确认 | 箱数相符,按来源清单接受该组 | 所有箱唛/SKU都经过现场验证 |
| FBA 后台数量分摊 | 可审计的账务/计划分摊 | 扫某托就保证能取出某客户指定货物 |
正常按目的仓统一交接可保持高速。后续按某客户、某入仓码、指定箱唛部分提货、扣货或换标时,必须读取这种精度差异:无法证明箱在哪托时,现场按所选箱码定位/拆托,并修订实际分配后出库。不能把推定分摊直接塞入现有精确拣货接口。若业务要求任意托盘都能准确按票出库,就必须增加按票/箱落托采集,不能同时声称“只录每托总数”且“精确到票”。
因此推荐将精准识别放在确实需要挑选具体货物的操作中;不要为所有正常 FBA 收货增加逐箱扫描。FBA 分组收货上线前,必须把此规则与现有排车/出库消费端一起落实。
## 4. 差异:允许结束现场作业,保留未核实事实
“只标记差异”不等于把计划数填成实收,也不等于责任已核清。
- FBA 计划100实收97:保存本组实收97、少货3。无法定位缺少哪票时,差异留在本组,不默认记给最后一个入仓码。不能声称所有入仓码已精确核平。
- FBA 计划100实收103:保存实物103及超出计划3;无归属的超出部分不得计入任意客户可用库存。不为了通过校验修改原计划100。
- 一件代发整托未收到:清单能确定该 DP 的缺失成员,可按来源明细标记未到。一托内部少几箱但未知箱码时,仅确定托级差异,不能随机减 SKU。
- 收到不属于当前柜的已知托盘:先作为错柜码拦住正常收货,不能当本柜超收并自动转移其他柜货权。
- 正常全部相符时,后台按来源清单完成各入仓码账;数量有差异且归属未知时,现场可结束,后台保留“差异待核”状态和相关已收事实。未核部分不凭自动分摊变成某客户可用货。
推荐整柜结束只出现一次汇总确认,正常无差异直接完成;有差异时一并确认差异数量即可,不要求仓库填写逐客户归责或新建异常单。没有结清差异不应迫使唯一 PDA 一直锁在上一柜。
实现必须区分“现场收货结束”和“账务核平/可用库存”。现有代码将完整入库、库存入账和柜级卸柜事件绑在一起,多层要求计划数等于实收数;不能只放开按钮。需定义正常完成、带差异结束的处理及完成事件真实含义:全柜实物已卸完才能形成卸柜完成事实,不能把差异结束自动解释为所有计划已足量入库。推荐现场结束、差异记录、可确认部分库存处理和对应 Outbox 在同一事务完成,不补造缺货库存;未知归属部分留在接收事实中待核。
## 5. 托盘与跨区数据的最小改造原则
1. **DP 先于柜存在。** 当前国内顺序是清点→绑托→封托→待分柜。DP 应是独立稳定托盘身份,箱明细持有客户/入仓码;分柜后建立装载关系。同一封托 DP 的成员原子分配到同一柜,不能把混托成员分别装不同柜。跨客户不必阻断,同一实际交接路径/业务约束仍由后台校验。
2. **公共实物资源已有,不重复建设。** `warehouse-overseas-service` 的托盘/库位已经是平台公共资源。改造重点是一个实物托盘对应多客户货物组成、统一物理占用、各自库存记账。保留现有独立客户订单/计划,不为了隐藏客户把所有订单合并成一张公共订单。
3. **客户隐藏在服务端。** PDA 专用响应省去客户名称/编号/客户数,写入只带扫码值、数量和必要业务凭证。实际仓来自登录身份与会话,客户由真实货物明细解析。内部事件与库存账仍保留客户,不删除安全隔离字段,不要求客户端传入客户。
4. **不直接拍板新增柜级事件。** 当前装柜事件按客户拆分。可在新冻结契约中用共同 DP、清单版本/哈希、整托总量和预期分片标识,聚合各客户片段;也可采用一次完整公共交接清单。两者都必须证明组成已到齐、无重复、同版、同柜。先对比改造范围与完整性,再确定协议;不能仅对“当前已收到的片段”求和便开放整托收货。
5. **扫码不回国内查业务。** 海外用已验证的本地交接快照解析 DP/箱码与 FBA 组;缺快照是资料准备问题,不要求海外仓扫码补客户。保留现有网关实时身份校验,不为提速绕开鉴权。
6. **FBA 标签预生成不等于物理货物预分配。** 资源可提前准备,但在海外实际录入各托箱数后才形成该组真实托数。不要再建设“普通 FBA 国内逐箱打托”来支持用户明确的国内散货流程。
跨客户混托必须同步检查出库、移库、拆托、暂扣及物理资源释放。当前发现一个具体风险:`InventoryCommandService.ship()` 按当前客户的托盘余量归零判断整托空,并调用报废;如果另一客户仍有货,就可能错误处置公共托盘。因此必须以可信后台范围核对整托所有客户的库存和占用,再决定资源处理。不能只删除一托一客户校验就上线。
排车目前还存在唯一客户范围约束。混托后应允许一次物理搬运关联多个内部客户单据、分别记账;涉及某客户货不能走时,按箱/明细处理,不能随着其他客户整托误发。费用统计按真实物理托盘去重,不能因一托多客户重复计算托数;沿现有费用来源检查,不在 PDA 新增收费步骤。
## 6. 一台 PDA 的连续扫码设计
- 单入口、顺序处理,扫码进入队列。不能像当前页面那样忙时直接丢弃输入。
- 已保存成功才播放成功音;等待处理与保存成功分开显示。队列满或请求失败时明确暂停并保留输入,不悄悄吞码。
- 每笔使用稳定幂等键;请求超时保留原键重试。应用退出后恢复未确认命令和服务端收货状态,不重复生成新命令。
- DP/箱码两条入口还需按真实 DP 判断是否已收,不能只靠请求键去重;撤销后可重新收货,历史保留。
- 收货请求直接返回本托结果、组进度和柜进度;正常每笔不再 POST 后立即全量 GET current。全量读取用于入页、恢复和冲突对账。
- 网络不可用时显示待处理,不声称已入库。第一版只做可靠恢复,不额外建设完整离线作业、多人抢占和分布式协同平台。
- 撤销/改数量优先服务“刚才扫错”的小范围操作。任何修正同步更新明细、SKU实收、托盘/组/柜汇总;柜已完成或货物已出库后走对应更正业务,不允许静默删记录。
## 7. 当前代码事实与差距
| 现状事实 | 入口与证据 | 对方案的影响 |
|---|---|---|
| 国内一件代发有逐箱清点、实际件数、绑托、封托;当前拒绝其他客户/任务共用托盘 | [DropshipPalletizationService.java](C:/Users/BY-OY/Desktop/code/chongchong-global/baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/DropshipPalletizationService.java:166),`getOrCreatePallet` | 可复用清单基础,需支持多个入仓任务共同组成 DP |
| 普通 FBA 事件只传来源托盘码,`skuPackages` 为空 | [LoadingCompletedOutboxService.java](C:/Users/BY-OY/Desktop/code/chongchong-global/baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/LoadingCompletedOutboxService.java:140) | 符合国内散货事实,不应推断为国内整托 |
| 当前 V2 信封内订单必须客户一致 | [FirstLegLoadingPlanCompletedV2.java](C:/Users/BY-OY/Desktop/code/chongchong-global/baiyue-firstleg/common-event-contract/src/main/java/com/baiyue/common/event/FirstLegLoadingPlanCompletedV2.java:23) | 混客户 DP 要补完整性聚合设计,不能直接塞进原协议 |
| 后端有 `/current/receipts/pallet`,只收来源托盘号,要求恰好一个分配匹配 | [ReceivingContainerService.java](C:/Users/BY-OY/Desktop/code/chongchong-global/baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/ReceivingContainerService.java:368),`receiveWholePallet` | 需箱码反查、整托多成员、语义去重 |
| PDA未封装整托接口,页面仍按FBA/OVERSEAS两路提交,提交后清空上下文 | [inbound.js](C:/Users/BY-OY/Desktop/code/chongchong-global/apps/pda-overseas-uniapp/src/api/inbound.js:23)、[operation.vue](C:/Users/BY-OY/Desktop/code/chongchong-global/apps/pda-overseas-uniapp/src/pages/operation/operation.vue:173) | 要改扫码入口和持续作业状态,不能只增加一个按钮 |
| 整托扫码只记录实收,整柜完成时才创建可用库存 | [InboundPdaWorkflowService.java](C:/Users/BY-OY/Desktop/code/chongchong-global/baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/InboundPdaWorkflowService.java:332),`pickWholePallet`、`completePlan` | 可复用每笔保存/最后完成,不增加纯本地待提交账 |
| 库存入账要求逐入仓码数量相符;一件代发要求完整来源托盘相符 | [InboundStockReceiptService.java](C:/Users/BY-OY/Desktop/code/chongchong-global/baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/InboundStockReceiptService.java:99) | 差异结束需联改账务与状态,现有部分入库不能直接拼成整柜完成 |
| 公共托盘业务绑定及预留项仍独占一个物理托盘 | [warehouse.sql](C:/Users/BY-OY/Desktop/code/chongchong-global/baiyue-firstleg/warehouse-overseas-service/src/main/resources/db/warehouse.sql:104) | 一个物理占用、多业务组成,不能按客户重复锁/释放 |
| 出库按单客户判断托盘为空,可能错误报废混托 | [InventoryCommandService.java](C:/Users/BY-OY/Desktop/code/chongchong-global/baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inventory/command/service/InventoryCommandService.java:242) | 混托启用前必须修正并回归 |
另有一件代发件数快照风险待验证:国内已保存实际 SKU 件数,装柜也消费了实数;但 `LoadingCompletedOutboxService.actualPalletSnapshots` 仍按明细数量比例推算各托商品件数,[LoadingCompletedEventMapper.java](C:/Users/BY-OY/Desktop/code/chongchong-global/baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/mapper/LoadingCompletedEventMapper.java:83) 的逐箱来源关联也需核对。同一 SKU/明细分在多个 DP、每箱实际件数不同时,可能重复匹配或数量失真。当前只做静态检查,未复现;实现前应以逐箱实际件数聚合冻结并运行该案例,不能将箱数、商品件数混用。
## 8. 推荐开发拆分与验收
开发可按以下顺序推进,发布必须按完整业务能力交付:
1. 先冻结扫码语义、FBA 分摊精度、差异结束规则和海外仓中转颗粒度;明确DP先封托再分柜。
2. 补齐一件代发多成员托盘清单、箱码反查及跨区完整性;改好公共托盘占用/释放及相关出库约束。
3. 实现 FBA 当前柜目的仓聚合、每托累计箱数、计划分摊标识及下游精度约束;复用现有标签和资源准备。
4. PDA 接单入口持续扫码、数量回车、成功音、队列、防重、恢复、纠错及客户信息隐藏。当前一件代发已有整托服务可作为基础,不将单客户试用当作混客户需求完成。
5. 联改完成门禁及差异状态,回归整柜入账、下游取货、资源释放和卸柜事件。对外API、网关、DTO、OpenAPI、权限、SQL及测试同步收敛到同一目标契约,不保留新旧并行补丁。
关键验收案例:
- 同一 DP 含多客户、多入仓码;扫 DP、扫任意箱均只收整托一次,无客户展示和客户选择。
- DP 先创建后分柜;所有组成原子进入同柜,缺事件片段时不可按不完整数量收货。
- 同一 SKU/明细跨两托、实际每箱件数不同,国内清单、跨区快照和海外库存件数一致。
- FBA 三入仓码100箱,首次只扫一箱,随后3托录40/35/25;无重复扫入仓码、额外校验或封托按钮。
- 同目的 FBA 的一件代发不能进入散货组;不同柜同FBA不能合并;未保存数量不能因换组丢失。
- 重复扫描、数量从40改45、撤销后重收、超时重试、应用重启均无重复数量;快速扫码不静默丢失。
- FBA计划4托实际3托可以结束,反向需要第4托时有可操作的资源补充路径。
- 100/97、100/103、整托未到、托内少箱均保留真实差异;未知缺货不自动归责给最后一票,错柜货不自动转入。
- 一客户出完,另一客户仍在同托,公共托盘及库位不被释放/报废;组级数量分摊不被当成指定箱唛位置。
- 完成后只产生一次有效库存/卸柜事件;有差异的现场结束不冒充全部计划足量入库。
效率按交互次数验收:一件代发 N 托为 N 次有效扫描、正常路径0次逐托点击;FBA K 个目的仓、P 个实际托盘为 K 次扫箱选组、P 次扫托和 P 次箱数回车。照片、整柜结束、纠错及异常操作单独统计。真实耗时、网络等待和设备吞吐必须真机测量,本稿不预报百分比提升。
## 9. 仍需业务明确的两处边界
1. 普通 FBA 是否通常按同目的仓整组交接,还是经常要求拆出某一客户/入仓码单独发运?推荐保留快速计数,对确实需要挑货的后续环节增加箱码确认;若日常必须精准按票拣货,需接受更细的落托记录。
2. “海外仓中转”是否指纯数量交接的中转散货,还是需保留箱级库存的存储/服务货物?推荐先保持已有箱级能力并去掉重复操作;有可靠整托清单优先整托接收,纯数量中转的简化另行明确。
这两项作为实施前业务边界记录,不要求仓库在每次收货时做选择。收货策略由后台计划预先确定,PDA只执行当前货物对应的最短操作路径。