Files
clientflow_backend/scripts/reopen_chatwoot_review_tasks.py
2026-06-09 22:55:58 +01:00

72 lines
2.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""Reabre tasks Chatwoot que foram classificadas como revisão/remoção mas ficaram skipped.
Uso seguro:
PYTHONPATH=. python scripts/reopen_chatwoot_review_tasks.py --dry-run
PYTHONPATH=. python scripts/reopen_chatwoot_review_tasks.py --days 7
Por defeito só olha para os últimos 7 dias e não toca em spam/NO_ACTION.
"""
from __future__ import annotations
import argparse
import json
from sqlalchemy import text
from app.db import engine
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--days", type=int, default=7, help="Janela de dias a corrigir")
parser.add_argument("--dry-run", action="store_true", help="Mostra o que faria sem alterar")
args = parser.parse_args()
params = {"days": int(args.days)}
select_sql = text("""
SELECT id::text, created_at, action_code, route, action, status, conversation_id, contact_id
FROM tasks
WHERE source_system = 'chatwoot'
AND status = 'skipped'
AND action_code IN ('REVIEW_MANUALLY', 'REMOVE_FROM_LIST')
AND created_at >= now() - (:days * interval '1 day')
ORDER BY created_at DESC
""")
with engine.begin() as conn:
rows = conn.execute(select_sql, params).mappings().all()
print(f"Encontradas {len(rows)} task(s) Chatwoot a reabrir.")
for row in rows[:50]:
print(f"- {row['created_at']} {row['action_code']} conversa={row['conversation_id']} task={row['id']}")
if args.dry_run or not rows:
print("Dry-run: nenhuma alteração aplicada." if args.dry_run else "Nada para alterar.")
return 0
ids = [row["id"] for row in rows]
update_sql = text("""
UPDATE tasks
SET status = 'pending',
priority = CASE WHEN action_code = 'REVIEW_MANUALLY' THEN 'alta' ELSE COALESCE(priority, 'normal') END,
route = CASE WHEN action_code = 'REMOVE_FROM_LIST' THEN 'marketing' ELSE route END,
updated_at = now(),
metadata = COALESCE(metadata, '{}'::jsonb) || CAST(:patch AS JSONB)
WHERE id = ANY(CAST(:ids AS uuid[]))
""")
patch = json.dumps({
"v46_reopened": True,
"v46_reason": "REVIEW_MANUALLY/REMOVE_FROM_LIST devem gerar trabalho humano pendente",
}, ensure_ascii=False)
with engine.begin() as conn:
conn.execute(update_sql, {"ids": ids, "patch": patch})
print(f"Reabertas {len(ids)} task(s) como pending.")
return 0
if __name__ == "__main__":
raise SystemExit(main())