import { prisma } from "@/lib/db"; import { getConfigBranding } from "@/lib/config-helpers"; import { formatDate, formatCurrency, calcularTotalesOpcion, esCotizacionPorTiempo, tarifaHoraSugerida, IVA_RATE, type MetaOpcion, } from "@/lib/calculators"; import Link from "next/link"; import { ArrowLeft, Pencil } from "lucide-react"; import { notFound } from "next/navigation"; import { ExportExcelButtonSaved, ExportPDFButtonSaved, PreviewPDFButtonSaved } from "@/components/ExportButtons"; import { DeleteCotizacionButton } from "./DeleteButton"; import { CambiarEstadoButtons } from "./CambiarEstadoButtons"; import { PreciosEditables } from "./PreciosEditables"; import { RegistroHorasPanel } from "./RegistroHorasPanel"; export const dynamic = "force-dynamic"; export default async function CotizacionDetailPage({ params, }: { params: Promise<{ id: string }>; }) { const { id } = await params; const cot = await prisma.cotizacion.findUnique({ where: { id }, include: { cliente: true, asesor: true, servicios: { include: { servicioCatalogo: true } }, planBucefalo: true, registrosHoras: { orderBy: [{ fecha: "asc" }, { horaInicio: "asc" }] }, }, }); if (!cot) notFound(); // El registro de horas (notas de pago) solo aplica a cotizaciones aprobadas que se // cobran por tiempo (horas/retainer/demanda). const mostrarHoras = cot.estado === "aprobada" && esCotizacionPorTiempo(cot.servicios); const branding = mostrarHoras ? await getConfigBranding() : null; const serviciosUnicos = cot.servicios .filter((s) => s.tipoPago === "unico" && s.seleccionado) .map((s) => ({ id: s.id, nombre: s.servicioCatalogo?.nombre || s.nombre || "Servicio", precio: s.precio, modeloCobro: s.modeloCobro, tarifaHora: s.tarifaHora, })); const serviciosMensuales = cot.servicios .filter((s) => s.tipoPago === "mensual" && s.seleccionado) .map((s) => ({ id: s.id, nombre: s.servicioCatalogo?.nombre || s.nombre || "Servicio", precio: s.precio, modeloCobro: s.modeloCobro, tarifaHora: s.tarifaHora, })); const opcionesMeta = (cot.opcionesMetadata as { "1"?: MetaOpcion; "2"?: MetaOpcion } | null) ?? {}; const totalesOpcion = cot.esDoble ? { "1": calcularTotalesOpcion(cot.servicios, "1"), "2": calcularTotalesOpcion(cot.servicios, "2"), } : null; return (
{cot.cliente.empresa || cot.cliente.nombre} | {cot.proyecto}
{cot.cliente.nombre}
{cot.cliente.empresa || "-"}
{cot.asesor.name}
{formatDate(cot.fecha)}
{formatDate(cot.vigencia)}
{cot.moneda}
{cot.esquemaPago}
{meta.descripcion}
)} {meta?.noIncluye && (No incluye:{" "} {meta.noIncluye}
)}Las partidas marcadas Ambas suman en las dos opciones. Edita la asignacion de cada partida desde Editar.
{cot.observaciones}