This commit is contained in:
David Arranz 2025-12-09 11:42:13 +01:00
parent a42e762b17
commit c319e55744
9 changed files with 176773 additions and 96 deletions

View File

@ -17,7 +17,7 @@ import {
type CustomerInvoiceStatus,
InvoiceAmount,
type InvoiceRecipient,
type InvoiceTaxGroup,
InvoiceTaxGroup,
type ItemAmount,
} from "../value-objects";
@ -66,7 +66,7 @@ export interface ICustomerInvoice {
hasRecipient: boolean;
hasPaymentMethod: boolean;
getTaxes(): Collection<InvoiceTaxGroup>;
//getTaxes(): Collection<InvoiceTaxGroup>;
getProps(): CustomerInvoiceProps;
}
@ -231,6 +231,8 @@ export class CustomerInvoice
const taxesAmount = this._toInvoiceAmount(itemsTotals.taxesAmount);
const totalAmount = this._toInvoiceAmount(itemsTotals.totalAmount);
const taxGroups = this._groupTaxes();
return {
subtotalAmount,
itemDiscountAmount,
@ -239,6 +241,7 @@ export class CustomerInvoice
taxableAmount,
taxesAmount,
totalAmount,
taxGroups,
} as const;
}
@ -296,39 +299,40 @@ export class CustomerInvoice
return this.calculateAllAmounts().totalAmount;
}
/**
* @summary Devuelve la agrupación de impuestos útil para poblar `customer_invoice_taxes`.
*/
public getTaxesGroupedByCode() {
return this.items.groupTaxesByCode();
}
public getTaxes(): Collection<InvoiceTaxGroup> {
const map = this.items.groupTaxesByCode();
const currency = this.currencyCode.code;
const result = new Collection<InvoiceTaxGroup>([]);
for (const [tax_code, entry] of map.entries()) {
const value: InvoiceTaxGroup = {
ta,
};
result.push(value);
/*result.push({
tax: entry.tax,
taxableAmount: InvoiceAmount.create({
value: entry.taxable.convertScale(2).value,
currency_code: currency,
}).data,
taxesAmount: InvoiceAmount.create({
value: entry.total.convertScale(2).value,
currency_code: currency,
}).data,
});*/
return this._groupTaxes();
}
return new Collection(result);
/**
* @summary Agrupa impuestos a nivel factura usando el trío (iva|rec|ret),
* construyendo InvoiceTaxGroup desde los datos de los ítems.
*/
private _groupTaxes(): Collection<InvoiceTaxGroup> {
const map = this.items.groupTaxesByCode();
const groups: InvoiceTaxGroup[] = [];
for (const [, entry] of map.entries()) {
const { taxes, taxable } = entry;
const iva = taxes.iva.unwrap(); // IVA siempre obligatorio
const rec = taxes.rec; // Maybe<Tax>
const retention = taxes.retention; // Maybe<Tax>
const invoiceAmount = InvoiceAmount.create({
value: taxable.convertScale(InvoiceAmount.DEFAULT_SCALE).value,
currency_code: this.currencyCode.code,
}).data;
const item = InvoiceTaxGroup.create({
iva,
rec,
retention,
taxableAmount: invoiceAmount,
}).data;
groups.push(item);
}
return new Collection(groups);
}
}

View File

@ -1,8 +1,7 @@
import type { Tax } from "@erp/core/api";
import type { CurrencyCode, LanguageCode, Percentage } from "@repo/rdx-ddd";
import { Collection } from "@repo/rdx-utils";
import { ItemAmount, ItemDiscount } from "../../value-objects";
import { ItemAmount, ItemDiscount, type ItemTaxGroup } from "../../value-objects";
import type { CustomerInvoiceItem } from "./customer-invoice-item";
@ -184,81 +183,61 @@ export class CustomerInvoiceItems extends Collection<CustomerInvoiceItem> {
}
/**
* @summary Agrupa bases e importes por código fiscal.
* @remarks
* Este método se usa para poblar la tabla `customer_invoice_taxes`.
* @summary Recalcula totales agrupando por el trío iva, rec y retención.
*/
public groupTaxesByCode() {
const map = new Map<string, { tax: Tax; taxable: ItemAmount; total: ItemAmount }>();
const map = new Map<
string,
{
taxes: ItemTaxGroup;
taxable: ItemAmount;
ivaAmount: ItemAmount;
recAmount: ItemAmount;
retentionAmount: ItemAmount;
taxesAmount: ItemAmount;
}
>();
for (const item of this.getAll()) {
const amounts = item.calculateAllAmounts();
const taxable = amounts.taxableAmount;
const { ivaAmount, recAmount, retentionAmount, taxesAmount } = amounts;
const { ivaAmount, recAmount, retentionAmount } = amounts;
const taxes = item.taxes;
const ivaCode = taxes.iva.match(
(t) => t.code,
() => ""
);
const recCode = taxes.rec.match(
(t) => t.code,
() => ""
);
const retentionCode = taxes.retention.match(
(t) => t.code,
() => ""
);
// Clave del grupo: combinación IVA|REC|RET
const key = `${ivaCode}|${recCode}|${retentionCode}`;
/* ----------------------------- IVA ----------------------------- */
item.taxes.iva.match(
(iva) => {
const key = iva.code;
const prev = map.get(key) ?? {
tax: iva,
taxes,
taxable: ItemAmount.zero(taxable.currencyCode),
total: ItemAmount.zero(taxable.currencyCode),
ivaAmount: ItemAmount.zero(taxable.currencyCode),
recAmount: ItemAmount.zero(taxable.currencyCode),
retentionAmount: ItemAmount.zero(taxable.currencyCode),
taxesAmount: ItemAmount.zero(taxable.currencyCode),
};
map.set(key, {
tax: iva,
taxes,
taxable: prev.taxable.add(taxable),
total: prev.total.add(ivaAmount),
ivaAmount: prev.ivaAmount.add(ivaAmount),
recAmount: prev.recAmount.add(recAmount),
retentionAmount: prev.retentionAmount.add(retentionAmount),
taxesAmount: prev.taxesAmount.add(taxesAmount),
});
},
() => {
//
}
);
/* ----------------------------- REC ----------------------------- */
item.taxes.rec.match(
(rec) => {
const key = rec.code;
const prev = map.get(key) ?? {
tax: rec,
taxable: ItemAmount.zero(taxable.currencyCode),
total: ItemAmount.zero(taxable.currencyCode),
};
map.set(key, {
tax: rec,
taxable: prev.taxable.add(taxable),
total: prev.total.add(recAmount),
});
},
() => {
//
}
);
/* -------------------------- RETENCIÓN -------------------------- */
item.taxes.retention.match(
(retention) => {
const key = retention.code;
const prev = map.get(key) ?? {
tax: retention,
taxable: ItemAmount.zero(taxable.currencyCode),
total: ItemAmount.zero(taxable.currencyCode),
};
map.set(key, {
tax: retention,
taxable: prev.taxable.add(taxable),
total: prev.total.add(retentionAmount),
});
},
() => {
//
}
);
}
return map;

View File

@ -106,10 +106,10 @@ export class CustomerInvoiceItemDomainMapper
);
const globalDiscountPercentage = extractOrPushError(
ItemDiscount.create({
value: source.global_discount_percentage_value,
}),
`items[${index}].global_discount_percentage`,
maybeFromNullableVO(source.global_discount_percentage_value, (v) =>
ItemDiscount.create({ value: v })
),
`items[${index}].discount_percentage`,
errors
);

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -0,0 +1,338 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Factura</title>
<style type="text/css">{{ asset 'tailwind.min.css' }}</style>
<style type="text/css">
header {
width: 100%;
margin-bottom: 15px;
}
/* Fila superior */
.top-header {
display: flex;
justify-content: space-between;
width: 100%;
}
/* Bloque izquierdo */
.left-block {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 75%;
}
.logo {
height: 80px;
margin-bottom: 5px;
}
.company-text {
font-size: 7pt;
line-height: 1.2;
padding-left: 10px;
text-align: right;
}
/* Bloque derecho */
.right-block {
display: flex;
flex-direction: column;
/* uno encima de otro */
align-items: flex-end;
/* o flex-start / center según quieras */
justify-content: flex-start;
width: 25%;
padding: 4px;
}
.factura-img {
height: 45px;
}
.factura-text {
font-size: 26px;
font-weight: bolder;
}
/* Fila inferior */
.bottom-header {
margin-top: 10px;
display: flex;
justify-content: space-between;
gap: 20px;
}
/* Cuadros */
.info-box {
width: 40%;
}
.info-dire {
width: 70%;
}
/* ---------------------------- */
/* ESTRUCTURA BODY */
/* ---------------------------- */
body {
font-family: Arial, sans-serif;
margin: 40px;
color: #333;
font-size: 9pt;
line-height: 1.5;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 0px;
margin-bottom: 10px;
}
table th,
table td {
padding: 3px 10px;
text-align: left;
vertical-align: top;
}
table th {
border-bottom: 1px solid #000;
}
.totals {
margin-top: 20px;
width: 100%;
}
.totals td {
padding: 5px 10px;
}
.totals td.label {
text-align: right;
font-weight: bold;
}
/* Anchos por columna */
.col-concepto { width: auto; text-align: left; }
.col-cantidad { width: 70px; text-align: center; border-right: 1px solid #000;}
.col-precio { width: 110px; text-align: right; border-right: 1px solid #000;}
.col-total { width: 110px; text-align: right; }
.resume-table td {
background: #f0f0f0; /* gris como en la imagen */
}
.resume-table th {
border: transparent; /* gris como en la imagen */
}
/* Columna izquierda (notas / forma de pago) */
.left-col {
width: 70%;
vertical-align: top;
padding: 10px;
border: 1px solid #000;
}
/* Etiquetas */
.resume-table .label {
width: 15%;
padding: 6px 8px;
text-align: right;
border: 1px solid #000;
}
/* Valores numéricos */
.resume-table .value {
width: 15%;
padding: 6px 8px;
text-align: right;
border: 1px solid #000;
}
/* Total factura */
.total-row .label,
.total-row .value {
background-color: #eee;
font-size: 9pt;
border: 1px solid #000;
}
.resume-table .empty {
border: 1px solid transparent;
}
footer {
margin-top: 40px;
font-size: 8px;
}
@media print {
* {
-webkit-print-color-adjust: exact;
}
thead {
display: table-header-group;
}
tfoot {
display: table-footer-group;
}
}
</style>
</head>
<body>
<header>
<!-- FILA SUPERIOR: logo + dirección / imagen factura -->
<div class="top-header">
<div class="left-block">
<div style="display: flex; align-items: center; gap: 4px; align-content: stretch">
<img src="{{asset 'logo_alonsoysal.jpg'}}" alt="Logo Alonso y Sal" class="logo" />
{{#if verifactu.qr_code}}
<div style="flex-grow: 0; flex-shrink: 0; flex-basis:90px;">
<img src="{{verifactu.qr_code}}" alt="QR factura" style="width: 90px; height: 90px;" />
</div>
<div style="text-align: left; flex-grow: 1; flex-shrink: 1; flex-basis: auto;">
QR tributario factura verificable en sede electronica de AEAT VERI*FACTU
</div>
{{/if}}
</div>
</div>
<div class="right-block">
<div>
<div class="company-text">
<p><strong>Cocinas y Baños</strong><br/>Calle Vía Carpetana 340<br/>28047 Madrid</p>
<p>Teléfono: 914 652 842<br/>WhatsApp: 607 528 495<br/>Email: <a href="mailto:info@alonsoysal.com">info@alonsoysal.com</a><br/>Web: <a href="https://www.acanainteriorismo.com" target="_blank">www.alonsoysal.com</a></p>
</div>
</div>
</div>
</div>
<!-- FILA INFERIOR: cuadro factura + cuadro cliente -->
<div class="bottom-header">
<div class="info-box">
<p class="factura-text">FACTURA</p>
<p>Factura nº: {{series}}{{invoice_number}}</p>
<p>Fecha: {{invoice_date}}</p>
</div>
<div class="info-box info-dire">
<h2 style="font-weight:600; text-transform:uppercase; margin-bottom:0.25rem;">{{recipient.name}}</h2>
<p>{{recipient.tin}}</p>
<p>{{recipient.street}}</p>
<p>{{recipient.postal_code}} {{recipient.city}} {{recipient.province}}</p>
</div>
</div>
</header>
<main id="main">
<section id="details">
<!-- Tu tabla -->
<table class="table-header">
<thead>
<tr>
<th class="col-concepto">Concepto</th>
<th class="col-cantidad">Cantidad</th>
<th class="col-precio">Precio unidad</th>
<th class="col-total">Importe total</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td class="col-concepto">{{description}}</td>
<td class="col-cantidad">{{#if quantity}}{{quantity}}{{else}}&nbsp;{{/if}}</td>
<td class="col-precio">{{#if unit_amount}}{{unit_amount}}{{else}}&nbsp;{{/if}}</td>
<td class="col-total">{{#if taxable_amount}}{{taxable_amount}}{{else}}&nbsp;{{/if}}</td>
</td>
</tr>
{{/each}}
</tbody>
</table>
<table class="resume-table">
<thead>
<tr>
<th class="col-concepto"></th>
{{#if discount_percentage}}
<th class="col-total">Importe neto</th>
<th class="col-total">Dto {{discount_percentage}}</th>
{{/if}}
<th class="col-total">Base imponible</th>
{{#each taxes}}
<th class="col-total">{{tax_name}}</th>
{{/each}}
<th class="col-total"><strong>Total</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td class="col-concepto"></td>
{{#if discount_percentage}}
<td class="col-total">{{subtotal_amount}}</td>
<td class="col-total">{{discount_amount.value}}</td>
{{/if}}
<td class="col-total">{{taxable_amount}}</td>
{{#each taxes}}
<td class="col-total">{{taxes_amount}}</td>
{{/each}}
<td class="col-total">{{total_amount}}</td>
</tr>
</tbody>
</table>
<!-- Columna izquierda: notas y forma de pago -->
<table>
<tr>
<td class="info-box" style="text-align: right;">
{{#if payment_method}}
<p><strong>Forma de pago</strong><br/> {{payment_method}}</p>
{{/if}}
{{#if notes}}
<p><strong>Notas</strong><br/> {{notes}}</p>
{{/if}}
</td>
</tr>
</tbody>
</table>
</section>
</main>
<footer id="footer">
<tfoot >
<div style="border-bottom: 1px solid #000;">
<p>Acota Cocinas S.L. Insc. en el Reg. Merc. de Madrid, Tomo 44.740, Folio 72, Hoja M-787831 CIF: B44670040</p>
</div>
<div>
<p style="text-align: left; font-size: 6pt;">Información en protección de datos<br />Conforme a lo establecido en el Reglamento (UE) 2016/679 (RGPD), así como lo dispuesto en la normativa nacional sobre esta materia, le informamos de lo siguiente: Los datos personales facilitados serán responsabilidad de la entidad ACOTA COCINAS, S.L., además, sus datos personales serán utilizados para las siguientes finalidades: - Realización de acciones y comunicaciones comerciales y de marketing para informar y fidelizar clientes, - Prestación propia de nuestros servicios derivados de la actividad y distribución o comercialización de nuestros productos. Gestión fiscal y contable con la finalidad de cumplir con obligaciones legales. Todo ello bajo la legitimación otorgada por Consentimiento y firma de la persona, Interés legítimo, Ejecución de un contrato. No se cederán datos a terceros salvo obligaciones legales. No obstante es posible que determinados encargados del tratamiento externos puedan acceder a sus datos para la necesaria prestación del servicio. En cuanto a sus derechos, podrá reclamar ante la Autoridad de Control Nacional y en todo momento acceder, rectificar y suprimir sus datos, limitarlos o incluso oponerse a su tratamiento, solicitar su portabilidad a otros responsables, enviándonos una comunicación dirigida a Calle VIA CARPETANA, 340, B, CP 28047 Madrid, o bien enviándonos un email a monica@alonsoysal.com. Por último, puede consultar la información adicional y detallada sobre nuestra política de Protección de datos, mediante comunicación dirigida a nuestra dirección postal.<br/>
OBTENCIÓN DE CONSENTIMIENTOS: Le informamos que marcando “SI” en las siguientes casillas estará dándonos su consentimiento expreso para llevar a cabo las finalidades descritas a continuación. Este consentimiento podrá ser retirado en cualquier momento posterior comunicándolo por cualquier medio fehaciente: X SI NO</p>
</div>
</tfoot>
</footer>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -0,0 +1,344 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="{{ asset 'tailwind.css' }}" />
<title>Factura proforma</title>
<style type="text/css">
/* ---------------------------- */
/* ESTRUCTURA CABECERA */
/* ---------------------------- */
header {
width: 100%;
margin-bottom: 15px;
}
/* Fila superior */
.top-header {
display: flex;
justify-content: space-between;
width: 100%;
}
/* Bloque izquierdo */
.left-block {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 60%;
}
.logo {
height: 70px;
margin-bottom: 5px;
}
.company-text {
font-size: 7pt;
line-height: 1;
padding-left: 10px;
}
/* Bloque derecho */
.right-block {
display: flex;
align-items: flex-start;
justify-content: flex-end;
width: 40%;
}
.factura-img {
height: 45px;
}
/* Fila inferior */
.bottom-header {
margin-top: 10px;
display: flex;
justify-content: space-between;
gap: 20px;
}
/* Cuadros */
.info-box {
border: 1px solid black;
border-radius: 12px;
padding: 8px 12px;
width: 45%;
}
.info-dire {
width: 65%;
}
/* ---------------------------- */
/* ESTRUCTURA BODY */
/* ---------------------------- */
body {
font-family: Tahoma, sans-serif;
margin: 40px;
color: #333;
font-size: 9pt;
line-height: 1.5;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 0px;
margin-bottom: 10px;
}
table th,
table td {
border-top: 0px solid;
border-left: 1px solid #000;
border-right: 1px solid #000;
border-bottom: 0px solid;
padding: 3px 10px;
text-align: left;
vertical-align: top;
}
table th {
margin-bottom: 10px;
border-top: 1px solid #000;
border-bottom: 1px solid #000;
text-align: center;
background-color: #e7e0df;
color: #ff0014;
}
.totals {
margin-top: 20px;
width: 100%;
}
.totals td {
padding: 5px 10px;
}
.totals td.label {
text-align: right;
font-weight: bold;
}
.resume-table {
width: 100%;
border-collapse: collapse;
font-size: 9pt;
font-family: Tahoma, sans-serif;
}
/* Columna izquierda (notas / forma de pago) */
.left-col {
width: 70%;
vertical-align: top;
padding: 10px;
border: 1px solid #000;
}
/* Etiquetas */
.resume-table .label {
width: 15%;
padding: 6px 8px;
text-align: right;
border: 1px solid #000;
}
/* Valores numéricos */
.resume-table .value {
width: 15%;
padding: 6px 8px;
text-align: right;
border: 1px solid #000;
}
/* Total factura */
.total-row .label,
.total-row .value {
background-color: #eee;
font-size: 9pt;
border: 1px solid #000;
}
.total {
color: #d10000;
font-weight: bold;
text-align: right;
}
.resume-table .empty {
border: 1px solid transparent;
}
footer {
margin-top: 40px;
font-size: 8px;
}
@media print {
* {
-webkit-print-color-adjust: exact;
}
thead {
display: table-header-group;
}
tfoot {
display: table-footer-group;
}
}
</style>
</head>
<body>
<header>
<!-- FILA SUPERIOR: logo + dirección / imagen factura -->
<div class="top-header">
<div class="left-block">
<img src="{{asset 'logo_acana.jpg'}}" alt="Logo Acana" class="logo" />
<div class="company-text">
<p>Aliso Design S.L. B86913910</p>
<p>C/ La Fundición, 27. Pol. Santa Ana</p>
<p>Rivas Vaciamadrid 28522 Madrid</p>
<p>Telf: 91 301 65 57 / 91 301 65 58</p>
<p>
<a href="mailto:info@acanainteriorismo.com">info@acanainteriorismo.com</a> -
<a href="https://www.acanainteriorismo.com" target="_blank">www.acanainteriorismo.com</a>
</p>
</div>
</div>
<div class="right-block">
<img src="{{asset 'factura_acana.jpg' }}" alt="Factura" class="factura-img" />
</div>
</div>
<!-- FILA INFERIOR: cuadro factura + cuadro cliente -->
<div class="bottom-header">
<div class="info-box">
<p>Factura nº: <strong>{{series}}{{invoice_number}}</strong></p>
<p>Fecha: <strong>{{invoice_date}}</strong></p>
<p>Página <span class="pageNumber"></span> de <span class="totalPages"></span></p>
</div>
<div class="info-box info-dire">
<h2 class="font-semibold uppercase mb-1">{{recipient.name}}</h2>
<p>{{recipient.tin}}</p>
<p>{{recipient.street}}</p>
<p>{{recipient.postal_code}} {{recipient.city}} {{recipient.province}}</p>
</div>
</div>
</header>
<main id="main">
<section id="details">
<!-- Tu tabla -->
<table class="table-header">
<thead>
<tr>
<th class="py-2">Concepto</th>
<th class="py-2">Ud.</th>
<th class="py-2">Imp.</th>
<th class="py-2">&nbsp;</th>
<th class="py-2">Imp.&nbsp;total</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td>{{description}}</td>
<td class="text-right">{{#if quantity}}{{quantity}}{{else}}&nbsp;{{/if}}</td>
<td class="text-right">{{#if unit_amount}}{{unit_amount}}{{else}}&nbsp;{{/if}}</td>
<td class="text-right">{{#if discount_percentage}}{{discount_percentage}}{{else}}&nbsp;{{/if}}</td>
<td class="text-right">{{#if taxable_amount}}{{taxable_amount}}{{else}}&nbsp;{{/if}}</td>
</td>
</tr>
{{/each}}
<tr class="resume-table">
<!-- Columna izquierda: notas y forma de pago -->
<td class="left-col" rowspan="10">
{{#if payment_method}}
<p><strong>Forma de pago:</strong> {{payment_method}}</p>
{{/if}}
{{#if notes}}
<p class="mt-2"><strong>Notas:</strong> {{notes}}</p>
{{/if}}
</td>
<!-- Columna derecha: totales -->
{{#if discount_percentage}}
<td colspan="2" class="label">Importe neto</td>
<td colspan="2" class="value">{{subtotal_amount}}</td>
{{else}}
<td colspan="2" class="label">Base imponible</td>
<td colspan="2" class="value">{{taxable_amount}}</td>
{{/if}}
</tr>
{{#if discount_percentage}}
<tr class="resume-table">
<td colspan="2" class="label">Dto {{discount_percentage}}</td>
<td colspan="2" class="value">{{discount_amount.value}}</td>
</tr>
<tr class="resume-table">
<td colspan="2" class="label">Base imponible</td>
<td colspan="2" class="value">{{taxable_amount}}</td>
</tr>
{{/if}}
{{#each taxes}}
<tr class="resume-table">
<td colspan="2" class="label">{{tax_name}}</td>
<td colspan="2" class="value">{{taxes_amount}}</td>
</tr>
{{/each}}
<tr class="total-row">
<td colspan="2" class="label"><strong>Total factura</strong></td>
<td colspan="2" class="value total"><strong>{{total_amount}}</strong></td>
</tr>
</tbody>
</table>
</section>
</main>
<footer id="footer" class="mt-4 border-t border-black">
<aside class="mt-4">
<tfoot>
<p class="text-center">Insc. en el Reg. Merc. de Madrid, Tomo 31.839, Libro 0, Folio 191, Sección 8, Hoja
M-572991
CIF: B86913910</p>
<p class="text-left" style="font-size: 6pt;">Información en protección de datos<br />De conformidad con lo
dispuesto en el RGPD y LOPDGDD,
informamos que los datos personales serán tratados por
ALISO DESIGN S.L para cumplir con la obligación tributaria de emitir facturas. Podrá solicitar más
información, y ejercer sus derechos escribiendo a info@acanainteriorismo.com o mediante correo postal a la
dirección CALLE
LA FUNDICION 27 POL. IND. SANTA ANA (28522) RIVAS-VACIAMADRID, MADRID. Para el ejercicio de sus derechos, en
caso
de que sea necesario, se le solicitará documento que acredite su identidad. Si siente vulnerados sus derechos
puede presentar una reclamación ante la AEPD, en su web: www.aepd.es.</p>
</tfoot>
</aside>
</footer>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long