647 lines
19 KiB
Markdown
647 lines
19 KiB
Markdown
|
|
# 财务单据标准模型
|
|||
|
|
|
|||
|
|
## 1. 为什么需要标准模型
|
|||
|
|
|
|||
|
|
OCR、MCP、用户填写、业务数据库可能都描述同一张发票,但字段名和格式不同。
|
|||
|
|
|
|||
|
|
如果没有标准模型:
|
|||
|
|
|
|||
|
|
- 规则无法复用。
|
|||
|
|
- Agent 难以解释。
|
|||
|
|
- Hermes 难以批量统计。
|
|||
|
|
- MCP 返回结果难以合并。
|
|||
|
|
|
|||
|
|
这里要区分三层:
|
|||
|
|
|
|||
|
|
- 标准模型:定义 Agent、规则、MCP、OCR、数据库之间统一交换的数据结构。
|
|||
|
|
- 业务数据库表:定义 MVP 阶段真正落库存储、查询和统计所依赖的业务表。
|
|||
|
|
- 文件存储对象:定义原始票据、预览件、OCR 中间产物、验真结果附件的存储位置与版本规则。
|
|||
|
|
|
|||
|
|
如果只有标准模型,没有业务表和文件资产表,User Agent 无法真正发起报销;如果只有数据库表,没有统一标准模型,语义解析、规则解释、OCR 回填和 Hermes 巡检会越来越混乱。
|
|||
|
|
|
|||
|
|
## 2. 标准对象
|
|||
|
|
|
|||
|
|
第一版建议定义这些对象:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Invoice
|
|||
|
|
Receipt
|
|||
|
|
ExpenseClaim
|
|||
|
|
PaymentRequest
|
|||
|
|
AccountsReceivableRecord
|
|||
|
|
AccountsPayableRecord
|
|||
|
|
BankTransaction
|
|||
|
|
Contract
|
|||
|
|
Customer
|
|||
|
|
Vendor
|
|||
|
|
Employee
|
|||
|
|
CostCenter
|
|||
|
|
DocumentAsset
|
|||
|
|
RiskEvent
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 对外语义层建议统一使用 `ExpenseClaim` 概念,不再把“报销申请”和“报销单据”拆成两个平行主概念。
|
|||
|
|
- 现有代码中仍有 `reimbursement_requests` 表,MVP 阶段不建议再继续扩张该表,而应以 `expense_claims` 作为报销主表。
|
|||
|
|
- `reimbursement_requests` 可保留用于兼容旧页面或审批联动,但新能力默认挂到 `expense_claims`。
|
|||
|
|
|
|||
|
|
## 3. Invoice 标准模型
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"invoice_id": "",
|
|||
|
|
"invoice_code": "",
|
|||
|
|
"invoice_number": "",
|
|||
|
|
"invoice_type": "",
|
|||
|
|
"seller_name": "",
|
|||
|
|
"seller_tax_no": "",
|
|||
|
|
"buyer_name": "",
|
|||
|
|
"buyer_tax_no": "",
|
|||
|
|
"issue_date": "",
|
|||
|
|
"total_amount": 0,
|
|||
|
|
"tax_amount": 0,
|
|||
|
|
"currency": "CNY",
|
|||
|
|
"verify_status": "",
|
|||
|
|
"ocr_confidence": 0,
|
|||
|
|
"source_document_id": ""
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 4. ExpenseClaim 标准模型
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"claim_id": "",
|
|||
|
|
"claim_no": "",
|
|||
|
|
"employee_id": "",
|
|||
|
|
"employee_name": "",
|
|||
|
|
"department_id": "",
|
|||
|
|
"department_name": "",
|
|||
|
|
"cost_center_code": "",
|
|||
|
|
"project_code": "",
|
|||
|
|
"expense_type": "",
|
|||
|
|
"reason": "",
|
|||
|
|
"location": "",
|
|||
|
|
"amount": 0,
|
|||
|
|
"currency": "CNY",
|
|||
|
|
"status": "",
|
|||
|
|
"occurred_at": "",
|
|||
|
|
"submitted_at": "",
|
|||
|
|
"approval_stage": "",
|
|||
|
|
"items": [],
|
|||
|
|
"attachments": [],
|
|||
|
|
"risk_flags": []
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- `reason`、`location`、`occurred_at` 是报销语义判断、规则解释、风险识别的最小必要字段。
|
|||
|
|
- 一张报销单通常包含多条费用明细,标准模型中允许聚合,数据库层必须拆到明细表。
|
|||
|
|
- `attachments` 指向文件资产,不直接嵌入二进制文件。
|
|||
|
|
|
|||
|
|
## 5. AccountsReceivableRecord 标准模型
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"ar_id": "",
|
|||
|
|
"document_no": "",
|
|||
|
|
"customer_id": "",
|
|||
|
|
"customer_name": "",
|
|||
|
|
"contract_no": "",
|
|||
|
|
"invoice_no": "",
|
|||
|
|
"amount_receivable": 0,
|
|||
|
|
"amount_received": 0,
|
|||
|
|
"amount_outstanding": 0,
|
|||
|
|
"currency": "CNY",
|
|||
|
|
"due_date": "",
|
|||
|
|
"posting_date": "",
|
|||
|
|
"status": "",
|
|||
|
|
"aging_days": 0,
|
|||
|
|
"risk_flags": []
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 6. AccountsPayableRecord 标准模型
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"ap_id": "",
|
|||
|
|
"document_no": "",
|
|||
|
|
"vendor_id": "",
|
|||
|
|
"vendor_name": "",
|
|||
|
|
"invoice_no": "",
|
|||
|
|
"amount_payable": 0,
|
|||
|
|
"amount_paid": 0,
|
|||
|
|
"amount_outstanding": 0,
|
|||
|
|
"currency": "CNY",
|
|||
|
|
"due_date": "",
|
|||
|
|
"posting_date": "",
|
|||
|
|
"status": "",
|
|||
|
|
"aging_days": 0,
|
|||
|
|
"risk_flags": []
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 7. BankTransaction 标准模型
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"transaction_id": "",
|
|||
|
|
"bank_account": "",
|
|||
|
|
"transaction_date": "",
|
|||
|
|
"amount": 0,
|
|||
|
|
"currency": "CNY",
|
|||
|
|
"counterparty_name": "",
|
|||
|
|
"summary": "",
|
|||
|
|
"matched_object_type": "",
|
|||
|
|
"matched_object_id": "",
|
|||
|
|
"match_status": ""
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 8. MVP 真实业务表设计
|
|||
|
|
|
|||
|
|
标准模型不等于数据库表,但 MVP 至少要有以下真实表,才能支撑 Day 5 用户报销对话、Day 6 风险巡检和后续审批/验真闭环。
|
|||
|
|
|
|||
|
|
### 8.1 设计原则
|
|||
|
|
|
|||
|
|
- 报销主数据统一落在 `expense_claims`,不再新建第三套“报销主表”。
|
|||
|
|
- 原始票据文件二进制不进数据库,只存元数据和关联信息。
|
|||
|
|
- OCR 结果、发票结构化结果、验真结果、风险事件要分表存,避免把所有字段塞进一个 JSON。
|
|||
|
|
- 所有表都要能被 Agent 解释,也要能被 Hermes 批量扫表。
|
|||
|
|
- `reimbursement_requests` 进入兼容态,不作为新能力主干表继续扩展。
|
|||
|
|
|
|||
|
|
### 8.2 报销主表 `expense_claims`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 作为用户报销会话最终落单的主业务对象。
|
|||
|
|
- 承接语义层补槽后的草稿、提交、审批、打回、归档状态。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
claim_no string(50) UK, 报销单号
|
|||
|
|
source string(30) 来源: agent/web/import/api
|
|||
|
|
title string(200) 报销标题
|
|||
|
|
employee_id string(64) 申请人 ID
|
|||
|
|
employee_name string(100) 申请人姓名
|
|||
|
|
department_id string(64) 部门 ID
|
|||
|
|
department_name string(100) 部门名
|
|||
|
|
company_code string(50) 公司编码
|
|||
|
|
cost_center_code string(50) 成本中心
|
|||
|
|
project_code string(50) 项目编码
|
|||
|
|
expense_type string(50) 费用大类
|
|||
|
|
reason text 事由
|
|||
|
|
location string(100) 地点
|
|||
|
|
amount numeric(12,2) 报销总金额
|
|||
|
|
currency string(10) 币种
|
|||
|
|
invoice_count int 附件票据数
|
|||
|
|
attachment_count int 附件总数
|
|||
|
|
occurred_start_at timestamptz 发生开始时间
|
|||
|
|
occurred_end_at timestamptz 发生结束时间
|
|||
|
|
submitted_at timestamptz 提交时间
|
|||
|
|
status string(30) draft/submitted/approved/rejected/paid
|
|||
|
|
status_changed_at timestamptz 最近状态变更时间
|
|||
|
|
status_changed_by string(64) 最近状态变更人
|
|||
|
|
status_change_note text 状态变更备注
|
|||
|
|
approval_stage string(50) 当前审批节点
|
|||
|
|
risk_level string(20) none/low/medium/high
|
|||
|
|
risk_flags_json json 风险标记快照
|
|||
|
|
conversation_id string(64) 对话会话 ID
|
|||
|
|
created_by string(64) 创建人
|
|||
|
|
updated_by string(64) 更新人
|
|||
|
|
created_at timestamptz
|
|||
|
|
updated_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 现有模型已有一部分字段,后续只做增量扩展即可。
|
|||
|
|
- `occurred_start_at`、`occurred_end_at` 比单一 `occurred_at` 更适合差旅、接待等跨时段报销。
|
|||
|
|
|
|||
|
|
### 8.2.1 报销状态流转建议
|
|||
|
|
|
|||
|
|
建议状态:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
draft
|
|||
|
|
submitted
|
|||
|
|
approved
|
|||
|
|
rejected
|
|||
|
|
paid
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
建议流转:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
语义补槽完成
|
|||
|
|
-> 创建 expense_claims 草稿
|
|||
|
|
-> status = draft
|
|||
|
|
|
|||
|
|
用户继续补充字段 / 上传附件
|
|||
|
|
-> 更新 expense_claims / expense_claim_items / expense_item_documents
|
|||
|
|
-> status 仍为 draft
|
|||
|
|
|
|||
|
|
用户明确确认提交
|
|||
|
|
-> status = submitted
|
|||
|
|
-> 写入 submitted_at / status_changed_at / status_changed_by
|
|||
|
|
|
|||
|
|
审批流结果回写
|
|||
|
|
-> status = approved 或 rejected
|
|||
|
|
|
|||
|
|
付款完成回写
|
|||
|
|
-> status = paid
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
边界:
|
|||
|
|
|
|||
|
|
- User Agent 可以创建 `draft`,也可以在用户确认后提交到 `submitted`。
|
|||
|
|
- User Agent 不应直接把状态改为 `approved`、`rejected`、`paid`。
|
|||
|
|
- 所有状态变化都应写审计日志,必要时保留 `status_change_note`。
|
|||
|
|
|
|||
|
|
### 8.3 报销明细表 `expense_claim_items`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 表达一单多明细。
|
|||
|
|
- 作为 OCR 发票比对、重复报销识别、风险定位的最小粒度。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
claim_id string(36) FK -> expense_claims.id
|
|||
|
|
line_no int 明细序号
|
|||
|
|
item_date date 费用发生日期
|
|||
|
|
item_type string(50) 费用小类
|
|||
|
|
item_reason text 明细事由
|
|||
|
|
item_location string(100) 明细地点
|
|||
|
|
merchant_name string(200) 商户/酒店/餐厅
|
|||
|
|
customer_name string(200) 客户单位
|
|||
|
|
participants_json json 参与人员
|
|||
|
|
transport_type string(50) 交通方式
|
|||
|
|
item_amount numeric(12,2) 明细金额
|
|||
|
|
tax_amount numeric(12,2) 税额
|
|||
|
|
currency string(10)
|
|||
|
|
invoice_match_status string(30) unmatched/partial/matched
|
|||
|
|
risk_level string(20)
|
|||
|
|
risk_flags_json json
|
|||
|
|
remark text
|
|||
|
|
created_at timestamptz
|
|||
|
|
updated_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 现有 `invoice_id` 单字段不足以覆盖多张附件挂同一明细的情况,后续应改为关联表。
|
|||
|
|
|
|||
|
|
### 8.4 票据资产主表 `document_assets`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 作为所有原始附件的主索引表。
|
|||
|
|
- 支持报销单、报销明细、审批、验真、风控证据等多对象挂载。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
biz_domain string(30) expense/ap/ar/common
|
|||
|
|
biz_object_type string(50) expense_claim/expense_item/approval_record
|
|||
|
|
biz_object_id string(36) 业务对象 ID
|
|||
|
|
document_type string(50) invoice/receipt/itinerary/contract/other
|
|||
|
|
document_subtype string(50) vat_special/taxi/train/hotel/meal 等
|
|||
|
|
source string(30) upload/agent/import/system
|
|||
|
|
original_filename string(255)
|
|||
|
|
mime_type string(100)
|
|||
|
|
file_ext string(20)
|
|||
|
|
page_count int
|
|||
|
|
file_size_bytes bigint
|
|||
|
|
sha256 string(64) 去重与追溯
|
|||
|
|
storage_provider string(30) local/minio/s3/oss/cos
|
|||
|
|
storage_bucket string(100) 本地模式可为空
|
|||
|
|
storage_key string(500) 指向当前有效版本原件
|
|||
|
|
current_version_no int
|
|||
|
|
classification_status string(30) pending/success/failed
|
|||
|
|
ocr_status string(30) pending/running/success/failed
|
|||
|
|
virus_scan_status string(30) pending/clean/infected
|
|||
|
|
retention_policy string(30) finance_default/legal_hold/manual
|
|||
|
|
uploaded_by string(64)
|
|||
|
|
uploaded_at timestamptz
|
|||
|
|
created_at timestamptz
|
|||
|
|
updated_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.5 票据版本表 `document_asset_versions`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 保留原始文件和后续重新上传版本。
|
|||
|
|
- 允许“修正”但不允许覆盖原始证据。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
document_id string(36) FK -> document_assets.id
|
|||
|
|
version_no int 1,2,3...
|
|||
|
|
is_current bool
|
|||
|
|
change_reason string(100) replace/rotate/desensitize/reupload
|
|||
|
|
original_filename string(255)
|
|||
|
|
mime_type string(100)
|
|||
|
|
file_size_bytes bigint
|
|||
|
|
sha256 string(64)
|
|||
|
|
storage_provider string(30)
|
|||
|
|
storage_bucket string(100)
|
|||
|
|
storage_key string(500)
|
|||
|
|
uploaded_by string(64)
|
|||
|
|
uploaded_at timestamptz
|
|||
|
|
created_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.6 衍生文件表 `document_derivatives`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 存储缩略图、预览 PDF、逐页图片、脱敏件等衍生产物。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
document_version_id string(36) FK -> document_asset_versions.id
|
|||
|
|
derivative_type string(50) thumb/preview/page_image/desensitized
|
|||
|
|
page_no int 可空
|
|||
|
|
mime_type string(100)
|
|||
|
|
file_size_bytes bigint
|
|||
|
|
storage_provider string(30)
|
|||
|
|
storage_bucket string(100)
|
|||
|
|
storage_key string(500)
|
|||
|
|
created_by string(64)
|
|||
|
|
created_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.7 OCR 结果表 `document_ocr_results`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 保留每次 OCR 原始结果、模型版本、置信度和错误信息。
|
|||
|
|
- 支持后续重跑 OCR 与人工纠错对比。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
document_id string(36) FK -> document_assets.id
|
|||
|
|
document_version_id string(36) FK -> document_asset_versions.id
|
|||
|
|
ocr_engine string(50) paddle/aliyun/tencent/openai 等
|
|||
|
|
ocr_model string(100)
|
|||
|
|
run_no int 第几次 OCR
|
|||
|
|
status string(30) success/failed/partial
|
|||
|
|
language string(20)
|
|||
|
|
raw_text text
|
|||
|
|
raw_result_json json
|
|||
|
|
structured_result_json json
|
|||
|
|
confidence numeric(5,4)
|
|||
|
|
error_message text
|
|||
|
|
started_at timestamptz
|
|||
|
|
finished_at timestamptz
|
|||
|
|
created_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.8 发票结构化表 `invoice_structured_records`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 将发票核心字段标准化后独立存储,便于查重、验真、规则计算。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
document_id string(36) FK -> document_assets.id
|
|||
|
|
ocr_result_id string(36) FK -> document_ocr_results.id
|
|||
|
|
invoice_code string(50)
|
|||
|
|
invoice_number string(50)
|
|||
|
|
invoice_type string(50)
|
|||
|
|
seller_name string(200)
|
|||
|
|
seller_tax_no string(50)
|
|||
|
|
buyer_name string(200)
|
|||
|
|
buyer_tax_no string(50)
|
|||
|
|
issue_date date
|
|||
|
|
total_amount numeric(12,2)
|
|||
|
|
tax_amount numeric(12,2)
|
|||
|
|
currency string(10)
|
|||
|
|
check_code string(100)
|
|||
|
|
is_red_invoice bool
|
|||
|
|
is_electronic bool
|
|||
|
|
ocr_confidence numeric(5,4)
|
|||
|
|
normalized_status string(30) normalized/manual_corrected
|
|||
|
|
duplicate_fingerprint string(100) 发票号+代码+金额+日期
|
|||
|
|
created_at timestamptz
|
|||
|
|
updated_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.9 发票验真记录表 `invoice_verification_records`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 保留每次调用税局/第三方验真服务的结果,支持追溯。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
invoice_record_id string(36) FK -> invoice_structured_records.id
|
|||
|
|
verification_channel string(50) tax_mcp/third_party/manual
|
|||
|
|
request_payload_json json
|
|||
|
|
response_payload_json json
|
|||
|
|
verify_status string(30) verified/unverified/voided/error
|
|||
|
|
voided bool
|
|||
|
|
red_reversed bool
|
|||
|
|
verified_amount numeric(12,2)
|
|||
|
|
verified_issue_date date
|
|||
|
|
error_code string(50)
|
|||
|
|
error_message text
|
|||
|
|
verified_by string(64)
|
|||
|
|
verified_at timestamptz
|
|||
|
|
created_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.10 明细与票据关联表 `expense_item_documents`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 解决一条明细可关联多张票据、一张票据也可能支撑多条拆分明细的场景。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
claim_id string(36) FK -> expense_claims.id
|
|||
|
|
claim_item_id string(36) FK -> expense_claim_items.id
|
|||
|
|
document_id string(36) FK -> document_assets.id
|
|||
|
|
relation_type string(30) evidence/invoice/boarding_pass/receipt
|
|||
|
|
allocated_amount numeric(12,2) 分摊到该明细的金额
|
|||
|
|
match_status string(30) unmatched/partial/matched
|
|||
|
|
match_confidence numeric(5,4)
|
|||
|
|
created_at timestamptz
|
|||
|
|
updated_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.11 风险事件表 `risk_events`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 记录风险命中,而不是只在主表里塞一个 `risk_flags_json`。
|
|||
|
|
- 作为 Agent 解释“为什么拦截”的核心依据。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
biz_domain string(30) expense/ap/ar
|
|||
|
|
biz_object_type string(50) expense_claim/expense_item/invoice
|
|||
|
|
biz_object_id string(36)
|
|||
|
|
risk_code string(50) duplicate_invoice/amount_mismatch 等
|
|||
|
|
risk_name string(100)
|
|||
|
|
risk_level string(20) low/medium/high
|
|||
|
|
hit_source string(30) rule/agent/hermes/manual
|
|||
|
|
evidence_json json
|
|||
|
|
status string(30) open/confirmed/resolved/ignored
|
|||
|
|
detected_at timestamptz
|
|||
|
|
detected_by string(64)
|
|||
|
|
resolved_at timestamptz
|
|||
|
|
resolved_by string(64)
|
|||
|
|
resolution_note text
|
|||
|
|
created_at timestamptz
|
|||
|
|
updated_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.12 风险处置表 `risk_actions`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 记录每次人工确认、驳回、忽略、要求补件等处置动作。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
risk_event_id string(36) FK -> risk_events.id
|
|||
|
|
action_type string(30) confirm/reject/ignore/request_more
|
|||
|
|
action_note text
|
|||
|
|
operator_id string(64)
|
|||
|
|
operator_name string(100)
|
|||
|
|
created_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8.13 文件访问审计表 `document_access_logs`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- 记录谁看过、下载过、导出过原始票据。
|
|||
|
|
- 支撑财务审计和数据安全追溯。
|
|||
|
|
|
|||
|
|
建议字段:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
id string(36) PK
|
|||
|
|
document_id string(36) FK -> document_assets.id
|
|||
|
|
document_version_id string(36) FK -> document_asset_versions.id
|
|||
|
|
action string(30) preview/download/export/delete
|
|||
|
|
operator_id string(64)
|
|||
|
|
operator_name string(100)
|
|||
|
|
operator_role string(50)
|
|||
|
|
client_ip string(64)
|
|||
|
|
user_agent string(255)
|
|||
|
|
trace_id string(64)
|
|||
|
|
created_at timestamptz
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9. 表关系建议
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
expense_claims
|
|||
|
|
└─ expense_claim_items
|
|||
|
|
└─ expense_item_documents
|
|||
|
|
└─ document_assets
|
|||
|
|
└─ document_asset_versions
|
|||
|
|
└─ document_derivatives
|
|||
|
|
└─ document_ocr_results
|
|||
|
|
└─ invoice_structured_records
|
|||
|
|
└─ invoice_verification_records
|
|||
|
|
|
|||
|
|
risk_events -> 可指向 expense_claims / expense_claim_items / invoice_structured_records
|
|||
|
|
risk_actions -> risk_events
|
|||
|
|
document_access_logs -> document_assets / document_asset_versions
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
原则:
|
|||
|
|
|
|||
|
|
- 主业务对象和文件资产解耦。
|
|||
|
|
- OCR、验真、风险都挂在文件资产或业务对象之上,不把责任塞到一个巨表。
|
|||
|
|
- 文件版本和业务关系分离,避免替换附件时把历史证据冲掉。
|
|||
|
|
|
|||
|
|
## 10. 与现有表的衔接策略
|
|||
|
|
|
|||
|
|
当前代码中已经存在:
|
|||
|
|
|
|||
|
|
- `expense_claims`
|
|||
|
|
- `expense_claim_items`
|
|||
|
|
- `reimbursement_requests`
|
|||
|
|
|
|||
|
|
建议策略:
|
|||
|
|
|
|||
|
|
- `expense_claims` 继续作为未来报销主表。
|
|||
|
|
- `expense_claim_items` 增量扩字段并替换当前单一 `invoice_id` 直连方式。
|
|||
|
|
- `reimbursement_requests` 暂不删除,但冻结扩表。
|
|||
|
|
- 如旧流程仍引用 `reimbursement_requests`,可在过渡期建立:
|
|||
|
|
- `request_no -> claim_no` 对照字段
|
|||
|
|
- 或由 `approval_records` 同时支持两类来源对象
|
|||
|
|
|
|||
|
|
不建议做法:
|
|||
|
|
|
|||
|
|
- 再新建第四张“报销申请主表”。
|
|||
|
|
- 把原始发票图片以 blob 方式存进 `expense_claims`。
|
|||
|
|
- 把 OCR、验真、风控结果全塞进一个 JSON 大字段。
|
|||
|
|
|
|||
|
|
## 11. 实施顺序建议
|
|||
|
|
|
|||
|
|
Phase 1:
|
|||
|
|
|
|||
|
|
- 扩展 `expense_claims`
|
|||
|
|
- 扩展 `expense_claim_items`
|
|||
|
|
- 新增 `document_assets`
|
|||
|
|
- 新增 `document_asset_versions`
|
|||
|
|
- 新增 `expense_item_documents`
|
|||
|
|
|
|||
|
|
Phase 2:
|
|||
|
|
|
|||
|
|
- 新增 `document_ocr_results`
|
|||
|
|
- 新增 `invoice_structured_records`
|
|||
|
|
- 新增 `invoice_verification_records`
|
|||
|
|
- 新增 `document_derivatives`
|
|||
|
|
|
|||
|
|
Phase 3:
|
|||
|
|
|
|||
|
|
- 新增 `risk_events`
|
|||
|
|
- 新增 `risk_actions`
|
|||
|
|
- 新增 `document_access_logs`
|
|||
|
|
|
|||
|
|
Phase 4:
|
|||
|
|
|
|||
|
|
- 逐步弱化 `reimbursement_requests`
|
|||
|
|
- 将 Agent 草稿、审批、OCR、验真、风控全收敛到 `expense_claims` 体系
|
|||
|
|
|
|||
|
|
## 12. 对 Agent 的直接收益
|
|||
|
|
|
|||
|
|
- 用户说“我要报销”时,Agent 能先创建 `expense_claims` 草稿,再持续补槽。
|
|||
|
|
- 用户上传票据后,系统有明确的 `document_assets` 与 `expense_item_documents` 可挂载。
|
|||
|
|
- OCR 和验真结果不是一次性临时输出,而是可追溯、可回放、可审计的长期资产。
|
|||
|
|
- Agent 回答“为什么被拦截”时,可以直接引用 `risk_events` 和票据证据,不再靠拼字符串解释。
|