Files
docs/财务管理/海外仓费用统一接入财务评审方案.md
T
2026-09-21 13:22:46 +08:00

745 lines
72 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.
# 海外仓费用统一接入财务评审方案
> 文档状态:评审稿 V0.2(首轮评审修订,待继续评审)
> 编制日期:2026-09-21
> 适用范围:头程、柜级费用、海外仓作业费用及其进入 Finance 统一应收应付的链路
> 事实口径:当前代码静态盘点 + 既有财务跨服务契约;本稿不代表测试环境已经部署或通过真实 HTTP 验收
本轮仅修订方案,不表示新增能力已经实现。第三节记录当前事实;其余章节区分复用能力与目标改造。计费日期、收费单位、最低收费等业务口径仍为推荐值,第十四节集中列出待确认项。
V0.2 重点修正:区分漏生成、待审核和展示遗漏;纠正换标、拆柜、派送的接入判断;补齐资金账户关联、人工与自动收费去重、跨区变更结果闭环;重写仓租计量与算例;增加阶段 0,并将入仓、本土卡车、散板纳入覆盖清单。另补多海外仓报价的新增、复制、修改、生效、查看与试算流程(7.5—7.8)。
## 一、评审目标
本次不重建 Finance,也不让各业务模块直接生成账单或修改客户余额。目标是把分散在头程、柜子、海外仓、退货、仓租、销毁、滞留等环节的费用,先在业务域形成可追溯、可审核、可调整的费用事实,再统一进入 Finance 的应收应付费用池。
本次重点解决六个问题:
1. 当前哪些费用已经进入 Finance,哪些只有字段或页面,哪些完全没有接入。
2. “退货按票收费”中的一票如何定义,何时收费,如何避免分批收货导致重复收费。
3. 仓租如何按仓库当地日期、库存批次和结算周期准确计费,而不是用当前库存倒推历史费用。
4. 同一业务动作如何同时形成客户应收和供应商应付,并正确区分月结与已直付。
5. 后续新增各种操作费时,如何只增加费用项目和计价规则,不再为每种费用重复建设一条财务链路。
6. 一个或多个海外仓如何新增收费配置、区分销售价与成本价、调价生效、查看历史,并从实际费用反查所用报价。
## 二、先给结论
### 2.1 总体结论
Finance 现有统一费用来源、跨区域事件、费用池、对账单和应收应付结算能力可以继续复用。主要缺口在 Lastleg 的费用生产、计价、审核与业务页面聚合;Finance 仍需参与来源变更结果确认、资金账户关联扩展和必要的查询展示,不能把本次改造理解为只改海外业务服务。
建议采用以下唯一链路:
```text
业务动作/库存事实
-> Lastleg 海外仓计费中心
-> 匹配客户销售价或供应商成本价
-> 生成不可变费用来源版本
-> 海外 Outbox / Event Bridge
-> Finance 校验并保存来源,返回接受或拒绝结果(结果回传为本次新增目标)
-> 未结算应收进入客户对账 / 已由资金账户结算的应收关联结清
/ 月结应付进入供应商结算 / 直接已付仅记录成本
```
核心原则:
- 业务服务只生产费用事实;Finance 负责财务归集、出账、收付款和核销。
- 同一业务动作的客户应收与供应商应付是两条独立费用来源,不能用一条记录同时表达收入和成本。
- 已发布费用不原地改金额;调整形成新版本,作废形成可审计的变更请求。Finance 接受前不覆盖双方最后一致的有效版本;已冻结费用由财务单据调整处理,不能直接发送负数来源充当冲销。
- Finance 不维护仓租算法和海外仓报价;Finance 只消费业务域已经确认的数量、单价、期间、币种和金额快照。
- 新仓内费用优先复用 `OVERSEAS_WAREHOUSE_FEE` 来源类型,通过稳定的 `businessType + feeItemCode` 区分业务。既有采购、换标、派送等来源类型和资金关联按真实业务保留,不为统一展示强行改名或重复生成一套来源。
### 2.2 应收应付进入 Finance 后的口径
| 费用方向 | 结算方式 | Finance 去向 | 说明 |
|---|---|---|---|
| `RECEIVABLE` | 对账收款 | `AVAILABLE` 客户费用池 -> 对账单 -> 应收结算 | 尚未由资金账户结算的客户费用 |
| `RECEIVABLE` | 资金账户结算 | 关联资金结算记录并标记 `SETTLED` | 采购、换标已有该分支,不再进入对账候选;关联中的费用按第九节阻止重复出账 |
| `PAYABLE` | `ON_ACCOUNT` | 供应商应付来源 -> 应付结算单 | 尚未付款、后续与供应商结算 |
| `PAYABLE` | `DIRECT_PAID` | 已确认成本 | 业务侧已经支付,只记成本,不再形成待付应付 |
表中应收“对账收款/资金账户结算”是业务收款路径,不复用应付的 `settlementMode` 字段。资金账户金额和流水仍由 Finance 负责,Lastleg 只发送受控资金指令。
## 三、当前接入盘点
### 3.1 已有费用生产或发布基础
“存在来源记录/事件”不等于所有业务分支、应收应付、调整和页面均已闭环。头程与国内柜费沿用既有契约,本轮重点核验海外链路。
| 业务范围 | 触发与来源 | 应收/应付现状 | 审核与调整现状 | 展示及本轮处理 |
|---|---|---|---|---|
| 头程 FBA/入库运费 | 已确认计费形成来源 | 自动客户应收 | 沿用现有审核发布链路 | 保持现有链路,受影响时回归 |
| 头程人工费用 | 人工费用审核发布 | 支持应收、应付 | 有审核、调整和作废能力 | 保持现有链路 |
| 国内柜级公共费用 | 按真实客户和业务订单分摊后发布 | 客户分摊与供应商应付独立 | 按现有整组处理契约 | 保持分摊守恒,不把客户分摊当作供应商应付 |
| 国内拖车预约费 | 按实际体积形成成本分摊 | 供应商成本链路已具备 | 沿用现有契约 | 保持现有链路 |
| 海外接柜相关费用 | 柜级页面人工维护港杂、仓储、维修、吊机、码头拖车等 | 已有通用应收/应付来源能力 | 柜级页面已有创建、提交、审核、调整和作废 | 补报价与标准项目映射,不能归为“海外全无审核入口” |
| 海外拆柜打托费 | 全柜 PDA 入仓完成后,按实物托盘单价合计并按客户实收 CBM 分摊 | 自动生成 `RECEIVABLE`;未自动生成供应商应付 | 自动发布;`DESTUFF_PALLET` 项目及业务身份与通用调整校验不一致 | 阶段 0 修调整链路;后续独立补供应商成本 |
| 海外采购费用 | 人工维护费用;满足资金冻结和采购入库数量条件后发布 | 当前自动来源为客户应收,关联资金账户结算;缺自动供应商成本 | 存在自动发布链路 | 保留资金关联;补供应商、成本定价与结算方式 |
| 海外派送费用 | 转派送请求人工传入 `fees`,转单时发布 | 可传应收或应付;同请求不能提交同一费用项目的两个方向 | 当前人工金额也自动审核;去重键仅含费用类型 | 补方向/交易对手维度,按人工审核目标收敛;不视为报价自动计费已完成 |
| 海外换标费用 | `changeStatus(COMPLETED)` 分支发布应收并发送资金结算指令 | 有应收生产者;纯 SKU 等无需出库分支客户确认后直接完成,未走发布/结算分支 | 存在漏发路径,不能整体标记完成 | 阶段 0 统一所有合法完成分支的费用与资金结算触发 |
### 3.2 已有基础,但尚未形成完整闭环
| 业务范围 | 当前事实 | 主要断点 |
|---|---|---|
| 尾程订单人工费用 | 页面创建后调用提交,形成 `PENDING`;应付页面当前仅提交 `ON_ACCOUNT` | 缺待审页面和来源跳转;后端还缺草稿/驳回内容修改接口,直付证据未在该页面接通 |
| 海外入仓费 | Lastleg 通用创建、审核、发布及真实入仓业务归属校验已具备 | 未找到对应业务自动生产者和专用页面闭环,不是只有 Finance 枚举预留 |
| 海外本土卡车费 | Lastleg 通用来源接口及真实卡车业务归属校验已具备 | 缺业务自动触发、计价与页面闭环 |
| 海外散板费 | Lastleg 通用来源接口及真实散板业务归属校验已具备 | 缺业务自动触发、计价与页面闭环 |
| 海外仓服务费 | 已有 `OVERSEAS_WAREHOUSE_FEE` 和 `WAREHOUSE_SERVICE` 通用入口 | 主要依赖人工录入,尚无统一业务触发、计价和自动发布能力 |
| 海外仓报价 | 已有仓库、服务商名称、币种、生效区间、版本、计费单位、单价和最低收费 | 服务商名称并非供应商主档 ID;项目和单位为自由文本,缺价格角色与计价消费者 |
### 3.3 当前未接入的重点费用
| 费用 | 已有业务事实 | 当前缺口 |
|---|---|---|
| 退货按票处理费 | 退货单、分批收货、收货批次均已存在 | 没有按退货单去重的费用来源 |
| 退货收货操作费 | 每次 PDA 确认形成技术签收批次,当前限定单 SKU 并生成签收箱 | 技术批次不等于一次物流到货;需先冻结按件/包裹/到货批次的业务口径 |
| 退货仓租 | 完成收货时已经记录 `storageStartedAt` 和 `PENDING_PRICING` | 没有价格匹配、日库存计量、账期切分和费用发布消费者 |
| 普通库存仓租 | 有库存和出入库业务 | 缺统一计费批次、每日数量事实和最后计费截止日 |
| 销毁费 | 已保存包裹数、每包单价、总金额和 USD 币种;已有 PDA 作业后正式 `complete` 节点 | 完成节点未发布 Finance 费用;现有金额来自配置,尚未统一报价 |
| 滞留/扣留费 | 订单有收费标记、原因及暂扣/解除历史时间 | 缺稳定的暂扣期间对象、收费数量、价格和费用来源;不得用解除后的当前标记倒推是否收费 |
| 入库、出库、换箱、托盘、转仓、异常处理等 | 页面已有部分人工费用项目 | 仍是分散人工录入,未统一接入价格规则和业务动作 |
### 3.4 “费用为空”的诊断口径与证据
| 断点 | 当前证据 | 应采取的处理 |
|---|---|---|
| 未生产 | 业务完成后没有费用事实,例如退货处理/仓租/销毁,以及换标漏发分支 | 补生产者或修完成触发,不能用手工补录掩盖漏发 |
| 未审核发布 | 尾程人工费用只调用 `create + submit` | 在海外费用中心完成审核、驳回修改和发布 |
| 页面未聚合 | 尾程详情只查 `LASTLEG_ORDER + orderId` | 按稳定业务关联汇总其他来源,不能凭页面空认定未入池 |
| Finance 未接受或无需待出账 | 发布失败、被拒绝,或已由资金账户结清/供应商已直付 | 展示接收结果及结算状态,不能重复生成一笔待收待付 |
本次证据为源代码及既有契约,详见附录 A;不以历史 P0/P1 的验收报告证明新增计价和所有完成分支已经通过。本方案范围完成后须补第十三节的直接证据。
## 四、统一费用分类
### 4.1 来源类型、业务类型和费用项目分层
三者职责必须分开:
| 层级 | 示例 | 用途 |
|---|---|---|
| `sourceType` | `OVERSEAS_WAREHOUSE_FEE` | Finance 归集大类,保持稳定 |
| `businessType` | `RETURN_ORDER`、`RETURN_RECEIPT_BATCH`、`STORAGE_LOT`、`CARGO_DISCARD` | 说明费用由哪个业务对象产生 |
| `feeItemCode` | `RETURN_HANDLING`、`STORAGE_FEE`、`DISCARD_FEE` | 说明具体收的是什么费用 |
不建议用“其他”长期承接可识别费用。`OTHER_MANUAL` 只用于低频、暂未标准化的人工费用,必须填写原因并人工审核。
### 4.2 首批标准费用项目
| 费用编码 | 中文名称 | 推荐计费对象 | 常见计费单位 | 默认触发点 |
|---|---|---|---|---|
| `RETURN_HANDLING` | 退货按票处理费 | 退货单 | `TICKET` | 首个有效收货批次完成 |
| `RETURN_RECEIPT_OPERATION` | 退货收货操作费 | 实收事实 | 首期推荐 `ITEM`;`PACKAGE`/`BATCH` 需先有对应真实事实 | 每次有效签收,按实收增量计费 |
| `REPACK_FEE` | 重新打包费 | 作业单/包裹 | `PACKAGE`、`ITEM` | 重新打包完成 |
| `REBOX_FEE` | 换箱费 | 作业单/箱 | `BOX` | 换箱完成 |
| `RELABEL_SERVICE` | 换标费(沿用现有编码) | 换标单/件/箱 | `ITEM`、`BOX`,由作业与报价明确 | 所有合法换标完成分支汇合;禁止再次按新编码收费 |
| `STORAGE_FEE` | 仓租 | 库存计费批次 | `PACKAGE_DAY`、`PALLET_DAY`、`CBM_DAY` | 日结/月结或库存清零 |
| `INBOUND_OPERATION` | 入库操作费 | 入库单/收货批次 | `TICKET`、`PALLET`、`CBM` | 入库完成 |
| `OUTBOUND_OPERATION` | 出库操作费 | 出库单 | `TICKET`、`PACKAGE`、`PALLET` | 出库完成 |
| `DESTUFF_PALLET` | 拆柜打托费(沿用现有编码) | 拆柜与客户分摊 | 现有按实收 `CBM` 分摊 | 全柜入仓完成 |
| `PALLET_FEE` | 独立托盘作业费 | 独立托盘作业 | `PALLET` | 作业完成;不得对已包含于拆柜打托的同一服务重复收费 |
| `TRANSFER_FEE` | 转仓费 | 转仓单 | `TICKET`、`PALLET`、`CBM` | 转仓完成 |
| `DISCARD_FEE` | 销毁费 | 销毁申请 | 当前按申请实物包裹数;扩展 `ITEM` 需事实支持 | PDA 作业后正式 `complete` 确认完成 |
| `HOLD_FEE` | 滞留处理费 | 滞留期间 | `TICKET`、`DAY` | 解除滞留或周期结算 |
| `EXCEPTION_FEE` | 异常处理费 | 异常单 | `TICKET`、`HOUR` | 异常处理完成 |
| `OTHER_MANUAL` | 其他人工费用 | 明确业务对象 | 由录入人选择 | 人工提交并审核通过 |
费用编码是稳定契约。中文名称、外文名称和页面展示可以调整,但编码一旦产生财务来源不得复用为另一种业务含义。
现有人工项目与自动项目必须建立一份唯一目标映射。同一收费含义使用同一目标编码和收费身份;不同服务只有在合同明确可分别收费时才保留不同项目。实现时直接同步源码、调用端、报价、初始化 SQL 和测试,不维护旧编码别名、双发来源或开发存量迁移。
### 4.3 同一收费事项的唯一身份
目标收费身份至少包含:客户、业务事实类型与 ID、事实明细/作业轮次、费用项目、价格角色,以及成本侧实际供应商;周期费用另含已占用的计费日期范围。报价版本、操作人和请求幂等键不是收费身份,换人补录或换报价不能生成第二笔正常收费。
- 自动任务与人工补录共用收费身份和数据库唯一约束。人工补录必须选择真实业务事实;已有自动费时进入该费的调整流程。
- 客户应收与供应商应付身份独立;同一服务涉及多个真实供应商时按实际成本责任拆分,不能由缺失报价自动猜测供应商。
- 业务事件重放、人工与自动并发、报价补齐后重试均返回同一计费结果。需要补差时记录原来源和调整原因,不使用新业务键规避冻结。
- 仓租不能只依赖“起止日期完全相同”的键;不同范围的重叠期间也须在锁定计费对象后拒绝,见第六节。
## 五、退货按票收费设计
### 5.1 “一票”的推荐定义
推荐将“一票”定义为一个退货单 `returnNo`,不是一次 PDA 收货批次。
原因:一个退货单允许分批到仓。如果按收货批次收取按票费,同一退货单分三次收货会被收三次;这通常与客户理解的“一票退货”不一致。确实需要按每次收货收费时,应使用 `RETURN_RECEIPT_OPERATION`,不能复用 `RETURN_HANDLING`。
### 5.2 推荐触发与去重
- 触发:退货单的首个有效收货批次完成时生成一次 `RETURN_HANDLING`。
- 数量:`1`。
- 单位:`TICKET`。
- 业务对象:`RETURN_ORDER + returnOrderId + returnNo`。
- 幂等业务键:`RETURN_ORDER:{returnOrderId}:RETURN_HANDLING:{priceRole}`。
- 后续分批收货:不重复生成按票处理费;阶段 1 推荐按实收件数生成操作费,包裹/到货批次收费按 5.4 定义后启用。
- 未发生任何收货即取消:不收费。
- 已收货后退货单作废:不直接删除已发布费用;未冻结时申请作废并等待 Finance 接受,已冻结时进入待财务处理,不自动生成冲销版本。
`priceRole` 用于区分 `CUSTOMER_SALE` 和 `SUPPLIER_COST`。以上为对客简式;成本身份必须再包含实际供应商,完整约束按 4.3 执行。首个有效收货以服务端事务内的实收事实判断,不以事件到达顺序决定。
### 5.3 金额形成
```text
退货单首个收货批次完成
-> 按客户 + 海外仓 + 业务日期匹配客户销售价
-> 生成 RECEIVABLE / RETURN_HANDLING
-> 按服务商 + 海外仓 + 业务日期匹配供应商成本价(如配置)
-> 生成 PAYABLE / RETURN_HANDLING
```
没有匹配到价格时不得默认为 0 元并自动发布,应进入“待定价”队列。允许有业务但不收费时,必须命中一条明确的零价规则并记录规则版本。
### 5.4 签收技术批次与收货收费单位
当前 `ReturnReceiptBatch` 随每次 PDA 确认生成,并限定单 SKU、生成一个签收箱;它是库存追溯起点,不自动等于快递包裹、一次运输到货或一次预约到货。
阶段 1 推荐按实收 `ITEM` 数量增量计收操作费,技术签收批次只承担事实去重。例:同一退货单 30 件,分 3 次每次 10 件签收,按票费为 1 票,操作费合计为 30 件;操作员拆分确认次数不改变金额。最低收费若存在,推荐在该退货单操作费范围汇总一次,不能每按一次确认就收一次最低收费。
若合同按 `PACKAGE` 收费,先明确其含义是入仓包裹还是签收后新箱,并建立真实标识及防重复计数;若按到货 `BATCH` 收费,先补业务到货批次对象及其与技术签收的关系。两者未经确认不以技术批次数量替代。多个分批收货操作费的合计应与业务单位守恒。
## 六、仓租设计
### 6.1 为什么不能直接用当前库存乘天数
当前库存只代表此刻数量,无法证明过去每天存了多少。如果发生部分出库、拆包、合箱、转仓或库存调整,用当前数量倒推历史仓租会多收或少收,并且无法审计。
仓租必须以“库存计费批次 + 每日数量事实 + 已计费期间”计算。
### 6.2 计费批次
每一批可独立追踪实收时间和数量的库存形成一个原始计费分量 `storageLot`:
- 退货:从 `ReturnReceiptBatch` 和实收明细建立原始分量;批次数不决定最低收费次数。
- 普通入库:按真实收货明细建立原始分量,不能只引用汇总库存余额。
- 转仓:记录来源与目标仓的数量转移,结束原仓物理占用并开始目标仓物理占用;原始库龄和免租期不自动重置。仓租归属按 6.5 处理。
- 合箱/拆箱、合托/拆托:保存“原始分量—实际箱/托盘—数量/份额—生效时间”的关系,不能只拼接来源批次号。一次出库必须能扣减对应原始分量,不用 FIFO 猜测来源。
每个原始分量至少保存:客户、真实仓库、业务编号、实收 UTC 时间、仓库 IANA 时区、当地收货日期、数量及单位、原始库龄起点、免费截止日、物理占用区间和来源关系。日计费事实另保存当天数量、报价版本、免费/收费依据及金额;计费期间保存计算版本、已发布/已接受金额和截止日,不能只依靠一个最后计费日期恢复所有状态。
包裹数、托盘数、体积必须来自对应业务事实;缺少测量、仓位份额或历史来源时进入异常,不用默认体积、整托数量或当前库存倒推。
### 6.3 推荐日计费口径
以下为一套相互一致的推荐值,仍待第十四节确认;不再同时采用“同日进出收一天”和“只取日终库存”。
1. 按仓库当地自然日计费,每日区间为当地 `[00:00, 次日00:00)`;实际事件保存 UTC 时间和时区。夏令时产生的 23/25 小时仍为一个自然日。
2. 对每个不追加实收的原始分量,收货日使用实际入仓数量,后续日使用日初仍在库数量。当日出库数量当日仍计,次日减少;同日入库出库计一天,但免租优先。日界线整点出库仅归结束前的占用日。同仓移库、换托和重复事件不新增实收量。
3. 收货当地日期为库龄第 1 天,`freeDays=N` 表示前 N 个自然日免费。首次匹配收货日适用规则时冻结免费天数/截止日,后续报价改价不自动改变既有免租资格。库龄按自然日连续计算,包装转换不重置;转仓途中整日无仓储占用时不收仓租。
4. 每日先按原始分量的库龄、数量与适用报价计算高精度金额,再按自然月归集;数量/库龄阶梯须明确逐段累进或整量套档,未确认的规则不可启用。
5. 最低收费推荐按“客户 + 仓库 + 费用项目 + 价格角色 + 原币 + 自然月”汇总一次,成本侧另分供应商。最低收费与按批次的库龄阶梯是不同维度;同组命中互相矛盾的最低收费规则进入异常。
```text
日基础费 = Σ(非免租且有实际计费占用的分量数量 × 对应日单价)
月累计目标金额 = 0 (无正价应收费事实,或整组明确免收)
= max(月最低收费, Σ日基础费) (存在正价应收费事实)
本次待处理差额 = 月累计目标金额 - 本组已经生效的累计净额
```
最低收费不能由零库存、全免租或明确零价事实触发。清零结算、补结算、月末结算及同月再次入仓共用同一累计范围,不重复收最低费。正差额形成有关联明细的增量来源;零差额不发来源;负差额或历史纠错进入第九节的调整流程,不直接发布负数,也不能忽略差额。
阶段 2 同时支持 `PACKAGE_DAY`、`PALLET_DAY`、`CBM_DAY`;若业务选择按件天,还须明确增加 `ITEM_DAY`。报价单位与事实单位不匹配时停止计算,禁止自动换算。计量分量可按日追溯,Finance 接收按计费组/期间汇总的来源及其明细关联,不能把每个分量都重复套一次月最低费。
内部期间统一使用半开区间 `[periodStart, periodEnd)`,跨月强制拆分;用户显示的截止日为 `periodEnd` 前一日。仅以起止日期组成幂等键不足以防止重叠:必须锁定计费组与原始分量日期占用,保证同一日期/分量/项目/价格角色只计入一次正常费用;调整引用原明细,不新占一份日期。
试算结果保存稳定计算 ID、日期明细与输入快照;发布关联同一计算 ID,重跑返回已有结果。每个计费组至多有一个待 Finance 确认的增量或调整;未收到结果时不再次按同一累计差额收费。业务已计算、来源已发布与 Finance 已接受的截止日分开记录。
### 6.4 仓租状态
当前退货收货批次已经写入 `PENDING_PRICING` 和 `storageStartedAt`,建议扩展为统一状态:
| 状态 | 含义 | 允许动作 |
|---|---|---|
| `PENDING_PRICING` | 尚未匹配有效价格 | 补报价、重新试算 |
| `READY` | 价格和计费单位已确认 | 等待日结/月结 |
| `BILLING` | 当前账期正在计算 | 防止重复任务并发 |
| `BILLED` | 已生成至少一个期间的计费结果 | 继续下一期间;独立展示 Finance 接受状态 |
| `CLOSED` | 库存清零,全部尾期费用已被 Finance 接受或形成免收事实 | 停止新增占用计费;历史调整仍走独立流程 |
| `EXCEPTION` | 数量、价格或期间异常 | 人工修复后重试 |
状态只描述仓租计费进度,不能替代 Finance 的审核、出账和结算状态。
### 6.5 转仓与包装转换的归属
- 同一时区、同一当地日期离仓并到达目标仓,推荐当天仓租归当天首个实际存放仓,目标仓次日开始计费;同日多次转仓仍只归一个仓。跨日运输时原仓计至离仓日,途中整日不计,目标仓从实际到仓日计费。例如 9 月 1 日离 A、9 月 3 日到 B,A 计至 1 日、2 日不计、B 从 3 日计。目标仓保留真实物理到仓时间,不能为了收费归属修改库存事实。
- 跨时区转仓的自然日不可直接对齐。启用前须确认统一结算时区和归属规则;规则缺失时相关期间转人工计费异常,不自动双收,不阻断真实库存转移。
- 合拆箱/托盘推荐转换次日起按新单位计量,操作当天只计转换前单位。同日多次转换按已冻结日初/实收单位和次日最终包装事实计量,不能累加每次中间包装。
- 多批次合成一箱/一托,按已确认的实际件数或体积分摊份额,合计必须等于真实箱/托数量;各份额继续使用原始库龄与免费期。禁止每个来源批次都收一个整箱/整托。不同计价单位的份额依据不能混用,无法还原来源时停止自动发布。
- 库存盘点或迟到事实影响已计费日期时,保留旧日事实及纠正版本,进入受控重算/调整,不悄悄改历史快照或只修改当前余额。
### 6.6 评审算例(推荐口径,未代表已实现)
金额均使用原币,除注明外无最低收费;仅当报价支持对应单位时适用。
| 场景 | 输入 | 应得到的结果 |
|---|---|---|
| 同日入出 | 9 月 10 日 10:00 入 10 包,18:00 全出,0.2/包天,免租 0 天 | 收 2;若免租 1 天则收 0,不触发最低收费 |
| 免租、部分出库、跨月 | 9 月 28 日入 100 包,免租 2 天;9 月 30 日出 40 包,10 月 2 日出余下 60 包;0.1/包天,每月最低 15,同组无其他库存 | 9 月 28—29 日免费,30 日基础费 10,9 月收 15;10 月 1—2 日每天 6,10 月收 15;清零后月末重跑新增 0 |
| 全免租期间 | 一批全部在免租期内出库,月最低 15 | 基础费与应收费事实均为 0,最终收 0 |
| 同日转仓 | 已过免租的 10 包从 A 转 B,同一时区;A 为 0.2/包天,B 为 0.3/包天 | 转仓日 A 收 2、B 收 0;次日仍在 B 则 B 收 3,库龄不重置 |
| 不同库龄合箱 | A 批 4 件已过免租、B 批 6 件免费至 9 月 3 日,原各一箱,9 月 2 日合一箱;0.5/箱天,按件数分箱份额 | 9 月 2 日 A 收 0.5、B 免费;3 日 A 占 0.4 箱收 0.2、B 免费;4 日全箱合计收 0.5 |
最低收费补结算例:同组当月基础费先为 10、最低 15,清零时已收 15;同月再次入仓使累计基础费到 18,只新增 3。技术批次拆成几次、任务执行几次均不改变月累计 18。
## 七、报价与计价规则
### 7.1 在现有海外报价上直接收敛
现有海外报价已具备仓库、服务商名称、币种、生效起止日、版本、状态、计费单位、单价和最低收费。服务商当前是名称文本,尚不是可用于供应商应付的主档引用。直接将这套报价升级为结构化规则并接业务消费者,不另建平行报价。
建议至少增加以下能力:
| 字段/能力 | 说明 |
|---|---|
| `feeItemCode` | 稳定费用项目编码,替代仅靠自由文本匹配 |
| `priceRole` | `CUSTOMER_SALE` 或 `SUPPLIER_COST` |
| `customerId` | 客户销售价可限定客户;空值可作为仓库公共价 |
| `supplierId` | 成本价必须关联有效供应商主档及名称/分类快照,不能把 `providerName` 文本当作供应商身份 |
| `billingMode` | 固定按业务、按数量、按期间数量 |
| `billingUnit` | 票、批次、包裹、件、托盘、立方、公斤及其天数组合 |
| `freeDays` | 仓租免费天数 |
| `minimumCharge` / 作用范围 | 明确按业务单据还是客户仓库月度汇总;技术批次/执行任务不是最低收费单位 |
| 阶梯规则 | 明确按数量或存储天数、逐段累进或整量套档,以及取单批次还是同仓汇总 |
| `autoApproval` | 是否允许确定性计算后自动审核发布 |
| 生效版本 | 费用来源必须保存命中的报价版本和规则快照 |
### 7.2 价格匹配优先级
建议客户应收价格按以下顺序匹配:
1. 客户 + 海外仓 + 费用项目 + 业务日期;
2. 海外仓公共销售价 + 费用项目 + 业务日期;
3. 未命中则进入待定价,不自动发布。
供应商成本价格按以下步骤匹配:
1. 从真实作业委托/成本责任确定供应商;仓库默认服务商仅在确实承担该业务时作为实际供应商,不因缺价更换交易对手。
2. 按该供应商 + 海外仓 + 费用项目 + 业务日期匹配成本价;首期不再增加客户专属成本价层级。
3. 无供应商成本责任的业务不生成成本;已有成本责任但缺价时进入成本待定价,不能改取另一供应商的报价或静默省略。
同一优先级出现两条同时生效的规则必须报冲突,不允许随机取一条。
供应商应从真实作业委托/成本责任中确定,“默认服务商”必须有明确有效主档配置;没有成本责任与“成本应计但缺报价”分别展示,不能都静默省略。直付还需真实支付日期、方式、流水和凭证;仅填写 `DIRECT_PAID` 不构成已支付事实。
### 7.3 业务日期、币种、汇率与舍入
当前来源支持 CNY、USD 原币,结算币固定 CNY;USD 必须命中业务日期所在月份的有效 USD/CNY 汇率。此能力可以复用,但以下计费口径需要明确实施:
- 离散费用冻结真实收费触发的当地业务日期;仓租先按当地自然月拆分,推荐每个期间以最后一个实际收费日作为业务日期,汇率月份始终属于该计费月。
- 补报价、补结算和任务重跑不改变业务日期及汇率归属月份。缺报价、缺汇率分别进入可见队列,不用执行日期、汇率 1 或零金额兜底。
- 日金额先保留计算精度,按收费组/期间汇总,将原币金额四舍五入至 2 位、乘以冻结的 6 位汇率、将 CNY 四舍五入至 2 位。离散单笔可复用现有转换;仓租月内多次结算必须按下述双币累计差额扩展转换契约,不能把每个原币增量独立折汇后相加。
- 记录报价版本、原币单价、数量/份额、原币金额、汇率值及月份、结算金额与计算规则快照。已形成版本重放使用原快照,不随新报价或新汇率重算历史版本。
- 报价中途生效如何影响存量仓租需确认:推荐未计费日单价按当天有效报价冻结,原始免租天数/截止日保持不变;免租资格变更须单独受控审核,不由新报价静默重置。若合同锁定入仓价,则显式配置,不混用两种规则。
同一月计费组首次形成收费结果时冻结该月统一汇率快照;后续结算分别计算月累计原币目标与月累计 CNY 目标,再分别减去 Finance 已接受的双币累计净额,得到本次双币增量。待确认候选不计入已接受净额,但占用该组唯一待确认名额。
例:同组 USD 累计先 0.01、后 0.02,汇率 7.500000。首次 CNY 目标为 0.08;第二次累计 CNY 目标为 0.15,因此第二笔原币增量 0.01、CNY 增量 0.07,最终累计为 0.02/0.15,而非 0.02/0.16。增量来源保存累计计算关联和折算尾差,Finance/展示/导出校验相同口径,不能用单笔增量乘汇率把尾差“修正”掉。这是阶段 2 新增能力,当前转换服务不直接具备。
本次差额为零则不发来源;双币差额不能同时满足正金额契约时进入精度/调整异常,不伪造原币金额或放宽为零/负数来源。冻结月汇率若需纠错,走受控调整,不在后续补结算中混入新汇率。
### 7.4 零价和免收事实
Finance 当前要求原币金额与 CNY 结算金额均大于 0。明确零价或全免租应在 Lastleg 保存“已免收”事实、规则版本、数量、期间和原因,不生成 Finance 应收应付来源;免收事实也占用收费身份,重试和人工录入不能再重复收费。
缺报价不是免收。正数费用因舍入变成零时也不能标成命中零价:先按规定范围汇总,仍无法形成正金额时进入精度异常,处理口径另行确认。免收后改为收费须经过带原因的受控审核,不能因报价更新自动补收。
### 7.5 配置入口与多仓组织
当前正式入口为“通用 → 海外仓报价”,路由 `/overseas-master-data/quotes`。已支持报价列表、仓库筛选、新增、详情、编辑、启停和 CSV 导出;一个报价头绑定一个仓库。现状只有报价资料维护,尚不能等同于自动计费已经使用这些价格。
本次沿用该入口,目标组织方式为:
```text
标准费用项目(平台统一定义收费含义)
-> 选择实际海外仓
-> 客户销售价:本仓公共价 / 本仓客户专属价
-> 供应商成本价:本仓实际供应商
-> 报价版本、生效期间、币种
-> 各费用项目的单位、单价、免租、最低收费和阶梯规则
```
费用项目与仓库报价分开维护:“退货按票费”“仓租”只定义一次收费含义,A 仓、B 仓各自填写价格,不为每个仓复制新的费用编码。一个仓可同时拥有多家客户专属价和多家实际供应商成本价;客户销售价不要求虚填供应商,供应商成本价必须绑定真实供应商。
仓库必须引用国内仓库主档的实际作业仓 ID。当前报价候选来自“海外合作仓”接口,不能假定已覆盖所有实际海外作业仓;本次需统一报价候选与业务冻结的真实仓 ID,纳入需要计费的自营/合作海外仓,并校验启用状态及适用业务能力。FBA 目的仓、仓库名称文本、国内来源仓均不能替代实际作业仓。已停用仓仍允许查历史报价,不允许新启用报价。
| 示例配置(示例价格) | 仓库 | 适用对象 | 费用项目 | 单价 | 匹配结果 |
|---|---|---|---|---|---|
| A 仓公共销售价 | A 仓 | 无专属价的客户 | 退货按票费 | USD 5/票 | A 仓普通客户命中 |
| A 仓客户甲专属价 | A 仓 | 客户甲 | 退货按票费 | USD 4/票 | 客户甲在 A 仓优先命中 |
| B 仓公共销售价 | B 仓 | 无专属价的客户 | 退货按票费 | USD 7/票 | 客户甲在 B 仓也只查 B 仓规则,不套 A 仓专属价 |
| A 仓供应商乙成本价 | A 仓 | 实际受托供应商乙 | 退货按票费 | USD 2/票 | 另生成供应商应付,不改变客户销售价 |
### 7.6 怎么新增、给多个仓配置
1. 在报价列表选仓库,点击“新增报价”;未筛选仓库时,表单必须先选择一个真实海外仓。
2. 选择“客户销售价”或“供应商成本价”。销售价再选“本仓公共价”或具体客户;成本价选择真实供应商,首期按供应商和本仓维护,不另加客户专属成本价。
3. 填写报价名称/业务编号、币种、生效起止日;仓库时区随主档展示。日期口径统一为当地开始日含、截止日含,后端转换为半开区间,空截止表示持续有效。
4. 从标准项目中添加收费行,填写计费单位、单价及必要的免租、最低收费/范围、阶梯和自动审核配置。明确不收费时选择“免收”并写原因;空白项目表示未配置,不能自动视为 0 元。
5. 保存草稿,可预览金额与使用样例;执行“校验并生效”时展示覆盖对象、日期、被替代项目与冲突。校验同仓、同价格角色、同客户/供应商范围、同项目和计费条件的生效区间,禁止同优先级重叠。
多仓可逐仓新增,也可“复制为其他仓草稿”:选择一个源版本和一个或多个目标仓,逐仓生成独立草稿。复制收费项目及规则供核对,不复制启用状态、历史引用和费用;客户/供应商归属、币种、时区和适用日期均需在目标仓确认。目标仓已有报价时不覆盖,逐仓返回冲突或草稿创建结果;每个草稿可单独修改和生效。修改 A 仓的报价不会联动修改 B 仓。
新增标准费用项目应从统一费用项目维护入口完成,并定义收费对象、支持单位和业务触发。报价表里不能通过随意输入文字绕过项目定义;若当前业务尚无事实生产者,页面明确标注“已配置价格,业务计费尚未接入”,不能承诺立即自动收费。
### 7.7 怎么修改、停用和查看版本
当前报价启用时禁止编辑,但停用后可原地修改明细;计价接入后必须收敛为以下规则,不能继续停用、改旧版、再启用来改写历史价格。
| 对象 | 允许操作 | 对费用的影响 |
|---|---|---|
| 从未生效且未被引用的草稿 | 编辑、保存或删除草稿 | 不影响业务费用 |
| 已安排生效但尚未生效且未被引用的版本 | 取消计划后修改草稿,重新校验并安排 | 不可与其他同优先级报价重叠 |
| 已生效、已过期或已被费用引用的版本 | 查看;“基于此版本调价”生成新版本 | 历史报价与已形成费用快照保持可追溯 |
| 新版本生效 | 预览后原子切换新旧有效区间 | 生效后的新事实按匹配规则取价;存量仓租按 R18 的已确认规则执行 |
| 停用/结束报价 | 填终止时间与原因,显示影响项目及后续可用报价 | 不修改已有费用;后续无可用报价进入待定价 |
生效版本内容不可原地改写;报价启停/替代保存独立时间记录,旧费用仍按冻结版本及有效区间追溯。变更客户、供应商或仓库属于新建对应范围的报价,不把已生效报价移到另一个仓。
客户专属价未覆盖的项目按 7.2 逐项目查询本仓公共价;明确免收的专属规则已经命中,不再取公共价。停用专属价可能改为命中公共价,操作前必须展示影响;用户若希望停止收费,应配置明确免收,若希望阻止自动收费,应将该业务收费设为待人工定价,不能靠删掉专属价表达。
### 7.8 怎么查看和验证配置
- **全部仓库看覆盖:**列表支持仓库、销售/成本、客户、供应商、费用项目、币种、有效日期和状态筛选;显示已配置、未配置、即将到期、冲突的项目数量。只维护报价记录的现有列表不等于已具备这些覆盖指标。
- **单仓看明细:**查看公共销售价、客户专属价、供应商成本价;每行显示项目、单位、单价、免费期、最低收费范围、生效区间和版本,操作列放第一列。
- **单项看历史:**按仓库、价格角色、适用对象和费用项目查看历次版本、修改原因、生效时间和引用费用;显示当前、将来和历史版本,不以“停用”隐藏历史。
- **按业务试算:**输入真实仓库、客户、项目、业务日期、数量或仓租期间;成本另选实际供应商。返回命中范围/版本、数量依据、免租、最低费、原币与汇率计算;未命中说明缺哪个条件。试算不生成费用,也不能绕过正式业务事实创建应收。
- **从费用反查:**费用详情显示使用的仓库、项目、报价版本和计量依据,点击可看当时价格快照;当前最新价另行展示,避免用新价解释旧费用。
报价查看、维护草稿、安排/启用/停用价格、删除未使用草稿的权限应分别落实;实际费用审核仍是独立权限。仓库配置权不自动授予查看全部客户或供应商成本的权限,数据范围由服务端控制。
## 八、统一计费中心职责
建议在 Lastleg 内收敛 `WarehouseChargeService` 和 `StorageBillingService` 两类职责,具体类名可在实现阶段确定。
### 8.1 `WarehouseChargeService`
- 接收退货、入库、出库、换标、换箱、托盘、转仓、销毁、滞留和异常处理等已完成业务事实;
- 按业务日期匹配客户销售价和供应商成本价;
- 计算数量、单价、最低收费和金额;
- 生成待定价、待审核或已审核费用;
- 调用现有海外费用来源服务生成不可变版本和 Outbox;
- 保证同一业务动作重放不重复收费。
业务完成与计费事实/待处理任务必须在 Lastleg 本地事务内可靠落地。缺报价、缺汇率进入计费队列,不应让真实收货、销毁等作业因为价格尚未维护而无法完成;也不能先完成业务再用无持久化保障的临时回调计费。
### 8.2 `StorageBillingService`
- 管理库存计费批次的开始、转移和结束;
- 基于库存流水或每日库存快照计算历史数量;
- 应用免费天数、阶梯价、最低收费和账期切分;
- 记录最后计费截止日,支持任务失败后安全重跑;
- 生成客户仓租应收和供应商仓储成本;
- 对异常库存、缺报价和规则冲突进入异常队列。
计算锁与并发门禁以数据库事务、版本和唯一约束为准,不能仅靠 `BILLING` 字样或单机定时任务防重复;失败重跑应复用已保存的输入和计算身份。
### 8.3 发布到现有费用来源
现有 `ll_finance_fee_source` 已包含客户、供应商、方向、结算方式、数量、单位、单价、计费期间、币种、原币金额、汇率、审核和发布状态,能够承接上述结果。首期应优先复用,不应把仓租明细直接写入 Finance 数据库。
需要扩展的是业务类型校验和来源关联,使 `RETURN_ORDER`、`RETURN_RECEIPT_BATCH`、`STORAGE_LOT`、`CARGO_DISCARD`、`WAREHOUSE_TRANSFER`、`HOLD_PERIOD` 等业务对象可以安全发布为 `OVERSEAS_WAREHOUSE_FEE`。
仓租月度汇总涉及多个原始分量时,费用绑定真实计费结算记录(目标业务类型如 `STORAGE_BILLING`),通过明细关联各 `storageLot`;不能随意选一个批次冒充整笔费用归属。业务类型和表名在实现契约冻结时确定,并同步归属校验、事件、查询与页面。
现有来源表不能替代待定价事实、日计量明细、报价快照、收费身份、资金分配和 Finance 结果记录。只扩展必要模型,保留来源表作为统一发布出口;新接口同时纳入 Gateway、OpenAPI 和权限清单。
## 九、审核、调整与作废
### 9.1 推荐审核策略
| 场景 | 推荐策略 |
|---|---|
| 已命中有效报价、数量来自已完成业务事实、计算无异常 | 可按费用项目配置自动审核并发布 |
| 人工录入费用 | 必须人工审核 |
| 未命中报价 | 待定价,不能发布 |
| 多条报价冲突、数量为负、计费期间重叠 | 异常,不能发布 |
| 零价规则/全免租 | 业务侧记录免收及依据,不发布零金额 Finance 来源 |
| `OTHER_MANUAL` | 必须填写原因并人工审核 |
当前派送人工金额在转派送时自动审核,与本节目标不一致,必须列入阶段 0 改造。人工录入、业务作业完成和费用审核是独立权限;标准报价自动审核必须能追溯规则授权,不能由页面自行声明“自动费用”。
### 9.2 草稿、驳回和调整边界
- 未发布草稿/驳回费用允许按版本编辑并重新提交;补后端修改接口、操作历史、页面和权限。待审核费用不得绕过重新提交静默改金额。
- 已发布费用修改生成候选新版本,作废生成变更命令。Finance 接受前保留原有效版本;每个来源最多一个待确认变更。
- 已进入有效账单、结算单或资金账户结算的来源不可直接替换或作废。业务侧创建关联原来源/原单据的调整申请,由 Finance 按可执行流程处理。
- 本次阶段 0/1 交付冻结拒绝及“待财务处理”队列,不宣称已收款退款、供应商退款、资金账户退款或任意负向冲销已经可用。需要新增这类动作时,先明确单据、权限和收付款反向处理;不得用负金额来源或反转应收应付方向代替。
- Finance 页面不编辑上游业务数量和单价;提供真实来源定位和跳转,由海外业务维护计价事实。
### 9.3 跨区接受结果与冻结竞态(本次新增目标)
当前海外 Relay 收到的是 Event Bridge 接收确认,Finance 在消费时才最终校验冻结状态;本地已发布不证明国内已经入池。
目标流程:
```text
业务审核通过 -> 本地计费版本/变更命令 + Outbox
-> Event Bridge 接收(仅投递状态)
-> Finance 锁定来源并校验版本、快照、占用与资金关系
-> 同事务保存接受/拒绝结果、必要来源变更及结果 Outbox
-> 海外消费结果,接受才切换有效版本或确认作废;拒绝保留原有效版本
```
业务审核状态、投递状态和财务同步状态分别保存。财务同步至少区分 `PENDING_FINANCE`、`ACCEPTED`、`REJECTED`;超时/网络失败保持待确认并重试,不当作业务拒绝或成功。首次发布被拒绝也必须显示原因,不能进入“已入池”。
每次命令携带稳定 `commandId`、来源身份、目标版本、预期有效前序版本和快照哈希;作废引用预期有效版本。同命令同内容重放返回原结果,同命令异内容或同版本异快照拒绝。预期有效前序指最后被 Finance 接受且仍有效的版本,不是上一个本地候选;首次发布无有效前序时显式为空。
候选被审核或 Finance 拒绝后保留审计,修订生成新候选和新命令,仍以最后有效版本为基准,不修改原拒绝命令载荷,也不等待被拒绝候选生效。例如 V1 有效、V2 被拒绝,V3 可基于 V1 申请;候选编号允许有未生效间隔。已知前序正在投递而尚未到达时等待重试,真正有效版本冲突则返回拒绝,不能无限等待。迟到/重复结果仅更新对应命令,不回退当前有效版本;业务拒绝结果应可靠回传,不能只有无休止重试日志。
Finance 的来源变更与创建对账/结算占用必须锁定同一来源,在事务内原子裁决。海外先查“未冻结”再发布、或缓存一份冻结状态,均不能替代这个最终校验。
此机制应同步修改 Lastleg、Finance、公共事件契约与 Event Bridge 的双向路由、Inbox/Outbox 和权限/内部服务校验;不通过跨区数据库回查。开发阶段直接使用新目标协议,更新全部生产者、消费者和测试,不引入双协议或旧数据补偿。
### 9.4 资金账户结算关联
当前采购/换标费用与资金结算事件支持先后到达,Finance 按客户、业务类型、业务单号和金额匹配,成功后来源变为 `SETTLED`,不再进入对账候选。这一能力须保留,但不能据此认为多费用拆分或所有事件竞态已经覆盖。
- 现有采购/换标业务身份与收费粒度不因统一展示而改变。若一笔扣款对应多笔费用,建立明确的结算关联 ID 和分配明细,校验分配总额与扣款一致;不得继续靠同额猜测关联。
- 计划走资金账户的应收来源,从进入 Finance 起先处于“待资金结算”,在结果到达前也不能暂时进入 `AVAILABLE` 对账池;成功后 `SETTLED`,失败进入异常。
- 切换为账期收款必须显式处理原资金冻结/扣款及分配关系并校验状态,不能扣款失败就自动转待出账。
- 验收须覆盖费用先到、扣款先到、重复/迟到事件、同单多个同额项目、合计不等及出账并发。
## 十、页面与权限建议
### 10.1 海外仓侧
新增或收敛为“海外仓费用中心”,至少包含:
- 待定价:未找到报价、报价冲突、计费单位缺失;
- 待审核:人工费用和需要人工确认的自动费用;
- 已发布:分别展示业务版本、投递状态、Finance 接受结果及当前有效版本;
- 计费异常:重复期间、负库存、数量缺失和事件投递失败;
- 仓租批次:查看开始时间、免费期、已计费截止日、当前数量和历史期间;
- 业务详情费用页签:按稳定业务关系汇总所有相关来源,并标明直接费用、客户分摊、共享费用及资金结清状态。
聚合查询不能用单号模糊匹配,也不能只查 `LASTLEG_ORDER`。订单、入仓、柜、派送、换标和退货等关系由服务端校验客户归属;跨客户柜费只展示当前客户的分摊。同客户多个订单共用一笔费用时,明确分摊金额或“共享费用”引用,不把整笔金额重复计入每票小计。聚合返回同一来源的当前有效版本,待确认变更另行展示。
待审工作台包括编辑草稿、提交、批准、驳回、修改重提、调整/作废申请和结果查询;Finance 侧提供按稳定来源身份跳转的真实入口,不能仅提示“请到海外业务处理”。
报价页把自由文本费用项目和单位改成标准选择,明确客户销售价/供应商成本价,供应商绑定主档。应付表单补 `ON_ACCOUNT/DIRECT_PAID` 和直付证据录入。免收、待定价、待汇率、待资金结算、Finance 拒绝分别显示,避免统一呈现为空或零。
### 10.2 Finance 侧
继续使用现有客户应收应付、对账单和应付结算页面,不在 Finance 新增仓租计算页面。列表和详情需展示:
- 来源系统、来源类型、业务类型;
- 业务单号、退货单号或库存计费批次号;
- 费用项目;
- 数量、单位、单价、计费期间;
- 海外仓、客户、供应商、结算方式;
- 来源版本和调整关系。
现有 Finance DTO 和费用页已有数量、单位、单价、期间、原币与汇率字段,应复用;本轮补业务类型、仓库、结算路径、变更结果及关联跳转。来源拒绝尚未入池时从海外异常入口查询,不能依赖 Finance 费用池一定存在该记录。
### 10.3 权限最小集合
- 海外仓费用查看;
- 海外仓费用人工新增;
- 海外仓费用草稿/驳回修改与提交;
- 海外仓费用审核;
- 海外仓费用调整/作废;
- 海外报价维护;
- 仓租试算与结算;
- Finance 应收查看/出账;
- Finance 应付查看/结算。
查看权限和写权限分离,业务详情只读权限不能隐式获得报价维护、审核或作废权限。
客户页面只展示本企业应收及允许公开的计费依据,不暴露供应商成本、内部审核信息和平台付款凭证。新增写权限同步 IAM、Controller、OpenAPI 与页面;查询按列表权限覆盖详情只读,操作列放第一列。
## 十一、分阶段实施建议
阶段是实现和验收顺序,不排除全流程范围。以下均为计划,不把本文修订视为代码或部署完成。
### 阶段 0:先修已有链路的漏发、审核、展示与一致性
范围:
- 修正换标所有合法完成分支的费用发布及资金结算;修正拆柜打托费用的项目/业务身份与通用调整校验。
- 派送同项目支持独立应收应付身份,人工费进入审核;先明确转派送动作与财务审核的独立状态。
- 尾程费用按稳定关系聚合,补来源跳转、共享费用/分摊展示;复用柜级费用已有能力。
- 补草稿/驳回修改 API、统一待审页面、版本/幂等和权限;补应付直付表单与证据。
- 建立人工与自动共用的收费身份、免收事实与待处理队列,防止后续自动化重复收费。
- 落地 Finance 接受/拒绝回传和来源变更并发裁决;保留最后有效版本,冻结费用转待财务处理。
- 保留并补强资金账户关联,资金未确认前不得进入对账候选。
完成标准:新建业务可分别验证“未生成、待审核、待确认、已接受、已结清、已拒绝”;换标合法完成不漏发,同一派送项目应收应付各一笔;人工费可以驳回修改重审;已冻结来源的调整与出账竞态不会让双方有效金额不一致。不是只验证页面有数据或 Outbox 已发送。
### 阶段 1:退货、销毁和固定滞留费
范围:
- 退货按票处理费;
- 退货收货操作费,推荐先按实收件数,不启用未经定义的到货批次固定费;
- 销毁正式完成后的费用;现有单据已展示金额与最终收费必须一致,报价变更不能静默改已确认单价;
- 滞留固定处理费,先建立每次暂扣至解除的稳定期间身份,保存当次收费标记;解除后触发,重复暂扣是否每次收费按合同规则;
- 标准费用项目和结构化报价最小字段;按 7.5—7.8 实现实际自营/合作仓候选、多仓独立报价、客户公共/专属价、供应商成本价、草稿复制与不可变版本。
完成标准:上述费用从业务事实生成应收及已配置真实成本责任的应付,跨区得到明确接受结果;未冻结费用可调整/作废,冻结费用拒绝并进入待财务处理。缺报价/汇率不丢业务事实,免收不发零金额来源,重复实收或拆分 PDA 操作不改变应收费总额。
### 阶段 2:仓租闭环
范围:
- 退货与普通入库的原始计费分量、包装/托盘来源份额和实际数量事件;
- 每日占用事实、时区、免费期、部分出库、合拆箱与转仓计费归属;
- 月度最低收费累计、库龄阶梯、跨月切分、清零及补结算;
- 仓租客户应收和供应商成本;
- 待定价、异常和补结算工作台。
完成标准:6.6 算例、重叠期间、迟到事实、相同输入重算和重复发布均有直接验证;每笔月度费用可追溯到历史数量、报价与汇率。最低收费不随技术批次数或任务次数增加,合箱后份额守恒,结果未确认时不重复发布累计差额。跨时区规则缺失的期间必须显示异常,不能宣称自动计费覆盖。
### 阶段 3:其余作业费、海外本土业务与供应商成本
范围:
- 入库、出库、换箱、重新打包、托盘、转仓、异常处理等;
- 海外入仓、本土卡车、本土散板的业务触发、计价、审核与页面;
- 采购、拆柜、派送、换标的供应商成本与客户销售价独立计价,明确真实供应商及月结/直付;
- 按合同需要扩展滞留按天费、真实到货批次费,不复用普通仓租或技术签收次数冒充;
- 统计报价命中率、待定价量和投递异常量。
完成标准:第三节每项都有明确生产者、触发点、收付方向、业务归属、审核、调整边界、页面和验收证据;已有标准业务事实与算法的新增项目通过配置接入,新业务动作仍需补事实适配,不能承诺所有费用都“只配规则无需开发”。Finance 继续复用统一入池链路。
| 覆盖对象 | 首次交付阶段 | 后续范围 |
|---|---|---|
| 已有接柜/拆柜/派送/换标/采购、尾程人工费 | 0:修现有发布、审核、关联和展示 | 3:补自动定价及真实供应商成本 |
| 退货按票、实收操作、销毁、固定滞留 | 1 | 3:确有合同需要时扩展收费单位/按天滞留 |
| 普通库存与退货仓租 | 2 | 同阶段覆盖最低收费、合拆箱、转仓与异常边界 |
| 海外入仓、本土卡车、本土散板及其他仓内作业 | 3 | 每种业务逐项留验收证据,不只验证通用 API |
## 十二、预计改造范围
评审通过后,预计涉及以下部署单元。此表用于评估范围,不是已经确认的开发清单。
| 部署单元 | 主要改造 | 不应承担的职责 |
|---|---|---|
| Lastleg | 收费身份、结构化报价、业务触发、日计量、草稿修改/审核、变更命令及结果 Inbox | 不生成 Finance 账单,不修改财务余额 |
| Admin 海外仓/海外业务/通用资料模块 | 报价与供应商绑定、审核/异常队列、仓租、资金关联状态及聚合费用页签 | 不在前端自行计算最终金额 |
| Finance | 来源接受/拒绝及结果 Outbox、冻结原子裁决、待资金结算门禁和必要分配关系、查询展示 | 不实现退货、库存或仓租算法 |
| Admin Finance 模块 | 展示业务单号、费用项目、数量、期间、供应商和来源版本 | 不允许修改上游业务计价事实 |
| 公共事件契约 / Event Bridge | 扩展费用命令身份和接受结果契约、双向路由、幂等、拒绝与重试分类 | 不跨区域回查海外数据库,不把转发成功当消费成功 |
| Gateway Overseas / IAM | 随新增或变化接口同步路由、内部结果入口隔离、权限资源及初始化 SQL | 不在网关实现计价与财务状态机 |
| 国内 Warehouse 主档接口(按实际需要) | 支持按计费适用范围查询真实自营/合作海外仓,供报价复用;保持唯一仓库 ID | 不在 Lastleg 复制另一套仓库主档或用 FBA 目的仓替代 |
| Admin/Client/PDA 受影响调用端 | 同步费用查询、业务身份及字段类型;PDA 继续只提交真实作业事实 | 不在终端决定最终价格、审核结果或 Finance 状态 |
实现前需要特别核对一个现状:退货收货批次中的 `overseasWarehouseId` 当前为字符串,而统一海外费用来源的 `warehouseId` 为数值类型。进入开发时应直接统一当前目标类型和调用端,不能靠运行时猜测或保留双类型兼容。
阶段 0 最小实现清单应逐项列出:草稿/驳回修改、统一待审查询与动作、业务关联费用查询、来源变更命令、Finance 结果消费及查询、资金待结算标识、直付证据。每项对应 DTO/表字段、Controller、Gateway、OpenAPI、权限与直接受影响检查;不得仅按页面数量估算范围。
代码实施遵守当前工作区/当前分支、最新初始化基线和既有服务数据库边界;本方案不包含历史测试数据迁移、回填、旧协议兼容或自动部署授权。新增/变更 API 按仓库规则执行 Gateway 合同,事件变更覆盖生产者、消费者、桥接、乱序和事务回滚检查。
## 十三、验收场景
以下为本方案验收清单,全部待实施验证。每项保存业务事实、Lastleg 计费/来源版本、事件结果、Finance 状态以及页面/接口证据,不能以历史报告代替。
| 编号 | 阶段 | 场景与断言 |
|---|---|---|
| A01 | 0 | 正价纯 SKU、退货 SKU、需要出库的换标分别走合法完成路径,费用与资金结算各一次;重复完成不增加金额 |
| A02 | 0 | 自动拆柜打托费可在未冻结时按正确业务身份调整;客户分摊守恒,不能误标为供应商应付 |
| A03 | 0 | 同一派送费用项目可产生独立应收和应付;人工金额未经审核不入池,不阻断已完成的真实作业事实 |
| A04 | 0 | 尾程人工费新增、提交、驳回、修改、重审、接受全链可操作;旧版本并发编辑被拒绝 |
| A05 | 0 | 尾程详情聚合接柜、派送、换标等来源,同一来源只显示一次;跨客户柜费只显示本人分摊,共享费用不重复计小计 |
| A06 | 0 | 人工补录和自动任务并发命中同一收费身份,只产生一笔正常费用;免收也不能重跑再收费 |
| A07 | 0 | Finance 接受前海外保留原有效版本;拒绝/超时、重复结果、迟到结果、前序事件晚到均不造成版本倒退或假成功;V2 被拒绝后 V3 可基于有效 V1 接受 |
| A08 | 0 | 来源调整/作废与创建账单/结算并发,Finance 原子裁决;冻结冲突进入待财务处理,不产生负数来源或覆盖已出账金额 |
| A09 | 0 | 资金事件与费用事件双向乱序、同单同额多项目、分配金额不等;待资金结果期间不可出账,成功后只结算一次 |
| A10 | 1 | 同一退货单 100 件分多个 SKU、2/3/5 次 PDA 确认,按票费均 1 票、按件费均 100 件;重复请求不增量,不按技术批次收最低费 |
| A11 | 1 | 销毁审核通过但未正式完成不收费,PDA 作业后正式完成收费一次;数量与已确认单价可追溯,取消/拒绝不收费 |
| A12 | 1 | 暂扣、解除、再次暂扣按不同真实期间关联,保留当次收费标记;重复解除不重复收费 |
| A13 | 1/3 | 有销售价、无成本责任时只生成应收;有成本责任但缺成本价则成本侧待定价,不虚构供应商也不静默漏记 |
| A14 | 0/1/3 | `ON_ACCOUNT` 进入应付,`DIRECT_PAID` 有完整付款证据且只形成成本;缺证据或供应商错误被拒绝 |
| A15 | 1/2 | 缺报价、报价冲突、缺汇率各自可诊断并重试,业务完成事实不丢;明确零价/全免租不发零金额来源 |
| A16 | 2 | 6.6 全部算例金额一致;7 天免租从第 8 天开始收费,日界线与夏令时按当地自然日处理 |
| A17 | 2 | 月中清零、同月再次入仓、补结算与月末任务共用累计最低费;重放和待 Finance 确认时不再发同一差额 |
| A18 | 2 | 完全相同期间和不同起止但重叠期间均不能重复计费;迟到库存事实不能静默修改已出账历史 |
| A19 | 2 | 合拆箱/托盘保留原始数量与免费期,份额守恒;同日转仓不双收,跨日到仓从真实到仓日计,跨时区无规则时进入明确异常;新单价不重置旧免费期 |
| A20 | 1/2 | 次月补价/重跑仍使用原业务月份;仓租分两次 USD 0.01、0.01,汇率 7.5,CNY 分别 0.08、0.07,累计与单次月结 0.15 相同;正数舍入为零不冒充免收 |
| A21 | 3 | 入仓、本土卡车、散板各自从真实业务动作产生费用;采购等供应商成本与客户应收独立,并具有正确页面入口 |
| A22 | 全部 | 同命令同载荷幂等、异载荷拒绝;事务回滚无半笔来源;越权/跨客户查询与写入被拒绝,客户不见供应商成本及平台凭证 |
| A23 | 1 | A/B 两仓分别配置同一项目;同一客户在 A 用专属价、在 B 用 B 仓公共价,不能跨仓取价;销售与成本各自匹配 |
| A24 | 1 | 从 A 复制到 B/C 只生成独立草稿;不覆盖已有价、不自动启用;修改 A 不改变 B/C;自营和合作真实作业仓均可按权限配置 |
| A25 | 1 | 已生效/已引用版本不能停用后原地改金额;调价产生新版本,旧费用可反查原价;新旧生效区间无同优先级重叠 |
| A26 | 1 | 专属项目缺失、明确免收、专属价停用分别命中公共价/免收/预览后的有效规则;无报价、未接计费和零价三种状态可区分 |
| A27 | 1/2 | 全仓覆盖、单仓明细、单项历史和真实业务试算可查询;试算不产生费用,历史费用不因最新报价变化而改变 |
自动化接口/计算检查与页面验收分开记录。Admin/Client 页面按 1920×1080、100% 缩放执行人工操作;当前无本稿变更后的人工截图,状态为“待人工截图确认”。真实 HTTP、数据库操作和部署仍需对应轮次明确授权,本次文档修订不执行。
## 十四、本次评审需要拍板的问题
下一轮优先确认退货操作费单位、仓租日数量、最低收费、转仓和合箱口径。以下全部为待确认推荐值;“按建议修订文档”不等于已批准收费合同。现有 Finance 服务边界、正金额入池、已结算不得重复出账等已确认约束不重复列作开放问题。
| 编号 | 待确认问题 | 推荐口径 |
|---|---|---|
| R1 | 退货“一票”按什么定义 | 一个退货单 `returnNo` |
| R2 | 退货按票费何时产生 | 首个有效收货批次完成;未收货取消不收费 |
| R3 | 是否另收操作费,按什么单位 | 首期按实收 `ITEM`,同票总件数决定金额;按包裹/到货批次需先补真实对象,不按 PDA 提交次数收费 |
| R4 | 销毁收费节点和已确认价格 | 使用已有正式 `complete` 节点,单据已确认数量/单价与收费一致;不在仅审核通过时收费 |
| R5 | 仓租入仓当天是否算第 1 天 | 推荐算第 1 天,按仓库当地日期 |
| R6 | 同日入库并出库是否收 1 天仓租 | 推荐计占用 1 天,但仍先应用免租;有 1 天免租则当日为 0 |
| R7 | 仓租以哪个数量为准 | 收货日实收量、后续日日初量;出库当日仍计、次日减少;不取单纯日终余额 |
| R8 | 首批仓租结算周期 | 推荐自然月结;库存清零时立即结清尾期 |
| R9 | 客户销售价未配置时怎么办 | 待定价,不按 0 元、不自动发布 |
| R10 | 自动计算费用是否需要逐笔人工审核 | 推荐标准规则自动审核,人工和异常费用人工审核,可按项目配置 |
| R11 | 是否首批同时生成供应商成本 | 推荐数据模型一次支持,阶段 1 可先对已明确服务商的费用启用 |
| R12 | 仓租阶梯范围及算法 | 库龄阶梯推荐按原始计费分量、逐段累进;按客户汇总数量或整量套档的合同需显式选择,不能自动解释 |
| R13 | 免费天数按自然日还是满 24 小时 | 推荐仓库当地自然日,便于对账和月结 |
| R14 | 负库存或历史库存调整如何处理 | 停止自动发布并进入异常,不自动生成负仓租 |
| R15 | 最低收费按什么范围、是否清零后重收 | 推荐客户+仓库+项目+角色+原币+自然月,成本另分供应商;同月只累计一次,全免租/零价不触发 |
| R16 | 转仓日与跨时区归属 | 同时区同日转仓归首个实际存放仓、目标次日计;跨日运输目标从真实到仓日计,不重置免租。跨时区启用前专项确认,无规则则异常 |
| R17 | 合拆箱/托盘如何分摊 | 推荐次日按新单位,以确认的件数/体积分份额并保留各自库龄;接受小数箱天/托盘天,不能每个来源各收一整单位 |
| R18 | 存量仓租调价、业务日期与金额舍入 | 推荐未计费日适用新单价、既有免费期不变;期间最后收费日确定汇率月,同组冻结月汇率并按双币累计目标结算尾差 |
| R19 | 已收款、已付供应商或资金账户已扣款后的差错 | 阶段 0/1 先交付冻结拒绝和待财务处理;需要新增退款/冲销闭环时单独冻结单据、权限和资金处理,不能当作现成能力 |
R15 的仓租最低收费范围不自动套用于退货按件费;退货若需要最低收费,建议按退货单汇总一次,具体金额与适用范围随 R3 确认。上述算例随着确认结论同步调整,不能正文一套、验收另一套。
## 十五、评审通过后的下一步
1. 下一轮先评审 V0.2 的接入矩阵、阶段 0 和仓租算例,记录 R1—R19 中实际确认的结论;未讨论项保持待确认。
2. 阶段 0 不以仓租商业口径未定为由搁置现有漏发、审核和展示修复;开工前形成该阶段表字段、API、事件、页面、权限和验证清单。
3. 根据阶段 1 相关确认结果冻结收费身份、项目编码、单位、触发和金额快照,实施退货、销毁及固定滞留费。
4. 阶段 2 在 R5—R8、R12—R18 口径与可计算样例一致后实施历史数量、份额和周期计费;阶段 3 补齐范围矩阵剩余业务。
5. 各阶段交付时分别报告本地检查、真实 HTTP、人工页面证据和未覆盖边界,不用通用费用接口通过代替全部业务完成。
## 十六、与现有契约的关系
- Finance 服务边界、费用来源唯一键、版本和跨区域 Outbox/Inbox 机制继续遵循 [Firstleg-Finance 跨服务契约](Firstleg-Finance跨服务契约.md)。
- 费用进入统一费用池后的对账、应收应付与结算继续遵循 [财务费用入池 P0 闭环](财务费用入池P0闭环.md) 和 [财务对账结算 P1 闭环](财务对账结算P1闭环.md)。
- 本文专门补充海外仓费用如何形成业务费用事实;与历史盘点冲突时,以后续评审确认和实现契约为准。
- 本稿是待确认方案,不覆盖已确认的服务边界、资金主账和区域通信约束。接受结果回传、待资金结算和多来源资金分配属于新增目标,评审通过后必须同步修订受影响契约,不能只改本稿就宣称闭环完成。
## 附录 A:当前实现证据入口
以下入口用于复核“当前状态”;代码可能随实施变化,不反向证明本稿新增目标已经完成。代码入口均相对本文件可访问。
| 事实/问题 | 证据入口与定位符号 |
|---|---|
| Finance 待出账范围、应付结算 | [FinanceQueryService](../../baiyue-firstleg/finance/src/main/java/com/baiyue/finance/service/FinanceQueryService.java)、[FinanceSettlementService](../../baiyue-firstleg/finance/src/main/java/com/baiyue/finance/service/FinanceSettlementService.java) |
| 正金额、冻结检查与费用后到的资金关联 | [BusinessFeeSourceEventService](../../baiyue-firstleg/finance/src/main/java/com/baiyue/finance/service/BusinessFeeSourceEventService.java) |
| 资金结果后到的费用关联 | [WalletCommandEventService](../../baiyue-firstleg/finance/src/main/java/com/baiyue/finance/service/WalletCommandEventService.java) |
| 来源字段、审核发布、调整和作废 | [OverseasFeeSource](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/financefee/entity/OverseasFeeSource.java)、[OverseasFeeSourceService](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/financefee/service/OverseasFeeSourceService.java) 的 `create/submit/review/adjust/voidSource` |
| 通用业务归属校验及当前接口动作 | [OverseasFeeBusinessGuard](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/financefee/service/OverseasFeeBusinessGuard.java)、[PlatformOverseasFeeSourceController](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/financefee/controller/PlatformOverseasFeeSourceController.java) |
| 桥接接收与实际入池的差别 | [OverseasFeeOutboxRelay](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/financefee/service/OverseasFeeOutboxRelay.java) |
| USD/CNY 与按业务月份转换 | [OverseasFeeCurrencyConverter](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/financefee/service/OverseasFeeCurrencyConverter.java) 的 `convert` |
| 尾程详情只查本业务类型,人工费只提交 | [LastlegOrderService](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/service/LastlegOrderService.java) 的 `detail/createFee` |
| 换标完成分支差异 | [RelabelApplicationService](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/relabel/service/RelabelApplicationService.java) 的 `changeStatus/confirmCompletion` |
| 拆柜打托应收及通用调整身份不一致 | [DestuffingPalletCostService](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/DestuffingPalletCostService.java) 的 `fee`,联查 `OverseasFeeBusinessGuard` |
| 派送人工费用与仅按项目去重 | [DeliveryTransferService](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/service/DeliveryTransferService.java) 的 `validateTransferFees` 及 `publishApproved` 调用 |
| 退货技术批次与仓租起点 | [ReturnReceiptService](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/returnreceipt/service/ReturnReceiptService.java) 的 `confirm`、[ReturnReceiptBatch](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/returnreceipt/entity/ReturnReceiptBatch.java) |
| 合箱来源与实际数量 | [ReturnInventoryService](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/returnreceipt/service/ReturnInventoryService.java) 的 `merge/createReceiptCarton` |
| 销毁现有金额与正式完成节点 | [CargoDiscardService](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/discard/service/CargoDiscardService.java) 的 `create/review/complete` |
| 暂扣收费标记与历史 | [LastlegOrderCommandService](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/service/LastlegOrderCommandService.java) 的 `hold` |
| 尾程人工费用页面和柜级审核入口 | [LastMileOrderDetailView](../../apps/admin-web/src/modules/overseas-warehouse/pages/LastMileOrderDetailView.vue)、[ContainerLastLegFeesPanel](../../apps/admin-web/src/modules/container-loading/components/ContainerLastLegFeesPanel.vue) |
| Finance 来源展示与海外来源动作提示 | [FinanceCustomerArapView](../../apps/admin-web/src/modules/finance/pages/FinanceCustomerArapView.vue) |
| 现有报价入口与增改查界面 | [adminNavigation](../../apps/admin-web/src/core/navigation/adminNavigation.ts)、[OverseasQuotesView](../../apps/admin-web/src/modules/overseas-master-data/pages/OverseasQuotesView.vue) |
| 报价仓候选、启停及停用后原地编辑 | [OverseasQuoteService](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/masterdata/quote/service/OverseasQuoteService.java)、[DomesticPartnerWarehouseClient](../../baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/masterdata/quote/client/DomesticPartnerWarehouseClient.java) |
## 附录 B:下一轮 review 建议顺序
1. 先看 7.5—7.8:多仓新增、公共/专属销售价、供应商成本价、复制与版本是否符合实际操作。
2. 再看第三节与阶段 0:确认先修已有链路的漏发、审核和展示,并接受跨区结果与资金待结算的必要改造范围。
3. 按 5.4 和 6.6 算例确认收费结果:退货按件、同日进出、免费期、最低收费、转仓与合箱。
4. 最后按第十四节记录具体确认项,再冻结阶段接口/数据契约;未实现或未验证的能力继续保持待办,不写成已上线。