# 现行数据库表结构与看板字段口径

更新时间：2026-06-12（新增打款核销 + 合同/应收应付/资金管理/个人账/财务总览模块）

> 本文记录当前已落地代码和 PostgreSQL 表结构对应的字段口径。以后改报销字段、看板列、附件/COS 来源展示时，必须同步更新本文和项目 README，不能只临时查云端。

## 1. 当前数据事实源

当前 source of truth：

```text
本地项目：/Users/bot1/Volumes/root_for_ai/AI工作区/公司财务_业务梳理_报销走账系统重构_20260603_2006
本地 schema：backend/db/schema.sql
线上服务：https://wwyl.yipeng.online/finance-reimbursement/
线上看板：https://wwyl.yipeng.online/finance-reimbursement/dashboard/
线上数据库：PostgreSQL / company_finance
```

旧飞书多维表、旧云数据库/Prisma 设计、旧 `/finance/` 看板只作历史参考，不作为当前字段权威口径。

## 2. 报销审批看板当前目标列

用户确认后的表格列（现行 schema 没有独立 `department` 表，因此主表不显示“部门”）：

| 看板列 | 当前字段来源 | 说明 |
|---|---|---|
| 公司主体 | `reimbursement_order.default_owner_subject_id -> subject.name` | 报销默认归属公司主体。 |
| 报销人 | `reimbursement_order.applicant_subject_id -> subject.name` | 用户语义里的报销申请人；不再和“收款人/人员/实际付款人”混放。 |
| 报销内容 | 明细聚合自 `reimbursement_item.description` | 最接近“实际买了什么 / 这笔钱拿去报销干嘛用了”。多条明细时聚合展示，弹窗内逐条展示。 |
| 金额 | `reimbursement_order.total_amount` | 整单金额。弹窗里每条明细用 `reimbursement_item.amount`。 |
| 日期 | 优先 `reimbursement_order.submitted_at`，其次 `created_at`；明细用 `reimbursement_item.occurred_at` | 表格展示整单日期，来源弹窗展示明细日期。 |
| 状态 | `reimbursement_order.status` | 前端状态口径：`APPROVAL_PENDING`=发起审批，`REJECTED`=被拒绝，`APPROVED`=审批通过，`PAID`=已打款。 |
| 来源 | 不是数据源调试列；是“报销来源/附件入口” | 点击打开弹窗，查看每条报销内容明细和对应发票/附件源文件。 |

不建议继续作为主表列展示：

- `部门`：现行 schema 没有独立部门表，避免用项目名伪装部门；归属项目/费用类别放在“来源”弹窗明细里；
- `人员`：容易与报销人/收款人重复；
- `实际付款人`：更适合付款核销或付款看板，不适合作为报销审批主表核心列；
- `附件`：放到“来源”弹窗里；
- `实例来源` / `source`：属于系统内部调试口径，不面向普通用户展示。

## 3. 报销核心表结构

### 3.1 `reimbursement_order`：报销单整单

关键字段：

| 字段 | 口径 |
|---|---|
| `id` | 报销单主键。 |
| `order_no` | 报销单号。 |
| `applicant_subject_id` | 报销人/申请人。 |
| `payee_subject_id` | 收款人；当前主表不展示，后续付款核销可用。 |
| `default_owner_subject_id` | 公司主体/默认归属主体。 |
| `status` | 报销状态：发起审批、被拒绝、审批通过、已打款等。 |
| `total_amount` | 整单金额。 |
| `submitted_at` | 提交/发起时间。 |
| `approved_at` | 审批通过时间。 |
| `paid_at` | 付清时间；首次累计核销达到整单金额时写入。 |
| `source_draft_id` | 来源草稿。 |
| `remark` | 整单备注；不是“买了什么”的首选字段。 |

### 3.2 `reimbursement_item`：报销明细

关键字段：

| 字段 | 口径 |
|---|---|
| `reimbursement_order_id` | 所属报销单。 |
| `project_id` | 明细归属项目，映射到 `project.name`；主表不作为“部门”列展示。 |
| `owner_subject_id` | 明细归属主体。 |
| `expense_category_id` | 费用类别，如采购/样品、物流、AI 工具等。 |
| `source_category_id` | 来源类别，如有票报销、无票报销、个人代付等。 |
| `advancer_subject_id` | 垫付人。 |
| `amount` | 明细金额。 |
| `occurred_at` | 明细发生日期。 |
| `invoice_status` | 发票状态。 |
| `description` | 报销内容/买了什么/用途；看板“报销内容”的首选字段。 |
| `remark` | 明细备注；`description` 为空时可作为补充展示。 |

后端入库时已支持从 `item.description` 或 `item.name` 写入 `reimbursement_item.description`。

### 3.3 打款核销：`fund_transaction` + `reimbursement_payment`

打款核销口径（2026-06-12 起生效）：

- `fund_transaction` 是真实资金流水主账：每一笔实际打款单独成一条 `direction='OUT'`、`status='SETTLED'` 的流水；
- `reimbursement_payment` 是核销关联表：把流水金额拆分核销到具体报销单；报销单“已付金额”由核销金额加和得出，不人工维护；
- 一笔流水可核销多张报销单（合并打款），一张报销单也可由多笔流水分次付清（部分付款）；
- 报销单累计核销金额达到 `total_amount` 时，状态自动从 `APPROVED` 流转到 `PAID` 并写 `paid_at`；未付清时保持 `APPROVED`；
- 只有 `APPROVED` 状态的报销单可记录打款；超过未付金额、超过流水未核销余额的请求会被拒绝；
- 每次核销写一条 `audit_log`（action=`record_reimbursement_payment`）；支持 `idempotency_key` 防重复打款。

`fund_transaction` 关键字段：

| 字段 | 口径 |
|---|---|
| `transaction_no` | 流水号；新建时缺省自动生成 `FT<日期>-<后缀>`。 |
| `direction` / `amount` / `occurred_at` | 方向（报销打款为 `OUT`）、金额、实际发生时间。 |
| `payer_subject_id` / `payer_cash_account_id` | 付款主体与付款资金账户；缺省取报销单 `default_owner_subject_id`。 |
| `receiver_subject_id` | 收款主体；缺省取报销单 `payee_subject_id` / `applicant_subject_id`。 |
| `source_category_id` | 报销打款固定为 `src_company_repay_person`（公司还个人）。 |
| `status` | 实际已发生的打款为 `SETTLED`。 |

`reimbursement_payment` 关键字段：

| 字段 | 口径 |
|---|---|
| `reimbursement_order_id` / `fund_transaction_id` | 核销双方引用。 |
| `amount` | 本次核销到该报销单的金额。 |
| `paid_at` | 本次打款时间。 |
| `operator_subject_id` | 经办人。 |
| `idempotency_key` | 幂等键；带唯一部分索引，重复调用返回首次结果。 |

汇总视图：

- `reimbursement_order_summary`：每张报销单的 `paid_amount` / `unpaid_amount`；
- `fund_transaction_allocation_summary`：每笔流水的 `allocated_amount` / `unallocated_amount`（合并打款时校验余额用）。

资金账户 `cash_account` 由接口配置维护（见 5.4），不在代码里写死。

### 3.4 合同与应收应付（2026-06-12 新增）

| 表 | 作用 | 编号前缀 |
|---|---|---|
| `commercial_order` | 合同/订单统一台账；必须挂项目，归属主体缺省从项目带出 | `CT` |
| `receivable` | 应收/收入计划；实收由 `receivable_settlement` 加和派生 | `AR` |
| `receivable_settlement` | 应收-资金流水核销（支持分期到账、一笔流水拆多个应收） | `rst` |
| `payable` | 应付/费用义务；实付由 `payable_settlement` 加和派生 | `AP` |
| `payable_settlement` | 应付-资金流水核销（支持部分付款、个人代付） | `pst` |

状态机：

- 应收：`PLANNED/CONFIRMED → PARTIALLY_RECEIVED → RECEIVED`（核销自动流转），`OVERDUE/VOID` 人工；
- 应付：`DRAFT/CONFIRMED/PENDING_PAYMENT → PARTIALLY_PAID → PAID`（核销自动流转），`VOID` 人工；
- 核销守卫与报销打款一致：不超未结金额、复用流水不超未核销余额、幂等键防重复。

汇总视图：`receivable_summary` / `payable_summary`（含已收付/未结）、`commercial_order_summary`（合同金额/关联应收/已收）、`cash_account_balance_view`（期初+流入−流出）。`fund_transaction_allocation_summary` 已扩展为合并报销付款、应收核销、应付核销三类分配。

个人账派生与财务总览口径见：`docs/个人账派生与财务总览口径.md`。

## 4. 发票、附件与 COS 源文件

### 4.1 相关表

| 表 | 作用 |
|---|---|
| `attachment` | 附件源文件引用，包括原文件名、COS key、content type、文件大小、sha256 等。 |
| `invoice` | 发票结构化信息；`file_attachment_id` 可指向发票原始附件。 |
| `invoice_link` | 发票与报销明细等业务对象的关联。 |

### 4.2 `attachment` 关键字段

| 字段 | 口径 |
|---|---|
| `target_type` / `target_id` | 附件直接关联的业务对象，如 `reimbursement_order` 或 `reimbursement_item`。 |
| `file_name` | 原始文件名。 |
| `file_path` / `file_token` | 兼容旧附件引用；COS 接入后通常可存 key。 |
| `attachment_type` | `invoice`、`contract`、`proof`、`payment_proof`、`other` 等。 |
| `storage_provider` | 当前为 `tencent_cos`。 |
| `storage_bucket` / `storage_region` / `storage_key` | COS 对象定位信息；不包含密钥。 |
| `content_type` / `file_size` / `sha256` / `etag` | 文件元数据，便于审计追溯。 |

### 4.3 看板“来源”弹窗

点击表格“来源”后，弹窗应展示：

1. 整单摘要：公司主体、报销人、金额、报销内容；
2. 每条 `reimbursement_item` 明细：报销内容、归属项目、费用类别、发生日期、来源类别、明细金额；
3. 每条明细对应的发票/附件；
4. 整单级附件；
5. 附件“查看源文件”按钮：调用后端 `/api/attachments/:id/download`，由后端向 `studio-cloud-bridge` 请求短期 COS 签名下载链接，再返回给前端打开。

安全口径：前端只拿短期签名下载 URL，不暴露 COS Secret、cloud bridge token、数据库连接串或长期公开 URL。

## 5. 后端接口口径

### 5.1 报销看板列表

接口：

```text
GET /api/dashboards/reimbursements
```

当前列表需返回：

```text
company_name
applicant_name
reimbursement_content
amount
date / occurred_at
approval_status
reimbursement_items[]
attachments[]
attachment_count
```

其中 `reimbursement_items[]` 内部应包含：

```text
description
amount
occurred_at
project_name / department_name
expense_category_name
source_category_name
invoice_status
attachments[]
```

### 5.2 附件下载

接口：

```text
GET /api/attachments/:id/download
```

流程：

```text
前端点击查看源文件
  -> company-finance 后端读取 attachment.storage_key
  -> 调用 studio-cloud-bridge /v1/cos/sign-download
  -> 返回短期 download_url
  -> 前端新窗口打开源文件
```

注意：`download_url` 是短期链接，不应写入数据库或文档。

### 5.3 报销打款核销

```text
POST /api/reimbursements/:id/payments   # :id 可传报销单 ID 或 order_no
GET  /api/reimbursements/:id/payments
```

POST 请求体要点：

```text
amount                  必填，本次打款金额，不可超过未付金额
paid_at                 实际打款时间，缺省当前时间
fund_transaction_id     可选；传已有流水 ID/流水号时复用该流水做合并打款核销
payer_cash_account_id   建议填写，便于资金账户对账
payer_subject_id        缺省取报销单公司主体
operator_subject_id     经办人，写入审计
idempotency_key         幂等键，防重复打款
```

对应 MCP 工具：`finance_record_reimbursement_payment`。
报销单详情 `GET /api/reimbursements/:id` 的返回已包含 `payments[]`。

### 5.4 资金账户

```text
GET  /api/cash-accounts?owner_subject_id=...
POST /api/cash-accounts   # name + owner_subject_id 必填
```

对应 MCP 工具：`finance_list_cash_accounts`。

## 6. 状态快捷筛选

表格上方使用轻量状态筛选行：

```text
全部 / 发起审批 / 被拒绝 / 审批通过 / 已打款
```

点击后更新同一个 canonical `filters.status`，并重新加载看板。状态口径同第 2 节。

## 7. 维护要求

以后凡是改动以下内容，必须同步更新本文和 README：

1. 报销表结构；
2. `reimbursement_item.description`、附件、发票、COS key 等字段口径；
3. 报销审批看板主表列；
4. “来源”弹窗展示逻辑；
5. 附件下载/签名链接接口；
6. 状态机或状态中文展示。
