让Mock流水查询复用logId主体账号绑定
This commit is contained in:
@@ -13,7 +13,7 @@ router = APIRouter()
|
|||||||
# 初始化服务实例
|
# 初始化服务实例
|
||||||
token_service = TokenService()
|
token_service = TokenService()
|
||||||
file_service = FileService()
|
file_service = FileService()
|
||||||
statement_service = StatementService()
|
statement_service = StatementService(file_service=file_service)
|
||||||
|
|
||||||
|
|
||||||
def _parse_log_ids(log_ids: str) -> List[int]:
|
def _parse_log_ids(log_ids: str) -> List[int]:
|
||||||
|
|||||||
@@ -67,6 +67,10 @@ class FileService:
|
|||||||
self.file_records: Dict[int, FileRecord] = {} # logId -> FileRecord
|
self.file_records: Dict[int, FileRecord] = {} # logId -> FileRecord
|
||||||
self.log_counter = settings.INITIAL_LOG_ID
|
self.log_counter = settings.INITIAL_LOG_ID
|
||||||
|
|
||||||
|
def get_file_record(self, log_id: int) -> FileRecord:
|
||||||
|
"""按 logId 获取已存在的文件记录。"""
|
||||||
|
return self.file_records.get(log_id)
|
||||||
|
|
||||||
def _infer_bank_name(self, filename: str) -> tuple:
|
def _infer_bank_name(self, filename: str) -> tuple:
|
||||||
"""根据文件名推断银行名称和模板名称"""
|
"""根据文件名推断银行名称和模板名称"""
|
||||||
if "支付宝" in filename or "alipay" in filename.lower():
|
if "支付宝" in filename or "alipay" in filename.lower():
|
||||||
|
|||||||
@@ -13,19 +13,38 @@ logger = logging.getLogger(__name__)
|
|||||||
class StatementService:
|
class StatementService:
|
||||||
"""流水数据服务"""
|
"""流水数据服务"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, file_service=None):
|
||||||
# 缓存:logId -> (statements_list, total_count)
|
# 缓存:logId -> (statements_list, total_count)
|
||||||
self._cache: Dict[int, tuple] = {}
|
self._cache: Dict[int, tuple] = {}
|
||||||
|
self.file_service = file_service
|
||||||
# 配置日志级别为 INFO
|
# 配置日志级别为 INFO
|
||||||
logger.info(f"StatementService initialized with empty cache")
|
logger.info(f"StatementService initialized with empty cache")
|
||||||
|
|
||||||
def _generate_random_statement(self, index: int, group_id: int, log_id: int) -> Dict:
|
def _resolve_primary_binding(self, log_id: int) -> tuple:
|
||||||
|
"""优先从 FileService 读取真实主绑定,不存在时再走 fallback。"""
|
||||||
|
if self.file_service is not None:
|
||||||
|
record = self.file_service.get_file_record(log_id)
|
||||||
|
if record is not None:
|
||||||
|
return record.primary_enterprise_name, record.primary_account_no
|
||||||
|
|
||||||
|
return "张传伟", f"{random.randint(100000000000000, 999999999999999)}"
|
||||||
|
|
||||||
|
def _generate_random_statement(
|
||||||
|
self,
|
||||||
|
index: int,
|
||||||
|
group_id: int,
|
||||||
|
log_id: int,
|
||||||
|
primary_enterprise_name: str,
|
||||||
|
primary_account_no: str,
|
||||||
|
) -> Dict:
|
||||||
"""生成单条随机流水记录
|
"""生成单条随机流水记录
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
index: 流水序号
|
index: 流水序号
|
||||||
group_id: 项目ID
|
group_id: 项目ID
|
||||||
log_id: 文件ID
|
log_id: 文件ID
|
||||||
|
primary_enterprise_name: 本方主体名称
|
||||||
|
primary_account_no: 本方账号
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
单条流水记录字典
|
单条流水记录字典
|
||||||
@@ -75,7 +94,7 @@ class StatementService:
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
"accountId": 0,
|
"accountId": 0,
|
||||||
"accountMaskNo": f"{random.randint(100000000000000, 999999999999999)}",
|
"accountMaskNo": primary_account_no,
|
||||||
"accountingDate": accounting_date,
|
"accountingDate": accounting_date,
|
||||||
"accountingDateId": accounting_date_id,
|
"accountingDateId": accounting_date_id,
|
||||||
"archivingFlag": 0,
|
"archivingFlag": 0,
|
||||||
@@ -104,7 +123,7 @@ class StatementService:
|
|||||||
"groupId": group_id,
|
"groupId": group_id,
|
||||||
"internalFlag": 0,
|
"internalFlag": 0,
|
||||||
"leId": 16308,
|
"leId": 16308,
|
||||||
"leName": "张传伟",
|
"leName": primary_enterprise_name,
|
||||||
"overrideBsId": 0,
|
"overrideBsId": 0,
|
||||||
"paymentMethod": "",
|
"paymentMethod": "",
|
||||||
"sourceCatalogId": 0,
|
"sourceCatalogId": 0,
|
||||||
@@ -137,11 +156,31 @@ class StatementService:
|
|||||||
Returns:
|
Returns:
|
||||||
流水记录列表
|
流水记录列表
|
||||||
"""
|
"""
|
||||||
|
primary_enterprise_name, primary_account_no = self._resolve_primary_binding(log_id)
|
||||||
statements = []
|
statements = []
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
statements.append(self._generate_random_statement(i, group_id, log_id))
|
statements.append(
|
||||||
|
self._generate_random_statement(
|
||||||
|
i,
|
||||||
|
group_id,
|
||||||
|
log_id,
|
||||||
|
primary_enterprise_name,
|
||||||
|
primary_account_no,
|
||||||
|
)
|
||||||
|
)
|
||||||
return statements
|
return statements
|
||||||
|
|
||||||
|
def _apply_primary_binding(
|
||||||
|
self,
|
||||||
|
statements: List[Dict],
|
||||||
|
primary_enterprise_name: str,
|
||||||
|
primary_account_no: str,
|
||||||
|
) -> None:
|
||||||
|
"""将解析出的主绑定统一回填到已有流水记录。"""
|
||||||
|
for statement in statements:
|
||||||
|
statement["leName"] = primary_enterprise_name
|
||||||
|
statement["accountMaskNo"] = primary_account_no
|
||||||
|
|
||||||
def get_bank_statement(self, request: Union[Dict, object]) -> Dict:
|
def get_bank_statement(self, request: Union[Dict, object]) -> Dict:
|
||||||
"""获取银行流水列表
|
"""获取银行流水列表
|
||||||
|
|
||||||
@@ -174,6 +213,12 @@ class StatementService:
|
|||||||
|
|
||||||
# 从缓存获取数据
|
# 从缓存获取数据
|
||||||
all_statements, total_count = self._cache[log_id]
|
all_statements, total_count = self._cache[log_id]
|
||||||
|
primary_enterprise_name, primary_account_no = self._resolve_primary_binding(log_id)
|
||||||
|
self._apply_primary_binding(
|
||||||
|
all_statements,
|
||||||
|
primary_enterprise_name,
|
||||||
|
primary_account_no,
|
||||||
|
)
|
||||||
|
|
||||||
# 模拟分页
|
# 模拟分页
|
||||||
start = (page_now - 1) * page_size
|
start = (page_now - 1) * page_size
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
集成测试 - 完整的接口调用流程测试
|
集成测试 - 完整的接口调用流程测试
|
||||||
"""
|
"""
|
||||||
import pytest
|
import pytest
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
def test_complete_workflow(client):
|
def test_complete_workflow(client):
|
||||||
@@ -123,3 +122,51 @@ def test_pagination(client):
|
|||||||
if page1["data"]["totalCount"] > 1:
|
if page1["data"]["totalCount"] > 1:
|
||||||
assert len(page1["data"]["bankStatementList"]) == 1
|
assert len(page1["data"]["bankStatementList"]) == 1
|
||||||
assert len(page2["data"]["bankStatementList"]) >= 0
|
assert len(page2["data"]["bankStatementList"]) >= 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_upload_status_and_bank_statement_share_same_primary_binding(client, monkeypatch):
|
||||||
|
"""上传状态接口与银行流水接口对同一 logId 必须使用同一组主体/账号绑定。"""
|
||||||
|
from routers.api import file_service
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
file_service,
|
||||||
|
"_generate_primary_binding",
|
||||||
|
lambda: ("链路主体", "6222555566667777"),
|
||||||
|
)
|
||||||
|
|
||||||
|
fetch_response = client.post(
|
||||||
|
"/watson/api/project/getJZFileOrZjrcuFile",
|
||||||
|
data={
|
||||||
|
"groupId": 1001,
|
||||||
|
"customerNo": "customer_002",
|
||||||
|
"dataChannelCode": "channel_code",
|
||||||
|
"requestDateId": 20240101,
|
||||||
|
"dataStartDateId": 20240101,
|
||||||
|
"dataEndDateId": 20240131,
|
||||||
|
"uploadUserId": 902001,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert fetch_response.status_code == 200
|
||||||
|
log_id = fetch_response.json()["data"][0]
|
||||||
|
|
||||||
|
status_response = client.get(f"/watson/api/project/bs/upload?groupId=1001&logId={log_id}")
|
||||||
|
assert status_response.status_code == 200
|
||||||
|
status_log = status_response.json()["data"]["logs"][0]
|
||||||
|
|
||||||
|
statement_response = client.post(
|
||||||
|
"/watson/api/project/getBSByLogId",
|
||||||
|
data={
|
||||||
|
"groupId": 1001,
|
||||||
|
"logId": log_id,
|
||||||
|
"pageNow": 1,
|
||||||
|
"pageSize": 5,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert statement_response.status_code == 200
|
||||||
|
statements = statement_response.json()["data"]["bankStatementList"]
|
||||||
|
|
||||||
|
assert status_log["enterpriseNameList"] == ["链路主体"]
|
||||||
|
assert status_log["accountNoList"] == ["6222555566667777"]
|
||||||
|
assert statements
|
||||||
|
assert all(item["leName"] == status_log["enterpriseNameList"][0] for item in statements)
|
||||||
|
assert all(item["accountMaskNo"] == status_log["accountNoList"][0] for item in statements)
|
||||||
|
|||||||
47
lsfx-mock-server/tests/test_statement_service.py
Normal file
47
lsfx-mock-server/tests/test_statement_service.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
"""
|
||||||
|
StatementService 主绑定注入测试
|
||||||
|
"""
|
||||||
|
|
||||||
|
from services.file_service import FileService
|
||||||
|
from services.statement_service import StatementService
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_bank_statement_uses_primary_binding_from_file_service(monkeypatch):
|
||||||
|
"""同一 logId 的流水记录必须复用 FileService 中的主体与账号绑定。"""
|
||||||
|
file_service = FileService()
|
||||||
|
statement_service = StatementService(file_service=file_service)
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
file_service,
|
||||||
|
"_generate_primary_binding",
|
||||||
|
lambda: ("绑定主体", "6222000011112222"),
|
||||||
|
)
|
||||||
|
|
||||||
|
response = file_service.fetch_inner_flow(
|
||||||
|
{
|
||||||
|
"groupId": 1001,
|
||||||
|
"customerNo": "customer_001",
|
||||||
|
"dataChannelCode": "test",
|
||||||
|
"requestDateId": 20240101,
|
||||||
|
"dataStartDateId": 20240101,
|
||||||
|
"dataEndDateId": 20240131,
|
||||||
|
"uploadUserId": 902001,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
log_id = response["data"][0]
|
||||||
|
record = file_service.file_records[log_id]
|
||||||
|
|
||||||
|
statement_response = statement_service.get_bank_statement(
|
||||||
|
{
|
||||||
|
"groupId": 1001,
|
||||||
|
"logId": log_id,
|
||||||
|
"pageNow": 1,
|
||||||
|
"pageSize": 5,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
statements = statement_response["data"]["bankStatementList"]
|
||||||
|
assert statements
|
||||||
|
assert all(item["leName"] == record.primary_enterprise_name for item in statements)
|
||||||
|
assert all(item["accountMaskNo"] == record.primary_account_no for item in statements)
|
||||||
|
|
||||||
Reference in New Issue
Block a user