# 公司财务报销系统部署记录

## 2026-06-12 20:30 +0800：项目建档接口 + 各模块测试数据填充（不走审批）

### 部署内容

1. 新增项目建档/查询接口：`POST/GET /api/projects`（项目必须归属主体，同主体同名拒绝，自动生成项目编号）；MCP 工具 `finance_create_project` / `finance_list_projects`（合计 29 个）；单元测试 34 个全绿。
2. 按用户口径"先不走审批流程，做完功能"，为每个模块填充业务自洽的测试数据；报销通过草稿直接 commit 为 `APPROVED` 入库，未发起飞书审批。

### 本次测试数据清单（全部带"测试"标记，后续整体清理）

| 模块 | 数据 |
|---|---|
| 项目 | 良渚文创合作（云汉）、文旅文创定制（云汉）、灵感周边产品线（万物）、点绛直播带货（点绛） |
| 资金账户 | 测试-云汉对公（期初 5万）、测试-万物对公（期初 2万）、测试-万物支付宝（期初 3千） |
| 合同 | 良渚年度合作 8万（3期）、灵感周边订单 2.5万（2期）、点绛直播专场 1.2万（1期） |
| 应收核销 | 良渚首付 3.2万全额 + 中期 1.2万部分；周边预付 1.5万全额；独立应收文旅尾款 8千未收 |
| 应付 | 打样费 6800 付清、模具费 1.5万待付、物流费 1200 个人代付、AI工具 4800 部分付 2400 |
| 资金流水 | 注资 5万（钱丽云→万物对公）、归还 5千 |
| 报销（未走审批） | RB20260612-65836ED9 无票差旅 356.50 APPROVED、RB20260612-48F4D12B 有票办公 1280 APPROVED、RB20260612-625D02EB 打样垫付 642 已打款 PAID |

### 验证结果（全部精确对账）

- 个人帐 钱丽云余额 48852.78 = 报销待打款 1752.78（无票 472.78/有票 1280）+ 注资 51000 + 代付 1400 − 公司已还 5300；按公司拆分 万物 46672.78 / 云汉 2180；
- 资金账户余额逐户核对一致（云汉对公 84158 = 5万期初 + 4.4万回款 − 9842 付款）；
- 财务总览：应收未收 68000/130000、应付未付 17400/28000、合同 4 份已收 62000、月度收支 5 月/6 月拆分正确；
- 当前数据量：项目 9、合同 4、应收 9、应付 5、流水 17、报销 10、账户 4。

## 2026-06-12 19:35 +0800：合同/应收应付/资金管理/个人账/财务总览模块部署

### 部署内容

按 `docs/一期业务事实模型与基础表结构草案.md` 实现并上线五个新模块：

1. **合同台账**：`commercial_order` 表 + `POST/GET /api/contracts`，建档时可同时创建分期应收；
2. **应收应付**：`receivable`/`payable` + 核销表，`POST /api/{receivables,payables}/:id/settlements`，实收/实付由核销加和派生，状态自动流转（PARTIALLY_* → RECEIVED/PAID）；
3. **资金管理**：`POST/GET /api/fund-transactions` 直接登记真实资金流水（个人注资 = IN + `src_personal_injection`）；`fund_transaction_allocation_summary` 视图扩展为合并报销/应收/应付三类核销；
4. **个人账派生**：`GET /api/dashboards/personal-ledger`，实时派生 +报销待打款（无票/有票拆分）+个人注资+个人代付−公司还个人，按人/按公司拆分，明细可溯源；口径见 `docs/个人账派生与财务总览口径.md`；
5. **财务总览**：`GET /api/dashboards/finance-overview`，资金账户余额、月度收支、应收应付未结、报销待打款、合同回款进度、按主体汇总。

前端看板中心改为多视图导航：财务总览 / 报销审批 / 个人帐 / 资金流水 / 应收应付 / 合同台账（原预留导航位全部落地）。

MCP 工具新增 11 个（合计 27 个）：finance_create_contract、finance_settle_obligation、finance_record_fund_transaction、finance_personal_ledger、finance_overview 等。

### 部署前备份

- `/srv/company-finance/backups/company-finance-before-modules-20260612_192136.tar.gz`
- `/srv/company-finance/backups/frontend-before-multiview-20260612_192136.tar.gz`

### 验证结果

- 云端 `npm run check` 通过，33 个单元测试全部通过；
- `db:migrate`：表/视图数 18 → 27，现有数据无影响；
- 服务重启 active，内外网 health 200，前端新 bundle（index-BXgPNFWc.js）已生效；
- 测试数据全链路验证（金额均为小额测试值）：
  - 合同 `CT20260612-747A8B91`（5000，两期应收 3000+2000）；
  - 首付款部分到账 1000 → `PARTIALLY_RECEIVED`，补足 → `RECEIVED`；超额核销被 409 拒绝；
  - 个人注资 1000（钱丽云→云汉）、应付 200 个人代付核销 → `PAID`、公司还个人 300；
  - 个人账派生精确对账：钱丽云余额 1016.28 = 报销待打款 116.28（全无票）+ 注资 1000 + 代付 200 − 已还 300；按公司拆分 云汉 900 / 万物有灵 116.28；
  - 财务总览各项指标与流水/核销记录一致。

### 测试数据补充（待整体清理）

本次新增测试数据：合同 CT20260612-747A8B91、应收 AR20260612-A72A8BD7/C423361B、应付 AP20260612-1399B550、流水 FT20260612-3E177B67/95EC37FA/B8788673/3DD9316F/5D7CD2CC 及对应核销/审计记录。

## 2026-06-12 18:35 +0800：报销打款核销（APPROVED → PAID）部署

### 部署内容

后端新增打款核销链路，补完报销状态机最后一段：

- `POST /api/reimbursements/:id/payments`：对 `APPROVED` 报销单记录打款；自动创建 `fund_transaction`（`OUT/SETTLED`，来源 `src_company_repay_person`），或复用已有流水合并打款核销多单；
- `reimbursement_payment` 核销关联；付清后报销单与来源草稿流转 `PAID`，写 `paid_at`；部分付款保持 `APPROVED`；
- 守卫：非 `APPROVED` 拒付、超未付金额拒付、超流水未核销余额拒付、`idempotency_key` 幂等；全程写 `audit_log`；
- 资金账户接口：`GET/POST /api/cash-accounts`；
- MCP 工具：`finance_record_reimbursement_payment`、`finance_list_cash_accounts`。

### 本次同步文件

- `backend/db/schema.sql`（`reimbursement_order.paid_at`、`reimbursement_payment` 幂等/经办/创建时间列、`fund_transaction_allocation_summary` 视图）
- `backend/src/server.js`
- `backend/src/mcp-tools.js`
- `backend/src/services/database-service.js`
- `backend/test/reimbursement-payment-service.test.js`（新增）
- `backend/test/approval-submission-service.test.js`（云端为旧版，补同步）
- `backend/package.json`
- `docs/mcp_tools_一期草案.json`
- `docs/现行数据库表结构与看板字段口径.md`
- `docs/feishu_reimbursement_approval_backend_flow.md`

### 部署前备份

- `/srv/company-finance/backups/company-finance-current-before-payment-settlement-20260612_182712.tar.gz`（46 个文件，已校验含 src/db/test/data）

### 验证结果

- 云端 `npm run check`：通过；
- 云端 `npm run test:unit`：24 个测试全部通过（首跑 1 失败系云端 `approval-submission-service.test.js` 为旧版，同步本地版本后全绿；服务代码两边 md5 一致）；
- `npm run db:migrate`：通过，`company_finance` 表数 17 → 18；
- `reimbursement_order.paid_at` 列、`fund_transaction_allocation_summary` / `reimbursement_order_summary` 视图已确认存在；
- `systemctl restart company-finance`：服务 active；
- 内部 `/health`：postgresql 模式正常；公网 `/finance-reimbursement/health`：200；
- `GET /api/cash-accounts`：200，当前为空列表（资金账户待配置）。

### 后续待办

1. ~~用 0.01 元测试单走一次真实打款核销~~：已于 2026-06-12 18:47 完成，三张测试单全部 `APPROVED → PAID` 验证通过（含幂等重放、已付拒付、流水超额核销拒绝、资金账户关联、看板回查），详见 `docs/2026-06-12_报销打款核销上线验证.md`；
2. 配置实际资金账户（`POST /api/cash-accounts`），打款时带 `payer_cash_account_id` 便于对账（本次验证用测试账户 `cac_1781261240741_1387d9f3`，属待清理测试数据）；
3. 审批拒绝/撤回/取消异常分支回归测试；
4. 用户确认：当前云端数据均为测试数据，全部验证做完后整体清理。

## 2026-06-09 19:49:44 +0800：飞书审批自动回调闭环已验证

### 结论

真实飞书审批自动回调已经跑通。公司财务系统可以完成系统入库、发起飞书审批、接收飞书自动 webhook、按审批实例 ID 回写状态。

### 验证单据

- `RB20260609-97CB911E`：飞书实例 `32F25E1C-6235-402B-A425-22FBBB7ABD67`，最终 `APPROVED`。
- `RB20260609-F392C5DA`：飞书实例 `C8EE2972-EAEF-4244-9F84-ED3B0F512725`，最终 `APPROVED`。
- `RB20260609-CC5EAD97`：飞书实例 `4E8DA5D2-4229-4281-B338-815AB9D268EA`，最终 `APPROVED`；同时验证有票附件链路。

### 回调事件统计

2026-06-09 17:30 后，`approval_callback_event` 统计：

```text
callback_events=18
approved_events=9
unknown_events=3
```

每个关键实例均有：`APPROVAL_PENDING=2`、`APPROVED=3`、`UNKNOWN=1`。

### 当前口径

- 飞书审批链路已通过真实自动回调验证，不再按“未配置 verification token / 未验证真实回调”描述当前状态。
- `UNKNOWN` 是飞书后续无状态事件的审计记录，不允许覆盖已通过/拒绝/已付款等终态。
- `APPROVED` 表示审批通过/待打款，付款核销到 `PAID` 仍是后续资金流水工作。
- 合成 PDF 有票测试验证附件链路，不代表真实发票结构化解析完成。

详细记录：`docs/2026-06-09_报销审批自动回调闭环验证.md`

## 2026-06-09 15:44:55 +0800：审批专用飞书 App 凭据隔离部署

### 目标

将公司财务后端的飞书审批 OpenAPI 调用与 Hermes 财务聊天机器人隔离，避免审批事件订阅、回调和 OpenAPI 权限配置影响当前飞书对话机器人。

### 本次变更

- 本地 finance profile `.env` 已新增审批专用变量：
  - `COMPANY_FINANCE_FEISHU_APP_ID`
  - `COMPANY_FINANCE_FEISHU_APP_SECRET`
- 云端 `/etc/company-finance/company-finance.env` 已新增同名变量，并保留时间戳备份。
- 后端 `backend/src/config.js` 已调整为优先读取审批专用变量，再回退到旧 `FEISHU_APP_ID / FEISHU_APP_SECRET`：
  - `COMPANY_FINANCE_FEISHU_APP_ID || FEISHU_APPROVAL_APP_ID || FEISHU_APP_ID`
  - `COMPANY_FINANCE_FEISHU_APP_SECRET || FEISHU_APPROVAL_APP_SECRET || FEISHU_APP_SECRET`
- 已部署到云端 `/srv/company-finance/current/src/config.js` 并重启 `company-finance`。

### 验证

- 本地新 App 凭据可成功获取飞书 `tenant_access_token`。
- 云端新 App 凭据可成功获取飞书 `tenant_access_token`。
- 云端服务重启后状态为 `active`。
- 云端 `/health` 返回 `ok: true`，数据库连接正常。
- 本地后端检查与单元测试通过：`npm run check`、`npm run test:unit`，共 16 项测试通过。

### 2026-06-09 15:53:53 +0800 补充：Verification Token 已配置

- 已将新 App 加密策略页的 `Verification Token` 配置到本地 finance profile `.env` 和云端 `/etc/company-finance/company-finance.env`。
- 已重启云端 `company-finance`，健康检查显示 `verification_token_configured: true`。
- 公网回调地址探测通过：
  - v2 `challenge` URL 校验返回 200 且 challenge 正确。
  - 携带正确 token 但不含审批实例 ID 的探测请求返回 400，说明 token 校验已通过并进入业务字段检查。
  - 携带错误 token 的请求返回 401，说明校验生效。
- 截图显示 `Encrypt Key` 未开启；当前后端不解析飞书加密事件，因此保持未开启即可。

### 2026-06-09 16:24:54 +0800 补充：重置 session 前 Skill/MCP 接口核查

- 已核对 `company-finance-cos-reimbursement` 与 `finance-assistant` skill。发现 `company-finance-cos-reimbursement` 的 MCP 工具名说明仍保留旧草案名，已修正为当前云端 `/mcp/tools` 实际暴露的 14 个工具名。
- 本地后端检查通过：`npm run check`。
- 本地单元测试通过：`npm run test:unit`，16 项通过、0 失败。
- 云端 `company-finance` 健康检查通过：PostgreSQL enabled，callback verification token configured。
- 云端 `/mcp/tools` 返回 14 个工具，且与预期集合一致，无缺失、无额外异常工具。
- 云端 `/mcp/call` 鉴权验证通过：未带 Bearer 返回 401；带正确服务端 token 后 `finance_get_intake_rules`、`finance_validate_intake_draft`、`finance_preview_intake` 均返回 200。
- 公网 callback v2 challenge 探测返回 200 且 challenge 正确。

### 当时未完成事项（已被 2026-06-09 19:49 记录更新）

- 当时仍需通过新测试审批验证真实状态变更回调；该事项已经在 2026-06-09 晚通过三张测试审批完成。

## 2026-06-09 15:07:58 +0800：飞书审批回调排查与当前实例状态同步

### 问题现象

用户在飞书审批单中已点“审批通过”，但后台看板仍显示 `发起审批 / APPROVAL_PENDING`。

### 排查结果

- 云端数据库中当前报销单 `RB20260609-EBA23300` 已绑定飞书实例，后台状态原为 `APPROVAL_PENDING`。
- 通过飞书 OpenAPI 实时读取该实例，飞书侧状态已是 `APPROVED`，审批单号为 `202606090001`。
- 云端 `approval_callback_event` 表原本为空，说明后台没有收到并记录过真实 webhook 事件。
- Nginx 最近访问日志未发现 `/finance-reimbursement/api/approval/feishu/callback` 或 `/api/webhooks/feishu/approval` 的真实回调命中。
- 云端 health 显示 `FEISHU_CALLBACK_VERIFICATION_TOKEN` 未配置，`FEISHU_CALLBACK_ALLOW_UNSIGNED=false`。
- 代码原先只识别旧版顶层 `{ challenge }` URL 校验体；飞书事件订阅 v2 形态可能是 `{ schema, header, event: { challenge } }`，需要兼容。

### 已完成修复

- `backend/src/services/feishu-callback-service.js` 已兼容：
  - 顶层 `challenge`；
  - v2 嵌套 `event.challenge`；
  - token 从 `body.token`、`header.token`、`event.token` 读取。
- `backend/test/feishu-callback-service.test.js` 已增加 v2 URL 校验与 header token 测试。
- 已部署到云端并重启 `company-finance`。
- 线上已验证 v2 URL verification：`POST /finance-reimbursement/api/approval/feishu/callback` 返回 200 和对应 `challenge`。
- 已用飞书 OpenAPI 读取当前实例状态，并通过系统标准状态回写路径将当前报销单同步为 `APPROVED`，写入 `approval_callback_event` 和 `audit_log`，事件类型为 `manual_feishu_status_sync`。

### 验证结果

- 本地 `npm run check`：通过。
- 本地 `npm run test:unit`：16/16 通过。
- 云端 `npm run check`：通过。
- 云端 `node --test test/feishu-callback-service.test.js`：3/3 通过。
- 云端服务：`company-finance` active。
- 线上 dashboard API 已显示当前报销单状态为 `APPROVED`。
- 汇总接口显示 `approved_count=1`，`by_status.APPROVED=1`。

### 当时仍需配置（已被 2026-06-09 19:49 记录更新）

以下为当时排查阶段的配置说明；当前 verification token、事件订阅和自动回调已完成真实测试验证。

```text
请求地址：https://wwyl.yipeng.online/finance-reimbursement/api/approval/feishu/callback
事件：审批实例状态变化 / approval instance status change（以飞书后台展示名称为准）
Verification Token：复制到云端 /etc/company-finance/company-finance.env 的 FEISHU_CALLBACK_VERIFICATION_TOKEN
```

配置 token 后重启 `company-finance`，再发起一笔测试审批并确认 `approval_callback_event` 自动新增。

## 2026-06-09 01:09:53 +0800：审批发起人/模板实时读取部署

### 部署目标

将本地最新报销审批闭环改动部署到云端正式 `company-finance` 服务：

- 审批发起人改为“当前和机器人对话并确认提交的飞书用户”；
- `公司统一报销申请（测试）` 模板继续作为联调模板，流程走通后作为正式模板维护；
- 云端正式提交前必须能实时读取飞书审批模板，不依赖本地映射兜底；
- webhook 回调解析、状态归一化、回写路径补充测试覆盖。

### 云端路径

- 公网入口：`https://wwyl.yipeng.online/finance-reimbursement/`
- systemd：`company-finance`
- 后端路径：`/srv/company-finance/current`
- 文档路径：`/srv/company-finance/docs`
- 内部端口：`127.0.0.1:8102`
- 数据库：`company_finance`

### 本次同步文件

- `backend/src/services/reimbursement-approval-service.js`
- `backend/src/services/feishu-approval-service.js`
- `backend/src/services/feishu-callback-service.js`
- `backend/test/approval-submission-service.test.js`
- `backend/test/feishu-callback-service.test.js`
- `backend/package.json`
- `docs/feishu_reimbursement_approval_backend_flow.md`

### 云端环境修正

已补入：

- `FEISHU_APP_ID`
- `FEISHU_APP_SECRET`
- `FEISHU_REIMBURSEMENT_APPROVAL_CODE=04E7B2B1-DCD7-44E1-84DA-7590CDD3DFE1`

仍待补：

- `FEISHU_CALLBACK_VERIFICATION_TOKEN`：当前云端 health 显示未配置。真实 webhook 回写前，需要从飞书开放平台事件订阅/回调配置复制 verification token 到 `/etc/company-finance/company-finance.env`，重启服务后再验证。

### 部署前备份

云端已在 `/srv/company-finance/backups/` 创建部署前备份：

- `company-finance-current-before-approval-user-context-20260609_010200.tar.gz`

环境变量文件也已按修改时间点创建 `.bak.*` 备份，位于 `/etc/company-finance/`。

### 验证结果

云端执行：

- `npm ci --omit=dev`：通过；
- `npm run check`：通过；
- `npm run test:unit`：15 个测试全部通过；
- `npm run db:migrate`：通过，数据库 `company_finance`，表数 17；
- `systemctl restart company-finance`：成功，服务 active；
- 内部 `/health`：`local_trial_only=false`，数据库模式 `postgresql`；
- 公网 `/finance-reimbursement/health`：200，数据库模式 `postgresql`；
- 云端 `POST /api/reimbursements/approval/prepare`：通过，且：
  - `template_source=feishu_openapi`；
  - `submit_ready=true`；
  - `missing_count=0`；
  - `applicant_source=request_context`；
  - `request_context_user_configured=true`。

验证用草稿已删除，最终正式库计数：

- `intake_draft_count=0`
- `reimbursement_order_count=0`

### 后续待办

1. 配置 `FEISHU_CALLBACK_VERIFICATION_TOKEN` 并重启 `company-finance`；
2. 用真实飞书会话用户 ID/open_id 走一次 submit，但必须先给用户发送审批预览并取得明确确认；
3. 等待飞书 webhook 回调，确认状态能从 `APPROVAL_PENDING` 更新为 `APPROVED` / `REJECTED`；
4. 确认审批通过后的“待打款/已打款”状态切换边界。
