feat(api): 更新代销平台 API v0.1,增强适当性检查功能
- 在 `risk_suitability_log` 表中新增 `check_source` 枚举值 `platform`,支持代销平台的适当性检查。 - 更新相关 SQL 脚本以适应新的数据结构,确保数据一致性。 - 修改文档以反映 API 的最新状态和测试基线,确保文档与实现保持一致。 - 测试基线更新至 530 passed, 0 skipped,确保系统稳定性。 此更新为代销平台提供了更全面的适当性检查能力,提升了系统的功能性与可维护性。
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
"""Repair UTF-8 demo seed data (core display_name + risk_aml_list).
|
||||
|
||||
Windows mysql CLI pipe may corrupt CJK; use SQLAlchemy + utf-8 file reads instead.
|
||||
Idempotent: safe to re-run after partial bootstrap.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from app.config.settings import settings
|
||||
from app.utils.db import get_engine
|
||||
|
||||
CUSTOMER_SEED = ROOT / "scripts/core/03-seed-customers.sql"
|
||||
AML_SEED = ROOT / "scripts/agent/seed-aml-list.sql"
|
||||
RISK_DEMO = ROOT / "scripts/demo/prepare_risk_demo.sql"
|
||||
|
||||
_ROW_RE = re.compile(r"\('(CUST-[^']+)',\s*'([^']+)'")
|
||||
|
||||
|
||||
def _parse_customer_names() -> list[tuple[str, str]]:
|
||||
content = CUSTOMER_SEED.read_text(encoding="utf-8")
|
||||
block = content.split("INSERT INTO core_customer_risk")[0]
|
||||
return _ROW_RE.findall(block)
|
||||
|
||||
|
||||
def _parse_aml_rows() -> list[dict[str, str]]:
|
||||
content = AML_SEED.read_text(encoding="utf-8")
|
||||
rows: list[dict[str, str]] = []
|
||||
for m in re.finditer(
|
||||
r"\('(AML-\d+)',\s*'(\w+)',\s*'([^']*)',\s*NULL,\s*NULL,\s*([\d.]+),\s*"
|
||||
r"'([^']*)',\s*'([^']*)',\s*'(\d{4}-\d{2}-\d{2})'\)",
|
||||
content,
|
||||
):
|
||||
rows.append(
|
||||
{
|
||||
"list_id": m.group(1),
|
||||
"list_type": m.group(2),
|
||||
"full_name": m.group(3),
|
||||
"match_threshold": m.group(4),
|
||||
"source": m.group(5),
|
||||
"list_version": m.group(6),
|
||||
"effective_date": m.group(7),
|
||||
}
|
||||
)
|
||||
if len(rows) != 8:
|
||||
raise RuntimeError(f"expected 8 AML rows, parsed {len(rows)}")
|
||||
return rows
|
||||
|
||||
|
||||
def _run_sql_file(engine, path: Path) -> None:
|
||||
statements = [s.strip() for s in path.read_text(encoding="utf-8").split(";") if s.strip()]
|
||||
with engine.begin() as conn:
|
||||
for stmt in statements:
|
||||
if stmt.upper().startswith("USE "):
|
||||
continue
|
||||
conn.execute(text(stmt))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
core = get_engine(settings.mysql_core_database)
|
||||
agent = get_engine(settings.mysql_database)
|
||||
|
||||
names = _parse_customer_names()
|
||||
with core.begin() as conn:
|
||||
for customer_id, display_name in names:
|
||||
conn.execute(
|
||||
text("UPDATE core_customer SET display_name = :n WHERE customer_id = :id"),
|
||||
{"id": customer_id, "n": display_name},
|
||||
)
|
||||
print(f"updated {len(names)} core_customer.display_name")
|
||||
|
||||
aml_rows = _parse_aml_rows()
|
||||
with agent.begin() as conn:
|
||||
conn.execute(text("DELETE FROM risk_aml_list"))
|
||||
for row in aml_rows:
|
||||
conn.execute(
|
||||
text(
|
||||
"""
|
||||
INSERT INTO risk_aml_list
|
||||
(list_id, list_type, full_name, id_no, bank_card_no,
|
||||
match_threshold, source, list_version, effective_date, is_active)
|
||||
VALUES
|
||||
(:list_id, :list_type, :full_name, NULL, NULL,
|
||||
:match_threshold, :source, :list_version, :effective_date, 1)
|
||||
"""
|
||||
),
|
||||
row,
|
||||
)
|
||||
print(f"reseeded {len(aml_rows)} risk_aml_list rows")
|
||||
|
||||
_run_sql_file(core, RISK_DEMO)
|
||||
print("ran prepare_risk_demo.sql")
|
||||
|
||||
with core.connect() as conn:
|
||||
sample = conn.execute(
|
||||
text("SELECT customer_id, display_name FROM core_customer WHERE customer_id = 'CUST-3001'")
|
||||
).one()
|
||||
print("verify CUST-3001:", sample)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user