Actualizar backend/leads_logic.py
This commit is contained in:
@@ -1,4 +1,14 @@
|
|||||||
# backend/leads_logic.py
|
# backend/leads_logic.py
|
||||||
|
|
||||||
|
# Ganchos de clasificacion por JSON (los setea services.py al arrancar). Si estan
|
||||||
|
# definidos, meta_curso/tipo_programa_curso los usan; si no, cae al metodo viejo.
|
||||||
|
_CLASIF_SEDE = None # funcion(dsc_programa) -> sede
|
||||||
|
_CLASIF_PROG = None # funcion(dsc_programa) -> TEAC/TERC/SEMINARIOS/OTROS
|
||||||
|
|
||||||
|
def set_clasificadores(f_sede, f_prog):
|
||||||
|
global _CLASIF_SEDE, _CLASIF_PROG
|
||||||
|
_CLASIF_SEDE = f_sede
|
||||||
|
_CLASIF_PROG = f_prog
|
||||||
"""
|
"""
|
||||||
Lógica del módulo LEADS. Traduce las medidas DAX del PBI a Python.
|
Lógica del módulo LEADS. Traduce las medidas DAX del PBI a Python.
|
||||||
Columnas calculadas replicadas:
|
Columnas calculadas replicadas:
|
||||||
@@ -97,6 +107,11 @@ def grupo_programa_curso(dsc_programa):
|
|||||||
SEMINARIOS = SEMINARIOS
|
SEMINARIOS = SEMINARIOS
|
||||||
OTROS = OTROS + CARRERA"""
|
OTROS = OTROS + CARRERA"""
|
||||||
tp = tipo_programa_curso(dsc_programa)
|
tp = tipo_programa_curso(dsc_programa)
|
||||||
|
# Con el clasificador por JSON, tipo_programa_curso ya devuelve las 4 categorias
|
||||||
|
# simples (TEAC/TERC/SEMINARIOS/OTROS) -> se devuelven tal cual.
|
||||||
|
if tp in ("TEAC", "TERC", "SEMINARIOS", "OTROS"):
|
||||||
|
return tp
|
||||||
|
# Compatibilidad con el metodo viejo (nombres detallados sin JSON).
|
||||||
if tp in ("PROGRAMAS TEAC", "PROVINCIA TEAC"):
|
if tp in ("PROGRAMAS TEAC", "PROVINCIA TEAC"):
|
||||||
return "TEAC"
|
return "TEAC"
|
||||||
if tp in ("PROGRAMAS TERC", "PROVINCIA TERC"):
|
if tp in ("PROGRAMAS TERC", "PROVINCIA TERC"):
|
||||||
@@ -162,8 +177,10 @@ def tipo_programa_cohorte(sede, programa_cat):
|
|||||||
|
|
||||||
|
|
||||||
def tipo_programa_curso(dsc_programa):
|
def tipo_programa_curso(dsc_programa):
|
||||||
"""Réplica EXACTA del DAX Tipo_Programa (columna calculada de Fact_SQL_Base_Cursos).
|
"""Tipo de programa. Si hay clasificador por JSON, devuelve directo las 4
|
||||||
Usa CONTAINSSTRING en el mismo ORDEN que el PBI (el orden importa)."""
|
categorias simples (TEAC/TERC/SEMINARIOS/OTROS), igual que Ocupabilidad."""
|
||||||
|
if _CLASIF_PROG:
|
||||||
|
return _CLASIF_PROG(dsc_programa) # TEAC / TERC / SEMINARIOS / OTROS
|
||||||
p = str(dsc_programa or "")
|
p = str(dsc_programa or "")
|
||||||
def has(s): # CONTAINSSTRING es sensible a may/min en DAX; comparamos tal cual
|
def has(s): # CONTAINSSTRING es sensible a may/min en DAX; comparamos tal cual
|
||||||
return s in p
|
return s in p
|
||||||
@@ -215,8 +232,15 @@ def tipo_programa_curso(dsc_programa):
|
|||||||
|
|
||||||
|
|
||||||
def meta_curso(dsc_programa):
|
def meta_curso(dsc_programa):
|
||||||
"""Meta por curso según Tipo_Programa (igual que el DAX Meta_Curso):
|
"""Meta por curso: LIMA TEAC/TERC=22, PROVINCIA TEAC/TERC=18, resto=15.
|
||||||
PROGRAMAS TEAC/TERC=22, PROVINCIA TEAC/TERC=18, resto=15."""
|
Usa la clasificacion del JSON (sede+programa) si esta disponible."""
|
||||||
|
if _CLASIF_SEDE and _CLASIF_PROG:
|
||||||
|
sede = _CLASIF_SEDE(dsc_programa)
|
||||||
|
prog = _CLASIF_PROG(dsc_programa)
|
||||||
|
if prog in ("TEAC", "TERC"):
|
||||||
|
return 22 if sede == "LIMA" else 18
|
||||||
|
return 15
|
||||||
|
# respaldo: metodo viejo
|
||||||
tp = tipo_programa_curso(dsc_programa)
|
tp = tipo_programa_curso(dsc_programa)
|
||||||
if tp in ("PROGRAMAS TEAC", "PROGRAMAS TERC"):
|
if tp in ("PROGRAMAS TEAC", "PROGRAMAS TERC"):
|
||||||
return 22
|
return 22
|
||||||
@@ -474,10 +498,14 @@ def leads_por_dia(leads, ano, mes, dia):
|
|||||||
|
|
||||||
# ── Tabla por Sede_Act -> Tipo_Programa con 4 medidas (cohorte de leads) ──
|
# ── Tabla por Sede_Act -> Tipo_Programa con 4 medidas (cohorte de leads) ──
|
||||||
def tabla_pauta(leads, matriculas, ano, mes, dia, importe_por_pauta_periodo=None,
|
def tabla_pauta(leads, matriculas, ano, mes, dia, importe_por_pauta_periodo=None,
|
||||||
resultados_por_pauta_periodo=None, campanias_sede_cargo=None):
|
resultados_por_pauta_periodo=None, campanias_sede_cargo=None,
|
||||||
|
codigos_branding=None):
|
||||||
importe_por_pauta_periodo = importe_por_pauta_periodo or {}
|
importe_por_pauta_periodo = importe_por_pauta_periodo or {}
|
||||||
resultados_por_pauta_periodo = resultados_por_pauta_periodo or {}
|
resultados_por_pauta_periodo = resultados_por_pauta_periodo or {}
|
||||||
campanias_sede_cargo = campanias_sede_cargo or {}
|
campanias_sede_cargo = campanias_sede_cargo or {}
|
||||||
|
# Codigos (pautas) de BRANDING/COPEAIRE: su importe suma normal, pero sus
|
||||||
|
# resultados NO se cuentan (se ponen en 0).
|
||||||
|
codigos_branding = codigos_branding or set()
|
||||||
# 1) Leads únicos del periodo con su teléfono, fecha, sede y tipo
|
# 1) Leads únicos del periodo con su teléfono, fecha, sede y tipo
|
||||||
lp = [l for l in leads if l["es_unico"] and _en_periodo(l["fecha"], ano, mes, dia)]
|
lp = [l for l in leads if l["es_unico"] and _en_periodo(l["fecha"], ano, mes, dia)]
|
||||||
# mapa teléfono -> fecha del lead (para "matrícula posterior al lead")
|
# mapa teléfono -> fecha del lead (para "matrícula posterior al lead")
|
||||||
@@ -541,6 +569,8 @@ def tabla_pauta(leads, matriculas, ano, mes, dia, importe_por_pauta_periodo=None
|
|||||||
continue
|
continue
|
||||||
se = str(info.get("sede") or "").upper()
|
se = str(info.get("sede") or "").upper()
|
||||||
tp = grupo_tipo_cohorte(tipo_programa_cohorte(se, info.get("cargo")))
|
tp = grupo_tipo_cohorte(tipo_programa_cohorte(se, info.get("cargo")))
|
||||||
|
# Guarda el resultado REAL (para mostrarlo en el detalle del codigo).
|
||||||
|
# Los BRANDING/COPEAIRE no se restan aqui, sino al sumar subtotales/total.
|
||||||
res_st.setdefault((se, tp), {})[str(cod).strip()] = int(res_val or 0)
|
res_st.setdefault((se, tp), {})[str(cod).strip()] = int(res_val or 0)
|
||||||
|
|
||||||
filas = []
|
filas = []
|
||||||
@@ -558,10 +588,14 @@ def tabla_pauta(leads, matriculas, ano, mes, dia, importe_por_pauta_periodo=None
|
|||||||
d = cods[cod]
|
d = cods[cod]
|
||||||
imp_cod = float(imp_map.get(str(cod).strip(), 0.0))
|
imp_cod = float(imp_map.get(str(cod).strip(), 0.0))
|
||||||
res_cod = int(res_map.get(str(cod).strip(), 0))
|
res_cod = int(res_map.get(str(cod).strip(), 0))
|
||||||
|
# El detalle muestra el resultado REAL; pero si es branding NO suma
|
||||||
|
# al subtotal ni al total.
|
||||||
|
es_brand = str(cod).strip() in codigos_branding
|
||||||
codigos.append({"codigo": cod, **_fila(d), "importe": round(imp_cod, 2),
|
codigos.append({"codigo": cod, **_fila(d), "importe": round(imp_cod, 2),
|
||||||
"resultados": res_cod})
|
"resultados": res_cod})
|
||||||
t_rec += d["recibidos"]; t_proc += d["procesados"]
|
t_rec += d["recibidos"]; t_proc += d["procesados"]
|
||||||
t_mats |= d["mats"]; t_inv += d["inv"]; t_imp += imp_cod; t_res += res_cod
|
t_mats |= d["mats"]; t_inv += d["inv"]; t_imp += imp_cod
|
||||||
|
t_res += (0 if es_brand else res_cod)
|
||||||
subfilas.append({
|
subfilas.append({
|
||||||
"tipo": tp, "recibidos": t_rec, "procesados": t_proc,
|
"tipo": tp, "recibidos": t_rec, "procesados": t_proc,
|
||||||
"matriculas": len(t_mats), "inversion": round(t_inv, 0),
|
"matriculas": len(t_mats), "inversion": round(t_inv, 0),
|
||||||
@@ -582,7 +616,8 @@ def tabla_pauta(leads, matriculas, ano, mes, dia, importe_por_pauta_periodo=None
|
|||||||
t_imp = round(sum(float(v or 0.0) for cod, v in importe_por_pauta_periodo.items()
|
t_imp = round(sum(float(v or 0.0) for cod, v in importe_por_pauta_periodo.items()
|
||||||
if str(cod).strip() in campanias_sede_cargo), 2)
|
if str(cod).strip() in campanias_sede_cargo), 2)
|
||||||
t_res = sum(int(v or 0) for cod, v in resultados_por_pauta_periodo.items()
|
t_res = sum(int(v or 0) for cod, v in resultados_por_pauta_periodo.items()
|
||||||
if str(cod).strip() in campanias_sede_cargo)
|
if str(cod).strip() in campanias_sede_cargo
|
||||||
|
and str(cod).strip() not in codigos_branding)
|
||||||
# matrículas total: unión global
|
# matrículas total: unión global
|
||||||
all_mats = set()
|
all_mats = set()
|
||||||
for tel, e in mat_por_tel.items():
|
for tel, e in mat_por_tel.items():
|
||||||
@@ -660,7 +695,8 @@ def matriz_cursos(cursos, leads, ano, mes, dia, pauta_map=None,
|
|||||||
campanias_map=None, cartera_all=None, cartera_asig=None,
|
campanias_map=None, cartera_all=None, cartera_asig=None,
|
||||||
mat_por_indice=None, cartera_tels=None, cartera_origen=None,
|
mat_por_indice=None, cartera_tels=None, cartera_origen=None,
|
||||||
importe_por_pauta=None, importe_por_pauta_periodo=None,
|
importe_por_pauta=None, importe_por_pauta_periodo=None,
|
||||||
cartera_canal=None, conjunto_por_pauta=None, pautas_por_indice=None):
|
cartera_canal=None, conjunto_por_pauta=None, pautas_por_indice=None,
|
||||||
|
resultados_por_pauta=None):
|
||||||
pauta_map = pauta_map or {}
|
pauta_map = pauta_map or {}
|
||||||
pautas_por_indice = pautas_por_indice or {} # {num_indice: [pautas]} (muchos-a-muchos)
|
pautas_por_indice = pautas_por_indice or {} # {num_indice: [pautas]} (muchos-a-muchos)
|
||||||
campanias_map = campanias_map or {}
|
campanias_map = campanias_map or {}
|
||||||
@@ -671,6 +707,7 @@ def matriz_cursos(cursos, leads, ano, mes, dia, pauta_map=None,
|
|||||||
cartera_origen = cartera_origen or {}
|
cartera_origen = cartera_origen or {}
|
||||||
importe_por_pauta = importe_por_pauta or {}
|
importe_por_pauta = importe_por_pauta or {}
|
||||||
importe_por_pauta_periodo = importe_por_pauta_periodo or {}
|
importe_por_pauta_periodo = importe_por_pauta_periodo or {}
|
||||||
|
resultados_por_pauta = resultados_por_pauta or {}
|
||||||
conjunto_por_pauta = conjunto_por_pauta or {} # {pauta: [conjuntos de anuncios]}
|
conjunto_por_pauta = conjunto_por_pauta or {} # {pauta: [conjuntos de anuncios]}
|
||||||
# cartera_canal = {"PAUTA": {"all","asig","tels"}, "OTROS": {...}} para el desglose por canal
|
# cartera_canal = {"PAUTA": {"all","asig","tels"}, "OTROS": {...}} para el desglose por canal
|
||||||
cartera_canal = cartera_canal or {}
|
cartera_canal = cartera_canal or {}
|
||||||
@@ -734,6 +771,9 @@ def matriz_cursos(cursos, leads, ano, mes, dia, pauta_map=None,
|
|||||||
pre.append({
|
pre.append({
|
||||||
"num_indice": ni,
|
"num_indice": ni,
|
||||||
"personalizado": nombre,
|
"personalizado": nombre,
|
||||||
|
# Nombre real del curso (para enlazar al apartado PROGRAMA, cuyo filtro
|
||||||
|
# usa dsc_det_programa). Solo se agrega; no cambia nada mas.
|
||||||
|
"dsc_det_programa": str(c.get("dsc_det_programa") or c.get("dsc_programa") or "").strip(),
|
||||||
"fch": fch,
|
"fch": fch,
|
||||||
"pauta": cods[0] if cods else None, # pauta principal (para mostrar)
|
"pauta": cods[0] if cods else None, # pauta principal (para mostrar)
|
||||||
"pautas": cods, # todas las pautas (para sumar)
|
"pautas": cods, # todas las pautas (para sumar)
|
||||||
@@ -816,6 +856,8 @@ def matriz_cursos(cursos, leads, ano, mes, dia, pauta_map=None,
|
|||||||
importe_pauta = round(sum(float(importe_por_pauta.get(str(cd), 0.0)) for cd in cods), 2)
|
importe_pauta = round(sum(float(importe_por_pauta.get(str(cd), 0.0)) for cd in cods), 2)
|
||||||
# IMPORTE PAUTA EN EL MES: igual, pero solo del periodo filtrado.
|
# IMPORTE PAUTA EN EL MES: igual, pero solo del periodo filtrado.
|
||||||
importe_pauta_mes = round(sum(float(importe_por_pauta_periodo.get(str(cd), 0.0)) for cd in cods), 2)
|
importe_pauta_mes = round(sum(float(importe_por_pauta_periodo.get(str(cd), 0.0)) for cd in cods), 2)
|
||||||
|
# LEADS META: Resultados TOTALES de la pauta (sin filtro de fecha).
|
||||||
|
resultados_pauta = int(sum(float(resultados_por_pauta.get(str(cd), 0.0)) for cd in cods))
|
||||||
|
|
||||||
# ── SUBFILAS por CANAL (PAUTA / OTROS) ── mismo criterio que la fila padre
|
# ── SUBFILAS por CANAL (PAUTA / OTROS) ── mismo criterio que la fila padre
|
||||||
# (SEDE+PROGRAMA vía campanias, misma fecha) + filtro de canal desde cartera.
|
# (SEDE+PROGRAMA vía campanias, misma fecha) + filtro de canal desde cartera.
|
||||||
@@ -870,10 +912,12 @@ def matriz_cursos(cursos, leads, ano, mes, dia, pauta_map=None,
|
|||||||
filas.append({
|
filas.append({
|
||||||
"num_indice": r["num_indice"],
|
"num_indice": r["num_indice"],
|
||||||
"personalizado": r["personalizado"],
|
"personalizado": r["personalizado"],
|
||||||
|
"dsc_det_programa": r.get("dsc_det_programa", ""), # para enlazar al apartado PROGRAMA
|
||||||
"fecha_inicio": r["fecha_inicio"],
|
"fecha_inicio": r["fecha_inicio"],
|
||||||
"pauta": r.get("pauta"),
|
"pauta": r.get("pauta"),
|
||||||
"importe_pauta": importe_pauta,
|
"importe_pauta": importe_pauta,
|
||||||
"importe_pauta_mes": importe_pauta_mes,
|
"importe_pauta_mes": importe_pauta_mes,
|
||||||
|
"resultados_pauta": resultados_pauta,
|
||||||
"cartera_total": cartera_total,
|
"cartera_total": cartera_total,
|
||||||
"cartera_total_asig": cartera_total_asig,
|
"cartera_total_asig": cartera_total_asig,
|
||||||
"matriculas_no_iden": matriculas_no_iden,
|
"matriculas_no_iden": matriculas_no_iden,
|
||||||
|
|||||||
Reference in New Issue
Block a user