feat: add BLIF Flow v2 authoritative operational adapter

This commit is contained in:
plx
2026-08-16 01:15:26 +00:00
parent 7cc9fecbdc
commit fc092a96b6
10 changed files with 531 additions and 23 deletions

View File

@@ -672,6 +672,42 @@ def get_operations_summary(limit: int = 24) -> Dict[str, Any]:
conversation_timeline = {str(row["conversation_id"]): dict(row) for row in timeline_rows}
seed_rows = [dict(r) for r in work_seed_rows]
# In authoritative mode the factual projection, not a legacy task/stage,
# selects material processes that have current business work. Synthetic
# rows are read-model seeds only and are never persisted.
if str(settings.blif_flow_v2_mode or "off").strip().lower() == "authoritative":
seeded = {str(row.get("opportunity_id") or "") for row in seed_rows}
with engine.connect() as conn:
v2_seeds = conn.execute(text("""
SELECT p.opportunity_id::text, p.business_next_action, p.derived_at,
o.title, o.value_amount, o.currency, o.lifecycle_state,
c.name AS customer_name
FROM opportunity_flow_state_v2 p
JOIN opportunities o ON o.id = p.opportunity_id
LEFT JOIN customers c ON c.id = o.local_customer_id
WHERE p.is_duplicate_representation = false
AND (p.business_next_action IS NOT NULL
OR p.business_state IN ('AWAITING_CUSTOMER', 'AWAITING_PAYMENT'))
""")).mappings().all()
for projection_seed in v2_seeds:
oid = str(projection_seed["opportunity_id"])
if oid in seeded:
continue
seed_rows.append({
"source": "flow_v2", "id": oid, "opportunity_id": oid,
"created_at": projection_seed.get("derived_at"), "due_at": None,
"priority": "normal", "queue": "vendas",
"action_code": projection_seed.get("business_next_action"), "status": "projected",
"title": projection_seed.get("title") or "Oportunidade",
"opportunity_title": projection_seed.get("title") or "",
"customer_name": projection_seed.get("customer_name") or "",
"fiscal_customer_name": projection_seed.get("customer_name") or "",
"item_metadata": {}, "opportunity_metadata": {},
"opportunity_lifecycle_state": projection_seed.get("lifecycle_state") or "",
"opportunity_value_amount": projection_seed.get("value_amount") or 0,
"opportunity_currency": projection_seed.get("currency") or "EUR",
"href": f"/opportunities/{oid}", "action_label": "Abrir",
})
for row in seed_rows:
timeline = conversation_timeline.get(str(row.get("conversation_id") or ""), {})
row.update({key: timeline.get(key) for key in ("latest_public_inbound", "latest_public_outbound")})