修复Mock流水按数据库员工及亲属绑定身份证
This commit is contained in:
@@ -14,11 +14,21 @@ from config.settings import settings
|
||||
from routers.api import file_service
|
||||
|
||||
|
||||
class FakeStaffIdentityRepository:
|
||||
def select_random_staff_with_families(self):
|
||||
return {
|
||||
"staff_name": "测试员工",
|
||||
"staff_id_card": "320101199001010030",
|
||||
"family_id_cards": ["320101199201010051"],
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_file_service_state():
|
||||
"""避免 file_service 单例状态影响测试顺序。"""
|
||||
file_service.file_records.clear()
|
||||
file_service.log_counter = settings.INITIAL_LOG_ID
|
||||
file_service.staff_identity_repository = FakeStaffIdentityRepository()
|
||||
yield
|
||||
file_service.file_records.clear()
|
||||
file_service.log_counter = settings.INITIAL_LOG_ID
|
||||
|
||||
@@ -11,9 +11,18 @@ from fastapi.datastructures import UploadFile
|
||||
from services.file_service import FileService
|
||||
|
||||
|
||||
class FakeStaffIdentityRepository:
|
||||
def select_random_staff_with_families(self):
|
||||
return {
|
||||
"staff_name": "数据库员工",
|
||||
"staff_id_card": "320101199001010030",
|
||||
"family_id_cards": ["320101199201010051", "320101199301010052"],
|
||||
}
|
||||
|
||||
|
||||
def test_upload_file_primary_binding_response(monkeypatch):
|
||||
"""同一 logId 的主绑定必须稳定且只保留一组主体/账号信息。"""
|
||||
service = FileService()
|
||||
service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
|
||||
|
||||
monkeypatch.setattr(
|
||||
service,
|
||||
@@ -42,7 +51,7 @@ def test_upload_file_primary_binding_response(monkeypatch):
|
||||
|
||||
def test_upload_file_total_records_range(monkeypatch):
|
||||
"""上传文件返回的流水条数必须限制在 150-200 条。"""
|
||||
service = FileService()
|
||||
service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
|
||||
|
||||
monkeypatch.setattr(
|
||||
service,
|
||||
@@ -69,7 +78,7 @@ def test_upload_file_total_records_range(monkeypatch):
|
||||
|
||||
def test_upload_file_then_upload_status_reads_same_record(monkeypatch):
|
||||
"""上传后再查状态时,上传状态接口必须读取同一条真实记录。"""
|
||||
service = FileService()
|
||||
service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
|
||||
|
||||
monkeypatch.setattr(
|
||||
service,
|
||||
@@ -108,8 +117,8 @@ def test_upload_file_then_upload_status_reads_same_record(monkeypatch):
|
||||
|
||||
|
||||
def test_fetch_inner_flow_persists_primary_binding_record(monkeypatch):
|
||||
"""拉取行内流水必须创建并保存绑定记录。"""
|
||||
service = FileService()
|
||||
"""拉取行内流水必须创建并保存数据库员工及亲属身份。"""
|
||||
service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
|
||||
|
||||
monkeypatch.setattr(
|
||||
service,
|
||||
@@ -137,6 +146,9 @@ def test_fetch_inner_flow_persists_primary_binding_record(monkeypatch):
|
||||
assert record.parsing is False
|
||||
assert record.primary_enterprise_name
|
||||
assert record.primary_account_no
|
||||
assert record.staff_name == "数据库员工"
|
||||
assert record.staff_id_card == "320101199001010030"
|
||||
assert record.family_id_cards == ["320101199201010051", "320101199301010052"]
|
||||
assert record.primary_enterprise_name == "行内主体"
|
||||
assert record.primary_account_no == "6210987654321098"
|
||||
assert record.enterprise_name_list == ["行内主体"]
|
||||
|
||||
@@ -12,6 +12,15 @@ from services.statement_rule_samples import (
|
||||
)
|
||||
|
||||
|
||||
class FakeStaffIdentityRepository:
|
||||
def select_random_staff_with_families(self):
|
||||
return {
|
||||
"staff_name": "数据库员工",
|
||||
"staff_id_card": "320101199001010030",
|
||||
"family_id_cards": ["320101199201010051", "320101199301010052"],
|
||||
}
|
||||
|
||||
|
||||
def test_generate_statements_should_include_seeded_samples_before_noise():
|
||||
"""生成流水时必须先混入固定命中样本,而不是纯随机噪声。"""
|
||||
service = StatementService()
|
||||
@@ -89,6 +98,30 @@ def test_generate_statements_should_fill_noise_up_to_requested_count():
|
||||
assert len(statements) == 80
|
||||
|
||||
|
||||
def test_generate_statements_should_stay_within_single_employee_scope_per_log_id():
|
||||
"""同一 logId 的流水只能落在 FileRecord 绑定的员工及亲属身份证内。"""
|
||||
file_service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
|
||||
service = StatementService(file_service=file_service)
|
||||
response = file_service.fetch_inner_flow(
|
||||
{
|
||||
"groupId": 1001,
|
||||
"customerNo": "customer_scope",
|
||||
"dataChannelCode": "test",
|
||||
"requestDateId": 20240101,
|
||||
"dataStartDateId": 20240101,
|
||||
"dataEndDateId": 20240131,
|
||||
"uploadUserId": 902001,
|
||||
}
|
||||
)
|
||||
log_id = response["data"][0]
|
||||
record = file_service.file_records[log_id]
|
||||
allowed_id_cards = {record.staff_id_card, *record.family_id_cards}
|
||||
|
||||
statements = service._generate_statements(group_id=1000, log_id=log_id, count=1600)
|
||||
|
||||
assert {item["cretNo"] for item in statements}.issubset(allowed_id_cards)
|
||||
|
||||
|
||||
def test_generate_statements_should_only_use_recognizable_identity_cards():
|
||||
"""命中样本和随机噪声都只能使用现库可识别的身份证号。"""
|
||||
service = StatementService()
|
||||
@@ -121,7 +154,7 @@ def test_get_bank_statement_should_keep_same_cached_result_for_same_log_id():
|
||||
|
||||
def test_get_bank_statement_uses_primary_binding_from_file_service(monkeypatch):
|
||||
"""同一 logId 的流水记录必须复用 FileService 中的主体与账号绑定。"""
|
||||
file_service = FileService()
|
||||
file_service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
|
||||
statement_service = StatementService(file_service=file_service)
|
||||
|
||||
monkeypatch.setattr(
|
||||
@@ -161,7 +194,7 @@ def test_get_bank_statement_uses_primary_binding_from_file_service(monkeypatch):
|
||||
|
||||
def test_get_bank_statement_contains_large_transaction_hit_samples(monkeypatch):
|
||||
"""流水 Mock 首次生成时必须稳定包含可命中大额交易规则的样本簇。"""
|
||||
file_service = FileService()
|
||||
file_service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
|
||||
statement_service = StatementService(file_service=file_service)
|
||||
|
||||
monkeypatch.setattr(
|
||||
@@ -182,6 +215,9 @@ def test_get_bank_statement_contains_large_transaction_hit_samples(monkeypatch):
|
||||
}
|
||||
)
|
||||
log_id = response["data"][0]
|
||||
record = file_service.file_records[log_id]
|
||||
staff_id_card = record.staff_id_card
|
||||
family_id_card = record.family_id_cards[0]
|
||||
|
||||
statement_response = statement_service.get_bank_statement(
|
||||
{
|
||||
@@ -195,12 +231,7 @@ def test_get_bank_statement_contains_large_transaction_hit_samples(monkeypatch):
|
||||
|
||||
assert statements
|
||||
assert any(
|
||||
item["cretNo"] in {
|
||||
"330101198801010011",
|
||||
"330101199001010022",
|
||||
"330101198802020033",
|
||||
"330101199202020044",
|
||||
}
|
||||
item["cretNo"] in {staff_id_card, family_id_card}
|
||||
for item in statements
|
||||
)
|
||||
assert any("房产首付款" in item["userMemo"] for item in statements)
|
||||
@@ -212,7 +243,7 @@ def test_get_bank_statement_contains_large_transaction_hit_samples(monkeypatch):
|
||||
|
||||
for item in statements:
|
||||
if (
|
||||
item["cretNo"] == "330101198802020033"
|
||||
item["cretNo"] == staff_id_card
|
||||
and item["customerName"] == "浙江远望贸易有限公司"
|
||||
and item["crAmount"] > 0
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user