优化
This commit is contained in:
+44
-2
@@ -25,6 +25,15 @@
|
||||
- 文件先由 File 服务上传,Finance 接收 `fileId` 引用,不直接接收二进制。
|
||||
- 平台账单列表必须带 `customerId`;收款和成本列表的 `customerId` 为可选筛选。首期接口返回非分页数组,前端分页只能在适配层完成;不得把数组伪装成服务端分页对象。
|
||||
- Finance 对外 DTO 应稳定使用 camelCase;数据库 JDBC `snake_case` 仅限适配层,不能作为长期前后端契约。
|
||||
- 所有成功和失败响应固定包含 `requestId`、`traceId`、`timestamp`;`timestamp` 使用 UTC ISO-8601。账单、收款、成本和账期分别使用 OpenAPI 中的固定 DTO,不允许返回 JDBC `Map` 或未声明字段。
|
||||
|
||||
### 2.1 幂等处理
|
||||
|
||||
- 幂等范围为 `customerId + operatorId + operation + Idempotency-Key`,请求哈希由 HTTP 方法、规范化路径、客户范围和规范化 JSON 请求体计算,不得只哈希幂等键。
|
||||
- 同键同参且原请求已成功:返回第一次创建的资源和业务结果,不重复写库;本次响应生成新的 `requestId/traceId/timestamp`。
|
||||
- 同键异参:返回 HTTP 409、`FIN-IDEMPOTENCY-CONFLICT`,不得覆盖原记录。
|
||||
- 同键同参但原请求为 `PROCESSING`:返回 HTTP 409、`FIN-IDEMPOTENCY-PROCESSING` 和 `Retry-After: 2`;调用方只能用原键重试,不得自动换键重复创建。
|
||||
- `PROCESSING` 超过 30 秒由服务端恢复任务核对业务资源和事务结果,恢复为 `SUCCEEDED` 或可重试失败;客户端不负责判断原事务是否落库。
|
||||
|
||||
## 3. 对象与状态
|
||||
|
||||
@@ -42,11 +51,30 @@
|
||||
|
||||
`allocations[]` 每项为 `billId + allocatedAmount`。首期要求分配金额之和等于收款金额;每项不得超过对应账单未收余额。收款凭证可被同一笔收款的多张账单共享。
|
||||
|
||||
收款只允许分配到同一客户且状态为 `ISSUED/PARTIALLY_PAID` 的账单;已收清、草稿、作废和跨客户账单均拒绝。服务端必须在同一事务内锁定所有账单、写入收款与分配并更新余额,不允许部分成功。
|
||||
|
||||
### 3.3 成本
|
||||
|
||||
字段:`costEntryId`、`costNo`、`costType`(`SINGLE_ORDER`/`CONTAINER_SHARED`)、`orderId`/`containerId`、费用项目、供应商/成本对象快照、金额、币种、凭证文件、备注、操作人。
|
||||
|
||||
单票成本直接归属单票;整柜公共成本按 `票体积 / 柜内有效票总体积` 分摊。体积为零或总量为零时拒绝自动分摊,改为人工指定;舍入尾差归最后一票并记录调整原因。
|
||||
单票成本必须提供 `orderId`,订单必须存在并属于表单中的客户。整柜公共成本必须提供 `containerId`,柜次及柜内参与分摊的有效票必须属于同一客户;混入其他客户、已作废票或不属于该柜的票时拒绝。
|
||||
|
||||
整柜分摊固定规则:
|
||||
|
||||
1. 使用成本创建时冻结的订单有效体积快照,单位 CBM、精度 6 位;有效票按 `orderId` 升序形成确定顺序。
|
||||
2. `ratio = orderVolume / totalVolume`;除最后一票外,`allocatedAmount = costAmount × ratio`,按 6 位小数 `HALF_UP`。
|
||||
3. 最后一票金额为 `costAmount - 前序分摊金额合计`,承接全部尾差;保存 `roundingAdjustment`,保证分摊金额合计严格等于成本金额。
|
||||
4. 单票体积为零时该票自动分摊为 0;柜内有效票总体积为零时返回 `FIN-COST-002`,随后仅允许 `MANUAL_ZERO_VOLUME` 人工指定同柜订单金额,且合计必须等于成本金额。
|
||||
5. 已落库的体积、比例、分摊金额和尾差均为不可变快照;来源体积后续变化不追改历史成本。
|
||||
|
||||
### 3.4 财务凭证上传与关联
|
||||
|
||||
1. Admin 先调用 File 的 `POST /api/platform/v1/files/finance-vouchers`,提交 `customerId + purpose(RECEIPT/COST) + file`,取得临时 `fileId`。
|
||||
2. File 只接受 JPEG、PNG、WebP、PDF,单文件不超过 10 MiB;记录客户、用途、上传人、SHA-256、状态 `TEMPORARY`。临时文件不得直接对客户开放。
|
||||
3. Finance 创建收款/成本前,使用内部服务令牌调用 `POST /internal/file/v1/finance-vouchers/validate` 批量校验:文件存在、`ACTIVE/TEMPORARY`、未删除、客户一致、用途一致、类型/大小合规、尚未关联其他资源。任一失败则整个财务表单不落库。
|
||||
4. Finance 落单成功后调用 `POST /internal/file/v1/finance-vouchers/associate`,把文件幂等关联到 `FINANCE_RECEIPT/FINANCE_COST + resourceId`;失败由 Finance Outbox 使用原幂等键重试,不重复创建收款或成本。
|
||||
5. 相同文件关联同一资源视为同参重放并返回原结果;关联其他资源返回 `FIN-FILE-004`。Finance 保存 fileId 关联,文件内容和元数据由 File 管理。
|
||||
6. 客户侧收款 DTO 不返回 `voucherFileIds`、内部备注或下载地址;首期客户不能查看平台收款/成本凭证。
|
||||
|
||||
## 4. 接口清单
|
||||
|
||||
@@ -78,6 +106,8 @@
|
||||
|
||||
客户端禁止 POST、PUT、PATCH、DELETE 财务写操作。
|
||||
|
||||
客户列表和详情只能返回当前客户且状态为 `ISSUED/PARTIALLY_PAID/PAID` 的账单。`DRAFT/VOIDED`、跨客户和不存在的账单详情统一返回 `FIN-AR-001`,不得通过错误差异泄露账单存在性;客户收款列表只返回分配到上述可见账单的记录。
|
||||
|
||||
## 5. 最小错误码
|
||||
|
||||
| 错误码 | 场景 |
|
||||
@@ -94,6 +124,14 @@
|
||||
| `FIN-AR-010` | 幂等键重复但请求内容不同 |
|
||||
| `FIN-COST-001` | 成本归属对象缺失 |
|
||||
| `FIN-COST-002` | 体积为零,无法按体积分摊 |
|
||||
| `FIN-COST-003` | 订单、柜次或柜内票不属于指定客户 |
|
||||
| `FIN-COST-004` | 人工分摊金额合计不等于成本金额 |
|
||||
| `FIN-FILE-001` | 凭证不存在、已删除或状态无效 |
|
||||
| `FIN-FILE-002` | 凭证客户或用途不匹配 |
|
||||
| `FIN-FILE-003` | 凭证类型或大小不允许 |
|
||||
| `FIN-FILE-004` | 凭证已关联其他财务资源 |
|
||||
| `FIN-IDEMPOTENCY-CONFLICT` | 同一幂等键对应不同请求内容 |
|
||||
| `FIN-IDEMPOTENCY-PROCESSING` | 同参请求仍在处理中,可按 Retry-After 使用原键重试 |
|
||||
| `FIN-AUTH-001` | 当前角色无平台财务写权限 |
|
||||
|
||||
## 6. 验收用例
|
||||
@@ -107,7 +145,11 @@
|
||||
7. 客户只读可见本客户账单和收款记录,不可写入、不跨客户查询。
|
||||
8. 客户子用户停用后不能访问财务页面,但历史操作人和客户财务归属不变。
|
||||
9. 登记单票成本成功;整柜公共成本按体积分摊,零体积场景要求人工指定。
|
||||
10. 重复 `Idempotency-Key` 返回原结果;同键不同请求返回 `FIN-AR-010`。
|
||||
10. 重复 `Idempotency-Key` 且同参返回原结果;同键不同请求返回 `FIN-IDEMPOTENCY-CONFLICT`。
|
||||
11. 同键同参处于 `PROCESSING` 时返回 409、`FIN-IDEMPOTENCY-PROCESSING` 和 `Retry-After`,不会生成第二张单。
|
||||
12. File 凭证客户、用途、状态、类型或大小任一不匹配时,收款/成本和分配均不落库;关联失败可由 Outbox 幂等补偿。
|
||||
13. 整柜自动分摊按 6 位 `HALF_UP` 计算,最后一票承接尾差且合计严格等于成本金额;总体积为零只允许同柜同客户订单人工分摊。
|
||||
14. 客户列表、详情和收款记录均看不到 `DRAFT/VOIDED` 账单,也看不到平台凭证 fileId 和内部备注。
|
||||
|
||||
## 7. 权限矩阵
|
||||
|
||||
|
||||
Reference in New Issue
Block a user