Clientes y facturas de cliente
This commit is contained in:
parent
9ef847d54b
commit
a57dfe2a02
@ -1,254 +0,0 @@
|
||||
<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>Factura #{{id}}</title>
|
||||
<style>
|
||||
:root {
|
||||
--gray: #6b7280;
|
||||
--light: #f3f4f6;
|
||||
--border: #e5e7eb;
|
||||
}
|
||||
|
||||
@page {
|
||||
margin: 24mm 18mm;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
color: #000;
|
||||
font-size: 10.5pt;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.small {
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
.xsmall {
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--gray);
|
||||
}
|
||||
|
||||
.box {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: .375rem;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background: var(--light);
|
||||
}
|
||||
|
||||
.table th,
|
||||
.table td {
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.totals td {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.totals tr td:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
letter-spacing: .03em;
|
||||
}
|
||||
|
||||
#meta td {
|
||||
padding: .35rem .5rem;
|
||||
}
|
||||
|
||||
@media print {
|
||||
thead {
|
||||
display: table-header-group;
|
||||
}
|
||||
|
||||
tfoot {
|
||||
display: table-footer-group;
|
||||
}
|
||||
|
||||
a[href]:after {
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header id="header" class="mb-4">
|
||||
<section class="flex items-start justify-between">
|
||||
<!-- Bloque empresa -->
|
||||
<aside class="pr-4">
|
||||
<h1 class="text-2xl font-semibold leading-tight">{{dealer.name}}</h1>
|
||||
{{#if dealer.logo}}
|
||||
<img id="dealer-logo" src="{{dealer.logo}}" alt="Logo" class="mt-1 h-10 object-contain" />
|
||||
{{/if}}
|
||||
<address id="from" class="not-italic whitespace-pre-line small mt-2">
|
||||
{{dealer.contact_information}}
|
||||
</address>
|
||||
</aside>
|
||||
|
||||
<!-- Bloque meta factura -->
|
||||
<aside class="box p-3 min-w-[260px]">
|
||||
<table id="meta" class="w-full small">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="font-semibold">Factura nº:</td>
|
||||
<td class="text-right">{{reference}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-semibold">Fecha:</td>
|
||||
<td class="text-right">{{date}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-semibold">Página:</td>
|
||||
<td class="text-right"><span class="pageNumber"></span> / <span class="totalPages"></span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
<!-- Cliente -->
|
||||
<section class="grid grid-cols-2 gap-4 mt-4 pb-3 border-b border-gray-200">
|
||||
<aside>
|
||||
<h3 class="font-semibold mb-1">Cliente</h3>
|
||||
<address id="to" class="not-italic whitespace-pre-line">{{customer_information}}</address>
|
||||
</aside>
|
||||
<aside class="small">
|
||||
{{#if customer_reference}}
|
||||
<p><span class="font-semibold">Referencia cliente:</span> {{customer_reference}}</p>
|
||||
{{/if}}
|
||||
</aside>
|
||||
</section>
|
||||
</header>
|
||||
|
||||
<main id="main">
|
||||
<!-- Detalle líneas -->
|
||||
<section id="details" class="mt-3">
|
||||
<table class="table w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="text-left">
|
||||
<th class="px-2 py-2">Concepto</th>
|
||||
<th class="px-2 py-2 text-right w-24">Cantidad</th>
|
||||
<th class="px-2 py-2 text-right w-32">Precio unidad</th>
|
||||
{{#if any_item_has_discount}}
|
||||
<th class="px-2 py-2 text-right w-24">Dto (%)</th>
|
||||
{{/if}}
|
||||
<th class="px-2 py-2 text-right w-36">Importe total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each items}}
|
||||
<tr class="align-top">
|
||||
<td class="px-2 py-2">
|
||||
<div class="font-medium">{{description}}</div>
|
||||
{{#if note}}<div class="small muted whitespace-pre-line">{{note}}</div>{{/if}}
|
||||
</td>
|
||||
<td class="px-2 py-2 text-right">{{quantity}}</td>
|
||||
<td class="px-2 py-2 text-right">{{unit_price}}</td>
|
||||
{{#if ../any_item_has_discount}}
|
||||
<td class="px-2 py-2 text-right">{{discount}}</td>
|
||||
{{/if}}
|
||||
<td class="px-2 py-2 text-right">{{total_price}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="5" class="px-2 py-1 xsmall muted">* Precios en {{currency}}.</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<!-- Resumen / totales -->
|
||||
<section id="resume" class="grid grid-cols-2 gap-6 mt-6">
|
||||
<!-- Notas y forma de pago -->
|
||||
<aside>
|
||||
{{#if payment_method}}
|
||||
<p class="small"><span class="font-semibold">Forma de pago:</span> {{payment_method}}</p>
|
||||
{{/if}}
|
||||
{{#if notes}}
|
||||
<div class="mt-2 small"><span class="font-semibold">Notas:</span> {{notes}}</div>
|
||||
{{/if}}
|
||||
|
||||
{{!-- Bloque especial Domiciliación bancaria --}}
|
||||
{{#if payment_is_direct_debit}}
|
||||
<div class="mt-4 box p-3 small">
|
||||
<div class="font-semibold mb-1 uppercase tracking-wide">DOMICILIACIÓN BANCARIA</div>
|
||||
<div class="whitespace-pre-line">{{direct_debit_text}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</aside>
|
||||
|
||||
<!-- Totals box -->
|
||||
<aside class="justify-self-end w-full max-w-md">
|
||||
<table class="w-full totals">
|
||||
<tbody>
|
||||
{{#if subtotal_price}}
|
||||
<tr>
|
||||
<td class="py-1">Importe neto</td>
|
||||
<td class="py-1 text-right">{{subtotal_price}}</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
{{#if discount_price}}
|
||||
<tr>
|
||||
<td class="py-1">% Descuento ({{discount.amount}})</td>
|
||||
<td class="py-1 text-right">-{{discount_price}}</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
<tr class="border-t border-gray-200">
|
||||
<td class="py-1 font-medium">Base imponible</td>
|
||||
<td class="py-1 text-right font-medium">{{before_tax_price}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-1">IVA {{tax}}</td>
|
||||
<td class="py-1 text-right">{{tax_price}}</td>
|
||||
</tr>
|
||||
<tr class="border-t-2 border-gray-300">
|
||||
<td class="py-2 text-lg font-semibold">Total factura</td>
|
||||
<td class="py-2 text-right text-lg font-semibold">{{total_price}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
<!-- Términos legales -->
|
||||
<section id="legal_terms" class="mt-6">
|
||||
<p class="xsmall muted whitespace-pre-line">{{quote.default_legal_terms}}</p>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer id="footer" class="mt-8 pt-3 border-t border-gray-200">
|
||||
<div class="grid grid-cols-2 gap-4 small">
|
||||
<div>
|
||||
<span class="font-semibold">{{dealer.name}}</span>
|
||||
<div class="whitespace-pre-line">{{dealer.footer_information}}</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
{{#if dealer.website}}<div><a href="{{dealer.website}}">{{dealer.website}}</a></div>{{/if}}
|
||||
{{#if dealer.email}}<div>{{dealer.email}}</div>{{/if}}
|
||||
{{#if dealer.phone}}<div>{{dealer.phone}}</div>{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{{!-- Helpers opcionales esperados por la plantilla --}}
|
||||
{{!--
|
||||
any_item_has_discount: boolean precomputado en tu código
|
||||
payment_is_direct_debit: boolean si forma de pago es domiciliación
|
||||
direct_debit_text: texto para el bloque de domiciliación bancaria
|
||||
currency: ISO o símbolo (EUR, €, etc.)
|
||||
--}}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -119,7 +119,6 @@
|
||||
<div class="p-1 ">
|
||||
<p>Factura nº:<strong> {{invoice_number}}</strong></p>
|
||||
<p><span>Fecha:<strong> {{invoice_date}}</strong></p>
|
||||
<p><span>Página:</span><span class="pageNumber"></span> / <span class="totalPages"></span></p>
|
||||
</div>
|
||||
<div class="p-1 ml-9">
|
||||
<h2 class="font-semibold uppercase mb-1">{{recipient.name}}</h2>
|
||||
|
||||
@ -38,7 +38,7 @@ export interface CustomerInvoiceProps {
|
||||
languageCode: LanguageCode;
|
||||
currencyCode: CurrencyCode;
|
||||
|
||||
taxes: Maybe<InvoiceTaxes>;
|
||||
taxes: InvoiceTaxes;
|
||||
items: CustomerInvoiceItems;
|
||||
|
||||
discountPercentage: Percentage;
|
||||
@ -71,10 +71,7 @@ export class CustomerInvoice
|
||||
currencyCode: props.currencyCode,
|
||||
});
|
||||
|
||||
this._taxes = props.taxes.match(
|
||||
(taxes) => taxes,
|
||||
() => InvoiceTaxes.create({})
|
||||
);
|
||||
this._taxes = props.taxes;
|
||||
}
|
||||
|
||||
static create(props: CustomerInvoiceProps, id?: UniqueID): Result<CustomerInvoice, Error> {
|
||||
|
||||
@ -115,5 +115,5 @@ export const customerInvoicesRouter = (params: ModuleParams) => {
|
||||
}
|
||||
);
|
||||
|
||||
app.use(`${baseRoutePath}/customer-invoices`, router);
|
||||
app.use(`${baseRoutePath}/proforma-invoices`, router);
|
||||
};
|
||||
|
||||
@ -11,7 +11,7 @@ import {
|
||||
extractOrPushError,
|
||||
maybeFromNullableVO,
|
||||
} from "@repo/rdx-ddd";
|
||||
import { Maybe, Result } from "@repo/rdx-utils";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import {
|
||||
CustomerInvoice,
|
||||
CustomerInvoiceItems,
|
||||
@ -243,7 +243,7 @@ export class CustomerInvoiceDomainMapper
|
||||
|
||||
discountPercentage: attributes.discountPercentage!,
|
||||
|
||||
taxes: Maybe.some(taxes),
|
||||
taxes: taxes,
|
||||
items,
|
||||
};
|
||||
|
||||
|
||||
@ -200,8 +200,8 @@ const data2 = {
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Facturas de cliente",
|
||||
url: "/customer-invoices",
|
||||
title: "Proformas de cliente",
|
||||
url: "/customer-proforma",
|
||||
icon: Bot,
|
||||
items: [
|
||||
{
|
||||
@ -219,8 +219,8 @@ const data2 = {
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Documentation",
|
||||
url: "#",
|
||||
title: "Facturas de cliente",
|
||||
url: "/customer-invoices",
|
||||
icon: BookOpen,
|
||||
items: [
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user