# -*- coding: utf-8 -*- """Unit tests for the new ODS ingestion tasks.""" import logging import os import sys from pathlib import Path # Ensure project root is resolvable when running tests in isolation PROJECT_ROOT = Path(__file__).resolve().parents[2] if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) os.environ.setdefault("ETL_SKIP_DOTENV", "1") from tasks.ods_tasks import ODS_TASK_CLASSES from .task_test_utils import create_test_config, get_db_operations, FakeAPIClient def _build_config(tmp_path): archive_dir = tmp_path / "archive" temp_dir = tmp_path / "temp" return create_test_config("ONLINE", archive_dir, temp_dir) def test_assistant_accounts_masters_ingest(tmp_path): """Ensure assistant_accounts_masterS task stores raw payload with record_index dedup keys.""" config = _build_config(tmp_path) sample = [ { "id": 5001, "assistant_no": "A01", "nickname": "灏忓紶", } ] api = FakeAPIClient({"/PersonnelManagement/SearchAssistantInfo": sample}) task_cls = ODS_TASK_CLASSES["assistant_accounts_masterS"] with get_db_operations() as db_ops: task = task_cls(config, db_ops, api, logging.getLogger("test_assistant_accounts_masters")) result = task.execute() assert result["status"] == "SUCCESS" assert result["counts"]["fetched"] == 1 assert db_ops.commits == 1 row = db_ops.upserts[0]["rows"][0] assert row["id"] == 5001 assert row["record_index"] == 0 assert row["source_file"] is None or row["source_file"] == "" assert '"id": 5001' in row["payload"] def test_goods_stock_movements_ingest(tmp_path): """Ensure goods_stock_movements task stores raw payload with record_index dedup keys.""" config = _build_config(tmp_path) sample = [ { "siteGoodsStockId": 123456, "stockType": 1, "goodsName": "娴嬭瘯鍟嗗搧", } ] api = FakeAPIClient({"/GoodsStockManage/QueryGoodsOutboundReceipt": sample}) task_cls = ODS_TASK_CLASSES["goods_stock_movements"] with get_db_operations() as db_ops: task = task_cls(config, db_ops, api, logging.getLogger("test_goods_stock_movements")) result = task.execute() assert result["status"] == "SUCCESS" assert result["counts"]["fetched"] == 1 assert db_ops.commits == 1 row = db_ops.upserts[0]["rows"][0] assert row["sitegoodsstockid"] == 123456 assert row["record_index"] == 0 assert '"siteGoodsStockId": 123456' in row["payload"] def test_member_profiless_ingest(tmp_path): """Ensure ODS_MEMBER task stores tenantMemberInfos raw JSON.""" config = _build_config(tmp_path) sample = [{"tenantMemberInfos": [{"id": 101, "mobile": "13800000000"}]}] api = FakeAPIClient({"/MemberProfile/GetTenantMemberList": sample}) task_cls = ODS_TASK_CLASSES["ODS_MEMBER"] with get_db_operations() as db_ops: task = task_cls(config, db_ops, api, logging.getLogger("test_ods_member")) result = task.execute() assert result["status"] == "SUCCESS" row = db_ops.upserts[0]["rows"][0] assert row["record_index"] == 0 assert '"id": 101' in row["payload"] def test_ods_payment_ingest(tmp_path): """Ensure ODS_PAYMENT task stores payment_transactions raw JSON.""" config = _build_config(tmp_path) sample = [{"payId": 901, "payAmount": "100.00"}] api = FakeAPIClient({"/PayLog/GetPayLogListPage": sample}) task_cls = ODS_TASK_CLASSES["ODS_PAYMENT"] with get_db_operations() as db_ops: task = task_cls(config, db_ops, api, logging.getLogger("test_ods_payment")) result = task.execute() assert result["status"] == "SUCCESS" row = db_ops.upserts[0]["rows"][0] assert row["record_index"] == 0 assert '"payId": 901' in row["payload"] def test_ods_settlement_records_ingest(tmp_path): """Ensure settlement_records task stores settleList raw JSON.""" config = _build_config(tmp_path) sample = [{"data": {"settleList": [{"id": 701, "orderTradeNo": 8001}]}}] api = FakeAPIClient({"/Site/GetAllOrderSettleList": sample}) task_cls = ODS_TASK_CLASSES["settlement_records"] with get_db_operations() as db_ops: task = task_cls(config, db_ops, api, logging.getLogger("test_settlement_records")) result = task.execute() assert result["status"] == "SUCCESS" row = db_ops.upserts[0]["rows"][0] assert row["record_index"] == 0 assert '"orderTradeNo": 8001' in row["payload"] def test_ods_settlement_ticket_by_payment_relate_ids(tmp_path): """Ensure settlement tickets are fetched per payment relate_id and skip existing ones.""" config = _build_config(tmp_path) ticket_payload = {"data": {"data": {"orderSettleId": 9001, "orderSettleNumber": "T001"}}} api = FakeAPIClient({"/Order/GetOrderSettleTicketNew": [ticket_payload]}) task_cls = ODS_TASK_CLASSES["ODS_SETTLEMENT_TICKET"] with get_db_operations() as db_ops: # First query: existing ticket ids; Second query: payment relate_ids db_ops.query_results = [ [{"order_settle_id": 9002}], [ {"order_settle_id": 9001}, {"order_settle_id": 9002}, {"order_settle_id": None}, ], ] task = task_cls(config, db_ops, api, logging.getLogger("test_ods_settlement_ticket")) result = task.execute() assert result["status"] == "SUCCESS" counts = result["counts"] assert counts["fetched"] == 1 assert counts["inserted"] == 1 assert counts["updated"] == 0 assert counts["skipped"] == 0 assert '"orderSettleId": 9001' in db_ops.upserts[0]["rows"][0]["payload"] assert any( call["endpoint"] == "/Order/GetOrderSettleTicketNew" and call.get("params", {}).get("orderSettleId") == 9001 for call in api.calls )