""" Backfill SLA response_due and resolution_due on all tickets that have a category but no SLA dates set. """ import asyncio import os import sys from datetime import timedelta sys.path.insert(0, '/app') os.chdir('/app') from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker from sqlalchemy import text async def run(): database_url = os.environ.get( 'DATABASE_URL', 'postgresql+asyncpg://postgres:postgres@db:5432/servicemanager' ) engine = create_async_engine(database_url) async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) async with async_session() as session: # Find all tickets with a category but missing SLA dates result = await session.execute(text(""" SELECT t.id, t.created_at, c.sla_response_hours, c.sla_resolution_hours FROM tickets t JOIN ticket_categories c ON c.id = t.category_id WHERE t.sla_response_due IS NULL AND t.sla_resolution_due IS NULL """)) rows = result.fetchall() print(f"Tickets to update: {len(rows)}") updated = 0 for row in rows: ticket_id, created_at, resp_h, res_h = row # Ensure naive datetime for DB compatibility if hasattr(created_at, 'tzinfo') and created_at.tzinfo is not None: from datetime import timezone created_at = created_at.astimezone(timezone.utc).replace(tzinfo=None) sla_response_due = created_at + timedelta(hours=float(resp_h)) sla_resolution_due = created_at + timedelta(hours=float(res_h)) await session.execute(text(""" UPDATE tickets SET sla_response_due = :sla_resp, sla_resolution_due = :sla_res WHERE id = :ticket_id """), { "sla_resp": sla_response_due, "sla_res": sla_resolution_due, "ticket_id": ticket_id, }) updated += 1 await session.commit() print(f"Updated {updated} tickets with SLA dates.") # Verify r2 = await session.execute(text(""" SELECT ticket_number, sla_response_due, sla_resolution_due FROM tickets WHERE sla_response_due IS NOT NULL ORDER BY created_at LIMIT 10 """)) print("\nSample of tickets with SLA dates now:") for row in r2.fetchall(): print(f" {row[0]}: response_due={row[1]}, resolution_due={row[2]}") await engine.dispose() asyncio.run(run())