diff --git a/lastleg-service/AGENTS.md b/lastleg-service/AGENTS.md index 3424cec54..98c3ab0e1 100644 --- a/lastleg-service/AGENTS.md +++ b/lastleg-service/AGENTS.md @@ -50,7 +50,7 @@ | 仓储资源调用 | `inboundplan/pda/gateway/WarehouseResourceGateway.java` | | 仓储转运、历史订单/入仓绑定、可选换标联动 | `transfer/controller/WarehouseTransferController.java` | | 一件代发接收、SKU/箱唛库存 | `dropship/controller/DropshipOrderController.java` | -| 货物废弃、待审锁箱、审批扣减 | `discard/controller/CargoDiscardController.java` | +| 货物废弃、待审锁箱、实际确认扣减 | `discard/controller/CargoDiscardController.java` | | 客户拜访、派送状态与签收附件 | `customervisit/controller/CustomerVisitController.java` | | 派送三类资料、摘要与历史证据 | `delivery/controller/DeliveryDocumentController.java` | | 异常订单与派送退回入仓 | `exceptionorder/controller/ExceptionOrderController.java` | @@ -141,7 +141,7 @@ - `FIRST_LEG` 在途、计划转换与 PDA 入账统一使用尾程订单冻结的实际接柜海外仓 ID/编码/名称,禁止使用国内来源仓或 FBA 目的仓冒充;接柜仓变更必须在同一事务内修订尚未形成实物仓位的在途余额并写零差额审计流水。余额分页、汇总和 CSV 默认排除所有数量桶均为零的维度,跨仓入账清空的无仓位来源余额必须原子删除。 - 列表、详情、导出和更新必须使用同一租户边界,不能仅在列表过滤而让详情或更新越权。 - 目的仓变更必须写状态/操作历史或审计证据,并使用版本控制防止并发覆盖。 -- 货物废弃只使用可核对 SKU 和箱唛的一件代发库存。创建申请只能将箱从 `AVAILABLE` 锁定为 `DISCARD_PENDING`,不得扣减 SKU 箱数;实际扣库存节点固定为具备 `lastleg:cargo-discard:approve` 权限的仓库/PDA 审核人确认废弃时,并且必须在审核事务内调用专用 discard adjustment。该 adjustment 必须将箱改为 `DISCARDED`、写逐箱业务流水及唯一幂等键,并校验 `扣减前箱数 - 废弃箱数 = 扣减后箱数` 且逐箱数等于申请总箱数;任一环节失败须整体回滚。拒绝申请只释放锁箱,不得扣库存。 +- 一件代发废弃:申请只锁箱 `AVAILABLE→DISCARD_PENDING`;平台批准(`lastleg:cargo-discard:approve`)只授权。绑定仓的海外 PDA(`lastleg:pda:operate`)实际确认时,同事务调用 discard adjustment,扣 SKU 件数及库存余额/位置,实际箱转 `DISCARDED` 并写唯一逐箱流水,数量须守恒;未废弃预留箱释放,失败整体回滚。按实际数量汇总费用,平台结案不再扣减。终态同完整载荷重放不新增流水/历史,异数量拒绝;驳回只释放锁箱。完整流程见 `../../docs/头程到尾程分阶段流程/阶段五-海外接柜库存与库内服务.md` 第9.5节。 - 海外采购客户下单固定进入 `PENDING_REVIEW`;采购编辑可维护入库数量和采购出库明细,出库量为明细数量汇总,审核通过且有入库量后按 `PENDING_OUTBOUND`、`PARTIALLY_OUTBOUND`、`OUTBOUNDED` 派生展示状态。采购出库只记录采购单据流转,不得写入或冒充 `available_packages`;只有海外仓 PDA 完成实收后,`InboundStockReceiptService` 才能以 `PDA_STOCK_IN:{taskId}:{allocationId}` 幂等键调用库存 `stockIn` 转入可用库存。禁止通过通用平台接口绕过 PDA 入可用库存。 - 派车状态只允许 PDA 拣货、完成和出库动作推进,普通派车编辑接口不得修改状态。PDA 写操作要求 `lastleg:pda:operate`;后台库存表单操作要求 `lastleg:inventory:manage`,盘点调整另要求 `lastleg:inventory:adjust`,转仓库存操作要求 `lastleg:warehouse-transfer:manage`。 - `ll_order.current_status` 只保存尾程主流程状态;换标、转仓、出库和派送等子单精确状态保存到各自单据并汇总到 `sub_order_status`,不得再用子单状态覆盖主流程状态。PDA 入仓及库存落账完成后,主流程状态固定推进为 `INBOUND_COMPLETED`。 diff --git a/scripts/agents-index-contract.ps1 b/scripts/agents-index-contract.ps1 index 81a8449e2..4ba170505 100644 --- a/scripts/agents-index-contract.ps1 +++ b/scripts/agents-index-contract.ps1 @@ -201,20 +201,20 @@ Assert-Contains $docsIndex '[测试环境独立任务协作登记](独立任务 Assert-Contains $docsIndex '[开发环境独立任务协作登记](开发环境独立任务协作登记.md)' '文档开发登记入口' # BEGIN CURRENT TEST REGISTRY CONTRACT function Assert-TestTaskRegistry([string]$registry) { - $current = ($registry -split '(?m)^## 2026-10-03 归档与重新规划')[0] - Assert-Contains $current '## 2026-10-03 车辆管理四任务协作(当前)' '当前车辆协作入口' - Assert-Contains $current '确认创建三个任务,我们当前目标调整一下,加上自己,一共4个任务' '测试任务精确数量授权' - Assert-Contains $current '车辆总控:当前对话 `01a0f19d-3f0b-7ae0-a860-c0d1d2e84475`' '测试所属总控' + $current = ($registry -split '(?m)^## 2026-10-04 全流程唯一持续目标与车辆交接(当前)')[0] + Assert-Contains $current '## 2026-10-04 用户确认的三个独立执行对话(当前派工)' '当前全流程协作入口' + Assert-Contains $current '用户明确选择“按这 3 个独立对话创建”' '测试任务精确数量授权' + Assert-Contains $current '所属唯一总控仍为 `退税报关` / `01a0d0da-130f-7d43-97b5-9c76abc1b5f1`' '测试所属总控' Assert-Contains $current '`c64729ff-6710-43c6-8ef2-d84e9666cc1e`' '测试保存项目' Assert-Contains $current '`C:/Users/BY-OY/Desktop/code/chongchong-global`' '测试工作目录' - Assert-Contains $current '不混入开发环境' '测试授权环境边界' - Assert-Contains $current '其他旧任务仍保持归档,不自动恢复' '测试任务禁止历史恢复' - $expectedIds = @('01a0ffcf-7150-7db3-9d8c-108e568c12b1','01a0ffcf-eea3-7111-b30b-4be63547ac33','01a0ffd0-2a4d-7210-bad8-a790cd965e8a') + Assert-Contains $current 'host `local` 与 cwd' '测试授权环境边界' + Assert-Contains $current '旧对话保持原状态,不恢复或唤醒' '测试任务禁止历史恢复' + $expectedIds = @('01a10686-c55c-75a3-9639-655b50cbce6c','01a10686-cae9-7943-b976-27e78ad92723','01a10686-cfdd-7f50-8500-7704e6fbc768') $actualIds = @([regex]::Matches($current, '(?m)^\|\s*`([0-9a-f-]{36})`\s*\|') | ForEach-Object { $_.Groups[1].Value }) $script:checked++ if ($actualIds.Count -ne 3 -or @($actualIds | Select-Object -Unique).Count -ne 3 -or @($expectedIds | Where-Object { $actualIds -notcontains $_ }).Count -gt 0) { - Add-Failure '测试当前登记必须恰为三个独立任务,加车辆总控共四个任务' + Add-Failure '测试当前登记必须恰为三个已授权独立任务,归属于唯一全流程总控' } Assert-NotContains $registry '当前无登记任务' '测试登记不得混入过期清空状态' Assert-NotContains $registry '01a0194a-259c-7171-8967-074731a27618' '测试登记历史总控' diff --git a/scripts/agents-index-registry-contract.test.mjs b/scripts/agents-index-registry-contract.test.mjs index 7ac952cca..3e009b82f 100644 --- a/scripts/agents-index-registry-contract.test.mjs +++ b/scripts/agents-index-registry-contract.test.mjs @@ -23,12 +23,12 @@ test('actual explicitly authorized TEST registry passes the production validator assert.deepEqual(failures(registry), []) }) for (const [name, mutate] of [ - ['missing creation authorization', s => s.replace('确认创建三个任务,我们当前目标调整一下,加上自己,一共4个任务', '安排任务')], - ['wrong controller', s => s.replace('车辆总控:当前对话 `01a0f19d-3f0b-7ae0-a860-c0d1d2e84475`', 'task_id=unknown')], + ['missing creation authorization', s => s.replace('用户明确选择“按这 3 个独立对话创建”', '安排任务')], + ['wrong controller', s => s.replace('所属唯一总控仍为 `退税报关` / `01a0d0da-130f-7d43-97b5-9c76abc1b5f1`', 'task_id=unknown')], ['wrong project', s => s.replace('`c64729ff-6710-43c6-8ef2-d84e9666cc1e`', 'projectId=wrong')], ['wrong workspace', s => s.replace('`C:/Users/BY-OY/Desktop/code/chongchong-global`', '`C:/Users/BY-OY/Desktop/code/chongchong-global-dev`')], - ['duplicate task', s => s.replace('01a0ffcf-eea3-7111-b30b-4be63547ac33', '01a0ffcf-7150-7db3-9d8c-108e568c12b1')], - ['unregistered replacement', s => s.replace('01a0ffcf-eea3-7111-b30b-4be63547ac33', '00000000-0000-0000-0000-000000000000')], + ['duplicate task', s => s.replace('01a10686-cae9-7943-b976-27e78ad92723', '01a10686-c55c-75a3-9639-655b50cbce6c')], + ['unregistered replacement', s => s.replace('01a10686-cae9-7943-b976-27e78ad92723', '00000000-0000-0000-0000-000000000000')], ['obsolete empty status', s => s + '\n当前无登记任务'], ['foreign project identity', s => s + '\n6f874ec3-d3b2-49bd-8625-327f4d685f98'], ['retired controller', s => s + '\n01a0194a-259c-7171-8967-074731a27618'],