Files
fn_registry/scratchpad/gen_intel.py
T
egutierrez 2ebc9efeb2 chore: auto-commit (8 archivos)
- scratchpad/gen_docs.py
- scratchpad/gen_intel.py
- scratchpad/gen_verify.py
- scratchpad/intel_build.json
- scratchpad/intel_lineage.json
- scratchpad/lineage_graph.json
- scratchpad/trace_intel.py
- scratchpad/trace_lineage.py

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-01 19:00:06 +02:00

165 lines
8.0 KiB
Python

"""Genera 05_construccion_clientes_intel/ (SQL CTAS de cada tabla de clientes_intel)
y 00b_FUENTES_DE_CLIENTE.txt (mapa fuente-de-cliente -> consulta que la lee).
Fuente de datos: scratchpad/intel_build.json (SQL de construccion capturado de
INFORMATION_SCHEMA.JOBS) y scratchpad/intel_lineage.json (tablas implicadas).
"""
import json
import os
import textwrap
DEST = "/mnt/c/Users/egutierrez/Desktop/linaje_customer_marts"
PROJECT = "autingo-159109"
builds = json.load(open("scratchpad/intel_build.json"))
lin = json.load(open("scratchpad/intel_lineage.json"))
# Tablas para las que escribimos el SQL de construccion: las del linaje de customer_marts
# + las que leen fuentes de cliente/Salesforce.
EXTRA = ["seg_vega_persona", "fact_campana_respuesta__sfnew"]
want = sorted(set(lin["intel_involved"]) | set(EXTRA))
want = [t for t in want if t in builds] # solo las que tienen SQL capturado
DESC = {
"_persona_records":
"IDENTIDAD DEL CLIENTE (nucleo). UNION de 7 fuentes -> normaliza DNI/NIE/CIF, email y "
"telefono -> resuelve persona_id (FARM_FINGERPRINT de persona_key) con nivel de confianza. "
"AQUI es donde se juntan TPV customers, customers web, OTR, Navision, citaprevia, users y "
"Salesforce contacts_latest.",
"dim_persona":
"Dimension PERSONA final: una fila por persona_id, elegida desde _persona_records "
"(prioriza el mejor registro por fuente/confianza) + banderas de contacto.",
"dim_vehiculo":
"Dimension VEHICULO: una fila por vehiculo (matricula/bastidor) desde TPV vehicles, OTR, "
"citaprevia matriculas y calibrado de ano de matricula.",
"map_persona_fuente":
"Mapeo persona -> fuente(s) de origen (tpv/web/otr/navision/citaprevia/users/salesforce). "
"Registra de que sistemas proviene cada persona.",
"map_persona_vehiculo":
"Mapeo N:N persona <-> vehiculo (quien conduce/posee que coche) desde OTR, TPV vehicleowner "
"y citaprevia matriculas.",
"map_persona_canal8":
"Mapeo persona -> canal8 (canal de entrada del cliente).",
"fact_transaccion":
"Tabla de HECHOS de transaccion (linea/venta por persona). Base de los marts monetarios.",
"fact_visita":
"Tabla de HECHOS de visita (visitas del cliente al taller/tienda).",
"fact_campana_respuesta":
"HECHOS de respuesta a campanas: cruza envios/aperturas/clics/sms de Salesforce con personas.",
"fact_campana_respuesta__sfnew":
"Variante de fact_campana_respuesta con el esquema nuevo de Salesforce (email_sent/opened/clicked/sms).",
"feat_cliente_persona":
"Features agregadas por PERSONA (RFM, mix de canal, ticket medio, margen, recencia...).",
"feat_cliente_vehiculo":
"Features agregadas por VEHICULO.",
"seg_cliente_360":
"Segmentacion 360 del cliente (segmentos/clusters de negocio).",
"seg_vega_persona":
"Segmentacion VEGA por persona (contactabilidad/valor); lee fuentes de cliente para calcular "
"disponibilidad de contacto.",
"seg_cluster_persona":
"Clustering de personas (asignacion de cluster) que alimenta la segmentacion.",
"reco_acciones":
"Recomendaciones / proxima mejor accion (NBA) por cliente.",
"data_points_contacto":
"Puntos de dato de contacto (email/telefono) consolidados y calidad por persona.",
"_margen_rate_producto":
"Tasa de margen por producto (auxiliar para features monetarias).",
"_plate_year_calib":
"Calibrado del ano a partir de la matricula (auxiliar para dim_vehiculo).",
"dim_cp_provincia":
"Diccionario codigo postal -> provincia/CCAA.",
"tipologia_cliente":
"Tipologia de cliente (clasificacion de negocio).",
}
# Descripcion corta de cada fuente de cliente.
SRC_DESC = {
"psql_dcpublic.tpv_customers": "Clientes del TPV (mostrador). Replica Postgres ANJANA (DCPublic).",
"psql_dcpublic.customers": "Clientes web (e-commerce). Replica Postgres ANJANA (DCPublic).",
"psql_dcpublic.otr_customers": "Clientes de OTR (ordenes de reparacion/taller). Replica Postgres ANJANA.",
"psql_dcpublic.users": "Usuarios (cuentas). Replica Postgres ANJANA (DCPublic).",
"mssql2022_dbo.anjana_customer": "Cliente de NAVISION (SQL Server 2022, esquema dbo). Campos no_/e_mail/movil/name/post_code.",
"salesforce_ew1.contacts_latest": "Contactos de SALESFORCE (ultima version). Dataset en europe-west1.",
"salesforce_ew1.email_sent": "Envios de email de Salesforce (Marketing Cloud).",
"salesforce_ew1.email_opened": "Aperturas de email de Salesforce.",
"salesforce_ew1.email_clicked": "Clics de email de Salesforce.",
"salesforce_ew1.sms": "SMS de Salesforce.",
"citaprevia_aurphcp.clientes": "Clientes de CITA PREVIA (aurphcp).",
"citaprevia_aurphcp.clientes_matriculas": "Matriculas por cliente en cita previa.",
"psql_dcpublic.tpv_vehicles_vehicle": "Vehiculos del TPV. Replica Postgres ANJANA.",
"psql_dcpublic.tpv_vehicles_vehicleowner": "Propietarios de vehiculo del TPV (N:N). Replica Postgres ANJANA.",
}
CUST_SOURCES = list(SRC_DESC.keys())
SEP = "=" * 78 + "\n"
def w(path, text):
full = os.path.join(DEST, path)
os.makedirs(os.path.dirname(full), exist_ok=True)
with open(full, "w", newline="\r\n", encoding="utf-8") as f:
f.write(text)
def build_file(tbl):
b = builds[tbl]
out = [SEP, f"OBJETO : {PROJECT}.clientes_intel.{tbl}\n",
f"TIPO : TABLA BASE construida por {b['stmt']} (se reconstruye periodicamente)\n",
f"ULTIMA EJECUCION CAPTURADA: {b['last_run']}\n", SEP,
"\nQUE ES\n------\n",
textwrap.fill(DESC.get(tbl, "(sin descripcion)"), width=78) + "\n"]
if b["refs"]:
out.append("\nLEE DE (tablas fuente / intermedias)\n------------------------------------\n")
for r in b["refs"]:
note = " << FUENTE DE CLIENTE" if r in SRC_DESC else ""
out.append(f" - {PROJECT}.{r}{note}\n")
out.append("\nSQL DE CONSTRUCCION (copiable)\n------------------------------\n\n")
out.append(b["query"].strip() + "\n")
return "".join(out)
for t in want:
w(f"05_construccion_clientes_intel/{t}.txt", build_file(t))
# 00b_FUENTES_DE_CLIENTE.txt
f = [SEP, "FUENTES DE CLIENTE -> QUE CONSULTA DE clientes_intel LAS USA\n", SEP,
"\nResponde a: de donde salen los clientes (TPV, web, OTR, Navision, Salesforce, cita\n"
"previa) y en que consulta se juntan. El punto de union de identidades es\n"
"_persona_records (ver 05_construccion_clientes_intel/_persona_records.txt).\n\n"]
f.append(SEP + "RESUMEN: LO QUE PEDISTE\n" + SEP + "\n")
mapping = [
("TPV customers", "psql_dcpublic.tpv_customers"),
("customers (web)", "psql_dcpublic.customers"),
("customers (OTR / taller)", "psql_dcpublic.otr_customers"),
("users", "psql_dcpublic.users"),
("customer de NAVISION", "mssql2022_dbo.anjana_customer"),
("SALESFORCE (contactos)", "salesforce_ew1.contacts_latest"),
]
for label, src in mapping:
f.append(f" {label:26s} -> {PROJECT}.{src}\n")
f.append("\n SI: tenemos Salesforce. El dataset es `salesforce_ew1` (europe-west1):\n"
" contactos en contacts_latest; marketing en email_sent/opened/clicked y sms.\n\n")
for src in CUST_SOURCES:
consumers = sorted(t for t, b in builds.items() if src in b["refs"])
f.append(SEP)
f.append(f"{PROJECT}.{src}\n")
f.append(SEP)
f.append(f" {SRC_DESC[src]}\n")
f.append(" La leen estas tablas de clientes_intel (con su SQL en 05_construccion_...):\n")
if consumers:
for t in consumers:
star = " [SQL disponible]" if t in want else ""
f.append(f" - {t} ({builds[t]['stmt']}){star}\n")
else:
f.append(" (ninguna la referencia directamente)\n")
f.append("\n")
w("00b_FUENTES_DE_CLIENTE.txt", "".join(f))
print("Generado:")
print(f" 05_construccion_clientes_intel/ -> {len(want)} archivos con SQL de construccion")
print(f" 00b_FUENTES_DE_CLIENTE.txt")
print("\nTablas con SQL de construccion escrito:")
for t in want:
print(f" - {t}")