# 对账域 (Reconciliation Domain) ## 一、领域概述 对账域负责确保系统账务与银行账务的一致性,包括交易匹配、差异处理、手工补录、三账校验等功能。 ## 二、核心概念 ### 2.1 三账对账闭环 ``` ┌─────────────────────────────────────────────────────────┐ │ 三账校验公式 │ │ │ │ 总账余额 = 银行账余额 + 在途净额 │ │ │ │ ledger_total = bank_balance + transit_net │ └─────────────────────────────────────────────────────────┘ 银行账: 银行实际余额(通过银行接口查询) 在途账: 已扣未确认的资金(transit_amount) 总账: 系统记账余额(personal + labor + frozen) ``` ### 2.2 对账流程 ```mermaid graph TD A[获取银行流水] --> B[获取系统交易] B --> C[交易匹配] C --> D{匹配结果} D -->|匹配| E[标记已匹配] D -->|系统未达| F[创建系统未达项] D -->|银行未达| G[创建银行未达项] D -->|金额不匹配| H[创建差异项] E --> I[三账校验] F --> I G --> I H --> I I --> J{是否平衡} J -->|是| K[对账完成] J -->|否| L[需要审核] ``` ## 三、核心实体 ### 3.1 对账批次 (ReconciliationBatch) ```rust pub struct ReconciliationBatch { pub id: i64, pub batch_no: String, // 批次编号 pub physical_account_id: i64, // 实体账户ID pub recon_date: NaiveDate, // 对账日期 pub total_count: i32, // 总记录数 pub matched_count: i32, // 匹配数 pub mismatch_count: i32, // 不匹配数 pub status: ReconciliationStatus, // 状态 pub created_at: DateTime, // 创建时间 pub completed_at: Option>, // 完成时间 // 三账对账结果 pub bank_total: Option, // 银行账汇总 pub transit_net: Option, // 在途净额 pub ledger_total: Option, // 总账汇总 pub three_account_balanced: Option, // 三账是否平衡 } ``` **核心方法**: ```rust impl ReconciliationBatch { // 计算匹配率 pub fn match_rate(&self) -> f64 { if self.total_count == 0 { return 100.0; } (self.matched_count as f64 / self.total_count as f64) * 100.0 } // 是否全部匹配 pub fn is_all_matched(&self) -> bool { self.mismatch_count == 0 } // 是否已完成三账对账 pub fn has_three_account_result(&self) -> bool { self.three_account_balanced.is_some() } // 三账差异金额 pub fn three_account_difference(&self) -> Option { match (self.ledger_total, self.bank_total, self.transit_net) { (Some(ledger), Some(bank), Some(transit)) => { Some(ledger - (bank + transit)) } _ => None, } } } ``` ### 3.2 对账明细项 (ReconciliationItem) ```rust pub struct ReconciliationItem { pub id: i64, pub batch_id: i64, // 批次ID pub system_txn_no: Option, // 系统交易号 pub bank_ref_no: Option, // 银行参考号 pub system_amount: Option, // 系统金额 pub bank_amount: Option, // 银行金额 pub diff_amount: Decimal, // 差异金额 pub status: ReconciliationItemStatus, // 状态 pub remark: Option, // 处理备注 pub created_at: DateTime, } ``` **核心方法**: ```rust impl ReconciliationItem { // 检查是否需要手工处理 pub fn needs_manual_handling(&self) -> bool { matches!( self.status, ReconciliationItemStatus::SystemUnreached | ReconciliationItemStatus::BankUnreached | ReconciliationItemStatus::AmountMismatch ) } } ``` ### 3.3 手工补录 (ManualAdjustment) ```rust pub struct ManualAdjustment { pub id: i64, pub adjustment_no: String, // 补录编号 pub related_txn_no: Option, // 关联交易号 pub reconciliation_item_id: Option,// 关联对账项ID pub adjustment_type: AdjustmentType, // 补录类型 pub account_id: i64, // 账户ID pub amount: Decimal, // 金额 pub reason: String, // 原因说明 pub operator: String, // 操作人 pub approver: Option, // 审批人 pub status: AdjustmentStatus, // 状态 pub created_at: DateTime, pub approved_at: Option>, // 审批时间 } ``` ## 四、枚举类型 ### 4.1 对账批次状态 (ReconciliationStatus) ```rust pub enum ReconciliationStatus { Processing, // 处理中 Completed, // 已完成 NeedReview, // 需要审核 } ``` ### 4.2 对账项状态 (ReconciliationItemStatus) ```rust pub enum ReconciliationItemStatus { Matched, // 已匹配 SystemUnreached, // 系统未达(系统有银行无) BankUnreached, // 银行未达(银行有系统无) AmountMismatch, // 金额不匹配 Adjusted, // 已调整 } ``` | 状态 | 说明 | 处理方式 | |------|------|----------| | Matched | 系统与银行完全匹配 | 无需处理 | | SystemUnreached | 系统有记录但银行无 | 核实后补录或冲销 | | BankUnreached | 银行有记录但系统无 | 核实后补录 | | AmountMismatch | 金额不一致 | 核实后调整 | | Adjusted | 已手工调整 | 已处理 | ### 4.3 补录类型 (AdjustmentType) ```rust pub enum AdjustmentType { Add, // 补录(新增) Reverse, // 冲销 Modify, // 修改 } ``` ### 4.4 补录状态 (AdjustmentStatus) ```rust pub enum AdjustmentStatus { Pending, // 待审批 Approved, // 已审批 Rejected, // 已拒绝 } ``` ## 五、对账匹配规则 ### 5.1 匹配策略 1. **精确匹配**:银行交易号 = 系统银行参考号 2. **金额匹配**:金额完全一致 3. **时间匹配**:交易时间在允许范围内 4. **方向匹配**:入账/出账方向一致 ### 5.2 匹配优先级 ``` 1. 按银行交易号精确匹配 2. 按金额 + 时间 + 方向模糊匹配 3. 按 SourceKey 匹配(入账) 4. 无法匹配则标记为未达 ``` ### 5.3 差异处理 | 差异类型 | 处理方式 | |----------|----------| | 金额差异 < 1分 | 自动调平 | | 金额差异 < 100元 | 人工审核 | | 金额差异 >= 100元 | 升级处理 | ## 六、三账校验 ### 6.1 校验结果 ```rust pub struct ThreeAccountResult { pub bank_balance: Decimal, // 银行账余额 pub transit_net: Decimal, // 在途净额 pub ledger_total: Decimal, // 总账余额 pub is_balanced: bool, // 是否平衡 pub difference: Decimal, // 差异金额 } ``` ### 6.2 校验公式 ``` 期望总账 = 银行余额 + 在途净额 差异 = 实际总账 - 期望总账 平衡 = (差异 == 0) ``` ### 6.3 不平衡原因分析 | 原因 | 说明 | 处理 | |------|------|------| | 银行延迟 | 银行入账延迟 | 等待银行同步 | | 系统错误 | 记账错误 | 查找并修正 | | 在途异常 | 在途状态不正确 | 核实在途交易 | | 并发问题 | 对账期间有新交易 | 锁定后重新对账 | ## 七、领域服务 ### 7.1 ReconciliationService ```rust impl ReconciliationService { // ========== 对账批次管理 ========== // 执行对账 pub async fn run_reconciliation(&self, req: CreateReconciliationBatchRequest) -> Result; // 获取对账批次 pub async fn get_batch(&self, id: i64) -> Result; // 获取对账明细 pub async fn get_batch_items(&self, batch_id: i64) -> Result>; // ========== 三账校验 ========== // 执行三账校验 pub async fn verify_three_accounts(&self, physical_account_id: i64) -> Result; // 更新批次三账结果 pub async fn update_three_account_result(&self, batch_id: i64, result: &ThreeAccountResult) -> Result<()>; // ========== 手工补录 ========== // 创建手工补录 pub async fn create_adjustment(&self, req: CreateManualAdjustmentRequest) -> Result; // 审批补录 pub async fn approve_adjustment(&self, id: i64, approver: &str) -> Result<()>; // 拒绝补录 pub async fn reject_adjustment(&self, id: i64, approver: &str, reason: &str) -> Result<()>; // 获取待审批补录 pub async fn list_pending_adjustments(&self) -> Result>; // ========== 统计查询 ========== // 获取对账统计 pub async fn get_stats(&self, batch_id: i64) -> Result; } ``` ### 7.2 三账校验实现 ```rust pub async fn verify_three_accounts(&self, physical_account_id: i64) -> Result { // 1. 获取银行余额 let bank_balance = self.bank_client.query_balance(physical_account_id).await?; // 2. 计算在途净额 let transit_net = self.ledger_service.get_transit_total(physical_account_id).await?; // 3. 计算总账余额 let ledger_total = self.ledger_service.get_ledger_total(physical_account_id).await?; // 4. 校验 let expected_total = bank_balance + transit_net; let difference = ledger_total - expected_total; let is_balanced = difference.abs() < Decimal::new(1, 2); // 允许1分误差 Ok(ThreeAccountVerificationResult { physical_account_id, bank_balance, transit_net, ledger_total, expected_total, difference, is_balanced, verified_at: Utc::now(), }) } ``` ## 八、API 接口 | 方法 | 路径 | 说明 | |------|------|------| | POST | /api/v1/reconciliation/run | 执行对账 | | GET | /api/v1/reconciliation/batches/:id | 获取对账批次 | | GET | /api/v1/reconciliation/batches/:id/items | 获取对账明细 | | GET | /api/v1/reconciliation/three-account/:id | 三账校验 | | POST | /api/v1/reconciliation/adjustments | 创建手工补录 | | POST | /api/v1/reconciliation/adjustments/:id/approve | 审批补录 | | POST | /api/v1/reconciliation/adjustments/:id/reject | 拒绝补录 | | GET | /api/v1/reconciliation/adjustments/pending | 获取待审批补录 | ## 九、数据库表结构 ### 9.1 reconciliation_batch 表 ```sql CREATE TABLE reconciliation_batch ( id BIGINT PRIMARY KEY AUTO_INCREMENT, batch_no VARCHAR(64) NOT NULL UNIQUE, physical_account_id BIGINT NOT NULL, recon_date DATE NOT NULL, total_count INT DEFAULT 0, matched_count INT DEFAULT 0, mismatch_count INT DEFAULT 0, status VARCHAR(32) DEFAULT 'processing', bank_total DECIMAL(20, 2), transit_net DECIMAL(20, 2), ledger_total DECIMAL(20, 2), three_account_balanced BOOLEAN, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, completed_at TIMESTAMP NULL, INDEX idx_physical_account (physical_account_id), INDEX idx_recon_date (recon_date), INDEX idx_status (status) ); ``` ### 9.2 reconciliation_item 表 ```sql CREATE TABLE reconciliation_item ( id BIGINT PRIMARY KEY AUTO_INCREMENT, batch_id BIGINT NOT NULL, system_txn_no VARCHAR(64), bank_ref_no VARCHAR(64), system_amount DECIMAL(20, 2), bank_amount DECIMAL(20, 2), diff_amount DECIMAL(20, 2) DEFAULT 0.00, status VARCHAR(32) NOT NULL, remark TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (batch_id) REFERENCES reconciliation_batch(id), INDEX idx_batch (batch_id), INDEX idx_status (status) ); ``` ### 9.3 manual_adjustment 表 ```sql CREATE TABLE manual_adjustment ( id BIGINT PRIMARY KEY AUTO_INCREMENT, adjustment_no VARCHAR(64) NOT NULL UNIQUE, related_txn_no VARCHAR(64), reconciliation_item_id BIGINT, adjustment_type VARCHAR(32) NOT NULL, account_id BIGINT NOT NULL, amount DECIMAL(20, 2) NOT NULL, reason TEXT NOT NULL, operator VARCHAR(64) NOT NULL, approver VARCHAR(64), status VARCHAR(32) DEFAULT 'pending', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, approved_at TIMESTAMP NULL, INDEX idx_status (status), INDEX idx_operator (operator) ); ``` ## 十、对账时机 ### 10.1 自动对账 - 每日定时对账(T+1) - 配置对账频率(按账户) - 批量处理 ### 10.2 手动对账 - 运营人员触发 - 指定日期范围 - 单账户或多账户 ### 10.3 实时对账 - 大额交易实时校验 - 异常交易即时告警 - 关键节点检查 ## 十一、告警机制 | 告警级别 | 触发条件 | 处理方式 | |----------|----------|----------| | 警告 | 匹配率 < 99% | 记录日志 | | 严重 | 三账不平衡 | 通知运营 | | 紧急 | 大额差异 | 升级处理 |