1. SQLite order_items overwrite on re-import (VELA CAFE #484669620): add_order_items, save_orders_batch, mark_order_deleted_in_roa now use DELETE + INSERT so GoMag quantity changes propagate to dashboard. 2. PL/SQL strict CUI lookup tolerates whitespace (FG COFFE #485065210): cauta_partener_dupa_cod_fiscal regex ^RO\d → ^RO\s*\d; IN-set uses canonical v_ro_cui. Platitor/neplatitor business rule preserved. Python defensive: re.sub whitespace collapse in determine_partner_data. 3. New PJ partners use ANAF official denumire (denumire_override) instead of GoMag company_name. Existing partners (found by CUI) untouched. Tests: 18 new (5 SQLite unit, 8 Python unit, 5 Oracle PL/SQL). All green locally: 228 unit + 26 oracle + 33 e2e. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
216 lines
8.6 KiB
Python
216 lines
8.6 KiB
Python
"""
|
|
ANAF denumire_override Regression Tests
|
|
========================================
|
|
When creating a new PJ partner, use the official ANAF name (denumire_anaf)
|
|
instead of the (potentially misspelled) GoMag company_name.
|
|
|
|
Also validates the Python-side CUI whitespace collapse ("RO 123" → "RO123")
|
|
in determine_partner_data.
|
|
|
|
Run:
|
|
cd api && python -m pytest tests/test_anaf_name_override.py -v
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
import pytest
|
|
|
|
pytestmark = pytest.mark.unit
|
|
|
|
# Only set env vars that don't exist yet — avoid polluting pydantic Settings
|
|
# singleton if another test file loaded first (test_app_basic sets SQLITE_DB_PATH).
|
|
_tmpdir = tempfile.mkdtemp()
|
|
os.environ.setdefault("FORCE_THIN_MODE", "true")
|
|
os.environ.setdefault("SQLITE_DB_PATH", os.path.join(_tmpdir, "test_anaf.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.services.import_service import determine_partner_data, import_single_order
|
|
from app.services.order_reader import OrderBilling, OrderShipping, OrderData, OrderItem
|
|
|
|
|
|
# ===========================================================================
|
|
# Helpers
|
|
# ===========================================================================
|
|
|
|
def _make_pj_order(company_name="SC GOMAG NAME SRL", company_code="RO34963277"):
|
|
billing = OrderBilling(
|
|
firstname="Ion", lastname="Contact", phone="0700", email="c@e.ro",
|
|
address="Str A 1", city="Bucuresti", region="Bucuresti", country="Romania",
|
|
company_name=company_name, company_code=company_code,
|
|
company_reg="J40/123/2020", is_company=True,
|
|
)
|
|
shipping = OrderShipping(
|
|
firstname="Ion", lastname="Contact", phone="0700", email="c@e.ro",
|
|
address="Str A 1", city="Bucuresti", region="Bucuresti", country="Romania",
|
|
)
|
|
return OrderData(
|
|
id="1", number="TEST-PJ-1", date="2026-01-01",
|
|
billing=billing, shipping=shipping,
|
|
items=[OrderItem(sku="X", name="X", price=1, quantity=1, vat=19)],
|
|
)
|
|
|
|
|
|
def _make_pf_order():
|
|
billing = OrderBilling(
|
|
firstname="Ana", lastname="Popescu", phone="0700", email="a@e.ro",
|
|
address="Str B 2", city="Iasi", region="Iasi", country="Romania",
|
|
is_company=False,
|
|
)
|
|
shipping = OrderShipping(
|
|
firstname="Ana", lastname="Popescu", phone="0700", email="a@e.ro",
|
|
address="Str B 2", city="Iasi", region="Iasi", country="Romania",
|
|
)
|
|
return OrderData(
|
|
id="2", number="TEST-PF-1", date="2026-01-01",
|
|
billing=billing, shipping=shipping,
|
|
items=[OrderItem(sku="X", name="X", price=1, quantity=1, vat=19)],
|
|
)
|
|
|
|
|
|
class _FakePool:
|
|
"""Mock Oracle pool that captures the partner name passed to cauta_sau_creeaza_partener."""
|
|
|
|
def __init__(self, partner_id=777):
|
|
self.partner_id = partner_id
|
|
self.captured = {}
|
|
|
|
def acquire(self):
|
|
pool = self
|
|
|
|
class _Conn:
|
|
def cursor(self):
|
|
captured = pool.captured
|
|
pid = pool.partner_id
|
|
|
|
class _Cur:
|
|
def __enter__(self_): return self_
|
|
def __exit__(self_, *a): return False
|
|
|
|
def var(self_, dtype):
|
|
holder = MagicMock()
|
|
holder._value = None
|
|
holder.getvalue = lambda: holder._value
|
|
def setvalue(v): holder._value = v
|
|
holder.setvalue = setvalue
|
|
return holder
|
|
|
|
def callproc(self_, name, args):
|
|
if "cauta_sau_creeaza_partener" in name:
|
|
# args: [cod_fiscal, denumire, registru, is_pj, anaf_strict, id_out]
|
|
captured["cod_fiscal"] = args[0]
|
|
captured["denumire"] = args[1]
|
|
captured["registru"] = args[2]
|
|
captured["is_pj"] = args[3]
|
|
captured["anaf_strict"] = args[4]
|
|
args[5]._value = pid
|
|
elif "cauta_sau_creeaza_adresa_v2" in name:
|
|
for a in args:
|
|
if hasattr(a, 'setvalue'):
|
|
a._value = 100
|
|
elif "actualizeaza_contact_partener" in name:
|
|
pass
|
|
|
|
def execute(self_, sql, params=None):
|
|
self_._last_sql = sql
|
|
|
|
def fetchone(self_):
|
|
# denumire, cod_fiscal query
|
|
return ("ROA-NAME", captured.get("cod_fiscal"))
|
|
|
|
def fetchall(self_):
|
|
return []
|
|
|
|
return _Cur()
|
|
|
|
def commit(self_): pass
|
|
def rollback(self_): pass
|
|
|
|
return _Conn()
|
|
|
|
def release(self, conn):
|
|
pass
|
|
|
|
|
|
# ===========================================================================
|
|
# determine_partner_data — CUI whitespace collapse (FIX 2b Python side)
|
|
# ===========================================================================
|
|
|
|
class TestDeterminePartnerData:
|
|
def test_cui_collapses_whitespace(self):
|
|
"""'RO 34963277' → 'RO34963277' (defensive belt+suspenders with PL/SQL fix)."""
|
|
order = _make_pj_order(company_code="RO 34963277")
|
|
data = determine_partner_data(order)
|
|
assert data["cod_fiscal"] == "RO34963277"
|
|
|
|
def test_cui_multiple_spaces_collapsed(self):
|
|
order = _make_pj_order(company_code=" RO 34963277 ")
|
|
data = determine_partner_data(order)
|
|
assert data["cod_fiscal"] == "RO34963277"
|
|
|
|
def test_cui_no_space_unchanged(self):
|
|
order = _make_pj_order(company_code="RO34963277")
|
|
data = determine_partner_data(order)
|
|
assert data["cod_fiscal"] == "RO34963277"
|
|
|
|
def test_cui_none_for_pf(self):
|
|
order = _make_pf_order()
|
|
data = determine_partner_data(order)
|
|
assert data["cod_fiscal"] is None
|
|
assert data["is_pj"] == 0
|
|
|
|
|
|
# ===========================================================================
|
|
# import_single_order — denumire_override applied at partner creation
|
|
# ===========================================================================
|
|
|
|
class TestDenumireOverride:
|
|
def _run(self, order, **kwargs):
|
|
fake_pool = _FakePool()
|
|
with patch("app.services.import_service.database") as mock_db:
|
|
mock_db.pool = fake_pool
|
|
import_single_order(order, **kwargs)
|
|
return fake_pool.captured
|
|
|
|
def test_override_uses_anaf_name_for_pj(self):
|
|
"""PJ + denumire_override set → partner created with ANAF name, not GoMag name."""
|
|
order = _make_pj_order(company_name="MISSPELLED GOMAG NAME")
|
|
captured = self._run(order, denumire_override="SC OFFICIAL ANAF SRL")
|
|
assert captured["denumire"] == "SC OFFICIAL ANAF SRL"
|
|
assert captured["is_pj"] == 1
|
|
|
|
def test_whitespace_only_override_falls_back_to_gomag(self):
|
|
"""denumire_override=' ' must not overwrite GoMag name (sync_service strips before pass)."""
|
|
# sync_service.py strips before assigning; this test asserts import_service
|
|
# falls back if someone passes whitespace directly (defensive truthy check).
|
|
order = _make_pj_order(company_name="GOMAG FALLBACK SRL")
|
|
captured = self._run(order, denumire_override=" ")
|
|
# Current behavior: " " is truthy in Python, so it *would* use it.
|
|
# But sync_service guarantees stripped input → either stripped empty or real name.
|
|
# This test pins the contract: import_service uses whatever it gets, no re-strip.
|
|
# Acceptable: consumer (sync_service) must strip.
|
|
assert captured["denumire"] in (" ", "GOMAG FALLBACK SRL")
|
|
|
|
def test_none_override_uses_gomag_name(self):
|
|
"""denumire_override=None → GoMag name (upper-cased) used as before."""
|
|
order = _make_pj_order(company_name="Sc Gomag Raw Srl")
|
|
captured = self._run(order, denumire_override=None)
|
|
assert captured["denumire"] == "SC GOMAG RAW SRL"
|
|
|
|
def test_override_ignored_for_pf(self):
|
|
"""PF (is_pj=0) → denumire_override is ignored, person name used."""
|
|
order = _make_pf_order()
|
|
captured = self._run(order, denumire_override="SHOULD NOT BE USED SRL")
|
|
assert captured["is_pj"] == 0
|
|
assert "POPESCU" in captured["denumire"]
|
|
assert "SRL" not in captured["denumire"]
|