113 lines
4.5 KiB
Python
113 lines
4.5 KiB
Python
"""v4.9.20: fiscal customer identity is not purchase identity."""
|
|
|
|
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 _jasmin_doc(id_, external_type, number, date, amount):
|
|
return {
|
|
"id": id_,
|
|
"source_system": "jasmin",
|
|
"external_type": external_type,
|
|
"title": f"Documento Jasmin · {number}",
|
|
"customer_name": "ACZCO BRAGA ENERGY, LDA",
|
|
"customer_tax_id": "517249200",
|
|
"document_number": number,
|
|
"document_date": date,
|
|
"amount": amount,
|
|
"currency": "EUR",
|
|
"operation_suggestions": [],
|
|
}
|
|
|
|
|
|
def test_same_company_two_jasmin_quotes_stay_as_two_purchase_candidates(monkeypatch):
|
|
monkeypatch.setattr(
|
|
svc,
|
|
"list_reconciliation_items",
|
|
lambda *, status, limit, days: [
|
|
_jasmin_doc("quote-154", "jasmin_quotation", "ORC.ORC2026.154", "2026-06-03", "638.60"),
|
|
_jasmin_doc("quote-160", "jasmin_quotation", "ORC.ORC2026.160", "2026-06-06", "190.00"),
|
|
],
|
|
)
|
|
|
|
candidates = svc.list_reconciliation_process_candidates(status="open", days=7, limit=10)
|
|
|
|
assert len(candidates) == 2
|
|
keys = {candidate["operation_key"] for candidate in candidates}
|
|
assert "jasmin_quotation:ORC.ORC2026.154" in keys
|
|
assert "jasmin_quotation:ORC.ORC2026.160" in keys
|
|
assert {tuple(candidate["item_ids"]) for candidate in candidates} == {("quote-154",), ("quote-160",)}
|
|
|
|
|
|
def test_quote_and_invoice_with_same_amount_and_near_date_can_form_one_purchase(monkeypatch):
|
|
monkeypatch.setattr(
|
|
svc,
|
|
"list_reconciliation_items",
|
|
lambda *, status, limit, days: [
|
|
_jasmin_doc("quote-154", "jasmin_quotation", "ORC.ORC2026.154", "2026-06-03", "638.60"),
|
|
_jasmin_doc("invoice-80", "jasmin_invoice", "FA2026.80", "2026-06-05", "638.60"),
|
|
_jasmin_doc("quote-160", "jasmin_quotation", "ORC.ORC2026.160", "2026-06-20", "190.00"),
|
|
],
|
|
)
|
|
|
|
candidates = svc.list_reconciliation_process_candidates(status="open", days=30, limit=10)
|
|
|
|
grouped = {candidate["operation_key"]: set(candidate["item_ids"]) for candidate in candidates}
|
|
assert grouped["jasmin_quotation:ORC.ORC2026.154"] == {"quote-154", "invoice-80"}
|
|
assert grouped["jasmin_quotation:ORC.ORC2026.160"] == {"quote-160"}
|
|
|
|
|
|
def test_payment_proof_assigns_only_when_order_match_is_unambiguous(monkeypatch):
|
|
order_a = {
|
|
"id": "sale-279",
|
|
"source_system": "odoo",
|
|
"external_type": "odoo_sale_order",
|
|
"title": "Venda Odoo sem oportunidade · S00279",
|
|
"customer_name": "ACZCO BRAGA ENERGY, LDA",
|
|
"customer_tax_id": "517249200",
|
|
"document_number": "S00279",
|
|
"document_date": "2026-06-05",
|
|
"amount": "638.60",
|
|
"currency": "EUR",
|
|
"payload": {"record": {"name": "S00279", "invoice_status": "to invoice"}},
|
|
"operation_suggestions": [],
|
|
}
|
|
order_b = {**order_a, "id": "sale-280", "document_number": "S00280", "amount": "190.00", "payload": {"record": {"name": "S00280", "invoice_status": "to invoice"}}}
|
|
proof = {
|
|
"id": "proof-279",
|
|
"source_system": "email",
|
|
"external_type": "payment_proof",
|
|
"title": "Comprovativo recebido",
|
|
"customer_name": "ACZCO BRAGA ENERGY, LDA",
|
|
"customer_tax_id": "517249200",
|
|
"document_number": "comprovativo-279",
|
|
"document_date": "2026-06-06",
|
|
"amount": "638.60",
|
|
"currency": "EUR",
|
|
"operation_suggestions": [],
|
|
}
|
|
monkeypatch.setattr(svc, "list_reconciliation_items", lambda *, status, limit, days: [order_a, order_b, proof])
|
|
|
|
candidates = svc.list_reconciliation_process_candidates(status="open", days=7, limit=10)
|
|
|
|
grouped = {candidate["operation_key"]: set(candidate["item_ids"]) for candidate in candidates}
|
|
assert grouped["odoo_sale_order:S00279"] == {"sale-279", "proof-279"}
|
|
assert grouped["odoo_sale_order:S00280"] == {"sale-280"}
|