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

180 lines
5.2 KiB
Rust

//! 充值流程集成测试
use chrono::Utc;
use rust_decimal_macros::dec;
use rust_decimal::Decimal;
use rustjr::domain::ledger::entity::AccountBalance;
use rustjr::domain::account::AccountType;
use rustjr::infrastructure::bank_integration::{BankClient, mock_bank::MockBankClient};
// ==================== 测试辅助 ====================
fn create_balance(personal: rust_decimal::Decimal, labor: rust_decimal::Decimal) -> AccountBalance {
AccountBalance {
id: 1,
account_id: 1001,
account_type: AccountType::Virtual,
personal_balance: personal,
labor_balance: labor,
frozen_balance: Decimal::ZERO,
bank_balance: personal + labor,
transit_amount: Decimal::ZERO,
system_balance: personal + labor,
available_balance: personal + labor,
frozen_amount: Decimal::ZERO,
version: 1,
updated_at: Utc::now(),
}
}
// ==================== 个人余额充值测试 ====================
#[test]
fn test_personal_deposit() {
let mut balance = create_balance(dec!(1000.00), dec!(500.00));
// 模拟外部充值(家属汇款)
balance.add_personal(dec!(2000.00));
assert_eq!(balance.personal_balance, dec!(3000.00));
assert_eq!(balance.labor_balance, dec!(500.00));
assert_eq!(balance.bank_balance, dec!(3500.00));
assert!(balance.validate_invariant().is_ok());
}
#[test]
fn test_multiple_deposits() {
let mut balance = create_balance(dec!(0.00), dec!(0.00));
// 多次充值
balance.add_personal(dec!(100.00));
balance.add_personal(dec!(200.00));
balance.add_personal(dec!(300.00));
assert_eq!(balance.personal_balance, dec!(600.00));
assert_eq!(balance.bank_balance, dec!(600.00));
assert!(balance.validate_invariant().is_ok());
}
// ==================== 劳动报酬发放测试 ====================
#[test]
fn test_labor_deposit() {
let mut balance = create_balance(dec!(1000.00), dec!(0.00));
// 劳动报酬发放
balance.add_labor(dec!(500.00));
assert_eq!(balance.personal_balance, dec!(1000.00));
assert_eq!(balance.labor_balance, dec!(500.00));
assert_eq!(balance.bank_balance, dec!(1500.00));
assert!(balance.validate_invariant().is_ok());
}
#[test]
fn test_mixed_deposits() {
let mut balance = create_balance(dec!(0.00), dec!(0.00));
// 先充值个人
balance.add_personal(dec!(1000.00));
assert!(balance.validate_invariant().is_ok());
// 再发放劳动报酬
balance.add_labor(dec!(500.00));
assert!(balance.validate_invariant().is_ok());
// 再充值个人
balance.add_personal(dec!(200.00));
assert!(balance.validate_invariant().is_ok());
assert_eq!(balance.personal_balance, dec!(1200.00));
assert_eq!(balance.labor_balance, dec!(500.00));
assert_eq!(balance.bank_balance, dec!(1700.00));
}
// ==================== 外部入账模拟测试 ====================
#[tokio::test]
async fn test_external_deposit_via_mock_bank() {
let client = MockBankClient::new();
client.create_account("PRISON001", "监狱账户", dec!(100000.00)).unwrap();
// 模拟外部入账
let bank_ref = client.simulate_external_deposit(
"PRISON001",
"FAMILY001",
"家属张三",
dec!(2000.00),
Some("给罪犯XXX的充值".to_string()),
).unwrap();
assert!(bank_ref.starts_with("MOCK"));
// 验证余额
let balance = client.query_balance("PRISON001").await.unwrap();
assert_eq!(balance.balance, dec!(102000.00));
}
#[tokio::test]
async fn test_external_deposit_in_statements() {
let client = MockBankClient::new();
client.create_account("PRISON001", "监狱账户", dec!(100000.00)).unwrap();
// 模拟外部入账
client.simulate_external_deposit(
"PRISON001",
"FAMILY001",
"家属张三",
dec!(2000.00),
Some("家属汇款".to_string()),
).unwrap();
// 查询流水
let today = Utc::now().date_naive();
let statements = client.query_statements("PRISON001", today, today).await.unwrap();
assert!(!statements.is_empty());
// 找到入账流水
let deposit = statements.iter().find(|s| s.direction == "in").unwrap();
assert_eq!(deposit.amount, dec!(2000.00));
}
// ==================== 边界条件测试 ====================
#[test]
fn test_zero_deposit() {
let mut balance = create_balance(dec!(1000.00), dec!(500.00));
let original_bank = balance.bank_balance;
balance.add_personal(dec!(0.00));
assert_eq!(balance.bank_balance, original_bank);
assert!(balance.validate_invariant().is_ok());
}
#[test]
fn test_large_deposit() {
let mut balance = create_balance(dec!(0.00), dec!(0.00));
balance.add_personal(dec!(999999999.99));
assert_eq!(balance.personal_balance, dec!(999999999.99));
assert_eq!(balance.bank_balance, dec!(999999999.99));
assert!(balance.validate_invariant().is_ok());
}
#[test]
fn test_decimal_precision_deposit() {
let mut balance = create_balance(dec!(0.00), dec!(0.00));
balance.add_personal(dec!(0.01));
balance.add_personal(dec!(0.01));
balance.add_personal(dec!(0.01));
assert_eq!(balance.personal_balance, dec!(0.03));
assert!(balance.validate_invariant().is_ok());
}