补充异常账户规则样本生成器
This commit is contained in:
@@ -811,6 +811,117 @@ def build_salary_unused_samples(group_id: int, log_id: int, **kwargs) -> List[Di
|
||||
]
|
||||
|
||||
|
||||
def build_sudden_account_closure_samples(
|
||||
group_id: int,
|
||||
log_id: int,
|
||||
*,
|
||||
account_fact: Dict,
|
||||
le_name: str = "模型测试主体",
|
||||
) -> List[Dict]:
|
||||
invalid_date = datetime.strptime(account_fact["invalid_date"], "%Y-%m-%d")
|
||||
owner_id_card = account_fact["owner_id_card"]
|
||||
account_no = account_fact["account_no"]
|
||||
account_name = account_fact["account_name"]
|
||||
|
||||
return [
|
||||
_build_statement(
|
||||
group_id,
|
||||
log_id,
|
||||
trx_datetime=invalid_date - timedelta(days=30, hours=-1),
|
||||
cret_no=owner_id_card,
|
||||
customer_name="杭州临时往来款账户",
|
||||
user_memo=f"{account_name}销户前资金回笼",
|
||||
cash_type="对私转账",
|
||||
cr_amount=88000.0,
|
||||
le_name=le_name,
|
||||
account_mask_no=account_no,
|
||||
customer_account_mask_no="6222024666610001",
|
||||
),
|
||||
_build_statement(
|
||||
group_id,
|
||||
log_id,
|
||||
trx_datetime=invalid_date - timedelta(days=12, hours=2),
|
||||
cret_no=owner_id_card,
|
||||
customer_name="杭州消费支付商户",
|
||||
user_memo=f"{account_name}销户前集中支出",
|
||||
cash_type="快捷支付",
|
||||
dr_amount=62000.0,
|
||||
le_name=le_name,
|
||||
account_mask_no=account_no,
|
||||
customer_account_mask_no="6222024666610002",
|
||||
),
|
||||
_build_statement(
|
||||
group_id,
|
||||
log_id,
|
||||
trx_datetime=invalid_date - timedelta(days=1, hours=3),
|
||||
cret_no=owner_id_card,
|
||||
customer_name="浙江异常账户清理专户",
|
||||
user_memo=f"{account_name}异常账户销户前转出",
|
||||
cash_type="对私转账",
|
||||
dr_amount=126000.0,
|
||||
le_name=le_name,
|
||||
account_mask_no=account_no,
|
||||
customer_account_mask_no="6222024666610003",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def build_dormant_account_large_activation_samples(
|
||||
group_id: int,
|
||||
log_id: int,
|
||||
*,
|
||||
account_fact: Dict,
|
||||
le_name: str = "模型测试主体",
|
||||
) -> List[Dict]:
|
||||
effective_date = datetime.strptime(account_fact["effective_date"], "%Y-%m-%d")
|
||||
activation_start = datetime(effective_date.year, effective_date.month, effective_date.day) + timedelta(days=181)
|
||||
owner_id_card = account_fact["owner_id_card"]
|
||||
account_no = account_fact["account_no"]
|
||||
account_name = account_fact["account_name"]
|
||||
|
||||
return [
|
||||
_build_statement(
|
||||
group_id,
|
||||
log_id,
|
||||
trx_datetime=activation_start,
|
||||
cret_no=owner_id_card,
|
||||
customer_name="浙江存量资产回收账户",
|
||||
user_memo=f"{account_name}休眠后异常账户激活入账",
|
||||
cash_type="对公转账",
|
||||
cr_amount=180000.0,
|
||||
le_name=le_name,
|
||||
account_mask_no=account_no,
|
||||
customer_account_mask_no="6222024666620001",
|
||||
),
|
||||
_build_statement(
|
||||
group_id,
|
||||
log_id,
|
||||
trx_datetime=activation_start + timedelta(days=9, hours=2),
|
||||
cret_no=owner_id_card,
|
||||
customer_name="浙江大额往来备付金专户",
|
||||
user_memo=f"{account_name}休眠激活后大额转入",
|
||||
cash_type="对公转账",
|
||||
cr_amount=260000.0,
|
||||
le_name=le_name,
|
||||
account_mask_no=account_no,
|
||||
customer_account_mask_no="6222024666620002",
|
||||
),
|
||||
_build_statement(
|
||||
group_id,
|
||||
log_id,
|
||||
trx_datetime=activation_start + timedelta(days=18, hours=1),
|
||||
cret_no=owner_id_card,
|
||||
customer_name="杭州临时资金调拨账户",
|
||||
user_memo=f"{account_name}休眠账户异常账户激活转出",
|
||||
cash_type="对私转账",
|
||||
dr_amount=120000.0,
|
||||
le_name=le_name,
|
||||
account_mask_no=account_no,
|
||||
customer_account_mask_no="6222024666620003",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
LARGE_TRANSACTION_BUILDERS = {
|
||||
"HOUSE_OR_CAR_EXPENSE": build_house_or_car_samples,
|
||||
"TAX_EXPENSE": build_tax_samples,
|
||||
|
||||
@@ -4,6 +4,7 @@ StatementService 主绑定注入测试
|
||||
|
||||
from collections import Counter, defaultdict
|
||||
|
||||
import services.statement_rule_samples as statement_rule_samples
|
||||
from services.file_service import FileService
|
||||
from services.statement_service import StatementService
|
||||
from services.statement_rule_samples import (
|
||||
@@ -234,6 +235,47 @@ def test_generate_statements_should_follow_rule_hit_plan_from_file_record():
|
||||
assert not any("购汇" in item["userMemo"] for item in statements)
|
||||
|
||||
|
||||
def test_sudden_account_closure_samples_should_stay_within_30_days_before_invalid_date():
|
||||
statements = statement_rule_samples.build_sudden_account_closure_samples(
|
||||
group_id=1000,
|
||||
log_id=20001,
|
||||
account_fact={
|
||||
"account_no": "6222000000000001",
|
||||
"owner_id_card": "320101199001010030",
|
||||
"account_name": "测试员工工资卡",
|
||||
"status": 2,
|
||||
"effective_date": "2024-01-01",
|
||||
"invalid_date": "2026-03-20",
|
||||
},
|
||||
le_name="测试主体",
|
||||
)
|
||||
|
||||
assert statements
|
||||
assert all("6222000000000001" == item["accountMaskNo"] for item in statements)
|
||||
assert all("2026-02-18" <= item["trxDate"][:10] < "2026-03-20" for item in statements)
|
||||
|
||||
|
||||
def test_dormant_account_large_activation_samples_should_exceed_threshold_after_6_months():
|
||||
statements = statement_rule_samples.build_dormant_account_large_activation_samples(
|
||||
group_id=1000,
|
||||
log_id=20001,
|
||||
account_fact={
|
||||
"account_no": "6222000000000002",
|
||||
"owner_id_card": "320101199001010030",
|
||||
"account_name": "测试员工工资卡",
|
||||
"status": 1,
|
||||
"effective_date": "2025-01-01",
|
||||
"invalid_date": None,
|
||||
},
|
||||
le_name="测试主体",
|
||||
)
|
||||
|
||||
assert statements
|
||||
assert min(item["trxDate"][:10] for item in statements) >= "2025-07-01"
|
||||
assert sum(item["drAmount"] + item["crAmount"] for item in statements) >= 500000
|
||||
assert max(item["drAmount"] + item["crAmount"] for item in statements) >= 100000
|
||||
|
||||
|
||||
def test_generate_statements_should_stay_within_single_employee_scope_per_log_id():
|
||||
"""同一 logId 的流水只能落在 FileRecord 绑定的员工及亲属身份证内。"""
|
||||
file_service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
|
||||
|
||||
Reference in New Issue
Block a user