From 449bd4c30599f56b9e95305d7bd44e9a07c0f7a7 Mon Sep 17 00:00:00 2001 From: Administrator Date: Tue, 29 Sep 2026 16:37:22 -0500 Subject: [PATCH] Actualizar frontend/src/pages/Cobranza.jsx --- frontend/src/pages/Cobranza.jsx | 50 +++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/frontend/src/pages/Cobranza.jsx b/frontend/src/pages/Cobranza.jsx index 0301f6a..c2532bc 100644 --- a/frontend/src/pages/Cobranza.jsx +++ b/frontend/src/pages/Cobranza.jsx @@ -339,8 +339,8 @@ export default function Cobranza() { // al menos un grupo expandido, o siempre en PROGRAMA. const conColsExtra = esPrograma || (expandidas.size > 0); const headers = !conColsExtra - ? ["GRUPO","CTA X COB. MES ANT.","COB. MES ANT.","% ANT","CTA X COB EN CURSO","COB. EN CURSO","% MES","CTA X COB TOTAL","COB. TOTAL","% TOTAL","SALDO","SALDO POR RETIRAR","OPC."] - : [(esPrograma?"PROGRAMA":"GRUPO"),"FREC.","N° CUOTA","VENCIMIENTO","CTA X COB. MES ANT.","COB. MES ANT.","% ANT","CTA X COB EN CURSO","COB. EN CURSO","% MES","CTA X COB TOTAL","COB. TOTAL","% TOTAL","SALDO","SALDO POR RETIRAR","OPC."]; + ? ["GRUPO","CTA X COB. MES ANT.","COB. MES ANT.","% ANT","CTA X COB EN CURSO","COB. EN CURSO","% MES","CTA X COB TOTAL","COB. TOTAL","% TOTAL","SALDO","RETIROS","DIFERENCIA","OPC."] + : [(esPrograma?"PROGRAMA":"GRUPO"),"FREC.","N° CUOTA","VENCIMIENTO","CTA X COB. MES ANT.","COB. MES ANT.","% ANT","CTA X COB EN CURSO","COB. EN CURSO","% MES","CTA X COB TOTAL","COB. TOTAL","% TOTAL","SALDO","RETIROS","DIFERENCIA","OPC."]; // Anchos para columnas redimensionables (1ª columna más ancha, resto estándar) const anchosCob = headers.map((h, i) => i === 0 ? (conColsExtra ? 280 : 200) : (h === "FREC." || h.startsWith("%") || h === "OPC." ? 80 : 120)); @@ -598,7 +598,7 @@ export default function Cobranza() { {datos.map((fRaw, ri) => { const f = filaLayout(fRaw); // layout normalizado (15 o 12 cols) - const nCols = headers.length - 1; // sin OPC + const nCols = headers.length - 2; // sin RETIROS (calculada) ni OPC const sedeKey = String(f[0]).toUpperCase(); const abiertaSede = !esPrograma && expandidas.has(sedeKey); // Hijos a mostrar al expandir: en SEDE los programas de la sede; @@ -609,7 +609,14 @@ export default function Cobranza() { const av = !String(fila[LAY.ant[2]]||"").trim() || ["-","—"].includes(String(fila[LAY.ant[2]]).trim()); const mv = !String(fila[LAY.mes[2]]||"").trim() || ["-","—"].includes(String(fila[LAY.mes[2]]).trim()); const tv = !String(fila[LAY.tot[2]]||"").trim() || ["-","—"].includes(String(fila[LAY.tot[2]]).trim()); - return fila.slice(0, nCols).map((v, ci) => { + // RETIROS (calculada) = SALDO − SALDO POR RETIRAR de la propia fila. + const retiros = toMonto(fila[LAY.saldo]) - toMonto(fila[LAY.saldoRet]); + const celdaRetiros = ( + + {"S/ " + retiros.toLocaleString("es-PE",{maximumFractionDigits:0})} + + ); + const celdas = fila.slice(0, nCols).map((v, ci) => { const isPct = LAY.ant[2]===ci || LAY.mes[2]===ci || LAY.tot[2]===ci; let val = v; if ((ci===LAY.ant[0]||ci===LAY.ant[1]||ci===LAY.ant[2]) && av) val = "—"; @@ -642,6 +649,7 @@ export default function Cobranza() { ); }); + return [...celdas, celdaRetiros]; }; return ( @@ -688,6 +696,7 @@ export default function Cobranza() { if (ci===LAY.tot[2]) return ratio(T.oTot,T.cTot); if (ci===LAY.saldo) return money(T.saldo); if (ci===LAY.saldoRet) return money(T.saldoRet); + if (ci===LAY.saldoRet+1) return money(T.saldo - T.saldoRet); // RETIROS (calculada) return ""; }; return ( @@ -703,10 +712,12 @@ export default function Cobranza() { boxShadow:`inset -1px 0 0 0 #cbd5e1${ci===FIJAS_MAIN-1?", 3px 0 5px -2px rgba(0,0,0,0.18)":""}, inset 0 1px 0 0 #cbd5e1` } : { position:"sticky", bottom:0, zIndex:9, backgroundColor:"#eff6ff", boxShadow:"inset 0 1px 0 0 #cbd5e1" }; + const esRetiros = ci===LAY.saldoRet+1; return ( + color: ci===LAY.saldoRet ? "#dc2626" : (esRetiros ? "#7c3aed" : undefined), + fontWeight: esRetiros ? 700 : undefined, ...st}}> {isPct ? : val} ); @@ -841,8 +852,8 @@ function Tarjetas({ kpis, retiro, loading }) { 0?"#dc2626":"#10b981"} /> - - + + {cta>0 && (
@@ -892,8 +903,8 @@ function TarjetasResumen({ r, retiro }) { 0?"#dc2626":"#10b981"} /> - - + + {cta>0 && (
@@ -1136,7 +1147,7 @@ function ModalEstadoCuenta({ grupo, ano, mes, sectorista, agrupacion, progFiltro }; useEffect(() => { cargarPorRetirar(); }, [ano, mes]); - const COLS = ["PROGRAMA","ALUMNO","N° CUOTA","F. VENC.","CTA ANT.","COB ANT.","% ANT","CTA MES","COB MES","% MES","CTA TOT","COB TOT","% TOT","SALDO","INFO"]; + const COLS = ["PROGRAMA","ALUMNO","N° CUOTA","F. VENC.","CTA ANT.","COB ANT.","% ANT","CTA MES","COB MES","% MES","CTA TOT","COB TOT","% TOT","SALDO","DIFERENCIA","INFO"]; // Alumno seleccionado para el pop-up de INFO (estado + observaciones) const [infoAlumno, setInfoAlumno] = useState(null); @@ -1256,7 +1267,7 @@ function ModalEstadoCuenta({ grupo, ano, mes, sectorista, agrupacion, progFiltro Ver solo por retirar
-
+
{COLS.map((c,i)=>{ @@ -1264,7 +1275,7 @@ function ModalEstadoCuenta({ grupo, ano, mes, sectorista, agrupacion, progFiltro const stH = fija ? stickyCol(i,{esHeader:true,bg:"#334155"}) : { position:"sticky", top:0, zIndex:12, backgroundColor:"#334155" }; - const ordenable = i !== 14; + const ordenable = i !== 14 && i !== 15; // RETIROS (14, calculada) e INFO (15) no ordenables return ; @@ -1282,6 +1293,9 @@ function ModalEstadoCuenta({ grupo, ano, mes, sectorista, agrupacion, progFiltro const totVacio = !String(f[12]||"").trim() || ["-","—"].includes(String(f[12]).trim()); const programa = f[14] || "-"; // programa del alumno (extra del backend) const retira = porRetirar.has(String(f[0])); // alumno POR RETIRAR + // RETIROS (calculada) = SALDO − SALDO POR RETIRAR. Si el alumno está POR + // RETIRAR, todo su saldo es "por retirar" ⇒ RETIROS = 0; si no, = su saldo. + const retirosFila = retira ? 0 : saldo; return ( ); })} + {/* RETIROS (calculada) = SALDO − SALDO POR RETIRAR */} + {/* Botón INFO por alumno (estado + observaciones) */} ); })} + {/* RETIROS total (calculada) */} + );
clickOrden(i)} style={{...stH, position:stH.position||"relative", cursor: ordenable?"pointer":"default", userSelect:"none"}}> {c}{ordenable && _flecha(ordCol===i, ordDir)}
+ {"S/ " + retirosFila.toLocaleString("es-PE",{maximumFractionDigits:0})} + + {"S/ " + retirosTot.toLocaleString("es-PE",{maximumFractionDigits:0})} +