""" CUI Gate Tests ============== Unit tests for evaluate_cui_gate() and _record_order_error() in sync_service. Tests 1-6: pure predicate, no IO. Test 7: integration — _record_order_error with pre-seeded SQLite IMPORTED row verifies COALESCE preserves existing id_partener. Run: cd api && python -m pytest tests/test_sync_cui_gate.py -v """ import os import sys import tempfile import pytest pytestmark = pytest.mark.unit _tmpdir = tempfile.mkdtemp() os.environ.setdefault("FORCE_THIN_MODE", "true") os.environ.setdefault("SQLITE_DB_PATH", os.path.join(_tmpdir, "test_cui_gate.db")) os.environ.setdefault("ORACLE_DSN", "dummy") os.environ.setdefault("ORACLE_USER", "dummy") os.environ.setdefault("ORACLE_PASSWORD", "dummy") os.environ.setdefault("JSON_OUTPUT_DIR", _tmpdir) _api_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if _api_dir not in sys.path: sys.path.insert(0, _api_dir) from app import database from app.services import sqlite_service from app.services.sync_service import evaluate_cui_gate, _record_order_error from app.services.order_reader import OrderBilling, OrderShipping, OrderData, OrderItem from app.constants import OrderStatus # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- _VALID_ANAF_FOUND = {"scpTVA": True, "denumire_anaf": "NONA ROYAL SRL", "checked_at": "2026-04-22T10:00:00"} _ANAF_NOT_FOUND = {"scpTVA": None, "denumire_anaf": "", "checked_at": "2026-04-22T10:00:00"} # A CUI with valid format and valid checksum (MATTEO&OANA CAFFE 2022 SRL) _VALID_CUI = "49033051" # Same body but last digit modified → fails checksum _BAD_CHECKSUM_CUI = "49033052" # J-format — the incident CUI (registru number in the CUI field) _J_FORMAT = "J1994000194225" def _make_pj_order(company_code=_VALID_CUI, number="O-001"): billing = OrderBilling( firstname="Ion", lastname="Pop", phone="0700", email="x@x.ro", address="Str A 1", city="Cluj", region="Cluj", country="Romania", company_name="TEST SRL", company_code=company_code, company_reg="J12/123/2020", is_company=True, ) shipping = OrderShipping( firstname="Ion", lastname="Pop", phone="0700", email="x@x.ro", address="Str A 1", city="Cluj", region="Cluj", country="Romania", ) return OrderData( id=number, number=number, date="2026-04-22", billing=billing, shipping=shipping, items=[OrderItem(sku="SKU1", name="Prod", price=10.0, quantity=1, vat=19)], ) def _make_pf_order(number="O-PF-1"): billing = OrderBilling( firstname="Ana", lastname="Pop", phone="0700", email="a@x.ro", address="Str B 2", city="Iasi", region="Iasi", country="Romania", is_company=False, ) shipping = OrderShipping( firstname="Ana", lastname="Pop", phone="0700", email="a@x.ro", address="Str B 2", city="Iasi", region="Iasi", country="Romania", ) return OrderData( id=number, number=number, date="2026-04-22", billing=billing, shipping=shipping, items=[OrderItem(sku="SKU1", name="Prod", price=10.0, quantity=1, vat=19)], ) # --------------------------------------------------------------------------- # Tests 1-6: pure predicate — no IO # --------------------------------------------------------------------------- class TestEvaluateCuiGate: def test_format_invalid_incident_case(self): """Test 1: J-format in cod_fiscal field (the 22-Apr-2026 incident) → blocked.""" # bare_cui from sanitize_cui("J1994000194225") = "J1994000194225" (not digits) result = evaluate_cui_gate( is_ro_company=True, company_code_raw=_J_FORMAT, bare_cui=_J_FORMAT, anaf_data=_VALID_ANAF_FOUND, ) assert result is not None assert "format" in result def test_checksum_invalid(self): """Test 2: valid format, wrong check digit → blocked.""" result = evaluate_cui_gate( is_ro_company=True, company_code_raw=_BAD_CHECKSUM_CUI, bare_cui=_BAD_CHECKSUM_CUI, anaf_data=_VALID_ANAF_FOUND, ) assert result is not None assert "cifra de control" in result def test_anaf_not_found_explicit(self): """Test 3: ANAF explicit notFound → blocked with registry hint.""" result = evaluate_cui_gate( is_ro_company=True, company_code_raw=_VALID_CUI, bare_cui=_VALID_CUI, anaf_data=_ANAF_NOT_FOUND, ) assert result is not None assert "nu exista in registrul ANAF" in result assert "registrul comertului" in result def test_anaf_found_vat_payer_passes(self): """Test 4: ANAF found + platitor TVA → pass.""" result = evaluate_cui_gate( is_ro_company=True, company_code_raw=_VALID_CUI, bare_cui=_VALID_CUI, anaf_data=_VALID_ANAF_FOUND, ) assert result is None def test_anaf_down_fallback_passes(self): """Test 5 [CRITICAL REGRESSION]: ANAF down (anaf_data=None) + valid CUI → pass. If this test fails, the gate is breaking the ANAF-down fallback and all RO company orders would error when ANAF is unavailable. """ result = evaluate_cui_gate( is_ro_company=True, company_code_raw=_VALID_CUI, bare_cui=_VALID_CUI, anaf_data=None, # ANAF down / transient error ) assert result is None, ( "ANAF down must NOT block orders — gate must only block on explicit notFound" ) def test_pf_always_passes(self): """Test 6: PF order (is_ro_company=False) → always pass, regardless of CUI.""" result = evaluate_cui_gate( is_ro_company=False, company_code_raw=_J_FORMAT, bare_cui=_J_FORMAT, anaf_data=_ANAF_NOT_FOUND, ) assert result is None def test_no_company_code_passes(self): """PJ without company_code → pass (nothing to validate).""" result = evaluate_cui_gate( is_ro_company=True, company_code_raw=None, bare_cui="", anaf_data=None, ) assert result is None def test_anaf_found_non_vat_passes(self): """ANAF found non-platitor TVA (scpTVA=False) → pass.""" result = evaluate_cui_gate( is_ro_company=True, company_code_raw=_VALID_CUI, bare_cui=_VALID_CUI, anaf_data={"scpTVA": False, "denumire_anaf": "FIRMA SRL", "checked_at": "2026-04-22T10:00:00"}, ) assert result is None # --------------------------------------------------------------------------- # Test 7: integration — COALESCE preserves id_partener on gate block # --------------------------------------------------------------------------- @pytest.fixture(autouse=True) def _init_db(): database.init_sqlite() @pytest.mark.asyncio async def test_record_order_error_preserves_id_partener(): """Test 7: _record_order_error called with id_partener=None preserves existing id_partener via SQLite COALESCE in upsert_order. Scenario: order was previously IMPORTED with id_partener=9001. At resync the gate blocks it (bad CUI). _record_order_error passes id_partener=None. After upsert, the row should have status=ERROR and id_partener=9001 (preserved). """ order = _make_pj_order(company_code=_J_FORMAT, number="O-COALESCE-1") run_id = "test-run-coalesce" # Seed an existing IMPORTED row with id_partener=9001 db = await sqlite_service.get_sqlite() try: await db.execute( """INSERT OR REPLACE INTO orders (order_number, order_date, customer_name, status, id_partener, items_count) VALUES (?, ?, ?, ?, ?, ?)""", (order.number, order.date, "TEST SRL", OrderStatus.IMPORTED.value, 9001, 1), ) await db.commit() finally: await db.close() # Gate fires → calls _record_order_error with id_partener=None (gate doesn't know it) await _record_order_error( run_id=run_id, order=order, customer="TEST SRL", shipping_name="Ion Pop", billing_name="TEST SRL", payment_method="card", delivery_method="curier", discount_split_json=None, order_items_data=[{ "sku": "SKU1", "product_name": "Prod", "quantity": 1, "price": 10.0, "baseprice": None, "vat": 19, "mapping_status": "direct", "codmat": None, "id_articol": None, "cantitate_roa": None, }], reason=f"CUI invalid (format): {_J_FORMAT!r}", id_partener=None, # gate doesn't have it ) # Verify: status=ERROR, id_partener=9001 (COALESCE preserved), error_message populated db = await sqlite_service.get_sqlite() try: row = await db.execute( "SELECT status, id_partener, error_message FROM orders WHERE order_number = ?", (order.number,), ) row = await row.fetchone() finally: await db.close() assert row is not None, "Order row missing after _record_order_error" assert row[0] == OrderStatus.ERROR.value, f"Expected ERROR, got {row[0]}" assert row[1] == 9001, f"Expected id_partener=9001 (preserved by COALESCE), got {row[1]}" assert row[2] and "format" in row[2], f"Expected error_message with 'format', got {row[2]!r}"