Files
docs/财务管理/财务领域模型与数据字典.md
T
2026-08-11 18:06:30 +08:00

210 lines
17 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.
# 财务领域模型与数据字典(F0/F1 首版)
> **范围说明**:本文包含长期数据模型候选。钱包、充值、发票、费用分析和利润表不属于一期,不得据此建菜单、路由或接口;一期数据模型以《财务一期五页产品与接口验收契约》为准。
> 版本:V0.1(开发前设计稿)
> 日期:2026-08-10
> 范围:F0 财务底座、F1 客户应收与对账;F2-F4 预留
> 关联:[财务服务边界设计](财务服务边界设计.md)、[财务管理产品确认表](财务管理产品确认表.md)、[二期费用项目数据归属决策记录](../二期/二期费用项目数据归属决策记录.md)
## 1. 阅读和决策标记
| 标记 | 含义 |
|---|---|
| 技术已确认 | 已由当前架构或总控决策冻结,开发必须遵守;不再要求产品选择技术方案。 |
| 建议默认值 | 为保证模型可实施而提出的默认值,产品未确认前可调整。 |
| 产品待确认 | 会改变业务口径、页面或验收结果,不能当作已确定需求。 |
本稿只冻结逻辑归属、关系和不可逆数据保护规则。账期天数、账套/主体、收入确认日、汇率及分摊算法等业务口径仍以产品确认表为准。
## 2. 已确认的公共约束
### 2.1 服务与数据库
- **技术已确认**:Finance 为独立 `finance-service`,数据库为 `baiyue_finance`;Finance 不跨库 Join,不引用其他服务 Entity,不接受 Firstleg 直接写库。
- **技术已确认**:Firstleg 只提供已发布的业务费用版本;Finance 入池后保存来源快照,历史账单不依赖 Firstleg 当前行回算。
- **技术已确认**:跨服务只使用 DTO、受保护内部查询和 Outbox/Inbox 事件;事件消费必须幂等、可重试、可查结果。
### 2.2 主体、客户和 ID
- **技术已确认**:产品层级为“平台—客户”,`tenant_id=0` 仅为平台技术作用域,客户业务数据使用 `tenant_id>0`。Finance 表按客户隔离;平台公共主数据不因客户筛选改变候选范围。
- **建议默认值**:所有主键使用 `BIGINT UNSIGNED`(雪花/号段 ID);API、JSON 和前端 TypeScript 均按字符串传输。
- **技术已确认**:往来单位只保存 `party_id` 引用、`party_type` 和当时的名称/编码快照,不复制客户或供应商实体。
### 2.3 平台、客户与子用户
- **当前对话已确认**:产品只有平台、客户两种身份;平台维护平台角色/用户,客户维护本客户角色/用户。
- **技术已确认**:客户用户的财务操作上下文必须来自服务端当前客户成员关系和权限快照;不能信任前端传入的 `customerId/tenantId`,也不能让客户用户切换到其他客户范围。
- **技术已确认**:财务单据保存操作人的 `userId/memberId`、角色/权限快照标识和操作时姓名快照;成员停用只撤销后续访问,不改历史单据。
- **当前对话已确认**:账单、应收、余额、收款和核销等财务聚合均归属客户企业/对客结算对象,不归属某个客户子用户。子用户停用只撤销登录和权限,不改变客户财务归属,也不触发财务单据转交。
- **当前对话已确认**:首期一个客户企业唯一对应一个对客结算对象;不支持一个客户多个对客结算对象或独立账套。客户用户默认仍共享本客户财务数据边界,具体动作由角色权限控制。
- **当前对话已确认**:客户管理员决定财务角色和成员;获权成员共享本客户财务数据范围,不按本人/部门切分。客户端首期只读,异议线下反馈;财务写操作全部由平台财务完成。
- **当前对话已确认**:首期不做强制双人复核和金额分级审批,但权限、原因、版本和审计仍是技术硬约束。
- **术语约束**:客户企业是客户数据归属/结算对象;平台收付款、开票和核算的法律主体仍以 Finance 的 `FinancialEntity`/账套表达。客户子用户永远不是新的财务主体。
### 2.4 金额、币种和精度
- **技术已确认**:币种保存 ISO 4217 三位码;原币金额不可覆盖;不同币种不能直接合并或核销。
- **当前对话已确认**:首期只支持 RMB/CNY;金额使用定点小数保存,首期不做 USD、汇率折算或汇兑损益。
- **建议默认值**:金额 `DECIMAL(20,6)` 保存原始计算值,展示/结算精度和舍入模式另设字段;数量/重量/体积 `DECIMAL(20,6)`。具体精度需与产品确认的计费规则复核。
- 所有金额字段成对保存 `*_amount` 与 `currency_code`(或由单据头统一币种且明细校验一致),不得用浮点数。
### 2.5 通用字段与审计
所有业务表建议具备:`id`、`tenant_id`、`version`(乐观锁)、`created_at`、`created_by`、`updated_at`、`updated_by`、`deleted`(仅允许非财务事实草稿使用)。已出账、收款、核销、冲销、开票和期间记录禁止物理删除;更正使用反向/调整记录。
## 3. 聚合边界与关系
```text
Firstleg FeeVersion --(Outbox)--> FinanceFeeSource
FinanceFeeSource --(可选多条)--> ARStatementLine --(一条有效来源只入一张有效账单)
ARStatement --(确认后生成)--> ARReceivable
ARReceipt <--> ARAllocation <--> ARReceivable
ARAllocation --(反核销)--> ARAllocationReversal
所有写操作 --> FinanceAuditLog / FinanceOutbox
```
聚合根建议:`FinanceFeeSource`(来源池)、`ARStatement`(客户对账单)、`ARReceivable`(应收单)、`ARReceipt`(收款单)。核销是独立不可变事实,不把余额直接写成“收款成功”。
## 4. F0 财务底座数据字典
以下为建议物理表名;字段类型是实现建议,不代表已经执行建表。
### 4.1 `fin_subject`:财务主体(首期已确认一个平台主体)
| 字段 | 类型/约束 | 说明 | 状态 |
|---|---|---|---|
| `id` | BIGINT PK | 主体 ID | 技术已确认(ID 规则) |
| `subject_code` | VARCHAR(64) UNIQUE | 收款/付款法律或业务主体编码 | 技术已确认:服务端生成/维护 |
| `subject_name` | VARCHAR(200) | 主体名称快照;入口为平台“我的资料” | 当前对话已确认 |
| `subject_type` | VARCHAR(32) | 首期 `BOTH`;后续可扩展 `RECEIVING`/`PAYING` | 当前对话已确认 |
| `status` | VARCHAR(20) | `ACTIVE`/`INACTIVE` | 建议默认值 |
### 4.2 `fin_ledger`:账套与期间归属(账套待确认)
`ledger` 关联 `subject_id`,不把客户 ID 当作账套。首期一个平台主体对应一个默认账套;客户企业是对客结算对象,不创建客户账套。期间表使用自定义 `period_code` 和 `status=OPEN|CLOSING|CLOSED`;关账后允许平台财务重开,但必须记录原因和审计。
### 4.3 `fin_counterparty_ref`:往来单位引用快照
| 字段 | 类型/约束 | 说明 |
|---|---|---|
| `id` | BIGINT PK | Finance 内部引用 ID |
| `tenant_id` | BIGINT UNSIGNED NOT NULL | 客户隔离键;供应商为平台公共或其所属业务范围需按确认结果定 |
| `party_type` | VARCHAR(20) | `CUSTOMER`/`SUPPLIER` |
| `party_id` | BIGINT UNSIGNED NOT NULL | IAM/Warehouse 的外部 ID,仅引用 |
| `party_code`,`party_name` | VARCHAR | 获取时快照,保障历史可读 |
| 唯一约束 | `(tenant_id, party_type, party_id)` | 禁止同一客户重复引用 |
往来单位来源服务和供应商归属规则为**产品待确认**;Finance 不跨库外键。
### 4.4 `fin_currency` / `fin_exchange_rate`(F0 预留)
`fin_currency`:`currency_code CHAR(3) PK`、名称、精度、启用状态。
`fin_exchange_rate`:首期不建业务流程;如保留扩展表,仅作为未来能力预留,不参与 CNY 账单和利润计算。
### 4.5 `fin_number_sequence`:单据编号
按 `sequence_type`(`AR`、`AP`、`STATEMENT`、`RECEIPT`、`PAYMENT`、`ALLOCATION`、`INVOICE`、`ACCOUNT`)和年月/主体分段发号。采用成熟软件常见的“类型+年月+流水号”格式;数据库锁或原子更新保证并发安全,重试使用幂等键返回原单号,作废号不回收。
### 4.6 `fin_fee_source`:财务费用来源池
| 字段 | 类型/约束 | 说明 |
|---|---|---|
| `id` | BIGINT PK | Finance 来源记录 ID |
| `tenant_id` | BIGINT UNSIGNED NOT NULL, CHECK >0 | 客户隔离键 |
| `source_type` | VARCHAR(32) | `FIRSTLEG_FEE` 等 |
| `source_id`,`source_version` | BIGINT/INT NOT NULL | Firstleg 费用 ID 与不可变版本 |
| `source_no` | VARCHAR(64) | 业务费用单号快照 |
| `inbound_id`,`order_id` | BIGINT NULL | 业务关联 ID 快照,不建跨库 FK |
| `fee_item_id`,`fee_item_code`,`fee_item_name` | ID + 快照 | 引用平台公共费用项目;名称保留快照 |
| `direction` | VARCHAR(16) | `RECEIVABLE`/`PAYABLE`,供应商方向待 F2 确认 |
| `amount`,`currency_code` | DECIMAL + CHAR(3) | 原币金额 |
| `tax_amount`,`tax_rate` | DECIMAL | 税务字段,税口径待确认 |
| `business_date` | DATE | 来源业务日期 |
| `eligibility_status` | VARCHAR(20) | `PENDING/ELIGIBLE/EXCLUDED/BILLED/VOIDED` |
| `source_hash` | CHAR(64) | 来源内容哈希 |
| `event_id` | VARCHAR(100) | Outbox 事件 ID |
| 唯一约束 | `(source_type, source_id, source_version)`;`(event_id)` | 防重复入池 |
**当前对话已确认**:仅 `APPROVED + PUBLISHED + settlementIncluded=true`、未作废版本进入 `ELIGIBLE`;未出账允许按权限修改,进入有效账单后冻结。首发不迁移历史费用。
### 4.7 `fin_inbox_event` / `fin_audit_log`
`fin_inbox_event` 保存 `event_id`、事件类型、来源服务、幂等键、payload_hash、处理状态、重试次数、最后错误和处理时间;唯一 `(source_service,event_id)`,同键不同哈希必须拒绝并报警。
`fin_audit_log` 保存聚合类型/ID、动作、前后状态、变更摘要、操作者、请求/幂等键、trace_id、时间和原因。审计留存期、是否需要不可篡改存储为**产品待确认**,但财务事实不得删除是技术底线。
## 5. F1 客户应收与对账数据字典
### 5.1 `ar_statement`:客户对账单聚合根
核心字段:`id`、`tenant_id`、`statement_no`、`ledger_id`、`subject_id`、`counterparty_ref_id`、`currency_code`、`period_start/end`、`due_date`、`status`、`subtotal_amount`、`tax_amount`、`total_amount`、`confirmed_at/by`、`dispute_reason`、`version`。
建议唯一 `(tenant_id, statement_no)`;首期账单币种固定 CNY,防重复出账的业务唯一键建议 `(tenant_id,counterparty_ref_id,currency_code,period_start,period_end,generation_key)`。每个客户维护账期天数,默认 30 天;账期日期基准(出账日/账单日、自然日/工作日)需在接口契约中明确。
状态建议:`DRAFT → INTERNAL_REVIEW → ISSUED → CLOSED`;平台财务可 `ISSUED → ADJUSTED/VOIDED → ISSUED`,原账单不覆盖。客户首期只读查看,异议线下反馈,不开放 `CUSTOMER_CONFIRMED/DISPUTED` 客户操作状态。
### 5.2 `ar_statement_line`:对账单明细快照
字段:`id`、`statement_id`、`tenant_id`、`fee_source_id`、`source_version`、费用项目/来源单号快照、`quantity`、`unit_price`、`amount`、`currency_code`、税额、争议标记、排除原因、审计字段。
唯一建议 `(statement_id, fee_source_id)`;另以唯一条件约束同一有效 `fee_source_id` 只能关联一张未作废账单。明细不直接回写 Firstleg。
### 5.3 `ar_receivable`:应收单
字段:`id`、`tenant_id`、`receivable_no`、`statement_id`、`counterparty_ref_id`、`subject_id`、`currency_code`、`original_amount`、`allocated_amount`、`outstanding_amount`、`due_date`、`status`、`overdue_flag`、`recognized_at`、版本与审计字段。
唯一建议 `(tenant_id, statement_id)`(若产品允许一张账单拆多应收,改为 `(statement_id, receivable_no)`)。余额由核销事实汇总并在事务内更新,禁止前端传余额。
状态建议:`OPEN → PARTIALLY_SETTLED → SETTLED`;到期只置 `overdue_flag`。是否账单确认即生成应收、是否允许账单拆分,为**产品待确认**。
### 5.4 `ar_receipt`:收款单
字段:`id`、`tenant_id`、`receipt_no`、`subject_id`、`counterparty_ref_id`、`currency_code`、`received_amount`、`allocated_amount`、`available_amount`、`received_at`、`method`、`voucher_no`、`file_id`、`status`、登记/复核人、版本与审计字段。
建议状态 `DRAFT → CONFIRMED → PARTIALLY_ALLOCATED → FULLY_ALLOCATED → VOIDED`。到账方式、是否需复核和银行流水接入均为**产品待确认**;首版默认人工登记。
### 5.5 `ar_allocation` 与 `ar_allocation_reversal`
核销记录字段:`id`、`tenant_id`、`allocation_no`、`receipt_id`、`receivable_id`、`currency_code`、`allocated_amount`、`allocated_at`、`status=ACTIVE|REVERSED`、幂等键、操作者、原因和版本。
反核销字段:`id`、`allocation_id`、`reversal_no`、`reversed_amount`、`reason`、审批/操作人、时间、幂等键。唯一建议 `(tenant_id, idempotency_key)`;服务端校验同币种、不可超出收款可用额和应收未结额,反核销不删除原核销。
### 5.6 `ar_dispute`(建议预留)
保存 `statement_id`、提出方、争议明细/原因、状态 `OPEN|PROCESSING|RESOLVED|REJECTED`、处理结论和审计字段。首期争议来源为线下反馈,由平台财务录入和处理,不开放客户独立争议动作。
## 6. F2-F4 预留模型(不代表本期开发)
| 阶段 | 建议聚合/表 | 预留关系 | 产品待确认 |
|---|---|---|---|
| F2 应付 | `ap_statement`、`ap_statement_line`、`ap_payable`、`ap_payment`、`ap_allocation`、`ap_allocation_reversal` | 成本来源池 → 供应商账单 → 应付 → 付款核销 | 供应商主数据、成本确认节点、付款主体、审批分级 |
| F3 账户 | `fin_customer_account`、`fin_account_entry`、`fin_account_hold`、`fin_account_refund` | 充值/冻结/扣款/退款与应收核销分开,任何抵扣关联 `ar_allocation` | 账户是预付款还是授信、冻结/退款规则 |
| F3 发票 | `fin_invoice_application`、`fin_invoice`、`fin_invoice_action` | 应收可选关联发票;红冲/作废新增动作,不覆盖原票 | 开票主体、税率、含税口径、外部平台 |
| F4 分析 | `fin_cost_entry`、`fin_allocation_rule`、`fin_profit_snapshot`、`fin_report_snapshot` | CNY 账单收入、单票成本、整柜公共成本分摊 → 可钻取利润 | 成本来源字段和报表触发点仍需写入契约;不做汇率和月结 |
F2 的来源必须具备供应商、付款主体、成本凭证、币种金额和成本归属;当前人工 `PAYABLE` 明细不自动视为应付闭环。
## 7. 跨服务来源契约(逻辑字段)
Firstleg Outbox 事件建议包含:`eventId`、`eventType`、`occurredAt`、`customerId`、`inboundId`、`orderId`、`sourceFeeId`、`sourceFeeVersion`、`sourceFeeNo`、`feeDetailId`、`direction`、`businessDate`、`currency`、`amount`、`sourceHash`、`settlementIncluded`、`isVoided`。Finance 收到后通过内部 DTO 查询完整费用快照并写入 `fin_fee_source`。
事件顺序可乱序:以 `(source_id, source_version)` 和版本状态机处理,旧版本不得覆盖新版本。相同幂等键不同 `source_hash` 必须进入冲突状态并告警。费用调整/作废不改写已出账明细,而是形成新的补差或冲销来源(具体业务单据待 F1/F2 确认)。
## 8. 数据访问、索引和隔离验收
- 业务表查询索引必须以 `tenant_id` 开头,并覆盖状态、日期、客户和单号等常用筛选;单据号在客户内唯一。
- Finance 不建立跨库外键;所有外部 ID 仅作引用和快照,失联时显示“来源不可用”而不删除财务事实。
- 平台员工按授权客户范围查询;客户端从登录态取 `tenant_id`,禁止信任请求体客户 ID。供应商成本、内部备注、审计详情和内部附件不向客户返回。
- 金额变更必须通过服务方法在同一财务期间事务内完成,使用幂等键和乐观锁;期间 `CLOSING/CLOSED` 禁止直接编辑。
- 关键唯一约束:来源 `(source_type,source_id,source_version)`;有效账单来源占用;单据号;核销幂等键;主体/账套/币种编码。
## 9. 产品待确认清单(本稿不替代确认表)
1. F0:财务主体与账套数量、往来单位/供应商归属、账期与关账、单据编号格式、来源入池和历史迁移。
2. F1:账单生成维度和周期、应收生成节点、收款登记/复核、到期日、预收/多收/手续费/退款处理。
3. F2:供应商成本确认节点、付款主体、应付审批和付款方式。
4. F3:账户资金性质、冻结/解冻/退款、发票税务主体和外部平台。
5. F4:收入/成本确认日、汇率来源和日期、公共成本分摊、期间快照及报表权限。
## 10. 实施前检查
- 产品确认表中 S1-S8、F0、F1 形成结论或“暂缓+临时口径”后,冻结本稿对应字段和状态。
- 冻结后补充 API/权限/错误码/事件契约,并将表名建议转为迁移脚本;不得先从页面或跨库查询反推模型。
- 迁移前只读核对历史已发布费用和线下结算事实,避免重复入账;任何冲突先停在预检,不直接改写历史。
- 本文件是设计文档,不代表已创建 `finance-service`、`baiyue_finance` 或任何数据库表。