Test #1

Merged
admin merged 256 commits from test into main 2026-09-28 16:01:16 +08:00
8 changed files with 407 additions and 89 deletions
Showing only changes of commit 60d2f8e097 - Show all commits
+1 -1
View File
@@ -7,7 +7,7 @@
- [一期文档](一期/README.md):一期范围、开发进度和头程订单最小闭环。
- [二期文档](二期/README.md):预约取货、到仓收货、实测差异和指定库位闭环。
- [三期文档](三期/README.md):智能排柜、订舱、拖车、PDA 拣货、报关协同和国内出仓闭环。
- [独立任务协作登记](独立任务协作登记.md):以稳定 `routing_key + task_id` 维护长期复用通道,并保留一次性任务执行历史。
- [独立任务协作登记](独立任务协作登记.md):以稳定 `routing_key + task_id` 维护长期复用通道,并临时登记尚未结束的一次性任务。
## 跨阶段参考
+15 -47
View File
@@ -1,6 +1,6 @@
# 独立任务协作登记
> 本文件登记用户可独立打开和查看的 Codex 任务/对话,不登记子代理。长期复用通道负责创建前路由,执行历史只负责追溯;任务名称始终只是展示标签。
> 本文件登记用户可独立打开和查看的 Codex 任务/对话,不登记子代理。长期复用通道负责创建前路由,当前执行任务只保留未结束工作;任务名称始终只是展示标签。
## 长期复用通道
@@ -10,71 +10,39 @@
|---|---|---|---|---|---|---|---|
| `phase3.control.release-acceptance` | `019fdf57-2f16-7cf1-88f0-a75854ed7629` | 三期总控|发布与验收 | 三期发布、测试环境验收、阻断分类与最终汇总 | 三期总控 | idle | 2026-08-11 | 后续三期发布与验收优先向此 ID 续发;一次性复验或部署默认使用子代理 |
| `finance.control` | `019feaa3-9f10-7ab0-8023-4b121ff9662c` | 财务模块-总控 | 财务范围、跨端契约、后端/Admin/Client 协调与汇总 | 财务总控 | active | 2026-08-11 | Finance一期最终验收FAIL;正在协调11个一期P0 operation返工与独立复验 |
| `database-comments.control` | `019fef70-b644-7071-8b76-975b8940985c` | 数据库注释治理 | 数据库中文注释规范、模块分派、统一 SQL 集成与总体验收 | 数据库注释总控 | idle | 2026-08-11 | 后续数据库注释工作优先向此 ID 续发;模块盘点和修改默认使用子代理 |
| `database-comments.control` | `019fef70-b644-7071-8b76-975b8940985c` | 数据库注释治理 | 数据库中文注释规范、模块分派、统一 SQL 集成与总体验收 | 数据库注释总控 | idle | 2026-08-11 | 本地 MySQL 8.4 全场景验收 PASS;开发 MySQL 8.0.45 已执行统一 SQL 并取得唯一 PASS,九库表/字段中文注释缺口均为0;后续工作继续复用此 ID |
### 通道路由规则
- `routing_key` 按长期职责确定,格式为 `<domain>.<unit>.<responsibility>`;不包含序号、日期、批次、提交号或本轮动作。
- 命中未归档通道后直接使用其 `task_id` 通信;标题相同或不同均不影响寻址。通道开始新一轮工作时改为 `active`,一轮工作结束后回到 `idle`。
- `completed` 只用于下方一次性执行历史,不是长期通道状态。长期通道不得因为一轮工作完成而失去复用资格。
- 长期通道不得使用 `completed`;一轮工作完成后回到 `idle`,继续保留复用资格。
- 用户未明确要求新增独立对话时,未命中通道也不自动创建;使用当前任务或子代理完成工作。
- 永久停用才标记 `archived`。创建替代通道时,在新旧记录备注中互相写明 ID,不覆盖或复用旧 ID。
## 登记规则
- 下表只保存既有一次性任务和已结束轮次,不作为新任务的复用路由;可长期复用的任务必须同时登记到上方“长期复用通道”。
- 下表只临时保存 `planned`、`active`、`blocked` 的一次性独立任务,不作为新任务的复用路由;可长期复用的职责必须登记到上方“长期复用通道”。
- 独立任务创建成功并获得平台返回的稳定 ID 后立即登记;没有稳定 ID 不得写入临时名称或自行生成替代 ID。
- 任务名称可以修改,`task_id` 不得复用、改写或转给另一项工作。历史任务完成后保留记录,不删除历史 ID。
- 任务名称可以修改,`task_id` 不得复用、改写或转给另一项工作。一次性任务完成或被替代后,先归档聊天,再删除本表记录;重要业务结论必须已写入对应业务、验收或进度文档。
- 跨任务共享契约由总控记录在备注中;独立任务回复必须带回自身 `task_id`、状态、变更文件、验证结果和阻断项。
## 执行历史状态值
## 当前执行状态值
`planned`、`active`、`blocked`、`completed`、`archived`。
`planned`、`active`、`blocked`。完成和归档不是表内常驻状态。
## 执行历史
## 当前执行任务
以下仅保留当前仍在执行或受阻的任务;已完成或已替代的一次性任务从本表移除,对应聊天可在 Codex 归档中恢复。
| task_id | display_name | scope | owner | status | worktree/branch | last_update | notes |
|---|---|---|---|---|---|---|---|
| 019feb17-b5de-7d63-a0e4-5a8c2181e323 | PDA 后端作业链收口 | `baiyue-firstleg/firstleg` PDA 拣货事务、原子批量提交和相关测试 | 三期总控 | completed | 后端 `test` | 2026-08-11 | `40171b7` 已推送;根因是 operation CHECK 未允许 BATCH,统一SQL与模块SQL已补幂等迁移;定向17/17、Firstleg 524项无失败 |
| 019feb17-c56c-7e02-8f9c-0b74f960df34 | 三期验收 fixture 审计 | `baiyue-firstleg/scripts/admin-test-env-modules` | 三期总控 | completed | 后端 `test` | 2026-08-11 | `df0f05c`已推送:修正customs同一来源fixture配对及loading-finalize失败后误标LOADED;4/4契约测试通过,仅脚本无需部署 |
| 019feb17-d3c2-7480-802a-498db11c7d3c | Admin 装柜工作流页面 | `apps/admin-web` 统一订单、智能装柜、预装清单、装柜清单、证据与完成入口 | 三期总控 | completed | Admin `release/test` | 2026-08-11 | 装柜`9b99404`、服务中心接线`17d483b`、出仓空态`af30c0c`均已部署;103 files/535 tests、typecheck/build、浏览器真实页面通过 |
| 019feb2a-419b-7161-8174-5aed7e84a047 | PDA 原子批量提交契约 | PDA 后端 Controller/DTO/OpenAPI/调用方只读契约梳理 | 三期总控 | completed | 后端 `test` | 2026-08-10 | 只读阶段完成;等待 S0500 修复后进入实现 |
| 019feb29-ef52-7f83-96d7-42d963d2ae34 | PDA uni-app 前端验收 | `apps/pda-uniapp` 登录、领取、广播扫码、设备草稿、批量提交、证据和真实 API 映射 | 三期总控 | completed | PDA `release/test` | 2026-08-11 | 功能提交`be776c8`已推送,远端`f83a0c4`;43/43 PASS,A0409刷新和失败回滚已验证;HBuilderX/Android真机仍为最终gap |
| 019febc3-8735-7e53-b797-a8af24bcc0ec | Firstleg 单余量装柜闭环 | `baiyue-firstleg/firstleg` 单余量结算、PDA pick、装柜完成与跨服务幂等/补偿 | 三期总控 | completed | 后端 `test` | 2026-08-11 | `9b3ff06` 修复 loading/complete 更新目标表自引用;定向14/14、Firstleg 524项无失败,无SQL,仅需部署Firstleg |
| 019feeb5-6c6b-7f50-9bcd-eba8c7057b24 | Gateway 与 Order 测试环境发布 | Jenkins `backend-java` 的 `gateway + order` 定向发布与健康检查 | 三期总控 | completed | 后端 `test` | 2026-08-11 | backend-java #100、gateway #36、order #41 成功;部署 166ebfb7,未执行 SQL,未部署 Firstleg/Admin |
| 019feec0-008e-72e2-95d6-8e99d604b5c0 | Admin 服务中心三期页面 | `apps/admin-web` 订舱、拖车、船期、报关与出仓模块页面 | 三期总控 | completed | Admin `release/test` | 2026-08-11 | 服务中心模块与出仓空态修复已推送;订舱41条、拖车51条真实页面通过,最终由接线任务统一部署 |
| 019feed6-edeb-7da3-aa75-8c40aa5fb305 | Firstleg P0 测试环境发布 | Jenkins `backend-java` 的 `firstleg` 定向发布与健康检查 | 三期总控 | completed | 后端 `test` | 2026-08-11 | backend-java #101、firstleg #71 成功;部署 `9f455b6`,包含 `7aa2b50` 与 PDA 原子 `/batch`;无 SQL,已通知全量复跑 |
| 019feeee-e042-73b0-ba84-c6b8e21fa6c9 | Loading-finalize 测试环境发布 | Jenkins `backend-java` 的 `firstleg` 定向发布与健康检查 | 三期总控 | completed | 后端 `test` | 2026-08-11 | backend-java #102、firstleg #72成功,部署`3f301e3`;消费者单跑缺同轮fixture,需随生产者链最终复验 |
| 019feef5-59e3-7110-b87f-4aea14bb67c6 | PDA BATCH SQL 与 Firstleg 发布 | 测试库统一SQL、Jenkins `firstleg` 定向发布和健康检查 | 三期总控 | archived | 后端 `test` | 2026-08-11 | 执行前卡在工具审批,未开始备份或写库;已由新任务`019fef02-863b-7413-84f7-36593aac0c4e`替代 |
| 019fef02-863b-7413-84f7-36593aac0c4e | PDA BATCH SQL 与 Firstleg 发布(替代) | 测试库统一SQL、Jenkins `firstleg` 定向发布和健康检查 | 三期总控 | completed | 后端 `test` | 2026-08-11 | 统一SQL连续两次唯一PASS,CHECK含BATCH;backend-java #103、firstleg #73成功,部署`40171b7`,健康/OpenAPI通过,已通知最终全量 |
| 019fef67-b9b5-7f20-a19f-0f2bb9e91a68 | Loading complete 最终阻断修复 | `baiyue-firstleg/firstleg` 装柜完成首次提交、幂等重放与事务状态收口 | 三期总控 | completed | 后端 `test` | 2026-08-11 | `bf7c214`已推送:修复普通注解SQL误用XML实体导致MySQL语法异常;定向13/13、Firstleg 527项无失败,无SQL,仅需部署Firstleg |
| 019fef75-68c8-7d63-9f28-d2f5ac068c8b | Loading complete 修复发布 | Jenkins `firstleg` 定向发布、健康与OpenAPI核验 | 三期总控 | completed | 后端 `test` | 2026-08-11 | backend-java #104、firstleg #74成功,部署`cb308399`(包含`bf7c214`与`df0f05c`);无SQL,Gateway健康与Firstleg OpenAPI通过,已通知最终全量复跑 |
| 019fef90-4707-7c62-af0d-8b3395ef1e80 | 柜次与计划状态机复验分类 | 三期柜次push、计划推进、预装门禁及验收fixture顺序 | 三期总控 | completed | 后端 `test` | 2026-08-11 | 已确认双缺口:`cb308399`正确引入WAIT_LOADING/推送后EDITING,但错误地在首笔写库而非claim时推进LOADING;脚本仍按旧push即LOADING顺序,需后端claim推进与fixture重排后再部署复验 |
| 019fef9a-e00d-7ea2-8450-5a5930e5279d | PDA claim 推进装柜中 | `baiyue-firstleg/firstleg` 任务领取、计划LOADING推进、历史与幂等 | 三期总控 | completed | 后端 `test` | 2026-08-11 | `16a2f83`已推送:claim首次及同作业员重入幂等推进LOADING,保留pick/batch兜底且START_LOADING历史不重复;定向10/10、Firstleg 531项无失败,无SQL,仅需部署Firstleg |
| 019fef9b-046a-7062-bcfd-8069f02a4822 | 三期装柜状态验收脚本重排 | `phase3-container-loading`、`phase3-loading`及级联fixture | 三期总控 | completed | 后端 `test` | 2026-08-11 | 远端`386eae6`已收口:WAIT_LOADING→EDITING→claim后LOADING→真实pick/batch→COMPLETED,customs/finalize同轮fixture;脚本契约6/6、node check、diff check通过,仅脚本无需部署 |
| 019fefb4-ef2e-7db2-a698-a65f185df8f8 | PDA claim 状态修复发布 | Jenkins `firstleg` 定向发布、健康与OpenAPI核验 | 三期总控 | completed | 后端 `test` | 2026-08-11 | backend-java #105、firstleg #75成功,部署`a59f4634`(包含`16a2f83`与`386eae6`);无SQL,健康/OpenAPI通过,已放行完整生产者链与默认全量 |
| 019fef9f-0a38-7523-bb40-33256352505b | Firstleg claim 推进装柜状态 | `LoadingPickService.claim` 原子推进计划至LOADING并保持幂等 | 三期总控 | completed | 后端 `test` | 2026-08-11 | `16a2f83`已推送origin/test;claim成功/同作业员重入调用`startPicking`,仅首次写START_LOADING历史;LoadingPickService定向10/10、Firstleg 531项0失败2跳过、diff check通过;无SQL,仅需部署Firstleg |
| 019fef8f-8134-7380-b112-33ba490fa911 | 柜次推送状态机阻断排查 | `baiyue-firstleg/firstleg` 柜次推送、计划状态与预装确认门禁 | 三期总控 | completed | 后端 `test` | 2026-08-11 | 后端契约完整无需改动:push-preload保持EDITING,PDA task claim后才推进LOADING;失败为脚本旧顺序,已交fixture任务修正 |
| 019fef8f-994b-75c0-a3a2-0c76574567b4 | 三期最终fixture稳定性审计 | `baiyue-firstleg/scripts/admin-test-env-modules` 生产者链marker与跨模块fixture | 三期总控 | completed | 后端 `test` | 2026-08-11 | `386eae6`已推送:按push EDITING、claim EDITING、首笔PICK/BATCH启动装柜的真实顺序修正3个脚本;静态3/3、契约6/6通过 |
| 019fefae-09e8-7993-906e-95b073ffc0b7 | 预装确认与装柜启动门禁矛盾修复 | `baiyue-firstleg/firstleg` 入库预装确认、柜次启动与主状态同步 | 三期总控 | completed | 后端 `test` | 2026-08-11 | `a59f463`已推送:confirming允许INBOUNDED或LOADING,LOADING仍强制关联柜次已启动;定向4/4、Firstleg 532项无失败,无SQL |
| 019fefb7-d33d-7521-ae9d-1ef268755b9c | 预装门禁修复发布 | Jenkins `firstleg` 定向发布、健康与OpenAPI核验 | 三期总控 | completed | 后端 `test` | 2026-08-11 | backend-java #105、firstleg #75成功,部署`a59f463`;Firstleg 533项0失败2跳过,Gateway health与Firstleg OpenAPI HTTP200,未执行SQL,已通知最终全量复跑 |
| 019ff02d-924c-7290-a34e-b2c3704601b8 | 三期最终验收状态与finalize fixture修正 | `baiyue-firstleg/scripts/admin-test-env-modules` claim/CONFIRMING真实状态与订舱拖车报关到finalize柜次关联 | 三期总控 | archived | 后端 `test` | 2026-08-11 | 发布任务越权创建但未下发业务工作;已归档,范围交回现有全量任务`019fdf0a-4933-7903-8a0c-10018c379f6f`处理 |
| 019ff034-87cb-7d32-8c93-3e8aa992b082 | 三期最终脚本与全量收口 | `baiyue-firstleg/scripts/admin-test-env-*` 状态断言、finalize实际柜次关联、定向与默认全量 | 三期总控 | active | 后端 `test` | 2026-08-11 | 因原全量任务被Finance独占而建立的唯一替代任务;修复后直接跑定向和默认全量,完成即归档,不再拆分 |
| 019ff034-87cb-7d32-8c93-3e8aa992b082 | 三期最终脚本与全量收口 | `baiyue-firstleg/scripts/admin-test-env-*` 状态断言、finalize实际柜次关联、定向与默认全量 | 三期总控 | active | 后端 `test` | 2026-08-11 | 因原全量任务被Finance独占而建立的唯一替代任务;修复后直接跑定向和默认全量,完成后回收到三期长期通道,不再拆分 |
| 019fdf0a-4933-7903-8a0c-10018c379f6f | 后台真实全量测试 | `baiyue-firstleg/scripts/admin-test-env-*` 与测试环境真实 HTTP 验收 | 三期总控 | active | 后端 `test` | 2026-08-11 | 当前基线复跑与下一批 PDA batch/Admin 终验分两轮执行;禁止 mock、放宽断言或 gap 伪装 PASS |
| 019febc3-704f-7c72-8e82-dc317f69dc9b | Finance 后端与数据库 | `baiyue-firstleg/finance`、Finance 依赖的 `file/firstleg/gateway/iam` 契约、模块 SQL 与统一 SQL | 财务总控 | active | 共享工作区 | 2026-08-11 | 最终专项判定11个一期operation缺失;已返工账户/流水、来源审核与纳入结算、对账单和应收应付结算单正式闭环 |
| 019febc3-7c39-7ec2-8051-a4cce8d5f104 | Finance F1 接口契约 | `docs/财务管理/` 的 OpenAPI、接口契约、门禁和状态文档 | 财务总控 | active | 共享工作区 | 2026-08-11 | 11个NOT_IMPLEMENTED已判定一期P0;正在冻结DTO、状态、权限、幂等、错误码和验收用例并跟踪实现 |
| 019febc3-89f3-7991-b7eb-6c697fd9f032 | Admin 人工财务模块 | `apps/admin-web/src/modules/finance/` 及其路由、权限和测试 | 财务总控 | active | Admin 当前工作区 | 2026-08-11 | 五路由已存在但后三页仍为旧能力映射;返工正式生成、详情、状态动作和来源审核/结算纳入交互 |
| 019febc3-9519-7982-81dd-bc048819bf48 | Client 财务只读模块 | `apps/client-web/src/modules/finance/` 及财务权限映射和测试 | 财务总控 | active | Client 当前工作区 | 2026-08-11 | Client交付已完成;因原全量ID被三期持续占用,复用本独立ID执行Finance一期五页最终只读专项,禁止修改文件 |
| 019fef83-0763-7930-8c00-c42d5398b0f1 | 数据库注释全库盘点 | `baiyue-firstleg/*/src/main/resources/db/` 与统一 SQL 的只读盘点 | 数据库注释总控 | completed | 共享工作区 | 2026-08-11 | 155个建表定义、约2339字段;字段注释覆盖约69%,缺失724;Finance缺164、Firstleg缺461;未修改文件 |
| 019fef83-2697-7062-a902-a0e9791d75ea | 数据库注释规范与门禁 | 数据库中文注释规范、静态审计脚本和 CI/验收门禁 | 数据库注释总控 | completed | 共享工作区 | 2026-08-11 | 规范与离线门禁完成;多行CHECK假阳性已按MySQL数据类型白名单修复并补SelfTest;Order/Finance Issues=0 |
| 019fef8b-9f95-7102-a57b-dc4960ff5ffa | Firstleg 二期数据库注释 | `firstleg` 基线、入库、测量、计费、价格及托盘相关模块 SQL | 数据库注释总控 | completed | 共享工作区 | 2026-08-11 | 7文件新增47个注释、修正1个英文状态;范围内Issues=0、结构不变、聚合构建成功;完整测试被并行Finance测试编译错误阻断 |
| 019fef8b-a844-75c1-9ed3-85dfca8a89f1 | Firstleg 三期船期数据库注释 | `firstleg` 船司查询与港口船期模块 SQL | 数据库注释总控 | completed | 共享工作区 | 2026-08-11 | 两文件补齐/中文化113字段;覆盖100%;SQL契约测试6/6、BUILD SUCCESS;仅COMMENT变更 |
| 019fef8b-afb6-7342-a707-f014f7baa785 | Order Auth IAM 数据库注释 | `order`、`auth`、`iam` 模块 SQL | 数据库注释总控 | completed | 共享工作区 | 2026-08-11 | 26表389字段覆盖100%;Auth/IAM测试通过;Order 125/126,唯一失败为统一SQL旧注释镜像待集成同步 |
| 019fef8b-b84f-70e2-b312-bebdce157ad0 | Warehouse File Audit Event 数据库注释 | `warehouse`、`file`、`audit-service`、`event-bridge-service` 模块 SQL | 数据库注释总控 | completed | 共享工作区 | 2026-08-11 | 28个表定义、433字段注释100%;四模块Maven测试BUILD SUCCESS;未改统一SQL |
| 019fef9d-ddf6-7963-b683-46bab7685bee | Firstleg 三期报关数据库注释 | `phase3-customs-schema.sql` | 数据库注释总控 | completed | 共享工作区 | 2026-08-11 | 8表107字段中文注释完成;CustomsSqlContractTest通过;仅COMMENT变更,未改统一SQL |
| 019fef9d-e7df-7bd2-9d07-ef22bbac1e6a | Firstleg 三期订舱拖车数据库注释 | `phase3-ocean-booking-schema.sql`、`phase3-truck-appointment-schema.sql` | 数据库注释总控 | completed | 共享工作区 | 2026-08-11 | 两文件Issues=0且结构不变;订舱/拖车定向测试20/20、BUILD SUCCESS;未改统一SQL |
| 019fef9d-f2f1-7e12-8f70-63e54a855851 | Firstleg 三期装柜PDA数据库注释 | 三期装柜、出仓、PDA、分柜、排柜及桥接脚本 | 数据库注释总控 | completed | 共享工作区 | 2026-08-11 | 七文件完成;Firstleg 89表1443字段覆盖100%、Issues=0;相关SQL测试33项通过、1跳过;统一SQL待同步 |
| 019fefb9-fce8-78e3-8270-dd569546ae9d | 数据库注释统一SQL集成 | `deploy/sql/头程数据库统一增量-MySQL8.sql` 与相关SQL契约测试 | 数据库注释总控 | completed | 共享工作区 | 2026-08-11 | 150唯一表2456字段;每表最多一次DDL并验签;九库断言/唯一PASS;DryRun PASS;Firstleg549、Finance35通过;未执行真实MySQL |
| 019febc3-704f-7c72-8e82-dc317f69dc9b | Finance 后端与数据库 | `baiyue-firstleg/finance`、Finance 依赖的 `file/firstleg/gateway/iam` 契约、模块 SQL 与统一 SQL | 财务总控 | active | 共享工作区 | 2026-08-11 | 一期财务后端与数据库实现及专项门禁 |
| 019febc3-7c39-7ec2-8051-a4cce8d5f104 | Finance F1 接口契约 | `docs/财务管理/` 的 OpenAPI、接口契约、门禁和状态文档 | 财务总控 | active | 共享工作区 | 2026-08-11 | 一期财务接口与验收契约 |
| 019febc3-89f3-7991-b7eb-6c697fd9f032 | Admin 人工财务模块 | `apps/admin-web/src/modules/finance/` 及其路由、权限和测试 | 财务总控 | active | Admin 当前工作区 | 2026-08-11 | 一期 Admin 财务页面与真实接口交互 |
| 019febc3-9519-7982-81dd-bc048819bf48 | Client 财务只读模块 | `apps/client-web/src/modules/finance/` 及财务权限映射和测试 | 财务总控 | active | Client 当前工作区 | 2026-08-11 | 一期 Client 财务只读专项,禁止修改范围外文件 |
## 通信与汇总格式
@@ -92,7 +92,7 @@
| D11 | 客户状态可见性 | **后端完成。** 客户账单只见 `ISSUED/PARTIALLY_PAID/PAID`;客户收款只见 `CONFIRMED`,使用 `ClientReceipt` 专用 DTO 并去除凭证、操作人和内部字段;脱敏测试通过 | 后端门禁关闭;保留跨客户与序列化回归 |
| D12 | Finance 费用来源写入 | **后端完成。** 内部事件入口、令牌鉴权、Inbox 幂等、Firstleg 快照回查、来源写入/替代/作废均已实现;非作废事件必须 `PUBLISHED`,未发布返回 `FIN-EVT-015`;金额必须 `>0`,零/负返回 `FIN-EVT-010`;专项 10/10、Finance 全量 35/35 通过 | 后端门禁关闭;保留真实跨服务 HTTP 冒烟 |
| D13 | 柜子费用来源 | **后端完成并验证。** Firstleg 已有柜子费用模型、审核/参与结算/作废、事件、Relay 和内部快照;Firstleg 相关 17/17、Finance 柜子来源消费测试通过 | 后端门禁关闭;测试环境补真实跨服务事件冒烟 |
| D14 | 一期 5 页 | **后端查询契约完成,页面开发中。** 五页固定 DTO 路径、Client 脱敏和错误码已经验证;11 个目标写/明细 operation 仍真实标记 `NOT_IMPLEMENTED`,Admin 正在接入 | 完成 Admin 五页矩阵和剩余 11 个 operation;删除费用分析、利润表、充值及假入口并完成端到端验收 |
| D14 | 一期 5 页 | **FAIL / 一期 P0 未关闭。** 部分五页固定 DTO 路径、Client 脱敏和错误码已经验证;11 个目标 operation 仍真实标记 `NOT_IMPLEMENTED`,且全部属于一期 P0,不得列为后续 | 按《财务一期P0操作契约与验收用例》逐项完成 Controller/DTO、状态机、权限、幂等、错误码、客户隔离和直接行为测试,再完成 Admin 五页端到端验收 |
## 4. 非阻断但需锁定的契约说明
@@ -107,7 +107,7 @@
进入前后端联调前至少满足:
1. D1-D8、D10-D13 已具备后端直接证据;剩余以 D9 和 D14 的 11 个 operation/Admin 验收为准。
1. D1-D8、D10-D13 已具备后端直接证据;D14 当前 FAIL,11 个 operation 全部为一期 P0,任一未完成均不得通过一期完整联调验收。
2. D2 已固定为首期非分页数组;后续若改服务端分页须另行升级契约。
3. 幂等门禁已关闭;后续写 operation 继续复用同参重放、异参冲突和恢复语义。
4. Finance 集成测试覆盖:默认 30 天、CNY 拒绝、出账冻结、300 分 3 单、超额/跨客户/草稿拒绝、部分收款到收清、调整修订、已收不可作废。
@@ -118,8 +118,8 @@
## 6. 放行结论
- **当前阶段:专项修复中。** Finance、SQL、Admin 和 Client 均已有实现,不再按“未开发”管理。
- **可继续开发:是。** 路径、权限、固定 DTO、凭证、分摊、幂等和客户可见性已经冻结,不再需要新增产品决策。
- **可继续开发:是。** 11 个 P0 的路径、权限、DTO、状态、凭证、幂等、错误码和客户隔离已经冻结,不再需要新增产品决策。
- **可进行接口冒烟:有条件。** 可验证现有路径、鉴权和基础创建/查询,但结果不代表业务验收通过。
- **可进入完整联调验收:否。** Finance 来源写入及 `PUBLISHED + amount>0`、五页 DTO、完整幂等、File fail-closed、客户脱敏、稳定错误码和柜子来源已经通过后端测试,不再是阻断;剩余阻断是 11 个目标 operation、Admin 五页接入和真实跨服务冒烟。
- **可进入完整联调验收:否。** Finance 来源写入及 `PUBLISHED + amount>0`、现有查询 DTO、完整幂等、File fail-closed、客户脱敏、稳定错误码和柜子来源已经通过后端测试;11 个 P0 operation、Admin 五页接入和真实跨服务冒烟未完成。11 个 P0 不得降级为后续事项。
本次审查只修订文档与 OpenAPI,未修改 Java、前端或 SQL。
+4 -1
View File
@@ -1,7 +1,7 @@
# 财务管理闭环盘点与范围建议
> 盘点日期:2026-08-10
> 当前状态:F0/F1 已有 Finance 服务、数据库、权限、Admin/Client 页面和基础接口;费用来源主链、固定 DTO、脱敏、凭证 fail-closed 和稳定错误码已通过后端验证,剩余为五页页面与未实现 operation 收口
> 当前状态:F0/F1 已有 Finance 服务、数据库、权限、Admin/Client 页面和基础接口;费用来源主链、固定 DTO、脱敏、凭证 fail-closed 和稳定错误码已通过后端验证;尚未实现的 11 个 operation 全部属于一期 P0 阻断,不得排到后续
> 盘点范围:二期入库计费现状、平台后台财务原型、Admin/Client/Firstleg 当前实现
> 结论口径:本文区分“代码已实现”“原型展示”和“建议范围”;原型功能不自动成为开发范围。
@@ -15,6 +15,8 @@
一期领导验收唯一范围入口:[财务一期五页产品与接口验收契约](财务一期五页产品与接口验收契约.md)。
一期 11 个 P0 操作、状态机与验收用例:[财务一期 P0 操作契约与验收用例](财务一期P0操作契约与验收用例.md)。
文档优先级:五页验收契约和本轮产品确认 > 五页目标 OpenAPI > 既有人工 F1 契约/门禁 > 领域模型、历史全量规划和迁移文档。旧文档用于追溯,不得据此把钱包、充值、发票、费用分析或利润表重新纳入一期。
旧文档降级规则:
@@ -35,6 +37,7 @@
- [F1 人工财务契约审查与门禁](F1人工财务契约审查与门禁.md)
- [财务一期五页产品与接口验收契约](财务一期五页产品与接口验收契约.md)
- [财务一期五页 OpenAPI](openapi/finance-phase1-five-pages-v1.yaml)
- [财务一期 P0 操作契约与验收用例](财务一期P0操作契约与验收用例.md)
- [财务历史迁移与上线验收方案](财务历史迁移与上线验收方案.md)
- [财务F0实施任务拆分](财务F0实施任务拆分.md)
@@ -6,7 +6,8 @@ info:
一期领导验收 5 页目标契约:客户账户、客户应收应付、客户对账单、结算单应收、
结算单应付。只支持 CNY。费用分析、利润表、钱包、预收和充值不属于本契约。
每个 operation 通过 x-implementation-status 标记当前 Java 实现事实;NOT_IMPLEMENTED
仅代表目标契约尚未落地,不得生成按钮或模拟成功入口。
代表一期 P0 尚未落地,不得排到后续、生成按钮或模拟成功入口。只有 Controller/DTO
与直接行为测试均提供证据后,才允许逐项改为 IMPLEMENTED。
servers:
- url: /api
x-product-scope:
@@ -31,6 +32,25 @@ x-current-verification:
checkedAt: '2026-08-11'
source: 当前 baiyue-firstleg 工作树中的 Controller、DTO、Service、Client 和现有 Surefire 报告。
testStatus: Finance 35/35、Firstleg 549/549(2 skip)、File 114/114、Gateway 26/26、IAM 163/163、Phase3/PDA SQL 12/12、Order SQL 3/3,均 BUILD SUCCESS;来源消费专项 10/10。
x-phase1-p0-gate:
status: FAIL
notImplementedOperations: 11
rule: 11 个 operation 均为一期 P0;必须有一致的 Controller/固定 DTO/权限/状态机/客户隔离/幂等及直接行为测试证据,方可逐项改为 IMPLEMENTED。
contract: ../财务一期P0操作契约与验收用例.md
x-idempotency-contract:
scope: method + normalizedPath + resolvedCustomerId + completeQueryAndBody
sameKeySameRequest: replay original result
sameKeyDifferentRequest: FIN_409
processing: FIN_409;超时后按现有 Finance 抢占恢复规则执行
failed: 按现有 Finance FAILED 恢复规则执行
x-error-contract:
FIN_400: 参数、日期、CNY 或正金额校验失败
FIN_404: 对象不存在或跨客户对象隐藏
FIN_409: 非法状态、乐观锁、重复占用或幂等冲突
FIN_503: File 或内部依赖不可用且 fail-closed
FIN_001: 未分类服务端错误
authentication: HTTP 401
permission: HTTP 403
paths:
/internal/finance/v1/fee-source-events:
post:
@@ -84,6 +104,14 @@ paths:
summary: 查询客户财务账户派生汇总
description: 只读聚合,不返回钱包余额,不提供充值或余额调整动作。
x-implementation-status: NOT_IMPLEMENTED
x-delivery-priority: PHASE1_P0
x-request-dto: AccountListQuery
x-response-dto: AccountPageEnvelope
x-idempotency: READ_ONLY_NOT_APPLICABLE
x-customer-isolation: 平台权限下按真实客户主体聚合;不得返回 tenantId,不得产生可写余额。
x-state-machine: READ_ONLY_DERIVED_VIEW
x-error-codes: [FIN_400, FIN_001]
x-acceptance-cases: [AC-01, AC-02]
x-permission: platform:finance:account:view
parameters:
- $ref: '#/components/parameters/Page'
@@ -96,6 +124,8 @@ paths:
schema: {type: string, enum: [ACTIVE, DISABLED]}
responses:
'200': {$ref: '#/components/responses/AccountPageResponse'}
'400': {$ref: '#/components/responses/BusinessError'}
'403': {$ref: '#/components/responses/BusinessError'}
/platform/finance/v1/customer-accounts/{customerId}:
get:
operationId: getDerivedCustomerAccount
@@ -113,6 +143,14 @@ paths:
operationId: listDerivedCustomerAccountLedger
summary: 查询客户财务派生流水
x-implementation-status: NOT_IMPLEMENTED
x-delivery-priority: PHASE1_P0
x-request-dto: AccountLedgerQuery
x-response-dto: LedgerPageEnvelope
x-idempotency: READ_ONLY_NOT_APPLICABLE
x-customer-isolation: customerId 必须解析为真实客户,流水只聚合该客户数据;跨客户对象不得出现。
x-state-machine: READ_ONLY_DERIVED_VIEW
x-error-codes: [FIN_400, FIN_404, FIN_001]
x-acceptance-cases: [AC-03, AC-04]
x-permission: platform:finance:account:view
parameters:
- $ref: '#/components/parameters/CustomerId'
@@ -129,6 +167,9 @@ paths:
schema: {type: string, format: date}
responses:
'200': {$ref: '#/components/responses/LedgerPageResponse'}
'400': {$ref: '#/components/responses/BusinessError'}
'403': {$ref: '#/components/responses/BusinessError'}
'404': {$ref: '#/components/responses/BusinessError'}
/platform/finance/v1/fee-pool:
get:
operationId: listFinanceFeeSources
@@ -151,17 +192,34 @@ paths:
operationId: getFinanceFeeSource
summary: 查询费用来源详情、业务关联和操作记录
x-implementation-status: NOT_IMPLEMENTED
x-delivery-priority: PHASE1_P0
x-request-dto: FeeSourceIdPath
x-response-dto: FeeSourceDetailEnvelope
x-idempotency: READ_ONLY_NOT_APPLICABLE
x-customer-isolation: 按费用来源真实 customerId 返回;跨客户关联按 FIN_404 隐藏。
x-state-machine: READ_ONLY_ALL_SOURCE_STATES
x-error-codes: [FIN_404, FIN_001]
x-acceptance-cases: [AC-05]
x-permission: platform:finance:fee-source:view
parameters:
- $ref: '#/components/parameters/FeeSourceId'
responses:
'200': {$ref: '#/components/responses/FeeSourceDetailResponse'}
'403': {$ref: '#/components/responses/BusinessError'}
'404': {$ref: '#/components/responses/BusinessError'}
/platform/finance/v1/fee-sources/{feeSourceId}/review:
post:
operationId: reviewFinanceFeeSource
summary: 审核费用来源
x-implementation-status: NOT_IMPLEMENTED
x-delivery-priority: PHASE1_P0
x-request-dto: ReviewRequest
x-response-dto: FeeSourceDetailEnvelope
x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT
x-customer-isolation: 只按 feeSourceId 解析其真实客户;请求不得覆盖 customerId 或金额。
x-state-machine: PENDING -> APPROVED | REJECTED
x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_001]
x-acceptance-cases: [AC-06, AC-07, AC-29]
x-permission: platform:finance:fee-source:review
parameters:
- $ref: '#/components/parameters/FeeSourceId'
@@ -173,12 +231,23 @@ paths:
schema: {$ref: '#/components/schemas/ReviewRequest'}
responses:
'200': {$ref: '#/components/responses/FeeSourceDetailResponse'}
'400': {$ref: '#/components/responses/BusinessError'}
'403': {$ref: '#/components/responses/BusinessError'}
'404': {$ref: '#/components/responses/BusinessError'}
'409': {$ref: '#/components/responses/BusinessError'}
/platform/finance/v1/fee-sources/{feeSourceId}/settlement-inclusion:
put:
operationId: updateFeeSourceSettlementInclusion
summary: 设置参与结算或禁止结算
x-implementation-status: NOT_IMPLEMENTED
x-delivery-priority: PHASE1_P0
x-request-dto: SettlementInclusionRequest
x-response-dto: FeeSourceDetailEnvelope
x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT
x-customer-isolation: 只按 feeSourceId 解析其真实客户;跨客户业务引用按 FIN_404 隐藏。
x-state-machine: APPROVED + PUBLISHED + AVAILABLE + CNY 可切换;LOCKED/BILLED/VOIDED/SUPERSEDED 禁止修改
x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_001]
x-acceptance-cases: [AC-08, AC-09, AC-29]
x-permission: platform:finance:fee-source:settlement
parameters:
- $ref: '#/components/parameters/FeeSourceId'
@@ -190,6 +259,9 @@ paths:
schema: {$ref: '#/components/schemas/SettlementInclusionRequest'}
responses:
'200': {$ref: '#/components/responses/FeeSourceDetailResponse'}
'400': {$ref: '#/components/responses/BusinessError'}
'403': {$ref: '#/components/responses/BusinessError'}
'404': {$ref: '#/components/responses/BusinessError'}
'409': {$ref: '#/components/responses/BusinessError'}
/platform/finance/v1/statements:
get:
@@ -209,6 +281,14 @@ paths:
operationId: createReconciliationStatement
summary: 按截止时间或勾选来源生成客户对账单草稿
x-implementation-status: NOT_IMPLEMENTED
x-delivery-priority: PHASE1_P0
x-request-dto: CreateReconciliationRequest
x-response-dto: ReconciliationDetailEnvelope
x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT
x-customer-isolation: 所有来源必须属于 request.customerId;跨客户来源按 FIN_404,禁止部分落库。
x-state-machine: 合格且未占用来源 -> DRAFT;创建时锁定所选来源
x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_001]
x-acceptance-cases: [AC-10, AC-11, AC-12, AC-29]
x-permission: platform:finance:reconciliation:create
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
@@ -219,6 +299,9 @@ paths:
schema: {$ref: '#/components/schemas/CreateReconciliationRequest'}
responses:
'200': {$ref: '#/components/responses/ReconciliationDetailResponse'}
'400': {$ref: '#/components/responses/BusinessError'}
'403': {$ref: '#/components/responses/BusinessError'}
'404': {$ref: '#/components/responses/BusinessError'}
'409': {$ref: '#/components/responses/BusinessError'}
/platform/finance/v1/bills/{billId}:
get:
@@ -235,9 +318,24 @@ paths:
/platform/finance/v1/reconciliation-statements/{statementId}/actions:
post:
operationId: actionReconciliationStatement
summary: 提交审核、通过、拒绝或作废客户对账单
summary: 提交、审核、出账、调整、作废或重开客户对账单
x-implementation-status: NOT_IMPLEMENTED
x-permission: platform:finance:reconciliation:review
x-delivery-priority: PHASE1_P0
x-request-dto: ReconciliationActionRequest
x-response-dto: ReconciliationDetailEnvelope
x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT
x-customer-isolation: statementId 决定客户;调整行必须全部属于该对账单,跨客户按 FIN_404。
x-state-machine: DRAFT->PENDING_REVIEW->APPROVED->ISSUED;REJECTED/VOIDED 可 REOPEN 新 revision;ISSUED 仅 ADJUST 新 revision
x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_001]
x-acceptance-cases: [AC-13, AC-14, AC-15, AC-16, AC-17, AC-29]
x-permission-by-action:
SUBMIT: platform:finance:reconciliation:create
APPROVE: platform:finance:reconciliation:review
REJECT: platform:finance:reconciliation:review
ISSUE: platform:finance:reconciliation:issue
ADJUST: platform:finance:reconciliation:adjust
VOID: platform:finance:reconciliation:void
REOPEN: platform:finance:reconciliation:void
parameters:
- $ref: '#/components/parameters/StatementId'
- $ref: '#/components/parameters/IdempotencyKey'
@@ -245,9 +343,12 @@ paths:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/DocumentActionRequest'}
schema: {$ref: '#/components/schemas/ReconciliationActionRequest'}
responses:
'200': {$ref: '#/components/responses/ReconciliationDetailResponse'}
'400': {$ref: '#/components/responses/BusinessError'}
'403': {$ref: '#/components/responses/BusinessError'}
'404': {$ref: '#/components/responses/BusinessError'}
'409': {$ref: '#/components/responses/BusinessError'}
/platform/finance/v1/receivable-settlements:
get:
@@ -267,6 +368,14 @@ paths:
operationId: createReceivableSettlement
summary: 从审核通过的客户对账单生成应收结算单
x-implementation-status: NOT_IMPLEMENTED
x-delivery-priority: PHASE1_P0
x-request-dto: CreateReceivableSettlementRequest
x-response-dto: SettlementDetailEnvelope
x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT
x-customer-isolation: 客户从对账单派生,不接受前端覆盖;跨客户关联按 FIN_404。
x-state-machine: ISSUED reconciliation -> ISSUED RECEIVABLE settlement;一张对账单只允许一个有效 AR
x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_001]
x-acceptance-cases: [AC-18, AC-19, AC-29]
x-permission: platform:finance:settlement-ar:create
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
@@ -277,6 +386,9 @@ paths:
schema: {$ref: '#/components/schemas/CreateReceivableSettlementRequest'}
responses:
'200': {$ref: '#/components/responses/SettlementDetailResponse'}
'400': {$ref: '#/components/responses/BusinessError'}
'403': {$ref: '#/components/responses/BusinessError'}
'404': {$ref: '#/components/responses/BusinessError'}
'409': {$ref: '#/components/responses/BusinessError'}
/platform/finance/v1/payable-settlements:
get:
@@ -296,6 +408,14 @@ paths:
operationId: createPayableSettlement
summary: 从审核通过且参与结算的应付来源生成应付结算单
x-implementation-status: NOT_IMPLEMENTED
x-delivery-priority: PHASE1_P0
x-request-dto: CreatePayableSettlementRequest
x-response-dto: SettlementDetailEnvelope
x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT
x-customer-isolation: 所有 PAYABLE 来源必须同 customerId 且同 supplierId;跨客户来源按 FIN_404。
x-state-machine: 合格未占用 PAYABLE 来源 -> ISSUED PAYABLE settlement
x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_001]
x-acceptance-cases: [AC-20, AC-21, AC-29]
x-permission: platform:finance:settlement-ap:create
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
@@ -306,6 +426,9 @@ paths:
schema: {$ref: '#/components/schemas/CreatePayableSettlementRequest'}
responses:
'200': {$ref: '#/components/responses/SettlementDetailResponse'}
'400': {$ref: '#/components/responses/BusinessError'}
'403': {$ref: '#/components/responses/BusinessError'}
'404': {$ref: '#/components/responses/BusinessError'}
'409': {$ref: '#/components/responses/BusinessError'}
/platform/finance/v1/receipts:
get:
@@ -356,6 +479,14 @@ paths:
operationId: getSettlement
summary: 查询应收或应付结算单详情
x-implementation-status: NOT_IMPLEMENTED
x-delivery-priority: PHASE1_P0
x-request-dto: SettlementIdPath
x-response-dto: SettlementDetailEnvelope
x-idempotency: READ_ONLY_NOT_APPLICABLE
x-customer-isolation: 按结算单真实客户返回;不得返回其他客户数据,客户侧仍使用独立脱敏接口。
x-state-machine: READ_ONLY_ALL_SETTLEMENT_STATES
x-error-codes: [FIN_404, FIN_001]
x-acceptance-cases: [AC-22, AC-23]
x-permission-any-of:
- platform:finance:settlement-ar:view
- platform:finance:settlement-ap:view
@@ -363,12 +494,21 @@ paths:
- $ref: '#/components/parameters/SettlementId'
responses:
'200': {$ref: '#/components/responses/SettlementDetailResponse'}
'403': {$ref: '#/components/responses/BusinessError'}
'404': {$ref: '#/components/responses/BusinessError'}
/platform/finance/v1/settlements/{settlementId}/transactions:
post:
operationId: createSettlementPayment
summary: 人工登记应付结算单付款并上传凭证
x-implementation-status: NOT_IMPLEMENTED
x-delivery-priority: PHASE1_P0
x-request-dto: CreateSettlementPaymentRequest
x-response-dto: SettlementDetailEnvelope
x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT
x-customer-isolation: settlementId 决定客户和供应商;凭证必须属于同一客户的 FINANCE_VOUCHER。
x-state-machine: PAYABLE ISSUED -> PARTIALLY_PAID -> PAID;金额不得超过 outstandingAmount
x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_503, FIN_001]
x-acceptance-cases: [AC-24, AC-25, AC-26, AC-29]
x-permission: platform:finance:payment:create
parameters:
- $ref: '#/components/parameters/SettlementId'
@@ -380,7 +520,11 @@ paths:
schema: {$ref: '#/components/schemas/CreateSettlementPaymentRequest'}
responses:
'200': {$ref: '#/components/responses/SettlementDetailResponse'}
'400': {$ref: '#/components/responses/BusinessError'}
'403': {$ref: '#/components/responses/BusinessError'}
'404': {$ref: '#/components/responses/BusinessError'}
'409': {$ref: '#/components/responses/BusinessError'}
'503': {$ref: '#/components/responses/BusinessError'}
components:
parameters:
InternalServiceToken:
@@ -472,6 +616,9 @@ components:
Money:
type: string
pattern: '^(0|[1-9][0-9]*)(\.[0-9]{1,6})?$'
PositiveMoney:
type: string
pattern: '^(0\.(?=[0-9]{0,5}[1-9])[0-9]{1,6}|[1-9][0-9]*(\.[0-9]{1,6})?)$'
FeeDirection:
type: string
enum: [RECEIVABLE, PAYABLE]
@@ -483,7 +630,7 @@ components:
enum: [PENDING, APPROVED, REJECTED]
ReconciliationStatus:
type: string
enum: [DRAFT, PENDING_REVIEW, APPROVED, REJECTED, VOIDED]
enum: [DRAFT, PENDING_REVIEW, APPROVED, ISSUED, REJECTED, VOIDED]
SettlementStatus:
type: string
enum: [DRAFT, PENDING_REVIEW, ISSUED, PARTIALLY_PAID, PAID, REJECTED, VOIDED]
@@ -672,15 +819,44 @@ components:
allOf:
- $ref: '#/components/schemas/ReconciliationSummary'
- type: object
required: [lines, paymentHistory]
required: [lines, paymentHistory, revisions]
properties:
remark: {type: string}
lines:
type: array
items: {$ref: '#/components/schemas/FeeSource'}
items: {$ref: '#/components/schemas/ReconciliationLine'}
paymentHistory:
type: array
items: {$ref: '#/components/schemas/SettlementTransaction'}
revisions:
type: array
items: {$ref: '#/components/schemas/ReconciliationRevision'}
ReconciliationLine:
type: object
required: [statementLineId, feeSourceId, sourceVersion, feeItemName, sourceAmount, statementAmount, currency]
properties:
statementLineId: {$ref: '#/components/schemas/Id'}
feeSourceId: {$ref: '#/components/schemas/Id'}
sourceVersion: {type: integer, minimum: 1}
sourceHash: {type: string}
inboundId: {$ref: '#/components/schemas/Id'}
containerId: {$ref: '#/components/schemas/Id'}
feeItemName: {type: string}
sourceAmount: {$ref: '#/components/schemas/Money'}
statementAmount: {$ref: '#/components/schemas/Money'}
currency: {type: string, enum: [CNY]}
adjustmentReason: {type: string}
ReconciliationRevision:
type: object
required: [revisionNo, action, beforeAmount, afterAmount, operatorId, occurredAt]
properties:
revisionNo: {type: integer, minimum: 1}
action: {type: string, enum: [CREATE, SUBMIT, APPROVE, REJECT, ISSUE, ADJUST, VOID, REOPEN]}
beforeAmount: {$ref: '#/components/schemas/Money'}
afterAmount: {$ref: '#/components/schemas/Money'}
reason: {type: string}
operatorId: {$ref: '#/components/schemas/Id'}
occurredAt: {type: string, format: date-time}
StatementRead:
type: object
required: [id, customerId, billNo, billDate, dueDate, totalAmount, receivedAmount, outstandingAmount, currency, status, version]
@@ -756,24 +932,57 @@ components:
version: {type: integer, minimum: 0}
CreateReconciliationRequest:
type: object
required: [customerId, generationMode, periodStart, periodEnd]
required: [customerId, currency, generationMode, periodStart, periodEnd]
description: SELECTED 模式 feeSourceIds 至少一项;BY_CUTOFF 模式由服务端按 periodEnd 选取合格来源。来源金额只能取服务端快照。
properties:
customerId: {$ref: '#/components/schemas/Id'}
currency: {type: string, enum: [CNY]}
generationMode: {type: string, enum: [BY_CUTOFF, SELECTED]}
feeSourceIds:
type: array
minItems: 1
uniqueItems: true
items: {$ref: '#/components/schemas/Id'}
periodStart: {type: string, format: date}
periodEnd: {type: string, format: date}
remark: {type: string, maxLength: 500}
DocumentActionRequest:
oneOf:
- properties:
generationMode: {type: string, enum: [BY_CUTOFF]}
not: {required: [feeSourceIds]}
- required: [feeSourceIds]
properties:
generationMode: {type: string, enum: [SELECTED]}
ReconciliationActionRequest:
type: object
required: [action, reason, expectedVersion]
required: [action, expectedVersion]
description: REJECT/ADJUST/VOID/REOPEN 必须填写 reason;ADJUST 必须提交至少一条 adjustmentLines,且调整后总额不得低于已收金额。
properties:
action: {type: string, enum: [SUBMIT, APPROVE, REJECT, VOID]}
reason: {type: string, minLength: 1, maxLength: 500}
action: {type: string, enum: [SUBMIT, APPROVE, REJECT, ISSUE, ADJUST, VOID, REOPEN]}
reason: {type: string, maxLength: 500}
expectedVersion: {type: integer, minimum: 0}
adjustmentLines:
type: array
minItems: 1
items: {$ref: '#/components/schemas/StatementAdjustmentLineRequest'}
oneOf:
- properties:
action: {type: string, enum: [SUBMIT, APPROVE, ISSUE]}
- required: [reason]
properties:
action: {type: string, enum: [REJECT, VOID, REOPEN]}
reason: {type: string, minLength: 1, maxLength: 500}
- required: [reason, adjustmentLines]
properties:
action: {type: string, enum: [ADJUST]}
reason: {type: string, minLength: 1, maxLength: 500}
StatementAdjustmentLineRequest:
type: object
required: [statementLineId, adjustedAmount, reason]
properties:
statementLineId: {$ref: '#/components/schemas/Id'}
adjustedAmount: {$ref: '#/components/schemas/Money'}
reason: {type: string, minLength: 1, maxLength: 500}
SettlementSummary:
type: object
required: [settlementId, settlementNo, direction, currency, totalAmount, paidAmount, outstandingAmount, generatedDate, dueDate, paymentStatus, status, version]
@@ -800,7 +1009,7 @@ components:
allOf:
- $ref: '#/components/schemas/SettlementSummary'
- type: object
required: [lines, transactions]
required: [lines, transactions, revisions]
properties:
lines:
type: array
@@ -808,15 +1017,32 @@ components:
transactions:
type: array
items: {$ref: '#/components/schemas/SettlementTransaction'}
revisions:
type: array
items: {$ref: '#/components/schemas/SettlementRevision'}
SettlementRevision:
type: object
required: [revisionNo, action, beforeAmount, afterAmount, operatorId, occurredAt]
properties:
revisionNo: {type: integer, minimum: 1}
action: {type: string, enum: [CREATE, ISSUE, RECEIPT, PAYMENT, ADJUST, VOID, REOPEN]}
beforeAmount: {$ref: '#/components/schemas/Money'}
afterAmount: {$ref: '#/components/schemas/Money'}
reason: {type: string}
operatorId: {$ref: '#/components/schemas/Id'}
occurredAt: {type: string, format: date-time}
CreateReceivableSettlementRequest:
type: object
required: [reconciliationStatementId]
required: [reconciliationStatementId, currency]
description: 客户、金额、期间和默认 30 天到期日均从已出账对账单与客户账期派生,不接受前端覆盖。
properties:
reconciliationStatementId: {$ref: '#/components/schemas/Id'}
currency: {type: string, enum: [CNY]}
CreatePayableSettlementRequest:
type: object
required: [supplierId, feeSourceIds, dueDate]
required: [customerId, supplierId, feeSourceIds, dueDate, currency]
properties:
customerId: {$ref: '#/components/schemas/Id'}
supplierId: {$ref: '#/components/schemas/Id'}
feeSourceIds:
type: array
@@ -824,6 +1050,7 @@ components:
uniqueItems: true
items: {$ref: '#/components/schemas/Id'}
dueDate: {type: string, format: date}
currency: {type: string, enum: [CNY]}
SettlementTransaction:
type: object
required: [transactionId, transactionType, transactionDate, amount, method, createdBy, createdAt]
@@ -831,9 +1058,12 @@ components:
transactionId: {$ref: '#/components/schemas/Id'}
transactionType: {type: string, enum: [RECEIPT, PAYMENT]}
transactionDate: {type: string, format: date}
amount: {$ref: '#/components/schemas/Money'}
amount: {$ref: '#/components/schemas/PositiveMoney'}
method: {type: string, enum: [BANK_TRANSFER, CASH, OTHER]}
referenceNo: {type: string}
voucherFileIds:
type: array
items: {$ref: '#/components/schemas/Id'}
createdBy: {$ref: '#/components/schemas/Id'}
createdAt: {type: string, format: date-time}
remark: {type: string}
@@ -842,14 +1072,14 @@ components:
required: [settlementId, amount]
properties:
settlementId: {$ref: '#/components/schemas/Id'}
amount: {$ref: '#/components/schemas/Money'}
amount: {$ref: '#/components/schemas/PositiveMoney'}
CreateReceiptRequest:
type: object
required: [customerId, receivedDate, amount, paymentMethod, voucherFileIds, allocations]
properties:
customerId: {$ref: '#/components/schemas/Id'}
receivedDate: {type: string, format: date}
amount: {$ref: '#/components/schemas/Money'}
amount: {$ref: '#/components/schemas/PositiveMoney'}
currency: {type: string, enum: [CNY], default: CNY}
paymentMethod: {type: string, enum: [BANK_TRANSFER, CASH, OTHER]}
voucherFileIds:
@@ -914,10 +1144,12 @@ components:
version: {type: integer, minimum: 0}
CreateSettlementPaymentRequest:
type: object
required: [transactionDate, amount, method, voucherFileIds]
required: [transactionDate, amount, currency, method, voucherFileIds, expectedVersion]
description: 仅用于 PAYABLE 结算单人工付款;amount 必须大于 0 且不得超过未付余额,File 校验必须 fail-closed。
properties:
transactionDate: {type: string, format: date}
amount: {$ref: '#/components/schemas/Money'}
amount: {$ref: '#/components/schemas/PositiveMoney'}
currency: {type: string, enum: [CNY]}
method: {type: string, enum: [BANK_TRANSFER, CASH, OTHER]}
referenceNo: {type: string}
voucherFileIds:
@@ -925,6 +1157,7 @@ components:
minItems: 1
uniqueItems: true
items: {$ref: '#/components/schemas/Id'}
expectedVersion: {type: integer, minimum: 0}
remark: {type: string, maxLength: 500}
ErrorEnvelope:
allOf:
@@ -0,0 +1,114 @@
# 财务一期 P0 操作契约与验收用例
> 日期:2026-08-11
> 适用范围:一期 5 页闭环中尚未实现的 11 个 operation
> 状态口径:以下 11 项全部是一期 P0;只有 Controller/DTO 已落地且直接行为测试通过后,才能逐项把 OpenAPI 的 `NOT_IMPLEMENTED` 改为 `IMPLEMENTED`
> 机器契约:`openapi/finance-phase1-five-pages-v1.yaml`
## 1. 统一冻结规则
- 金额只允许 CNY;请求出现其他币种或金额 `<= 0` 返回 `FIN_400`。
- 财务操作全部由平台财务人员人工提交表单。客户只能读取自己的已出账结果,不能审核、生成、调整、作废或登记收付款。
- 客户账户是账单、费用来源和收付款派生视图,不建设余额表,不提供钱包、预收、充值或余额调整接口。
- 平台接口使用权限码控制。实体必须按其真实客户归属校验;同一写请求中的来源、对账单、结算单和收付款对象必须属于同一客户。跨客户对象按不存在处理,返回 `FIN_404`,不得泄露对象是否存在。
- 所有写操作必须带 `Idempotency-Key`。请求哈希至少覆盖 method、规范化 path、目标客户、全部 query/body 字段;同键同参重放原结果,同键异参或仍在 `PROCESSING` 返回 `FIN_409`,FAILED/超时 PROCESSING 按现有 Finance 恢复规则执行。
- 带 `expectedVersion` 的操作使用乐观锁;版本不一致返回 `FIN_409`。出账后不原地覆盖,调整、作废和重开必须新增 revision 并保留操作人、原因、时间和前后值。
- 稳定错误码固定为:`FIN_400` 参数/CNY/金额错误,`FIN_404` 不存在或跨客户隐藏,`FIN_409` 状态/版本/重复占用/幂等冲突,`FIN_503` File 或内部依赖不可用,`FIN_001` 未分类服务端错误。认证和权限拒绝使用 HTTP `401/403`。
- 所有成功和业务错误响应固定包含 `requestId`、`traceId`、`timestamp`;成功 body 使用 `code="200"`,不得返回 Entity、Map 或临时字段。
## 2. 11 个 P0 operation 冻结矩阵
| P0 | operationId | 请求 DTO | 响应 DTO | 权限 | 状态/隔离与核心验收 |
|---|---|---|---|---|---|
| P0-01 | `listDerivedCustomerAccounts` | `AccountListQuery`(page/pageSize/keyword/status) | `AccountPageEnvelope<AccountSummary>` | `platform:finance:account:view` | 聚合未收、待出账、本期已收、应付;停用客户仍保留历史金额;无钱包字段。验收 AC-01、AC-02 |
| P0-02 | `listDerivedCustomerAccountLedger` | `AccountLedgerQuery`(customerId path、业务类型、日期、分页) | `LedgerPageEnvelope<LedgerEntry>` | `platform:finance:account:view` | 只返回指定客户来源/单据/收付款派生流水;日期闭区间;跨客户对象不可混入。验收 AC-03、AC-04 |
| P0-03 | `getFinanceFeeSource` | `FeeSourceIdPath` | `FeeSourceDetailEnvelope<FeeSourceDetail>` | `platform:finance:fee-source:view` | 返回业务关联、版本、审核、参与结算、占用和操作日志;不接受前端金额覆盖。验收 AC-05 |
| P0-04 | `reviewFinanceFeeSource` | `ReviewRequest` | `FeeSourceDetailEnvelope<FeeSourceDetail>` | `platform:finance:fee-source:review` | `PENDING -> APPROVED/REJECTED`;非 PENDING、旧版本、已占用均拒绝。验收 AC-06、AC-07 |
| P0-05 | `updateFeeSourceSettlementInclusion` | `SettlementInclusionRequest` | `FeeSourceDetailEnvelope<FeeSourceDetail>` | `platform:finance:fee-source:settlement` | 仅 `APPROVED + PUBLISHED + AVAILABLE + CNY` 可纳入;LOCKED/BILLED/VOIDED/SUPERSEDED 不可改。验收 AC-08、AC-09 |
| P0-06 | `createReconciliationStatement` | `CreateReconciliationRequest` | `ReconciliationDetailEnvelope<ReconciliationDetail>` | `platform:finance:reconciliation:create` | 按截止日或勾选来源生成 DRAFT;来源须同客户、合格且未被有效单据占用,金额由服务端快照读取。验收 AC-10 至 AC-12 |
| P0-07 | `actionReconciliationStatement` | `ReconciliationActionRequest` | `ReconciliationDetailEnvelope<ReconciliationDetail>` | 按 action 使用 review/issue/adjust/void 权限 | 提交、审核、出账、调整、作废、重开均走 revision;ISSUED 冻结来源,调整后总额不得低于已收。验收 AC-13 至 AC-17 |
| P0-08 | `createReceivableSettlement` | `CreateReceivableSettlementRequest` | `SettlementDetailEnvelope<SettlementDetail>` | `platform:finance:settlement-ar:create` | 只从同客户 ISSUED 对账单生成,一张有效对账单只能有一个有效应收结算单;直接进入 ISSUED。验收 AC-18、AC-19 |
| P0-09 | `createPayableSettlement` | `CreatePayableSettlementRequest` | `SettlementDetailEnvelope<SettlementDetail>` | `platform:finance:settlement-ap:create` | 同客户、同供应商的 APPROVED/INCLUDED/AVAILABLE/CNY PAYABLE 来源生成;直接进入 ISSUED。验收 AC-20、AC-21 |
| P0-10 | `getSettlement` | `SettlementIdPath` | `SettlementDetailEnvelope<SettlementDetail>` | AR/AP view 二选一并与单据方向匹配 | 返回结算单、来源快照、revision 和收付款记录;没有对应方向权限时 HTTP 403。验收 AC-22、AC-23 |
| P0-11 | `createSettlementPayment` | `CreateSettlementPaymentRequest` | `SettlementDetailEnvelope<SettlementDetail>` | `platform:finance:payment:create` | 只允许 PAYABLE 的 ISSUED/PARTIALLY_PAID;金额不得超过余额,凭证 File fail-closed;更新为 PARTIALLY_PAID/PAID。验收 AC-24 至 AC-26 |
`createReceiptWithAllocations` 已实现,不计入上述 11 项,但仍属于一期 P0 回归门禁:一笔 300 元收款可人工分配到同一客户 3 张各 100 元应收结算单并共用凭证;跨客户、草稿、超额、非 CNY、无有效凭证必须拒绝。
## 3. 状态机
### 3.1 费用来源
```text
PENDING --APPROVE--> APPROVED
PENDING --REJECT---> REJECTED
APPROVED + PUBLISHED + AVAILABLE --INCLUDE/EXCLUDE--> settlementIncluded true/false
AVAILABLE --对账单占用--> LOCKED --对账单出账--> BILLED
任意未出账有效版本 --上游作废--> VOIDED
AVAILABLE --上游调整新版本--> SUPERSEDED
```
### 3.2 客户对账单
```text
DRAFT --SUBMIT--> PENDING_REVIEW
PENDING_REVIEW --APPROVE--> APPROVED
PENDING_REVIEW --REJECT--> REJECTED
REJECTED/VOIDED --REOPEN--> DRAFT(新 revision)
APPROVED --ISSUE--> ISSUED(冻结来源)
ISSUED --ADJUST--> ISSUED(新 revision,不覆盖旧版)
DRAFT/PENDING_REVIEW/APPROVED/ISSUED --VOID--> VOIDED(已收金额=0 且无有效结算单)
```
`ADJUST` 必须提交至少一条调整行和原因;新总额不得小于已收金额。`VOID/REOPEN` 必须填写原因。ISSUED 后普通编辑接口不存在。
### 3.3 应收/应付结算单和收付款
```text
生成成功 -> ISSUED
ISSUED --部分收/付款--> PARTIALLY_PAID
ISSUED/PARTIALLY_PAID --收/付清--> PAID
ISSUED --VOID--> VOIDED(已收付金额=0)
VOIDED --REOPEN--> ISSUED(新 revision)
```
一期不处理预收、多收、退款、手续费、自动银行对账或汇率折算。人工收付款只能分配到同客户、同方向、CNY 且已出账的结算单。
## 4. 请求字段条件
- `CreateReconciliationRequest`:`customerId/currency/generationMode/periodStart/periodEnd` 必填;`currency=CNY`。`SELECTED` 时 `feeSourceIds` 至少 1 个,`BY_CUTOFF` 时服务端按 `periodEnd` 选择合格来源。
- `ReconciliationActionRequest`:`action/expectedVersion` 必填;`REJECT/ADJUST/VOID/REOPEN` 时 `reason` 必填;`ADJUST` 时 `adjustmentLines` 至少 1 个,每行包含 `statementLineId/adjustedAmount/reason`。
- `CreateReceivableSettlementRequest`:只提交 `reconciliationStatementId/currency`;客户、期间、金额和默认 30 天到期日由对账单与客户账期派生,不信任前端重复提交。
- `CreatePayableSettlementRequest`:`customerId/supplierId/feeSourceIds/dueDate/currency` 必填;来源必须同客户、同供应商。
- `CreateSettlementPaymentRequest`:`transactionDate/amount/currency/method/voucherFileIds/expectedVersion` 必填;`currency=CNY`、金额 `>0`、至少一张有效付款凭证。
## 5. 行为验收用例
| 用例 | 期望 |
|---|---|
| AC-01/02 | 账户列表金额可由来源、已出账结算单和收付款重算;响应不存在 balance/recharge/prepayment 字段 |
| AC-03/04 | 客户 A 流水不出现客户 B 单据;起止日期非法返回 `FIN_400` |
| AC-05 | 详情返回来源版本、业务对象和操作日志;不存在返回 `FIN_404` |
| AC-06/07 | PENDING 审核成功;重复审核、旧 expectedVersion 返回 `FIN_409` |
| AC-08/09 | 合格来源可切换参与结算;已锁定/出账/作废/替代版本返回 `FIN_409` |
| AC-10/11/12 | 两种生成模式成功;跨客户、非 CNY、重复占用或不合格来源分别返回 `FIN_404/FIN_400/FIN_409`,且不产生半成品 |
| AC-13/14 | 合法提交、审核和出账按状态迁移;非法 action/state 或并发版本返回 `FIN_409` |
| AC-15/16/17 | ISSUED 调整产生 revision;低于已收拒绝;有收款或有效结算单时作废拒绝;重开保留历史 |
| AC-18/19 | ISSUED 对账单生成唯一 AR;重复生成同参重放,异参或已有有效 AR 返回 `FIN_409` |
| AC-20/21 | 同客户同供应商 PAYABLE 来源生成 AP;混客户/供应商、已占用或非合格来源拒绝 |
| AC-22/23 | AR/AP 详情 DTO 完整;缺方向权限返回 403,不存在返回 `FIN_404` |
| AC-24/25/26 | 部分付款、付清状态正确;超额/重复/非 CNY/无凭证拒绝;File 不可用返回 `FIN_503` 且不落付款或更新余额 |
| AC-27 | 已实现收款回归:300 元分配 3 张 100 元同客户应收单成功并共用凭证 |
| AC-28 | 客户接口只能看到本人 `ISSUED/PARTIALLY_PAID/PAID` 单据和 `CONFIRMED` 收款,不返回凭证、内部备注、供应商成本或其他客户数据 |
| AC-29 | 每个写 operation 覆盖同键同参、同键异参、PROCESSING、FAILED/超时恢复;请求哈希改变任一业务字段即视为异参 |
## 6. 实现状态更新规则
每个 operation 必须同时满足以下证据,才允许把 `x-implementation-status` 从 `NOT_IMPLEMENTED` 改为 `IMPLEMENTED`:
1. Controller 存在与 OpenAPI 一致的 method/path、权限和固定 DTO。
2. Service/Repository 实现上述状态、客户归属、CNY、幂等、版本和审计规则。
3. 正向、非法状态、跨客户、无权限、同参重放、异参冲突和并发版本行为测试通过。
4. 涉及凭证的操作补 File fail-closed 测试;涉及客户可见数据的操作补脱敏与状态过滤测试。
5. 文档记录具体测试类、用例数和最近通过结果。只有代码存在、只有编译通过或只有间接测试均不得提前标完成。
@@ -1,11 +1,12 @@
# 财务一期五页产品与接口验收契约
> 日期:2026-08-11
> 状态:产品范围已确认;Finance 来源链与五页查询契约已实现并验证,剩余 11 个目标 operation、Admin 五页接入及跨服务 HTTP 冒烟待完成
> 状态:产品范围已确认;Finance 来源链与部分五页查询契约已实现并验证;当前 11 个 `NOT_IMPLEMENTED` operation 全部为一期 P0 阻断,禁止排到后续
> 领导验收范围:客户账户、客户应收应付、客户对账单、结算单应收、结算单应付
> 原型依据:`docs/悦/货代SAAS平台后台/货代SaaS平台原型.html`
> 目标 OpenAPI:`openapi/finance-phase1-five-pages-v1.yaml`;当前人工接口继续参考 `openapi/finance-f1-manual-v1.yaml`。
> 11 个 P0 操作的 DTO、状态机、权限、幂等、错误码、隔离和验收用例以 `财务一期P0操作契约与验收用例.md` 为准。
## 1. 一期范围结论
@@ -47,8 +48,8 @@
| 客户账户 | 汇总卡、客户列表、账户详情、流水详情;客户名称/编号、账户状态、余额条件、流水类型和日期 | 客户基本信息、客户编号、联系人、电话、未收余额、待出账金额、本期已收金额、应付余额、账户状态、最后变动时间;流水号、时间、业务类型、关联单据、应收/应付变动、变动后未收余额、操作人、备注 | 详情、查询、重置、导出;**无充值、扣款或余额调整** | 客户主体正常/停用只影响访问和新业务;所有金额可由来源、单据和收付款逐笔追溯,禁止直接写余额 |
| 客户应收应付 | 工具栏、组合查询、选中汇总、费用列表、费用详情、审核进度、关联业务、操作记录 | 客户、费用单号、是否已生成对账单、参与结算、审核状态、应收/应付、入仓码/柜次号、业务状态、费用类型、金额、业务发生日、来源类型、来源版本 | 详情、审核通过、审核拒绝、编辑未审核人工项、参与结算/禁止结算、按截止时间或勾选生成;已发布来源不可删除,只能作废/调整 | `PENDING -> APPROVED/REJECTED`;只有 `APPROVED + INCLUDED + AVAILABLE + CNY` 可生成;同一来源版本不能重复进入有效单据 |
| 客户对账单 | 查询区、主表、账单明细、支付历史;审核状态、账单编号、客户、柜次、结算起止日、是否结清、创建日期、最后收款时间 | 对账单号、客户、期间、账期、CNY、总应收、已收、未收、最后收款时间、是否结清、备注、创建/更新人时间;明细保留入仓单/柜次、业务日、计费量、费用项、金额、来源版本 | 生成草稿、详情、导出、审核通过、审核拒绝、作废;不提供发票和汇率操作 | `DRAFT -> PENDING_REVIEW -> APPROVED/REJECTED/VOIDED`;审核通过后来源冻结,调整必须留 revision;支付历史只读展示有效收款 |
| 结算单应收 | 汇总卡、筛选、列表、详情、费用明细、收款记录;收款状态、客户、结算单号 | 结算单号、客户、CNY、应收、已收、余额、关联对账单、业务期间、生成日、到期日、收款状态、制单人、状态 | 从审核通过对账单生成、详情、部分收款、导出、作废/重开;不保留高级查询假入口 | `DRAFT -> ISSUED -> PARTIALLY_PAID -> PAID`,未收款可作废;出账后冻结,调整保留 revision;收款人工表单和图片沿用 F1 契约 |
| 结算单应付 | 汇总卡、供应商筛选、列表、详情、费用明细、付款记录 | 结算单号、供应商、费用类型、CNY、应付、已付、余额、来源期间、生成日、到期日、付款状态、制单人、审核人、状态 | 从审核通过且参与结算的应付来源生成、详情、审核、部分付款、导出、作废/重开;删除利润分析和利润审批按钮 | `DRAFT -> PENDING_REVIEW -> ISSUED -> PARTIALLY_PAID -> PAID`,拒绝/作废保留记录;付款为人工登记和凭证图片 |
| 结算单应收 | 汇总卡、筛选、列表、详情、费用明细、收款记录;收款状态、客户、结算单号 | 结算单号、客户、CNY、应收、已收、余额、关联对账单、业务期间、生成日、到期日、收款状态、制单人、状态 | 从已出账对账单生成、详情、部分收款、导出、作废/重开;不保留高级查询假入口 | 生成后直接 `ISSUED -> PARTIALLY_PAID -> PAID`;来源已在对账单阶段审核,结算单不重复增加假审批;未收款可作废,调整保留 revision |
| 结算单应付 | 汇总卡、供应商筛选、列表、详情、费用明细、付款记录 | 结算单号、供应商、费用类型、CNY、应付、已付、余额、来源期间、生成日、到期日、付款状态、制单人、状态 | 从审核通过且参与结算的应付来源生成、详情、部分付款、导出、作废/重开;删除利润分析和利润审批按钮 | 生成后直接 `ISSUED -> PARTIALLY_PAID -> PAID`;不重复增加结算单审批;作废/重开保留 revision,付款为人工登记和凭证图片 |
表格“操作”列必须位于第一列。原型中未形成真实闭环的“新增、生成账单、高级查询、快捷导出”等按钮,只有在对应接口和权限完成后才显示。
@@ -57,12 +58,12 @@
| 页面 | 当前仓库事实 | 一期目标 | 差异等级 |
|---|---|---|---|
| 客户账户 | 后端已新增 `/customer-accounts/{customerId}` 和固定读 DTO;无列表接口 | 派生财务往来汇总、详情和流水,无任何充值/余额写入口 | IMPLEMENTED(单客户查询);列表/筛选仍缺,Finance DTO 测试通过 |
| 客户应收应付 | `/fee-pool` 固定 DTO、Firstleg 事件/快照和 `fin_fee_source` 写入均已实现并验证 | 真实入库/柜子费用来源池,支持审核、参与结算、详情和生成对账单 | 查询与来源入池已实现;详情/页面操作仍是 P0/P1 |
| 客户应收应付 | `/fee-pool` 固定 DTO、Firstleg 事件/快照和 `fin_fee_source` 写入均已实现并验证 | 真实入库/柜子费用来源池,支持审核、参与结算、详情和生成对账单 | 查询与来源入池已实现;详情、审核、参与结算均为一期 P0 |
| 客户对账单 | 后端已新增 `/statements` 和 `/bills/{billId}` 固定读 DTO 路径;独立生成/审核模型仍缺失 | 按截止时间或勾选合格来源生成,支持审核、明细、支付历史和 revision | IN_PROGRESS/P0 |
| 结算单应收 | 后端已新增 `/receivable-settlements` 固定读 DTO 路径;`fin_bill + fin_receipt` 已有人工状态能力 | 关联审核通过的客户对账单,按原型结构形成应收结算页 | IN_PROGRESS/P0 适配 |
| 结算单应付 | 后端已新增 `/payable-settlements` 固定读 DTO 路径并读取人工成本;付款单和完整供应商来源池仍缺失 | 从真实 PAYABLE 来源生成,审核后人工登记付款与凭证 | IN_PROGRESS/P0 |
Finance 来源写入不再是阻断:内部事件入口、Inbox 幂等、Firstleg 入库/柜子快照、`fin_fee_source` 新版本写入/替代/作废、`PUBLISHED + amount>0` 入池校验、五页固定 DTO、完整幂等、File fail-closed、Client 脱敏和稳定错误码均已实现并通过测试。剩余主要阻断转为 11 个目标 operation、Admin 五页接入和测试环境跨服务冒烟。
Finance 来源写入不再是阻断:内部事件入口、Inbox 幂等、Firstleg 入库/柜子快照、`fin_fee_source` 新版本写入/替代/作废、`PUBLISHED + amount>0` 入池校验、部分五页固定 DTO、完整幂等、File fail-closed、Client 脱敏和稳定错误码均已实现并通过测试。当前 11 个目标 operation 是一期 P0,不是可延期的“剩余优化”;此外还需完成 Admin 五页接入和测试环境跨服务冒烟。
## 4. 费用来源到结算全链路
@@ -88,16 +89,11 @@ flowchart LR
现有 `fl_inbound_fee_detail` 已具备客户、入库单、方向、业务日、费用项快照、计费量、单价、金额、审核、发布和 `settlement_included` 字段;已有列表、新增、编辑、删除、审核通过和驳回接口。
仍缺:
- 通用费用的“参与结算/禁止结算”接口和原因、操作人、版本控制。
- 非 FBA 头程运费的统一发布动作;当前发布主要由 FBA 费用发送流程触发。
- 费用调整/作废事件及旧版本替代规则的完整实现。
- Finance 消费者和来源快照写入。
当前 Firstleg 来源发布、调整/作废事件、Relay、Finance 消费者和来源快照写入已经实现并通过测试。Finance 五页内的费用来源详情、二次审核和参与结算操作仍按一期 P0 补齐;这些操作不得绕过已发布不可变来源版本或覆盖上游业务事实。
### 4.2 柜子费用项
当前工作树已新增柜子费用来源表/实体、Controller、审核/参与结算/作废服务、发布事件和内部快照代码;这些文件尚未形成通过测试的稳定基线。既有 Firstleg 柜次体积快照仍只服务 Finance 人工整柜成本分摊,不能替代新来源模型的审核和不可变发布链路。
当前柜子费用来源表/实体、Controller、审核/参与结算/作废服务、发布事件、Relay 和内部快照已经实现,相关定向测试 17/17 通过。Firstleg 的真实柜次体积快照同时服务 Finance 整柜成本分摊,但仍不能由 Admin 手工提交的订单归属或体积替代。
一期至少需要业务侧模型:
@@ -146,7 +142,7 @@ Finance 必须通过 Inbox 幂等消费来源版本,或通过受保护的快
| 模型 | 必要字段 | 当前缺口 |
|---|---|---|
| `fin_fee_source` | 来源系统/类型/ID/版本/hash、方向、客户、供应商、订单/入库/柜次、业务日、费用项、数量/单价/金额、审核/参与结算快照、状态、占用单据 | 已有写入、类型、方向、柜次、费用编码、hash、完整 JSON 快照和版本状态;供应商顶层字段及对账单占用关系仍待后续模型落地 |
| `fin_fee_source` | 来源系统/类型/ID/版本/hash、方向、客户、供应商、订单/入库/柜次、业务日、费用项、数量/单价/金额、审核/参与结算快照、状态、占用单据 | 已有写入、类型、方向、柜次、费用编码、hash、完整 JSON 快照和版本状态;供应商顶层字段及对账单占用关系属于本期 P0 数据模型,不得延后 |
| `fin_reconciliation_statement` | 对账单号、客户、期间、账期、CNY 总额、状态、审核、版本、备注 | 缺失 |
| `fin_reconciliation_line` | 对账单、feeSourceId/version/hash、业务与计费快照、金额 | 缺失 |
| `fin_settlement` | AR/AP、客户/供应商、来源对账单、期间、到期日、总额、已收付、余额、状态、版本 | 当前 `fin_bill` 仅覆盖部分 AR |
@@ -156,10 +152,11 @@ Finance 必须通过 Inbox 幂等消费来源版本,或通过受保护的快
## 7. 专项优先级
### P0:不开工或不联调就无法闭环
### P0:一期验收硬阻断
1. 入库费用独立的参与结算/禁止结算和通用发布动作;柜子费用来源模型已完成,不再列为阻断。
2. 客户对账单、应收结算单、应付结算单的数据模型、状态机和剩余 11 个 operation。
1. 以下 11 个 operation 全部实现并通过直接行为测试:账户列表/流水;费用来源详情/审核/参与结算;对账单生成及出账/调整/作废;应收/应付结算单生成;结算单详情;人工付款登记。人工收款已实现但必须继续通过 300 元分配 3 张 100 元应收单等 P0 回归。
2. 对账单、应收/应付结算单、付款和 revision 所需数据模型与唯一约束同步落地,不能只做空 Controller。
3. 详细冻结契约见 `财务一期P0操作契约与验收用例.md`;不得把其中任何一项标为 P1、后续优化或假入口。
### P1:领导验收前必须完成
@@ -48,6 +48,8 @@ G0 允许:完善 API/OpenAPI、数据库迁移草案、契约测试样例、
当前按以下冻结口径修复和补测:
- `财务一期P0操作契约与验收用例.md` 中的 11 个 operation 全部为一期 P0;任一项仍为 `NOT_IMPLEMENTED` 时,G2 不得关闭,也不得写入后续排期;
- 账单聚合维度(首期固定 RMB/CNY)和账期计算规则冻结;
- 平台出账、关闭、重开和线下异议录入状态冻结;客户首期只读;
- 应收生成节点、人工收款表单字段、凭证关联和到期日冻结;首期不实现复杂多对多核销模型;
@@ -83,6 +85,7 @@ G0 允许:完善 API/OpenAPI、数据库迁移草案、契约测试样例、
- 设计 Finance Admin/Client 页面和空态、错误态、线下异议录入态;
- 准备脱敏历史费用样本与迁移校验脚本设计;
- 按 OpenAPI 1.2.0 完成剩余服务端 DTO、File fail-closed、幂等和客户可见 DTO,并让 Admin 移除人工体积、接入账期与 revision。
- 按五页目标 OpenAPI 和 P0 操作契约逐项实现 11 个 operation;仅在 Controller/DTO 与直接行为测试均有证据后更新实现状态。
### 本轮不再等待产品确认