diff --git a/addons/l10n_es_edi_tbai/data/template_invoice.xml b/addons/l10n_es_edi_tbai/data/template_invoice.xml
index 4067f490c40..edfeeadb419 100644
--- a/addons/l10n_es_edi_tbai/data/template_invoice.xml
+++ b/addons/l10n_es_edi_tbai/data/template_invoice.xml
@@ -119,7 +119,7 @@
-
+
diff --git a/addons/l10n_es_edi_tbai/models/account_edi_format.py b/addons/l10n_es_edi_tbai/models/account_edi_format.py
index 32d4d2c67cd..ef1ddbae073 100644
--- a/addons/l10n_es_edi_tbai/models/account_edi_format.py
+++ b/addons/l10n_es_edi_tbai/models/account_edi_format.py
@@ -339,11 +339,12 @@ class AccountEdiFormat(models.Model):
else:
balance_before_discount = line.balance / (1 - line.discount / 100)
discount = (balance_before_discount - line.balance)
+ line_price_total = self._l10n_es_tbai_get_invoice_line_price_total(line)
if not any([t.l10n_es_type == 'sujeto_isp' for t in line.tax_ids]):
- total = line.price_total * abs(line.balance / line.amount_currency if line.amount_currency != 0 else 1) * -refund_sign
+ total = line_price_total * abs(line.balance / line.amount_currency if line.amount_currency != 0 else 1) * -refund_sign
else:
- total = abs(line.balance) * -refund_sign * (-1 if line.price_total < 0 else 1)
+ total = abs(line.balance) * -refund_sign * (-1 if line_price_total < 0 else 1)
invoice_lines.append({
'line': line,
'discount': discount * refund_sign,
@@ -353,9 +354,10 @@ class AccountEdiFormat(models.Model):
})
values['invoice_lines'] = invoice_lines
# Tax details (desglose)
- importe_total, desglose = self._l10n_es_tbai_get_importe_desglose(invoice)
+ importe_total, desglose, amount_retention = self._l10n_es_tbai_get_importe_desglose(invoice)
values['amount_total'] = importe_total
values['invoice_info'] = desglose
+ values['amount_retention'] = amount_retention * refund_sign if amount_retention != 0.0 else 0.0
# Regime codes (ClaveRegimenEspecialOTrascendencia)
# NOTE there's 11 more codes to implement, also there can be up to 3 in total
@@ -368,18 +370,35 @@ class AccountEdiFormat(models.Model):
return values
+ def _l10n_es_tbai_get_invoice_line_price_total(self, invoice_line):
+ price_total = invoice_line.price_total
+ retention_tax_lines = invoice_line.tax_ids.filtered(lambda t: t.l10n_es_type == "retencion")
+ if retention_tax_lines:
+ line_discount_price_unit = invoice_line.price_unit * (1 - (invoice_line.discount / 100.0))
+ tax_lines_no_retention = invoice_line.tax_ids - retention_tax_lines
+ if tax_lines_no_retention:
+ taxes_res = tax_lines_no_retention.compute_all(line_discount_price_unit,
+ quantity=invoice_line.quantity,
+ currency=invoice_line.currency_id,
+ product=invoice_line.product_id,
+ partner=invoice_line.move_id.partner_id,
+ is_refund=invoice_line.is_refund)
+ price_total = taxes_res['total_included']
+ return price_total
+
def _l10n_es_tbai_get_importe_desglose(self, invoice):
com_partner = invoice.commercial_partner_id
sign = -1 if invoice.move_type in ('out_refund', 'in_refund') else 1
if com_partner.country_id.code in ('ES', False) and not (com_partner.vat or '').startswith("ESN"):
tax_details_info_vals = self._l10n_es_edi_get_invoices_tax_details_info(invoice)
+ tax_amount_retention = tax_details_info_vals['tax_amount_retention']
desglose = {'DesgloseFactura': tax_details_info_vals['tax_details_info']}
desglose['DesgloseFactura'].update({'S1': tax_details_info_vals['S1_list'],
'S2': tax_details_info_vals['S2_list']})
importe_total = round(sign * (
tax_details_info_vals['tax_details']['base_amount']
+ tax_details_info_vals['tax_details']['tax_amount']
- - tax_details_info_vals['tax_amount_retention']
+ - tax_amount_retention
), 2)
else:
tax_details_info_service_vals = self._l10n_es_edi_get_invoices_tax_details_info(
@@ -390,6 +409,8 @@ class AccountEdiFormat(models.Model):
invoice,
filter_invl_to_apply=lambda x: any(t.tax_scope == 'consu' for t in x.tax_ids)
)
+ service_retention = tax_details_info_service_vals['tax_amount_retention']
+ consu_retention = tax_details_info_consu_vals['tax_amount_retention']
desglose = {}
if tax_details_info_service_vals['tax_details_info']:
desglose.setdefault('DesgloseTipoOperacion', {})
@@ -407,12 +428,13 @@ class AccountEdiFormat(models.Model):
importe_total = round(sign * (
tax_details_info_service_vals['tax_details']['base_amount']
+ tax_details_info_service_vals['tax_details']['tax_amount']
- - tax_details_info_service_vals['tax_amount_retention']
+ - service_retention
+ tax_details_info_consu_vals['tax_details']['base_amount']
+ tax_details_info_consu_vals['tax_details']['tax_amount']
- - tax_details_info_consu_vals['tax_amount_retention']
+ - consu_retention
), 2)
- return importe_total, desglose
+ tax_amount_retention = service_retention + consu_retention
+ return importe_total, desglose, tax_amount_retention
def _l10n_es_tbai_get_trail_values(self, invoice, cancel):
prev_invoice = invoice.company_id._get_l10n_es_tbai_last_posted_invoice(invoice)
diff --git a/addons/l10n_es_edi_tbai/tests/test_edi_xml.py b/addons/l10n_es_edi_tbai/tests/test_edi_xml.py
index 8050a1a10a5..3930c8cd620 100644
--- a/addons/l10n_es_edi_tbai/tests/test_edi_xml.py
+++ b/addons/l10n_es_edi_tbai/tests/test_edi_xml.py
@@ -118,6 +118,20 @@ class TestEdiTbaiXmls(TestEsEdiTbaiCommon):
xml_expected = self.with_applied_xpath(xml_expected_base, xpath)
self.assertXmlTreeEqual(xml_doc, xml_expected)
+ def test_xml_tree_post_retention(self):
+ self.out_invoice.invoice_line_ids.tax_ids = [(4, self._get_tax_by_xml_id('s_irpf15').id)]
+ with freeze_time(self.frozen_today):
+ xml_doc = self.edi_format._get_l10n_es_tbai_invoice_xml(self.out_invoice, cancel=False)[self.out_invoice]['xml_file']
+ xml_doc.remove(xml_doc.find("Signature", namespaces=NS_MAP))
+ xml_expected_base = etree.fromstring(super().L10N_ES_TBAI_SAMPLE_XML_POST)
+ xpath = """
+
+ 600.00
+
+ """
+ xml_expected = self.with_applied_xpath(xml_expected_base, xpath)
+ self.assertXmlTreeEqual(xml_doc, xml_expected)
+
def test_xml_tree_in_post(self):
"""Test XML of vendor bill for LROE Batuz"""
with freeze_time(self.frozen_today):
diff --git a/doc/cla/individual/uolaizola.md b/doc/cla/individual/uolaizola.md
new file mode 100644
index 00000000000..faf19b2779d
--- /dev/null
+++ b/doc/cla/individual/uolaizola.md
@@ -0,0 +1,11 @@
+Spain, 2024-02-01
+
+I hereby agree to the terms of the Odoo Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Ugaitz Olaizola Arbelaitz uolaizola@binovo.es https://github.com/uolaizola