Spaces:
Running
Running
File size: 3,097 Bytes
831da15 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | """
check_callback_edit.py -- offline: a callback date/time can be set from the Edit form, and it reads back as
the exact wall-clock time that was typed (user, 2026-09-24).
uv run python scripts/check_callback_edit.py
No database, no network -- throwaway in-memory SQLite. Covers:
* a Callback Scheduled recorded WITHOUT a time (what the old production button did) leaves callback_at empty
* UpdateLeadInput now accepts callback_at, and update_lead() saves it
* LeadOut serializes it as naive wall-clock ISO (no "Z"/offset) -- it used to go through _dt_utc, which made
the browser shift a typed 3:00 PM to 8:00 PM in PKT
* an unrelated edit does NOT clear an existing callback_at (set-only, like every field on that model)
"""
from __future__ import annotations
import sys
from datetime import datetime
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from sqlalchemy import create_engine # noqa: E402
from sqlalchemy.orm import sessionmaker # noqa: E402
from sqlalchemy.pool import StaticPool # noqa: E402
import app.models # noqa: E402,F401
from app.crud import leads as crud_leads # noqa: E402
from app.database import Base # noqa: E402
from app.schemas.lead import LeadOut, UpdateLeadInput # noqa: E402
FAILED = 0
def check(label: str, ok: bool, detail: str = "") -> None:
global FAILED
FAILED += 0 if ok else 1
print(f" [{'ok ' if ok else 'FAIL'}] {label}" + ("" if ok else f" {detail}"))
def main() -> int:
engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool)
Base.metadata.create_all(engine)
db = sessionmaker(bind=engine)()
lead = crud_leads.add_lead_dict(db, {"company_name": "Callback Co"})
crud_leads.apply_call_outcome(db, lead, "callback_scheduled") # no callback_at, like the old button
print("\nCallback recorded without a time")
check("callback_at is empty", lead.callback_at is None)
check("last_call_outcome is callback_scheduled", lead.last_call_outcome == "callback_scheduled")
print("\nSet a time from the Edit form (UpdateLeadInput.callback_at)")
typed = datetime(2026, 9, 25, 15, 0, 0)
lead = crud_leads.update_lead(db, lead, UpdateLeadInput(callback_at=typed))
check("callback_at saved as typed", lead.callback_at == typed, str(lead.callback_at))
out = LeadOut.from_model(lead)
check("LeadOut.callback_at is naive wall-clock ISO", out.callback_at == "2026-09-25T15:00:00", out.callback_at)
check("no Z / UTC offset on it", "Z" not in out.callback_at and "+" not in out.callback_at)
check("stage untouched by setting it", lead.pipeline_stage == "followup_due", lead.pipeline_stage)
print("\nUnrelated edit leaves the callback alone")
lead = crud_leads.update_lead(db, lead, UpdateLeadInput(subject="New subject"))
check("callback_at still set", lead.callback_at == typed, str(lead.callback_at))
print(f"\n{'FAILED: ' + str(FAILED) if FAILED else 'All checks passed.'}")
return 1 if FAILED else 0
if __name__ == "__main__":
sys.exit(main())
|