Skip to content
Snippets Groups Projects
Commit d4035863 authored by dbkosky's avatar dbkosky Committed by dbkosky
Browse files

[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: def954e8
Signed-off-by: default avatarJosse Colpaert <jco@odoo.com>
parent 00d356d5
Branches
Tags
No related merge requests found
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment