""" check_call_tz.py — what timezone does validation.call_timezone() give for a number, and how many of the CRM's real leads resolve to a zone at all? Read-only. Two parts: 1. A few known numbers with the zone they SHOULD map to (PASS/FAIL). 2. Every lead in the DB: how many resolve to a timezone, the distribution, and a sample of the ones that come back unknown (toll-free, area codes spanning two zones, no country). uv run python scripts/check_call_tz.py uv run python scripts/check_call_tz.py --unknown 30 # print more unknown rows uv run python scripts/check_call_tz.py --sample 20 # cross-check real leads by eye --sample N picks N random leads that resolved to a timezone and prints, for each, what libphonenumber's OWN geography database says the number belongs to (city / state, from the area code) next to the timezone we derived and the local time right now -- so you can check "212 -> New York -> 6:04 AM" against a world clock yourself instead of trusting the code. """ from __future__ import annotations import argparse import random import sys from collections import Counter from datetime import datetime, timezone from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from sqlalchemy import select # noqa: E402 from app.database import SessionLocal # noqa: E402 from app.models import Lead # noqa: E402 from app.services.validation import call_timezone # noqa: E402 # (phone, country hint, expected zone or "" for unknown) KNOWN = [ ("+1 214-555-0142", "US", "America/Chicago"), # Dallas ("+1 212-555-0142", "US", "America/New_York"), # New York ("+1 310-555-0142", "US", "America/Los_Angeles"), # Los Angeles ("+1 604-555-0142", "CA", "America/Vancouver"), # Vancouver ("+44 20 7946 0958", "GB", "Europe/London"), ("+971 4 555 0142", "AE", "Asia/Dubai"), ("+1 800-555-0142", "US", ""), # toll-free, US multi-zone -> unknown ("+1 800-555-0142", "", ""), ("", "GB", "Europe/London"), # no number, single-zone country ("", "US", ""), ] def _print_sample(leads, n: int) -> None: import phonenumbers from phonenumbers import geocoder try: from zoneinfo import ZoneInfo except ImportError: # pragma: no cover ZoneInfo = None # type: ignore[assignment] pool = [l for l in leads if call_timezone(l.contact_phone or "", l.phone_country or l.country or "")] picks = random.sample(pool, min(n, len(pool))) now_utc = datetime.now(timezone.utc) print(f"\n3. Cross-check sample ({len(picks)} random leads). UTC now: {now_utc:%Y-%m-%d %H:%M}") print(" Compare 'number belongs to' and 'local time' with a world clock / a quick search.") warned = False for lead in picks: raw = (lead.contact_phone or "").split(",")[0].strip() if raw.startswith("00"): raw = "+" + raw[2:] region = (lead.phone_country or lead.country or "").upper() or None where = "?" try: parsed = phonenumbers.parse(raw, None if raw.startswith("+") else region) where = geocoder.description_for_number(parsed, "en") or "(country only)" except Exception: pass tz = call_timezone(lead.contact_phone or "", lead.phone_country or lead.country or "") local = "?" if ZoneInfo is not None: try: t = now_utc.astimezone(ZoneInfo(tz)) weekday = t.strftime("%a") is_open = weekday not in ("Sat", "Sun") and 9 <= t.hour < 17 local = f"{t:%a %H:%M} {'OPEN ' if is_open else 'closed'}" except Exception: if not warned: print(" (Windows has no IANA timezone data for Python: run uv pip install tzdata to see local times here)") warned = True print(f" #{lead.id:<5} {lead.company_name[:26]:26} {raw[:19]:19} belongs to: {where[:22]:22} tz={tz:20} local={local}") def main() -> int: ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) ap.add_argument("--unknown", type=int, default=15, help="how many unknown-zone leads to print") ap.add_argument("--sample", type=int, default=0, help="cross-check N random leads (geography + local time)") args = ap.parse_args() print("1. Known numbers") bad = 0 for phone, country, want in KNOWN: got = call_timezone(phone, country) ok = got == want bad += 0 if ok else 1 print(f" {'PASS' if ok else 'FAIL'} {phone or '(none)':20} {country or '-':3} -> {got or 'unknown':22} (want {want or 'unknown'})") db = SessionLocal() try: leads = list(db.scalars(select(Lead)).all()) finally: db.close() zones: Counter = Counter() unknown: list[Lead] = [] for lead in leads: tz = call_timezone(lead.contact_phone or "", lead.phone_country or lead.country or "") zones[tz or "(unknown)"] += 1 if not tz: unknown.append(lead) total = len(leads) known = total - len(unknown) no_phone = sum(1 for l in unknown if not (l.contact_phone or "").strip()) has_phone_total = sum(1 for l in leads if (l.contact_phone or "").strip()) print(f"\n2. {total} lead(s) in the CRM: {known} resolve to a timezone, {len(unknown)} unknown" + (f" ({100 * known // total}% known)" if total else "")) print(f" of the {len(unknown)} unknown: {no_phone} have NO phone number at all, " f"{len(unknown) - no_phone} have a number but no single timezone (toll-free / multi-zone area code)") print(f" leads with any phone number: {has_phone_total} of {total}" + (f" ({100 * has_phone_total // total}%)" if total else "")) for tz, n in zones.most_common(): print(f" {n:>5} {tz}") if unknown: print(f"\n Unknown sample (first {min(args.unknown, len(unknown))}):") for lead in unknown[: args.unknown]: print( f" #{lead.id:<5} {lead.company_name[:32]:32} phone={lead.contact_phone[:22]:22} " f"country={lead.country or '-':3} phone_country={lead.phone_country or '-'}" ) if args.sample: _print_sample(leads, args.sample) print("\nRESULT:", "all known-number checks passed" if not bad else f"{bad} known-number check(s) FAILED") return 0 if not bad else 1 if __name__ == "__main__": sys.exit(main())