fix: preserve Chatwoot message visibility and identity

This commit is contained in:
plx
2026-08-14 14:08:23 +00:00
parent 475ff15b9b
commit c4d55d37ed
10 changed files with 531 additions and 71 deletions

View File

@@ -477,6 +477,76 @@ def link_communication_to_opportunity(communication_id: str, opportunity_id: Opt
"""), {"id": communication_id, "opportunity_id": opportunity_id or ""})
def upsert_chatwoot_inbound_communication(
*, source_message_id: str, conversation_id: Optional[str], contact_id: Optional[str],
body: str, classification: Optional[str] = None, confidence: Optional[float] = None,
status: str = "new", customer_id: Optional[str] = None,
opportunity_id: Optional[str] = None, task_id: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None,
) -> Optional[str]:
"""Materialize one inbound Chatwoot message without schema or work creation."""
if not str(source_message_id or "").strip():
return None
with engine.begin() as conn:
row = conn.execute(text("""
INSERT INTO communications (
source_system, source_message_id, conversation_id, contact_id,
direction, body, classification, confidence, status,
customer_id, opportunity_id, task_id, metadata
) VALUES (
'chatwoot', :source_message_id, :conversation_id, :contact_id,
'inbound', :body, :classification, :confidence, :status,
CAST(:customer_id AS UUID), CAST(:opportunity_id AS UUID),
CAST(:task_id AS UUID), CAST(:metadata AS JSONB)
)
ON CONFLICT (source_system, source_message_id) WHERE source_message_id IS NOT NULL
DO UPDATE SET
conversation_id=COALESCE(NULLIF(EXCLUDED.conversation_id,''), communications.conversation_id),
contact_id=COALESCE(NULLIF(EXCLUDED.contact_id,''), communications.contact_id),
body=COALESCE(NULLIF(EXCLUDED.body,''), communications.body),
classification=COALESCE(EXCLUDED.classification, communications.classification),
confidence=COALESCE(EXCLUDED.confidence, communications.confidence),
status=CASE WHEN EXCLUDED.classification IS NULL THEN communications.status ELSE EXCLUDED.status END,
customer_id=COALESCE(EXCLUDED.customer_id, communications.customer_id),
opportunity_id=COALESCE(EXCLUDED.opportunity_id, communications.opportunity_id),
task_id=COALESCE(EXCLUDED.task_id, communications.task_id),
metadata=COALESCE(communications.metadata,'{}'::jsonb) || EXCLUDED.metadata,
updated_at=now()
RETURNING id::text
"""), {"source_message_id": str(source_message_id),
"conversation_id": conversation_id or "", "contact_id": contact_id or "",
"body": body or "", "classification": classification,
"confidence": confidence, "status": status or "new",
"customer_id": customer_id or None, "opportunity_id": opportunity_id or None,
"task_id": task_id or None,
"metadata": json.dumps(metadata or {}, ensure_ascii=False, default=str)}).first()
return str(row[0]) if row else None
def enrich_chatwoot_communication_from_task(
*, source_message_id: str, classification: str, confidence: Optional[float],
ignored: bool, conversation_id: Optional[str], contact_id: Optional[str], body: str,
task_id: Optional[str], metadata: Optional[Dict[str, Any]] = None,
) -> Optional[str]:
customer_id = opportunity_id = None
if task_id:
with engine.begin() as conn:
linked = conn.execute(text("""
SELECT NULLIF(t.customer_id, '') AS customer_id, t.opportunity_id::text
FROM tasks t WHERE t.id=CAST(:task_id AS UUID)
"""), {"task_id": task_id}).mappings().first()
if linked:
customer_id = linked.get("customer_id")
opportunity_id = linked.get("opportunity_id")
return upsert_chatwoot_inbound_communication(
source_message_id=source_message_id, conversation_id=conversation_id,
contact_id=contact_id, body=body, classification=classification,
confidence=confidence, status="ignored" if ignored else "classified",
customer_id=customer_id, opportunity_id=opportunity_id, task_id=task_id,
metadata=metadata,
)
def record_outbound_communication(