From 31379806beea4b5e26c59386ff0d88bccbfe1f11 Mon Sep 17 00:00:00 2001 From: Consult AS Technology Date: Sat, 12 Sep 2026 22:58:23 +0000 Subject: [PATCH] fix(cobranza): invariante engancheTotal=plan completo, pago 0 inicial y abonos al pago correcto --- .../scripts/importar-cobranza-maestro.js | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/api-gateway/scripts/importar-cobranza-maestro.js b/api-gateway/scripts/importar-cobranza-maestro.js index c871570..2c8e129 100644 --- a/api-gateway/scripts/importar-cobranza-maestro.js +++ b/api-gateway/scripts/importar-cobranza-maestro.js @@ -174,10 +174,11 @@ function leer() { planes.push({ proyecto: nombreHoja, + fechaVenta: col.fechaVenta != null ? aFecha(fila[col.fechaVenta]) : null, plan: { ventaRef, clienteNombre, clienteTelefono: null, unidadCodigo, proyecto: nombreHoja, fechaInicio, - engancheTotal: apartado + enganche, + engancheTotal: apartado + enganche, // se recalcula en escribir() con el plan completo numPagos: meses, mensualidad, tasaMoraMensual: 0, status: 'ACTIVO', }, abonosGrid, @@ -199,11 +200,9 @@ async function escribir(planesLeidos) { const borrados = await prisma.planPago.deleteMany({}) // cascada: Pago, AplicacionPago, NotaPlan console.log(`Planes borrados: ${borrados.count}`) - let totalPagos = 0, totalAbonos = 0, totalStandalone = 0 - - for (const { plan, abonosGrid } of planesLeidos) { - const creado = await prisma.planPago.create({ data: plan }) + let totalPagos = 0, totalAbonos = 0, totalStandalone = 0, totalInicial = 0 + for (const { plan, fechaVenta, abonosGrid } of planesLeidos) { // 1) calendario programado: mensualidades desde MES INICIO const pagosProg = [] if (plan.numPagos > 0 && plan.mensualidad > 0) { @@ -217,11 +216,26 @@ async function escribir(planesLeidos) { } } + // Invariante del módulo: Σ pagos.monto == engancheTotal. El apartado+enganche + // (ya pagado según el maestro) entra como pago 0 y engancheTotal = plan completo. + const inicialMonto = (plan.engancheTotal ?? 0) + if (inicialMonto > 0) { + pagosProg.unshift({ + numPago: 0, + fechaVencimiento: fechaVenta ?? plan.fechaInicio, + monto: inicialMonto, + montoPagado: inicialMonto, + }) + totalInicial++ + } + plan.engancheTotal = pagosProg.reduce((a, p) => a + p.monto, 0) + // 2) abonos del grid sobre la mensualidad del mismo mes; sobrantes → standalone const aplicaciones = [] // { idxPago, fechaPago, monto } const standalone = [] for (const ab of abonosGrid) { - const idx = pagosProg.findIndex((p) => claveMes(p.fechaVencimiento) === claveMes(ab.fecha)) + // idx del arreglo == numPago (el inicial ocupa numPago 0 en el índice 0) + const idx = pagosProg.findIndex((p) => p.numPago >= 1 && claveMes(p.fechaVencimiento) === claveMes(ab.fecha)) if (idx !== -1) { aplicaciones.push({ idx, fechaPago: ab.fecha, monto: ab.monto }) } else { @@ -235,8 +249,18 @@ async function escribir(planesLeidos) { p.montoPagado = Math.min(p.monto, p.montoPagado + ap.monto) } + // Si el maestro registra pagos por encima del plan declarado (filas con + // MESES/MENSUALIDAD vacíos pero grid lleno), el total del plan es lo pagado. + const totalPagadoAcumulado = pagosProg.reduce((a, p) => a + p.montoPagado, 0) + + standalone.reduce((a, s) => a + s.monto, 0) + if (totalPagadoAcumulado > plan.engancheTotal) { + plan.engancheTotal = Math.round(totalPagadoAcumulado * 100) / 100 + } + + const creado = await prisma.planPago.create({ data: plan }) + // crear pagos programados - let numSiguiente = pagosProg.length + let numSiguiente = pagosProg.length - 1 for (const p of pagosProg) { await prisma.pago.create({ data: { planId: creado.id, numPago: p.numPago, fechaVencimiento: p.fechaVencimiento, monto: p.monto, montoPagado: p.montoPagado }, @@ -257,7 +281,7 @@ async function escribir(planesLeidos) { // 3) aplicaciones de pago (abonos con fecha real) for (const ap of aplicaciones) { - const pagoId = porNum.get(ap.idx + 1) + const pagoId = porNum.get(ap.idx) if (!pagoId) continue await prisma.aplicacionPago.create({ data: { pagoId, fechaPago: ap.fechaPago, monto: ap.monto, referencia: 'Importación maestro cobranza 06/09/26', capturadoPorId: null }, @@ -266,7 +290,7 @@ async function escribir(planesLeidos) { } } - console.log(`\nPlanes: ${planesLeidos.length} | Pagos programados: ${totalPagos} | Standalone: ${totalStandalone} | Abonos (AplicacionPago): ${totalAbonos}`) + console.log(`\nPlanes: ${planesLeidos.length} | Pagos programados: ${totalPagos} (incl. ${totalInicial} pagos iniciales apartado+enganche) | Standalone: ${totalStandalone} | Abonos (AplicacionPago): ${totalAbonos}`) } async function verificar() {