From b22d1ed0c0faa316483712b32259b5387556e517 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Mon, 21 Sep 2026 20:39:30 +0800 Subject: [PATCH] 1 --- 财务管理/README.md | 1 + 财务管理/海外仓费用统一接入阶段0技术契约.md | 99 +++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 财务管理/海外仓费用统一接入阶段0技术契约.md diff --git a/财务管理/README.md b/财务管理/README.md index 9fb6f51..1800136 100644 --- a/财务管理/README.md +++ b/财务管理/README.md @@ -63,6 +63,7 @@ 详细设计材料: - [海外仓费用统一接入财务评审方案](海外仓费用统一接入财务评审方案.md) +- [海外仓费用统一接入阶段 0 技术契约](海外仓费用统一接入阶段0技术契约.md) - [财务业务操作流程图](财务全链路流程图.md) - [财务业务全流程总览图(PNG)](财务业务全流程总览图.png) - [财务来源接入现状](财务来源接入现状.md) diff --git a/财务管理/海外仓费用统一接入阶段0技术契约.md b/财务管理/海外仓费用统一接入阶段0技术契约.md new file mode 100644 index 0000000..3fc4537 --- /dev/null +++ b/财务管理/海外仓费用统一接入阶段0技术契约.md @@ -0,0 +1,99 @@ +# 海外仓费用统一接入阶段 0 技术契约 + +> 版本:V0.5-0A | 状态:开发前技术基线 | 来源:海外仓费用统一接入财务评审方案 V0.5 + +## 1. 目标与边界 + +阶段 0 只完成“费用事实可追踪、可幂等、可被 Finance 接受或拒绝”的底座,不新增业务收费规则,不部署测试环境,不启动 Java/Nacos/数据库。所有费用仍由业务服务产生事实,Finance 独立落库并负责应收/应付、钱包和结算。 + +实施顺序固定为: + +1. 0A:既有链路和收费身份; +2. 0B:统一来源命令、结果和 Outbox/Inbox; +3. 0C:冻结/结算按收费身份和计划版本; +4. 0D:退货、仓租、按票及库存日事实; +5. 0E:商业调整、拒绝和财务待办。 + +## 2. 当前代码事实与必须修正点 + +| 范围 | 当前实现 | V0.5 要求 | +|---|---|---| +| 来源事件 | `BusinessFeeSourceChangedV1` 单向完整快照 | 增加命令/结果闭环,Finance 明确 ACCEPTED/REJECTED | +| 费用版本 | Lastleg 调整、作废先改变当前状态再发事件 | Finance 接受新版本后,旧版本才可 SUPERSEDED/VOIDED | +| Wallet | 以 `businessType + businessNo + amount` 匹配冻结 | 绑定 `chargeIdentity + feeSourceVersion + walletPlanId` | +| Relabel | 部分完成路径发布费用,SKU/客户确认路径漏发 | 所有完成路径统一产出一条收费身份 | +| Destuff | 直接 insert 已审批客户应收,绕过服务和命令 | 进入统一来源命令;供应商应付按阶段配置 | +| Delivery | 转运时直接发布已审批费用 | 票级 AR/AP 分离,人工金额先待审 | +| 来源模型 | 无 `scenarioCode`、收费身份、Finance 同步状态 | 三者均为显式字段,不从业务单号推导 | + +## 3. 收费身份与状态 + +### 3.1 收费身份 + +`chargeIdentity` 是稳定的业务收费对象键,不等同于数据库 ID。格式由场景定义,至少包含 `scenarioCode`、业务主单号、客户和收费对象序号;同一身份可产生多个不可变 `sourceVersion`。Finance 唯一键为: + +`sourceSystem + sourceType + sourceFeeId + sourceVersion` + +费用明细必须同时保存 `chargeIdentity`,用于 AR/AP、钱包、账单和追溯关联。 + +### 3.2 状态轴 + +- 来源状态:`DRAFT`、`PENDING_REVIEW`、`APPROVED`、`REJECTED`、`SUPERSEDED`、`VOIDED`。 +- 发布状态:`NOT_PUBLISHED`、`PUBLISHED`、`ACCEPTED`、`REJECTED`。 +- Finance 同步状态:`PENDING`、`ACCEPTED`、`REJECTED`、`RETRYING`。 +- 结算状态:`UNSETTLED`、`FROZEN`、`SETTLED`、`RELEASED`。 + +状态轴不可互相覆盖。费用调整必须生成新版本;同一版本不同 hash 必须拒绝。已进入有效账单、结算或钱包结算的来源不得替换或作废。 + +## 4. 跨服务命令与结果 + +### 4.1 `BusinessFeeSourceCommandV2` + +事件头:`eventId`、`eventType`、`eventVersion=2`、`eventKey`、`occurredAt`、`sourceSystem`、`traceId`。 + +业务体:`action`(UPSERT/VOID)、`sourceType`、`sourceFeeId`、`sourceVersion`、`chargeIdentity`、`scenarioCode`、客户/业务/仓库/供应商引用、方向、币种金额、数量单价、期间、付款证据、来源状态、`sourceHash`。 + +发送方必须发送完整快照,不允许 Finance 回查海外库。`eventKey` 固定为 `sourceSystem:sourceFeeId:sourceVersion:action`。 + +### 4.2 `BusinessFeeSourceResultV2` + +Finance 处理后回传:`commandEventId`、`sourceFeeId`、`sourceVersion`、`result`(ACCEPTED/REJECTED)、`reasonCode`、`reasonMessage`、`financeFeeSourceId`、`processedAt`、`resultHash`。 + +业务方以 `commandEventId` 幂等接收结果;REJECTED 必须形成可重试或人工待办,不得静默丢弃。结果事件不能改变原始费用快照。 + +## 5. 钱包与账单关联 + +钱包命令新增 `chargeIdentity`、`sourceFeeId`、`sourceVersion`、`walletPlanId`、`walletPlanVersion`、`allocationId`。冻结、结算、释放均以 `allocationId` 幂等;禁止仅按业务类型、业务单号和金额猜测关联。 + +柜级费用先按真实客户/订单形成分摊明细,再分别产生收费身份和钱包分配;退货按票、仓租按期间/仓库、配送按票分别生成身份,不复用订单主单号充当费用键。 + +## 6. 场景接入约束 + +- **Relabel**:所有完成入口调用同一应用服务;一次业务收费身份只允许一个当前版本。 +- **Destuff**:按实际客户 CBM 分摊;客户应收与供应商应付分开建身份,禁止直接写 APPROVED/PUBLISHED 绕过命令。 +- **Delivery**:每票每收费项独立身份;收款方与付款方分离,手工金额进入待审。 +- **Return**:按票计费,退货收货完成才结束计费;迟到实收只能生成新版本/调整记录。 +- **Warehouse rent**:按仓库、库位/货主、计费期间和计费规则生成期间身份,不能伪造入仓码。 + +## 7. 阶段 0 开发门禁 + +开始改代码前必须完成并评审: + +1. V2 事件 DTO、事件类型、Gateway 路由、OpenAPI、权限码和跨区 Outbox/Inbox 位置; +2. Lastleg 来源表与 Finance 来源表的字段/索引/状态迁移设计; +3. 钱包计划及分摊表的唯一键与幂等键; +4. Relabel、Destuff、Delivery 的生产入口清单和漏发测试用例; +5. 拒绝、重试、迟到实收、旧版本已结算等异常验收用例。 + +实现后必须定向运行 DTO/事件/服务测试、`node scripts/gateway-route-contract.test.mjs`,若有 Mapper 变更再运行 `node scripts/mapper-scan-contract.mjs`。本阶段不执行部署和真实 HTTP 验收。 + +## 8. 代码入口 + +- 事件模型:`baiyue-firstleg/common-event-contract/` +- 海外来源服务:`baiyue-firstleg/lastleg-service/.../financefee/` +- Finance 消费:`baiyue-firstleg/finance/.../BusinessFeeSourceEventService.java` +- Relabel:`baiyue-firstleg/lastleg-service/.../relabel/` +- Delivery:`baiyue-firstleg/lastleg-service/.../delivery/` +- Destuff:`baiyue-firstleg/lastleg-service/.../inboundplan/` + +本文是 V0.5 的技术落地门禁;与 V0.5 方案冲突时,以当前对话确认和 V0.5 方案为准。