import type { Request, Response } from 'express' import { z } from 'zod' import { prisma } from '../services/prisma.js' import { AppError, NotFoundError } from '../utils/errors.js' // ---------- Borradores del alta de clientes ---------- const guardarBorradorSchema = z.object({ id: z.string().min(1).optional(), nombre: z.string().max(200).optional(), paso: z.number().int().min(0).max(50).default(0), // Estado del wizard serializado (objeto JSON cualquiera; sin Files) datos: z.unknown(), }) /** sub del JWT; con AUTH_ENABLED=false (tests) cae a un id fijo */ const usuarioDe = (req: Request): string => req.usuarioToken?.sub ?? 'anon' const esAdmin = (req: Request): boolean => req.usuarioToken?.rol === 'admin' /** 404 si no existe, 403 si es de otro usuario (salvo admin) */ async function borradorPropio(req: Request, id: string) { const borrador = await prisma.borradorAlta.findUnique({ where: { id } }) if (!borrador) throw new NotFoundError('Borrador no encontrado') if (borrador.usuarioId !== usuarioDe(req) && !esAdmin(req)) { throw new AppError(403, 'El borrador pertenece a otro usuario') } return borrador } // Etiqueta visible: nombre del cliente dentro del estado, o "Sin nombre" function etiquetaDe(datos: unknown, nombreExplicito: string | undefined): string { if (nombreExplicito?.trim()) return nombreExplicito.trim() const dg = (datos as { datosGenerales?: { nombreCompleto?: unknown } } | null)?.datosGenerales const nombre = typeof dg?.nombreCompleto === 'string' ? dg.nombreCompleto.trim() : '' return nombre || 'Sin nombre' } /** GET /api/borradores — lista los míos, SIN datosJson (metadatos) */ export async function listarBorradores(req: Request, res: Response): Promise { const borradores = await prisma.borradorAlta.findMany({ where: { usuarioId: usuarioDe(req) }, select: { id: true, nombre: true, paso: true, createdAt: true, updatedAt: true }, orderBy: { updatedAt: 'desc' }, }) res.json(borradores) } /** POST /api/borradores — upsert: con `id` actualiza (si es mío), sin `id` crea */ export async function guardarBorrador(req: Request, res: Response): Promise { const body = guardarBorradorSchema.parse(req.body) const datosJson = JSON.stringify(body.datos ?? null) const nombre = etiquetaDe(body.datos, body.nombre) if (body.id) { await borradorPropio(req, body.id) const actualizado = await prisma.borradorAlta.update({ where: { id: body.id }, data: { nombre, datosJson, paso: body.paso }, }) res.json(actualizado) return } const creado = await prisma.borradorAlta.create({ data: { usuarioId: usuarioDe(req), nombre, datosJson, paso: body.paso }, }) res.status(201).json(creado) } /** GET /api/borradores/:id — borrador completo (solo el dueño o admin) */ export async function obtenerBorrador(req: Request, res: Response): Promise { const borrador = await borradorPropio(req, String(req.params['id'])) res.json(borrador) } /** DELETE /api/borradores/:id — solo el dueño o admin */ export async function eliminarBorrador(req: Request, res: Response): Promise { const borrador = await borradorPropio(req, String(req.params['id'])) await prisma.borradorAlta.delete({ where: { id: borrador.id } }) res.status(204).end() }