90 lines
3.1 KiB
Python
90 lines
3.1 KiB
Python
"""v4.9.11 regression tests for Odoo name-only reconciliation.
|
|
|
|
Odoo customers may not have VAT/NIF filled in. Reconciliation should still be
|
|
able to suggest/link by normalized company name and should not abort the whole
|
|
process candidate list when an individual suggestion lookup fails.
|
|
"""
|
|
|
|
import sys
|
|
import types
|
|
|
|
if "sqlalchemy" not in sys.modules:
|
|
sqlalchemy = types.ModuleType("sqlalchemy")
|
|
sqlalchemy.text = lambda sql: sql
|
|
sys.modules["sqlalchemy"] = sqlalchemy
|
|
|
|
if "app.db" not in sys.modules:
|
|
app_db = types.ModuleType("app.db")
|
|
app_db.engine = object()
|
|
sys.modules["app.db"] = app_db
|
|
|
|
if "app.action_catalog" not in sys.modules:
|
|
action_catalog = types.ModuleType("app.action_catalog")
|
|
action_catalog.get_action_config = lambda code: {"route": "rever", "action": code, "action_required": True, "safe_to_post": False}
|
|
sys.modules["app.action_catalog"] = action_catalog
|
|
|
|
from app import reconciliation_service as svc
|
|
|
|
|
|
def test_company_name_normalization_matches_odoo_without_nif():
|
|
score = svc._name_match_score(
|
|
"ELEGANTLEGACY, LDA VALONGO Portugal",
|
|
"Elegantlegacy Lda",
|
|
"Oportunidade · elegantlegacy",
|
|
)
|
|
assert score >= 35
|
|
|
|
|
|
def test_single_odoo_sale_without_nif_becomes_process_candidate(monkeypatch):
|
|
monkeypatch.setattr(
|
|
svc,
|
|
"list_reconciliation_items",
|
|
lambda *, status, limit, days: [
|
|
{
|
|
"id": "odoo-sale-274",
|
|
"source_system": "odoo",
|
|
"external_type": "odoo_sale_order",
|
|
"title": "Venda Odoo sem oportunidade · S00274",
|
|
"customer_name": "ELEGANTLEGACY, LDA",
|
|
"customer_tax_id": "",
|
|
"customer_email": "",
|
|
"document_number": "S00274",
|
|
"document_date": "2026-06-02",
|
|
"amount": "537.00",
|
|
"currency": "EUR",
|
|
"operation_suggestions": [],
|
|
}
|
|
],
|
|
)
|
|
|
|
candidates = svc.list_reconciliation_process_candidates(status="open", days=7, limit=10)
|
|
|
|
assert len(candidates) == 1
|
|
candidate = candidates[0]
|
|
assert candidate["match_key"] == "name"
|
|
assert candidate["confidence"] == "alta"
|
|
assert candidate["identity_reason"] == "nome fiscal"
|
|
assert candidate["customer_name"] == "ELEGANTLEGACY, LDA"
|
|
assert candidate["suggested_stage"] == "ODOO_ORDER_CREATED"
|
|
assert candidate["suggested_action"] == "SEND_INVOICE"
|
|
assert candidate["item_ids"] == ["odoo-sale-274"]
|
|
|
|
|
|
def test_list_process_candidates_is_resilient_when_item_query_fails(monkeypatch):
|
|
def fail_listing(*, status, limit, days):
|
|
raise RuntimeError("simulated db lookup failure")
|
|
|
|
monkeypatch.setattr(svc, "list_reconciliation_items", fail_listing)
|
|
|
|
assert svc.list_reconciliation_process_candidates(status="open", days=7, limit=10) == []
|
|
|
|
|
|
def test_person_name_only_is_not_high_confidence_identity():
|
|
confidence, reason = svc._process_group_identity_label(
|
|
"name",
|
|
[{"customer_name": "Bruno Oliveira", "customer_tax_id": "", "source_system": "odoo"}],
|
|
)
|
|
|
|
assert confidence == "média"
|
|
assert reason == "nome"
|