Files
baiyue-firstleg/scripts/partial-loading-actual-acceptance-plan.md
T

69 lines
12 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.
# F21/F22 实装与部分装柜验收方案
本文件是本阶段的执行方案,不是已通过的 TEST 证据或状态主文档。不直接运行,不访问环境。真实执行必须等总控确认匹配 Firstleg 版本、受控触发器和独占样本窗口;发布、SQL、数据库取证由总控串行负责。凭据只从本轮指定 TEST 环境文件读取,报告不保存密码、Token 或内部服务令牌。
## 入口与样本
复用 `admin-test-env-modules/phase3-container-loading.mjs` 的合法订单、审核、测量、分柜、RELEASED 订舱、真实柜号、PDA 领取及五类装柜证据链;复用 `phase3-container-customs-fixture.mjs` 的客户资格和报关入口。现有全拣场景不能直接替代本方案的 PARTIAL/SKIPPED 场景,也不能直接运行内部模块当作新验收入口。
使用新批次标记 `PARTIAL-ACTUAL-<运行时间>`、独立客户/订单/柜次/任务。一个任务单请求流,只操作本批次样本;已有柜 `TSTU8545690` 仅做只读回查,不回填计划、库存、入仓单或重放历史事件。失败停在原样本,保留原请求和失败报告,不盲目重造样本。
最小场景分两柜,沿合法流程分别准备:
| 柜 | 来源与操作 | 验证目的 |
|---|---|---|
| A | 客户甲退税普通 PACKAGE 行计划 3 箱、每箱 7 件,实拣 2 箱并提交 PARTIAL;甲另一 SKU 零拣 SKIPPED;客户乙买单普通行全拣;客户丙退税整票零拣 SKIPPED | 混合客户/税制、部分数量缩放、同票跳过 SKU 与整客户跳过隔离 |
| B | 唯一实际买单 PACKAGE 行计划 2 箱、实拣 1 箱并提交 PARTIAL;同计划退税票全部 SKIPPED | 全部实际行均 PARTIAL 的完成预检,以及实际全买单柜不因计划历史退税票要求客户资料或退税发送 |
从预装详情冻结每行 itemId、客户/来源/明细三键、原箱数、unitsPerCarton、productQuantity、palletCount、重量和体积。件数先按每箱件数×实箱;无每箱件数时按原量比例 HALF_UP 至整数。重量 HALF_UP 至 3 位、体积至 4 位;NULL 保持 NULL。托数按原计划托数比例向上取整。托数为空/0 的标签回退另核对原入仓总箱数、合法确认称重/库位证据,不能用本次实拣总数替换原比例分母。样本中的未知值只来自正式接口允许的输入,不以 SQL 修改事实制造样本。
## PDA 正式动作
接口基址为 `/api/platform/v1/first-leg/pda-loading`,按正式仓绑定会话访问。
1. 回读任务、库存和每行版本;通过既有正式扫码/拣货入口取得真实箱码事实。PARTIAL 为最终实箱数,不能把增量当最终数量。
2. `POST /tasks/{taskId}/items/{itemId}/partial`:提交 `warehouseId, finalPickedPackageCount, version, operationId`。SKIPPED 使用 `POST /tasks/{taskId}/items/{itemId}/skip`,提交 `warehouseId, version, operationId, reason`,仅限零拣行。
3. 上传并回查 PHOTO_STEP_1–4 与 SEAL 的五类有效照片和锁码;保留任务及计划全量基线、操作历史、预装冻结行。缺证据拒绝场景优先复用已有证据,不额外销毁照片。
4. 在最终完成前回读标签,确认预检没有新增标签或占用冻结编号。内部数据库/序号核验由总控做只读取证;不存在公网独立预检写入口。
5. 回读最新任务版本后,只提交一次 `POST /tasks/{taskId}/complete`,载荷 `expectedTaskVersion, operationId, remark`;保存 HTTP 状态、业务 code、requestId/traceId、完整载荷和命令身份,等待实际 COMPLETED,不把受理态当完成。
6. 完成后原 operationId、原 expectedTaskVersion、原载荷重放,确认返回同一业务结果;另一独立 operationId 不作为原请求重放。
## 完成后的独立核对
| 对象 | 必须成立的断言 |
|---|---|
| 完成清单 | `/api/platform/v1/first-leg/loading-lists/{planId}?warehouseId=...` 的行集合严格等于有效实拣集合;PARTIAL 行已结算为实箱,SKIPPED/零拣不出现;列表与详情汇总一致 |
| 计划历史/PDA | 计划历史允许保留 SKIPPED;任务保留真实实拣及原计划数量。不能以原计划总箱数与实装箱数相等作为完成断言 |
| 部分指标 | 原 3 箱 21 件变为实 2 箱 14 件;重量/体积按冻结行缩放。例:10.001/8.002/6.004 kg、0.1001 cbm 对应 6.667/5.335/4.003 kg、0.0667 cbm;实际期望以正式冻结值为准 |
| 来源与余量 | 实箱+余量=原可用箱数;余量沿正式分片产生,原订单/入仓编号及 lineage 可追溯。重放后版本、历史、资源结算和分片数量不重复推进 |
| 标签/事件 | 预测与最终冻结托盘码/托数一致,预检零标签写入;最终 V3 只携带各客户实际货物。总控只读核对唯一 Outbox、载荷摘要、ACK 与接收结果,不伪造事件 |
| 报关平台 | `GET /api/platform/v1/customs/loading-plans/{planId}` 的 actualBoxCount 等于实拣之和;退税票/客户范围、资料覆盖要求排除整票跳过;已实装票缺资料仍拒绝开始 |
| 客户资料 | `/api/merchant/v1/customs/orders/{orderId}`:甲只能见自身已实装退税来源;丙整票跳过没有该柜资料入口;乙买单不会获得退税客户入口;外客户拒绝保持原 code 与诊断字段 |
| 买单导出 | 复用正式导出服务,只含乙实际行,不含跳过的买单行;记录分页最大ID、总数、输出行集合与字节摘要,不能只核对 XLSX 魔数 |
| 全买单 B 柜 | 跳过退税不阻断全买单报关开始/完成;拒绝创建退税申报/发送。报关完成后的自动离仓必须满足既有正式前置,不能用本方案绕过 |
| 下游 | Lastleg/入仓计划/在途库存独立读回与事件实际数一致;禁止把正确下游改成原计划总箱数;原柜只读回查保持下游完整快照不变 |
## 负向预检与证据界限
跨客户第二来源缺客户/目的仓快照、非法 PARTIAL、未结算最终发布等服务内非法事实,使用 `LoadingCompletedPreflightDatabaseTest` 的真实 Mapper 场景核验;不得通过 TEST SQL 捏造非法业务数据。有效新样本的跨客户正常完成必须走上述真实 HTTP。H2 对 MySQL UPDATE JOIN 的语法适配与 pendingAutoDispatch 关联替换均需在报告中披露;真实 MySQL 触发器与最终完成另验。
证据建议落在 `reports/partial-loading-actual-<批次>/`:版本/健康与触发器就绪证明、请求序列、before/after 全量快照、逐断言结果、事件/接收端只读取证、失败原件、会话退出结果。执行结束退出自己的全部会话,不删除数据或恢复他人资源。HTTP/DOM证据与人工1920×1080、100%缩放及PDA设备验收分别报告,不据服务测试宣布页面或全流程完成。
## 最小可执行入口及交给总控的 README 登记文本
下列段落应由总控集成到 `scripts/README.md`;本任务不修改共享索引。
> `partial-loading-actual-test-env.mjs` 是 F21/F22 两柜实装与部分装柜 TEST 专项入口,默认无参数或 `--plan` 零网络。执行必须在测试后端工作区、使用脚本前的 `node --env-file=<用户指定目录的test-acceptance.env>`,并传入 `--execute --environment=TEST --run-id=PARTIAL-ACTUAL-<新批次> --fixture=NEW`,仅在总控确认匹配 Firstleg 与受控触发器、开放新样本窗口后运行。NEW 模式复用既有资格/订单/测量合法模块,仅准备五个隔离客户/订单与两柜;A 为退税 3→2 PARTIAL、同来源 SKU SKIP、另一客户买单全拣及整客户退税 SKIP,B 为唯一实际买单 2→1 PARTIAL 且退税全部 SKIP。也支持 `--fixture=<manifest.json>` 消费本轮通过的 `manual-pda-batch-fixture` 报告,所有动作覆盖每条 PDA 明细,限定全新未领取、零拣货且跨柜不共享来源的样本。入口执行领取、原子 batch、五类证据、唯一完成、实装数量/件数/重量/体积和报关范围、原完成命令重放零漂移,以及 B 全买单报关开始/完成和退税发送拒绝;NEW 模式照片为明确标记的合成 HTTP 夹具,不是现场照片或真机证据。报告 `reports/partial-loading-actual-PARTIAL-ACTUAL-<新批次>/report.json` 使用独占目录,先保存原请求/幂等意图,凭据脱敏、单请求流;失败保留原样本,未知传输结果阻断后续命令,不自动重造、覆盖、续跑或重放历史事件。退出自己的所有会话;不操作旧客户库存、SQL、部署或船节点。B 全买单报关完成后停在合法当前状态供总控复用,不能自行推进进港、提柜或卸柜。此入口不展开 F01–F40 全量,不代替事件 ACK、下游库存、完整退税资料/XLSX及人工页面/PDA证据。直接离线测试为 `partial-loading-actual-test-env.test.mjs`。
当前可执行最小范围与上文完整方案分开:两柜完成/报关范围有可执行断言;事件、下游、客户资料隔离和 XLSX 必须另取实际证据,不将方案中的未执行项写成通过。
### 原样本恢复与准备检查点续接(追加 README 文本)
> 本入口支持本轮明确授权的 `--fixture=RESUME:<原失败report.json>`:核对冻结 `blocked-readback.json` 的原客户、订单、入仓码、测量批次、版本及无称重基线,将旧报告/回读 SHA 写入新的恢复目录;不再资格、创建客户或下单。测量直接从原草稿续接上传、独立 SKU 明细、称重确认、提交和审核,不运行“首次扫描新增”夹具断言。multipart 适配支持文件描述对象与现成 FormData,文件字节保留、Content-Type boundary 由 fetch 生成;直接测试使用本地真实 HTTP 接收原始字节。`--fixture=PREPARED:<本轮两柜准备report.json>` 只续接这次原来源形成的两柜零拣货检查点,不重新创建任何客户、订单或柜;任务可为未分配,或已分配给当前独立 PDA 会话的 IN_PROGRESS,仍须冻结版本、全部 PENDING/零实拣及无外部作业记录。任务已发生实拣或完成后不得用此模式重跑。同来源 SKU 的零拣跳过先走正式逐明细 SKIP,再以刷新后的版本和库存快照一次 batch 处理全部剩余待拣;不能把 SKIP 与同来源的实拣放在同一 batch,也不能提交只含部分待拣明细的 batch。原完成失败必须保留命令和失败状态,生产修复与原命令恢复由总控另行协调,不自动重新造柜、改业务事实或继续人工船节点。
### A 原完成命令恢复与纯读取证(追加 README 文本)
> `partial-loading-actual-test-env.mjs` 的 `--fixture=COMPLETION:<recovery-r7/report.json>` 模式仅恢复原 A command `2106716718935052290`,先从旧报告校验唯一已受理请求和准备报告 SHA;必须同时给出 `--ready-commit=ea9732749a9215e660530035c40afc69fe56a5ae`,且已收到总控匹配 Firstleg 就绪及恢复授权。请求体严格固定为 `expectedTaskVersion=2`、`operationId=PARTIAL-ACTUAL-20261004-recovery-r3-A-complete`、`remark=PARTIAL-ACTUAL-20261004-recovery-r3-A`,不使用失败后新 task version 创建另一命令。先保存两旧 LOADED owner、全跳来源及源分配数量/绑定快照,再只 POST 一次正式 complete;遇未知结果仅回查并停止,不盲重试。完成后对比旧来源版本/历史/源分配快照、正实拣集合、清单/报关实际数、Lastleg 事件建单历史和初始在途余额/流水;全部跳过来源不得 LOADED 或获得尾程/库存。B 在此模式明确暂缓,不做资格、下单、拣货、海运节点或 SQL。
>
> 若原命令已完成,但后续取证失败,使用新的报告目录和 `--fixture=VERIFY_A:<原COMPLETION执行report.json>` 纯读模式接续,仍带相同 ready commit;该模式只允许 GET 及自有登录/退出,不再 complete。库存列表是按维度聚合,入仓归属字段为空时必须沿 `/inventory/balances/{代表id}` 详情读取真实归属;`totalPackages` 表示在仓桶,在途数核对 `inTransitPackages`,不能把在途要求加入在仓总数。公开消费建单/流水事实只证明实装事件结果,不代替 Firstleg Outbox 发布状态、ACK/Inbox SQL 审计;精确 SQL 交总控串行读取。原失败和所有恢复/读取报告均保留,不覆盖。