完成LSFX Mock第二期稳定随机命中后端实施

This commit is contained in:
wkc
2026-03-22 11:48:22 +08:00
parent 4e4af5d9fb
commit cc209f04e2
12 changed files with 1131 additions and 6 deletions

View File

@@ -164,6 +164,35 @@ def _build_sample_context(
}
def _build_phase2_subjects(
log_id: int,
staff_id_card: Optional[str] = None,
family_id_cards: Optional[List[str]] = None,
) -> Dict[str, str]:
identity_scope = resolve_identity_scope(log_id)
fallback_staff = identity_scope["staff"]["id_card"]
fallback_family = identity_scope["family"]["id_card"]
primary_subject = staff_id_card or fallback_staff
family_pool = [
card
for card in (family_id_cards or [])
if card and card != primary_subject
]
secondary_subject = (
family_pool[0]
if family_pool
else (fallback_family if fallback_family != primary_subject else primary_subject)
)
tertiary_subject = family_pool[1] if len(family_pool) > 1 else secondary_subject
return {
"primary": primary_subject,
"secondary": secondary_subject,
"tertiary": tertiary_subject,
}
def build_house_or_car_samples(group_id: int, log_id: int, **kwargs) -> List[Dict]:
context = _build_sample_context(log_id, **kwargs)
return [
@@ -559,6 +588,223 @@ def build_withdraw_cnt_samples(group_id: int, log_id: int, **kwargs) -> List[Dic
]
def build_low_income_relative_large_transaction_samples(
group_id: int,
log_id: int,
**kwargs,
) -> List[Dict]:
context = _build_sample_context(log_id, **kwargs)
subjects = _build_phase2_subjects(
log_id,
staff_id_card=kwargs.get("staff_id_card"),
family_id_cards=kwargs.get("family_id_cards"),
)
return [
_build_statement(
group_id,
log_id,
trx_datetime=REFERENCE_NOW - timedelta(days=18),
cret_no=subjects["secondary"],
customer_name="兰溪惠民互助协会",
user_memo="亲属大额转入",
cash_type="对私转账",
cr_amount=68000.0,
le_name=context["le_name"],
account_mask_no=context["account_no"],
customer_account_mask_no="6222024888800001",
),
_build_statement(
group_id,
log_id,
trx_datetime=REFERENCE_NOW - timedelta(days=9),
cret_no=subjects["secondary"],
customer_name="兰溪惠民互助协会",
user_memo="亲属经营补贴",
cash_type="对私转账",
cr_amount=52000.0,
le_name=context["le_name"],
account_mask_no=context["account_no"],
customer_account_mask_no="6222024888800001",
),
]
def build_multi_party_gambling_transfer_samples(
group_id: int,
log_id: int,
**kwargs,
) -> List[Dict]:
context = _build_sample_context(log_id, **kwargs)
subjects = _build_phase2_subjects(
log_id,
staff_id_card=kwargs.get("staff_id_card"),
family_id_cards=kwargs.get("family_id_cards"),
)
transfer_specs = [
("欢乐游戏科技有限公司", 3888.0),
("星彩娱乐网络科技有限公司", 4288.0),
("极速竞技服务有限公司", 4688.0),
]
return [
_build_statement(
group_id,
log_id,
trx_datetime=datetime(2026, 3, 11, 10 + index, 0, 0),
cret_no=subjects["primary"],
customer_name=customer_name,
user_memo="手机银行转账",
cash_type="对私转账",
dr_amount=dr_amount,
le_name=context["le_name"],
account_mask_no=context["account_no"],
customer_account_mask_no=f"62220247777000{index + 1}",
)
for index, (customer_name, dr_amount) in enumerate(transfer_specs)
]
def build_monthly_fixed_income_samples(group_id: int, log_id: int, **kwargs) -> List[Dict]:
context = _build_sample_context(log_id, **kwargs)
subjects = _build_phase2_subjects(
log_id,
staff_id_card=kwargs.get("staff_id_card"),
family_id_cards=kwargs.get("family_id_cards"),
)
income_months = [
datetime(2025, 12, 5, 9, 0, 0),
datetime(2026, 1, 5, 9, 0, 0),
datetime(2026, 2, 5, 9, 0, 0),
datetime(2026, 3, 5, 9, 0, 0),
]
return [
_build_statement(
group_id,
log_id,
trx_datetime=trx_datetime,
cret_no=subjects["primary"],
customer_name="兰溪远航信息服务有限公司",
user_memo="月度稳定兼职收入",
cash_type="对私转账",
cr_amount=7200.0,
le_name=context["le_name"],
account_mask_no=context["account_no"],
customer_account_mask_no="6222024666600101",
)
for trx_datetime in income_months
]
def build_fixed_counterparty_transfer_samples(
group_id: int,
log_id: int,
**kwargs,
) -> List[Dict]:
context = _build_sample_context(log_id, **kwargs)
subjects = _build_phase2_subjects(
log_id,
staff_id_card=kwargs.get("staff_id_card"),
family_id_cards=kwargs.get("family_id_cards"),
)
quarter_dates = [
datetime(2025, 4, 8, 9, 0, 0),
datetime(2025, 7, 8, 9, 0, 0),
datetime(2025, 10, 8, 9, 0, 0),
datetime(2026, 1, 8, 9, 0, 0),
]
return [
_build_statement(
group_id,
log_id,
trx_datetime=trx_datetime,
cret_no=subjects["secondary"],
customer_name="兰溪零工服务有限公司",
user_memo="季度稳定兼职收入",
cash_type="对私转账",
cr_amount=4200.0,
le_name=context["le_name"],
account_mask_no=context["account_no"],
customer_account_mask_no="6222024666600201",
)
for trx_datetime in quarter_dates
]
def build_salary_quick_transfer_samples(group_id: int, log_id: int, **kwargs) -> List[Dict]:
context = _build_sample_context(log_id, **kwargs)
subjects = _build_phase2_subjects(
log_id,
staff_id_card=kwargs.get("staff_id_card"),
family_id_cards=kwargs.get("family_id_cards"),
)
salary_time = datetime(2026, 3, 14, 9, 0, 0)
return [
_build_statement(
group_id,
log_id,
trx_datetime=salary_time,
cret_no=subjects["primary"],
customer_name="浙江兰溪农村商业银行股份有限公司",
user_memo="工资入账",
cash_type="工资代发",
cr_amount=12000.0,
le_name=context["le_name"],
account_mask_no=context["account_no"],
customer_account_mask_no="6222024666600301",
),
_build_statement(
group_id,
log_id,
trx_datetime=salary_time + timedelta(hours=6),
cret_no=subjects["primary"],
customer_name="张某某",
user_memo="工资到账后快速转出",
cash_type="对私转账",
dr_amount=10800.0,
le_name=context["le_name"],
account_mask_no=context["account_no"],
customer_account_mask_no="6222024666600302",
),
]
def build_salary_unused_samples(group_id: int, log_id: int, **kwargs) -> List[Dict]:
context = _build_sample_context(log_id, **kwargs)
subjects = _build_phase2_subjects(
log_id,
staff_id_card=kwargs.get("staff_id_card"),
family_id_cards=kwargs.get("family_id_cards"),
)
salary_time = datetime(2026, 2, 10, 9, 0, 0)
return [
_build_statement(
group_id,
log_id,
trx_datetime=salary_time,
cret_no=subjects["secondary"],
customer_name="浙江兰溪农村商业银行股份有限公司",
user_memo="工资入账",
cash_type="工资代发",
cr_amount=9800.0,
le_name=context["le_name"],
account_mask_no=context["account_no"],
customer_account_mask_no="6222024666600401",
),
_build_statement(
group_id,
log_id,
trx_datetime=salary_time + timedelta(days=5),
cret_no=subjects["secondary"],
customer_name="兰溪住房公积金中心",
user_memo="代扣公积金",
cash_type="代扣支出",
dr_amount=500.0,
le_name=context["le_name"],
account_mask_no=context["account_no"],
customer_account_mask_no="6222024666600402",
),
]
LARGE_TRANSACTION_BUILDERS = {
"HOUSE_OR_CAR_EXPENSE": build_house_or_car_samples,
"TAX_EXPENSE": build_tax_samples,
@@ -581,6 +827,15 @@ PHASE1_RULE_BUILDERS = {
"WITHDRAW_CNT": build_withdraw_cnt_samples,
}
PHASE2_STATEMENT_RULE_BUILDERS = {
"LOW_INCOME_RELATIVE_LARGE_TRANSACTION": build_low_income_relative_large_transaction_samples,
"MULTI_PARTY_GAMBLING_TRANSFER": build_multi_party_gambling_transfer_samples,
"MONTHLY_FIXED_INCOME": build_monthly_fixed_income_samples,
"FIXED_COUNTERPARTY_TRANSFER": build_fixed_counterparty_transfer_samples,
"SALARY_QUICK_TRANSFER": build_salary_quick_transfer_samples,
"SALARY_UNUSED": build_salary_unused_samples,
}
def build_seed_statements_for_rule_plan(
group_id: int,
@@ -600,6 +855,11 @@ def build_seed_statements_for_rule_plan(
if builder is not None:
statements.extend(builder(group_id, log_id, **kwargs))
for rule_code in rule_plan.get("phase2_statement_hit_rules", []):
builder = PHASE2_STATEMENT_RULE_BUILDERS.get(rule_code)
if builder is not None:
statements.extend(builder(group_id, log_id, **kwargs))
return statements