fix(cobranza): invariante engancheTotal=plan completo, pago 0 inicial y abonos al pago correcto
This commit is contained in:
@@ -174,10 +174,11 @@ function leer() {
|
|||||||
|
|
||||||
planes.push({
|
planes.push({
|
||||||
proyecto: nombreHoja,
|
proyecto: nombreHoja,
|
||||||
|
fechaVenta: col.fechaVenta != null ? aFecha(fila[col.fechaVenta]) : null,
|
||||||
plan: {
|
plan: {
|
||||||
ventaRef, clienteNombre, clienteTelefono: null, unidadCodigo,
|
ventaRef, clienteNombre, clienteTelefono: null, unidadCodigo,
|
||||||
proyecto: nombreHoja, fechaInicio,
|
proyecto: nombreHoja, fechaInicio,
|
||||||
engancheTotal: apartado + enganche,
|
engancheTotal: apartado + enganche, // se recalcula en escribir() con el plan completo
|
||||||
numPagos: meses, mensualidad, tasaMoraMensual: 0, status: 'ACTIVO',
|
numPagos: meses, mensualidad, tasaMoraMensual: 0, status: 'ACTIVO',
|
||||||
},
|
},
|
||||||
abonosGrid,
|
abonosGrid,
|
||||||
@@ -199,11 +200,9 @@ async function escribir(planesLeidos) {
|
|||||||
const borrados = await prisma.planPago.deleteMany({}) // cascada: Pago, AplicacionPago, NotaPlan
|
const borrados = await prisma.planPago.deleteMany({}) // cascada: Pago, AplicacionPago, NotaPlan
|
||||||
console.log(`Planes borrados: ${borrados.count}`)
|
console.log(`Planes borrados: ${borrados.count}`)
|
||||||
|
|
||||||
let totalPagos = 0, totalAbonos = 0, totalStandalone = 0
|
let totalPagos = 0, totalAbonos = 0, totalStandalone = 0, totalInicial = 0
|
||||||
|
|
||||||
for (const { plan, abonosGrid } of planesLeidos) {
|
|
||||||
const creado = await prisma.planPago.create({ data: plan })
|
|
||||||
|
|
||||||
|
for (const { plan, fechaVenta, abonosGrid } of planesLeidos) {
|
||||||
// 1) calendario programado: mensualidades desde MES INICIO
|
// 1) calendario programado: mensualidades desde MES INICIO
|
||||||
const pagosProg = []
|
const pagosProg = []
|
||||||
if (plan.numPagos > 0 && plan.mensualidad > 0) {
|
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
|
// 2) abonos del grid sobre la mensualidad del mismo mes; sobrantes → standalone
|
||||||
const aplicaciones = [] // { idxPago, fechaPago, monto }
|
const aplicaciones = [] // { idxPago, fechaPago, monto }
|
||||||
const standalone = []
|
const standalone = []
|
||||||
for (const ab of abonosGrid) {
|
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) {
|
if (idx !== -1) {
|
||||||
aplicaciones.push({ idx, fechaPago: ab.fecha, monto: ab.monto })
|
aplicaciones.push({ idx, fechaPago: ab.fecha, monto: ab.monto })
|
||||||
} else {
|
} else {
|
||||||
@@ -235,8 +249,18 @@ async function escribir(planesLeidos) {
|
|||||||
p.montoPagado = Math.min(p.monto, p.montoPagado + ap.monto)
|
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
|
// crear pagos programados
|
||||||
let numSiguiente = pagosProg.length
|
let numSiguiente = pagosProg.length - 1
|
||||||
for (const p of pagosProg) {
|
for (const p of pagosProg) {
|
||||||
await prisma.pago.create({
|
await prisma.pago.create({
|
||||||
data: { planId: creado.id, numPago: p.numPago, fechaVencimiento: p.fechaVencimiento, monto: p.monto, montoPagado: p.montoPagado },
|
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)
|
// 3) aplicaciones de pago (abonos con fecha real)
|
||||||
for (const ap of aplicaciones) {
|
for (const ap of aplicaciones) {
|
||||||
const pagoId = porNum.get(ap.idx + 1)
|
const pagoId = porNum.get(ap.idx)
|
||||||
if (!pagoId) continue
|
if (!pagoId) continue
|
||||||
await prisma.aplicacionPago.create({
|
await prisma.aplicacionPago.create({
|
||||||
data: { pagoId, fechaPago: ap.fechaPago, monto: ap.monto, referencia: 'Importación maestro cobranza 06/09/26', capturadoPorId: null },
|
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() {
|
async function verificar() {
|
||||||
|
|||||||
Reference in New Issue
Block a user