- 系统架构文档 (architecture/README.md) - 6个领域文档: - 账户域 (01-account.md) - 账务域 (02-ledger.md) - 交易域 (03-transaction.md) - 对账域 (04-reconciliation.md) - 补偿域 (05-compensation.md) - 积分域 (06-points.md) - API 参考文档 (api/README.md) - 前后端对接清单 (integration/frontend-backend.md)
455 lines
13 KiB
Markdown
455 lines
13 KiB
Markdown
# 对账域 (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<Utc>, // 创建时间
|
||
pub completed_at: Option<DateTime<Utc>>, // 完成时间
|
||
|
||
// 三账对账结果
|
||
pub bank_total: Option<Decimal>, // 银行账汇总
|
||
pub transit_net: Option<Decimal>, // 在途净额
|
||
pub ledger_total: Option<Decimal>, // 总账汇总
|
||
pub three_account_balanced: Option<bool>, // 三账是否平衡
|
||
}
|
||
```
|
||
|
||
**核心方法**:
|
||
|
||
```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<Decimal> {
|
||
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<String>, // 系统交易号
|
||
pub bank_ref_no: Option<String>, // 银行参考号
|
||
pub system_amount: Option<Decimal>, // 系统金额
|
||
pub bank_amount: Option<Decimal>, // 银行金额
|
||
pub diff_amount: Decimal, // 差异金额
|
||
pub status: ReconciliationItemStatus, // 状态
|
||
pub remark: Option<String>, // 处理备注
|
||
pub created_at: DateTime<Utc>,
|
||
}
|
||
```
|
||
|
||
**核心方法**:
|
||
|
||
```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<String>, // 关联交易号
|
||
pub reconciliation_item_id: Option<i64>,// 关联对账项ID
|
||
pub adjustment_type: AdjustmentType, // 补录类型
|
||
pub account_id: i64, // 账户ID
|
||
pub amount: Decimal, // 金额
|
||
pub reason: String, // 原因说明
|
||
pub operator: String, // 操作人
|
||
pub approver: Option<String>, // 审批人
|
||
pub status: AdjustmentStatus, // 状态
|
||
pub created_at: DateTime<Utc>,
|
||
pub approved_at: Option<DateTime<Utc>>, // 审批时间
|
||
}
|
||
```
|
||
|
||
## 四、枚举类型
|
||
|
||
### 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<ReconciliationBatch>;
|
||
|
||
// 获取对账批次
|
||
pub async fn get_batch(&self, id: i64) -> Result<ReconciliationBatch>;
|
||
|
||
// 获取对账明细
|
||
pub async fn get_batch_items(&self, batch_id: i64) -> Result<Vec<ReconciliationItem>>;
|
||
|
||
// ========== 三账校验 ==========
|
||
|
||
// 执行三账校验
|
||
pub async fn verify_three_accounts(&self, physical_account_id: i64) -> Result<ThreeAccountVerificationResult>;
|
||
|
||
// 更新批次三账结果
|
||
pub async fn update_three_account_result(&self, batch_id: i64, result: &ThreeAccountResult) -> Result<()>;
|
||
|
||
// ========== 手工补录 ==========
|
||
|
||
// 创建手工补录
|
||
pub async fn create_adjustment(&self, req: CreateManualAdjustmentRequest) -> Result<ManualAdjustment>;
|
||
|
||
// 审批补录
|
||
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<Vec<ManualAdjustment>>;
|
||
|
||
// ========== 统计查询 ==========
|
||
|
||
// 获取对账统计
|
||
pub async fn get_stats(&self, batch_id: i64) -> Result<ReconciliationStats>;
|
||
}
|
||
```
|
||
|
||
### 7.2 三账校验实现
|
||
|
||
```rust
|
||
pub async fn verify_three_accounts(&self, physical_account_id: i64) -> Result<ThreeAccountVerificationResult> {
|
||
// 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% | 记录日志 |
|
||
| 严重 | 三账不平衡 | 通知运营 |
|
||
| 紧急 | 大额差异 | 升级处理 |
|
||
|