Plantilla de impresión de facturas
Las dos piezas de la factura de DemoUp: el documento API que produce el JSON y la plantilla Vue que lo muestra, con cada clave del JSON y su condición.
La factura de DemoUp son dos documentos dinámicos sobre la sección Ventas / Ingresos, los dos con la pregunta v.Factura. Factura JSON (tipo API) construye los datos; Factura - Moderna (tipo impresión) los incluye y los muestra con Vue.
Antes de empezar
- Un documento dinámico creado como en Crear documento dinámico, con JSON + Vue como texto de partida.
- Las funciones de tablas en memoria: Documentos y gráficos.
Cómo se unen
La plantilla incluye el documento API con F.Include y le pasa su propia pregunta. La salida del documento API es el objeto data de Vue:
<script>
const data = <!--: F.Include(S.DynamicDocuments.API.FacturaJSON.ID, v.Factura) :-->;
const app = Vue.createApp({
data() { return { data }; },
computed: {
resumen() { return this.data?.Resumen?.[0] || null; },
conceptos() { return this.data?.Conceptos || []; },
baseImponible() { return this.data?.BaseImponible || []; },
totales() { return this.data?.Totales || []; },
hayRE() { return this.baseImponible.some(x => Number(x?.CuotaRE || 0) > 0); },
totalesFiltrados() { return this.totales.filter(t => t.Concepto !== 'Total'); },
totalAbsoluto() { return this.totales.filter(t => t.Concepto === 'Total'); }
},
methods: {
euro(v) { return new Intl.NumberFormat('es-ES', { style: 'currency', currency: 'EUR' }).format(Number(v || 0)); }
}
});
app.mount('#app');
</script>F.Include(id, ...) admite tras el ID las preguntas del documento incluido, en su orden.
El JSON
Factura JSON crea cuatro tablas con F.DataTable_New y las escribe en JSON con F.DataTable_Build(tabla, 'jsonarrayf'):
{
"Resumen": <!--: F.Write(v.JSONResumen) :-->,
"Conceptos": <!--: F.Write(v.JSONConceptos) :-->,
"BaseImponible": <!--: F.Write(v.JSONBaseImponible) :-->,
"Totales": <!--: F.Write(v.JSONTotales) :-->
}Resumen
Una sola fila. En Vue se lee como resumen.<Clave>.
| Clave | Origen |
|---|---|
NumeroFactura, Fecha, FechaVencimiento, FacturaRectificada | Campos de la factura. Las fechas pasan por F.Cast_DateToText(fecha, S.Enums.formatofecha.diamesaño). |
ClienteNombre, ClienteNIF, ClienteDireccion, ClienteEmail, ClienteTelefono, ClienteCodigoPostal, ClientePoblacion, ClienteProvincia | Datos del cliente copiados en la factura. |
EmpresaRazonSocial, EmpresaNIF, EmpresaDireccion, EmpresaEmail, EmpresaTelefono, EmpresaCodigoPostal, EmpresaPoblacion, EmpresaProvincia, EmpresaWeb | Datos fiscales de la empresa emisora. |
LogoURL | D.EmpresaActual.URLLogoFactura. |
DatosFiscales, CondicionesPago, Notas, EnlacePago, DireccionEnvio | Textos opcionales de la factura. |
Conceptos
Una fila por línea de Lista - Ventas / Ingresos, filtrada con F.DataListLoadAddFilter por RelacionElementoContenedorListador igual a v.Factura.
| Clave | Campo de I.VentasIngresosLista |
|---|---|
Concepto | TextoPrincipal |
PrecioUnidad | ImportePrecioUnidad |
Unidades | CantidadUnidades |
Dtos | ImporteDescuentoFijoUnidad y SumaDescuentosPorcientoPorciento, formateados con F.FormatMoney y F.FormatPercentage |
Descuentos | ImporteTotalDescuentos |
Total | ImporteTotalConcepto |
BaseImponible
Una fila por base con importe distinto de cero: ImporteBaseImponible1, 2, 3 y ImporteBaseImponibleExenta.
| Clave | Origen |
|---|---|
BaseImponible | v.Factura.ImporteBaseImponibleN |
IVAPorciento | v.Factura.ReferenciaImpuestoN.ValorPorciento |
CuotaIVA | v.Factura.ImporteBaseImponibleNCuotaIVA |
REPorciento | v.Factura.ReferenciaImpuestoN.RecargoEquivalenciaPorciento |
CuotaRE | v.Factura.ImporteBaseImponibleNCuotaRE |
Totales
Filas Concepto / Importe: Subtotal, IVA, Suplidos y Total. totalAbsoluto separa la fila Total para mostrarla aparte.
Qué se muestra y cuándo
| Siempre | Con v-if |
|---|---|
resumen.NumeroFactura, resumen.Fecha, resumen.EmpresaRazonSocial, resumen.EmpresaNIF, resumen.EmpresaDireccion | resumen.LogoURL, resumen.FacturaRectificada, resumen.FechaVencimiento, resumen.DireccionEnvio, resumen.CondicionesPago, resumen.Notas, resumen.EnlacePago, resumen.EmpresaEmail, conceptos y totales (si traen filas) |
El bloque de cliente entero va bajo v-if="resumen.ClienteNIF". La tabla de bases usa hayRE para elegir entre cinco columnas y tres:
<table style="margin-top:20px; border-collapse:collapse; font-size:13px;">
<thead style="background-color:#edf2f7;">
<tr v-if="hayRE">
<th>Tipo</th><th>Base</th><th>Cuota IVA</th><th>RE %</th><th>Cuota RE</th>
</tr>
<tr v-else>
<th>Tipo</th><th>Base</th><th>Cuota</th>
</tr>
</thead>
<tbody>
<template v-for="(bi, i) in baseImponible" :key="i">
<tr v-if="hayRE">
<td>{{ bi.IVAPorciento }}%</td>
<td>{{ euro(bi.BaseImponible) }}</td>
<td>{{ euro(bi.CuotaIVA) }}</td>
<td>{{ bi.REPorciento }}</td>
<td>{{ euro(bi.CuotaRE) }}</td>
</tr>
<tr v-else>
<td>{{ bi.IVAPorciento }}%</td>
<td>{{ euro(bi.BaseImponible) }}</td>
<td>{{ euro(bi.CuotaIVA) }}</td>
</tr>
</template>
</tbody>
</table>Metadatos de la plantilla
Factura - Moderna fija titulo, email_subject, email_to, email_to_name y email_body con el ID de Factura - Plantilla de Email. El detalle está en Envío de emails.
Siguiente: Ejemplos. Otra factura completa sin Vue: Impresión de factura emitida.