import type { QuoteItem } from "@eden/database"; /** * Quote pricing/fidelity/approval engine — ported verbatim from eden.md §8 * (formulas) and §3–§4 (fidelity/discount business rules). These formulas * are exact, not approximate — do not "simplify" without an ADR. The * backend is always the source of truth (Master Prompt §6.4: "nunca * confiar no frontend para cálculo financeiro"); the frontend may mirror * this logic for UX, but every quote write recomputes from scratch here. */ export interface PricingInput { items: QuoteItem[]; contractPeriod: number; fidelityPeriod: number | null; implGeral: number; proposedMonthlyTotal: number | null; } export interface PricingResult { monthlyTotal: number; implFromProducts: number; totalImpl: number; hasSpecialPrice: boolean; isDiscount: boolean; isMarkup: boolean; diffMonthly: number; effectiveMonthly: number; hasReducedFidelity: boolean; needsApproval: boolean; contractTotal: number; /** What to persist to quotes.fidelity_period — null unless it's genuinely a reduced-fidelity exception (eden.md §8 "só persiste se for de fato menor que a faixa"). */ persistedFidelityPeriod: number | null; /** What to persist to quotes.proposed_monthly_total — null unless a special price is actually active. */ persistedProposedMonthlyTotal: number | null; } export function computeQuotePricing(input: PricingInput): PricingResult { const monthlyTotal = round2(input.items.reduce((sum, item) => sum + item.total, 0)); const implFromProducts = round2(input.items.reduce((sum, item) => sum + item.implTotal, 0)); const totalImpl = round2(implFromProducts + (input.implGeral || 0)); const proposedMonthly = input.proposedMonthlyTotal; const hasSpecialPrice = proposedMonthly != null && proposedMonthly > 0 && proposedMonthly !== monthlyTotal; const isDiscount = hasSpecialPrice && proposedMonthly! < monthlyTotal; const isMarkup = hasSpecialPrice && proposedMonthly! > monthlyTotal; const diffMonthly = hasSpecialPrice ? round2(monthlyTotal - proposedMonthly!) : 0; const effectiveMonthly = hasSpecialPrice ? proposedMonthly! : monthlyTotal; const hasReducedFidelity = input.fidelityPeriod != null && input.fidelityPeriod < input.contractPeriod; const needsApproval = isDiscount || hasReducedFidelity; const contractTotal = round2(effectiveMonthly * (input.contractPeriod || 1) + totalImpl); return { monthlyTotal, implFromProducts, totalImpl, hasSpecialPrice, isDiscount, isMarkup, diffMonthly, effectiveMonthly, hasReducedFidelity, needsApproval, contractTotal, persistedFidelityPeriod: hasReducedFidelity ? input.fidelityPeriod : null, persistedProposedMonthlyTotal: hasSpecialPrice ? proposedMonthly : null, }; } /** * Resolves what `approval_status` should be persisted, given the previous * status and whether the actor is submitting an approval decision. * Mirrors eden.md §8: `needsApproval ? (approvalStatus === 'none' ? * 'pending' : approvalStatus) : 'none'` — but generalized to accept an * explicit decision (approve/reject) from a privileged actor, which the * legacy handled as a separate code path (§3.3) that this folds in here * for a single source of truth. */ export function resolveApprovalStatus( needsApproval: boolean, previousStatus: "none" | "pending" | "approved" | "rejected", decision?: "approved" | "rejected", ): "none" | "pending" | "approved" | "rejected" { if (!needsApproval) return "none"; if (decision) return decision; return previousStatus === "none" ? "pending" : previousStatus; } /** eden.md §3.3: super_admin always; admin only with the explicit per-user flag — never inferred from role alone. */ export function canApproveDiscount(user: { roleKey: string; canApproveDiscount?: boolean }): boolean { if (user.roleKey === "super_admin") return true; return user.roleKey === "admin" && user.canApproveDiscount === true; } /** * The fidelity that actually has legal effect (vigência/vencimento/multa) * — eden.md §3.4/§10.4, repeated everywhere in the legacy as the single * most important rule to preserve: a pending/rejected exception NEVER * affects anything legal, only an approved one does. */ export function resolveEffectiveFidelity( contractPeriod: number, fidelityPeriod: number | null, approvalStatus: "none" | "pending" | "approved" | "rejected", ): number { return fidelityPeriod != null && approvalStatus === "approved" ? fidelityPeriod : contractPeriod || 0; } /** eden.md §7 (paymentConditions.js) — progressive by implementation value. */ export const PAYMENT_CONDITIONS = ["À vista", "1+1", "1+2"] as const; export function getAvailablePaymentConditions(implTotal: number): readonly string[] { const value = implTotal || 0; if (value <= 1500) return ["À vista"]; if (value <= 3000) return ["À vista", "1+1"]; return PAYMENT_CONDITIONS; } export interface SavingsResult { totalDescontoMensal: number; totalEconomiaMensal: number; economiaTotalContrato: number; beneficioTotalFidelidade: number; } /** * eden.md §3.5/§4.4 — two DIFFERENT numbers that must never be confused: * `beneficioTotalFidelidade` (fidelity discount only, used as the legal * cap for the RGC art. 37 early-termination penalty) vs. * `totalEconomiaMensal`/`economiaTotalContrato` (fidelity + special * discount combined, shown as commercial "savings" info to the client). */ export function computeSavings( items: QuoteItem[], contractPeriod: number, effectiveFidelityPeriod: number, monthlyTotal: number, proposedMonthlyTotal: number | null, ): SavingsResult { const totalDescontoMensal = round2( items.reduce((sum, item) => sum + ((item.price0 ?? 0) - item.unitPrice) * item.quantity, 0), ); const hasSpecialPrice = proposedMonthlyTotal != null && proposedMonthlyTotal > 0 && proposedMonthlyTotal !== monthlyTotal; const specialDiscount = hasSpecialPrice ? round2(monthlyTotal - proposedMonthlyTotal!) : 0; const totalEconomiaMensal = round2(totalDescontoMensal + specialDiscount); const economiaTotalContrato = totalEconomiaMensal > 0 && contractPeriod > 0 ? round2(totalEconomiaMensal * contractPeriod) : 0; const beneficioTotalFidelidade = round2(totalDescontoMensal * effectiveFidelityPeriod); return { totalDescontoMensal, totalEconomiaMensal, economiaTotalContrato, beneficioTotalFidelidade }; } function round2(value: number): number { return Math.round((value + Number.EPSILON) * 100) / 100; }