Import ClientFlow production v4928.1.5.132.4
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
from app.domain.opportunity_flow import build_opportunity_evidence, decide_opportunity_next_action, load_company_profile
|
||||
from app.domain.opportunity_flow.audit import audit_decisions
|
||||
|
||||
|
||||
def _profile():
|
||||
return load_company_profile("blif")
|
||||
|
||||
|
||||
def test_blif_profile_loads_defaults_and_labels():
|
||||
profile = _profile()
|
||||
assert profile.company == "blif"
|
||||
assert profile.defaults["payment_terms"] == "before_shipping"
|
||||
assert profile.defaults["delivery_terms"] == "carrier"
|
||||
assert profile.action_label("CONFIRM_PAYMENT") == "Confirmar pagamento"
|
||||
assert profile.documents["quote"]["label"] == "Orçamento"
|
||||
assert profile.documents["invoice"]["label"] == "Fatura"
|
||||
|
||||
|
||||
def test_quote_before_shipping_requires_confirm_payment_before_invoice():
|
||||
evidence = build_opportunity_evidence(
|
||||
{"id": "opp-1", "stage": "QUOTE_SENT", "metadata": {"payment_terms": "before_shipping"}},
|
||||
linked_customer={"id": "c1", "tax_id": "123", "billing_email": "a@b.pt", "address": "Rua", "postal_code": "1000", "city": "Lisboa"},
|
||||
linked_documents=[{"id": "q1", "document_kind": "quotation", "document_number": "ORC.ORC2026.177", "total_amount": 202.95}],
|
||||
operation_snapshot={"links": [], "cards": []},
|
||||
fiscal_data_complete=True,
|
||||
)
|
||||
decision = decide_opportunity_next_action(evidence, _profile())
|
||||
assert decision.next_action.code == "CONFIRM_PAYMENT"
|
||||
assert decision.next_action.document_number == "ORC.ORC2026.177"
|
||||
assert "antes da fatura" in decision.next_action.description or "antes de emitir fatura" in decision.next_action.description
|
||||
|
||||
|
||||
def test_payment_confirmed_without_invoice_sends_invoice():
|
||||
evidence = build_opportunity_evidence(
|
||||
{"id": "opp-2", "stage": "PAYMENT_CONFIRMED", "metadata": {"payment_terms": "before_shipping"}},
|
||||
linked_customer={"id": "c1", "tax_id": "123", "billing_email": "a@b.pt", "address": "Rua", "postal_code": "1000", "city": "Lisboa"},
|
||||
linked_documents=[{"id": "q1", "document_kind": "quotation", "document_number": "ORC.ORC2026.177"}],
|
||||
operation_snapshot={"links": [{"system": "clientflow", "external_type": "payment", "status": "confirmed"}], "cards": []},
|
||||
fiscal_data_complete=True,
|
||||
)
|
||||
decision = decide_opportunity_next_action(evidence, _profile())
|
||||
assert decision.next_action.code == "SEND_INVOICE"
|
||||
assert decision.next_action.label == "Enviar fatura ao cliente"
|
||||
|
||||
|
||||
def test_payment_invoice_pending_send_keeps_send_invoice_before_waiting_production():
|
||||
evidence = build_opportunity_evidence(
|
||||
{"id": "opp-3", "stage": "PAYMENT_CONFIRMED", "metadata": {"payment_terms": "before_shipping"}},
|
||||
linked_customer={"id": "c1", "tax_id": "123", "billing_email": "a@b.pt", "address": "Rua", "postal_code": "1000", "city": "Lisboa"},
|
||||
linked_documents=[
|
||||
{"id": "q1", "document_kind": "quotation", "document_number": "ORC.ORC2026.177"},
|
||||
{"id": "i1", "document_kind": "invoice", "document_number": "FA.FA2026.114", "status": "open"},
|
||||
],
|
||||
tasks=[{"id": "t1", "status": "pending", "action_code": "SEND_INVOICE", "action": "Enviar fatura"}],
|
||||
operation_snapshot={
|
||||
"links": [{"system": "clientflow", "external_type": "payment", "status": "confirmed"}],
|
||||
"cards": [{"key": "odoo_production", "status": "in_progress"}],
|
||||
},
|
||||
fiscal_data_complete=True,
|
||||
)
|
||||
decision = decide_opportunity_next_action(evidence, _profile())
|
||||
assert decision.next_action.code == "SEND_INVOICE"
|
||||
assert decision.next_action.target_url == "/tasks/t1"
|
||||
assert "Enviar PDF" in decision.next_action.description
|
||||
|
||||
|
||||
def test_payment_invoice_sent_and_odoo_production_waits_production_not_send_invoice():
|
||||
evidence = build_opportunity_evidence(
|
||||
{"id": "opp-3b", "stage": "PAYMENT_CONFIRMED", "metadata": {"payment_terms": "before_shipping"}},
|
||||
linked_customer={"id": "c1", "tax_id": "123", "billing_email": "a@b.pt", "address": "Rua", "postal_code": "1000", "city": "Lisboa"},
|
||||
linked_documents=[
|
||||
{"id": "q1", "document_kind": "quotation", "document_number": "ORC.ORC2026.177"},
|
||||
{"id": "i1", "document_kind": "invoice", "document_number": "FA.FA2026.114", "sent": True},
|
||||
],
|
||||
operation_snapshot={
|
||||
"links": [{"system": "clientflow", "external_type": "payment", "status": "confirmed"}],
|
||||
"cards": [{"key": "odoo_physical_status", "status": "created", "payload": {"label": "Em produção/preparação", "ready_to_ship": False, "next_action": "Aguardar conclusão da produção/preparação no Odoo."}}],
|
||||
},
|
||||
fiscal_data_complete=True,
|
||||
)
|
||||
decision = decide_opportunity_next_action(evidence, _profile())
|
||||
assert decision.next_action.code == "WAIT_PRODUCTION"
|
||||
assert decision.next_action.label == "Aguardar produção"
|
||||
assert decision.financial_state == "payment_confirmed"
|
||||
assert audit_decisions([decision]) == []
|
||||
|
||||
|
||||
def test_after_delivery_shipped_without_payment_followup_payment():
|
||||
evidence = build_opportunity_evidence(
|
||||
{"id": "opp-4", "stage": "SHIPMENT_CREATED", "metadata": {"payment_terms": "after_delivery"}},
|
||||
linked_customer={"id": "c1", "tax_id": "123", "billing_email": "a@b.pt", "address": "Rua", "postal_code": "1000", "city": "Lisboa"},
|
||||
linked_documents=[{"id": "q1", "document_kind": "quotation", "document_number": "ORC.ORC2026.200"}],
|
||||
operation_snapshot={"links": [], "cards": [{"key": "packlink_shipment", "status": "created"}]},
|
||||
fiscal_data_complete=True,
|
||||
)
|
||||
decision = decide_opportunity_next_action(evidence, _profile())
|
||||
assert decision.next_action.code == "FOLLOW_UP_PAYMENT"
|
||||
|
||||
|
||||
def test_fiscal_conflict_blocks_financial_actions():
|
||||
evidence = build_opportunity_evidence(
|
||||
{"id": "opp-5", "stage": "QUOTE_SENT", "metadata": {"has_nif_conflict": True}},
|
||||
linked_customer={"id": "c1", "tax_id": "123"},
|
||||
linked_documents=[{"id": "q1", "document_kind": "quotation", "document_number": "ORC.ORC2026.177"}],
|
||||
)
|
||||
decision = decide_opportunity_next_action(evidence, _profile())
|
||||
assert decision.next_action.code == "REVIEW"
|
||||
blocked = {a.code for a in decision.blocked_actions}
|
||||
assert {"CONFIRM_PAYMENT", "SEND_INVOICE", "CREATE_JASMIN_QUOTE"} <= blocked
|
||||
|
||||
|
||||
def test_after_delivery_invoice_without_payment_allows_prepare_odoo_before_payment():
|
||||
evidence = build_opportunity_evidence(
|
||||
{"id": "opp-after-delivery", "stage": "INVOICE_SENT", "metadata": {"payment_terms": "after_delivery"}},
|
||||
linked_customer={"id": "c1", "tax_id": "123", "billing_email": "a@b.pt", "address": "Rua", "postal_code": "1000", "city": "Lisboa"},
|
||||
linked_documents=[
|
||||
{"id": "q1", "document_kind": "quotation", "document_number": "ORC.ORC2026.194", "status": "completed"},
|
||||
{"id": "i1", "document_kind": "invoice", "document_number": "FA.FA2026.129", "status": "open"},
|
||||
],
|
||||
operation_snapshot={"links": [], "cards": []},
|
||||
fiscal_data_complete=True,
|
||||
)
|
||||
decision = decide_opportunity_next_action(evidence, _profile())
|
||||
assert decision.next_action.code == "PREPARE_ORDER"
|
||||
assert "sem pagamento prévio" in decision.reason or "sem exigir pagamento" in decision.next_action.description
|
||||
Reference in New Issue
Block a user