tangweijie 1460187516 docs: 添加完整技术文档体系
- 系统架构文档 (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)
2026-01-05 18:12:37 +08:00

489 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 账务域 (Ledger Domain)
## 一、领域概述
账务域是系统的核心财务引擎,负责余额管理、复式记账、三科目约束校验。该域实现了银行级别的资金安全保障机制。
## 二、核心概念:三科目余额模型
### 2.1 模型定义
```
┌─────────────────────────────────────────────────────────┐
│ 银行余额 (bank_balance) │
│ = 1000.00 │
├─────────────────────────────────────────────────────────┤
│ 个人余额 │ 劳动报酬 │ 冻结余额 │
│ personal │ labor │ frozen │
│ = 500.00 │ = 300.00 │ = 200.00 │
│ (可用) │ (可用) │ (不可用) │
└─────────────────────────────────────────────────────────┘
不变量约束: personal + labor + frozen = bank_balance
```
### 2.2 余额类型说明
| 余额类型 | 字段 | 说明 | 可用性 |
|----------|------|------|--------|
| 个人余额 | personal_balance | 个人可支配资金 | 可用 |
| 劳动报酬 | labor_balance | 劳动所得报酬 | 可用 |
| 冻结余额 | frozen_balance | 被冻结的资金 | 不可用 |
| 银行余额 | bank_balance | 银行账面余额 | 对照 |
| 在途金额 | transit_amount | 已扣未确认 | 过渡 |
### 2.3 可用余额计算
```rust
// 总可用余额 = 个人 + 劳动
fn total_available(&self) -> Decimal {
self.personal_balance + self.labor_balance
}
// 可支配余额 = 总可用 - 在途
fn calculate_available(&self) -> Decimal {
self.total_available() - self.transit_amount
}
```
## 三、核心实体
### 3.1 账户余额 (AccountBalance)
```rust
pub struct AccountBalance {
pub id: i64,
pub account_id: i64,
pub account_type: AccountType,
// 三科目余额
pub personal_balance: Decimal, // 个人余额
pub labor_balance: Decimal, // 劳动报酬
pub frozen_balance: Decimal, // 冻结余额
// 银行对照
pub bank_balance: Decimal, // 银行余额
// 在途管理
pub transit_amount: Decimal, // 在途金额
// 版本控制
pub version: i32, // 乐观锁版本
pub updated_at: DateTime<Utc>,
}
```
### 3.2 会计科目 (AccountingSubject)
```rust
pub struct AccountingSubject {
pub code: String, // 科目代码
pub name: String, // 科目名称
pub category: SubjectCategory, // 科目类别
pub direction_default: i8, // 默认增加方向
pub parent_code: Option<String>,// 父科目代码
pub level: i32, // 科目级别
}
```
**预定义科目**
| 代码 | 名称 | 类别 |
|------|------|------|
| 1002 | 银行存款 | 资产 |
| 1003 | 在途资金 | 资产 |
| 2001 | 客户存款 | 负债 |
| 2002 | 待清算款项 | 负债 |
| 3001 | 手续费收入 | 收入 |
| 4001 | 利息支出 | 支出 |
### 3.3 记账分录 (LedgerEntry)
```rust
pub struct LedgerEntry {
pub id: i64,
pub entry_no: String, // 分录编号
pub txn_no: String, // 关联交易号
pub post_date: NaiveDate, // 记账日期
pub post_time: DateTime<Utc>, // 记账时间
pub description: Option<String>,// 摘要描述
pub status: EntryStatus, // 状态
pub created_at: DateTime<Utc>,
}
```
### 3.4 分录明细 (LedgerLine)
```rust
pub struct LedgerLine {
pub id: i64,
pub entry_id: i64,
pub account_id: i64,
pub account_type: AccountType,
pub subject_code: String, // 科目代码
pub direction: Direction, // 借贷方向
pub amount: Decimal, // 金额
}
```
## 四、枚举类型
### 4.1 借贷方向 (Direction)
```rust
pub enum Direction {
Debit, // 借方
Credit, // 贷方
}
```
### 4.2 科目类别 (SubjectCategory)
```rust
pub enum SubjectCategory {
Asset, // 资产类 - 借方增加
Liability, // 负债类 - 贷方增加
Income, // 收入类 - 贷方增加
Expense, // 支出类 - 借方增加
}
```
### 4.3 分录状态 (EntryStatus)
```rust
pub enum EntryStatus {
Pending, // 待确认
Posted, // 已过账
Reversed, // 已冲销
}
```
## 五、核心业务逻辑
### 5.1 优先级扣款
出金时按优先级从余额中扣减:**先个人,后劳动**。
```rust
pub fn deduct_with_priority(&mut self, amount: Decimal) -> Result<DeductionResult> {
let available = self.available_balance();
if available < amount {
return Err(AppError::InsufficientBalance { available, required: amount });
}
let mut remaining = amount;
// 1. 先扣个人余额
let from_personal = remaining.min(self.personal_balance);
self.personal_balance -= from_personal;
remaining -= from_personal;
// 2. 再扣劳动报酬
let from_labor = remaining.min(self.labor_balance);
self.labor_balance -= from_labor;
// 3. 同步银行余额
self.bank_balance -= amount;
Ok(DeductionResult { from_personal, from_labor, total: amount })
}
```
**扣款示例**
| 场景 | 扣款金额 | 个人余额 | 劳动余额 | 扣款来源 |
|------|----------|----------|----------|----------|
| 1 | 300 | 500 | 200 | 个人300 |
| 2 | 600 | 500 | 200 | 个人500 + 劳动100 |
| 3 | 800 | 500 | 200 | 失败(余额不足) |
### 5.2 冻结/解冻
冻结操作将可用余额转移到冻结余额,按优先级从个人和劳动中扣减。
```rust
// 冻结
pub fn freeze(&mut self, amount: Decimal) {
let mut remaining = amount;
// 先从个人扣
let from_personal = remaining.min(self.personal_balance);
self.personal_balance -= from_personal;
remaining -= from_personal;
// 再从劳动扣
if remaining > Decimal::ZERO {
let from_labor = remaining.min(self.labor_balance);
self.labor_balance -= from_labor;
}
// 增加冻结余额
self.frozen_balance += amount;
}
// 解冻(默认返回到个人余额)
pub fn unfreeze(&mut self, amount: Decimal) {
let unfreeze_amount = amount.min(self.frozen_balance);
self.frozen_balance -= unfreeze_amount;
self.personal_balance += unfreeze_amount;
}
```
### 5.3 在途管理
在途金额表示已从可用余额扣减但尚未得到银行确认的资金。
```rust
// 建立在途(出金时)
pub fn add_transit(&mut self, amount: Decimal) {
self.transit_amount += amount;
}
// 结转在途(银行确认成功)
pub fn settle_transit(&mut self, amount: Decimal) -> Result<()> {
if self.transit_amount < amount {
return Err(AppError::BusinessRule("在途金额不足".into()));
}
self.transit_amount -= amount;
Ok(())
}
// 回退在途(银行失败)
pub fn rollback_transit(&mut self, amount: Decimal) {
let rollback = amount.min(self.transit_amount);
self.transit_amount -= rollback;
self.personal_balance += rollback; // 返回到个人余额
self.bank_balance += rollback; // 恢复银行余额
}
```
### 5.4 不变量校验
确保三科目之和等于银行余额。
```rust
pub fn validate_invariant(&self) -> Result<()> {
let sum = self.personal_balance + self.labor_balance + self.frozen_balance;
if sum == self.bank_balance {
Ok(())
} else {
Err(AppError::InvariantViolation {
account_id: self.account_id,
expected: self.bank_balance,
actual: sum,
})
}
}
```
## 六、领域服务
### 6.1 LedgerService
```rust
impl LedgerService {
// ========== 余额操作 ==========
// 获取账户余额
pub async fn get_balance(&self, account_id: i64, account_type: AccountType) -> Result<AccountBalance>;
// 冻结金额
pub async fn freeze_amount(&self, account_id: i64, account_type: AccountType, amount: Decimal) -> Result<()>;
// 解冻金额
pub async fn unfreeze_amount(&self, account_id: i64, account_type: AccountType, amount: Decimal) -> Result<()>;
// 优先级扣款
pub async fn deduct_with_priority(&self, account_id: i64, account_type: AccountType, amount: Decimal) -> Result<DeductionResult>;
// 建立在途
pub async fn add_transit(&self, account_id: i64, account_type: AccountType, amount: Decimal) -> Result<()>;
// 结转在途
pub async fn settle_transit(&self, account_id: i64, account_type: AccountType, amount: Decimal) -> Result<()>;
// 回退在途
pub async fn rollback_transit(&self, account_id: i64, account_type: AccountType, amount: Decimal) -> Result<()>;
// ========== 记账操作 ==========
// 创建分录
pub async fn create_entry(&self, req: CreateEntryRequest) -> Result<LedgerEntry>;
// 获取账户分录
pub async fn get_account_entries(&self, account_id: i64, account_type: AccountType) -> Result<Vec<LedgerEntry>>;
// ========== 科目操作 ==========
// 获取所有科目
pub async fn list_subjects(&self) -> Result<Vec<AccountingSubject>>;
// 初始化预定义科目
pub async fn initialize_subjects(&self) -> Result<()>;
// ========== 校验操作 ==========
// 校验不变量
pub async fn validate_invariant(&self, account_id: i64, account_type: AccountType) -> Result<()>;
}
```
## 七、复式记账
### 7.1 记账原则
1. **借贷必相等**:每笔分录的借方金额总和必须等于贷方金额总和
2. **有借必有贷**:每笔分录至少包含一个借方和一个贷方
3. **科目对应**:资产/费用借增贷减,负债/收入贷增借减
### 7.2 记账示例
**存款入账**
```
借: 银行存款 1002 1000.00
贷: 客户存款 2001 1000.00
```
**转账出金**
```
借: 客户存款 2001 500.00
贷: 银行存款 1002 500.00
```
**收取手续费**
```
借: 客户存款 2001 10.00
贷: 手续费收入 3001 10.00
```
### 7.3 分录验证
```rust
impl CreateEntryRequest {
pub fn validate_balance(&self) -> Result<(), (Decimal, Decimal)> {
let mut total_debit = Decimal::ZERO;
let mut total_credit = Decimal::ZERO;
for line in &self.lines {
match line.direction {
Direction::Debit => total_debit += line.amount,
Direction::Credit => total_credit += line.amount,
}
}
if total_debit == total_credit {
Ok(())
} else {
Err((total_debit, total_credit))
}
}
}
```
## 八、API 接口
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /api/v1/ledger/subjects | 获取会计科目列表 |
| GET | /api/v1/ledger/entries/:id | 获取分录详情 |
| GET | /api/v1/ledger/accounts/:id/entries | 获取账户分录列表 |
## 九、数据库表结构
### 9.1 account_balance 表
```sql
CREATE TABLE account_balance (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
account_id BIGINT NOT NULL,
account_type VARCHAR(32) NOT NULL,
-- 三科目余额
personal_balance DECIMAL(20, 2) DEFAULT 0.00,
labor_balance DECIMAL(20, 2) DEFAULT 0.00,
frozen_balance DECIMAL(20, 2) DEFAULT 0.00,
-- 银行对照
bank_balance DECIMAL(20, 2) DEFAULT 0.00,
-- 在途管理
transit_amount DECIMAL(20, 2) DEFAULT 0.00,
-- 兼容字段
system_balance DECIMAL(20, 2) DEFAULT 0.00,
available_balance DECIMAL(20, 2) DEFAULT 0.00,
frozen_amount DECIMAL(20, 2) DEFAULT 0.00,
version INT DEFAULT 0,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE INDEX idx_account (account_id, account_type)
);
```
### 9.2 ledger_entry 表
```sql
CREATE TABLE ledger_entry (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
entry_no VARCHAR(64) NOT NULL UNIQUE,
txn_no VARCHAR(64) NOT NULL,
post_date DATE NOT NULL,
post_time TIMESTAMP NOT NULL,
description TEXT,
status VARCHAR(32) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_txn_no (txn_no),
INDEX idx_post_date (post_date)
);
```
### 9.3 ledger_line 表
```sql
CREATE TABLE ledger_line (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
entry_id BIGINT NOT NULL,
account_id BIGINT NOT NULL,
account_type VARCHAR(32) NOT NULL,
subject_code VARCHAR(32) NOT NULL,
direction VARCHAR(16) NOT NULL,
amount DECIMAL(20, 2) NOT NULL,
FOREIGN KEY (entry_id) REFERENCES ledger_entry(id),
INDEX idx_account (account_id, account_type),
INDEX idx_subject (subject_code)
);
```
## 十、三账校验
### 10.1 校验公式
```
总账余额 = 银行账余额 + 在途净额
即: ledger_total = bank_balance + transit_net
```
### 10.2 校验结果
```rust
pub struct ThreeAccountResult {
pub bank_balance: Decimal, // 银行账余额
pub transit_net: Decimal, // 在途净额
pub ledger_total: Decimal, // 总账余额
pub is_balanced: bool, // 是否平衡
pub difference: Decimal, // 差异金额
}
```
### 10.3 不平衡处理
1. **记录差异**:生成差异报告
2. **人工审核**:提交人工对账
3. **自动调整**:小额差异自动调平
4. **告警通知**:大额差异触发告警