[FIX] l10n_it_edi: Tax calculation fails edi constraint if tax price included
When using price included taxes, the xml contained data that failed to meet the constraints of the edi. This is due to the local rounding on the lines of the invoice. For example: A product costing 321€, on two lines of the invoice, with a price included tax of 22% Rounded per line: float_round( 321 - (321/122 * 100), 2 # To two decimal places ) evaluates to 57.89, the total tax will be 2 * 57.89 = 115.78 In the case of global rounding float_round( 321 + 321 - (321/122*100) - (321/122*100), 2 # To two decimal places ) evaluates to 115.77, so we have a difference of one cent. This can be exacerbated by more lines. The constraints on the EDI that this conflicts with are on the tax summary section for each tax. The constraints (roughly reworded): 00422: The base taxable amount for the tax must be equal to the sum of the base product prices (for which we have already used the rounded computed values, calcuated in the invoice) + <Arrotondamento> (rounding). 00421: The value provided for the <importo> that is the value of the vat is equal to the taxable base multiplied by the tax rate. The problem is that because of our local roundings, the taxable base is equal to our products, but the tax rate * taxable base is not equal to the tax amount (as present in the invoice). This commit adds to the rounding field and subtracts from the taxable base of the tax summary a value rounding value that should make tax rate * taxable base equal to the value of the vat. closes odoo/odoo#86711 Task: 2789290 X-original-commit: def954e85e83e5be18c0a1805f0af20f8116bf3d Signed-off-by: Josse Colpaert <jco@odoo.com>
This commit is contained in:
@@ -162,26 +162,17 @@
|
||||
<t t-set="line_counter" t-value="line_counter + 1"/>
|
||||
<t t-call="l10n_it_edi.account_invoice_line_it_FatturaPA"/>
|
||||
</t>
|
||||
<t t-foreach="record.line_ids.filtered(lambda line: line.tax_line_id)" t-as="tax_line">
|
||||
<t t-foreach="tax_details['tax_details']" t-as="tax_name">
|
||||
<t t-set="tax_dict" t-value="tax_details['tax_details'][tax_name]"/>
|
||||
<DatiRiepilogo>
|
||||
<!--2.2.2-->
|
||||
<AliquotaIVA t-esc="format_numbers(tax_line.tax_line_id.amount)"/>
|
||||
<Natura t-if="tax_line.tax_line_id.l10n_it_has_exoneration" t-esc="tax_line.tax_line_id.l10n_it_kind_exoneration"/>
|
||||
<ImponibileImporto t-esc="format_monetary(tax_line.tax_base_amount, currency)"/>
|
||||
<Imposta t-esc="format_monetary(tax_line.price_unit, currency)"/>
|
||||
<EsigibilitaIVA t-if="not tax_line.tax_line_id.l10n_it_has_exoneration or tax_line.tax_line_id.l10n_it_kind_exoneration=='N6'" t-esc="tax_line.tax_line_id.l10n_it_vat_due_date"/>
|
||||
<RiferimentoNormativo t-if="tax_line.tax_line_id.l10n_it_has_exoneration" t-esc="tax_line.tax_line_id.l10n_it_law_reference"/>
|
||||
</DatiRiepilogo>
|
||||
</t>
|
||||
<!-- 0% tax lines -->
|
||||
<t t-foreach="tax_map" t-as="tax">
|
||||
<DatiRiepilogo>
|
||||
<AliquotaIVA t-esc="format_numbers(tax.amount)"/>
|
||||
<Natura t-if="tax.l10n_it_has_exoneration" t-esc="tax.l10n_it_kind_exoneration"/>
|
||||
<ImponibileImporto t-esc="format_monetary(tax_map[tax], currency)"/>
|
||||
<Imposta t-esc="format_monetary(0.00, currency)"/>
|
||||
<EsigibilitaIVA t-if="not tax.l10n_it_has_exoneration or tax.l10n_it_kind_exoneration=='N6'" t-esc="tax.l10n_it_vat_due_date"/>
|
||||
<RiferimentoNormativo t-if="tax.l10n_it_has_exoneration" t-esc="tax.l10n_it_law_reference"/>
|
||||
<AliquotaIVA t-esc="format_numbers(tax_dict['tax'].amount)"/>
|
||||
<Natura t-if="tax_dict['tax'].l10n_it_has_exoneration" t-esc="tax_dict['tax'].l10n_it_kind_exoneration"/>
|
||||
<Arrotondamento t-if="tax_dict.get('rounding')" t-esc="format_numbers(tax_dict['rounding'])"/>
|
||||
<ImponibileImporto t-esc="format_monetary(abs(tax_dict['base_amount']), currency)"/>
|
||||
<Imposta t-esc="format_monetary(abs(tax_dict['tax_amount']), currency)"/>
|
||||
<EsigibilitaIVA t-if="not tax_dict['tax'].l10n_it_has_exoneration or tax_dict['tax'].l10n_it_kind_exoneration=='N6'" t-esc="tax_dict['tax'].l10n_it_vat_due_date"/>
|
||||
<RiferimentoNormativo t-if="tax_dict['tax'].l10n_it_has_exoneration" t-esc="tax_dict['tax'].l10n_it_law_reference"/>
|
||||
</DatiRiepilogo>
|
||||
</t>
|
||||
</DatiBeniServizi>
|
||||
|
||||
@@ -11,7 +11,7 @@ from datetime import date, datetime
|
||||
from lxml import etree
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.tools import float_repr
|
||||
from odoo.tools import float_repr, float_compare
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.addons.base.models.ir_mail_server import MailDeliveryException
|
||||
from odoo.tests.common import Form
|
||||
@@ -164,6 +164,20 @@ class AccountMove(models.Model):
|
||||
if tax.amount == 0.0:
|
||||
tax_map[tax] = tax_map.get(tax, 0.0) + line.price_subtotal
|
||||
|
||||
# Constraints within the edi make local rounding on price included taxes a problem.
|
||||
# To solve this there is a <Arrotondamento> or 'rounding' field, such that:
|
||||
# taxable base = sum(taxable base for each unit) + Arrotondamento
|
||||
tax_details = self._prepare_edi_tax_details()
|
||||
for _tax_name, tax_dict in tax_details['tax_details'].items():
|
||||
base_amount = tax_dict['base_amount']
|
||||
tax_amount = tax_dict['tax_amount']
|
||||
tax_rate = tax_dict['tax'].amount
|
||||
if tax_dict['tax'].price_include and tax_dict['tax'].amount_type == 'percent':
|
||||
expected_base_amount = tax_amount * 100 / tax_rate if tax_rate else False
|
||||
if expected_base_amount and float_compare(base_amount, expected_base_amount, 2):
|
||||
tax_dict['rounding'] = base_amount - (tax_amount * 100 / tax_rate)
|
||||
tax_dict['base_amount'] = base_amount - tax_dict['rounding']
|
||||
|
||||
# Create file content.
|
||||
template_values = {
|
||||
'record': self,
|
||||
@@ -182,6 +196,7 @@ class AccountMove(models.Model):
|
||||
'pdf': pdf,
|
||||
'pdf_name': pdf_name,
|
||||
'tax_map': tax_map,
|
||||
'tax_details': tax_details,
|
||||
}
|
||||
return template_values
|
||||
|
||||
|
||||
Reference in New Issue
Block a user