Solucionado submodulos y subiendo codigo real
This commit is contained in:
221
backend/modules/cobranza/logic.py
Normal file
221
backend/modules/cobranza/logic.py
Normal file
@@ -0,0 +1,221 @@
|
||||
# modules/cobranza/logic.py
|
||||
import pandas as pd
|
||||
from .processor import CobranzaProcessor
|
||||
|
||||
class CobranzaLogic:
|
||||
def __init__(self, data_manager):
|
||||
self.data_manager = data_manager
|
||||
self.processor = CobranzaProcessor(data_manager)
|
||||
|
||||
def obtener_lista_sectoristas(self, ano, mes):
|
||||
return self.processor.obtener_lista_sectoristas(ano, mes)
|
||||
|
||||
def obtener_datos_tabla(self, ano, mes, sectorista="TODOS", agrupacion="SEDE"):
|
||||
datos_brutos = self.processor.obtener_datos_procesados(ano, mes, sectorista, agrupacion)
|
||||
|
||||
sheet_data = []
|
||||
t_cta_ant = t_cta_cur = t_cta_tot = t_cob_ant = t_cob_cur = t_cob_tot = t_saldo = 0.0
|
||||
|
||||
for d in datos_brutos:
|
||||
grupo = d.get('GRUPO', '')
|
||||
frecuencia = d.get('FRECUENCIA', '-')
|
||||
num_cuota = d.get('NUM_CUOTA', '-')
|
||||
fecha_venc = d.get('FCH_VENC_MODA', '-')
|
||||
|
||||
cta_ant = float(d.get('CTA_COB_ANT', 0.0))
|
||||
cta_cur = float(d.get('CTA_COB_MES_CURSO', 0.0))
|
||||
cta_tot = float(d.get('TOTAL_CTA_COB', 0.0))
|
||||
cob_ant = float(d.get('COB_ANT', 0.0))
|
||||
r1 = float(d.get('RATIO_1', 0.0))
|
||||
cob_cur = float(d.get('COB_MES_CURSO', 0.0))
|
||||
r2 = float(d.get('RATIO_2', 0.0))
|
||||
cob_tot = float(d.get('TOTAL_COBRADO', 0.0))
|
||||
r3 = float(d.get('RATIO_3', 0.0))
|
||||
saldo = float(d.get('SALDO', 0.0))
|
||||
opciones = d.get('OPCIONES', ' ≡ ▼ ')
|
||||
|
||||
t_cta_ant += cta_ant
|
||||
t_cta_cur += cta_cur
|
||||
t_cta_tot += cta_tot
|
||||
t_cob_ant += cob_ant
|
||||
t_cob_cur += cob_cur
|
||||
t_cob_tot += cob_tot
|
||||
t_saldo += saldo
|
||||
|
||||
avance_ant = f"{r1:.0f}%" if cta_ant > 0 else ""
|
||||
avance_cur = f"{r2:.0f}%" if cta_cur > 0 else ""
|
||||
avance_tot = f"{r3:.0f}%" if cta_tot > 0 else ""
|
||||
|
||||
if agrupacion == "PROGRAMA":
|
||||
fila = [
|
||||
grupo, frecuencia, num_cuota, fecha_venc,
|
||||
f"S/ {cta_ant:,.0f}", f"S/ {cob_ant:,.0f}", avance_ant,
|
||||
f"S/ {cta_cur:,.0f}", f"S/ {cob_cur:,.0f}", avance_cur,
|
||||
f"S/ {cta_tot:,.0f}", f"S/ {cob_tot:,.0f}", avance_tot,
|
||||
f"S/ {saldo:,.0f}", opciones
|
||||
]
|
||||
else:
|
||||
fila = [
|
||||
grupo,
|
||||
f"S/ {cta_ant:,.0f}", f"S/ {cob_ant:,.0f}", avance_ant,
|
||||
f"S/ {cta_cur:,.0f}", f"S/ {cob_cur:,.0f}", avance_cur,
|
||||
f"S/ {cta_tot:,.0f}", f"S/ {cob_tot:,.0f}", avance_tot,
|
||||
f"S/ {saldo:,.0f}", opciones
|
||||
]
|
||||
sheet_data.append(fila)
|
||||
|
||||
r_tot_1 = (t_cob_ant / t_cta_ant) * 100 if t_cta_ant > 0 else 0.0
|
||||
r_tot_2 = (t_cob_cur / t_cta_cur) * 100 if t_cta_cur > 0 else 0.0
|
||||
r_tot_3 = (t_cob_tot / t_cta_tot) * 100 if t_cta_tot > 0 else 0.0
|
||||
|
||||
if agrupacion == "PROGRAMA":
|
||||
fila_total = [
|
||||
"TOTAL GENERAL", "-", "-", "-",
|
||||
f"S/ {t_cta_ant:,.0f}", f"S/ {t_cob_ant:,.0f}", f"{r_tot_1:.0f}%",
|
||||
f"S/ {t_cta_cur:,.0f}", f"S/ {t_cob_cur:,.0f}", f"{r_tot_2:.0f}%",
|
||||
f"S/ {t_cta_tot:,.0f}", f"S/ {t_cob_tot:,.0f}", f"{r_tot_3:.0f}%",
|
||||
f"S/ {t_saldo:,.0f}", ""
|
||||
]
|
||||
else:
|
||||
fila_total = [
|
||||
"TOTAL GENERAL",
|
||||
f"S/ {t_cta_ant:,.0f}", f"S/ {t_cob_ant:,.0f}", f"{r_tot_1:.0f}%",
|
||||
f"S/ {t_cta_cur:,.0f}", f"S/ {t_cob_cur:,.0f}", f"{r_tot_2:.0f}%",
|
||||
f"S/ {t_cta_tot:,.0f}", f"S/ {t_cob_tot:,.0f}", f"{r_tot_3:.0f}%",
|
||||
f"S/ {t_saldo:,.0f}", ""
|
||||
]
|
||||
sheet_data.append(fila_total)
|
||||
return sheet_data
|
||||
|
||||
def obtener_detalle_programa_formateado(self, ano, mes, sectorista, programa):
|
||||
datos_brutos = self.processor.obtener_detalle_programa(ano, mes, sectorista, programa)
|
||||
|
||||
sheet_data = []
|
||||
t_cta_ant = t_cta_cur = t_cta_tot = t_cob_ant = t_cob_cur = t_cob_tot = t_saldo = 0.0
|
||||
|
||||
for d in datos_brutos:
|
||||
mat = d.get('MATRICULA', '')
|
||||
alumno = d.get('ALUMNO', '')
|
||||
num_cuota = d.get('NUM_CUOTA', '-')
|
||||
fch_venc = d.get('FCH_VENC', '-')
|
||||
|
||||
cta_ant = float(d.get('CTA_COB_ANT', 0.0))
|
||||
cta_cur = float(d.get('CTA_COB_MES_CURSO', 0.0))
|
||||
cta_tot = float(d.get('TOTAL_CTA_COB', 0.0))
|
||||
cob_ant = float(d.get('COB_ANT', 0.0))
|
||||
cob_cur = float(d.get('COB_MES_CURSO', 0.0))
|
||||
cob_tot = float(d.get('TOTAL_COBRADO', 0.0))
|
||||
saldo = float(d.get('SALDO', 0.0))
|
||||
|
||||
t_cta_ant += cta_ant; t_cta_cur += cta_cur; t_cta_tot += cta_tot
|
||||
t_cob_ant += cob_ant; t_cob_cur += cob_cur; t_cob_tot += cob_tot; t_saldo += saldo
|
||||
|
||||
r1 = (cob_ant / cta_ant) * 100 if cta_ant > 0 else 0.0
|
||||
r2 = (cob_cur / cta_cur) * 100 if cta_cur > 0 else 0.0
|
||||
r3 = (cob_tot / cta_tot) * 100 if cta_tot > 0 else 0.0
|
||||
|
||||
avance_ant = f"{r1:.0f}%" if cta_ant > 0 else ""
|
||||
avance_cur = f"{r2:.0f}%" if cta_cur > 0 else ""
|
||||
avance_tot = f"{r3:.0f}%" if cta_tot > 0 else ""
|
||||
|
||||
fila = [
|
||||
mat, alumno, num_cuota, fch_venc,
|
||||
f"S/ {cta_ant:,.0f}", f"S/ {cob_ant:,.0f}", avance_ant,
|
||||
f"S/ {cta_cur:,.0f}", f"S/ {cob_cur:,.0f}", avance_cur,
|
||||
f"S/ {cta_tot:,.0f}", f"S/ {cob_tot:,.0f}", avance_tot,
|
||||
f"S/ {saldo:,.0f}"
|
||||
]
|
||||
sheet_data.append(fila)
|
||||
|
||||
r_tot_1 = (t_cob_ant / t_cta_ant) * 100 if t_cta_ant > 0 else 0.0
|
||||
r_tot_2 = (t_cob_cur / t_cta_cur) * 100 if t_cta_cur > 0 else 0.0
|
||||
r_tot_3 = (t_cob_tot / t_cta_tot) * 100 if t_cta_tot > 0 else 0.0
|
||||
|
||||
fila_total = [
|
||||
"TOTAL", "GENERAL", "-", "-",
|
||||
f"S/ {t_cta_ant:,.0f}", f"S/ {t_cob_ant:,.0f}", f"{r_tot_1:.0f}%",
|
||||
f"S/ {t_cta_cur:,.0f}", f"S/ {t_cob_cur:,.0f}", f"{r_tot_2:.0f}%",
|
||||
f"S/ {t_cta_tot:,.0f}", f"S/ {t_cob_tot:,.0f}", f"{r_tot_3:.0f}%",
|
||||
f"S/ {t_saldo:,.0f}"
|
||||
]
|
||||
sheet_data.append(fila_total)
|
||||
return sheet_data
|
||||
|
||||
def exportar_detalle_excel(self, programa, headers, datos):
|
||||
if not datos: raise ValueError("No hay datos para exportar")
|
||||
|
||||
prog_limpio = "".join([c if c.isalnum() else "_" for c in str(programa)])[:30]
|
||||
archivo = f"Detalle_Cobranza_{prog_limpio}.xlsx"
|
||||
|
||||
df = pd.DataFrame(datos, columns=[h.replace('\n', ' ') for h in headers])
|
||||
try:
|
||||
with pd.ExcelWriter(archivo, engine='openpyxl') as writer:
|
||||
df.to_excel(writer, index=False, sheet_name='Detalle')
|
||||
except:
|
||||
df.to_excel(archivo, index=False)
|
||||
return archivo
|
||||
|
||||
def exportar_reporte_global(self, ano, mes, sectorista):
|
||||
datos_brutos = self.processor.obtener_detalle_programa(ano, mes, sectorista, "TODOS")
|
||||
if not datos_brutos: raise ValueError("No hay datos para exportar en este mes.")
|
||||
|
||||
filas_excel = []
|
||||
for d in datos_brutos:
|
||||
cta_ant = float(d.get('CTA_COB_ANT', 0.0))
|
||||
cob_ant = float(d.get('COB_ANT', 0.0))
|
||||
cta_cur = float(d.get('CTA_COB_MES_CURSO', 0.0))
|
||||
cob_cur = float(d.get('COB_MES_CURSO', 0.0))
|
||||
cta_tot = float(d.get('TOTAL_CTA_COB', 0.0))
|
||||
cob_tot = float(d.get('TOTAL_COBRADO', 0.0))
|
||||
|
||||
filas_excel.append({
|
||||
"ALUMNO": d.get('ALUMNO', ''),
|
||||
"PROGRAMA": d.get('PROGRAMA', '-'),
|
||||
"FRECUENCIA": d.get('FRECUENCIA', '-'),
|
||||
"NUM CUOTA": d.get('NUM_CUOTA', '-'),
|
||||
"FCH VENCIMIENTO": d.get('FCH_VENC', '-'),
|
||||
"CUENTA PENDIENTE": cta_ant,
|
||||
"COBRADO PENDIENTE": cob_ant,
|
||||
"AVANCE % ": (cob_ant / cta_ant) if cta_ant > 0 else 0.0,
|
||||
"CUENTA EN CURSO": cta_cur,
|
||||
"COBRADO EN CURSO": cob_cur,
|
||||
"AVANCE % ": (cob_cur / cta_cur) if cta_cur > 0 else 0.0,
|
||||
"TOTAL CUENTA": cta_tot,
|
||||
"TOTAL COBRADO": cob_tot,
|
||||
"AVANCE %": (cob_tot / cta_tot) if cta_tot > 0 else 0.0,
|
||||
"SALDO": float(d.get('SALDO', 0.0))
|
||||
})
|
||||
|
||||
df = pd.DataFrame(filas_excel)
|
||||
archivo = f"Reporte_Cobranza_Global_{ano}_{mes}.xlsx"
|
||||
|
||||
try:
|
||||
with pd.ExcelWriter(archivo, engine='openpyxl') as writer:
|
||||
df.to_excel(writer, index=False, sheet_name='Reporte Global')
|
||||
worksheet = writer.sheets['Reporte Global']
|
||||
from openpyxl.styles import PatternFill, Font, Alignment
|
||||
|
||||
fill_header = PatternFill(start_color="12345F", end_color="12345F", fill_type="solid")
|
||||
font_header = Font(color="FFFFFF", bold=True)
|
||||
for cell in worksheet[1]:
|
||||
cell.fill = fill_header
|
||||
cell.font = font_header
|
||||
cell.alignment = Alignment(horizontal="center", vertical="center")
|
||||
|
||||
for row in range(2, len(filas_excel) + 2):
|
||||
for col in [6, 7, 9, 10, 12, 13, 15]:
|
||||
worksheet.cell(row=row, column=col).number_format = '"S/" #,##0.00'
|
||||
for col in [8, 11, 14]:
|
||||
worksheet.cell(row=row, column=col).number_format = '0%'
|
||||
|
||||
for col in worksheet.columns:
|
||||
max_len = 0
|
||||
col_letter = col[0].column_letter
|
||||
for cell in col:
|
||||
if cell.value:
|
||||
max_len = max(max_len, len(str(cell.value)))
|
||||
worksheet.column_dimensions[col_letter].width = min(max_len + 2, 40)
|
||||
except Exception:
|
||||
df.to_excel(archivo, index=False)
|
||||
|
||||
return archivo
|
||||
Reference in New Issue
Block a user