feat: add BLIF Flow v2 authoritative operational adapter
This commit is contained in:
99
tests/test_authoritative_operational_adapter.py
Normal file
99
tests/test_authoritative_operational_adapter.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from app.authoritative_operational_adapter import decide_authoritative_operation
|
||||
from app.canonical_operations import canonicalize_operations
|
||||
|
||||
|
||||
NOW = datetime(2026, 8, 16, tzinfo=timezone.utc)
|
||||
|
||||
|
||||
def projection(state="AWAITING_CUSTOMER", action=None, **extra):
|
||||
return {"opportunity_id": "opp", "canonical_opportunity_id": "opp",
|
||||
"business_state": state, "business_next_action": action,
|
||||
"confidence": "high", **extra}
|
||||
|
||||
|
||||
def task(code, due=NOW, **extra):
|
||||
return {"id": code, "status": "pending", "action_code": code, "due_at": due, **extra}
|
||||
|
||||
|
||||
def test_business_baselines_and_terminal():
|
||||
for state, action in [("PROFORMA_REQUIRED", "CREATE_PROFORMA"),
|
||||
("INVOICE_REQUIRED", "CREATE_INVOICE"),
|
||||
("ODOO_ORDER_REQUIRED", "PREPARE_ORDER"),
|
||||
("ODOO_ORDER_CREATED", "VALIDATE_ODOO_ORDER")]:
|
||||
got = decide_authoritative_operation(projection(state, action), now=NOW)
|
||||
assert (got.effective_action, got.queue) == (action, "do_now")
|
||||
assert decide_authoritative_operation(projection("COMPLETED"), now=NOW).queue == "not_current"
|
||||
|
||||
|
||||
def test_missing_projection_fails_closed_without_v1():
|
||||
got = decide_authoritative_operation(None, now=NOW)
|
||||
assert (got.effective_action, got.queue, got.reason_code) == ("REVIEW_REQUIRED", "review", "MISSING_V2_PROJECTION")
|
||||
|
||||
|
||||
def test_due_and_future_customer_followup_semantics():
|
||||
due = decide_authoritative_operation(projection(), obligations=[task("FOLLOW_UP_CUSTOMER_REVIEW")], now=NOW)
|
||||
assert (due.effective_action, due.queue) == ("FOLLOW_UP_CUSTOMER_REVIEW", "do_now")
|
||||
future = decide_authoritative_operation(projection(), obligations=[task("FOLLOW_UP_CUSTOMER_REVIEW", NOW + timedelta(days=1))], now=NOW)
|
||||
assert (future.effective_action, future.queue) == (None, "waiting")
|
||||
assert decide_authoritative_operation(projection(), now=NOW).queue == "waiting"
|
||||
|
||||
|
||||
def test_only_active_non_superseded_tasks_override_and_precedence():
|
||||
stale = task("SUPPORT", resolved_at=NOW)
|
||||
assert decide_authoritative_operation(projection("PROFORMA_REQUIRED", "CREATE_PROFORMA"), obligations=[stale], now=NOW).effective_action == "CREATE_PROFORMA"
|
||||
obligations = [task("CALL_CUSTOMER"), task("SEND_INFO"), task("SUPPORT"), task("REVIEW_MANUALLY")]
|
||||
assert decide_authoritative_operation(projection(), obligations=obligations, now=NOW).effective_action == "REVIEW_MANUALLY"
|
||||
assert decide_authoritative_operation(projection(), obligations=[task("SUPPORT")], now=NOW).effective_action == "SUPPORT"
|
||||
assert decide_authoritative_operation(projection(), obligations=[task("SEND_INFO")], now=NOW).effective_action == "SEND_INFO"
|
||||
assert decide_authoritative_operation(projection(), obligations=[task("CALL_CUSTOMER")], now=NOW).effective_action == "CALL_CUSTOMER"
|
||||
|
||||
|
||||
def test_fiscal_and_reconciliation_only_block_formal_action():
|
||||
inquiry = decide_authoritative_operation(projection("INQUIRY", "SEND_INFO"), fiscal_complete=False, reconciliation_blocking=True, now=NOW)
|
||||
assert inquiry.effective_action == "SEND_INFO"
|
||||
formal = decide_authoritative_operation(projection("PROFORMA_REQUIRED", "CREATE_PROFORMA"), fiscal_complete=False, now=NOW)
|
||||
assert (formal.effective_action, formal.blocking_action_code) == ("VALIDATE_FISCAL_CUSTOMER", "VALIDATE_FISCAL_CUSTOMER")
|
||||
|
||||
|
||||
def test_duplicate_is_suppressed_even_with_pending_legacy_task():
|
||||
decision = decide_authoritative_operation(projection("REVIEW_REQUIRED", "REVIEW_REQUIRED",
|
||||
is_duplicate_representation=True,
|
||||
canonical_opportunity_id="canonical"),
|
||||
obligations=[task("REVIEW_MANUALLY")], now=NOW).to_dict()
|
||||
source = {"source": "task", "id": "t", "status": "pending", "action_code": "REVIEW_MANUALLY",
|
||||
"opportunity_id": "opp", "created_at": NOW}
|
||||
assert canonicalize_operations([source], {"opp": decision})["items"] == []
|
||||
|
||||
|
||||
def test_authoritative_queue_and_action_survive_canonical_boundary():
|
||||
decision = decide_authoritative_operation(projection(), obligations=[task("FOLLOW_UP_CUSTOMER_REVIEW")], now=NOW).to_dict()
|
||||
source = {"source": "task", "id": "old", "status": "pending", "action_code": "SEND_INVOICE",
|
||||
"opportunity_id": "opp", "created_at": NOW}
|
||||
item = canonicalize_operations([source], {"opp": decision})["items"][0]
|
||||
assert (item["action_code"], item["operational_queue"]) == ("FOLLOW_UP_CUSTOMER_REVIEW", "do_now")
|
||||
|
||||
|
||||
def test_named_case_acceptance_decisions():
|
||||
cases = {
|
||||
"5c33db95-fab8-477a-bddd-0b9cc8f91302": ("PROFORMA_REQUIRED", "CREATE_PROFORMA", [], "CREATE_PROFORMA", "do_now"),
|
||||
"fd79b9a1-07e6-4f61-95e8-09eab89c155e": ("AWAITING_CUSTOMER", None, [task("FOLLOW_UP_CUSTOMER_REVIEW")], "FOLLOW_UP_CUSTOMER_REVIEW", "do_now"),
|
||||
"61f1c955-a372-4ea7-b9b0-b8528d74a141": ("ODOO_ORDER_REQUIRED", "PREPARE_ORDER", [], "PREPARE_ORDER", "do_now"),
|
||||
"e3b23ac5-84db-4763-8a31-a684e873032c": ("ODOO_ORDER_REQUIRED", "PREPARE_ORDER", [], "PREPARE_ORDER", "do_now"),
|
||||
"dc89a466-db24-401b-bfe9-d47644b2d0c8": ("COMPLETED", None, [], None, "not_current"),
|
||||
"fd221608-e007-4043-a23d-07e0c119a345": ("REVIEW_REQUIRED", "REVIEW_REQUIRED", [], "REVIEW_REQUIRED", "review"),
|
||||
}
|
||||
for oid, (state, action, obligations, effective, queue) in cases.items():
|
||||
got = decide_authoritative_operation({**projection(state, action), "opportunity_id": oid,
|
||||
"canonical_opportunity_id": oid},
|
||||
obligations=obligations, now=NOW)
|
||||
assert (got.effective_action, got.queue) == (effective, queue)
|
||||
for duplicate, canonical in [
|
||||
("1816a06e-9a69-4a9b-9279-1263156892d3", "dc89a466-db24-401b-bfe9-d47644b2d0c8"),
|
||||
("434124fb-ac19-4d78-909a-55761d7e8daa", "fd221608-e007-4043-a23d-07e0c119a345"),
|
||||
]:
|
||||
got = decide_authoritative_operation({**projection("REVIEW_REQUIRED", "REVIEW_REQUIRED"),
|
||||
"opportunity_id": duplicate, "canonical_opportunity_id": canonical,
|
||||
"is_duplicate_representation": True}, now=NOW)
|
||||
assert (got.effective_action, got.queue, got.canonical_opportunity_id) == (None, "not_current", canonical)
|
||||
Reference in New Issue
Block a user