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

12 KiB
Raw Permalink Blame History

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 交总控串行读取。原失败和所有恢复/读取报告均保留,不覆盖。