This commit is contained in:
David Arranz 2024-08-01 16:55:30 +02:00
parent e73aeaeefe
commit 2650690772
19 changed files with 286722 additions and 155 deletions

View File

@ -12,5 +12,8 @@
"asciidoc.antora.enableAntoraSupport": true,
// other vscode settings
"tailwindCSS.rootFontSize": 16 // <- your root font size here
"tailwindCSS.rootFontSize": 16,
"[handlebars]": {
"editor.defaultFormatter": "vscode.html-language-features"
} // <- your root font size here
}

57
docker-compose.yml Normal file
View File

@ -0,0 +1,57 @@
version: "3.8"
services:
mariadb:
image: mariadb:latest
container_name: mariadb
environment:
MYSQL_ROOT_PASSWORD: uZm#bch6pPs8
MYSQL_DATABASE: uecko
MYSQL_USER: uecko
MYSQL_PASSWORD: u8Ax5Nw3%sjd
volumes:
- mariadb_data:/var/lib/mysql
networks:
- bridge
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: phpmyadmin
environment:
PMA_HOST: mariadb
PMA_USER: uecko
PMA_PASSWORD: u8Ax5Nw3%sjd
ports:
- "8080:80"
networks:
- bridge
nginx:
image: nginx:latest
container_name: nginx
volumes:
- nginx_conf:/etc/nginx
- nginx_html:/usr/share/nginx/html
ports:
- "80:80"
- "443:443"
networks:
- bridge
nodejs:
image: node:lts-iron
container_name: nodejs
ports:
- "3000:3000"
volumes:
- ./app:/usr/src/app
working_dir: /usr/src/app
volumes:
mariadb_data:
nginx_html:
nginx_conf:
app:
networks:
bridge:

2
server/.prettierignore Normal file
View File

@ -0,0 +1,2 @@
**/*.hbs

14
server/Dockerfile Normal file
View File

@ -0,0 +1,14 @@
FROM node:20 as builder
RUN corepack enable && corepack prepare pnpm@latest --activate
ENV PNPM_HOME=/usr/local/bin
# Establecer el directorio de trabajo
WORKDIR /api
COPY ./server/package.json pnpm-lock.yaml ./
# Copiar el código de la aplicación
COPY . .
RUN pnpm install
RUN pnpm build

View File

@ -79,6 +79,7 @@
"passport-local": "^1.0.0",
"path": "^0.12.7",
"puppeteer": "^22.13.1",
"puppeteer-report": "^3.1.0",
"remove": "^0.1.5",
"response-time": "^2.3.2",
"sequelize": "^6.37.3",

7595
server/pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

138833
server/public/css/tailwind.min.css vendored Normal file

File diff suppressed because it is too large Load Diff

1
server/public/index.html Normal file
View File

@ -0,0 +1 @@
<h1>public</h1>

138833
server/public/tailwind.min.css vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,65 +5,64 @@ import { ISalesContext } from "../../../../../Sales.context";
import { readFileSync } from "fs";
import * as handlebars from "handlebars";
import path from "path";
import * as puppeteer from "puppeteer";
import puppeteer from "puppeteer";
import report from "puppeteer-report";
export interface IReportQuoteReporter {
toHTML: (quote: Quote, context: ISalesContext) => string;
toPDF: (quote: Quote, context: ISalesContext) => Promise<Buffer>;
}
// https://plnkr.co/edit/lWk6Yd?preview
export const ReportQuotePresenter: IReportQuoteReporter = {
toHTML: (quote: Quote, context: ISalesContext): string => {
const quote_dto = map(quote, context);
//console.log(quote_dto);
// Obtener y compilar la plantilla HTML
const templateHtml = obtenerPlantillaHTML();
const templateHtml = readFileSync(
path.join(__dirname, "./templates/quote/template.hbs")
).toString();
const template = handlebars.compile(templateHtml, {});
const html = template(quote_dto);
return html;
return template(quote_dto);
},
toPDF: async (quote: Quote, context: ISalesContext): Promise<Buffer> => {
const html = ReportQuotePresenter.toHTML(quote, context);
// Generar el PDF con Puppeteer
const browser = await puppeteer.launch();
const page = await browser.newPage();
const browser = await puppeteer.launch({
args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage"],
});
const page = await browser.newPage();
const navigationPromise = page.waitForNavigation();
await page.setContent(html, { waitUntil: "networkidle2" });
const pdfBuffer = await page.pdf({
//path: "quote.pdf",
format: "A4",
printBackground: false,
displayHeaderFooter: false,
//headerTemplate: `<div style="font-size:12px; text-align:center; width:100%; margin:0 auto;">Quote #${quote_dto.id}</div>`,
//footerTemplate: `<div style="font-size:12px; text-align:center; width:100%; margin:0 auto;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>`,
await navigationPromise;
const reportPDF = await report.pdfPage(page, {
format: "a4",
margin: {
top: "0mm",
bottom: "0mm",
left: "0mm",
right: "0mm",
bottom: "10mm",
left: "10mm",
right: "10mm",
top: "10mm",
},
});
await browser.close();
return pdfBuffer;
return Buffer.from(reportPDF);
},
};
const obtenerPlantillaHTML = (): string => {
return readFileSync(path.join(__dirname, "./templates/quote.hbs")).toString();
};
const map = (quote: Quote, context: ISalesContext) => {
const { dealer } = context;
return {
id: quote.id.toString(),
status: quote.status.toString(),
date: quote.date.toISO8601(),
date: quote.date.toLocaleDateString(),
reference: quote.reference.toString(),
customer_information: quote.customer.toString(),
lang_code: quote.language.toString(),

View File

@ -0,0 +1,466 @@
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Presupuesto #29b6ac1a-ce83-44be-ac3a-714ceee1983f</title>
<style type="text/css">
.header {
background-color: #f0f0f0;
padding: 10px;
border-bottom: 1px solid #ccc;
}
.content {
padding: 20px;
}
/* Estilos para la impresión */
@media print {
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
background-color: #f0f0f0;
padding: 10px;
border-bottom: 1px solid #ccc;
}
.content {
margin-top: 100px;
/* Ajusta según el tamaño de tu cabecera */
}
@page {
margin-top: 0;
/* Ajusta según el tamaño de tu cabecera */
}
}
</style>
</head>
<body style="background-color: white;">
<header>
<div class="page-header">
<div class="header-content">
<div class="dealer-info">
<h1>DISTRIBUIDOR OFICIAL</h1>
<div class="contact-info">
<div class="mt-2">
<img src="https://via.placeholder.com/100x50" alt="Logo distribuidor" />
</div>
<div class="mt-2 text-sm">
GRUPO DE INTERIORES GTH, S.L.
Calle Castilla, 204
28009 Madrid
</div>
</div>
</div>
<div class="text-right">
<img src="https://via.placeholder.com/150x50" alt="Uecko Logo" />
<p class="text-xs text-gray-500">Essential Furniture</p>
<p class="text-xs text-gray-500">PREMIO AMBARRO DEL AÑO 2021</p>
<p class="text-xs text-gray-500">LUXURY SPAIN</p>
<p class="text-xs text-gray-500">ELLE 2021</p>
</div>
</div>
<div class="grid grid-cols-2 gap-4 pb-4 mb-4 border-b">
<div>
<p class="text-sm"><strong>Presupuesto nº:</strong> 29b6ac1a-ce83-44be-ac3a-714ceee1983f</p>
<p class="text-sm"><strong>Fecha:</strong> 2024-07-24T00:00:00.000Z</p>
<p class="text-sm"><strong>Validez:</strong> 2024-02-05</p>
<p class="text-sm"><strong>Vendedor:</strong> GRUPO DE INTERIORES GTH, S.L.</p>
<p class="text-sm"><strong>Referencia cliente:</strong> PR/8633</p>
</div>
<div>
<p class="text-sm">ALICIA PELAEZ SEVILLA, S.L.
AVDA. NAZARET - SEPARACION DE AMBIENTES Y PUERTAS DE PASO V2 SD</p>
</div>
</div>
<div class="mb-4">
<h2 style="font-size: 1.25rem; font-weight: 600;">Cotización</h2>
</div>
</div>
</header>
<footer>
<div class="page-footer">
<div class="page-footer-content">
<p>Información básica sobre protección de datos</p>
<p></p>
</div>
</div>
</footer>
<main>
<table>
<thead>
<tr>
<th class="page-header-space">HEADER
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="page-content">
<div class="page">
<!-- Contenido de la página -->
</div>
<div class="page">
<table class="table-header">
<thead>
<tr>
<th class="px-2 py-2 text-right border">Cant.</th>
<th class="px-2 py-2 border">Descripción</th>
<th class="px-2 py-2 text-right border">Prec. Unitario</th>
<th class="px-2 py-2 text-right border">Subtotal</th>
<th class="px-2 py-2 text-right border">Dto (%)</th>
<th class="px-2 py-2 text-right border">Importe total</th>
</tr>
</thead>
<tbody class="table-body">
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right"></td>
<td class="px-2 py-2 font-medium"> CORREDERAS</td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P1
Puerta de paso corredera lisa lacada BLANCO AV-501 a determinar de dimensiones 2600x1500 mm. incluyendo Kit de casonetto. </td>
<td class="content-start px-2 py-2 text-right">14,50 </td>
<td class="content-start px-2 py-2 text-right">14,50 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">14,50 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P7
Puerta de paso corredera lisa lacada BLANCO AV-501 a determinar de dimensiones 2600x820 mm incluyendo Kit de casonetto.</td>
<td class="content-start px-2 py-2 text-right">9,60 </td>
<td class="content-start px-2 py-2 text-right">9,60 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">9,60 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P8
Puerta de paso corredera lisa lacada BLANCO AV-501 a determinar de dimensiones 2600x820 mm incluyendo Kit de casonetto.</td>
<td class="content-start px-2 py-2 text-right">9,60 </td>
<td class="content-start px-2 py-2 text-right">9,60 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">9,60 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P9
Puerta de paso corredera lisa lacada BLANCO AV-501 a determinar de dimensiones 2600x960 mm incluyendo Kit de casonetto.</td>
<td class="content-start px-2 py-2 text-right">9,95 </td>
<td class="content-start px-2 py-2 text-right">9,95 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">9,95 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P10
Puerta de paso corredera lisa lacada BLANCO AV-501 a determinar de dimensiones 2600x965 mm. incluyendo Kit de casonetto.</td>
<td class="content-start px-2 py-2 text-right">9,95 </td>
<td class="content-start px-2 py-2 text-right">9,95 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">9,95 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P12
Puerta de paso corredera lisa lacada BLANCO AV-501 a determinar de dimensiones 2600x760 mm. incluyendo Kit de casonetto.</td>
<td class="content-start px-2 py-2 text-right">8,86 </td>
<td class="content-start px-2 py-2 text-right">8,86 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">8,86 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P13
Puerta de paso corredera lisa lacada BLANCO AV-501 a determinar de dimensiones 2600x760 mm. incluyendo Kit de casonetto.</td>
<td class="content-start px-2 py-2 text-right">8,86 </td>
<td class="content-start px-2 py-2 text-right">8,86 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">8,86 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P14
Puerta de paso corredera lisa lacada BLANCO AV-501 a determinar de dimensiones 2600x747 mm. incluyendo Kit de casonetto.</td>
<td class="content-start px-2 py-2 text-right">8,86 </td>
<td class="content-start px-2 py-2 text-right">8,86 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">8,86 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P15
Puerta de paso corredera lisa lacada BLANCO AV-501 a determinar de dimensiones 2600x900 mm. incluyendo Kit de casonetto.</td>
<td class="content-start px-2 py-2 text-right">9,60 </td>
<td class="content-start px-2 py-2 text-right">9,60 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">9,60 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right"></td>
<td class="px-2 py-2 font-medium"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right"></td>
<td class="px-2 py-2 font-medium"> ABATIBLES</td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P2
Puertas de paso abatible 1/c enrasada, sin cabecero, lisa lacado BLANCO AV-501 de 50 mm de espesor, de dimensiones de hoja 2600x860 mm. con cerco de 100/140x35, tapetas hasta 120x19 mm., resbalón unificado y bisagras ocultas negras. Apertura der</td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P3
Puertas de paso abatible 1/c enrasada, sin cabecero, lisa lacado BLANCO AV-501 de 50 mm de espesor, de dimensiones de hoja 2600x885 mm. con cerco de 100/140x35, tapetas hasta 120x19 mm., resbalón unificado y bisagras ocultas negras. Apertura der</td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1,75</td>
<td class="px-2 py-2 font-medium">Forrado paramentos 19 mm lacado m²</td>
<td class="content-start px-2 py-2 text-right">1,56 </td>
<td class="content-start px-2 py-2 text-right">2,72 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">2,72 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P4
Puertas de paso abatible 1/c enrasada, sin cabecero, lisa lacado BLANCO AV-501 de 50 mm de espesor, de dimensiones de hoja 2600x985 mm. con cerco de 100/140x35, tapetas hasta 120x19 mm., resbalón unificado y bisagras ocultas negras. Apertura der</td>
<td class="content-start px-2 py-2 text-right">11,81 </td>
<td class="content-start px-2 py-2 text-right">11,81 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">11,81 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P5
Puertas de paso abatible 1/c enrasada, sin cabecero, lisa lacado BLANCO AV-501 de 50 mm de espesor, de dimensiones de hoja 2600x885 mm. con cerco de 100/140x35, tapetas hasta 120x19 mm., resbalón unificado y bisagras ocultas negras. Apertura izq</td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">1</td>
<td class="px-2 py-2 font-medium"> P6
Puertas de paso abatible 1/c enrasada, sin cabecero, lisa lacado BLANCO AV-501 de 50 mm de espesor, de dimensiones de hoja 2600x885 mm. con cerco de 100/140x35, tapetas hasta 120x19 mm., resbalón unificado y bisagras ocultas negras. Apertura der</td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">11,05 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right"></td>
<td class="px-2 py-2 font-medium"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right"></td>
<td class="px-2 py-2 font-medium"> NOTA.-
-Casonetto propiedad del cliente.
-Manivelas y/o condenas no incluidas.</td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right"></td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right"></td>
<td class="px-2 py-2 font-medium"> DESCUENTO </td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right"></td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right"></td>
<td class="px-2 py-2 font-medium">null</td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
<td class="content-start px-2 py-2 text-right"></td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">161</td>
<td class="px-2 py-2 font-medium"> M.l. Rodapie lacado BLANCO AV-501 a determinar DE 200X19 mm con dos estrías horizontales </td>
<td class="content-start px-2 py-2 text-right">0,15 </td>
<td class="content-start px-2 py-2 text-right">24,79 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">24,79 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">0</td>
<td class="px-2 py-2 font-medium"> DESCUENTO </td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">0</td>
<td class="px-2 py-2 font-medium">null</td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">3</td>
<td class="px-2 py-2 font-medium"> Entrega de material en domicilio cliente</td>
<td class="content-start px-2 py-2 text-right">1,20 </td>
<td class="content-start px-2 py-2 text-right">3,60 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">3,60 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">0</td>
<td class="px-2 py-2 font-medium"> DESCUENTO </td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">0</td>
<td class="px-2 py-2 font-medium">null</td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">9</td>
<td class="px-2 py-2 font-medium"> Instalación PUERTA DE PASO CORREDERA</td>
<td class="content-start px-2 py-2 text-right">1,30 </td>
<td class="content-start px-2 py-2 text-right">11,70 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">11,70 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">5</td>
<td class="px-2 py-2 font-medium"> Instalación PUERTA DE PASO ABATIBLE</td>
<td class="content-start px-2 py-2 text-right">1,00 </td>
<td class="content-start px-2 py-2 text-right">5,00 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">5,00 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">159</td>
<td class="px-2 py-2 font-medium"> Instalación M.L. RODAPIE </td>
<td class="content-start px-2 py-2 text-right">0,09 </td>
<td class="content-start px-2 py-2 text-right">13,52 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">13,52 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">0</td>
<td class="px-2 py-2 font-medium"> DESCUENTO </td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
</tr>
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">0</td>
<td class="px-2 py-2 font-medium">null</td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
<td class="content-start px-2 py-2 text-right">0</td>
<td class="content-start px-2 py-2 text-right">0,00 </td>
</tr>
</tbody>
</table>
</div>
<div class="page"></div>
<div class="flex items-center justify-between pb-4 mb-4 border-b">
<div>
<div class="pt-4 border-t">
<p class="text-sm"><strong>Forma de pago:</strong> 60% Aceptación presupuesto
30% Un día antes de la entrega del material
10% Restante a la finalización de la obra</p>
</div>
<div class="pt-4 border-t">
<p class="text-sm"><strong>Notas:</strong> Este presupuesto no se considerará en firme hasta confirmar medidas y diseños definitivos. </p>
</div>
</div>
<div>
<table class="table-footer">
<tbody>
<tr class="border-b">
<td class="px-4 py-2 border">Importe neto</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 text-right border">207,12 </td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 border">% Descuento</td>
<td class="px-4 py-2 text-right border"></td>
<td class="px-4 py-2 text-right border"></td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 border">Impuestos</td>
<td class="px-4 py-2 text-right border"></td>
<td class="px-4 py-2 text-right border"></td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 border">Envío</td>
<td class="px-4 py-2 text-right border"></td>
<td class="px-4 py-2 text-right border"></td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 font-medium border">Total</td>
<td class="px-4 py-2 font-medium border"></td>
<td class="px-4 py-2 font-medium text-right border">207,12 </td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@ -0,0 +1,319 @@
<html lang="{{lang_code}}">
<head>
<meta charset="UTF-8" />
<title>Presupuesto #{{id}}</title>
<style type="text/css">
@page {
font-family: Pacifico;
margin: 1cm;
@bottom-left {
color: #1ee494;
content: "♥ Thank you!";
}
@bottom-right {
color: #a9a;
content: "contact@courtbouillon.org | courtbouillon.org";
font-size: 9pt;
}
}
.fullpage {
page: full;
}
.page {
margin: 7cm 0 0 0;
page-break-after: avoid;
}
html {
color: #14213d;
font-family: Source Sans Pro;
font-size: 11pt;
line-height: 1.6;
}
body {
margin: 0;
}
header {
position: fixed;
top: 0mm;
width: 100%;
border-bottom: 1px solid black;
/* for demo */
background: transparent;
/* for demo */
}
.page-header-space {}
.page-footer-space {}
h1 {
color: #1ee494;
font-family: Pacifico;
font-size: 40pt;
margin: 0;
}
aside {
display: flex;
margin: 2em 0 4em;
}
aside address {
flex: 1;
font-style: normal;
white-space: pre-line;
}
aside address#from {
border: 1px solid red;
color: #a9a;
flex: 1;
}
aside address#to {
border: 1px solid green;
text-align: right;
}
dl {
position: absolute;
right: 0;
text-align: right;
top: 0;
}
dt,
dd {
display: inline;
margin: 0;
}
dt {
color: #a9a;
}
dt::before {
content: "";
display: block;
}
dt::after {
content: "";
}
table {
border-collapse: collapse;
width: 100%;
}
th {
border-bottom: 0.2mm solid #a9a;
color: #a9a;
font-size: 10pt;
font-weight: 400;
padding-bottom: 0.25cm;
text-transform: uppercase;
}
td {
padding-top: 7mm;
}
td:last-of-type {
color: #1ee494;
font-weight: bold;
text-align: right;
}
th,
td {
text-align: center;
}
th:first-of-type,
td:first-of-type {
text-align: left;
}
th:last-of-type,
td:last-of-type {
text-align: right;
}
footer {
content: "";
display: block;
height: 6cm;
}
table#total {
background: #f6f6f6;
border-color: #f6f6f6;
border-style: solid;
border-width: 2cm 3cm;
bottom: 0;
font-size: 20pt;
margin: 0 -3cm;
position: absolute;
width: 18cm;
}
@media print {
thead {
display: table-header-group;
}
tfoot {
display: table-footer-group;
}
}
</style>
</head>
<body>
<main>
<table>
<thead>
<tr>
<th class="page-header-space">
<header>
<h1>Invoice</h1>
<aside>
<address id="from">
{{dealer.contact_information}}
</address>
<address id="to">
{{customer_information}}
</address>
</aside>
<dl id="informations">
</header>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="page">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tincidunt metus eu consectetur rutrum.
Praesent tempor facilisis dapibus. Aliquam cursus diam ac vehicula pulvinar. Integer lacinia non odio et
condimentum. Aenean faucibus cursus mi, sed interdum turpis sagittis a. Quisque quis pellentesque mi. Ut
erat eros, posuere sed scelerisque ut, pharetra vitae tellus. Suspendisse ligula sapien, laoreet ac
hendrerit sit amet, viverra vel mi. Pellentesque faucibus nisl et dolor pharetra, vel mattis massa
venenatis. Integer congue condimentum nisi, sed tincidunt velit tincidunt non. Nulla sagittis sed lorem
pretium aliquam. Praesent consectetur volutpat nibh, quis pulvinar est volutpat id. Cras maximus odio
posuere suscipit venenatis. Donec rhoncus scelerisque metus, in tempus erat rhoncus sed. Morbi massa
sapien,
porttitor id urna vel, volutpat blandit velit. Cras sit amet sem eros. Quisque commodo facilisis
tristique.
Proin pellentesque sodales rutrum. Vestibulum purus neque, congue vel dapibus in, venenatis ut felis.
Donec
et ligula enim. Sed sapien sapien, tincidunt vitae lectus quis, ultricies rhoncus mi. Nunc dapibus nulla
tempus nunc interdum, sed facilisis ex pellentesque. Nunc vel lorem leo. Cras pharetra sodales metus.
Cras
lacus ex, consequat at consequat vel, laoreet ac dui. Curabitur aliquam, sapien quis congue feugiat,
nisi
nisl feugiat diam, sed vehicula velit nulla ac nisl. Aliquam quis nisi euismod massa blandit pharetra
nec
eget nunc. Etiam eros ante, auctor sit amet quam vel, fringilla faucibus leo. Morbi a pulvinar nulla.
Praesent sed vulputate nisl. Orci varius natoque penatibus et magnis dis parturient montes, nascetur
ridiculus mus. Aenean commodo mollis iaculis. Maecenas consectetur enim vitae mollis venenatis. Ut
scelerisque pretium orci id laoreet. In sit amet pharetra diam. Vestibulum in molestie lorem. Nunc
gravida,
eros non consequat fermentum, ex orci vestibulum orci, non accumsan sem velit ac lectus. Vivamus
malesuada
lacus nec velit dignissim, ac fermentum nulla pretium. Aenean mi nisi, convallis sed tempor in,
porttitor
eu
libero. Praesent et molestie ante. Duis suscipit vitae purus sit amet aliquam. Vestibulum lectus justo,
lobortis a purus a, dapibus efficitur metus. Suspendisse potenti. Duis dictum ex lorem. Suspendisse nec
ligula consectetur magna hendrerit ullamcorper et eget mauris. Etiam vestibulum sodales diam, eget
venenatis
nunc luctus quis. Ut fermentum placerat neque nec elementum. Praesent orci erat, rhoncus vitae est eu,
dictum molestie metus. Cras et fermentum elit. Aenean eget augue lacinia, varius ante in, ullamcorper
dolor.
Cras viverra purus non egestas consectetur. Nulla nec dolor ac lectus convallis aliquet sed a metus.
Suspendisse eu imperdiet nunc, id pulvinar risus. Maecenas varius sagittis est, vel fermentum risus
accumsan
at. Vestibulum sollicitudin dui pharetra sapien volutpat, id convallis mi vestibulum. Phasellus commodo
sit
amet lorem quis imperdiet. Proin nec diam sed urna euismod ultricies at sed urna. Quisque ornare, nulla
et
vehicula ultrices, massa purus vehicula urna, ac sodales lacus leo vitae mi. Sed congue placerat justo
at
placerat. Aenean suscipit fringilla vehicula. Quisque iaculis orci vitae arcu commodo maximus. Maecenas
nec
nunc rutrum, cursus elit quis, porttitor sapien. Sed ac hendrerit ipsum, lacinia fringilla velit. Donec
ultricies feugiat dictum.
</div>
<div class="page">
<table class="min-w-full bg-white page">
<thead class="bg-gray-200">
<tr class="text-xs">
<th class="px-2 py-2 text-right border">Cant.</th>
<th class="px-2 py-2 border">Descripción</th>
<th class="px-2 py-2 text-right border">Prec. Unitario</th>
<th class="px-2 py-2 text-right border">Subtotal</th>
<th class="px-2 py-2 text-right border">Dto (%)</th>
<th class="px-2 py-2 text-right border">Importe total</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">{{quantity}}</td>
<td class="px-2 py-2 font-medium">{{description}}</td>
<td class="content-start px-2 py-2 text-right">{{unit_price}}</td>
<td class="content-start px-2 py-2 text-right">{{subtotal_price}}</td>
<td class="content-start px-2 py-2 text-right">{{discount}}</td>
<td class="content-start px-2 py-2 text-right">{{total_price}}</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</main>
<footer>
<table id="total">
<thead>
<tr>
<th>Due by</th>
<th>Account number</th>
<th>Total due</th>
</tr>
</thead>
<tbody>
<tr>
<td>May 10, 2018</td>
<td>132 456 789 012</td>
<td>€10,545.00</td>
</tr>
</tbody>
</table>
</footer>
</body>
</html>

View File

@ -0,0 +1,136 @@
@font-face {
font-family: Pacifico;
src: url(pacifico.ttf);
}
@font-face {
font-family: Source Sans Pro;
font-weight: 400;
src: url(sourcesanspro-regular.otf);
}
@font-face {
font-family: Source Sans Pro;
font-weight: 700;
src: url(sourcesanspro-bold.otf);
}
@page {
font-family: Pacifico;
margin: 3cm;
@bottom-left {
color: #1ee494;
content: "♥ Thank you!";
}
@bottom-right {
color: #a9a;
content: "contact@courtbouillon.org | courtbouillon.org";
font-size: 9pt;
}
}
.fullpage {
page: full;
}
html {
color: #14213d;
font-family: Source Sans Pro;
font-size: 11pt;
line-height: 1.6;
}
body {
margin: 0;
}
h1 {
color: #1ee494;
font-family: Pacifico;
font-size: 40pt;
margin: 0;
}
aside {
display: flex;
margin: 2em 0 4em;
}
aside address {
font-style: normal;
white-space: pre-line;
}
aside address#from {
color: #a9a;
flex: 1;
}
aside address#to {
text-align: right;
}
dl {
position: absolute;
right: 0;
text-align: right;
top: 0;
}
dt,
dd {
display: inline;
margin: 0;
}
dt {
color: #a9a;
}
dt::before {
content: "";
display: block;
}
dt::after {
content: ":";
}
table {
border-collapse: collapse;
width: 100%;
}
th {
border-bottom: 0.2mm solid #a9a;
color: #a9a;
font-size: 10pt;
font-weight: 400;
padding-bottom: 0.25cm;
text-transform: uppercase;
}
td {
padding-top: 7mm;
}
td:last-of-type {
color: #1ee494;
font-weight: bold;
text-align: right;
}
th,
td {
text-align: center;
}
th:first-of-type,
td:first-of-type {
text-align: left;
}
th:last-of-type,
td:last-of-type {
text-align: right;
}
footer {
content: "";
display: block;
height: 6cm;
}
table#total {
background: #f6f6f6;
border-color: #f6f6f6;
border-style: solid;
border-width: 2cm 3cm;
bottom: 0;
font-size: 20pt;
margin: 0 -3cm;
position: absolute;
width: 18cm;
}

View File

@ -1,129 +0,0 @@
<html lang="{{lang_code}}">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Presupuesto #{{id}}</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css"
referrerpolicy="no-referrer"
/>
</head>
<body class="px-20 py-12 bg-transparent border">
<div>
<div class="flex items-center justify-between pb-4 mb-4 border-b">
<div class="bg-red-400 border border-green-500">
<h1 class="text-2xl font-bold">DISTRIBUIDOR OFICIAL</h1>
<div class="flex space-x-4 bg-blue-500 border">
<div class="mt-2">
<img src="https://via.placeholder.com/100x50" alt="Logo distribuidor" />
</div>
<div class="mt-2 text-sm">
{{dealer.contact_information}}
</div>
</div>
</div>
<div class="text-right">
<img src="https://via.placeholder.com/150x50" alt="Uecko Logo" />
<p class="text-xs text-gray-500">Essential Furniture</p>
<p class="text-xs text-gray-500">PREMIO AMBARRO DEL AÑO 2021</p>
<p class="text-xs text-gray-500">LUXURY SPAIN</p>
<p class="text-xs text-gray-500">ELLE 2021</p>
</div>
</div>
<div class="grid grid-cols-2 gap-4 pb-4 mb-4 border-b">
<div>
<p class="text-sm"><strong>Presupuesto nº:</strong> {{id}}</p>
<p class="text-sm"><strong>Fecha:</strong> {{date}}</p>
<p class="text-sm"><strong>Validez:</strong> {{validity}}</p>
<p class="text-sm"><strong>Vendedor:</strong> {{dealer.name}}</p>
<p class="text-sm"><strong>Referencia cliente:</strong> {{reference}}</p>
</div>
<div>
<p class="text-sm">{{customer_information}}</p>
</div>
</div>
<div class="mb-4">
<h2 class="mb-2 text-xl font-semibold">Cotización</h2>
<table class="min-w-full bg-white">
<thead class="bg-gray-200">
<tr class="text-xs">
<th class="px-2 py-2 text-right border">Cant.</th>
<th class="px-2 py-2 border">Descripción</th>
<th class="px-2 py-2 text-right border">Prec. Unitario</th>
<th class="px-2 py-2 text-right border">Subtotal</th>
<th class="px-2 py-2 text-right border">Dto (%)</th>
<th class="px-2 py-2 text-right border">Importe total</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">{{quantity}}</td>
<td class="px-2 py-2 font-medium">{{description}}</td>
<td class="content-start px-2 py-2 text-right">{{unit_price}}</td>
<td class="content-start px-2 py-2 text-right">{{subtotal_price}}</td>
<td class="content-start px-2 py-2 text-right">{{discount}}</td>
<td class="content-start px-2 py-2 text-right">{{total_price}}</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
<div class="flex items-center justify-between pb-4 mb-4 border-b">
<div>
<div class="pt-4 border-t">
<p class="text-sm"><strong>Forma de pago:</strong> {{payment_method}}</p>
</div>
<div class="pt-4 border-t">
<p class="text-sm"><strong>Notas:</strong> {{notes}} </p>
</div>
</div>
<div>
<table class="min-w-full bg-transparent">
<tbody>
<tr class="border-b">
<td class="px-4 py-2 border">Importe neto</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 text-right border">{{subtotal_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 border">% Descuento</td>
<td class="px-4 py-2 text-right border">{{discount.amount}}</td>
<td class="px-4 py-2 text-right border">{{discount_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 border">Base imponible</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 text-right border">{{before_tax_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 border">% IVA</td>
<td class="px-4 py-2 text-right border">{{tax}}</td>
<td class="px-4 py-2 text-right border">{{tax_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 border">Importe total</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 text-right border">{{total_price}}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="pt-4 mt-4 border-t">
<p class="text-xs text-gray-500">Información básica sobre protección de datos</p>
<p class="text-xs text-gray-500">{{quote.default_legal_terms}}</p>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,267 @@
<html lang="{{lang_code}}">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Presupuesto #{{id}}</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css"
referrerpolicy="no-referrer" />
<style type="text/css">
header,
.page-header,
.page-header-space {
height: 300px;
}
footer,
.page-footer,
.page-footer-space {
height: 50px;
}
footer,
.page-footer {
position: fixed;
bottom: 0;
width: 100%;
border-top: 1px solid black;
/* for demo */
background: transparent;
/* for demo */
}
header,
.page-header {
position: fixed;
top: 0mm;
width: 100%;
border-bottom: 1px solid black;
/* for demo */
background: transparent;
/* for demo */
}
.page {
page-break-after: avoid;
}
@page {
margin: 20mm
}
@media print {
thead {
display: table-header-group;
}
tfoot {
display: table-footer-group;
}
button {
display: none;
}
body {
margin: 0;
}
}
</style>
</head>
<body class="bg-white">
<div class="page-header">
<div class="flex items-center justify-between pb-4 mb-4 border-b">
<div class="bg-red-400 border border-green-500">
<h1 class="text-2xl font-bold">DISTRIBUIDOR OFICIAL</h1>
<div class="flex space-x-4 bg-blue-500 border">
<div class="mt-2">
<img src="https://via.placeholder.com/100x50" alt="Logo distribuidor" />
</div>
<div class="mt-2 text-sm">
{{dealer.contact_information}}
</div>
</div>
</div>
<div class="text-right">
<img src="https://via.placeholder.com/150x50" alt="Uecko Logo" />
<p class="text-xs text-gray-500">Essential Furniture</p>
<p class="text-xs text-gray-500">PREMIO AMBARRO DEL AÑO 2021</p>
<p class="text-xs text-gray-500">LUXURY SPAIN</p>
<p class="text-xs text-gray-500">ELLE 2021</p>
</div>
</div>
<div class="grid grid-cols-2 gap-4 pb-4 mb-4 border-b">
<div>
<p class="text-sm"><strong>Presupuesto nº:</strong> {{id}}</p>
<p class="text-sm"><strong>Fecha:</strong> {{date}}</p>
<p class="text-sm"><strong>Validez:</strong> {{validity}}</p>
<p class="text-sm"><strong>Vendedor:</strong> {{dealer.name}}</p>
<p class="text-sm"><strong>Referencia cliente:</strong> {{reference}}</p>
</div>
<div>
<p class="text-sm">{{customer_information}}</p>
</div>
</div>
<div class="mb-4">
<h2 class="mb-2 text-xl font-semibold">Cotización</h2>
</div>
</div>
<div class="page-footer">
<div class="pt-4 mt-4 border-t">
<p class="text-xs text-gray-500">Información básica sobre protección de datos</p>
<p class="text-xs text-gray-500">{{quote.default_legal_terms}}</p>
</div>
</div>
<table>
<thead>
<tr>
<th class="page-header-space">
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="page-content">
<div class="page">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tincidunt metus eu consectetur rutrum.
Praesent tempor facilisis dapibus. Aliquam cursus diam ac vehicula pulvinar. Integer lacinia non odio et
condimentum. Aenean faucibus cursus mi, sed interdum turpis sagittis a. Quisque quis pellentesque mi. Ut
erat eros, posuere sed scelerisque ut, pharetra vitae tellus. Suspendisse ligula sapien, laoreet ac
hendrerit sit amet, viverra vel mi. Pellentesque faucibus nisl et dolor pharetra, vel mattis massa
venenatis. Integer congue condimentum nisi, sed tincidunt velit tincidunt non. Nulla sagittis sed lorem
pretium aliquam. Praesent consectetur volutpat nibh, quis pulvinar est volutpat id. Cras maximus odio
posuere suscipit venenatis. Donec rhoncus scelerisque metus, in tempus erat rhoncus sed. Morbi massa
sapien,
porttitor id urna vel, volutpat blandit velit. Cras sit amet sem eros. Quisque commodo facilisis
tristique.
Proin pellentesque sodales rutrum. Vestibulum purus neque, congue vel dapibus in, venenatis ut felis.
Donec
et ligula enim. Sed sapien sapien, tincidunt vitae lectus quis, ultricies rhoncus mi. Nunc dapibus nulla
tempus nunc interdum, sed facilisis ex pellentesque. Nunc vel lorem leo. Cras pharetra sodales metus. Cras
lacus ex, consequat at consequat vel, laoreet ac dui. Curabitur aliquam, sapien quis congue feugiat, nisi
nisl feugiat diam, sed vehicula velit nulla ac nisl. Aliquam quis nisi euismod massa blandit pharetra nec
eget nunc. Etiam eros ante, auctor sit amet quam vel, fringilla faucibus leo. Morbi a pulvinar nulla.
Praesent sed vulputate nisl. Orci varius natoque penatibus et magnis dis parturient montes, nascetur
ridiculus mus. Aenean commodo mollis iaculis. Maecenas consectetur enim vitae mollis venenatis. Ut
scelerisque pretium orci id laoreet. In sit amet pharetra diam. Vestibulum in molestie lorem. Nunc
gravida,
eros non consequat fermentum, ex orci vestibulum orci, non accumsan sem velit ac lectus. Vivamus malesuada
lacus nec velit dignissim, ac fermentum nulla pretium. Aenean mi nisi, convallis sed tempor in, porttitor
eu
libero. Praesent et molestie ante. Duis suscipit vitae purus sit amet aliquam. Vestibulum lectus justo,
lobortis a purus a, dapibus efficitur metus. Suspendisse potenti. Duis dictum ex lorem. Suspendisse nec
ligula consectetur magna hendrerit ullamcorper et eget mauris. Etiam vestibulum sodales diam, eget
venenatis
nunc luctus quis. Ut fermentum placerat neque nec elementum. Praesent orci erat, rhoncus vitae est eu,
dictum molestie metus. Cras et fermentum elit. Aenean eget augue lacinia, varius ante in, ullamcorper
dolor.
Cras viverra purus non egestas consectetur. Nulla nec dolor ac lectus convallis aliquet sed a metus.
Suspendisse eu imperdiet nunc, id pulvinar risus. Maecenas varius sagittis est, vel fermentum risus
accumsan
at. Vestibulum sollicitudin dui pharetra sapien volutpat, id convallis mi vestibulum. Phasellus commodo
sit
amet lorem quis imperdiet. Proin nec diam sed urna euismod ultricies at sed urna. Quisque ornare, nulla et
vehicula ultrices, massa purus vehicula urna, ac sodales lacus leo vitae mi. Sed congue placerat justo at
placerat. Aenean suscipit fringilla vehicula. Quisque iaculis orci vitae arcu commodo maximus. Maecenas
nec
nunc rutrum, cursus elit quis, porttitor sapien. Sed ac hendrerit ipsum, lacinia fringilla velit. Donec
ultricies feugiat dictum.
</div>
<div class="page">
<table class="min-w-full bg-white page">
<thead class="bg-gray-200">
<tr class="text-xs">
<th class="px-2 py-2 text-right border">Cant.</th>
<th class="px-2 py-2 border">Descripción</th>
<th class="px-2 py-2 text-right border">Prec. Unitario</th>
<th class="px-2 py-2 text-right border">Subtotal</th>
<th class="px-2 py-2 text-right border">Dto (%)</th>
<th class="px-2 py-2 text-right border">Importe total</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">{{quantity}}</td>
<td class="px-2 py-2 font-medium">{{description}}</td>
<td class="content-start px-2 py-2 text-right">{{unit_price}}</td>
<td class="content-start px-2 py-2 text-right">{{subtotal_price}}</td>
<td class="content-start px-2 py-2 text-right">{{discount}}</td>
<td class="content-start px-2 py-2 text-right">{{total_price}}</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
<div class="page"></div>
<div class="flex items-center justify-between pb-4 mb-4 border-b">
<div>
<div class="pt-4 border-t">
<p class="text-sm"><strong>Forma de pago:</strong> {{payment_method}}</p>
</div>
<div class="pt-4 border-t">
<p class="text-sm"><strong>Notas:</strong> {{notes}} </p>
</div>
</div>
<div>
<table class="min-w-full bg-transparent">
<tbody>
<tr class="border-b">
<td class="px-4 py-2 border">Importe neto</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 text-right border">{{subtotal_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 border">% Descuento</td>
<td class="px-4 py-2 text-right border">{{discount.amount}}</td>
<td class="px-4 py-2 text-right border">{{discount_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 border">Base imponible</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 text-right border">{{before_tax_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 border">% IVA</td>
<td class="px-4 py-2 text-right border">{{tax}}</td>
<td class="px-4 py-2 text-right border">{{tax_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2 border">Importe total</td>
<td class="px-4 py-2 border"></td>
<td class="px-4 py-2 text-right border">{{total_price}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
<div class="page-footer-space"></div>
</td>
</tr>
</tfoot>
</table>
</body>
</html>

View File

@ -0,0 +1,169 @@
<html lang="{{lang_code}}">
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css"
referrerpolicy="no-referrer" />
<title>Presupuesto #{{id}}</title>
<style>
@page {
size: A4;
}
@media print {
html,
body {
width: 210mm;
height: 297mm;
}
}
body {
font-family: Arial, Helvetica, sans-serif;
color: #000;
font-size: 11pt;
line-height: 1.6;
}
#header {}
#footer {}
@media print {
thead {
display: table-header-group;
}
tfoot {
display: table-footer-group;
}
}
</style>
</head>
<body>
<header id="header">
<aside class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold">DISTRIBUIDOR OFICIAL</h3>
<div id="logo" class="w-32">
<svg viewBox="0 0 336 133" fill="none" xmlns="http://www.w3.org/2000/svg" class="uecko-logo">
<path
d="M49.7002 83.0001H66.9002V22.5001H49.7002V56.2001C49.7002 64.3001 45.5002 68.5001 39.0002 68.5001C32.5002 68.5001 28.6002 64.3001 28.6002 56.2001V22.5001H0.700195V33.2001H11.4002V61.6001C11.4002 75.5001 19.0002 84.1001 31.9002 84.1001C40.6002 84.1001 45.7002 79.5001 49.6002 74.4001V83.0001H49.7002ZM120.6 48.0001H94.8002C96.2002 40.2001 100.8 35.1001 107.9 35.1001C115.1 35.2001 119.6 40.3001 120.6 48.0001ZM137.1 58.7001C137.2 57.1001 137.3 56.1001 137.3 54.4001V54.2001C137.3 37.0001 128 21.4001 107.8 21.4001C90.2002 21.4001 77.9002 35.6001 77.9002 52.9001V53.1001C77.9002 71.6001 91.3002 84.4001 109.5 84.4001C120.4 84.4001 128.6 80.1001 134.2 73.1001L124.4 64.4001C119.7 68.8001 115.5 70.6001 109.7 70.6001C102 70.6001 96.6002 66.5001 94.9002 58.7001H137.1ZM162.2 52.9001V52.7001C162.2 43.8001 168.3 36.2001 176.9 36.2001C183 36.2001 186.8 38.8001 190.7 42.9001L201.2 31.6001C195.6 25.3001 188.4 21.4001 177 21.4001C158.5 21.4001 145.3 35.6001 145.3 52.9001V53.1001C145.3 70.4001 158.6 84.4001 176.8 84.4001C188.9 84.4001 195.6 79.8001 201.5 73.3001L191.5 63.1001C187.3 67.1001 183.4 69.5001 177.6 69.5001C168.2 69.6001 162.2 62.1001 162.2 52.9001ZM269.1 83.0001L245.3 46.3001L268.3 22.5001H247.8L227.7 44.5001V0.600098H210.5V83.0001H227.7V64.6001L233.7 58.3001L249.5 83.0001H269.1ZM318.5 53.1001C318.5 62.0001 312.6 69.6001 302.8 69.6001C293.3 69.6001 286.9 61.8001 286.9 52.9001V52.7001C286.9 43.8001 292.8 36.2001 302.6 36.2001C312.1 36.2001 318.5 44.0001 318.5 52.9001V53.1001ZM335.4 52.9001V52.7001C335.4 35.3001 321.5 21.4001 302.8 21.4001C284 21.4001 270 35.5001 270 52.9001V53.1001C270 70.5001 283.9 84.4001 302.6 84.4001C321.4 84.4001 335.4 70.3001 335.4 52.9001Z"
fill="black" class="uecko-logo"></path>
</svg>
</div>
</aside>
<section class="flex pb-2 space-x-4">
<img id="dealer-logo" src="https://via.placeholder.com/200x100" alt="Logo distribuidor" />
<address class="text-base not-italic font-medium whitespace-pre-line" id="from">{{dealer.contact_information}}
</address>
</section>
<section class="grid grid-cols-2 gap-4 pb-4 mb-4 border-b">
<aside>
<p class="text-sm"><strong>Presupuesto nº:</strong> {{id}}</p>
<p class="text-sm"><strong>Fecha:</strong> {{date}}</p>
<p class="text-sm"><strong>Validez:</strong> {{validity}}</p>
<p class="text-sm"><strong>Vendedor:</strong> {{dealer.name}}</p>
<p class="text-sm"><strong>Referencia cliente:</strong> {{reference}}</p>
</aside>
<address class="text-base not-italic font-semibold whitespace-pre-line" id="to">{{customer_information}}
</address>
</section>
<aside class="flex items-center justify-between mb-4">
<h3 class="text-2xl font-normal">PRESUPUESTO</h3>
<div id="header-pagination">
Página <span class="pageNumber"></span> de <span class="totalPages"></span>
</div>
</aside>
</header>
<main id="main">
<section id="details">
<table class="table-header">
<thead>
<tr>
<th class="px-2 py-2 text-right border">Cant.</th>
<th class="px-2 py-2 border">Descripción</th>
<th class="px-2 py-2 text-right border">Prec. Unitario</th>
<th class="px-2 py-2 text-right border">Subtotal</th>
<th class="px-2 py-2 text-right border">Dto (%)</th>
<th class="px-2 py-2 text-right border">Importe total</th>
</tr>
</thead>
<tbody class="table-body">
{{#each items}}
<tr class="text-sm border-b">
<td class="content-start px-2 py-2 text-right">{{quantity}}</td>
<td class="px-2 py-2 font-medium">{{description}}</td>
<td class="content-start px-2 py-2 text-right">{{unit_price}}</td>
<td class="content-start px-2 py-2 text-right">{{subtotal_price}}</td>
<td class="content-start px-2 py-2 text-right">{{discount}}</td>
<td class="content-start px-2 py-2 text-right">{{total_price}}</td>
</tr>
{{/each}}
</tbody>
</table>
</section>
<section id="resume" class="flex items-center justify-between pb-4 mb-4">
<div class="grow">
<div class="pt-4">
<p class="text-sm"><strong>Forma de pago:</strong> {{payment_method}}</p>
</div>
<div class="pt-4">
<p class="text-sm"><strong>Notas:</strong> {{notes}} </p>
</div>
</div>
<div class="grow">
<table class="min-w-full bg-transparent">
<tbody>
<tr class="border-b">
<td class="px-4 py-2">Importe neto</td>
<td class="px-4 py-2"></td>
<td class="px-4 py-2 text-right border">{{subtotal_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2">% Descuento</td>
<td class="px-4 py-2 text-right border">{{discount.amount}}</td>
<td class="px-4 py-2 text-right border">{{discount_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2">Base imponible</td>
<td class="px-4 py-2"></td>
<td class="px-4 py-2 text-right border">{{before_tax_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2">% IVA</td>
<td class="px-4 py-2 text-right border">{{tax}}</td>
<td class="px-4 py-2 text-right border">{{tax_price}}</td>
</tr>
<tr class="border-b">
<td class="px-4 py-2">Importe total</td>
<td class="px-4 py-2"></td>
<td class="px-4 py-2 text-right border">{{total_price}}</td>
</tr>
</tbody>
</table>
</div>
</section>
<section id="legal_terms">
<p class="text-xs text-gray-500">{{quote.default_legal_terms}}</p>
</section>
</main>
<footer id="footer" class="mt-4">
<aside><img src="https://uecko.com/assets/img/uecko-footer_logos.jpg" class="w-full" /></aside>
</footer>
</body>
</html>

View File

@ -0,0 +1 @@
<svg viewBox="0 0 336 133" fill="none" xmlns="http://www.w3.org/2000/svg" class="uecko-logo"><path d="M49.7002 83.0001H66.9002V22.5001H49.7002V56.2001C49.7002 64.3001 45.5002 68.5001 39.0002 68.5001C32.5002 68.5001 28.6002 64.3001 28.6002 56.2001V22.5001H0.700195V33.2001H11.4002V61.6001C11.4002 75.5001 19.0002 84.1001 31.9002 84.1001C40.6002 84.1001 45.7002 79.5001 49.6002 74.4001V83.0001H49.7002ZM120.6 48.0001H94.8002C96.2002 40.2001 100.8 35.1001 107.9 35.1001C115.1 35.2001 119.6 40.3001 120.6 48.0001ZM137.1 58.7001C137.2 57.1001 137.3 56.1001 137.3 54.4001V54.2001C137.3 37.0001 128 21.4001 107.8 21.4001C90.2002 21.4001 77.9002 35.6001 77.9002 52.9001V53.1001C77.9002 71.6001 91.3002 84.4001 109.5 84.4001C120.4 84.4001 128.6 80.1001 134.2 73.1001L124.4 64.4001C119.7 68.8001 115.5 70.6001 109.7 70.6001C102 70.6001 96.6002 66.5001 94.9002 58.7001H137.1ZM162.2 52.9001V52.7001C162.2 43.8001 168.3 36.2001 176.9 36.2001C183 36.2001 186.8 38.8001 190.7 42.9001L201.2 31.6001C195.6 25.3001 188.4 21.4001 177 21.4001C158.5 21.4001 145.3 35.6001 145.3 52.9001V53.1001C145.3 70.4001 158.6 84.4001 176.8 84.4001C188.9 84.4001 195.6 79.8001 201.5 73.3001L191.5 63.1001C187.3 67.1001 183.4 69.5001 177.6 69.5001C168.2 69.6001 162.2 62.1001 162.2 52.9001ZM269.1 83.0001L245.3 46.3001L268.3 22.5001H247.8L227.7 44.5001V0.600098H210.5V83.0001H227.7V64.6001L233.7 58.3001L249.5 83.0001H269.1ZM318.5 53.1001C318.5 62.0001 312.6 69.6001 302.8 69.6001C293.3 69.6001 286.9 61.8001 286.9 52.9001V52.7001C286.9 43.8001 292.8 36.2001 302.6 36.2001C312.1 36.2001 318.5 44.0001 318.5 52.9001V53.1001ZM335.4 52.9001V52.7001C335.4 35.3001 321.5 21.4001 302.8 21.4001C284 21.4001 270 35.5001 270 52.9001V53.1001C270 70.5001 283.9 84.4001 302.6 84.4001C321.4 84.4001 335.4 70.3001 335.4 52.9001Z" fill="black" class="uecko-logo"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB