import type { Request, Response } from 'express' import { z } from 'zod' import { mondayService } from '../services/monday.service.js' import { calcularPropuesta, obtenerPrecioLista } from '../services/cotizacion.service.js' import { prisma } from '../services/prisma.js' import { NotFoundError } from '../utils/errors.js' const crearCotizacionSchema = z.object({ unidadCodigo: z.string().min(1), acabados: z.boolean(), apartado: z.number().positive().optional(), clienteNombre: z.string().min(1), clienteEmail: z.string().email().optional(), clienteTelefono: z.string().min(7).optional(), tipoPropuesta: z.enum(['BANCARIO', 'INFONAVIT', 'COFINAVIT', 'CONTADO', 'SEMI_CONTADO']), descuento: z.number().min(0).max(1).optional(), // fracción (0.02 = 2%) }) const hoyISO = (): string => { const d = new Date() const m = String(d.getMonth() + 1).padStart(2, '0') const dia = String(d.getDate()).padStart(2, '0') return `${d.getFullYear()}-${m}-${dia}` } /** POST /api/cotizaciones — calcula, persiste y registra la oportunidad en Monday */ export async function crearCotizacion(req: Request, res: Response): Promise { const body = crearCotizacionSchema.parse(req.body) const unidad = await mondayService.getUnidad(body.unidadCodigo) if (!unidad) throw new NotFoundError(`Unidad ${body.unidadCodigo} no encontrada`) const apartado = body.apartado ?? 20000 // APARTADO_DEFAULT const propuesta = calcularPropuesta(unidad, body.tipoPropuesta, body.acabados, apartado, body.descuento) const precioLista = obtenerPrecioLista(unidad, body.acabados) const cotizacion = await prisma.cotizacion.create({ data: { unidadCodigo: unidad.codigo, clienteNombre: body.clienteNombre, clienteEmail: body.clienteEmail ?? null, clienteTelefono: body.clienteTelefono ?? null, tipoPropuesta: body.tipoPropuesta, acabados: body.acabados, apartado, descuento: propuesta.descuento, precioLista, precioFinal: propuesta.precioFinal, enganche: propuesta.enganche, numMensualidades: propuesta.numMensualidades ?? 0, // 0 => plazo desconocido (sin fecha de entrega) mensualidad: propuesta.mensualidad, pagoFinal: propuesta.pagoFinal, }, }) // Registra la oportunidad en Monday; si Monday falla, la cotización ya quedó persistida let mondayItemId: string | null = null try { mondayItemId = await mondayService.crearOportunidad({ clienteNombre: body.clienteNombre, unidadCodigo: unidad.codigo, tipoPropuestaLabel: body.tipoPropuesta, precioLista, descuentoPct: propuesta.descuento * 100, precioFinal: propuesta.precioFinal, fechaCotizacion: hoyISO(), estadoLabel: 'COTIZADA', ...(body.clienteEmail !== undefined ? { clienteEmail: body.clienteEmail } : {}), ...(body.clienteTelefono !== undefined ? { clienteTelefono: body.clienteTelefono } : {}), }) await prisma.cotizacion.update({ where: { id: cotizacion.id }, data: { mondayItemId } }) } catch (err) { // eslint-disable-next-line no-console console.error('No se pudo crear la oportunidad en Monday:', err) } res.status(201).json({ ...cotizacion, mondayItemId, propuesta }) } /** GET /api/cotizaciones */ export async function listarCotizaciones(_req: Request, res: Response): Promise { const cotizaciones = await prisma.cotizacion.findMany({ orderBy: { createdAt: 'desc' } }) res.json(cotizaciones) } /** GET /api/cotizaciones/:id */ export async function obtenerCotizacion(req: Request, res: Response): Promise { const cotizacion = await prisma.cotizacion.findUnique({ where: { id: String(req.params['id']) } }) if (!cotizacion) throw new NotFoundError('Cotización no encontrada') res.json(cotizacion) }