draft de impresion presupuesto, añadiendo posibilidades de iva

This commit is contained in:
2025-10-13 14:38:30 +02:00
parent 9d88392a2b
commit d99ef65268
11 changed files with 712 additions and 252 deletions

View File

@ -1,142 +1,199 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="es">
<head>
<meta charset="UTF-8" />
<title th:text="'Presupuesto ' + ${numero}">Presupuesto</title>
<link rel="stylesheet" href="assets/css/bootstrap-for-pdf.css" />
<link rel="stylesheet" href="assets/css/presupuestopdf.css" />
</head>
<body>
<!-- BANDA SUPERIOR -->
<div class="topbar">
<div class="brand">
<img src="assets/img/logo-imprimelibros.png" alt="ImprimeLibros" class="logo"/>
<div class="brand-lines">
<div class="brand-name" th:text="${empresa?.nombre} ?: 'ImprimeLibros ERP'">ImprimeLibros ERP</div>
<div class="brand-meta">
<span th:text="${empresa?.direccion} ?: 'C. José Picón, 28 local A · 28028 Madrid'">C. José Picón, 28 local A · 28028 Madrid</span>
· <span th:text="${empresa?.telefono} ?: '910052574'">910052574</span>
· <span th:text="${empresa?.email} ?: 'info@imprimelibros.com'">info@imprimelibros.com</span>
· <span th:text="${empresa?.cif} ?: 'B04998886'">B04998886</span>
</div>
</div>
</div>
<div class="doc-title">P R E S U P U E S T O</div>
<body class="has-watermark">
<div class="watermark">
<img src="assets/images/logo-watermark.png" alt="Marca de agua" />
</div>
<!-- FICHA Nº / CLIENTE / FECHA -->
<table class="sheet-info">
<tr>
<td><span class="lbl">PRESUPUESTO Nº:</span> <span class="val" th:text="${numero}">153153</span></td>
<td><span class="lbl">CLIENTE:</span> <span class="val" th:text="${cliente?.nombre} ?: '-'">JUAN JOSÉ MÉNDEZ</span></td>
<td><span class="lbl">FECHA:</span> <span class="val" th:text="${#temporals.format(fecha, 'dd/MM/yyyy')}">10/10/2025</span></td>
</tr>
</table>
<div class="page-content">
<!-- HEADER: logo izq + caja empresa dcha -->
<!-- TÍTULO DEL LIBRO -->
<div class="line-title">
<span class="lbl">Título:</span>
<span class="val" th:text="${titulo} ?: '-'">Libro de prueba</span>
</div>
<!-- DATOS TÉCNICOS EN 2 COLUMNAS -->
<div class="specs">
<div class="col">
<div class="block-title">Encuadernación</div>
<div class="kv"><span>Encuadernación:</span><b th:text="${encuadernacion} ?: 'Fresado'">Fresado</b></div>
<div class="kv"><span>Formato:</span><b>
<span th:text="${ancho}">148</span>x<span th:text="${alto}">210</span> mm
</b></div>
<div class="kv"><span>Páginas:</span><b th:text="${paginasTotales} ?: 132">132</b></div>
<div class="kv"><span>Páginas Negro:</span><b th:text="${paginasNegro} ?: 100">100</b></div>
<div class="kv"><span>Páginas Color:</span><b th:text="${paginasColor} ?: 32">32</b></div>
<div class="subblock">
<div class="block-title">Interior</div>
<div class="kv"><span>Tipo de impresión:</span><b th:text="${interior?.tipoImpresion} ?: 'Color Premium'">Color Premium</b></div>
<div class="kv"><span>Papel interior:</span><b th:text="${interior?.papel} ?: 'Estucado Mate'">Estucado Mate</b></div>
<div class="kv"><span>Gramaje interior:</span><b th:text="${interior?.gramaje} ?: 115">115</b></div>
</div>
</div>
<div class="col">
<div class="subblock">
<div class="block-title">Cubierta</div>
<div class="kv"><span>Tipo de cubierta:</span><b th:text="${cubierta?.tipo} ?: 'Tapa blanda'">Tapa blanda</b></div>
<div class="kv"><span>Solapas:</span><b th:text="${cubierta?.solapas} ?: 'Sí'"></b></div>
<div class="kv"><span>Tamaño solapas:</span><b th:text="${cubierta?.tamSolapas} ?: '80 mm'">80 mm</b></div>
<div class="kv"><span>Impresión:</span><b th:text="${cubierta?.impresion} ?: 'Una cara'">Una cara</b></div>
<div class="kv"><span>Papel cubierta:</span><b th:text="${cubierta?.papel} ?: 'Estucado mate'">Estucado mate</b></div>
<div class="kv"><span>Gramaje cubierta:</span><b th:text="${cubierta?.gramaje} ?: 250">250</b></div>
<div class="kv"><span>Acabado:</span><b th:text="${cubierta?.acabado} ?: 'Plastificado Brillo 1/C'">Plastificado Brillo 1/C</b></div>
</div>
<div class="subblock">
<div class="block-title">Servicios Extras</div>
<!-- Ejemplos específicos -->
<div class="kv" th:if="${servicios != null}">
<ul class="services">
<li th:each="s : ${servicios}">
<span th:text="${s.descripcion}">Ferro Digital</span>
<span th:if="${s.precio != null}" th:text="${#numbers.formatDecimal(s.precio,1,'POINT',2,'COMMA')} + ' €'">0,00 €</span>
</li>
</ul>
</div>
<!-- Bloque marcapáginas (si existe en servicios) -->
<div class="bookmark" th:if="${marcapaginas != null}">
<div class="bk-title">Marcapáginas</div>
<div class="kv"><span>Tamaño:</span><b th:text="${marcapaginas.tamano} ?: '50x210'">50x210</b></div>
<div class="kv"><span>Papel:</span><b th:text="${marcapaginas.papel} ?: 'Estucado mate 300 g'">Estucado mate 300 g</b></div>
<div class="kv"><span>Impresión:</span><b th:text="${marcapaginas.impresion} ?: 'Una cara'">Una cara</b></div>
<div class="kv"><span>Plastificado:</span><b th:text="${marcapaginas.plastificado} ?: 'Brillo 1/C'">Brillo 1/C</b></div>
</div>
</div>
</div>
</div>
<!-- TABLA TIRADAS -->
<table class="prices">
<thead>
<!-- HEADER: logo izq + caja empresa dcha (tabla, sin flex) -->
<table class="il-header">
<tr>
<th class="col-tirada">TIRADA</th>
<th>IMPRESIÓN</th>
<th>IVA</th>
<th>TOTAL</th>
<th>UNIDAD</th>
<td class="il-left">
<img src="assets/images/logo-light.png" alt="ImprimeLibros" class="il-logo" />
</td>
<td class="il-right">
<div class="il-company-box">
<span class="corner tl"></span>
<span class="corner tr"></span>
<span class="corner bl"></span>
<span class="corner br"></span>
<div class="company-line company-name" th:text="#{pdf.company.name} ?: 'ImprimeLibros'">
ImprimeLibros ERP</div>
<div class="company-line" th:text="#{pdf.company.address} ?: ''">C/ José Picón, 28 local A</div>
<div class="company-line">
<span th:text="#{pdf.company.postalcode} ?: '28028'">28028</span>
<span th:text="#{pdf.company.city} ?: 'Madrid'">Madrid</span>
</div>
<div class="company-line" th:text="#{pdf.company.phone} ?: '+34 910052574'">+34 910052574</div>
</div>
</td>
</tr>
</thead>
<tbody>
<!-- Espera un modelo { tiradas:[...], impresion:[...], iva:[...], total:[...], unidad:[...] } -->
<tr th:each="i,idx : ${#numbers.sequence(0, #lists.size(pricing?.tiradas) - 1)}">
<td class="col-tirada" th:text="${pricing.tiradas[i]} + ' uds.'">100 uds.</td>
<td th:text="${#numbers.formatDecimal(pricing.impresion[i],1,'POINT',2,'COMMA')} + '€'">152,15€</td>
<td th:text="${#numbers.formatDecimal(pricing.iva[i],1,'POINT',2,'COMMA')} + '€'">7,68€</td>
<td th:text="${#numbers.formatDecimal(pricing.total[i],1,'POINT',2,'COMMA')} + '€'">159,99€</td>
<td th:text="${#numbers.formatDecimal(pricing.unidad[i],1,'POINT',2,'COMMA')} + '€'">1,52€</td>
</table>
<!-- BANDA SUPERIOR -->
<div class="doc-banner">
<div th:text="#{pdf.presupuesto} ?: 'PRESUPUESTO'" class="banner-text">PRESUPUESTO</div>
</div>
<!-- FICHA Nº / CLIENTE / FECHA -->
<table class="sheet-info">
<tr>
<td class="text-start"><span th:text="#{'pdf.presupuesto.number'}" class="lbl">PRESUPUESTO Nº:</span> <span
class="val" th:text="${numero}">153153</span></td>
<td class="text-center"><span th:text="#{pdf.presupuesto.client}" class="lbl">CLIENTE:</span> <span class="val"
th:text="${cliente?.nombre} ?: '-'">JUAN JOSÉ
MÉNDEZ</span></td>
<td class="text-end"><span class="lbl" th:text="#{pdf.presupuesto.date}">FECHA:</span> <span class="val"
th:text="${#temporals.format(fecha, 'dd/MM/yyyy')}">10/10/2025</span></td>
</tr>
</tbody>
</table>
</table>
<!-- TÍTULO DEL LIBRO -->
<div class="line-title">
<span class="lbl" th:text="#{pdf.presupuesto.titulo}">Título:</span>
<span class="val" th:text="${titulo} ?: '-'">Libro de prueba</span>
</div>
<!-- DATOS TÉCNICOS EN 2 COLUMNAS -->
<div class="specs-wrapper align-with-text ">
<div class="specs">
<div class="col">
<div class="block-title">Encuadernación</div>
<div class="kv"><span>Encuadernación:</span><b th:text="${encuadernacion} ?: 'Fresado'">Fresado</b></div>
<div class="kv"><span>Formato:</span><b>
<span th:text="${ancho}">148</span>x<span th:text="${alto}">210</span> mm
</b></div>
<div class="kv"><span>Páginas:</span><b th:text="${paginasTotales} ?: 132">132</b></div>
<div class="kv"><span>Páginas Negro:</span><b th:text="${paginasNegro} ?: 100">100</b></div>
<div class="kv"><span>Páginas Color:</span><b th:text="${paginasColor} ?: 32">32</b></div>
<div class="subblock">
<div class="block-title">Interior</div>
<div class="kv"><span>Tipo de impresión:</span><b
th:text="${interior?.tipoImpresion} ?: 'Color Premium'">Color
Premium</b></div>
<div class="kv"><span>Papel interior:</span><b th:text="${interior?.papel} ?: 'Estucado Mate'">Estucado
Mate</b>
</div>
<div class="kv"><span>Gramaje interior:</span><b th:text="${interior?.gramaje} ?: 115">115</b></div>
</div>
</div>
<div class="col">
<div class="subblock">
<div class="block-title">Cubierta</div>
<div class="kv"><span>Tipo de cubierta:</span><b th:text="${cubierta?.tipo} ?: 'Tapa blanda'">Tapa
blanda</b>
</div>
<div class="kv"><span>Solapas:</span><b th:text="${cubierta?.solapas} ?: 'Sí'"></b></div>
<div class="kv"><span>Tamaño solapas:</span><b th:text="${cubierta?.tamSolapas} ?: '80 mm'">80 mm</b></div>
<div class="kv"><span>Impresión:</span><b th:text="${cubierta?.impresion} ?: 'Una cara'">Una cara</b></div>
<div class="kv"><span>Papel cubierta:</span><b th:text="${cubierta?.papel} ?: 'Estucado mate'">Estucado
mate</b>
</div>
<div class="kv"><span>Gramaje cubierta:</span><b th:text="${cubierta?.gramaje} ?: 250">250</b></div>
<div class="kv"><span>Acabado:</span><b
th:text="${cubierta?.acabado} ?: 'Plastificado Brillo 1/C'">Plastificado
Brillo 1/C</b></div>
</div>
<div class="subblock">
<div class="block-title">Servicios Extras</div>
<!-- Ejemplos específicos -->
<div class="kv" th:if="${servicios != null}">
<ul class="services">
<li th:each="s : ${servicios}">
<span th:text="${s.descripcion}">Ferro Digital</span>
<span th:if="${s.precio != null}"
th:text="${#numbers.formatDecimal(s.precio,1,'POINT',2,'COMMA')} + ' €'">0,00 €</span>
</li>
</ul>
</div>
<!-- Bloque marcapáginas (si existe en servicios) -->
<div class="bookmark" th:if="${marcapaginas != null}">
<div class="bk-title">Marcapáginas</div>
<div class="kv"><span>Tamaño:</span><b th:text="${marcapaginas.tamano} ?: '50x210'">50x210</b></div>
<div class="kv"><span>Papel:</span><b th:text="${marcapaginas.papel} ?: 'Estucado mate 300 g'">Estucado
mate
300 g</b></div>
<div class="kv"><span>Impresión:</span><b th:text="${marcapaginas.impresion} ?: 'Una cara'">Una cara</b>
</div>
<div class="kv"><span>Plastificado:</span><b th:text="${marcapaginas.plastificado} ?: 'Brillo 1/C'">Brillo
1/C</b></div>
</div>
</div>
</div>
</div>
</div> <!-- .specs-wrapper -->
<!-- TABLA TIRADAS -->
<table class="prices">
<thead>
<tr>
<th class="col-tirada">TIRADA</th>
<th>IMPRESIÓN</th>
<th>IVA</th>
<th>TOTAL</th>
<th>UNIDAD</th>
</tr>
</thead>
<tbody th:if="${pricing != null and pricing.tiradas != null}">
<tr th:each="t, st : ${pricing.tiradas}">
<td class="col-tirada" th:text="${t} + ' uds.'">100 uds.</td>
<td th:text="${#numbers.formatDecimal(pricing.impresion[st.index],1,'POINT',2,'COMMA')} + '€'">152,15€</td>
<td th:text="${#numbers.formatDecimal(pricing.iva[st.index],1,'POINT',2,'COMMA')} + '€'">7,68€</td>
<td th:text="${#numbers.formatDecimal(pricing.total[st.index],1,'POINT',2,'COMMA')} + '€'">159,99€</td>
<td th:text="${#numbers.formatDecimal(pricing.unidad[st.index],1,'POINT',2,'COMMA')} + '€'">1,52€</td>
</tr>
</tbody>
<!-- Si no hay pricing, no renderizar filas -->
<tbody th:if="${pricing == null or pricing.tiradas == null}">
<tr>
<td colspan="5">Sin datos de tiradas.</td>
</tr>
</tbody>
</table>
</div>
<!-- PIE -->
<div class="footer">
<div class="address">
<div th:text="${empresa?.nombre} ?: 'Impresión Imprime libros SL'">Impresión Imprime libros SL</div>
<div th:text="${empresa?.direccion} ?: 'C. José Picón, 28 local A'">C. José Picón, 28 local A</div>
<div>28028 Madrid</div>
<div th:text="${empresa?.telefono} ?: '910052574'">910052574</div>
</div>
<div class="privacy">
<div class="pv-title">Política de privacidad</div>
<div class="pv-text">
Responsable: <span th:text="${empresa?.nombre} ?: 'Impresión Imprime Libros'">Impresión Imprime Libros</span> -
CIF: <span th:text="${empresa?.cif} ?: 'B04998886'">B04998886</span> -
Email: <span th:text="${empresa?.email} ?: 'info@imprimelibros.com'">info@imprimelibros.com</span> ·
Dirección: <span th:text="${empresa?.direccion} ?: 'Calle José Picón, Nº 28 Local A, 28028, Madrid'">Calle José Picón, Nº 28 Local A, 28028, Madrid</span>.
Sus datos se tratarán para la adecuada gestión fiscal y contable…
<div class="pv-title" th:text="#{pdf.politica-privacidad}">Política de privacidad</div>
<div class="pv-text" th:text="#{pdf.politica-privacidad.responsable}">Responsable: Impresión Imprime Libros - CIF:
B04998886 - Teléfono de contacto: 910052574</div>
<div class="pv-text" th:text="#{pdf.politica-privacidad.correo-direccion}">Correo electrónico:
info@imprimelibros.com - Dirección postal: Calle José Picón, Nº 28 Local A, 28028, Madrid</div>
<div class="pv-text" th:text="#{pdf.politica-privacidad.aviso}">
Le comunicamos que los datos que usted nos facilite quedarán incorporados
en nuestro registro interno de actividades de tratamiento con el fin de
llevar a cabo una adecuada gestión fiscal y contable.
Los datos proporcionados se conservarán mientras se mantenga la relación
comercial o durante los años necesarios para cumplir con las obligaciones legales.
Así mismo, los datos no serán cedidos a terceros salvo en aquellos casos en que exista
una obligación legal. Tiene derecho a acceder a sus datos personales, rectificar
los datos inexactos, solicitar su supresión, limitar alguno de los tratamientos
u oponerse a algún uso vía e-mail, personalmente o mediante correo postal.
</div>
</div>
</div>
<div class="page-count">Página <span class="page"></span> / <span class="pages"></span></div>
</body>
</html>
</html>

View File

@ -9,8 +9,8 @@
<div class="ribbon-content mt-4">
<div class="alert alert-danger alert-label-icon rounded-label fade show material-shadow d-none"
role="alert" id="datos-generales-alert">
<div class="alert alert-danger alert-label-icon rounded-label fade show material-shadow d-none" role="alert"
id="datos-generales-alert">
<i class="ri-error-warning-line label-icon"></i>
<strong th:text="#{presupuesto.errores-title}">Corrija los siguientes errores:</strong>
<ul class="mb-0" id="datos-generales-alert-list">
@ -33,13 +33,15 @@
<div class="col-sm-6">
<div class="mb-3">
<label for="autor" class="form-label" th:text="#{presupuesto.autor}">Autor</label>
<input type="text" class="form-control datos-generales-data" id="autor" th:value="${presupuesto?.autor} ?: ''">
<input type="text" class="form-control datos-generales-data" id="autor"
th:value="${presupuesto?.autor} ?: ''">
</div>
</div>
<div class="col-sm-6">
<div class="mb-3">
<label for="isbn" class="form-label" th:text="#{presupuesto.isbn}">ISBN</label>
<input type="text" class="form-control datos-generales-data" id="isbn" th:value="${presupuesto?.isbn} ?: ''" >
<input type="text" class="form-control datos-generales-data" id="isbn"
th:value="${presupuesto?.isbn} ?: ''">
</div>
</div>
</div>
@ -206,8 +208,8 @@
<!-- Opción: Cosido -->
<label class="tipo-libro image-container imagen-selector datos-generales-data"
th:attr="data-summary-text=#{presupuesto.cosido}" id="cosido">
<label class="tipo-libro image-container imagen-selector datos-generales-data"
th:attr="data-summary-text=#{presupuesto.cosido}" id="cosido">
<input type="radio" name="tipoEncuadernacion" value="cosido" hidden>
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/cosido.png"
alt="Cosido" />
@ -217,8 +219,8 @@
<!-- Opción: Grapado -->
<label class="tipo-libro image-container imagen-selector datos-generales-data"
th:attr="data-summary-text=#{presupuesto.grapado}" id="grapado">
<label class="tipo-libro image-container imagen-selector datos-generales-data"
th:attr="data-summary-text=#{presupuesto.grapado}" id="grapado">
<input type="radio" name="tipoEncuadernacion" value="grapado" hidden>
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/grapado.png"
alt="Grapado" />
@ -227,8 +229,8 @@
</label>
<!-- Opción: Espiral -->
<label class="tipo-libro image-container imagen-selector datos-generales-data"
th:attr="data-summary-text=#{presupuesto.espiral}" id="espiral">
<label class="tipo-libro image-container imagen-selector datos-generales-data"
th:attr="data-summary-text=#{presupuesto.espiral}" id="espiral">
<input type="radio" name="tipoEncuadernacion" value="espiral" hidden>
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/espiral.png"
alt="Espiral" />
@ -237,8 +239,8 @@
</label>
<!-- Opción: Wire-O -->
<label class="tipo-libro image-container imagen-selector datos-generales-data"
th:attr="data-summary-text=#{presupuesto.wire-o}" id="wireo">
<label class="tipo-libro image-container imagen-selector datos-generales-data"
th:attr="data-summary-text=#{presupuesto.wire-o}" id="wireo">
<input type="radio" name="tipoEncuadernacion" value="wireo" hidden>
<img class="image-presupuesto" src="/assets/images/imprimelibros/presupuestador/wire-o.png"
alt="Wire-O" />
@ -251,9 +253,54 @@
</div>
</div>
<!-- Ribbon Shape -->
<div class="card ribbon-box border shadow-none mb-lg-0 material-shadow mt-4">
<div class="card-body">
<div class="ribbon ribbon-primary ribbon-shape" th:text="#{presupuesto.informacion-adicional}">Información
adicional
</div>
<h5 class="fs-14 text-end" th:text="#{presupuesto.informacion-adicional-descripcion}"></h5>
</div>
<div class="ribbon-content mt-4">
<div class="row justify-content-center mb-2">
<div class="col-sm-3 justify-content-center">
<div
class="form-check form-switch form-switch-custom form-switch-presupuesto mb-3 d-flex align-items-center">
<input type="checkbox" class="form-check-input datos-generales-data me-2" id="iva-reducido"
name="iva-reducido">
<label for="iva-reducido" class="form-label d-flex align-items-center mb-0">
<span th:text="#{presupuesto.iva-reducido}" class="me-2">I.V. reducido</span>
<button type="button" id="btn-iva-reducido-detail"
class="btn btn-outline-primary btn-border btn-sm">
<i class="ri-questionnaire-line label-icon align-middle fs-16"></i>
</button>
</label>
</div>
</div>
<div class="row justify-content-center mb-2">
<div class="col-sm-3 justify-content-center">
<label for="entrega" class="form-label mt-2" th:text="#{presupuesto.entrega}">Entrega</label>
<select class="form-select select2 datos-generales-data" id="entrega" name="entrega">
<option selected value="peninsula" th:text="#{presupuesto.entrega.peninsula}">Península
y
Baleares</option>
<option value="canarias" th:text="#{presupuesto.entrega.canarias}">Canarias</option>
<option value="paises_ue" th:text="#{presupuesto.entrega.paises-ue}">Países UE</option>
</select>
</div>
</div>
</div>
</div>
</div>
<div class="d-flex align-items-center justify-content-center gap-3 mt-3">
<button type="button" id="next-datos-generales" class="btn btn-secondary d-flex align-items-center ms-auto order-2 order-md-3">
<button type="button" id="next-datos-generales"
class="btn btn-secondary d-flex align-items-center ms-auto order-2 order-md-3">
<span th:text="#{presupuesto.continuar-interior}">Continuar a diseño interior</span>
<i class="ri-arrow-right-circle-line fs-16 ms-2"></i>
</button>