Generación de Cotizaciones en PDF - Alejoso/Flujo-de-compras GitHub Wiki
Descripción general
Se implementó la capacidad de generar, almacenar y visualizar PDFs de cotizaciones. El sistema mantiene siempre el PDF de la primera versión (V1) y el de la versión más reciente, eliminando los intermedios. Las versiones intermedias pueden visualizarse como HTML y descargarse como PDF bajo demanda.
Configuración inicial requerida
Después de clonar el proyecto o migrar la base de datos, ejecutar:
php artisan migrate
php artisan storage:link
storage:link crea el enlace simbólico entre public/storage y storage/app/public, necesario para que los PDFs guardados sean accesibles desde el navegador.
Instalación
Se instaló la librería barryvdh/laravel-dompdf que permite convertir HTML/CSS a PDF:
composer require barryvdh/laravel-dompdf
Cambios en la base de datos
Se agregó la columna pdfPath a la tabla version_cotizaciones:
$table->string('pdfPath')->nullable();
Almacena la ruta relativa del archivo PDF dentro de storage/app/public/. Es nullable porque el registro se crea antes de generar el PDF.
Ejemplo de valor guardado: cotizaciones/cotizacion_1_v3.pdf
Archivos modificados / creados
Modelo — app/Models/VersionCotizacion.php
- Se agregó
pdfPathal$fillable - Se agregaron
getPdfPath()ysetPdfPath()
Migración — database/migrations/..._create_version_cotizaciones_table.php
- Se agregó la columna
pdfPath nullable
Controller — app/Http/Controllers/Tecnico/CotizacionController.php
Se agregaron los siguientes métodos:
| Método | Tipo | Descripción |
|---|---|---|
cargarVersionConRelaciones() |
private | Carga la versión con todos los eager loads necesarios |
prepararDatosPdf() |
private | Prepara $tecnico, $fecha, $materiales y $numeroCotizacion |
generarYGuardarPdf() |
private | Genera el PDF con dompdf y lo guarda en disco |
pdfView() |
public | Retorna la vista HTML que imita el documento PDF |
pdfDownload() |
public | Genera el PDF al vuelo y lo retorna como descarga sin guardarlo |
Lógica de gestión de PDFs en store() y update():
store() -> genera PDF de V1, nunca se elimina
update() -> si la versión más reciente NO es V1:
elimina su PDF del disco
pone pdfPath = null en BD
crea nueva versión
genera su PDF
Naming de archivos:
cotizaciones/cotizacion_{cotizacionId}_v{numeroVersion}.pdf
Vista PDF — resources/views/pdf/cotizacion.blade.php
Template HTML usado por dompdf. Sin lógica PHP, solo HTML con clases CSS. Recibe las variables ya procesadas desde el controller:
| Variable | Contenido |
|---|---|
$tecnico |
Usuario creador de la cotización |
$project |
Proyecto asociado |
$fecha |
Fecha formateada en español |
$materiales |
Array con cantidad, unidades, descripción y especificación |
$numeroCotizacion |
ID de la cotización |
$version |
Versión actual |
Vista previa — resources/views/tecnico/cotizacion/pdf-view.blade.php
Vista web que imita visualmente el documento PDF. Muestra un botón Descargar PDF que llama a pdfDownload(). Solo aparece para versiones intermedias (ni V1 ni la más reciente).
Estilos — public/css/tecnico.css
Se agregaron las clases cot-doc-* al final del archivo:
| Clase | Uso |
|---|---|
.cot-doc-wrapper |
Contenedor del documento (fondo blanco, tipografía serif) |
.cot-doc-header |
Encabezado con datos del técnico |
.cot-doc-title |
Título de la cotización |
.cot-doc-date |
Fecha centrada |
.cot-doc-intro |
Párrafo introductorio |
.cot-doc-table |
Tabla de materiales |
.cot-doc-page-number |
Número de página fijo en el pie (solo PDF) |
Rutas — routes/web.php
GET /tecnico/project/{id}/cotizacion/{versionId}/pdf -> pdfView
GET /tecnico/project/{id}/cotizacion/{versionId}/pdf/download -> pdfDownload
Comportamiento por versión
| Versión | PDF guardado | Botón "Ver PDF" |
|---|---|---|
| V1 (inicial) | Sí, permanente | No |
| V2, V3... (intermedias) | No (eliminado al crear siguiente) | Sí -> abre vista HTML + descarga |
| Vn (más reciente) | Sí, hasta que se cree otra | No |
Formulario de creación
Se unificó el formulario de creación con el de edición:
- Selector dropdown para elegir el material
- Botón Agregar a la lista que inserta la fila en la tabla
- Validación de duplicados en frontend (
data-id) y backend (regladistinct) - Archivos modificados:
StoreCotizacionRequest.php,UpdateCotizacionRequest.php,create.blade.php,edit.blade.php