Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Precisione decimale non usata durante l'importazione della fattura elettronica #4446

Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions l10n_it_fatturapa_in/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from . import fields
from . import models
from . import wizard
47 changes: 47 additions & 0 deletions l10n_it_fatturapa_in/fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copyright 2024 Simone Rubino - Aion Tech
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo.fields import Float

orig_convert_to_cache = Float.convert_to_cache
orig_get_digits = Float.get_digits

E_INVOICE_PRECISION_TO_FIELD = {
"Discount": "discount_decimal_digits",
"Product Price": "price_decimal_digits",
"Product Unit of Measure": "quantity_decimal_digits",
}
# Map a `decimal.precision` to the name of the field in `fatturapa.attachment`
# that stores the value used during import


def get_digits(self, env):
digits = orig_get_digits(self, env)
if e_invoice_precision := env.context.get("l10n_it_fatturapa_in_precision"):
digits = digits[0], e_invoice_precision
return digits


def convert_to_cache(self, value, record, validate=True):
if record._name in ("account.move", "account.move.line"):
e_invoice = record.fatturapa_attachment_in_id
if e_invoice:
# The invoice [line] has been created by importing an e-invoice.
# If a different precision has been used,
# keep using that precision to read values that have it.
field_precision = self._digits
if isinstance(field_precision, str):
e_invoice_precision_field = E_INVOICE_PRECISION_TO_FIELD.get(
field_precision
)
if e_invoice_precision_field:
if e_invoice_precision := e_invoice[e_invoice_precision_field]:
record = record.with_context(
l10n_it_fatturapa_in_precision=e_invoice_precision
)

return orig_convert_to_cache(self, value, record, validate=validate)


Float.convert_to_cache = convert_to_cache
Float.get_digits = get_digits
18 changes: 18 additions & 0 deletions l10n_it_fatturapa_in/models/attachment.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,24 @@ class FatturaPAAttachmentIn(models.Model):
compute="_compute_linked_invoice_id_xml",
store=True,
)
price_decimal_digits = fields.Integer(
string="Prices decimal digits",
help="Value used during import of this e-invoice "
'to override "Product Price" precision.',
readonly=True,
)
quantity_decimal_digits = fields.Integer(
string="Quantities decimal digits",
help="Value used during import of this e-invoice "
'to override "Product Unit of Measure" precision.',
readonly=True,
)
discount_decimal_digits = fields.Integer(
string="Discounts decimal digits",
help="Value used during import of this e-invoice "
'to override "Discount" precision.',
readonly=True,
)

_sql_constraints = [
(
Expand Down
87 changes: 87 additions & 0 deletions l10n_it_fatturapa_in/tests/data/IT01234567890_FPR16.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<q1:FatturaElettronica xmlns:q1="http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fatture/v1.2" versione="FPR12">
<FatturaElettronicaHeader>
<DatiTrasmissione>
<IdTrasmittente>
<IdPaese>IT</IdPaese>
<IdCodice>02780790107</IdCodice>
</IdTrasmittente>
<ProgressivoInvio>FPR14</ProgressivoInvio>
<FormatoTrasmissione>FPR12</FormatoTrasmissione>
<CodiceDestinatario>0000000</CodiceDestinatario>
<ContattiTrasmittente>
<Telefono>06543534343</Telefono>
<Email>[email protected]</Email>
</ContattiTrasmittente>
<PECDestinatario>[email protected]</PECDestinatario>
</DatiTrasmissione>
<CedentePrestatore>
<DatiAnagrafici>
<IdFiscaleIVA>
<IdPaese>IT</IdPaese>
<IdCodice>02780790107</IdCodice>
</IdFiscaleIVA>
<Anagrafica>
<Denominazione>YourCompany</Denominazione>
</Anagrafica>
<RegimeFiscale>RF01</RegimeFiscale>
</DatiAnagrafici>
<Sede>
<Indirizzo>Via Milano, 1</Indirizzo>
<CAP>00100</CAP>
<Comune>Roma</Comune>
<Provincia>AK</Provincia>
<Nazione>IT</Nazione>
</Sede>
<Contatti>
<Telefono>06543534343</Telefono>
<Email>[email protected]</Email>
</Contatti>
</CedentePrestatore>
<CessionarioCommittente>
<DatiAnagrafici>
<IdFiscaleIVA>
<IdPaese>IT</IdPaese>
<IdCodice>07973780013</IdCodice>
</IdFiscaleIVA>
<CodiceFiscale>07973780013</CodiceFiscale>
<Anagrafica>
<Denominazione>B2B Customer</Denominazione>
</Anagrafica>
</DatiAnagrafici>
<Sede>
<Indirizzo>Via Roma, 1</Indirizzo>
<CAP>16100</CAP>
<Comune>Genova</Comune>
<Provincia>AK</Provincia>
<Nazione>IT</Nazione>
</Sede>
</CessionarioCommittente>
</FatturaElettronicaHeader>
<FatturaElettronicaBody>
<DatiGenerali>
<DatiGeneraliDocumento>
<TipoDocumento>TD01</TipoDocumento>
<Divisa>EUR</Divisa>
<Data>2020-09-30</Data>
<Numero>14481</Numero>
<ImportoTotaleDocumento>81.49</ImportoTotaleDocumento>
</DatiGeneraliDocumento>
</DatiGenerali>
<DatiBeniServizi>
<DettaglioLinee>
<NumeroLinea>1</NumeroLinea>
<Descrizione>Test precisione decimale</Descrizione>
<Quantita>69.00</Quantita>
<PrezzoUnitario>0.968</PrezzoUnitario>
<PrezzoTotale>66.792</PrezzoTotale>
<AliquotaIVA>22.00</AliquotaIVA>
</DettaglioLinee>
<DatiRiepilogo>
<AliquotaIVA>22.00</AliquotaIVA>
<ImponibileImporto>66.79</ImponibileImporto>
<Imposta>14.69</Imposta>
</DatiRiepilogo>
</DatiBeniServizi>
</FatturaElettronicaBody>
</q1:FatturaElettronica>
4 changes: 4 additions & 0 deletions l10n_it_fatturapa_in/tests/fatturapa_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ def run_wizard(
):
if module_name is None:
module_name = "l10n_it_fatturapa_in"
if wiz_values is None:
wiz_values = dict()
attach = self.create_attachment(name, file_name, module_name=module_name)
attach.e_invoice_received_date = fields.Datetime.now()
attach_id = attach.id
Expand All @@ -297,6 +299,8 @@ def run_wizard(
active_ids=[attach_id], active_model="fatturapa.attachment.in"
)
)
for wiz_field, wiz_value in wiz_values.items():
setattr(wizard_form, wiz_field, wiz_value)
wizard = wizard_form.save()
return wizard.importFatturaPA()
if mode == "link":
Expand Down
59 changes: 59 additions & 0 deletions l10n_it_fatturapa_in/tests/test_import_fatturapa_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,65 @@ def test_ignore_global_discount(self):
self.assertEqual(invoice.amount_tax, 5.12)
self.assertEqual(invoice.amount_total, 28.39)

def test_increased_decimal_precision(self):
"""
Increase price decimal precision during import:
computation of line's price is more accurate.
"""
res = self.run_wizard(
"increased_decimal_precision",
"IT01234567890_FPR16.xml",
wiz_values={
"price_decimal_digits": 3,
},
)

# The new precision allows to compute the correct amount
invoice = self.invoice_model.search(res["domain"])
expected_invoice_values = {
"amount_untaxed": 66.79,
"amount_tax": 14.69,
"amount_total": 81.48,
}
self.assertRecordValues(
invoice,
[
expected_invoice_values,
],
)
invoice_line = invoice.invoice_line_ids
expected_invoice_line_values = {
"price_subtotal": 66.79,
"price_total": 81.48,
}
self.assertRecordValues(
invoice_line,
[
expected_invoice_line_values,
],
)

# Trigger amounts recomputation because:
# date triggers an update on date_due
# date_due triggers an update on needed_terms
# needed_terms needs amount_total_signed
with Form(invoice) as invoice_form:
invoice_form.date = fields.Date.today()

# The correct amount is kept
self.assertRecordValues(
invoice,
[
expected_invoice_values,
],
)
self.assertRecordValues(
invoice_line,
[
expected_invoice_line_values,
],
)


class TestFatturaPAEnasarco(FatturapaCommon):
def setUp(self):
Expand Down
41 changes: 19 additions & 22 deletions l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import re
from datetime import datetime

from odoo import api, fields, models, registry
from odoo import api, fields, models
from odoo.exceptions import UserError
from odoo.fields import first
from odoo.osv import expression
Expand Down Expand Up @@ -1786,34 +1786,25 @@ def create_and_get_line_id(self, invoice_line_ids, invoice_line_model, upd_vals)
)
invoice_line_ids.append(invoice_line_id)

def _set_decimal_precision(self, precision_name, field_name):
def _set_decimal_precision(self, precision_name, field_name, attachments):
precision = self.env["decimal.precision"].search(
[("name", "=", precision_name)], limit=1
)
different_precisions = original_precision = None
if precision:
precision_id = precision.id
original_precision = precision.digits
different_precisions = self[field_name] != original_precision
if different_precisions:
with registry(self.env.cr.dbname).cursor() as new_cr:
# We need a new env (and cursor) because 'digits' property of Float
# fields is retrieved with a new LazyCursor,
# see class Float at odoo.fields,
# so we need to write (commit) to DB in order to make the new
# precision available
new_env = api.Environment(new_cr, self.env.uid, self.env.context)
new_precision = new_env["decimal.precision"].browse(precision_id)
new_precision.sudo().write({"digits": self[field_name]})
new_cr.commit()
precision.sudo().digits = self[field_name]
attachments.update(
{
field_name: self[field_name],
}
)
return precision, different_precisions, original_precision

def _restore_original_precision(self, precision, original_precision):
with registry(self.env.cr.dbname).cursor() as new_cr:
new_env = api.Environment(new_cr, self.env.uid, self.env.context)
new_price_precision = new_env["decimal.precision"].browse(precision.id)
new_price_precision.sudo().write({"digits": original_precision})
new_cr.commit()
precision.sudo().digits = original_precision

def _get_invoice_partner_id(self, fatt):
cedentePrestatore = fatt.FatturaElettronicaHeader.CedentePrestatore
Expand All @@ -1822,28 +1813,34 @@ def _get_invoice_partner_id(self, fatt):

def importFatturaPA(self):
self.ensure_one()
fatturapa_attachments = self._get_selected_records()

(
price_precision,
different_price_precisions,
original_price_precision,
) = self._set_decimal_precision("Product Price", "price_decimal_digits")
) = self._set_decimal_precision(
"Product Price", "price_decimal_digits", attachments=fatturapa_attachments
)
(
qty_precision,
different_qty_precisions,
original_qty_precision,
) = self._set_decimal_precision(
"Product Unit of Measure", "quantity_decimal_digits"
"Product Unit of Measure",
"quantity_decimal_digits",
attachments=fatturapa_attachments,
)
(
discount_precision,
different_discount_precisions,
original_discount_precision,
) = self._set_decimal_precision("Discount", "discount_decimal_digits")
) = self._set_decimal_precision(
"Discount", "discount_decimal_digits", attachments=fatturapa_attachments
)

new_invoices = []
# convert to dict in order to be able to modify context
fatturapa_attachments = self._get_selected_records()
self.env.context = dict(self.env.context)
for fatturapa_attachment in fatturapa_attachments:
self.reset_inconsistencies()
Expand Down
Loading