Actualizar backend/modules/cobranza/processor.py

This commit is contained in:
2026-10-05 13:36:41 -05:00
parent 1ff3dde86d
commit 86800569e9

View File

@@ -388,7 +388,7 @@ class CobranzaProcessor:
def obtener_datos_procesados(self, ano, mes, sectorista_filtro="TODOS", agrupacion="SEDE",
sede_filtro="TODOS", prog_filtro="TODOS", venc_hasta=None,
mats_retirar=None):
mats_retirar=None, frec_filtro="TODOS"):
fecha_filtro, fecha_filtro_siguiente = self.obtener_fechas_filtro(ano, mes)
hoy = datetime.now()
# Filtro adicional por F. Vencimiento: solo cuotas con vencimiento <= venc_hasta.
@@ -414,6 +414,8 @@ class CobranzaProcessor:
indices_cronograma = set()
mapa_tc = {}
mapa_programa = {}
mapa_clasif = {} # mat -> (sede_meta, filtro_prog) para filtrar por alumno
mapa_frec = {} # mat -> frecuencia (cod_frecuencia) para filtrar por alumno
mapa_sectorista = {} # <-- NUEVO MAPA PARA CORREGIR ASESORES
# Sectorista puede venir con varios separados por pipe (multi). Vacío/TODOS = todos.
@@ -425,6 +427,9 @@ class CobranzaProcessor:
_sede_all = (not _sede_set) or ("TODOS" in _sede_set)
_prog_set = {p.strip().upper() for p in str(prog_filtro or "TODOS").split(",") if p.strip()}
_prog_all = (not _prog_set) or ("TODOS" in _prog_set)
# Frecuencia multi (coma). Vacío/TODOS = todas.
_frec_set = {f.strip().upper() for f in str(frec_filtro or "TODOS").split(",") if f.strip()}
_frec_all = (not _frec_set) or ("TODOS" in _frec_set)
for fila in cronograma_raw:
sectorista_str = str(fila.get('dsc_sectorista', ''))
@@ -451,20 +456,35 @@ class CobranzaProcessor:
prog = str(fila.get('dsc_det_programa', '')).strip()
mapa_programa[mat] = prog if (prog and prog != "None") else "SIN PROGRAMA"
# Clasificación SEDE/PROGRAMA por MATRICULA (1ª cuota), para filtrar por
# alumno completo igual que el detalle (Ver), no cuota por cuota.
# Usa dsc_det_programa (el MISMO campo que el detalle/Ver).
if mat not in mapa_clasif:
_pm = str(fila.get('dsc_det_programa', '')).strip()
if not _pm or _pm == "None": _pm = "SIN PROGRAMA"
mapa_clasif[mat] = (
str(self.clasificar_sede_meta(_pm)).upper(),
str(self.clasificar_filtro_programa(_pm)).upper(),
)
# Frecuencia por MATRICULA (1ª cuota), para filtrar por alumno.
if mat not in mapa_frec:
_fm = str(fila.get('cod_frecuencia', '')).strip().upper()
mapa_frec[mat] = _fm if _fm and _fm != "NONE" else ""
for fila in cronograma_raw:
idx = str(fila.get('num_indice', '')).strip()
if idx not in indices_cronograma: continue
mat = str(fila.get('num_matricula', '')).strip()
# Filtro por SEDE y PROGRAMA (REPLACE_META) — se aplica en cualquier
# agrupación cuando se pide (usado sobre todo en ASESOR).
_prog = fila.get('dsc_programa', '')
if not _sede_all:
if str(self.clasificar_sede_meta(_prog)).upper() not in _sede_set:
# Filtro por SEDE y PROGRAMA (REPLACE_META) — por MATRICULA (igual que "Ver").
_cs, _cp = mapa_clasif.get(mat, ("", ""))
if not _sede_all and _cs not in _sede_set:
continue
if not _prog_all:
if str(self.clasificar_filtro_programa(_prog)).upper() not in _prog_set:
if not _prog_all and _cp not in _prog_set:
continue
if not _frec_all and mapa_frec.get(mat, "") not in _frec_set:
continue
# Filtro por F. Vencimiento (<=). Sin fecha => se incluye siempre.
@@ -519,13 +539,13 @@ class CobranzaProcessor:
mat_factura = str(fila.get('num_matricula', '')).strip()
tc_correcto = mapa_tc.get(mat_factura, 1.0)
# Mismo filtro SEDE/PROGRAMA (REPLACE_META) que en el cronograma.
_progF = fila.get('dsc_programa', '')
if not _sede_all:
if str(self.clasificar_sede_meta(_progF)).upper() not in _sede_set:
# Mismo filtro SEDE/PROGRAMA por MATRICULA (igual que el cronograma y "Ver").
_csF, _cpF = mapa_clasif.get(mat_factura, ("", ""))
if not _sede_all and _csF not in _sede_set:
continue
if not _prog_all:
if str(self.clasificar_filtro_programa(_progF)).upper() not in _prog_set:
if not _prog_all and _cpF not in _prog_set:
continue
if not _frec_all and mapa_frec.get(mat_factura, "") not in _frec_set:
continue
# Filtro por F. Vencimiento (<=). En facturas la fecha es fch_vencimiento_cuota.
@@ -666,11 +686,14 @@ class CobranzaProcessor:
# =========================================================================
# DESGLOSE POR ALUMNO/MATRÍCULA
# =========================================================================
def obtener_detalle_programa(self, ano, mes, sectorista_filtro, programa_nombre, venc_hasta=None):
def obtener_detalle_programa(self, ano, mes, sectorista_filtro, programa_nombre, venc_hasta=None, frec_filtro="TODOS"):
fecha_filtro, fecha_filtro_siguiente = self.obtener_fechas_filtro(ano, mes)
hoy = datetime.now()
# Filtro por F. Vencimiento (<=). Sin fecha => se incluye siempre.
venc_corte = self.parse_corte_venc(venc_hasta)
# Frecuencia multi (coma). Vacío/TODOS = todas.
_frec_set = {f.strip().upper() for f in str(frec_filtro or "TODOS").split(",") if f.strip()}
_frec_all = (not _frec_set) or ("TODOS" in _frec_set)
try:
cronograma_raw, facturas_raw = self._obtener_datos_cached(ano)
@@ -699,6 +722,10 @@ class CobranzaProcessor:
if programa_nombre != "TODOS":
if self._aplicar_reemplazos_nombre(prog) != programa_nombre: continue
if not _frec_all:
_fm = str(fila.get('cod_frecuencia', '')).strip().upper()
if (_fm if _fm and _fm != "NONE" else "") not in _frec_set: continue
idx = str(fila.get('num_indice', '')).strip()
if idx: indices_cronograma.add(idx)