feat(cotizador): enganche adicional hasta 90% de anticipo total (UI, opciones de credito, PDF, API y persistencia)

This commit is contained in:
2026-09-29 21:08:02 +00:00
parent ed367582c3
commit 013e13b9df
15 changed files with 309 additions and 12 deletions

View File

@@ -9,7 +9,7 @@
* Módulo puro (sin UI, sin API) para probarlo a fondo.
*/
import { calcularEsquemaFrasa, type EsquemaFrasaResultado } from './esquema-frasa'
import { PCT_ENGANCHE_MAXIMO, calcularEsquemaFrasa, type EsquemaFrasaResultado } from './esquema-frasa'
export type TipoCredito =
| 'CREDITO_BANCARIO'
@@ -68,6 +68,8 @@ export interface EntradaOpcion {
apartado: number
numMensualidades: number
escrituracionDiferida: boolean
/** Enganche adicional (monto absoluto, >= 0): se acota al 90% del anticipo */
engancheAdicional?: number
tipo: TipoCredito
ajustes: AjustesCredito
}
@@ -135,14 +137,28 @@ export function calcularOpcionCredito(e: EntradaOpcion): ResultadoOpcionCredito
const montoDescuento = round2(e.precioLista * descuento)
const precioFinal = e.precioLista - montoDescuento
const esquema = calcularEsquemaFrasa({
const esquemaBase = calcularEsquemaFrasa({
precio: precioFinal,
apartado: e.apartado,
numMensualidades: e.numMensualidades,
escrituracionDiferida: e.escrituracionDiferida,
})
// El adicional se acota igual que en el hook: el anticipo total no puede
// superar el 90% del precio final de la opción
const adicionalSolicitado = Math.max(0, e.engancheAdicional ?? 0)
const adicionalEfectivo = Math.min(adicionalSolicitado, round2(precioFinal * PCT_ENGANCHE_MAXIMO - esquemaBase.totalPagado))
const esquema =
adicionalEfectivo > 0
? calcularEsquemaFrasa({
precio: precioFinal,
apartado: e.apartado,
numMensualidades: e.numMensualidades,
escrituracionDiferida: e.escrituracionDiferida,
engancheAdicional: adicionalEfectivo,
})
: esquemaBase
const saldoAFinanciar = round2(precioFinal - esquema.totalPagado)
const saldoAFinanciar = round2(esquema.saldoAFinanciar)
const esContado = e.tipo === 'CONTADO'
const pctContado = e.tipo === 'SEMI_CONTADO' ? (e.ajustes.pctContado ?? 0) : 0
const pagoContado = esContado ? 0 : round2(saldoAFinanciar * pctContado)