tangweijie d7f81893c5 Initial commit: 完整的 Rust 账户管理系统
- 实现账户管理改进设计文档中的所有核心功能
- 三科目余额管理 (个人余额、劳动报酬、冻结余额)
- 交易状态机 (created → pending → bank_submitted → success/failed/timeout → reversed)
- 三键幂等体系 (JZTxId/BankTxId/SourceKey)
- 优先级扣款规则 (先个人后劳动)
- 在途资金管理 (可用→在途→结转/回退)
- 三账对账闭环 (总账 = 银行账 + 在途净额)
- 补偿服务域 (超时检测、重试、死信队列)
- 虚拟银行模拟器用于业务测试
- 完整的集成测试套件 (133 个测试全部通过)
- Docker 容器化部署配置
- 前端 Vue3 + TypeScript 项目结构
2026-01-05 17:56:01 +08:00

189 lines
5.0 KiB
Rust

//! 账务服务单元测试
//!
//! 测试 LedgerService 的核心功能
// 由于 LedgerService 依赖仓储,这里主要测试账务逻辑
// 实际的服务测试在集成测试中进行
use rust_decimal_macros::dec;
use rustjr::domain::ledger::entity::ThreeAccountResult;
// ==================== 三账校验结果测试 ====================
#[test]
fn test_three_account_balanced() {
let result = ThreeAccountResult {
bank_balance: dec!(100000.00),
transit_net: dec!(5000.00),
ledger_total: dec!(95000.00),
is_balanced: true,
difference: dec!(0.00),
};
assert!(result.is_balanced);
assert_eq!(result.difference, dec!(0.00));
// 验证: ledger + transit = bank
assert_eq!(
result.ledger_total + result.transit_net,
result.bank_balance
);
}
#[test]
fn test_three_account_short() {
// 短款:银行 < 总账 + 在途
let result = ThreeAccountResult {
bank_balance: dec!(100000.00),
transit_net: dec!(5000.00),
ledger_total: dec!(100000.00),
is_balanced: false,
difference: dec!(-5000.00), // 银行少 5000
};
assert!(!result.is_balanced);
assert!(result.difference < dec!(0.00));
}
#[test]
fn test_three_account_long() {
// 长款:银行 > 总账 + 在途
let result = ThreeAccountResult {
bank_balance: dec!(110000.00),
transit_net: dec!(5000.00),
ledger_total: dec!(100000.00),
is_balanced: false,
difference: dec!(5000.00), // 银行多 5000
};
assert!(!result.is_balanced);
assert!(result.difference > dec!(0.00));
}
// ==================== 扣款优先级逻辑测试 ====================
#[test]
fn test_deduction_priority_logic() {
// 测试扣款优先级计算逻辑
let personal = dec!(300.00);
let labor = dec!(500.00);
let to_deduct = dec!(600.00);
// 先扣个人
let from_personal = personal.min(to_deduct);
let remaining = to_deduct - from_personal;
// 再扣劳动
let from_labor = labor.min(remaining);
assert_eq!(from_personal, dec!(300.00));
assert_eq!(from_labor, dec!(300.00));
assert_eq!(from_personal + from_labor, to_deduct);
}
#[test]
fn test_deduction_personal_sufficient() {
let personal = dec!(1000.00);
let labor = dec!(500.00);
let to_deduct = dec!(800.00);
let from_personal = personal.min(to_deduct);
let remaining = to_deduct - from_personal;
let from_labor = labor.min(remaining);
assert_eq!(from_personal, dec!(800.00));
assert_eq!(from_labor, dec!(0.00));
}
#[test]
fn test_deduction_total_insufficient() {
let personal = dec!(300.00);
let labor = dec!(200.00);
let to_deduct = dec!(600.00);
let available = personal + labor;
// 余额不足
assert!(available < to_deduct);
}
// ==================== 在途计算逻辑测试 ====================
#[test]
fn test_transit_flow_calculation() {
// 模拟在途流转计算
let initial_personal = dec!(1000.00);
let initial_bank = dec!(1000.00);
let transit_amount = dec!(300.00);
// 1. 扣款(可用 -> 在途)
let after_deduct_personal = initial_personal - transit_amount;
let after_deduct_bank = initial_bank; // 银行余额不变
let in_transit = transit_amount;
assert_eq!(after_deduct_personal, dec!(700.00));
assert_eq!(in_transit, dec!(300.00));
// 2. 结转(银行确认扣款)
let final_bank = after_deduct_bank - transit_amount;
let final_transit = in_transit - transit_amount;
assert_eq!(final_bank, dec!(700.00));
assert_eq!(final_transit, dec!(0.00));
}
#[test]
fn test_transit_rollback_calculation() {
// 模拟在途回退计算
let after_deduct_personal = dec!(700.00);
let initial_bank = dec!(1000.00);
let in_transit = dec!(300.00);
// 回退(银行失败)
let final_personal = after_deduct_personal + in_transit;
let final_bank = initial_bank; // 银行余额不变
let final_transit = dec!(0.00);
assert_eq!(final_personal, dec!(1000.00));
assert_eq!(final_bank, dec!(1000.00));
assert_eq!(final_transit, dec!(0.00));
}
// ==================== 冻结逻辑测试 ====================
#[test]
fn test_freeze_from_available() {
// 冻结只能从可用余额中冻结
let personal = dec!(1000.00);
let labor = dec!(500.00);
let available = personal + labor;
let to_freeze = dec!(800.00);
assert!(available >= to_freeze);
// 冻结后
let new_personal = personal - to_freeze;
let new_frozen = to_freeze;
assert_eq!(new_personal, dec!(200.00));
assert_eq!(new_frozen, dec!(800.00));
}
#[test]
fn test_frozen_cannot_be_deducted() {
// 冻结金额不能被扣款
let personal = dec!(200.00);
let labor = dec!(500.00);
let frozen = dec!(800.00);
let available = personal + labor; // 不含冻结
let to_deduct = dec!(1000.00);
// 余额不足(虽然总额够,但可用余额不够)
assert!(available < to_deduct);
}