Mejora el PDF de presupuesto: disclaimer, render y conversión de imágenes

- Añade bajo el título un párrafo orientativo: el precio final se fija tras
  la visita gratuita y la estimación se basa en datos estadísticos ajustados
  para acercarse lo máximo posible al importe definitivo.
- Añade una sección con el render del resultado y una descripción generada a
  partir de los materiales (materialesRender) y el estilo de la llamada, con
  fallback elegante cuando faltan datos.
- @react-pdf solo incrusta PNG/JPEG: convierte con sharp los WebP/SVG (render
  y logo) que antes se descartaban en silencio dejando el PDF sin imagen. El
  render va a JPEG redimensionado (PDF ~360 KB en vez de ~2,7 MB) y el logo a
  PNG para conservar transparencia.
- Fija sharp como dependencia directa (ya venía como transitiva de Next).
- Copy nuevo añadido primero a COPY-GUIDE.md (sección entrega del presupuesto).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Carlos Narro
2026-06-02 19:48:14 +02:00
parent e9637f77ff
commit 8de139f9d3
6 changed files with 178 additions and 6 deletions

View File

@@ -4,7 +4,9 @@ import { getLead } from '@/db/queries';
import { getTenantPerfil } from '@/db/tenant-queries';
import { TIPO_LABEL } from '@/lib/funnel';
import { PresupuestoDoc } from '@/lib/pdf/PresupuestoDoc';
import { construirDescripcionRender, resolverImagenPdf } from '@/lib/pdf/render-info';
import type { BudgetResult } from '@/budget/types';
import type { AbstractedPreferences } from '@/lib/voice/preferences';
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';
@@ -25,6 +27,22 @@ export async function GET(
const snapshot = lead.desgloseSnapshot as { result: BudgetResult } | null;
const desglose = snapshot?.result ?? null;
const [logoSrc, imagenSrc] = await Promise.all([
resolverImagenPdf(empresa.logoUrl, { formato: 'png', maxAncho: 400 }),
resolverImagenPdf(lead.renderUrl, { formato: 'jpeg', maxAncho: 1400 }),
]);
const prefs = lead.preferencesSnapshot as AbstractedPreferences | null;
const render = imagenSrc
? {
imagenSrc,
descripcion: construirDescripcionRender({
calidad: lead.calidadGlobal,
materiales: desglose?.materialesRender ?? [],
estilo: prefs?.estiloRender ?? [],
}),
}
: null;
const buffer = await renderToBuffer(
PresupuestoDoc({
empresa,
@@ -34,6 +52,8 @@ export async function GET(
fecha: lead.createdAt,
},
desglose,
logoSrc,
render,
})
);