import os, csv import requests from dotenv import load_dotenv from collections import Counter load_dotenv() # datos_unificados vive en el proyecto SUPABASE_URL2 / SUPABASE_KEY2 (el del sync) url = (os.getenv("SUPABASE_URL2") or os.getenv("SUPABASE_URL") or os.getenv("CARTERA_URL") or "") key = (os.getenv("SUPABASE_KEY2") or os.getenv("SUPABASE_KEY") or os.getenv("CARTERA_KEY") or "") t = "datos_unificados" assert url and key, "Falta SUPABASE_URL2 / SUPABASE_KEY2 (o SUPABASE_URL/KEY) en .env" sel = "Ejecutivo,Telefono,Fechacreada,Sede,Programa,Canal,Codigo,Codigo_Vendedor" paso, desde = 1000, 0 out = [] while True: hdr = {"apikey": key, "Authorization": f"Bearer {key}", "Range-Unit": "items", "Range": f"{desde}-{desde + paso - 1}"} r = requests.get(f"{url}/rest/v1/{t}", params={"select": sel, "order": "id.asc"}, headers=hdr, timeout=60) r.raise_for_status() data = r.json() if not data: break out.extend(data) desde += len(data) print(f" descargadas: {desde}", end="\r") print(f"\n\nTOTAL filas en datos_unificados: {len(out)}") def _tel_vacio(v): s = str(v or "") for x in ("+51", "+", " ", "-", "(", ")", ".0"): s = s.replace(x, "") s = s.strip() if not s or s in ("-", "nan") or set(s) == {"0"}: return True return s.isdigit() and len(s) <= 6 vacios = sum(1 for x in out if _tel_vacio(x.get("Telefono"))) print(f"Filas con teléfono VÁLIDO: {len(out) - vacios}") print(f"Filas BASURA (sin teléfono): {vacios}") # desglose por sede (para ver de qué Excel viene la basura) sede_basura = Counter() for x in out: if _tel_vacio(x.get("Telefono")): sede_basura[str(x.get("Sede") or "").strip().upper()] += 1 print("\nBASURA por SEDE:") for s, n in sede_basura.most_common(12): print(f" {s if s else '(vacio)':16} {n}") salida = "datos_unificados.csv" with open(salida, "w", newline="", encoding="utf-8-sig") as f: w = csv.DictWriter(f, fieldnames=sel.split(",")) w.writeheader() for x in out: w.writerow({k: x.get(k, "") for k in sel.split(",")}) print(f"\nExportado a: {salida}")