test(fba): preserve verified fleet and fulfillment acceptance workflows

This commit is contained in:
2026-10-03 06:26:33 +08:00
parent c55bd7f4b6
commit d858357c5d
52 changed files with 4217 additions and 103 deletions
+41 -4
View File
@@ -1,14 +1,49 @@
# Admin 测试环境 HTTP 模块
`TERMINAL_READONLY` 用于全部业务写入和结案助手均完成、仅专项入口汇总状态断言错误的已复核报告。结案助手成功状态为 `CARGO_COMPLETED_AND_RESOURCES_RELEASED`。该检查点登录后仅 GET 原车次、每张排车/派送、资源占用测试计划与精确财务来源版本,不重放任何业务写入,不覆盖原失败报告;真实状态、数量、签收或费用不符仍失败。它不补充生产者 ACK 或页面验收证据。
`EXTERNAL_RECEIPT_CONFIRMED` 仅接受原运营实收确认明确成功、后续只读/重放断言失败且尚未开始排车关联的样本。先核对原来货已可排车、实际容量及单一库存流水,再原键原载荷重放实收确认;不重新入库。重放比较以数据库持久化后的完整预订为基准,避免直接拿命令返回的纳秒 `updatedAt` 与数据库毫秒精度比较;货量、报价、版本及全部业务字段仍精确核对。实收总箱数字段为正式 `receivedPackages`。
`EXTERNAL_PALLETIZED` 仅用于原 PDA 入库命令明确成功、库存只读核对失败且尚未运营确认的原样本。要求保存原请求键、实托和本轮临时 PDA 账号,回查原容量预留、来货状态及账号仓绑定后,只重放原入库命令,不重新创建或收货;再继续运营核量。库存列表是分组汇总,来源归属须读取该组引用的余额详情及实物位置,并与本票不可变流水核对;不能假定汇总行包含来货码。每次显式续跑保存独立报告和原报告哈希,保留首次失败证据。
`EXTERNAL_RECEIPT_READY` 是另一处显式复核检查点:仅全/部分费用覆盖与占位均已验证、PDA账号创建明确因手机号冲突被拒绝、尚未创建外接来货时允许继续。继续前回查原车次分配、客户排车及未拣/未发事实;新测试PDA使用独立标识,不复用恢复前的联系电话生成序号。已有外接实收/关联或账号写入结果未知时不得使用此检查点。
若全覆盖命令已经返回成功、但后续只读核对失败,可在核对原出库/派送确实已保存且未执行后,显式使用 `--resume-stage FULL_COVERAGE_PERSISTED`。此模式要求原成功命令、出库号和完整派送集合,先查正式详情,再仅重放原键原载荷;不重新运行创建前的负向写用例,不更换请求键或重造业务单据。目的地以当前 `destinationWarehouseCode` 优先、`fbaWarehouseCode` 兜底,与车次及派送服务一致,不能用原始 FBA 快照否定已经变更的实际目的地。
车辆专项修复后可显式选择已复核的只读检查点:`--resume-report reports/<原批次>/report.json --resume-stage FULL_COVERAGE`,仍须新的 `--run-id`。只接受全覆盖阶段仅执行过 GET、尚无出库且无任何 POST 的失败记录;复核同一车次资源、排车货物及未拣/未发事实后继续原样本,原失败报告不覆盖,保留其哈希与旧检查记录。其他阶段及写入结果未知均拒绝自动续跑,须先按原命令核对实际结果。出库列表仅使用正式客户范围分页,再逐行匹配排车号;不假定该列表支持 `dispatchNo` 查询过滤。
车辆专项入口为 `../fleet-test-env-acceptance.mjs`,先使用原 `phase4-overseas-dispatch` 依赖链创建本轮客户、头程费用和海外库存,再执行专用车辆编排;不改变已通过的 F40 默认调用顺序。默认 `--plan` 无网络,实际运行须显式 `--execute --environment TEST --run-id <新批次>`。仅串行运行,会创建当前批次资源及执行正式未执行单据取消重排,不执行部署、配置修改或业务 SQL 写入;原收货取证沿用现有只读读取器。失败保留原样本、请求与报告,不自动重造或续跑。
四个内部助手及各自 `*-contract.test.mjs`:`fleet-booking-reservation-acceptance.mjs` 验证询价/确认/超卖/取消的逐段占位与重放;`fleet-fee-coverage-acceptance.mjs` 用独立排车验证全覆盖及多原入仓的部分覆盖,核对原费用版本、目的地、快照及重放不重复收费;`fleet-external-receipt-acceptance.mjs` 通过正式来货与 PDA 测量、生成托盘、扫码绑定、照片和完成接口入库,按客户/仓/来货码查询余额与流水,验证重放不再入库、运营核量改价和预留替换;`fleet-external-dispatch-acceptance.mjs` 将该实收货物预排并绑定原车次,重核容量并逐客户审核,验证约定运费来源与重放。后两者会产生新外接货,必须走专用编排,不能直接加入只拣一张排车的 F40 默认流程。专项入口继续逐单 PDA 拣货、整车发车、逐目的地签收及资源释放;报告将 Finance 消费入池与生产者 ACK 分别记录,消费行存在不能冒充生产者已收到 ACK。以上助手不能独立当作全链入口,离线合同通过不代表真实 HTTP 或页面验收通过。
头程提交、平台编辑与取消按首次原始详情版本冻结请求。原键原载荷重放成功;同键异载荷、旧版本及新键重复操作分别核验拒绝后事实不变。Platform 编辑使用平台权限与显式客户范围,客户 Token 不得调用。
`fleet-trip-fulfillment.mjs` 是内部车次验收助手,不是独立入口。五期与F40模块通过正式API建立本轮车辆容量、测试司机及PNG证照上传/审核、车次关联、目的站匹配及本单调度审核通过;拣货后确认明确标记为测试的实物测量,通过整车理货审核后携带最新车次版本统一发车。资源及文件ID保留到报告,不自动删除、不以SQL修改状态;失败停止,不能跳过资格或装载。`mixed-container-outbound-test-env.mjs` 与 `overseas-relabel-fulfillment-acceptance.mjs` 的留存场景须在拣货前已有正式车次关联和通过的调度审核,不能对已经开工的旧单补造关联;它们确认受控测试装载、理货审核并继续履约。改派检查保留拣货事实,但重新通过每张单的调度审核后再确认装载。`fleet-trip-fulfillment-contract.test.mjs` 离线验证重复实托、目的地及准备顺序,不代表HTTP验收。
`prepareFleetTrip` 创建的本轮车次必须完成发车前改派验证:`confirmFleetLoading` 先确认装载,再创建等容量替换车辆和经文件上传/审核的替班司机,经正式分配接口改派。回查客户关联、原货物、拣货数量、路线和到达时间未改变,原装载确认已清除;旧版本确认须被拒绝且不产生写入,最后按新版本重新确认。返回最终版本供既有 PDA 就绪检查和整车发车使用。报告 `createdResources.fleetTrips[].reassignment` 留存前后快照、替换资源、原请求和结果,只有全部通过才标记 `VERIFIED`;失败保留 `CHECKING`,同一证明对象禁止自动重试或重造。顶层资源引用随后更新为替换资源供结案/释放验证,原资源仍保留在快照中。留存场景不执行这段新建资源与改派流程。
五期和F40签收后继续调用 `finishFleetTrip`:正式结案并同键重放,通过两个无货计划及一辆隔离用测试车辆验证“结案仍占用车辆、只结束车辆仍占用司机、两项结束后可重新分配、旧结束请求重放不能清除新占用”。仅409不足以通过,必须是相应资源占用冲突;全部完成后以正式取消命令取消无货计划并保留历史。测试车辆/司机在末站结束,不含返程任务;地点、时间、原请求及计划号保存于 `createdResources.fleetTrips[].closure`。失败保留CHECKING及原资源,不自动重造或修复旧fixture;离线模拟通过不等于这些真实HTTP场景已执行。
`phase5-overseas-fulfillment.mjs` 的 `pickAll`、`saveReceiptAndComplete` 也供显式授权的 `../mixed-container-outbound-test-env.mjs` 留存混柜续跑入口复用;仍使用正式 PDA 拣货和签收文件绑定接口,不代替全模块验收。
总入口是 `../admin-test-env-acceptance.mjs`。每个业务模块使用独立的同名 `.mjs` 文件,避免多个对话同时修改总入口。
`phase3-loading.mjs` 的 PDA 原子证据上传在未取得 HTTP 响应时最多尝试三次,冻结原 URL、作业员身份、幂等键、文件名/内容、证据版本和封签号;不重试 HTTP/业务拒绝或已收到响应后的读取失败。`createdResources.loadingEvidenceTransport` 保存各次结果及白名单网络错误码,不保存凭据或原始错误对象。`phase3-evidence-transport-contract.test.mjs` 用持久幂等模型验证响应丢失重放仅一条证据、持续传输失败有界终止及拒绝不重试;离线模型不替代真实 HTTP。
`orders.mjs` 每次运行优先使用当前 `merchantQualificationFixture` 的完整账号对,其次为明确配置;不在模块 import 时缓存客户凭据。当前 fixture 不完整时停止,不与上一轮或环境账号拼接。`orders-session-contract.test.mjs` 在同进程重复调用真实订单登录入口,覆盖连续客户隔离,防止多模式串行时沿用前一轮身份。
`phase4-overseas-pda.mjs` 的收货入口对本轮 `containerBookingId + containerNo` 做有界候选收敛等待(最多 30 次、间隔 1 秒),只有唯一且可操作的原柜才继续;鉴权失败、畸形响应和重复候选立即阻断。它用于等待异步船节点投影,不构成事件重放证据。F40 在成功和失败时均保留 `receivingCandidateEvidence` 的逐次查询身份、结果和诊断信息,不覆盖已有收货会话,不借其他柜或历史柜继续。
多目的地排车 C52:`phase4-overseas-dispatch.mjs` 在本轮实际收货产生的同仓同客户托盘上验证多 FBA 目的地及重复目的地托盘的增加、移除、重放和拒绝后零漂移。路线期望从实际排车明细及本轮冻结候选独立推导,记录 `routeLifecycle`,最终恢复原主链排车并释放额外测试托盘;缺少至少两个目的地及同目的地双托前置时明确阻断,不借历史数据或用单目的地代替。复用 candidates、draft-locks/lock、pre-arrange、详情和 DELETE items 正式 API;定向入口仍为 `--modules phase4-overseas-dispatch`,会写 TEST,使用新报告路径,失败保留样本,不自动删除重跑。合同为 `phase4-overseas-dispatch-contract.test.mjs`;离线成功不代表实际 HTTP 生命周期通过。
船节点异常 C66:`phase3-carrier-schedule-queries.mjs` 的 `captureCarrierExceptionEvidence` 与 `verifyCarrierExceptionTransition` 对本轮原船任务采集只读 checkpoint,核对 CUSTOMS_HOLD/TERMINAL_HOLD/DOCUMENT_HOLD/UNKNOWN_HOLD 的追加、解除、重放及冲突前后正常实际/预计节点守恒。`phase3-carrier-exceptions-contract.test.mjs` 只验证离线比对逻辑;真实生命周期还需要 Integration 供应商结果经调度器消费的独立投递证据。默认 HTTP 链只采基线并保留该覆盖缺口;空异常数组、重复 GET、报关异常和合成快照均不能计为供应商异常生命周期通过。
对应本地数据库事务测试为 Firstleg `CarrierScheduleExceptionPersistenceTest`,使用真实 Service/Repository/MyBatis 和 H2,验证四类异常及解除的同事件重放、异摘要冲突、正常实际/预计节点整行不变,以及异常历史写入失败时事务回滚。它属于本地持久化验证,不代替 TEST MySQL 或真实供应商调度链验收。
`phase5-root-fulfillment.mjs` 是显式 TEST 的 F40 两箱根/余量专项,通过总入口 `--modules phase5-root-fulfillment` 准备本轮资质客户;模块用正式下单、测量、国内 PDA 拆分装柜、船节点、海外 PDA 收货、拣货发车及文件签收链创建两柜真实来源。默认根先签,编程调用 `AcceptanceRun.context.f40SignatureOrder='CHILD_FIRST'` 切换子先签;分别核对第一片签收不得根完成、最后一片签收才根完成、真实签收时间、状态历史和重放零新增。
默认税制为 `BUY_DECLARATION`;编程调用显式设置 `AcceptanceRun.context.f40TaxMode='TAX_REFUND'` 可执行退税链。内部模块 `phase5-root-tax-customs.mjs` 在每个实装柜走客户上传、平台回执、客户确认、发送执行、人工正式申报与放行、完成文件,再进入尾程;订单最终完成后回查本客户资料并校验原件、回执、完成文件的实际下载字节和 SHA-256。该模块不能独立执行,不用 SQL 修改状态,不借历史资料;依赖相同 TEST 授权、当轮客户与只读取证器,失败及重跑保留各轮原始报告。直接合同为 `phase5-root-tax-customs-contract.test.mjs`,离线通过不代替实际 HTTP 或页面验收。
`AcceptanceRun.context.f40SignatureOrder='ROOT_SIGNED_REMAINDER_CANCELLED'` 单独验证合法末票余量取消:本轮新根通过 `orderStopAtApproved=true` 停在原始 `APPROVED`,只装运签收首箱;回查真实履约树及未装子单原始 `APPROVED`、入仓 `WAIT_SPLIT` 和一箱余量后,调用公开取消接口。`PROCESSING` 子单不得作为取消样本。根完成事件必须唯一发布,取消子单完成事件显式为零;原键原版本原载荷取消重放成功;同键异载荷及新键重复取消返回 `A0409`,根子版本、历史、摘要、履约树及完成 Outbox 均不漂移。两种双签模式仍须两片实际签收,不能用取消替代第二签。
会写已授权测试环境,保留新客户、单据、文件及报告,临时海外 PDA 在 finally 停用;失败保留样本,不自动删除或重复执行部分已完成链。签收资料使用新 key 保存同文件时,按正式保存命令递增一次资料版本、新增一条版本历史及 `SAVE_DOCUMENTS` 审计;签收时间、状态、原完成记录、文件绑定和根子完成事件不得变化。同一新命令再用原 key、原请求重放,必须明确 `replayed=true` 且完整资料、派送事实、版本和审计历史零漂移。资料保存前后及原 key 重放响应保存在 `phase5RootFulfillment.receiptReplayProofs`,失败也保留已取得的快照。
@@ -135,6 +170,10 @@ export async function run(context) {
## 约束
`unified-pda-session-revocation.mjs` 是海外库内作业模块的内部安全检查;在本轮操作员完成库存作业后修改其作业仓,分别验证旧 Access/Refresh 失效、新登录只绑定新仓、角色及仓绑定清空后旧会话失效且不能继续 PDA 作业。只更新本轮临时账号并由原 finally 停用,凭据保持在私有上下文;不改仓库主档或业务库存。合同为 `unified-pda-session-revocation-contract.test.mjs`。
`direct-delivery-replay-proof.mjs` 是事件模块的内部证据校验器,不是独立执行入口。要求本轮原装柜事件的 ID/hash、12 次失败至 DEAD、人工恢复审计、持久 Inbox 及 DUPLICATE、恢复前后业务订单身份集合零新增和环境恢复同时成立;单纯重复 GET 或历史故障报告不能满足条件。离线合同为 `direct-delivery-replay-proof-contract.test.mjs`。
- 不记录密码、Token、图片二进制或 OCR 原文全文。
- 测试数据必须带 `context.marker`;可删除的清理,不能删除的最终停用。
- 缺少已确认契约时记录失败或 `deploymentBlocker`,不得模拟成功。
@@ -206,9 +245,9 @@ export async function run(context) {
| 海外仓业务跨区事件与安全门禁 | `phase4-cross-region-events.mjs`(统一平台会话、匿名拒绝、canonical 权限 403、国内装柜完成到 Lastleg 建单、海外柜完成到 Firstleg 回写、轮询与诊断证据;重复 GET 仅验证读取稳定,缺真实投递重放证据仍阻断;缺本轮 marker 前置时阻断) | `phase4-cross-region-events-contract.test.mjs` |
| 国内离仓至海外 PDA 可见人工验收节点 | `phase3-customs.mjs`(国内报关资料与整柜照片)、`phase3-outbound-dispatch.mjs`(柜级离仓)、`phase3-container-documents.mjs`(离仓后目的港清关、DO;PU 使用柜级数字码)、`phase3-carrier-schedule-queries.mjs`、`phase4-carrier-pickup-ready.mjs`、`phase4-overseas-pda.mjs`(同柜候选) | `phase3-phase4-departure-pickup-chain-contract.test.mjs` |
| 国内出仓聚合、门禁、待装柜与仓库权限 | `phase3-outbound-aggregate.mjs`、`phase3-dispatch-gate.mjs`、`phase3-waiting-for-loading.mjs`、`phase3-warehouse-rbac.mjs` | 由容器回归、生产者链和出仓相关合同覆盖;只消费本轮主链资源 |
| 人工状态矩阵 | `manual-state-matrix.mjs` | `manual-state-matrix-contract.test.mjs`;验证装柜完成、报关和订舱相关状态组合 |
| 人工状态矩阵 | `manual-state-matrix.mjs` | `manual-state-matrix-contract.test.mjs`;依赖本轮海外签收,保留有有效余量根订单的 `DELIVERED`;完成订单样本经 `phase5-root-fulfillment.mjs` 两票真实签收和只读完成 Outbox 核验产生,不调用已移除的人工 `/complete`,并继续验证装柜完成、报关和订舱状态组合 |
| 海外业务 HTTP 生命周期 | `phase4-overseas-business.mjs` | `phase4-overseas-business-contract.test.mjs` |
| 海外主数据 HTTP 生命周期 | `phase4-overseas-master-data.mjs` | `phase4-overseas-master-data-contract.test.mjs` |
| 海外主数据 HTTP 生命周期 | `phase4-overseas-master-data.mjs`;车辆新建、详情、修改及列表均核对实际托位/载重/容积,修改使用不同容量值,CSV 同时核对修改后的值与业务车牌号;缺失或猜测容量形成阻断,finally 停用本轮资源。内部助手 `vehicle-care.mjs` 验证保养/加油创建重放、版本冲突、历史、单位、照片重放和字节下载,并逐类验证维修/故障/救援/异常项目地点回显、处理人、完成处理及费用/付款独立;另建本轮车辆验证跨车读取/修改/照片拒绝,结束停用隔离车辆并保留记录。报告在 `phase4OverseasMasterData.vehicle.care`,错误地以处理完成推定付款必须阻断;无SQL或旧数据修复,不作独立入口 | `phase4-overseas-master-data-contract.test.mjs` |
| 目的港码头拖车与船节点终态 | `phase5-terminal-drayage.mjs`(PDA 卸柜前复用 `ACTIVE + TRUCKING + truckingScope=OVERSEAS` 主数据完成选车队、预约和实际提柜,卸柜后完成实际还柜,并覆盖四命令幂等/历史)、`phase4-carrier-nodes.mjs`(PDA 前补录至 `PICKUP_READY`;拖车完成后只读核验 `PICKED_UP/EMPTY_RETURNED` 和停止语义) | `phase5-terminal-drayage-contract.test.mjs`、`phase4-carrier-nodes-contract.test.mjs`;不再由船节点脚本直接伪造提柜和还柜 |
| 海外排车、出库、派送、异常与回访 HTTP 生命周期 | `phase5-overseas-fulfillment.mjs`(复用本轮海外仓已收货托盘和预排单,正式创建临时 PDA 操作员并在 `finally` 停用;覆盖排车编辑、按 FBA 目的仓转出库/拆分派送单、PDA 全量拣货/发车、逐单签收资料保存自动完成、头程入仓与订单跨区回推、客户回访、人工异常及派送退回) | `phase5-overseas-fulfillment-contract.test.mjs` |
| 初始化基线(仅离线) | — | `initialization-baseline-contract.test.mjs` |
@@ -357,5 +396,3 @@ node --test scripts/admin-test-env-modules/merchant-qualification-fixture-contra
国内拖车自动完成与应付回归由 `phase3-outbound-dispatch.mjs` 在真实离仓后只读核验:订舱全部柜数、逐柜离仓、唯一 `AUTO_COMPLETE`、按拖车编号追溯柜次应付、金额守恒及 Finance 来源入池(有界等待 Outbox)。该模块的原有确认/撤销边界操作仍会写目标环境,执行须获得对应环境授权。`manual-state-ocean-trucking.mjs` 只构造可人工操作的状态,不伪造已完成拖车;自动终态由上述离仓链路覆盖。
`event-bridge-pending-recovery.mjs` 为纯离线证据校验器,文件名保留为索引入口;无事件桥调用或历史事件常量。合同覆盖 Compose DNS、三服务内部凭据版本一致、有限重试/DEAD、原事件摘要、ACK 丢失后 DUPLICATE 与单次业务效果。合成合同通过不代表环境故障演练通过;`phase4-cross-region-events` 保留真实重放证据阻断项。环境验收需本轮 marker 事件逐次投递记录、Inbox 与业务计数;仅使用受保护 `event-outbox-operations.mjs` 对 DEAD 原事件执行另行授权重试,不重放 SENT,不改表或伪造新事件。
`direct-delivery-replay-proof.mjs` 是事件模块的内部证据校验器,不是独立执行入口。要求本轮原装柜事件的 ID/hash、12 次失败至 DEAD、人工恢复审计、持久 Inbox 及 DUPLICATE、恢复前后业务订单身份集合零新增和环境恢复同时成立;单纯重复 GET 或历史故障报告不能满足条件。离线合同为 `direct-delivery-replay-proof-contract.test.mjs`。