# 财务连接器与支付对账闭环 TODO

更新时间：2026-07-17

## 使用规则

- 每项必须回链 `CONCEPT.md`；只有代码、迁移、接口或容器验证提供证据后才能勾选。
- 外部回执、内部付款状态、ERP 入账和财务确认必须分开，mock 不得伪装成生产现金事实。

## 1. 契约与安全

- [x] [CONCEPT: 背景与问题] 盘点内部付款、申请归档、Business Event、Savings 实现和证据边界。
  证据：`expense_claim_approval_flow.py`、`expense_claim_application_handoff.py`、`expense_cases.py`、`savings_realization.py` 只读审计。
- [x] [CONCEPT: 目标与非目标] 冻结签名事件、幂等、对账、ERP 凭证、冲回和 mock 环境边界。
  证据：`CONCEPT.md`“目标与非目标”“数据与契约”“匹配算法”“降级策略”。
- [x] [CONCEPT: 权限与安全] 实现连接器签名认证、密钥版本、时间窗口、来源白名单和防重放。
  证据：`financial_connector_auth.py`、`financial_connector_ingestion.py`；HMAC 使用常量时间比较，tenant/provider/key version/timestamp/method/path 均进入签名边界，共享密钥跨 provider/key version 重放被拒绝，相同事件幂等重放、冲突 payload 返回 409。
- [x] [CONCEPT: 权限与安全] 实现平台配置权限与财务处置权限分离、跨租户 404 和申请人自证拒绝。
  证据：`financial_connectors.py`、`financial_connector_projection.py`；HTTP/服务回归覆盖普通用户、平台管理员、财务角色、跨租户隐藏与申请人自证拒绝。

## 2. 数据与迁移

- [x] [CONCEPT: 数据与契约] 新增配置、外部事件、对账投影和对账事件模型。
  证据：`models/financial_connector.py`、`schemas/financial_connector.py`。
- [x] [CONCEPT: 数据与契约] 新增后继 Alembic 迁移、迁移所有权、复合租户外键、唯一/检查约束和 append-only 触发器。
  证据：`20260716_0017_financial_connector_reconciliation.py`、`schema_ownership.py`、`migration_preflight.py`；一次性 PostgreSQL 17 完整迁移循环通过。
- [x] [CONCEPT: 数据与契约] 实现外部事件与退款/冲回引用、首次响应和 payload 指纹冲突。
  证据：`financial_connector_ingestion.py`、`payment_reconciliation.py`；同外部事件不同 payload 拒绝，退款/冲回必须绑定同租户已处理结算原事件。
- [x] [CONCEPT: 数据与契约] 新增配置 version、追加式配置审计和历史 normalized payload 脱敏迁移。
  证据：`20260716_0020_financial_connector_config_lifecycle.py`、`FinancialConnectorConfigEvent`；配置审计使用 PostgreSQL append-only trigger，历史 `claim_reference` 从不可变事件的 normalized payload 中受控移除，内容哈希继续保留；全新 PostgreSQL 17 完整升降级循环 1 项通过，另一个独立库验证 0019→0020 历史数据脱敏与 legacy 标识。

## 3. 服务与接口

- [x] [CONCEPT: 模块职责] 拆分认证、ingestion、reconciliation、action 和 projection 服务，核心文件不超过 800 行。
  证据：`financial_connector_auth.py`、`financial_connector_ingestion.py`、`payment_reconciliation.py`、`financial_connector_actions.py`、`financial_connector_projection.py` 职责独立，最大核心文件低于 800 行。
- [x] [CONCEPT: 接口] 实现统一事件入口、连接器配置、对账列表/详情、确认和拒绝接口。
  证据：`api/v1/endpoints/financial_connectors.py`。
- [x] [CONCEPT: 接口] 实现带 expected version、actor、request ID、reason 的 activate/disable/rotate 状态机与脱敏审计查询。
  证据：`financial_connector_config_lifecycle.py`、`financial_connector_config_audit.py`、`FinancialConnectorConfigLifecycleAction`、`FinancialConnectorConfigRotateAction`；激活/轮换前解析服务端密钥并校验强度，轮换原子切换新旧 key version。
- [x] [CONCEPT: 匹配算法] 完全匹配时复用现有幂等付款动作；任何金额、币种、单据或审批状态差异不产生付款副作用。
  证据：`FinancialConnectorActionService` 复用 `ExpenseClaimService.mark_claim_paid_from_connector()`；反向测试验证 mismatch/failure/conflict 无付款副作用。
- [x] [CONCEPT: 证据与审计] 把外部事件哈希写入 Expense Case/Business Event/Savings 证据 correlation 链。
  证据：连接器结算动作写入脱敏内容哈希、verification/evidence classification 与 correlation；服务 E2E 可回放付款、Case、Business Event 和 Savings evidence。
- [x] [CONCEPT: 状态转换] 实现支付失败、ERP posted/posting_failed、退款/冲回和对账重开。
  证据：`PaymentReconciliationService` 对六类生产事件分流；ERP 不重复付款，生产退款/冲回恢复 Claim 并追加 Savings 冲回事实。
- [x] [CONCEPT: 降级策略] test/mock/staging 六类事件只写 simulation-only connector fact/response projection，不修改核心财务状态。
  证据：`financial_connector_simulation.py`、`financial_connector_ingestion.py`；`test_financial_connector_services.py` 参数化覆盖三类非生产环境和六类事件，Claim、申请归档、对账、Business Event、ERP 与 Savings 均保持不变。

## 4. Mock 与可观测性

- [x] [CONCEPT: 降级策略] 实现明确标识 test/mock 的 adapter，覆盖成功、失败、乱序、重复、冲突、退款和 ERP 回执。
  证据：`financial_connector_mock_adapter.py`、`FinancialConnectorSimulationCreate/Read` 与平台管理员 simulate API；仅 active test/mock/staging 可运行，tenant/config/claim/scenario/request ID 确定性派生事件，production、disabled 和跨租户请求 fail-closed；7 场景服务/HTTP 回归通过。
- [x] [CONCEPT: 可观测性] 从现有事实输出最后成功时间、失败率、积压和对账异常，并在安全 DTO/UI 声明未采集指标。
  证据：`financial_connector_observability.py`、当前租户/管理员 observability API、`FinancialConnectorHealthPanel.vue`；所有查询先绑定 tenant，仅聚合 config/event/reconciliation 最小化事实，不返回原始 payload、签名和密钥。
- [x] [CONCEPT: 可观测性] 用后继 `0022` 追加式运行事件补齐 replay、auth_failure 和 payload conflict 耐久计数。
  证据：`20260716_0022_financial_connector_operational_events.py`、`financial_connector_operational_events.py`、`financial_connector_auth.py`、`financial_connector_ingestion.py`、`financial_connector_observability.py`；只有可信配置与服务端密钥解析后才归属认证失败，表内只保存 HMAC 指纹；同 candidate 重试幂等、不同接收尝试分别计数，API 返回窗口、source revision、真实数量和最近时间。
- [x] [CONCEPT: 兼容策略] 保留人工付款为低等级内部证据，并在 DTO/UI 区分外部回执和内部确认。
  证据：`financial_connector_payment_evidence.py`、payment-evidence API、`FinancialPaymentEvidenceRead` 与面板证据口径；人工付款=`internal_manual_payment`，通过 production-mode 契约验证的外部回执分类=`external_cash`，非生产回执=`simulated_connector|staging_connector`。真实 provider 仍待联调。

## 5. 测试与验收

- [x] [CONCEPT: 测试方案] 签名、防重放、幂等、冲突、字段白名单和错误恢复单元测试通过。
  证据：`test_financial_connector_services.py`、`test_financial_connector_endpoints.py`、`test_financial_connector_config_lifecycle.py` 与费用价值链 E2E 共 16 项通过；乱序原事件缺失保守进入 exception，不推进付款。
- [x] [CONCEPT: 测试方案] PostgreSQL 迁移、复合租户约束、append-only、并发和安全降级验证通过。
  证据：fresh PostgreSQL 17 最终迁移总探针 62 项通过；`financial_connector_migration_assertions.py` 验证配置/事件/运行事实 trigger、租户约束、HMAC 格式和 version check；`test_financial_connector_concurrency_postgres.py` 4 项通过，覆盖同事件、冲突补偿事实、配置单版本胜者和 operational candidate 单赢家；最终 head 为 `20260717_0028`。
- [x] [CONCEPT: 测试方案] 申请 → 票据 → 报销 → 预审 → 审批 → 外部付款 → 对账 → ERP 入账 → 归档端到端通过。
  证据：`test_expense_financial_value_chain_e2e.py` 使用测试密钥自签 production-mode HMAC 事件，覆盖申请审批、报销审批、ERP 入账、独立财务确认、Savings、商业价值与退款冲回契约；与连接器定向组合共 16 项通过，不代表真实 provider 回执或现金。
- [x] [CONCEPT: 测试方案] 支付失败、金额/币种错配、重复回执和退款反向链路通过。
  证据：`test_financial_connector_services.py` 覆盖 production-mode 失败/错配无副作用、稳定重放、ERP、reversal/refund 追加 Savings 冲回，以及非生产回执完全不创建 Savings。
- [x] [CONCEPT: 容器验证] 相关 pytest、Ruff、前端测试和构建均在 `local-x-financial-linux` 内通过。
  证据：历史连接器/配置/费用价值链/迁移组合 `140 passed, 1 skipped`；adapter/观测/证据 DTO 与既有连接器回归 `21 passed, 3 skipped`。2026-07-17 的 `0022` 收尾在容器内新增/定向回归 `115 passed`，全新 PostgreSQL 17 完整迁移循环 `51 passed`，连接器并发 `4 passed`，后继 `0023` 并发 `7 passed`；相关 Ruff、文件行数和全树 `git diff --check` 通过。历史连接器前端 3 项与 Vite 生产构建已通过；共享前端曾有 5 项旧路径测试失败，已单独记录且不属于本切片。

## 6. 客户配置待确认

- [ ] [CONCEPT: 风险与开放问题] 确认首个 provider、签名算法、字段映射、事件 SLA 和重试窗口。
- [ ] [CONCEPT: 风险与开放问题] 确认批次到单据映射、多币种汇率、会计期间、大额双人复核和退款口径。
