diff --git a/l10n_it_fatturapa_in/models/account.py b/l10n_it_fatturapa_in/models/account.py index bb12d1503982..a0f064cfc978 100644 --- a/l10n_it_fatturapa_in/models/account.py +++ b/l10n_it_fatturapa_in/models/account.py @@ -1,6 +1,6 @@ from odoo import fields, models, api, _ -from odoo.exceptions import ValidationError +from odoo.exceptions import ValidationError, UserError from odoo.tools import float_compare import odoo.addons.decimal_precision as dp @@ -43,6 +43,56 @@ class AccountInvoice(models.Model): e_invoice_received_date = fields.Date( string='E-Bill Received Date') + @api.depends('invoice_line_ids.price_subtotal', 'tax_line_ids.amount', + 'tax_line_ids.amount_rounding', 'currency_id', 'company_id', + 'date_invoice', 'type', 'efatt_rounding') + def _compute_amount(self): + super(AccountInvoice, self)._compute_amount() + if self.efatt_rounding != 0: + self.amount_total += self.efatt_rounding + amount_total_company_signed = self.amount_total + if self.currency_id and self.company_id and self.currency_id !=\ + self.company_id.currency_id: + currency_id = self.currency_id + amount_total_company_signed = currency_id._convert( + self.amount_total, self.company_id.currency_id, + self.company_id, self.date_invoice or fields.Date.today()) + sign = self.type in ['in_refund', 'out_refund'] and -1 or 1 + self.amount_total_company_signed = amount_total_company_signed * sign + self.amount_total_signed = self.amount_total * sign + + @api.model + def invoice_line_move_line_get(self): + """Append global rounding move lines""" + res = super().invoice_line_move_line_get() + + if self.efatt_rounding != 0: + if self.efatt_rounding > 0: + arrotondamenti_account_id = self.env.user.company_id.\ + arrotondamenti_passivi_account_id + if not arrotondamenti_account_id: + raise UserError(_("Round down account is not set " + "in Accounting Settings")) + name = _("Rounding down") + else: + arrotondamenti_account_id = self.env.user.company_id.\ + arrotondamenti_attivi_account_id + if not arrotondamenti_account_id: + raise UserError(_("Round up account is not set " + "in Accounting Settings")) + name = _("Rounding up") + + res.append({ + 'type': 'global_rounding', + 'name': name, + 'price_unit': self.efatt_rounding, + 'quantity': 1, + 'price': self.efatt_rounding, + 'account_id': arrotondamenti_account_id.id, + 'invoice_id': self.id, + }) + return res + @api.multi def invoice_validate(self): for invoice in self: @@ -208,19 +258,23 @@ def remove_attachment_link(self): @api.model def compute_xml_amount_untaxed(self, FatturaBody): - amount_untaxed = float( - FatturaBody.DatiGenerali.DatiGeneraliDocumento.Arrotondamento - or 0.0) + amount_untaxed = 0.0 for Riepilogo in FatturaBody.DatiBeniServizi.DatiRiepilogo: - rounding = float(Riepilogo.Arrotondamento or 0.0) - amount_untaxed += float(Riepilogo.ImponibileImporto) + rounding + amount_untaxed += float(Riepilogo.ImponibileImporto or 0.0) return amount_untaxed + @api.model + def compute_xml_amount_total(self, FatturaBody, amount_untaxed, amount_tax): + rounding = float( + FatturaBody.DatiGenerali.DatiGeneraliDocumento.Arrotondamento + or 0.0) + return amount_untaxed + amount_tax + rounding + @api.model def compute_xml_amount_tax(self, DatiRiepilogo): amount_tax = 0.0 for Riepilogo in DatiRiepilogo: - amount_tax += float(Riepilogo.Imposta) + amount_tax += float(Riepilogo.Imposta or 0.0) return amount_tax def set_einvoice_data(self, fattura): @@ -228,9 +282,8 @@ def set_einvoice_data(self, fattura): amount_untaxed = self.compute_xml_amount_untaxed(fattura) amount_tax = self.compute_xml_amount_tax( fattura.DatiBeniServizi.DatiRiepilogo) - amount_total = float( - fattura.DatiGenerali.DatiGeneraliDocumento. - ImportoTotaleDocumento or 0.0) + amount_total = self.compute_xml_amount_total( + fattura, amount_untaxed, amount_tax) reference = fattura.DatiGenerali.DatiGeneraliDocumento.Numero date_invoice = fields.Date.from_string( fattura.DatiGenerali.DatiGeneraliDocumento.Data) diff --git a/l10n_it_fatturapa_in/readme/CONTRIBUTORS.rst b/l10n_it_fatturapa_in/readme/CONTRIBUTORS.rst index 9b00be3d2b34..1721984a8682 100644 --- a/l10n_it_fatturapa_in/readme/CONTRIBUTORS.rst +++ b/l10n_it_fatturapa_in/readme/CONTRIBUTORS.rst @@ -2,3 +2,4 @@ * Roberto Onnis * Alessio Gerace * Sergio Zanchetta +* Giovanni Serra diff --git a/l10n_it_fatturapa_in/readme/ROADMAP.rst b/l10n_it_fatturapa_in/readme/ROADMAP.rst index 9ec04c0ccbb1..452aee30958f 100644 --- a/l10n_it_fatturapa_in/readme/ROADMAP.rst +++ b/l10n_it_fatturapa_in/readme/ROADMAP.rst @@ -16,4 +16,4 @@ la visibilità delle sezioni ``FatturaElettronicaBody.DatiBeniServizi.DatiRiepil Pertanto, al fine di ottenere il corretto valore del totale imponibile, i moduli che avessero ridefinito il metodo ``compute_xml_amount_untaxed`` nel modello ``account.invoice`` -dovranno adeguare la chiamata al metodo stesso preoccupandosi di utilizzare come primo parametro l'oggetto ``FatturaElettronicaBody``. \ No newline at end of file +dovranno adeguare la chiamata al metodo stesso preoccupandosi di utilizzare come primo parametro l'oggetto ``FatturaElettronicaBody``. diff --git a/l10n_it_fatturapa_in/tests/data/IT05979361218_013.xml b/l10n_it_fatturapa_in/tests/data/IT05979361218_013.xml index 2ade52ad22b1..9e5346afe016 100644 --- a/l10n_it_fatturapa_in/tests/data/IT05979361218_013.xml +++ b/l10n_it_fatturapa_in/tests/data/IT05979361218_013.xml @@ -54,7 +54,7 @@ xsi:schemaLocation="http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fatture/v1. TD01 EUR 2019-05-11 - 852S1 + A852S1 34.32 -0.35 Rif ordine 908 diff --git a/l10n_it_fatturapa_in/tests/data/IT05979361218_015.xml b/l10n_it_fatturapa_in/tests/data/IT05979361218_015.xml new file mode 100644 index 000000000000..ecbcd2956c1d --- /dev/null +++ b/l10n_it_fatturapa_in/tests/data/IT05979361218_015.xml @@ -0,0 +1,94 @@ + + + + + + IT + 05979361218 + + 006 + FPA12 + UFPQ1O + + + + + IT + 05979361218 + + + SOCIETA' ALPHA BETA SRL + + RF02 + + + VIALE ROMA 543B + 07100 + SASSARI + SS + IT + + + + + 80213330584 + + AMMINISTRAZIONE BETA + + + + VIA TORINO 38-B + 00145 + ROMA + RM + IT + + + + + + + TD01 + EUR + 2019-05-11 + 852S1 + 34.32 + Rif ordine 908 + + + + + 1 + USB4 + 1.00 + Pz. + 18.07 + 18.07 + 0.00 + N4 + + + 2 + USB + 1.00 + Pz. + 16.60 + 16.60 + 0.00 + N4 + + + 0.00 + N4 + -0.35 + 34.32 + 0.00 + I + Esenzione Art.8 comma 1 DPR 633/72 + + + + \ No newline at end of file diff --git a/l10n_it_fatturapa_in/tests/fatturapa_common.py b/l10n_it_fatturapa_in/tests/fatturapa_common.py index 15c2d7e883e7..1a3af0cbf85a 100644 --- a/l10n_it_fatturapa_in/tests/fatturapa_common.py +++ b/l10n_it_fatturapa_in/tests/fatturapa_common.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - import base64 import tempfile from odoo.modules import get_module_resource diff --git a/l10n_it_fatturapa_in/tests/test_import_fatturapa_xml.py b/l10n_it_fatturapa_in/tests/test_import_fatturapa_xml.py index 49c91b473e74..bb0c2481d598 100644 --- a/l10n_it_fatturapa_in/tests/test_import_fatturapa_xml.py +++ b/l10n_it_fatturapa_in/tests/test_import_fatturapa_xml.py @@ -486,14 +486,31 @@ def test_24_xml_import(self): res = self.run_wizard('test24', 'IT05979361218_012.xml') invoice_id = res.get('domain')[0][2][0] invoice = self.invoice_model.browse(invoice_id) - self.assertAlmostEqual(invoice.e_invoice_amount_untaxed, 34.32) - self.assertEqual(invoice.e_invoice_amount_tax, 0.0) - self.assertEqual(invoice.e_invoice_amount_total, 34.32) + self.assertEqual( + invoice.inconsistencies, + 'Computed amount untaxed 34.32 is different from' + ' summary data 34.67') def test_25_xml_import(self): res = self.run_wizard('test25', 'IT05979361218_013.xml') invoice_id = res.get('domain')[0][2][0] invoice = self.invoice_model.browse(invoice_id) + self.assertAlmostEqual(invoice.e_invoice_amount_untaxed, 34.67) + self.assertEqual(invoice.e_invoice_amount_tax, 0.0) + self.assertEqual(invoice.e_invoice_amount_total, 34.32) + self.assertEqual(invoice.efatt_rounding, -0.35) + invoice.action_invoice_open() + move_line = False + for line in invoice.move_id.line_ids: + if line.account_id.id == self.env.user.\ + company_id.arrotondamenti_attivi_account_id.id: + move_line = True + self.assertTrue(move_line) + + def test_26_xml_import(self): + res = self.run_wizard('test26', 'IT05979361218_015.xml') + invoice_id = res.get('domain')[0][2][0] + invoice = self.invoice_model.browse(invoice_id) self.assertAlmostEqual(invoice.e_invoice_amount_untaxed, 34.32) self.assertEqual(invoice.e_invoice_amount_tax, 0.0) self.assertEqual(invoice.e_invoice_amount_total, 34.32) diff --git a/l10n_it_fatturapa_in/views/account_view.xml b/l10n_it_fatturapa_in/views/account_view.xml index 22d25f1a949b..b781030096d0 100644 --- a/l10n_it_fatturapa_in/views/account_view.xml +++ b/l10n_it_fatturapa_in/views/account_view.xml @@ -138,6 +138,9 @@ + + + @@ -313,7 +316,7 @@ - + diff --git a/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py b/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py index 83e21879c485..6b7aa1136cef 100644 --- a/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py +++ b/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py @@ -315,6 +315,12 @@ def getCarrirerPartner(self, Carrier): def _prepare_generic_line_data(self, line): retLine = {} + account_taxes = self.get_account_taxes(line.AliquotaIVA, line.Natura) + if account_taxes: + retLine['invoice_line_tax_ids'] = [(6, 0, [account_taxes[0].id])] + return retLine + + def get_account_taxes(self, AliquotaIVA, Natura): account_tax_model = self.env['account.tax'] # check if a default tax exists and generate def_purchase_tax object ir_values = self.env['ir.default'] @@ -325,30 +331,30 @@ def _prepare_generic_line_data(self, line): def_purchase_tax = False if supplier_taxes_ids: def_purchase_tax = account_tax_model.browse(supplier_taxes_ids)[0] - if float(line.AliquotaIVA) == 0.0 and line.Natura: + if float(AliquotaIVA) == 0.0 and Natura: account_taxes = account_tax_model.search( [ ('type_tax_use', '=', 'purchase'), - ('kind_id.code', '=', line.Natura), + ('kind_id.code', '=', Natura), ('amount', '=', 0.0), ], order='sequence') if not account_taxes: self.log_inconsistency( _('No tax with percentage ' '%s and nature %s found. Please configure this tax.') - % (line.AliquotaIVA, line.Natura)) + % (AliquotaIVA, Natura)) if len(account_taxes) > 1: self.log_inconsistency( _('Too many taxes with percentage ' '%s and nature %s found. Tax %s with lower priority has ' 'been set on invoice lines.') - % (line.AliquotaIVA, line.Natura, + % (AliquotaIVA, Natura, account_taxes[0].description)) else: account_taxes = account_tax_model.search( [ ('type_tax_use', '=', 'purchase'), - ('amount', '=', float(line.AliquotaIVA)), + ('amount', '=', float(AliquotaIVA)), ('price_include', '=', False), # partially deductible VAT must be set by user ('children_tax_ids', '=', False), @@ -358,7 +364,7 @@ def _prepare_generic_line_data(self, line): _( "XML contains tax with percentage '%s' " "but it does not exist in your system" - ) % line.AliquotaIVA + ) % AliquotaIVA ) # check if there are multiple taxes with # same percentage @@ -367,18 +373,16 @@ def _prepare_generic_line_data(self, line): _logger.warning(_( "Too many taxes with percentage equals " "to '%s'.\nFix it if required" - ) % line.AliquotaIVA) + ) % AliquotaIVA) # if there are multiple taxes with same percentage # and there is a default tax with this percentage, # set taxes list equal to supplier_taxes_id, loaded before if ( def_purchase_tax and - def_purchase_tax.amount == (float(line.AliquotaIVA)) + def_purchase_tax.amount == (float(AliquotaIVA)) ): account_taxes = def_purchase_tax - if account_taxes: - retLine['invoice_line_tax_ids'] = [(6, 0, [account_taxes[0].id])] - return retLine + return account_taxes def get_line_product(self, line, partner): product = None @@ -1101,26 +1105,29 @@ def set_roundings(self, FatturaBody, invoice): _('Round up and down tax is not set') ) - line_vals = {} - if rounding > 0.0: - line_vals = { - 'invoice_id': invoice.id, - 'name': _("Rounding down"), - 'account_id': arrotondamenti_passivi_account_id.id, - 'price_unit': rounding, - 'invoice_line_tax_ids': - [(6, 0, [arrotondamenti_tax_id.id])], - } - elif rounding < 0.0: - line_vals = { - 'invoice_id': invoice.id, - 'name': _("Rounding up"), - 'account_id': arrotondamenti_attivi_account_id.id, - 'price_unit': rounding, - 'invoice_line_tax_ids': - [(6, 0, [arrotondamenti_tax_id.id])], - } - + line_sequence = max(invoice.invoice_line_ids.mapped('sequence')) + line_vals = [] + for summary in FatturaBody.DatiBeniServizi.DatiRiepilogo: + to_round = float(summary.Arrotondamento or 0.0) + if to_round != 0.0: + account_taxes = self.get_account_taxes( + summary.AliquotaIVA, summary.Natura) + arrotondamenti_account_id = arrotondamenti_passivi_account_id.id\ + if to_round > 0.0 else arrotondamenti_attivi_account_id.id + invoice_line_tax_id = account_taxes[0].id if account_taxes\ + else arrotondamenti_tax_id.id + name = _("Rounding down") if to_round > 0.0 else _( + "Rounding up") + line_sequence += 1 + line_vals.append({ + 'sequence': line_sequence, + 'invoice_id': invoice.id, + 'name': name, + 'account_id': arrotondamenti_account_id, + 'price_unit': to_round, + 'invoice_line_tax_ids': + [(6, 0, [invoice_line_tax_id])], + }) if line_vals: self.env['account.invoice.line'].create(line_vals)