feat(pendientes): cotizador (mensualidades, bloqueo de unidad, totales, numMensualidades), cobranza (recibos, atrasos, mora configurable, recordatorios), soporte (adjuntos, filtros, estados), clientes maestro (catalogos reales), contactos (ficha y duplicados) y permisos de captura por rol
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { jsPDF } from 'jspdf'
|
||||
import autoTable from 'jspdf-autotable'
|
||||
import type { AplicacionPago, Pago, PlanPago } from '../../types'
|
||||
import { round2 } from '../cobranza'
|
||||
import { round2, saldoPlan } from '../cobranza'
|
||||
import { formatoFechaCorta, formatoFechaLarga, formatoMoneda } from '../formatters'
|
||||
import type { DocumentoPdf } from './estadoCuenta'
|
||||
|
||||
@@ -12,11 +12,25 @@ export function folioRecibo(aplicacion: AplicacionPago): string {
|
||||
return aplicacion.id.slice(0, 8).toUpperCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* Saldos que imprime el recibo, tomados de los TOTALES del plan y del pago
|
||||
* (suma de montos − suma de pagado), no del historial de `AplicacionPago`:
|
||||
* el enganche/apartado histórico vive en `Pago.montoPagado` sin fila de
|
||||
* aplicación, así que acumular solo aplicaciones daba saldos falsos
|
||||
* (incluso negativos). El saldo nunca puede ser negativo porque un abono
|
||||
* jamás excede el restante de su pago.
|
||||
*/
|
||||
export function saldosDelRecibo(plan: PlanPago, pago: Pago): { restantePago: number; saldoPlan: number } {
|
||||
return {
|
||||
restantePago: round2(pago.monto - pago.montoPagado),
|
||||
saldoPlan: saldoPlan(plan),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construye el recibo de pago de una aplicación (abono) ya registrada.
|
||||
* El restante del pago y el saldo del plan se calculan acumulando las
|
||||
* aplicaciones registradas hasta esa aplicación (inclusive), de modo que el
|
||||
* recibo refleja los montos vigentes justo tras el abono.
|
||||
* El restante del pago y el saldo del plan son los totales vigentes del plan
|
||||
* (ver `saldosDelRecibo`).
|
||||
*/
|
||||
export function crearDocumento(
|
||||
plan: PlanPago,
|
||||
@@ -28,23 +42,7 @@ export function crearDocumento(
|
||||
const doc = new jsPDF()
|
||||
let y = MARGEN
|
||||
|
||||
// Aplicado acumulado (plan y pago) hasta la aplicación indicada, en orden de registro
|
||||
let aplicadoPlan = 0
|
||||
let aplicadoPago = 0
|
||||
let encontrada = false
|
||||
for (const p of plan.pagos) {
|
||||
for (const a of p.aplicaciones) {
|
||||
aplicadoPlan += a.monto
|
||||
if (p.id === pago.id) aplicadoPago += a.monto
|
||||
if (a.id === aplicacion.id) {
|
||||
encontrada = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (encontrada) break
|
||||
}
|
||||
const saldoTrasAbono = round2(plan.engancheTotal - aplicadoPlan)
|
||||
const restanteTrasAbono = round2(pago.monto - aplicadoPago)
|
||||
const { restantePago, saldoPlan: saldo } = saldosDelRecibo(plan, pago)
|
||||
|
||||
// 1. Encabezado
|
||||
doc.setFontSize(14)
|
||||
@@ -72,8 +70,8 @@ export function crearDocumento(
|
||||
['FECHA DE PAGO', formatoFechaCorta(aplicacion.fechaPago)],
|
||||
['MONTO DEL ABONO', formatoMoneda(aplicacion.monto)],
|
||||
['REFERENCIA', aplicacion.referencia || '—'],
|
||||
['RESTANTE DEL PAGO', formatoMoneda(restanteTrasAbono)],
|
||||
['SALDO DEL PLAN TRAS EL ABONO', formatoMoneda(saldoTrasAbono)],
|
||||
['RESTANTE DEL PAGO', formatoMoneda(restantePago)],
|
||||
['SALDO DEL PLAN (a la fecha de emisión)', formatoMoneda(saldo)],
|
||||
],
|
||||
theme: 'plain',
|
||||
columnStyles: { 0: { fontStyle: 'bold', cellWidth: 70 }, 1: { halign: 'left' } },
|
||||
|
||||
Reference in New Issue
Block a user