Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion addons/l10n_it_edi_withholding/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
from markupsafe import Markup
from odoo import _, api, fields, models
from odoo.addons.l10n_it_edi.models.account_move import get_float

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -276,7 +277,7 @@ def _l10n_it_edi_import_line(self, element, move_line_form, extra_info=None):
data_kind, data_text = data_kind_element[0].text.lower(), text_element[0].text.lower()
if data_kind == 'cassa-prev' and ('enasarco' in data_text or 'tc07' in data_text):
number_element = other_data_element.xpath("./RiferimentoNumero")
if not number_element:
if not number_element or not price_subtotal:
continue
enasarco_amount = float(number_element[0].text)
enasarco_percentage = -self.env.company.currency_id.round(enasarco_amount / price_subtotal * 100)
Expand All @@ -298,3 +299,47 @@ def _l10n_it_edi_import_line(self, element, move_line_form, extra_info=None):
move_line_form.tax_ids |= pension_fund_tax

return messages_to_log

def _l10n_it_edi_import_invoice(self, invoice, data, is_new):
""" Handle the case where ENASARCO pension fund contribution should be applied on the invoice globally.
In this case, there should only be one element with ENASARCO and these conditions should be fulfilled:
- AliquotaIVA is defined
- PrezzoUnitario == 0.0
- a corresponding DatiRiepilogo with the same AliquotaIVA and a ImponibileImporto
"""
res = super()._l10n_it_edi_import_invoice(invoice=invoice, data=data, is_new=is_new)
if not res:
return
self = res
tree = data['xml_tree']
global_enasarco_lines = []
for additional_data_element in tree.xpath('//AltriDatiGestionali'):
data_kind = additional_data_element.xpath('./TipoDato')[0].text.lower()
if data_kind == 'cassa-prev':
data_text = additional_data_element.xpath('./RiferimentoTesto')[0].text.lower()
if 'enasarco' in data_text or 'tc07' in data_text:
parent_element = additional_data_element.xpath('..')[0]
price_unit = get_float(parent_element, './PrezzoUnitario')
if price_unit == 0.0:
global_enasarco_lines.append(parent_element)

if len(global_enasarco_lines) == 1:
parent_element = global_enasarco_lines[0]
enasarco_amount = get_float(parent_element, './AltriDatiGestionali/RiferimentoNumero')
price_unit = get_float(parent_element, './PrezzoUnitario')
base_amount = self._get_l10_it_edi_get_taxable_amount_from_summary_data(parent_element.xpath('..')[0])
enasarco_percentage = -self.currency_id.round(enasarco_amount / base_amount * 100) if base_amount else 0.0
type_tax_use_domain = [('type_tax_use', '=', 'purchase' if self.is_outbound(include_receipts=True) else 'sale')]
domain = [('l10n_it_pension_fund_type', '=', 'TC07')] + type_tax_use_domain
if enasarco_tax := self._l10n_it_edi_search_tax_for_import(self.company_id, enasarco_percentage, domain, vat_only=False):
to_remove_index = int(get_float(parent_element, './NumeroLinea')) - 1
self.invoice_line_ids[to_remove_index].unlink()
self.invoice_line_ids.tax_ids |= enasarco_tax

return self

def _get_l10_it_edi_get_taxable_amount_from_summary_data(self, element):
taxable_amount = 0.0
for summary_data_element in element.xpath('.//DatiRiepilogo'):
taxable_amount += get_float(summary_data_element, './/ImponibileImporto')
return taxable_amount
45 changes: 45 additions & 0 deletions addons/l10n_it_edi_withholding/tests/test_withholding.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,51 @@ def test_enasarco_tax_import(self):
self.assertEqual(-8.5, enasarco_imported_tax.amount)
self.assertEqual(self.withholding_purchase_tax_23, line.tax_ids.filtered(lambda x: x.l10n_it_withholding_reason == 'ZO'))

def test_enasarco_tax_import_global(self):
"""Test that if we have a unique ENASARCO line with a price of 0.0,
the pension fund contribution will be applied on the total amount of
the invoice instead of the line amount because it's considered as global.
"""
applied_xml = """
<xpath expr="//DettaglioLinee[NumeroLinea=1]/AltriDatiGestionali" position="replace"/>
<xpath expr="//DettaglioLinee[NumeroLinea=2]/AltriDatiGestionali" position="replace"/>
<xpath expr="//DettaglioLinee[NumeroLinea=3]/AltriDatiGestionali" position="replace"/>
<xpath expr="//DettaglioLinee[NumeroLinea=4]/AltriDatiGestionali" position="replace"/>

<xpath expr="//DettaglioLinee[NumeroLinea=4]" position="after">
<DettaglioLinee>
<NumeroLinea>5</NumeroLinea>
<Descrizione>Contributo ENASARCO</Descrizione>
<PrezzoUnitario>0.00</PrezzoUnitario>
<PrezzoTotale>0.00</PrezzoTotale>
<AliquotaIVA>22.00</AliquotaIVA>
<AltriDatiGestionali>
<TipoDato>CASSA-PREV</TipoDato>
<RiferimentoTesto>TC07 - ENASARCO</RiferimentoTesto>
<RiferimentoNumero>63.75</RiferimentoNumero>
</AltriDatiGestionali>
</DettaglioLinee>
</xpath>
"""

invoice = self._assert_import_invoice('IT00470550013_enasa.xml', [{
'invoice_date': fields.Date.from_string('2022-03-24'),
'amount_untaxed': 750.0,
'amount_total': 765.0,
'amount_tax': 15.0,
'invoice_line_ids': [{
'name': name,
'price_unit': price_unit,
} for name, price_unit in self.get_real_client_invoice_data().lines]
}], applied_xml)

invoice_data = self.get_real_client_invoice_data()
for line in invoice.line_ids.filtered(lambda x: x.name in [data[0] for data in invoice_data.lines]):
enasarco_imported_tax = line.tax_ids.filtered(lambda x: x.l10n_it_pension_fund_type == 'TC07')
self.assertEqual(self.enasarco_purchase_tax, enasarco_imported_tax)
self.assertEqual(-8.5, enasarco_imported_tax.amount)
self.assertEqual(self.withholding_purchase_tax_23, line.tax_ids.filtered(lambda x: x.l10n_it_withholding_reason == 'ZO'))

def test_inps_tax_export(self):
"""
Invoice
Expand Down