From 773e1c3f61bf8f32197010a99f8094c97b1d9c07 Mon Sep 17 00:00:00 2001 From: eLBati Date: Tue, 10 Jul 2018 07:57:12 +0200 Subject: [PATCH] porting l10n_it_fatturapa_in to 10 (REF withholding tax integration, invoice interface, fiscal document type ADD some DatiGeneraliDocumento fields) ADD _setTerzoIntermediarioOSoggettoEmittente to l10n_it_fatturapa_out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit l10n_it_ipa ADD is_pa bool field ADD PECDestinatario, CodiceDestinatario , FormatoTrasmissione handling ADD Lotto di fatture verso soggetto privato ADD gestione prodotti nelle fatture passive ADD l10n_it_fatturapa_in_purchase ADD einvoice.line model IMP form fatture ADD Livello di dettaglio Fatture elettroniche ADD PDF preview dell'XML ADD Link to existing supplier invoice and handle "registered" XML ADD rappresentante fiscale e stabile organizzazione in emissione gestione prodotti DatiBollo , DatiCassaPrevidenziale e ScontoMaggiorazione CodiceArticolo, ftpa_line_number IMP "show preview" as link FIX invoice duplication ADD constraints and Nome Cognome Avoid to cancel invoice with XML Mostra i dati fattura elettronica solo se il cliente è soggetto IMP READMEs Gestione IVA inclusa nel prezzo ADD l10n_it_fatturapa_out_ddt IMP PEP8 IMP decimal precision ADD Export E-invoice button IMP README --- l10n_it_fatturapa_in/README.rst | 117 ++ l10n_it_fatturapa_in/__init__.py | 19 - l10n_it_fatturapa_in/__manifest__.py | 28 + l10n_it_fatturapa_in/__openerp__.py | 94 -- l10n_it_fatturapa_in/i18n/it.po | 1004 ++++++++----- l10n_it_fatturapa_in/models/__init__.py | 22 +- l10n_it_fatturapa_in/models/account.py | 157 +- l10n_it_fatturapa_in/models/attachment.py | 92 +- l10n_it_fatturapa_in/models/company.py | 69 + l10n_it_fatturapa_in/models/partner.py | 29 + l10n_it_fatturapa_in/readme/CONFIGURE.rst | 14 + l10n_it_fatturapa_in/readme/CONTRIBUTORS.rst | 3 + l10n_it_fatturapa_in/readme/DESCRIPTION.rst | 7 + l10n_it_fatturapa_in/readme/INSTALL.rst | 3 + l10n_it_fatturapa_in/readme/USAGE.rst | 6 + .../security/ir.model.access.csv | 2 + .../static/description/index.html | 460 ++++++ l10n_it_fatturapa_in/tests/__init__.py | 20 - ...7890_11002.xml => IT01234567890_FPR03.xml} | 94 +- .../tests/data/IT02780790107_11003.xml | 172 --- .../tests/data/IT02780790107_11004.xml | 14 +- .../tests/data/IT02780790107_11005.xml | 25 +- .../tests/data/IT02780790107_11006.xml | 9 +- .../tests/data/IT02780790107_11007.xml | 12 +- .../tests/data/IT05979361218_001.xml | 24 +- .../tests/data/IT05979361218_002.xml | 15 +- .../tests/data/IT05979361218_003.xml | 19 +- .../tests/data/IT05979361218_004.xml | 15 +- .../tests/data/IT05979361218_005.xml | 13 +- .../tests/data/IT05979361218_006.XML | 13 +- .../tests/data/IT05979361218_007.xml | 17 +- .../tests/data/IT05979361218_008.xml | 13 +- .../tests/data/IT05979361218_009.xml | 95 ++ .../tests/test_import_fatturapa_xml.py | 374 +++-- l10n_it_fatturapa_in/views/account_view.xml | 558 +++---- l10n_it_fatturapa_in/views/company_view.xml | 25 + l10n_it_fatturapa_in/views/partner_view.xml | 22 +- l10n_it_fatturapa_in/wizard/__init__.py | 20 +- .../wizard/link_to_existing_invoice.py | 20 + .../wizard/link_to_existing_invoice.xml | 34 + .../wizard/wizard_import_fatturapa.py | 1306 ++++++++--------- .../wizard/wizard_import_fatturapa_view.xml | 25 +- 42 files changed, 3097 insertions(+), 1983 deletions(-) create mode 100644 l10n_it_fatturapa_in/README.rst create mode 100644 l10n_it_fatturapa_in/__manifest__.py delete mode 100644 l10n_it_fatturapa_in/__openerp__.py create mode 100644 l10n_it_fatturapa_in/models/company.py create mode 100644 l10n_it_fatturapa_in/models/partner.py create mode 100644 l10n_it_fatturapa_in/readme/CONFIGURE.rst create mode 100644 l10n_it_fatturapa_in/readme/CONTRIBUTORS.rst create mode 100644 l10n_it_fatturapa_in/readme/DESCRIPTION.rst create mode 100644 l10n_it_fatturapa_in/readme/INSTALL.rst create mode 100644 l10n_it_fatturapa_in/readme/USAGE.rst create mode 100644 l10n_it_fatturapa_in/static/description/index.html rename l10n_it_fatturapa_in/tests/data/{IT01234567890_11002.xml => IT01234567890_FPR03.xml} (53%) delete mode 100644 l10n_it_fatturapa_in/tests/data/IT02780790107_11003.xml create mode 100644 l10n_it_fatturapa_in/tests/data/IT05979361218_009.xml create mode 100644 l10n_it_fatturapa_in/views/company_view.xml create mode 100644 l10n_it_fatturapa_in/wizard/link_to_existing_invoice.py create mode 100644 l10n_it_fatturapa_in/wizard/link_to_existing_invoice.xml diff --git a/l10n_it_fatturapa_in/README.rst b/l10n_it_fatturapa_in/README.rst new file mode 100644 index 000000000000..91656857baa3 --- /dev/null +++ b/l10n_it_fatturapa_in/README.rst @@ -0,0 +1,117 @@ +==================================================== +Italian Localization - Fattura Elettronica reception +==================================================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fl10n--italy-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-italy/tree/10.0/l10n_it_fatturapa_in + :alt: OCA/l10n-italy +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-italy-10-0/l10n-italy-10-0-l10n_it_fatturapa_in + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/122/10.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to import XML files of electronic invoices, version 1.2 + +http://www.fatturapa.gov.it/export/fatturazione/it/normativa/f-2.htm + +received through the exchange system (SDI) + +http://www.fatturapa.gov.it/export/fatturazione/it/sdi.htm + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +odoo server must run on linux and be able to run + +``openssl`` + +Configuration +============= + +Also see the README file of l10n_it_fatturapa module. + +For every supplier, it is possible to set the 'details level of electronic invoices': + + - Minimum level: Supplier invoice is created without lines; user will have to create them, according to what specified in electronic invoice + - Maximum level: every line contained in electronic invoice will create a line in supplier invoice. + +Moreover, it is possible, in supplier form, to set the 'default product for electronic invoices': this product will be used, during generation of supplier invoices, when no other possible product is found. Tax and account of invoice line will be set according to what configured in the product. + +Every product code used by suppliers can be set, in product form, in + +Inventory --> Suppliers + +If supplier specifies a known code in XML, the system will use it to retrieve the correct product to be used in invoice line, setting the related tax and account. + +Usage +===== + + * Go to Accounting --> Purchases --> Electronic Invoice + * Upload XML file + * View invoice content clicking on 'show preview' + * Run 'import electronic invoice' wizard to create a draft invoice or run 'link to existing supplier invoice' to link the XML file to an already (automatically) created invoice + +In the incoming electronic invoice files list, by default you will see files to be registered, that is files not yet linked to one or more supplier invoices + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Agile Business Group +* Innoviu + +Contributors +~~~~~~~~~~~~ + +* Lorenzo Battistini +* Roberto Onnis +* Alessio Gerace + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/l10n-italy `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_it_fatturapa_in/__init__.py b/l10n_it_fatturapa_in/__init__.py index 823e6fcb9a56..574498c3b125 100644 --- a/l10n_it_fatturapa_in/__init__.py +++ b/l10n_it_fatturapa_in/__init__.py @@ -1,23 +1,4 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 AgileBG SAGL -# Copyright (C) 2015 innoviu Srl -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## from . import models from . import tests diff --git a/l10n_it_fatturapa_in/__manifest__.py b/l10n_it_fatturapa_in/__manifest__.py new file mode 100644 index 000000000000..e00688104d9a --- /dev/null +++ b/l10n_it_fatturapa_in/__manifest__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Copyright 2015 AgileBG SAGL +# Copyright 2015 innoviu Srl +# Copyright 2018 Lorenzo Battistini + +{ + 'name': 'Italian Localization - Fattura Elettronica reception', + 'version': '10.0.1.0.0', + 'category': 'Localization/Italy', + 'summary': 'Electronic invoices reception', + 'author': 'Agile Business Group, Innoviu, ' + 'Odoo Community Association (OCA)', + 'website': 'http://www.agilebg.com', + 'license': 'LGPL-3', + "depends": [ + 'l10n_it_fatturapa', + 'l10n_it_withholding_tax_causali', + ], + "data": [ + 'views/account_view.xml', + 'views/partner_view.xml', + 'wizard/wizard_import_fatturapa_view.xml', + 'security/ir.model.access.csv', + 'wizard/link_to_existing_invoice.xml', + 'views/company_view.xml', + ], + "installable": True +} diff --git a/l10n_it_fatturapa_in/__openerp__.py b/l10n_it_fatturapa_in/__openerp__.py deleted file mode 100644 index 8a8013b893fc..000000000000 --- a/l10n_it_fatturapa_in/__openerp__.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 AgileBG SAGL -# Copyright (C) 2015 innoviu Srl -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -{ - 'name': 'Italian Localization - FatturaPA reception', - 'version': '0.1', - 'category': 'Localization/Italy', - 'summary': 'Electronic invoices reception', - 'author': 'Agile Business Group, Innoviu, ' - 'Odoo Community Association (OCA)', - 'description': """ -.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :alt: License - - -Italian Localization - FatturaPA - Reception -============================================ - -This module allows you to receive and parse the fatturaPA XML file version 1.1 -http://www.fatturapa.gov.it/export/fatturazione/en/normativa/f-2.htm -received from the Exchange System -http://www.fatturapa.gov.it/export/fatturazione/en/sdi.htm - - -Configuration -============= - -See l10n_it_fatturapa - -Usage -===== - - * Go to knowledge -> Documents - * Create a Incoming fatturaPA file - * Run Import FatturaPA wizard - -Credits -======= - -Contributors ------------- - -* Lorenzo Battistini -* Roberto Onnis -* Alessio Gerace - -Maintainer ----------- - -.. image:: http://odoo-community.org/logo.png - :alt: Odoo Community Association - :target: http://odoo-community.org - -This module is maintained by the OCA. - -OCA, or the Odoo Community Association, is a nonprofit organization whose -mission is to support the collaborative development of Odoo features and -promote its widespread use. - -To contribute to this module, please visit http://odoo-community.org. -""", - 'website': 'http://www.agilebg.com', - 'license': 'AGPL-3', - "depends": [ - 'l10n_it_fatturapa', - 'partner_firstname', - 'stock_invoice_picking_incoterm', - 'l10n_it_withholding_tax', - ], - "data": [ - 'views/account_view.xml', - 'views/partner_view.xml', - 'wizard/wizard_import_fatturapa_view.xml', - 'security/ir.model.access.csv', - ], - "installable": True -} diff --git a/l10n_it_fatturapa_in/i18n/it.po b/l10n_it_fatturapa_in/i18n/it.po index 8ccb9628d9b1..75d11c5c4a37 100644 --- a/l10n_it_fatturapa_in/i18n/it.po +++ b/l10n_it_fatturapa_in/i18n/it.po @@ -1,570 +1,900 @@ -# Translation of OpenERP Server. +# Translation of Odoo Server. # This file contains the translation of the following modules: -# * l10n_it_fatturapa_in -# -# Translators: +# * l10n_it_fatturapa_in +# msgid "" msgstr "" -"Project-Id-Version: l10n-italy (7.0)\n" +"Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-11-25 16:46+0000\n" -"PO-Revision-Date: 2015-11-18 17:08+0000\n" +"POT-Creation-Date: 2018-09-27 08:07+0000\n" +"PO-Revision-Date: 2018-09-27 08:07+0000\n" "Last-Translator: <>\n" -"Language-Team: Italian (http://www.transifex.com/oca/OCA-l10n-italy-7-0/language/it/)\n" +"Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" -"Language: it\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: \n" #. module: l10n_it_fatturapa_in -#: field:account.invoice,fatturapa_attachment_in_id:0 -msgid "FatturaPA Import File" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_tax_amount +msgid "Aliquota IVA" +msgstr "Aliquota IVA" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Altri Dati Gestionali" +msgstr "Altri Dati Gestionali" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_ids +msgid "Altri dati gestionali" +msgstr "Altri dati gestionali" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_ir_attachment_id +msgid "Attachment" +msgstr "Allegato" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_name +msgid "Attachment Name" +msgstr "Nome Allegato" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1229 +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_local_url +msgid "Attachment URL" +msgstr "URL Allegato" + +#. module: l10n_it_fatturapa_in +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1162 #, python-format -msgid "Parsing PEM to DER file %s" -msgstr "" +msgid "Attachment without name" +msgstr "Allegato senza nome" #. module: l10n_it_fatturapa_in -#: field:account.invoice.line,cod_article_ids:0 -msgid "Cod. Articles" -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Attachments" +msgstr "Allegati" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:97 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:691 #, python-format -msgid "DatiAnagrafici.Anagrafica.Cognome contains \"%s\". Your System contains \"%s\"" -msgstr "" +msgid "BIC is required and not exist in Xml\n" +"Curr bank data is: \n" +"IBAN: %s\n" +"Bank Name: %s\n" +"" +msgstr "BIC è richiesto e non esiste nell'XML\n" +"I dati della banca corrente sono: \n" +"IBAN: %s\n" +"Nome banca: %s\n" +"" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1208 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1228 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1235 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1256 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1263 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:578 #, python-format -msgid "Errore" -msgstr "" +msgid "Bollo assolto ai sensi del decreto MEF 17 giugno 2014 (art. 6)" +msgstr "Bollo assolto ai sensi del decreto MEF 17 giugno 2014 (art. 6)" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.wizard_import_fatturapa_form_view +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.wizard_link_supplier_invoice +msgid "Cancel" +msgstr "Annulla" + +#. module: l10n_it_fatturapa_in +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:955 +#, python-format +msgid "Cassa Previdenziale: %s" +msgstr "Cassa Previdenziale: %s" + +#. module: l10n_it_fatturapa_in +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:963 +#, python-format +msgid "CassaPrevidenziale %s has Ritenuta but no withholding tax was found in the system" +msgstr "CassaPrevidenziale %s ha la ritenuta me nessuna ritenuta è stata trovata nel sistema" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_checksum +msgid "Checksum/SHA1" +msgstr "Checksum/SHA1" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_article_code_name +msgid "Cod Type" +msgstr "Tipo codice" #. module: l10n_it_fatturapa_in -#: field:fatturapa.article.code,code_val:0 +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_cod_article_ids +msgid "Cod. Articles" +msgstr "Codici articoli" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_article_code_code_val msgid "Code Value" -msgstr "" +msgstr "Valore codice" #. module: l10n_it_fatturapa_in -#: view:res.partner:0 -msgid "FatturaPA Registration" -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Codice Articoli" +msgstr "Codice Articoli" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Inconsistencies" -msgstr "" +#: model:ir.model,name:l10n_it_fatturapa_in.model_res_company +msgid "Companies" +msgstr "Aziende" #. module: l10n_it_fatturapa_in -#: selection:account.invoice.line,service_type:0 -msgid "sconto" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_company_id +msgid "Company" +msgstr "Azienda" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1257 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1222 #, python-format -msgid "Signed Xml file %s" -msgstr "" +msgid "Computed amount untaxed %s is different from DatiRiepilogo %s" +msgstr "L'imponibile calcolato %s è diverso da quello di DatiRiepilogo %s" #. module: l10n_it_fatturapa_in -#: field:fatturapa.attachment.in,message_unread:0 -msgid "Unread Messages" -msgstr "" +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:151 +#, python-format +msgid "Country Code %s not found in system" +msgstr "Codice nazione %s non trovato nel sistema" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:771 -#, python-format -msgid "tipoDocumento %s not handled" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_create_uid +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_create_uid +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_article_code_create_uid +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_create_uid +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_import_fatturapa_create_uid +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_link_to_invoice_create_uid +msgid "Created by" +msgstr "Creato da" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Related Documents " -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_create_date +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_create_date +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_article_code_create_date +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_create_date +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_import_fatturapa_create_date +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_link_to_invoice_create_date +msgid "Created on" +msgstr "Creato il" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:311 -#, python-format -msgid "Too many taxes with percentage %s and nature %s found" -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_fatturapa_in_attachment_form +msgid "Creation" +msgstr "Creazione" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_period_end_date +msgid "Data Fine Periodo" +msgstr "Data Fine Periodo" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_period_start_date +msgid "Data Inizio Periodo" +msgstr "Data Inizio Periodo" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_db_datas +msgid "Database Data" +msgstr "Dati Database" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Dati generali" +msgstr "Dati generali" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1061 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:102 #, python-format -msgid "Payment method Code %s is incorrect" -msgstr "" +msgid "DatiAnagrafici.Anagrafica.Cognome contains \"%s\". Your System contains \"%s\"" +msgstr "DatiAnagrafici.Anagrafica.Cognome contiene \"%s\". Il tuo database contiene \"%s\"" #. module: l10n_it_fatturapa_in -#: view:fatturapa.attachment.in:0 -msgid "History" -msgstr "" +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:85 +#, python-format +msgid "DatiAnagrafici.Anagrafica.Denominazione contains \"%s\". Your System contains \"%s\"" +msgstr "DatiAnagrafici.Anagrafica.Denominazione contiene \"%s\". Il tuo database contiene \"%s\"" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:453 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:93 #, python-format -msgid "TipoCassa is not defined " -msgstr "" +msgid "DatiAnagrafici.Anagrafica.Nome contains \"%s\". Your System contains \"%s\"" +msgstr "DatiAnagrafici.Anagrafica.Nome contiene \"%s\". Il tuo database contiene \"%s\"" #. module: l10n_it_fatturapa_in -#: field:fatturapa.attachment.in,message_ids:0 -msgid "Messages" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_res_partner_e_invoice_default_product_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_res_users_e_invoice_default_product_id +msgid "Default product electronic invoice" +msgstr "Default product electronic invoice" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:248 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:746 #, python-format -msgid "REA Office Code ( %s ) not present in system" -msgstr "" +msgid "Define a purchase journal for this company: \"%s\" (id:%d)." +msgstr "Definire un sezionale di acquisto per questa azienda: \"%s\" (id:%d)." + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Delivery" +msgstr "Consegna" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_description +msgid "Description" +msgstr "Descrizione" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_name +msgid "Descrizione" +msgstr "Descrizione" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Dettaglio Linea" +msgstr "Dettaglio Linea" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1284 +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_account_invoice_e_invoice_line_ids +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Dettaglio Linee" +msgstr "Dettaglio Linee" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_discount_rise_price_ids +msgid "Discount and Rise Price Details" +msgstr "Dettagli sconto e maggiorazione" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_display_name +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_display_name +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_article_code_display_name +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_display_name +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_import_fatturapa_display_name +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_link_to_invoice_display_name +msgid "Display Name" +msgstr "Nome Visualizzato" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_account_invoice_fatturapa_attachment_in_id +msgid "E-Invoice Import File" +msgstr "File fattura elettronica" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "E-invoice Inconsistencies" +msgstr "Inconsistenze fattura elettronica" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "E-invoice details" +msgstr "Dettagli fattura elettronica" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Fattura PA V1.2 Schema" +msgstr "XML Schema V1.2" + +#. module: l10n_it_fatturapa_in +#: model:ir.model,name:l10n_it_fatturapa_in.model_fatturapa_article_code +msgid "FatturaPA Article Code" +msgstr "Codice articolo fattura elettronica" + +#. module: l10n_it_fatturapa_in +#: model:ir.model,name:l10n_it_fatturapa_in.model_discount_rise_price +msgid "FatturaPA Discount Rise Price Data" +msgstr "Dati sconto maggiorazione" + +#. module: l10n_it_fatturapa_in +#: model:ir.model,name:l10n_it_fatturapa_in.model_fatturapa_attachment_in +msgid "FatturaPA import File" +msgstr "Fattura Elettronica Importazione File" + +#. module: l10n_it_fatturapa_in +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:47 #, python-format -msgid "File is linked to invoices yet" -msgstr "" +msgid "File %s is linked to invoices yet" +msgstr "Il file %s è già collegato a delle fatture" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_datas +msgid "File Content" +msgstr "Contenuto del File" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_datas_fname +msgid "File Name" +msgstr "Nome File" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_file_size +msgid "File Size" +msgstr "Dimensione File" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:232 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:304 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:310 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:452 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:561 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:697 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:743 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1052 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1060 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1084 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1245 #, python-format -msgid "Error!" -msgstr "" +msgid "File is linked to invoices yet" +msgstr "Il file è già collegato a delle fatture" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:533 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:550 #, python-format msgid "Global invoice discount from DatiGeneraliDocumento" -msgstr "" +msgstr "Sconto globale da DatiGeneraliDocumento" #. module: l10n_it_fatturapa_in -#: help:fatturapa.attachment.in,message_unread:0 -msgid "If checked new messages require your attention." -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_fatturapa_in_attachment_form +msgid "History" +msgstr "Storico" #. module: l10n_it_fatturapa_in -#: field:account.invoice.line,service_type:0 -msgid "Service Type" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_article_code_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_import_fatturapa_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_link_to_invoice_id +msgid "ID" +msgstr "ID" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.wizard_import_fatturapa_form_view +msgid "Import" +msgstr "Importa" #. module: l10n_it_fatturapa_in -#: view:fatturapa.attachment.in:0 #: model:ir.actions.act_window,name:l10n_it_fatturapa_in.action_wizard_import_fatturapa +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_fatturapa_in_attachment_form +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.wizard_import_fatturapa_form_view +msgid "Import Fattura Elettronica" +msgstr "Import Fattura Elettronica" + +#. module: l10n_it_fatturapa_in #: model:ir.model,name:l10n_it_fatturapa_in.model_wizard_import_fatturapa -#: view:wizard.import.fatturapa:0 msgid "Import FatturaPA" -msgstr "Importa FatturaPA" +msgstr "Importa Fattura Elettronica" #. module: l10n_it_fatturapa_in -#: help:fatturapa.attachment.in,message_summary:0 -msgid "" -"Holds the Chatter summary (number of messages, ...). This summary is " -"directly in html format in order to be inserted in kanban views." -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_account_invoice_inconsistencies +msgid "Import Inconsistencies" +msgstr "Inconsistenze" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Related Documents" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_in_invoice_ids +msgid "In Invoices" +msgstr "Fatture passive" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Welfare Fund Details" -msgstr "" +#: model:ir.actions.act_window,name:l10n_it_fatturapa_in.action_fattura_pa_in +#: model:ir.ui.menu,name:l10n_it_fatturapa_in.menu_fattura_pa_in_tree +msgid "Incoming Fattura Elettronica files" +msgstr "File in ingresso Fattura Elettronica" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:698 -#, python-format -msgid "Define a purchase journal for this company: \"%s\" (id:%d)." -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_index_content +msgid "Indexed Content" +msgstr "Contenuto Indicizzato" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:562 +#: model:ir.model,name:l10n_it_fatturapa_in.model_account_invoice +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_invoice_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_link_to_invoice_invoice_id +msgid "Invoice" +msgstr "Fattura" + +#. module: l10n_it_fatturapa_in +#: model:ir.model,name:l10n_it_fatturapa_in.model_account_invoice_line +msgid "Invoice Line" +msgstr "Riga Fattura" + +#. module: l10n_it_fatturapa_in +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1207 #, python-format -msgid "ModalitaPagamento %s not defined in your system" -msgstr "" +msgid "Invoice total %s is different from ImportoTotaleDocumento %s" +msgstr "Il totale fattura %s è diverso da ImportoTotaleDocumento %s" #. module: l10n_it_fatturapa_in -#: field:fatturapa.attachment.in,message_follower_ids:0 -msgid "Followers" -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_fatturapa_in_attachment_form +msgid "Invoices" +msgstr "Fatture" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Rise Price Discount" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_invoices_number +msgid "Invoices number" +msgstr "Numero fatture" #. module: l10n_it_fatturapa_in -#: view:account.invoice.line:0 -msgid "Articles Code" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_invoices_total +msgid "Invoices total" +msgstr "Totale fatture" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:132 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:171 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:212 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:247 -#, python-format -msgid "Error !" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_public +msgid "Is public document" +msgstr "È un documento pubblico" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "FatturaPA Payment" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line___last_update +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data___last_update +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_article_code___last_update +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in___last_update +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_import_fatturapa___last_update +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_link_to_invoice___last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" #. module: l10n_it_fatturapa_in -#: field:account.invoice.line,service_start:0 -msgid "Service start at" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_write_uid +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_write_uid +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_article_code_write_uid +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_write_uid +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_import_fatturapa_write_uid +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_link_to_invoice_write_uid +msgid "Last Updated by" +msgstr "Ultima modifica di" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_write_date +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_write_date +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_article_code_write_date +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_write_date +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_import_fatturapa_write_date +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_link_to_invoice_write_date +msgid "Last Updated on" +msgstr "Ultima modifica il" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:623 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:308 #, python-format -msgid "Name of Bank with BIC \"%s\" is not set. Can't create bank" -msgstr "" +msgid "Line '%s': Too many taxes with percentage equals to \"%s\"\n" +"fix it if required" +msgstr "Riga '%s': Troppe imposte con aliquota uguale a\"%s\"\n" +"correggere se necessario" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Payments Details" -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.wizard_link_supplier_invoice +msgid "Link" +msgstr "Collega" #. module: l10n_it_fatturapa_in -#: field:fatturapa.attachment.in,in_invoice_ids:0 -msgid "In Invoices" -msgstr "" +#: model:ir.model,name:l10n_it_fatturapa_in.model_wizard_link_to_invoice +msgid "Link to Supplier Invoice" +msgstr "Collega a fattura fornitore" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "FatturaPA" -msgstr "" +#: model:ir.actions.act_window,name:l10n_it_fatturapa_in.action_wizard_link_supplier_invoice +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.wizard_link_supplier_invoice +msgid "Link to existing supplier invoice" +msgstr "Collega a fattura fornitore esistente" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:135 +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_res_partner_e_invoice_detail_level +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_res_users_e_invoice_detail_level +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_wizard_import_fatturapa_e_invoice_detail_level +msgid "Livello di dettaglio Fatture elettroniche" +msgstr "Livello di dettaglio Fatture elettroniche" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_res_partner_e_invoice_detail_level +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_res_users_e_invoice_detail_level +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_wizard_import_fatturapa_e_invoice_detail_level +msgid "Livello minimo: La fattura passiva viene creata senza righe; sarà l'utente a doverle creare in base a quanto indicato dal fornitore nella fattura elettronica\n" +"Livello Massimo: tutte le righe presenti nella fattura elettronica vengono create come righe della fattura passiva" +msgstr "Livello minimo: La fattura passiva viene creata senza righe; sarà l'utente a doverle creare in base a quanto indicato dal fornitore nella fattura elettronica\n" +"Livello Massimo: tutte le righe presenti nella fattura elettronica vengono create come righe della fattura passiva" + +#. module: l10n_it_fatturapa_in +#: selection:res.partner,e_invoice_detail_level:0 +#: selection:wizard.import.fatturapa,e_invoice_detail_level:0 +msgid "Massimo" +msgstr "Massimo" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_mimetype +msgid "Mime Type" +msgstr "Tipo Mime" + +#. module: l10n_it_fatturapa_in +#: selection:res.partner,e_invoice_detail_level:0 +#: selection:wizard.import.fatturapa,e_invoice_detail_level:0 +msgid "Minimo" +msgstr "Minimo" + +#. module: l10n_it_fatturapa_in +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:609 #, python-format -msgid "" -"Two distinct partners with Vat %s and Fiscalcode %s already present in db" -msgstr "" +msgid "ModalitaPagamento %s not defined in your system" +msgstr "Modalita Pagamento %s non definito nel sistema" #. module: l10n_it_fatturapa_in -#: field:account.invoice.line,ftpa_uom:0 -msgid "Fattura Pa Unit of Measure" -msgstr "" +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:667 +#, python-format +msgid "Name of Bank with BIC \"%s\" is not set. Can't create bank" +msgstr "Il nome della banca con BIC \"%s\" non è impostato. Impossibile creare la banca" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_tax_kind +msgid "Natura" +msgstr "Natura" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:328 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:829 #, python-format -msgid "" -"XML contains tax with percentage \"%s\" but it does not exist in your system" -msgstr "" +msgid "No currency found with code %s" +msgstr "Nessuna valuta trovata con codice %s" #. module: l10n_it_fatturapa_in -#: view:fatturapa.attachment.in:0 -msgid "on" -msgstr "" +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:279 +#, python-format +msgid "No tax with percentage %s and nature %s found. Please configure this tax" +msgstr "Nessuna imposta con aliquota %s e natura %s trovata. Configurare questa imposta" #. module: l10n_it_fatturapa_in -#: view:fatturapa.attachment.in:0 -msgid "Invoices" -msgstr "" +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:913 +#, python-format +msgid "No withholding tax found with Causale %s and rate %s" +msgstr "Nessuna ritenuta trovata con Causale %s e importo %s" #. module: l10n_it_fatturapa_in -#: view:fatturapa.attachment.in:0 -msgid "Xml Attachment" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_line_number +msgid "Numero Linea" +msgstr "Numero Linea" #. module: l10n_it_fatturapa_in -#: model:ir.model,name:l10n_it_fatturapa_in.model_account_invoice_line -msgid "Invoice Line" -msgstr "" +#: model:ir.model,name:l10n_it_fatturapa_in.model_res_partner +msgid "Partner" +msgstr "Partner" #. module: l10n_it_fatturapa_in -#: field:fatturapa.article.code,invoice_line_id:0 -msgid "Related Invoice line" -msgstr "" +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1145 +#, python-format +msgid "Payment method Code %s is incorrect" +msgstr "Codice metodo di oagamento %s non corretto" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:84 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1140 #, python-format -msgid "DatiAnagrafici.Anagrafica.Nome contains \"%s\". Your System contains \"%s\"" -msgstr "" +msgid "Payment method Code not found in document" +msgstr "Codice metodo di pagamento non trovato nel documento" #. module: l10n_it_fatturapa_in -#: selection:account.invoice.line,service_type:0 -msgid "abbuono" -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Payments" +msgstr "Pagamenti" #. module: l10n_it_fatturapa_in -#: field:fatturapa.attachment.in,ir_attachment_id:0 -msgid "Attachment" -msgstr "Allegato" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Payments Details" +msgstr "Payments Details" #. module: l10n_it_fatturapa_in -#: view:wizard.import.fatturapa:0 -msgid "Import" -msgstr "Importa" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_total_price +msgid "Prezzo Totale" +msgstr "Prezzo Totale" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1120 -#, python-format -msgid "XML IPA code (%s) different from company IPA code (%s)" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_unit_price +msgid "Prezzo unitario" +msgstr "Prezzo unitario" #. module: l10n_it_fatturapa_in -#: view:account.invoice.line:0 -msgid "Discount Rise Price" -msgstr "" +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_account_config_settings_dati_bollo_product_id +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_res_company_dati_bollo_product_id +msgid "Prodotto da utilizzare nelle fatture passive quando nell'XML viene valorizzato l'elemento DatiBollo" +msgstr "Prodotto da utilizzare nelle fatture passive quando nell'XML viene valorizzato l'elemento DatiBollo" #. module: l10n_it_fatturapa_in -#: selection:account.invoice.line,service_type:0 -msgid "premio" -msgstr "" +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_account_config_settings_cassa_previdenziale_product_id +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_res_company_cassa_previdenziale_product_id +msgid "Prodotto da utilizzare nelle fatture passive quando nell'XML viene valorizzato l'elemento DatiCassaPrevidenziale" +msgstr "Prodotto da utilizzare nelle fatture passive quando nell'XML viene valorizzato l'elemento DatiCassaPrevidenziale" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_account_config_settings_sconto_maggiorazione_product_id +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_res_company_sconto_maggiorazione_product_id +msgid "Prodotto da utilizzare nelle fatture passive quando nell'XML viene valorizzato l'elemento ScontoMaggiorazione" +msgstr "Prodotto da utilizzare nelle fatture passive quando nell'XML viene valorizzato l'elemento ScontoMaggiorazione" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_account_config_settings_dati_bollo_product_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_res_company_dati_bollo_product_id +msgid "Product for Dati Bollo" +msgstr "Prodotto per Dati Bollo" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:744 +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_account_config_settings_cassa_previdenziale_product_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_res_company_cassa_previdenziale_product_id +msgid "Product for Dati Cassa Previdenziale" +msgstr "Prodotto per Dati Cassa Previdenziale" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_account_config_settings_sconto_maggiorazione_product_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_res_company_sconto_maggiorazione_product_id +msgid "Product for Sconto Maggiorazione" +msgstr "Prodotto per Sconto Maggiorazione" + +#. module: l10n_it_fatturapa_in +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:198 #, python-format -msgid "No currency found with code %s" -msgstr "" +msgid "Provincia ( %s ) not present in system" +msgstr "Provincia ( %s ) non presente nel database" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:213 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:188 #, python-format msgid "ProvinciaAlbo ( %s ) not present in system" -msgstr "" +msgstr "ProvinciaAlbo ( %s ) non presente nel database" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_qty +msgid "Quantita'" +msgstr "Quantita'" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1053 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:228 #, python-format -msgid "Payment method Code not found in document" -msgstr "" +msgid "REA Office (Province) Code ( %s ) not present in system" +msgstr "Codice ufficio REA (Provincia) ( %s ) non presente nel database" #. module: l10n_it_fatturapa_in -#: field:fatturapa.attachment.in,message_is_follower:0 -msgid "Is a Follower" -msgstr "" +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:216 +#, python-format +msgid "RegimeFiscale %s is not present in your system" +msgstr "RegimeFiscale %s non presente nel database" #. module: l10n_it_fatturapa_in -#: field:account.invoice,inconsistencies:0 -msgid "Import Inconsistencies" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_registered +msgid "Registered" +msgstr "Registrata" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:172 -#, python-format -msgid "Country Code %s not found in system" -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Related Documents" +msgstr "Documenti Correlati" #. module: l10n_it_fatturapa_in -#: model:ir.model,name:l10n_it_fatturapa_in.model_fatturapa_article_code -msgid "FatturaPA Article Code" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_discount_rise_price_e_invoice_line_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_e_invoice_line_id +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_article_code_e_invoice_line_id +msgid "Related E-Invoice line" +msgstr "Riga fattura elettronica correlata" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1085 -#, python-format -msgid "Attachment Name is Required" -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_fatturapa_in_attachment_form +msgid "Remove" +msgstr "Rimuovi" #. module: l10n_it_fatturapa_in -#: field:fatturapa.attachment.in,message_summary:0 -msgid "Summary" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_res_field +msgid "Resource Field" +msgstr "Campo Risorsa" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:473 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:770 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1119 -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1284 -#, python-format -msgid "Error" -msgstr "Errore" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_res_id +msgid "Resource ID" +msgstr "ID Risorsa" #. module: l10n_it_fatturapa_in -#: field:fatturapa.article.code,name:0 -msgid "Cod Type" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_res_model +msgid "Resource Model" +msgstr "Modello della Risorsa" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:305 -#, python-format -msgid "No tax with percentage %s and nature %s found" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_res_name +msgid "Resource Name" +msgstr "Nome Risorsa" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Fattura PA V1.1 Schema" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_date_ref +msgid "Riferimento Data" +msgstr "Riferimento Data" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Attachments" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_num_ref +msgid "Riferimento Numero" +msgstr "Riferimento Numero" #. module: l10n_it_fatturapa_in -#: model:ir.model,name:l10n_it_fatturapa_in.model_account_invoice -msgid "Invoice" -msgstr "Fattura" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_text_ref +msgid "Riferimento Testo" +msgstr "Riferimento Testo" #. module: l10n_it_fatturapa_in -#: selection:account.invoice.line,service_type:0 -msgid "spesa accessoria" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_admin_ref +msgid "Riferimento mministrazione" +msgstr "Riferimento mministrazione" #. module: l10n_it_fatturapa_in -#: view:wizard.import.fatturapa:0 -msgid "Cancel" -msgstr "Annulla" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_wt_amount +msgid "Ritenuta" +msgstr "Ritenuta" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "SAL data" +msgstr "Dati SAL" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Sconto Maggiorazione" +msgstr "Sconto Maggiorazione" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_fatturapa_attachment_in_invoices_total +msgid "Se indicato dal fornitore, Importo totale del documento al netto dell'eventuale sconto e comprensivo di imposta a debito del cessionario / committente" +msgstr "Se indicato dal fornitore, Importo totale del documento al netto dell'eventuale sconto e comprensivo di imposta a debito del cessionario / committente" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_fatturapa_in_attachment_form +msgid "Show preview" +msgstr "Mostra anteprima" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Stabile Organizzazione" +msgstr "Stabile Organizzazione" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_store_fname +msgid "Stored Filename" +msgstr "Nome del File Registrato" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in msgid "Summary Data" -msgstr "" +msgstr "Dati riepilogo" #. module: l10n_it_fatturapa_in -#: field:account.invoice.line,discount_rise_price_ids:0 -msgid "Discount and Rise Price Details" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_xml_supplier_id +msgid "Supplier" +msgstr "Fornitore" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:337 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:901 #, python-format -msgid "" -"Line '%s': Too many taxes with percentage equals to \"%s\"\n" -"fix it if required" -msgstr "" +msgid "Supplier invoice contains withholding tax with CausalePagamento %s, but such a tax is not found in your system. Please set it" +msgstr "La fattura contiene la ritenuta con Causale Pagamento %s, ma tale ritenuta non è presente nel sistema. Prego impostarla" #. module: l10n_it_fatturapa_in -#: view:fatturapa.attachment.in:0 -msgid "Creation" -msgstr "" +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:471 +#, python-format +msgid "Tax kind %s not found" +msgstr "Tipo imposta %s non trovato" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Welfare Fund" -msgstr "" +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_fatturapa_attachment_in_res_model +msgid "The database object this attachment will be attached to." +msgstr "L'oggetto del database a cui verrà allegato questo allegato." + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_fatturapa_attachment_in_res_id +msgid "The record id this is attached to." +msgstr "L'ID del record a cui questo è allegato." #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1175 +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_service_type +msgid "Tipo Cessione Prestazione" +msgstr "Tipo Cessione Prestazione" + +#. module: l10n_it_fatturapa_in +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_other_data_name +msgid "Tipo Dato" +msgstr "Tipo Dato" + +#. module: l10n_it_fatturapa_in +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:498 #, python-format -msgid "Computed amount untaxed %s is different from DatiRiepilogo %s" -msgstr "" +msgid "TipoCassa %s is not present in your system" +msgstr "TipoCassa %s non presente nel database" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1264 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:480 #, python-format -msgid "Signed Xml file not decryptable" -msgstr "" +msgid "TipoCassa is not defined " +msgstr "TipoCassa non definito " + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_fatturapa_in_attachment_search +msgid "To Register" +msgstr "Da registrare" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1209 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:284 #, python-format -msgid "Check PEM file %s" -msgstr "" +msgid "Too many taxes with percentage %s and nature %s found" +msgstr "Troppe imposte con aliquota %s e natura %s trovate" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1158 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:135 #, python-format -msgid "Invoice total %s is different from ImportoTotaleDocumento %s" -msgstr "" +msgid "Two distinct partners with Vat %s and Fiscalcode %s already present in db" +msgstr "2 differenti partner con P.IVA %s e codice fiscale %s sono già presenti nel database" #. module: l10n_it_fatturapa_in -#: model:ir.model,name:l10n_it_fatturapa_in.model_fatturapa_attachment_in -msgid "FatturaPA import File" -msgstr "Fattura PA Importazione File" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_type +msgid "Type" +msgstr "Tipo" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Delivery" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_einvoice_line_uom +msgid "Unita' di misura" +msgstr "Unita' di misura" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Progress Work" -msgstr "" +#: model:ir.model.fields,field_description:l10n_it_fatturapa_in.field_fatturapa_attachment_in_url +msgid "Url" +msgstr "Url" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:474 -#, python-format -msgid "TipoCassa %s is not present in your system" -msgstr "" +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_res_partner_e_invoice_default_product_id +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_res_users_e_invoice_default_product_id +msgid "Used by electronic invoice XML import. If filled, generated invoice lines will use this product, when no other possible product is found." +msgstr "Usato nell'importazione XML delle fatture elettroniche. Se valorizzato, le fatture generate nell'importazione utilizzeranno questo prodotto, quando nessun'altro possibile prodotto verrà trovato" #. module: l10n_it_fatturapa_in -#: view:wizard.import.fatturapa:0 -msgid "Confirm?" -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Welfare Fund" +msgstr "Cassa previdenziale" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "FatturaPA attachments" -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_invoice_form_fatturapa_in +msgid "Welfare Fund Details" +msgstr "Dettagli cassa previdenziale" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:653 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:370 #, python-format -msgid "" -"BIC is required and not exist in Xml\n" -"Curr bank data is: \n" -"IBAN: %s\n" -"Bank Name: %s\n" -msgstr "" +msgid "XML contains tax %s. Product %s has tax %s. Using the XML one" +msgstr "L'XML contiene l'imposta %s. Il prodotto %s ha l'imposta %s. Utilizzo quella dell'XML" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Payments" -msgstr "" +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:299 +#, python-format +msgid "XML contains tax with percentage \"%s\" but it does not exist in your system" +msgstr "L'XML contiene l'imposta con alquota \"%s\" ma questa non esiste nel database" #. module: l10n_it_fatturapa_in -#: field:account.invoice.line,service_end:0 -msgid "Service end at" -msgstr "" +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_fatturapa_in_attachment_tree +msgid "Xml Attachment" +msgstr "Allegato XML" #. module: l10n_it_fatturapa_in -#: help:fatturapa.attachment.in,message_ids:0 -msgid "Messages and communication history" -msgstr "" +#: model:ir.model.fields,help:l10n_it_fatturapa_in.field_fatturapa_attachment_in_type +msgid "You can either upload a file from your computer or copy/paste an internet link to your file." +msgstr "Puoi inviare un file dal computer o copiare/incollare un indirizzo Internet che è collegato al tuo file." #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:1236 +#: code:addons/l10n_it_fatturapa_in/wizard/link_to_existing_invoice.py:19 #, python-format -msgid "ASN.1 structure is not parsable in DER" -msgstr "" +msgid "You can select only 1 XML file to link" +msgstr "E' possibile selezionare solo un file XML da collegare" #. module: l10n_it_fatturapa_in -#: model:ir.actions.act_window,name:l10n_it_fatturapa_in.action_fattura_pa_in -#: model:ir.ui.menu,name:l10n_it_fatturapa_in.menu_fattura_pa_in_tree -msgid "Incoming fatturaPA files" -msgstr "" +#: model:ir.model,name:l10n_it_fatturapa_in.model_account_config_settings +msgid "account.config.settings" +msgstr "account.config.settings" #. module: l10n_it_fatturapa_in -#: view:account.invoice:0 -msgid "Results" -msgstr "" +#: model:ir.model,name:l10n_it_fatturapa_in.model_einvoice_line +msgid "einvoice.line" +msgstr "einvoice.line" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:71 -#, python-format -msgid "" -"DatiAnagrafici.Anagrafica.Denominazione contains \"%s\". Your System " -"contains \"%s\"" -msgstr "" +#: model:ir.model,name:l10n_it_fatturapa_in.model_einvoice_line_other_data +msgid "einvoice.line.other.data" +msgstr "einvoice.line.other.data" + +#. module: l10n_it_fatturapa_in +#: model:ir.ui.view,arch_db:l10n_it_fatturapa_in.view_fatturapa_in_attachment_form +msgid "on" +msgstr "il" #. module: l10n_it_fatturapa_in -#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:233 +#: code:addons/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py:852 #, python-format -msgid "RegimeFiscale %s is not present in your system" -msgstr "" +msgid "tipoDocumento %s not handled" +msgstr "tipoDocumento %s non gestito" + diff --git a/l10n_it_fatturapa_in/models/__init__.py b/l10n_it_fatturapa_in/models/__init__.py index 98b75af48313..aa731e35a87e 100644 --- a/l10n_it_fatturapa_in/models/__init__.py +++ b/l10n_it_fatturapa_in/models/__init__.py @@ -1,24 +1,6 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 AgileBG SAGL -# Copyright (C) 2015 innoviu Srl -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - from . import attachment from . import account +from . import partner +from . import company diff --git a/l10n_it_fatturapa_in/models/account.py b/l10n_it_fatturapa_in/models/account.py index 91a13940e8de..33d5ff5c2ccd 100644 --- a/l10n_it_fatturapa_in/models/account.py +++ b/l10n_it_fatturapa_in/models/account.py @@ -1,75 +1,116 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2014 Davide Corio -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import fields, orm - - -class account_invoice(orm.Model): + +from odoo import fields, models, api +import odoo.addons.decimal_precision as dp + + +class AccountInvoice(models.Model): _inherit = "account.invoice" - _columns = { - 'fatturapa_attachment_in_id': fields.many2one( - 'fatturapa.attachment.in', 'FatturaPA Import File', - ondelete='restrict'), - 'inconsistencies': fields.text('Import Inconsistencies'), - } + fatturapa_attachment_in_id = fields.Many2one( + 'fatturapa.attachment.in', 'E-Invoice Import File', + ondelete='restrict', copy=False) + inconsistencies = fields.Text('Import Inconsistencies', copy=False) + e_invoice_line_ids = fields.One2many( + "einvoice.line", "invoice_id", string="Dettaglio Linee", + readonly=True, copy=False) + @api.multi + def name_get(self): + result = super(AccountInvoice, self).name_get() + res = [] + for tup in result: + invoice = self.browse(tup[0]) + if invoice.type in ('in_invoice', 'in_refund'): + name = "%s, %s" % (tup[1], invoice.partner_id.name) + if invoice.origin: + name += ', %s' % invoice.origin + res.append((invoice.id, name)) + else: + res.append(tup) + return res -class fatturapa_article_code(orm.Model): + @api.multi + def remove_attachment_link(self): + self.ensure_one() + self.fatturapa_attachment_in_id = False + return {'type': 'ir.actions.client', 'tag': 'reload'} + + +class fatturapa_article_code(models.Model): # _position = ['2.2.1.3'] _name = "fatturapa.article.code" _description = 'FatturaPA Article Code' - _columns = { - 'name': fields.char('Cod Type', size=35), - 'code_val': fields.char('Code Value', size=35), - 'invoice_line_id': fields.many2one( - 'account.invoice.line', 'Related Invoice line', - ondelete='cascade', select=True - ) - } + name = fields.Char('Cod Type') + code_val = fields.Char('Code Value') + e_invoice_line_id = fields.Many2one( + 'einvoice.line', 'Related E-Invoice line', readonly=True + ) -class account_invoice_line(orm.Model): +class AccountInvoiceLine(models.Model): # _position = [ # '2.2.1.3', '2.2.1.6', '2.2.1.7', # '2.2.1.8', '2.1.1.10' # ] _inherit = "account.invoice.line" - _columns = { - 'cod_article_ids': fields.one2many( - 'fatturapa.article.code', 'invoice_line_id', - 'Cod. Articles' - ), - 'service_type': fields.selection([ - ('SC', 'sconto'), - ('PR', 'premio'), - ('AB', 'abbuono'), - ('AC', 'spesa accessoria'), - ], string="Service Type"), - 'ftpa_uom': fields.char('Fattura Pa Unit of Measure', size=10), - 'service_start': fields.date('Service start at'), - 'service_end': fields.date('Service end at'), - 'discount_rise_price_ids': fields.one2many( - 'discount.rise.price', 'invoice_line_id', - 'Discount and Rise Price Details' - ), - } + fatturapa_attachment_in_id = fields.Many2one( + 'fatturapa.attachment.in', 'E-Invoice Import File', + readonly=True, related='invoice_id.fatturapa_attachment_in_id') + + +class DiscountRisePrice(models.Model): + _inherit = "discount.rise.price" + e_invoice_line_id = fields.Many2one( + 'einvoice.line', 'Related E-Invoice line', readonly=True + ) + + +class EInvoiceLine(models.Model): + _name = 'einvoice.line' + invoice_id = fields.Many2one( + "account.invoice", "Invoice", readonly=True) + line_number = fields.Integer('Numero Linea', readonly=True) + service_type = fields.Char('Tipo Cessione Prestazione', readonly=True) + cod_article_ids = fields.One2many( + 'fatturapa.article.code', 'e_invoice_line_id', + 'Cod. Articles', readonly=True + ) + name = fields.Char("Descrizione", readonly=True) + qty = fields.Float( + "Quantita'", readonly=True, + digits=dp.get_precision('Product Unit of Measure') + ) + uom = fields.Char("Unita' di misura", readonly=True) + period_start_date = fields.Date("Data Inizio Periodo", readonly=True) + period_end_date = fields.Date("Data Fine Periodo", readonly=True) + unit_price = fields.Float( + "Prezzo unitario", readonly=True, + digits=dp.get_precision('Product Price') + ) + discount_rise_price_ids = fields.One2many( + 'discount.rise.price', 'e_invoice_line_id', + 'Discount and Rise Price Details', readonly=True + ) + total_price = fields.Float("Prezzo Totale", readonly=True) + tax_amount = fields.Float("Aliquota IVA", readonly=True) + wt_amount = fields.Char("Ritenuta", readonly=True) + tax_kind = fields.Char("Natura", readonly=True) + admin_ref = fields.Char("Riferimento mministrazione", readonly=True) + other_data_ids = fields.One2many( + "einvoice.line.other.data", "e_invoice_line_id", + string="Altri dati gestionali", readonly=True) + + +class EInvoiceLineOtherData(models.Model): + _name = 'einvoice.line.other.data' + + e_invoice_line_id = fields.Many2one( + 'einvoice.line', 'Related E-Invoice line', readonly=True + ) + name = fields.Char("Tipo Dato", readonly=True) + text_ref = fields.Char("Riferimento Testo", readonly=True) + num_ref = fields.Float("Riferimento Numero", readonly=True) + date_ref = fields.Char("Riferimento Data", readonly=True) diff --git a/l10n_it_fatturapa_in/models/attachment.py b/l10n_it_fatturapa_in/models/attachment.py index 83d8767d2d67..9b8613c6f6e2 100644 --- a/l10n_it_fatturapa_in/models/attachment.py +++ b/l10n_it_fatturapa_in/models/attachment.py @@ -1,40 +1,66 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 AgileBG SAGL -# Copyright (C) 2015 innoviu Srl -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import fields, orm - - -class FatturaPAAttachmentIn(orm.Model): + +from odoo import fields, models, api + + +class FatturaPAAttachmentIn(models.Model): _name = "fatturapa.attachment.in" _description = "FatturaPA import File" _inherits = {'ir.attachment': 'ir_attachment_id'} _inherit = ['mail.thread'] + _order = 'id desc' + + ir_attachment_id = fields.Many2one( + 'ir.attachment', 'Attachment', required=True, ondelete="cascade") + in_invoice_ids = fields.One2many( + 'account.invoice', 'fatturapa_attachment_in_id', + string="In Invoices", readonly=True) + xml_supplier_id = fields.Many2one( + "res.partner", string="Supplier", compute="_compute_xml_data", + store=True) + invoices_number = fields.Integer( + "Invoices number", compute="_compute_xml_data", store=True) + invoices_total = fields.Float( + "Invoices total", compute="_compute_xml_data", store=True, + help="Se indicato dal fornitore, Importo totale del documento al " + "netto dell'eventuale sconto e comprensivo di imposta a debito " + "del cessionario / committente" + ) + registered = fields.Boolean( + "Registered", compute="_compute_registered", store=True) + + @api.onchange('datas_fname') + def onchagne_datas_fname(self): + self.name = self.datas_fname + + def get_xml_string(self): + return self.ir_attachment_id.get_xml_string() - _columns = { - 'ir_attachment_id': fields.many2one( - 'ir.attachment', 'Attachment', required=True, ondelete="cascade"), - 'in_invoice_ids': fields.one2many( - 'account.invoice', 'fatturapa_attachment_in_id', - string="In Invoices", readonly=True), - } + @api.multi + @api.depends('ir_attachment_id.datas') + def _compute_xml_data(self): + for att in self: + fatt = self.env['wizard.import.fatturapa'].get_invoice_obj(att) + cedentePrestatore = fatt.FatturaElettronicaHeader.CedentePrestatore + partner_id = self.env['wizard.import.fatturapa'].getCedPrest( + cedentePrestatore) + att.xml_supplier_id = partner_id + att.invoices_number = len(fatt.FatturaElettronicaBody) + att.invoices_total = 0 + for invoice_body in fatt.FatturaElettronicaBody: + att.invoices_total += float( + invoice_body.DatiGenerali.DatiGeneraliDocumento. + ImportoTotaleDocumento or 0 + ) - def set_name(self, cr, uid, ids, datas_fname, context=None): - return {'value': {'name': datas_fname}} + @api.multi + @api.depends('in_invoice_ids') + def _compute_registered(self): + for att in self: + if ( + att.in_invoice_ids and + len(att.in_invoice_ids) == att.invoices_number + ): + att.registered = True + else: + att.registered = False diff --git a/l10n_it_fatturapa_in/models/company.py b/l10n_it_fatturapa_in/models/company.py new file mode 100644 index 000000000000..d62e695d3595 --- /dev/null +++ b/l10n_it_fatturapa_in/models/company.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- + +from odoo import fields, models, api + + +class ResCompany(models.Model): + _inherit = 'res.company' + + dati_bollo_product_id = fields.Many2one( + 'product.product', 'Product for Dati Bollo', + help='Prodotto da utilizzare nelle fatture passive quando nell\'XML ' + 'viene valorizzato l\'elemento DatiBollo' + ) + cassa_previdenziale_product_id = fields.Many2one( + 'product.product', 'Product for Dati Cassa Previdenziale', + help='Prodotto da utilizzare nelle fatture passive quando nell\'XML ' + 'viene valorizzato l\'elemento DatiCassaPrevidenziale' + ) + sconto_maggiorazione_product_id = fields.Many2one( + 'product.product', 'Product for Sconto Maggiorazione', + help='Prodotto da utilizzare nelle fatture passive quando nell\'XML ' + 'viene valorizzato l\'elemento ScontoMaggiorazione' + ) + + +class AccountConfigSettings(models.TransientModel): + _inherit = 'account.config.settings' + + dati_bollo_product_id = fields.Many2one( + related='company_id.dati_bollo_product_id', + string="Product for Dati Bollo", + help='Prodotto da utilizzare nelle fatture passive quando nell\'XML ' + 'viene valorizzato l\'elemento DatiBollo' + ) + cassa_previdenziale_product_id = fields.Many2one( + related='company_id.cassa_previdenziale_product_id', + string="Product for Dati Cassa Previdenziale", + help='Prodotto da utilizzare nelle fatture passive quando nell\'XML ' + 'viene valorizzato l\'elemento DatiCassaPrevidenziale' + ) + sconto_maggiorazione_product_id = fields.Many2one( + related='company_id.sconto_maggiorazione_product_id', + string="Product for Sconto Maggiorazione", + help='Prodotto da utilizzare nelle fatture passive quando nell\'XML ' + 'viene valorizzato l\'elemento ScontoMaggiorazione' + ) + + @api.onchange('company_id') + def onchange_company_id(self): + res = super(AccountConfigSettings, self).onchange_company_id() + if self.company_id: + company = self.company_id + self.dati_bollo_product_id = ( + company.dati_bollo_product_id and + company.dati_bollo_product_id.id or False + ) + self.cassa_previdenziale_product_id = ( + company.cassa_previdenziale_product_id and + company.cassa_previdenziale_product_id.id or False + ) + self.sconto_maggiorazione_product_id = ( + company.sconto_maggiorazione_product_id and + company.sconto_maggiorazione_product_id.id or False + ) + else: + self.dati_bollo_product_id = False + self.cassa_previdenziale_product_id = False + self.sconto_maggiorazione_product_id = False + return res diff --git a/l10n_it_fatturapa_in/models/partner.py b/l10n_it_fatturapa_in/models/partner.py new file mode 100644 index 000000000000..73bae4c66468 --- /dev/null +++ b/l10n_it_fatturapa_in/models/partner.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +from odoo import models, fields + + +class Partner(models.Model): + _inherit = 'res.partner' + + e_invoice_default_product_id = fields.Many2one( + comodel_name='product.product', + string='Default product electronic invoice', + help="Used by electronic invoice XML import. " + "If filled, generated invoice lines will use this product, when " + "no other possible product is found." + ) + e_invoice_detail_level = fields.Selection([ + ('0', 'Minimo'), + # ('1', 'Aliquote'), + ('2', 'Massimo'), + ], string="Livello di dettaglio Fatture elettroniche passive", + help="Livello minimo: La fattura passiva viene creata senza righe; " + "sara' l'utente a doverle creare in base a quanto indicato dal " + "fornitore nella fattura elettronica\n" + # "Livello Aliquote: viene creata una riga fattura per ogni " + # "aliquota presente nella fattura elettronica\n" + "Livello Massimo: tutte le righe presenti nella fattura " + "elettronica vengono create come righe della fattura passiva", + default='2', required=True + ) diff --git a/l10n_it_fatturapa_in/readme/CONFIGURE.rst b/l10n_it_fatturapa_in/readme/CONFIGURE.rst new file mode 100644 index 000000000000..6024e6c477ae --- /dev/null +++ b/l10n_it_fatturapa_in/readme/CONFIGURE.rst @@ -0,0 +1,14 @@ +Also see the README file of l10n_it_fatturapa module. + +For every supplier, it is possible to set the 'details level of electronic invoices': + + - Minimum level: Supplier invoice is created without lines; user will have to create them, according to what specified in electronic invoice + - Maximum level: every line contained in electronic invoice will create a line in supplier invoice. + +Moreover, it is possible, in supplier form, to set the 'default product for electronic invoices': this product will be used, during generation of supplier invoices, when no other possible product is found. Tax and account of invoice line will be set according to what configured in the product. + +Every product code used by suppliers can be set, in product form, in + +Inventory --> Suppliers + +If supplier specifies a known code in XML, the system will use it to retrieve the correct product to be used in invoice line, setting the related tax and account. diff --git a/l10n_it_fatturapa_in/readme/CONTRIBUTORS.rst b/l10n_it_fatturapa_in/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..b3af0988acfe --- /dev/null +++ b/l10n_it_fatturapa_in/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Lorenzo Battistini +* Roberto Onnis +* Alessio Gerace diff --git a/l10n_it_fatturapa_in/readme/DESCRIPTION.rst b/l10n_it_fatturapa_in/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..f88850e18642 --- /dev/null +++ b/l10n_it_fatturapa_in/readme/DESCRIPTION.rst @@ -0,0 +1,7 @@ +This module allows to import XML files of electronic invoices, version 1.2 + +http://www.fatturapa.gov.it/export/fatturazione/it/normativa/f-2.htm + +received through the exchange system (SDI) + +http://www.fatturapa.gov.it/export/fatturazione/it/sdi.htm diff --git a/l10n_it_fatturapa_in/readme/INSTALL.rst b/l10n_it_fatturapa_in/readme/INSTALL.rst new file mode 100644 index 000000000000..7da985ac1c84 --- /dev/null +++ b/l10n_it_fatturapa_in/readme/INSTALL.rst @@ -0,0 +1,3 @@ +odoo server must run on linux and be able to run + +``openssl`` diff --git a/l10n_it_fatturapa_in/readme/USAGE.rst b/l10n_it_fatturapa_in/readme/USAGE.rst new file mode 100644 index 000000000000..3340773af555 --- /dev/null +++ b/l10n_it_fatturapa_in/readme/USAGE.rst @@ -0,0 +1,6 @@ + * Go to Accounting --> Purchases --> Electronic Invoice + * Upload XML file + * View invoice content clicking on 'show preview' + * Run 'import electronic invoice' wizard to create a draft invoice or run 'link to existing supplier invoice' to link the XML file to an already (automatically) created invoice + +In the incoming electronic invoice files list, by default you will see files to be registered, that is files not yet linked to one or more supplier invoices diff --git a/l10n_it_fatturapa_in/security/ir.model.access.csv b/l10n_it_fatturapa_in/security/ir.model.access.csv index 93910a1eca6c..056d7bcb6181 100644 --- a/l10n_it_fatturapa_in/security/ir.model.access.csv +++ b/l10n_it_fatturapa_in/security/ir.model.access.csv @@ -1,3 +1,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_fatturapa_attachment_in,access_fatturapa_attachment_in,model_fatturapa_attachment_in,account.group_account_invoice,1,1,1,1 access_fatturapa_article_code,access_fatturapa_article_code,model_fatturapa_article_code,account.group_account_invoice,1,1,1,1 +access_einvoice_line,access_einvoice_line,model_einvoice_line,account.group_account_invoice,1,1,1,1 +access_einvoice_line_other_data,access_einvoice_line_other_data,model_einvoice_line_other_data,account.group_account_invoice,1,1,1,1 diff --git a/l10n_it_fatturapa_in/static/description/index.html b/l10n_it_fatturapa_in/static/description/index.html new file mode 100644 index 000000000000..5b693059edef --- /dev/null +++ b/l10n_it_fatturapa_in/static/description/index.html @@ -0,0 +1,460 @@ + + + + + + +Italian Localization - Fattura Elettronica reception + + + +
+

Italian Localization - Fattura Elettronica reception

+ + +

Beta License: LGPL-3 OCA/l10n-italy Translate me on Weblate Try me on Runbot

+

This module allows to import XML files of electronic invoices, version 1.2

+

http://www.fatturapa.gov.it/export/fatturazione/it/normativa/f-2.htm

+

received through the exchange system (SDI)

+

http://www.fatturapa.gov.it/export/fatturazione/it/sdi.htm

+

Table of contents

+ +
+

Installation

+

odoo server must run on linux and be able to run

+

openssl

+
+
+

Configuration

+

Also see the README file of l10n_it_fatturapa module.

+

For every supplier, it is possible to set the ‘details level of electronic invoices’:

+
+
    +
  • Minimum level: Supplier invoice is created without lines; user will have to create them, according to what specified in electronic invoice
  • +
  • Maximum level: every line contained in electronic invoice will create a line in supplier invoice.
  • +
+
+

Moreover, it is possible, in supplier form, to set the ‘default product for electronic invoices’: this product will be used, during generation of supplier invoices, when no other possible product is found. Tax and account of invoice line will be set according to what configured in the product.

+

Every product code used by suppliers can be set, in product form, in

+

Inventory –> Suppliers

+

If supplier specifies a known code in XML, the system will use it to retrieve the correct product to be used in invoice line, setting the related tax and account.

+
+
+

Usage

+
+
    +
  • Go to Accounting –> Purchases –> Electronic Invoice
  • +
  • Upload XML file
  • +
  • View invoice content clicking on ‘show preview’
  • +
  • Run ‘import electronic invoice’ wizard to create a draft invoice or run ‘link to existing supplier invoice’ to link the XML file to an already (automatically) created invoice
  • +
+
+

In the incoming electronic invoice files list, by default you will see files to be registered, that is files not yet linked to one or more supplier invoices

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Agile Business Group
  • +
  • Innoviu
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/l10n-italy project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/l10n_it_fatturapa_in/tests/__init__.py b/l10n_it_fatturapa_in/tests/__init__.py index bea8e1ef33fa..2d2485f34333 100644 --- a/l10n_it_fatturapa_in/tests/__init__.py +++ b/l10n_it_fatturapa_in/tests/__init__.py @@ -1,23 +1,3 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2014 Alessio Gerace -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## from . import test_import_fatturapa_xml - -checks = [test_import_fatturapa_xml] diff --git a/l10n_it_fatturapa_in/tests/data/IT01234567890_11002.xml b/l10n_it_fatturapa_in/tests/data/IT01234567890_FPR03.xml similarity index 53% rename from l10n_it_fatturapa_in/tests/data/IT01234567890_11002.xml rename to l10n_it_fatturapa_in/tests/data/IT01234567890_FPR03.xml index a5e9e02cc1b9..df5f743da8b7 100644 --- a/l10n_it_fatturapa_in/tests/data/IT01234567890_11002.xml +++ b/l10n_it_fatturapa_in/tests/data/IT01234567890_FPR03.xml @@ -1,21 +1,21 @@ - + IT - 01234567890 + 05979361218 00001 - SDI11 - AAAAAA + FPR12 + 0000000 IT - 02537410900 + 02780790107 SOCIETA' ALPHA SRL @@ -32,9 +32,9 @@ - 02537410900 + 03533590174 - AMMINISTRAZIONE BETA + BETA GAMMA @@ -60,36 +60,12 @@ 1 66685 1 - 123abc - 456def - - 1 - 123 - 2012-09-01 - 5 - 123abc - 456def - - - 1 - 123 - 5 - 123abc - 456def - - - 1 - 123 - 5 - 123abc - 456def - IT - 24681012141 + 04507990150 Trasporto spa @@ -101,6 +77,10 @@ 1 + + INT + ART123 + LA DESCRIZIONE DELLA FORNITURA PUO' SUPERARE I CENTO CARATTERI CHE RAPPRESENTAVANO IL PRECEDENTE LIMITE DIMENSIONALE. TALE LIMITE NELLA NUOVA VERSIONE E' STATO PORTATO A MILLE CARATTERI 5.00 1.00 @@ -117,9 +97,9 @@ 22.00 - 27.00 - 5.95 - D + 25.00 + 5.50 + I @@ -127,8 +107,48 @@ MP01 2015-01-30 - 32.95 + 32.50 - + + + + TD01 + EUR + 2014-12-20 + 456 + LA FATTURA FA RIFERIMENTO AD UNA OPERAZIONE AAAA BBBBBBBBBBBBBBBBBB CCC DDDDDDDDDDDDDDD E FFFFFFFFFFFFFFFFFFFF GGGGGGGGGG HHHHHHH II LLLLLLLLLLLLLLLLL MMM NNNNN OO PPPPPPPPPPP QQQQ RRRR SSSSSSSSSSSSSS + SEGUE DESCRIZIONE CAUSALE NEL CASO IN CUI NON SIANO STATI SUFFICIENTI 200 CARATTERI AAAAAAAAAAA BBBBBBBBBBBBBBBBB + + + 1 + 66685 + 1 + + + + + 1 + PRESTAZIONE DEL SEGUENTE SERVIZIO PROFESSIONALE: LA DESCRIZIONE DELLA PRESTAZIONE PUO' SUPERARE I CENTO CARATTERI CHE RAPPRESENTAVANO IL PRECEDENTE LIMITE DIMENSIONALE. TALE LIMITE NELLA NUOVA VERSIONE E' STATO PORTATO A MILLE CARATTERI + 2000.00 + 2000.00 + 22.00 + + + 22.00 + 2000.00 + 440.00 + I + + + + TP01 + + MP19 + 2015-01-28 + 2440.00 + + + + \ No newline at end of file diff --git a/l10n_it_fatturapa_in/tests/data/IT02780790107_11003.xml b/l10n_it_fatturapa_in/tests/data/IT02780790107_11003.xml deleted file mode 100644 index c4b664bd73d4..000000000000 --- a/l10n_it_fatturapa_in/tests/data/IT02780790107_11003.xml +++ /dev/null @@ -1,172 +0,0 @@ - - - - - - IT - 02780790107 - - 00001 - SDI11 - AAAAAA - - - - - - IT - 02780790107 - - - SOCIETA' ALPHA SRL - - RF01 - - - VIALE ROMA 543 - 07100 - SASSARI - SS - IT - - - - - 09876543210 - - AMMINISTRAZIONE BETA - - - - VIA TORINO 38-B - 00145 - ROMA - RM - IT - - - - - - - TD01 - EUR - 2014-12-23 - 125 - LA FATTURA FA RIFERIMENTO AD UNA OPERAZIONE AAAA BBBBBBBBBBBBBBBBBB CCC DDDDDDDDDDDDDDD E FFFFFFFFFFFFFFFFFFFF GGGGGGGGGG HHHHHHH II LLLLLLLLLLLLLLLLL - SEGUE DESCRIZIONE CAUSALE NEL CASO IN CUI NON SIANO STATI SUFFICIENTI 200 CARATTERI AAAAAAAAAAA BBBBBBBBBBBBBBBBB - - - 1 - 1 - 66685 - 1 - 123abc - 456def - - - 2 - 666852 - 2012-10-01 - 4 - 123cba2 - 456fed2 - - - 1 - 123 - 2012-09-01 - 5 - 123abc - 456def - - - 2 - 1232 - 2012-08-01 - 4 - 123abc2 - 456def2 - - - 1 - 2 - 123 - 5 - 123abc - 456def - - - 1 - 123 - 5 - 123abc - 456def - - - 1 - 123 - 2012-09-01 - 1 - 123abc - 456def - - - - - IT - 05714511002 - - - Trasporto spa - - - 2012-10-22T16:46:12.000+02:00 - - - - - 1 - LA DESCRIZIONE DELLA FORNITURA PUO' SUPERARE I CENTO CARATTERI CHE RAPPRESENTAVANO IL PRECEDENTE LIMITE DIMENSIONALE. TALE LIMITE NELLA NUOVA VERSIONE E' STATO PORTATO A MILLE CARATTERI - 5.00 - 1.00 - 5.00 - 22.00 - - - 2 - FORNITURE VARIE PER UFFICIO - 10.00 - 2.00 - 20.00 - 22.00 - - - 22.00 - 27.00 - 5.95 - D - - - - TP01 - - MP01 - 2015-01-30 - 32.95 - - - - test.png - png - descrizione test - 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ly1bJ//xna6PPesN3lx+rf7qsla6+DefwLNTH7xakvz5u6mDELyHHBpgWkgEEAnp8wAge0e2bVESi8UcIsLMSZPeCgYCb8e6YQbAUz0cx1HZbBaM8/cfeeSRkvPPP9999dVX+bZt246LIaq3bNGvueYaedmIEbjv3nufNAOBB5UXkAs/Y1E4GPyaoeupO9ev95maA8Dll1/u0UR0ddDTo7sdmEIINDU1YeCgQdNWr127ctiwYZBSyoMHDx5XH+3evVt77bXXaMmSJVizfv0KJsR17777bo+JIo8XR8XQbLnnovhs04FaYirlSeni7qFtL4wLvJt6HwEhbqkZd9/G3++ZgdN/MtD923easfeHyaNa5e794RT9b985xD5+x31OPnUVqq+4525G5gPvp5tAIOoufa9Syi0NxqBp5v/865opf9iMaoSWHxkals16DK6Fw1ODgYAfm9glbZxznsvlKONlWGp56KGHvvi5z31ONTQ0yA0bNuhHuVhkO3bsMDOZDCZPmeI8VF2Nl3772zc1wxizd+9eWJblKqVIKUX5fF4dOnTINkOhyKm6/hQAVFZWEgCEQiGHiDB9+vSXhRB/725gtmfqAwcOIGia19y/cuUzQ4YMwZAhQ9zm5mYkk0fZR3v36rt378Y555zj7t27F7+85541hqb98NChQ/3OzMAx5LazbiI9dBtz6sevuYgZ9NsDyQ8guGeB7i4hOYFQHohBKpU1BT9n1LYl//C98zB9o/EkBkC/HtL6goXxGE+P4lEWejkE5y6Iy4PvAqsX2F6DGZ4cty6eg/U3g2untOZb/LMBWLE2tOWfALHSQAlKA+FBwzde1VD3uzox5qLOuR785OGVGze+aFnW8EQi4TAvPWy3abRM02TxeBxpy1oXC4fnzCocZVZTU8MCgYA+evRo2rZtm5o4cSIBwOOPP85efPFFPmLECDZixAjFOW9juocfeWSMct0niQiJZLJTtqH2WZtisRgGlJcfkb/i2muv1e+77z5n49atH80lk283NjX1ipn88gCAdP38xXPn/tW/vn79euOUU04BAGlZFsaPH0+PPvooM00To0eP5g888ABfvHhx3m/f6tWrB+UcZ7ehafHW1tZj9tdgAE7/6EfNKePG2fX19T0ebXds2Ud3rgX79znYMXXdk2knN6Yh1ywFetaLXKUoaoZZVAuiCdhpB+1p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 - - - test2.png - png - descrizione test 2 - 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ly1bJ//xna6PPesN3lx+rf7qsla6+DefwLNTH7xakvz5u6mDELyHHBpgWkgEEAnp8wAge0e2bVESi8UcIsLMSZPeCgYCb8e6YQbAUz0cx1HZbBaM8/cfeeSRkvPPP9999dVX+bZt246LIaq3bNGvueYaedmIEbjv3nufNAOBB5UXkAs/Y1E4GPyaoeupO9ev95maA8Dll1/u0UR0ddDTo7sdmEIINDU1YeCgQdNWr127ctiwYZBSyoMHDx5XH+3evVt77bXXaMmSJVizfv0KJsR17777bo+JIo8XR8XQbLnnovhs04FaYirlSeni7qFtL4wLvJt6HwEhbqkZd9/G3++ZgdN/MtD923easfeHyaNa5e794RT9b985xD5+x31OPnUVqq+4525G5gPvp5tAIOoufa9Syi0NxqBp5v/865opf9iMaoSWHxkals16DK6Fw1ODgYAfm9glbZxznsvlKONlWGp56KGHvvi5z31ONTQ0yA0bNuhHuVhkO3bsMDOZDCZPmeI8VF2Nl3772zc1wxizd+9eWJblKqVIKUX5fF4dOnTINkOhyKm6/hQAVFZWEgCEQiGHiDB9+vSXhRB/725gtmfqAwcOIGia19y/cuUzQ4YMwZAhQ9zm5mYkk0fZR3v36rt378Y555zj7t27F7+85541hqb98NChQ/3OzMAx5LazbiI9dBtz6sevuYgZ9NsDyQ8guGeB7i4hOYFQHohBKpU1BT9n1LYl//C98zB9o/EkBkC/HtL6goXxGE+P4lEWejkE5y6Iy4PvAqsX2F6DGZ4cty6eg/U3g2untOZb/LMBWLE2tOWfALHSQAlKA+FBwzde1VD3uzox5qLOuR785OGVGze+aFnW8EQi4TAvPWy3abRM02TxeBxpy1oXC4fnzCocZVZTU8MCgYA+evRo2rZtm5o4cSIBwOOPP85efPFFPmLECDZixAjFOW9juocfeWSMct0niQiJZLJTtqH2WZtisRgGlJcfkb/i2muv1e+77z5n49atH80lk283NjX1ipn88gCAdP38xXPn/tW/vn79euOUU04BAGlZFsaPH0+PPvooM00To0eP5g888ABfvHhx3m/f6tWrB+UcZ7ehafHW1tZj9tdgAE7/6EfNKePG2fX19T0ebXds2Ud3rgX79znYMXXdk2knN6Yh1ywFetaLXKUoaoZZVAuiCdhpB+1p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 - - - diff --git a/l10n_it_fatturapa_in/tests/data/IT02780790107_11004.xml b/l10n_it_fatturapa_in/tests/data/IT02780790107_11004.xml index 1bb43017a3b2..59524300a05c 100644 --- a/l10n_it_fatturapa_in/tests/data/IT02780790107_11004.xml +++ b/l10n_it_fatturapa_in/tests/data/IT02780790107_11004.xml @@ -1,5 +1,8 @@ - + @@ -7,8 +10,8 @@ 02780790107 00001 - SDI11 - 79SRAK + FPA12 + UFPQ1O @@ -88,6 +91,7 @@ LA FATTURA FA RIFERIMENTO AD UNA OPERAZIONE AAAA BBBBBBBBBBBBBBBBBB CCC DDDDDDDDDDDDDDD E FFFFFFFFFFFFFFFFFFFF GGGGGGGGGG HHHHHHH II LLLLLLLLLLLLLLLLL MMM NNNNN OO PPPPPPPPPPP QQQQ SEGUE DESCRIZIONE CAUSALE NEL CASO IN CUI NON SIANO STATI SUFFICIENTI 200 CARATTERI AAAAAAAAAAA BBBBBBBBBBBBBBBBB + SI 1 @@ -160,8 +164,8 @@ 22.00 - 25.00 - 5.50 + 34.00 + 7.48 D diff --git a/l10n_it_fatturapa_in/tests/data/IT02780790107_11005.xml b/l10n_it_fatturapa_in/tests/data/IT02780790107_11005.xml index d14bfb7c3095..8aba9de93e66 100644 --- a/l10n_it_fatturapa_in/tests/data/IT02780790107_11005.xml +++ b/l10n_it_fatturapa_in/tests/data/IT02780790107_11005.xml @@ -1,5 +1,8 @@ - + @@ -7,8 +10,8 @@ 02780790107 11005 - SDI11 - 79SRAK + FPA12 + UFPQ1O @@ -82,8 +85,8 @@ TC01 4.00 - 9.00 - 225.00 + 1.00 + 25.00 22.00 rif. amm @@ -156,15 +159,15 @@ 2 FORNITURE VARIE PER UFFICIO - 10.00 - 2.00 - 20.00 - 22.00 + 10.00 + 2.00 + 20.00 + 22.00 22.00 - 25.00 - 5.50 + 26.00 + 5.72 D diff --git a/l10n_it_fatturapa_in/tests/data/IT02780790107_11006.xml b/l10n_it_fatturapa_in/tests/data/IT02780790107_11006.xml index 969383576ed9..169d5f7e2a37 100644 --- a/l10n_it_fatturapa_in/tests/data/IT02780790107_11006.xml +++ b/l10n_it_fatturapa_in/tests/data/IT02780790107_11006.xml @@ -1,5 +1,8 @@ - + @@ -7,8 +10,8 @@ 02780790107 11005 - SDI11 - 79SRAK + FPA12 + UFPQ1O diff --git a/l10n_it_fatturapa_in/tests/data/IT02780790107_11007.xml b/l10n_it_fatturapa_in/tests/data/IT02780790107_11007.xml index 52f3df99f6c6..99e9fcb8507c 100644 --- a/l10n_it_fatturapa_in/tests/data/IT02780790107_11007.xml +++ b/l10n_it_fatturapa_in/tests/data/IT02780790107_11007.xml @@ -1,5 +1,8 @@ - + @@ -7,8 +10,8 @@ 02780790107 11007 - SDI11 - 79SRAK + FPA12 + UFPQ1O @@ -86,9 +89,8 @@ 15.55 - 26.00 25.00 - 5.50 + 3.89 D diff --git a/l10n_it_fatturapa_in/tests/data/IT05979361218_001.xml b/l10n_it_fatturapa_in/tests/data/IT05979361218_001.xml index 07076657a068..f58a3c51695e 100644 --- a/l10n_it_fatturapa_in/tests/data/IT05979361218_001.xml +++ b/l10n_it_fatturapa_in/tests/data/IT05979361218_001.xml @@ -1,5 +1,8 @@ - - + + @@ -7,8 +10,8 @@ 05979361218 001 - SDI11 - 79SRAK + FPA12 + UFPQ1O @@ -81,11 +84,20 @@ 54.00 0.00 N4 + + Vostro RIF + Riferimento + 3.00 + + + Vostro RIF + Riferimento2 + 0.00 N4 - 54.00 + 57.00 0.00 Operazioni senza addebito imposta regime contribuenti minimi art.27 c.1-2 DL.98/11 @@ -104,4 +116,4 @@ - + diff --git a/l10n_it_fatturapa_in/tests/data/IT05979361218_002.xml b/l10n_it_fatturapa_in/tests/data/IT05979361218_002.xml index e264753a1e0a..7f1c3f08644b 100644 --- a/l10n_it_fatturapa_in/tests/data/IT05979361218_002.xml +++ b/l10n_it_fatturapa_in/tests/data/IT05979361218_002.xml @@ -1,5 +1,8 @@ - - + + @@ -7,8 +10,8 @@ 05979361218 002 - SDI11 - 79SRAK + FPA12 + UFPQ1O @@ -81,7 +84,7 @@ 0.00 N4 - 54.00 + 57.00 0.00 Operazioni senza addebito imposta regime contribuenti minimi art.27 c.1-2 DL.98/11 @@ -100,4 +103,4 @@ - + diff --git a/l10n_it_fatturapa_in/tests/data/IT05979361218_003.xml b/l10n_it_fatturapa_in/tests/data/IT05979361218_003.xml index 3f1f97c5f1a8..240035ebebbe 100644 --- a/l10n_it_fatturapa_in/tests/data/IT05979361218_003.xml +++ b/l10n_it_fatturapa_in/tests/data/IT05979361218_003.xml @@ -1,5 +1,8 @@ - - + + @@ -7,8 +10,8 @@ 05979361218 003 - SDI11 - 79SRAK + FPA12 + UFPQ1O @@ -48,7 +51,7 @@ IT - 05979361228 + 03533590174 MRORSS90E25B111T @@ -66,6 +69,10 @@ EUR 2015-02-16 FT/2015/0008 + + SI + 6.00 + Rif ordine MAPA: --- Nr. Identificativo Ordine 1234567 @@ -92,4 +99,4 @@ - + diff --git a/l10n_it_fatturapa_in/tests/data/IT05979361218_004.xml b/l10n_it_fatturapa_in/tests/data/IT05979361218_004.xml index 1c2e8121e678..fc0442860da3 100644 --- a/l10n_it_fatturapa_in/tests/data/IT05979361218_004.xml +++ b/l10n_it_fatturapa_in/tests/data/IT05979361218_004.xml @@ -1,5 +1,8 @@ - - + + @@ -7,8 +10,8 @@ 05979361218 004 - SDI11 - 79SRAK + FPA12 + UFPQ1O @@ -48,7 +51,7 @@ IT - 05979361228 + 03533590174 MRORSS90E25B111T @@ -115,4 +118,4 @@ - + diff --git a/l10n_it_fatturapa_in/tests/data/IT05979361218_005.xml b/l10n_it_fatturapa_in/tests/data/IT05979361218_005.xml index dc9f4267c8d8..dfbee1c3f82c 100644 --- a/l10n_it_fatturapa_in/tests/data/IT05979361218_005.xml +++ b/l10n_it_fatturapa_in/tests/data/IT05979361218_005.xml @@ -1,5 +1,8 @@ - - + + @@ -7,8 +10,8 @@ 05979361218 005 - SDI11 - 79SRAK + FPA12 + UFPQ1O @@ -106,4 +109,4 @@ - + diff --git a/l10n_it_fatturapa_in/tests/data/IT05979361218_006.XML b/l10n_it_fatturapa_in/tests/data/IT05979361218_006.XML index e86b6765c2e6..d80f20d98b7a 100644 --- a/l10n_it_fatturapa_in/tests/data/IT05979361218_006.XML +++ b/l10n_it_fatturapa_in/tests/data/IT05979361218_006.XML @@ -1,5 +1,8 @@ - - + + @@ -7,8 +10,8 @@ 05979361218 006 - SDI11 - 79SRAK + FPA12 + UFPQ1O @@ -105,4 +108,4 @@ - + diff --git a/l10n_it_fatturapa_in/tests/data/IT05979361218_007.xml b/l10n_it_fatturapa_in/tests/data/IT05979361218_007.xml index f6385a9f6685..e4dccdf77f55 100644 --- a/l10n_it_fatturapa_in/tests/data/IT05979361218_007.xml +++ b/l10n_it_fatturapa_in/tests/data/IT05979361218_007.xml @@ -1,5 +1,8 @@ - - + + @@ -7,8 +10,8 @@ 05979361218 007 - SDI11 - 79SRAK + FPA12 + UFPQ1O @@ -50,7 +53,7 @@ TD01 EUR - 2015-03-16+02:00 + 2015-03-16 FT/2015/0009 Rif ordine MAPA: --- Nr. Identificativo Ordine 1234567 @@ -84,11 +87,11 @@ 2015-06-03+02:00 9.00 Bank Test - IT28V0100003245232200001200 + IT24J0617501400000006042218 GEBABEBB 2.00 2015-06-04+02:00 - + diff --git a/l10n_it_fatturapa_in/tests/data/IT05979361218_008.xml b/l10n_it_fatturapa_in/tests/data/IT05979361218_008.xml index a054f728f770..719edafa35f9 100644 --- a/l10n_it_fatturapa_in/tests/data/IT05979361218_008.xml +++ b/l10n_it_fatturapa_in/tests/data/IT05979361218_008.xml @@ -1,5 +1,8 @@ - - + + @@ -7,8 +10,8 @@ 05979361218 008 - SDI11 - 79SRAK + FPA12 + UFPQ1O @@ -87,4 +90,4 @@ - + diff --git a/l10n_it_fatturapa_in/tests/data/IT05979361218_009.xml b/l10n_it_fatturapa_in/tests/data/IT05979361218_009.xml new file mode 100644 index 000000000000..d63d98fcd40c --- /dev/null +++ b/l10n_it_fatturapa_in/tests/data/IT05979361218_009.xml @@ -0,0 +1,95 @@ + + + + + + IT + 05979361218 + + 009 + FPA12 + UFPQ1O + + + + + + IT + 05979361218 + + + SOCIETA' ALPHA SRL + + RF19 + + + VIALE ROMA 543 + 07100 + SASSARI + SS + IT + + + + + 80213330584 + + DITTA BETA + + + + VIA TORINO 38-B + 00145 + ROMA + RM + IT + + + + + + + TD01 + EUR + 2014-12-18 + 129 + + RT01 + 1.00 + 20.00 + A + + LA FATTURA FA RIFERIMENTO AD UNA OPERAZIONE AAAA BBBBBBBBBBBBBBBBBB CCC DDDDDDDDDDDDDDD E FFFFFFFFFFFFFFFFFFFF GGGGGGGGGG HHHHHHH II LLLLLLLLLLLLLLLLL MMM NNNNN OO PPPPPPPPPPP QQQQ RRRR SSSSSSSSSSSSSS + SEGUE DESCRIZIONE CAUSALE NEL CASO IN CUI NON SIANO STATI SUFFICIENTI 200 CARATTERI AAAAAAAAAAA BBBBBBBBBBBBBBBBB + + + + + 1 + DESCRIZIONE DELLA FORNITURA + 5.00 + 1.00 + 5.00 + 22.00 + SI + + + 22.00 + 5.00 + 1.10 + I + + + + TP01 + + MP01 + 2015-01-30 + 5.10 + + + + \ No newline at end of file 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 e613cc138dfe..b1be1d7a6468 100644 --- a/l10n_it_fatturapa_in/tests/test_import_fatturapa_xml.py +++ b/l10n_it_fatturapa_in/tests/test_import_fatturapa_xml.py @@ -1,113 +1,137 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2014 Davide Corio -# Copyright (C) 2015 Lorenzo Battistini -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## import base64 import tempfile -import openerp.tests.common as test_common -from openerp import addons -from openerp.osv.orm import except_orm +from odoo.tests.common import SingleTransactionCase +from odoo.modules import get_module_resource +from odoo.exceptions import UserError -class TestFatturaPAXMLValidation(test_common.SingleTransactionCase): +class TestFatturaPAXMLValidation(SingleTransactionCase): def getFile(self, filename): - path = addons.get_module_resource('l10n_it_fatturapa_in', - 'tests', 'data', filename) + path = get_module_resource( + 'l10n_it_fatturapa_in', 'tests', 'data', filename) with open(path) as test_data: with tempfile.TemporaryFile() as out: base64.encode(test_data, out) out.seek(0) return path, out.read() + def create_wt(self): + return self.env['withholding.tax'].create({ + 'name': '1040', + 'code': '1040', + 'account_receivable_id': self.payable_account_id, + 'account_payable_id': self.payable_account_id, + 'payment_term': self.env.ref('account.account_payment_term').id, + 'rate_ids': [(0, 0, {'tax': 20.0})], + 'causale_pagamento_id': + self.env.ref('l10n_it_causali_pagamento.a').id, + }) + def setUp(self): super(TestFatturaPAXMLValidation, self).setUp() - self.wizard_model = self.registry('wizard.import.fatturapa') - self.data_model = self.registry('ir.model.data') - self.attach_model = self.registry('fatturapa.attachment.in') - self.invoice_model = self.registry('account.invoice') + self.wizard_model = self.env['wizard.import.fatturapa'] + self.data_model = self.env['ir.model.data'] + self.attach_model = self.env['fatturapa.attachment.in'] + self.invoice_model = self.env['account.invoice'] + self.payable_account_id = self.env['account.account'].search([ + ('user_type_id', '=', self.env.ref( + 'account.data_account_type_payable').id) + ], limit=1).id + self.headphones = self.env.ref( + 'product.product_product_7_product_template') + self.imac = self.env.ref( + 'product.product_product_8_product_template') + self.service = self.env.ref('product.service_delivery') def run_wizard(self, name, file_name): - cr, uid = self.cr, self.uid - attach_id = self.attach_model .create( - cr, uid, + attach_id = self.attach_model.create( { 'name': name, 'datas': self.getFile(file_name)[1], 'datas_fname': file_name - }) - wizard_id = self.wizard_model.create(cr, uid, {}) - - return self.wizard_model.importFatturaPA( - cr, uid, wizard_id, context={'active_ids': [attach_id]}) + }).id + wizard = self.wizard_model.with_context( + active_ids=[attach_id]).create({}) + return wizard.importFatturaPA() def run_wizard_multi(self, file_name_list): - cr, uid = self.cr, self.uid active_ids = [] for file_name in file_name_list: - active_ids.append(self.attach_model .create( - cr, uid, + active_ids.append(self.attach_model.create( { 'name': file_name, 'datas': self.getFile(file_name)[1], 'datas_fname': file_name - })) - wizard_id = self.wizard_model.create(cr, uid, {}) - - return self.wizard_model.importFatturaPA( - cr, uid, wizard_id, context={'active_ids': active_ids}) + }).id) + wizard = self.wizard_model.with_context( + active_ids=active_ids).create({}) + return wizard.importFatturaPA() def test_00_xml_import(self): - cr, uid = self.cr, self.uid + self.env.user.company_id.cassa_previdenziale_product_id = ( + self.service.id) res = self.run_wizard('test0', 'IT05979361218_001.xml') invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) + invoice = self.invoice_model.browse(invoice_id) self.assertEqual(invoice.partner_id.register_code, 'TO1258B') self.assertEqual( invoice.partner_id.register_fiscalpos.code, 'RF02') - self.assertEqual(invoice.supplier_invoice_number, 'FT/2015/0006') - self.assertEqual(invoice.amount_total, 54.00) + self.assertEqual(invoice.reference, 'FT/2015/0006') + self.assertEqual(invoice.amount_total, 57.00) self.assertEqual(invoice.gross_weight, 0.00) self.assertEqual(invoice.net_weight, 0.00) + self.assertEqual(invoice.welfare_fund_ids[0].kind_id.code, 'N4') + self.assertFalse(invoice.art73) + welfare_found = False + for line in invoice.invoice_line_ids: + if line.product_id.id == self.service.id: + self.assertEqual(line.price_unit, 3) + welfare_found = True + self.assertTrue(welfare_found) + self.assertTrue(len(invoice.e_invoice_line_ids) == 1) + self.assertEqual( + invoice.e_invoice_line_ids[0].name, 'Prodotto di test al giorno') + self.assertEqual( + invoice.e_invoice_line_ids[0].qty, 15) + self.assertEqual( + invoice.e_invoice_line_ids[0].uom, 'Giorno(i)') + self.assertEqual( + invoice.e_invoice_line_ids[0].unit_price, 3.6) + self.assertEqual( + invoice.e_invoice_line_ids[0].total_price, 54) + self.assertEqual( + invoice.e_invoice_line_ids[0].tax_amount, 0) + self.assertEqual( + invoice.e_invoice_line_ids[0].tax_kind, 'N4') + self.assertTrue(len(invoice.e_invoice_line_ids[0].other_data_ids) == 2) + self.assertEqual( + invoice.e_invoice_line_ids[0].other_data_ids[0].text_ref, + 'Riferimento') def test_01_xml_import(self): - cr, uid = self.cr, self.uid res = self.run_wizard('test1', 'IT02780790107_11004.xml') invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) - self.assertEqual(invoice.supplier_invoice_number, '123') - self.assertEqual(invoice.amount_untaxed, 25.00) - self.assertEqual(invoice.amount_tax, 5.50) + invoice = self.invoice_model.browse(invoice_id) + self.assertEqual(invoice.reference, '123') + self.assertEqual(invoice.amount_untaxed, 34.00) + self.assertEqual(invoice.amount_tax, 7.48) self.assertEqual( - len(invoice.invoice_line[0].invoice_line_tax_id), 1) + len(invoice.invoice_line_ids[0].invoice_line_tax_ids), 1) self.assertEqual( - invoice.invoice_line[0].invoice_line_tax_id[0].name, '22% ftPA') + invoice.invoice_line_ids[0].invoice_line_tax_ids[0].name, + '22% ftPA acq') self.assertEqual( - invoice.fatturapa_summary_ids[0].amount_untaxed, 25.00) + invoice.fatturapa_summary_ids[0].amount_untaxed, 34.00) self.assertEqual( - invoice.fatturapa_summary_ids[0].amount_tax, 5.50) + invoice.fatturapa_summary_ids[0].amount_tax, 7.48) self.assertEqual( invoice.fatturapa_summary_ids[0].payability, 'D') self.assertEqual(invoice.partner_id.name, "SOCIETA' ALPHA SRL") self.assertEqual(invoice.partner_id.street, "VIALE ROMA 543") - self.assertEqual(invoice.partner_id.province.code, "SS") + self.assertEqual(invoice.partner_id.state_id.code, "SS") self.assertEqual( invoice.tax_representative_id.name, "Rappresentante fiscale") self.assertEqual(invoice.welfare_fund_ids[0].welfare_rate_tax, 0.04) @@ -121,76 +145,91 @@ def test_01_xml_import(self): invoice.welfare_fund_ids[0].welfare_amount_tax, 9) self.assertFalse(invoice.welfare_fund_ids[0].welfare_taxable) self.assertEqual(invoice.unit_weight, 'KGM') - self.assertEqual(invoice.incoterm.code, 'DAP') + self.assertEqual(invoice.ftpa_incoterms, 'DAP') + self.assertEqual(invoice.fiscal_document_type_id.code, 'TD01') + self.assertTrue(invoice.art73) - def test_02_xml_import(self): - cr, uid = self.cr, self.uid - res = self.run_wizard('test2', 'IT03638121008_X11111.xml') - invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) - self.assertEqual(invoice.supplier_invoice_number, '00001') - self.assertEqual(invoice.amount_untaxed, 3) - self.assertEqual(invoice.amount_tax, 0.66) - self.assertEqual( - invoice.fatturapa_summary_ids[0].amount_untaxed, 3) - self.assertEqual( - invoice.fatturapa_summary_ids[0].amount_tax, 0.66) - self.assertEqual(invoice.partner_id.name, "Societa' alpha S.r.l.") + # def test_02_xml_import(self): + # res = self.run_wizard('test2', 'IT03638121008_X11111.xml') + # invoice_id = res.get('domain')[0][2][0] + # invoice = self.invoice_model.browse(invoice_id) + # self.assertEqual(invoice.supplier_invoice_number, '00001') + # self.assertEqual(invoice.amount_untaxed, 3) + # self.assertEqual(invoice.amount_tax, 0.66) + # self.assertEqual( + # invoice.fatturapa_summary_ids[0].amount_untaxed, 3) + # self.assertEqual( + # invoice.fatturapa_summary_ids[0].amount_tax, 0.66) + # self.assertEqual(invoice.partner_id.name, "Societa' alpha S.r.l.") - def test_03_xml_import(self): - cr, uid = self.cr, self.uid - res = self.run_wizard('test3', 'IT05979361218_002.xml.p7m') - invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) - self.assertEqual(invoice.partner_id.register_code, 'TO1258B') - self.assertEqual( - invoice.partner_id.register_fiscalpos.code, 'RF02') - self.assertEqual(invoice.supplier_invoice_number, 'FT/2015/0007') - self.assertEqual(invoice.amount_total, 54.00) + # def test_03_xml_import(self): + # res = self.run_wizard('test3', 'IT05979361218_002.xml.p7m') + # invoice_id = res.get('domain')[0][2][0] + # invoice = self.invoice_model.browse(invoice_id) + # self.assertEqual(invoice.partner_id.register_code, 'TO1258B') + # self.assertEqual( + # invoice.partner_id.register_fiscalpos.code, 'RF02') + # self.assertEqual(invoice.supplier_invoice_number, 'FT/2015/0007') + # self.assertEqual(invoice.amount_total, 54.00) def test_04_xml_import(self): - cr, uid = self.cr, self.uid res = self.run_wizard('test4', 'IT02780790107_11005.xml') invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) - self.assertEqual(invoice.supplier_invoice_number, '124') + invoice = self.invoice_model.browse(invoice_id) + self.assertEqual(invoice.reference, '124') self.assertEqual(invoice.partner_id.name, "SOCIETA' ALPHA SRL") self.assertEqual( - invoice.invoice_line[0].invoice_line_tax_id[0].name, '22% ftPA') + invoice.invoice_line_ids[0].invoice_line_tax_ids[0].name, + '22% ftPA acq') self.assertEqual( - invoice.invoice_line[1].invoice_line_tax_id[0].name, '22% ftPA') + invoice.invoice_line_ids[1].invoice_line_tax_ids[0].name, + '22% ftPA acq') self.assertEqual( - invoice.invoice_line[0].invoice_line_tax_id[0].amount, 0.22) + invoice.invoice_line_ids[0].invoice_line_tax_ids[0].amount, 22) self.assertEqual( - invoice.invoice_line[1].invoice_line_tax_id[0].amount, 0.22) + invoice.invoice_line_ids[1].invoice_line_tax_ids[0].amount, 22) self.assertEqual( - invoice.invoice_line[1].price_unit, 2) - self.assertEqual( - invoice.invoice_line[0].cod_article_ids[0].name, 'EAN') - self.assertEqual( - invoice.invoice_line[0].cod_article_ids[0].code_val, '12345') + invoice.invoice_line_ids[1].price_unit, 2) + self.assertTrue(len(invoice.e_invoice_line_ids) == 2) + for e_line in invoice.e_invoice_line_ids: + self.assertTrue(e_line.line_number in (1, 2)) + if e_line.line_number == 1: + self.assertEqual( + e_line.cod_article_ids[0].name, 'EAN') + self.assertEqual( + e_line.cod_article_ids[0].code_val, '12345') self.assertEqual( invoice.inconsistencies, u'DatiAnagrafici.Anagrafica.Denominazione contains "Societa\' ' - 'Alpha SRL". Your System contains "SOCIETA\' ALPHA SRL"') + 'Alpha SRL". Your System contains "SOCIETA\' ALPHA SRL"\n\n') def test_05_xml_import(self): - cr, uid = self.cr, self.uid + self.env.user.company_id.dati_bollo_product_id = ( + self.service.id) res = self.run_wizard('test5', 'IT05979361218_003.xml') invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) - self.assertEqual(invoice.supplier_invoice_number, 'FT/2015/0008') + invoice = self.invoice_model.browse(invoice_id) + self.assertEqual(invoice.reference, 'FT/2015/0008') self.assertEqual(invoice.sender, 'TZ') self.assertEqual(invoice.intermediary.name, 'ROSSI MARIO') self.assertEqual(invoice.intermediary.firstname, 'MARIO') self.assertEqual(invoice.intermediary.lastname, 'ROSSI') - self.assertEqual( - invoice.invoice_line[0].discount_rise_price_ids[0].name, 'SC') - self.assertEqual( - invoice.invoice_line[0].discount_rise_price_ids[0].percentage, 10) - self.assertEqual(invoice.amount_untaxed, 9) + bollo_found = False + for line in invoice.invoice_line_ids: + if line.product_id.id == self.service.id: + self.assertEqual(line.price_unit, 6) + bollo_found = True + self.assertTrue(bollo_found) + self.assertEqual( + invoice.e_invoice_line_ids[0].discount_rise_price_ids[0].name, + 'SC') + self.assertEqual( + invoice.e_invoice_line_ids[0].discount_rise_price_ids[0]. + percentage, 10 + ) + self.assertEqual(invoice.amount_untaxed, 15) self.assertEqual(invoice.amount_tax, 0) - self.assertEqual(invoice.amount_total, 9) + self.assertEqual(invoice.amount_total, 15) def test_06_import_except(self): # File not exist Exception @@ -198,42 +237,39 @@ def test_06_import_except(self): Exception, self.run_wizard, 'test6_Exception', '') # fake Signed file is passed , generate orm_exception self.assertRaises( - except_orm, self.run_wizard, 'test6_orm_exception', + UserError, self.run_wizard, 'test6_orm_exception', 'IT05979361218_fake.xml.p7m' ) def test_07_xml_import(self): - cr, uid = self.cr, self.uid # 2 lines with quantity != 1 and discounts res = self.run_wizard('test7', 'IT05979361218_004.xml') invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) - self.assertEqual(invoice.supplier_invoice_number, 'FT/2015/0009') - self.assertEqual(invoice.amount_untaxed, 1173.60) + invoice = self.invoice_model.browse(invoice_id) + self.assertEqual(invoice.reference, 'FT/2015/0009') + self.assertAlmostEqual(invoice.amount_untaxed, 1173.60) self.assertEqual(invoice.amount_tax, 258.19) self.assertEqual(invoice.amount_total, 1431.79) - self.assertEqual(invoice.invoice_line[0].admin_ref, 'D122353') + self.assertEqual(invoice.invoice_line_ids[0].admin_ref, 'D122353') def test_08_xml_import(self): - cr, uid = self.cr, self.uid # using ImportoTotaleDocumento res = self.run_wizard('test8', 'IT05979361218_005.xml') invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) - self.assertEqual(invoice.supplier_invoice_number, 'FT/2015/0010') - self.assertEqual(invoice.amount_total, 1288.61) + invoice = self.invoice_model.browse(invoice_id) + self.assertEqual(invoice.reference, 'FT/2015/0010') + self.assertAlmostEqual(invoice.amount_total, 1288.61) self.assertFalse(invoice.inconsistencies) def test_09_xml_import(self): - cr, uid = self.cr, self.uid # using DatiGeneraliDocumento.ScontoMaggiorazione without # ImportoTotaleDocumento # add test file name case sensitive res = self.run_wizard('test9', 'IT05979361218_006.XML') invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) - self.assertEqual(invoice.supplier_invoice_number, 'FT/2015/0011') - self.assertEqual(invoice.amount_total, 1288.61) + invoice = self.invoice_model.browse(invoice_id) + self.assertEqual(invoice.reference, 'FT/2015/0011') + self.assertAlmostEqual(invoice.amount_total, 1288.61) self.assertEqual( invoice.inconsistencies, 'Computed amount untaxed 1030.42 is different from' @@ -241,11 +277,10 @@ def test_09_xml_import(self): def test_10_xml_import(self): # Fix Date format - cr, uid = self.cr, self.uid res = self.run_wizard('test6', 'IT05979361218_007.xml') invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) - self.assertEqual(invoice.supplier_invoice_number, 'FT/2015/0009') + invoice = self.invoice_model.browse(invoice_id) + self.assertEqual(invoice.reference, 'FT/2015/0009') self.assertEqual( invoice.date_invoice, '2015-03-16') self.assertEqual( @@ -261,25 +296,23 @@ def test_10_xml_import(self): def test_11_xml_import(self): # DatiOrdineAcquisto with RiferimentoNumeroLinea referring to # not existing invoice line - cr, uid = self.cr, self.uid res = self.run_wizard('test11', 'IT02780790107_11006.xml') invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) + invoice = self.invoice_model.browse(invoice_id) self.assertEqual( - len(invoice.invoice_line[0].related_documents), 0) + len(invoice.invoice_line_ids[0].related_documents), 0) self.assertEqual( - invoice.invoice_line[0].sequence, 1) + invoice.invoice_line_ids[0].sequence, 1) self.assertEqual( invoice.related_documents[0].type, "order") self.assertEqual( invoice.related_documents[0].lineRef, 60) def test_12_xml_import(self): - cr, uid = self.cr, self.uid res = self.run_wizard('test12', 'IT05979361218_008.xml') invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) - self.assertEqual(invoice.supplier_invoice_number, 'FT/2015/0012') + invoice = self.invoice_model.browse(invoice_id) + self.assertEqual(invoice.reference, 'FT/2015/0012') self.assertEqual(invoice.sender, 'TZ') self.assertEqual(invoice.intermediary.name, 'ROSSI MARIO') self.assertEqual(invoice.intermediary.firstname, 'MARIO') @@ -287,43 +320,102 @@ def test_12_xml_import(self): def test_13_xml_import(self): # inconsistencies must not be duplicated - cr, uid = self.cr, self.uid res = self.run_wizard_multi([ 'IT02780790107_11005.xml', 'IT02780790107_11005.xml', ]) invoice1_id = res.get('domain')[0][2][0] invoice2_id = res.get('domain')[0][2][1] - invoice1 = self.invoice_model.browse(cr, uid, invoice1_id) - invoice2 = self.invoice_model.browse(cr, uid, invoice2_id) + invoice1 = self.invoice_model.browse(invoice1_id) + invoice2 = self.invoice_model.browse(invoice2_id) self.assertEqual( invoice1.inconsistencies, u'DatiAnagrafici.Anagrafica.Denominazione contains "Societa\' ' - 'Alpha SRL". Your System contains "SOCIETA\' ALPHA SRL"') + 'Alpha SRL". Your System contains "SOCIETA\' ALPHA SRL"\n\n') self.assertEqual( invoice2.inconsistencies, u'DatiAnagrafici.Anagrafica.Denominazione contains "Societa\' ' - 'Alpha SRL". Your System contains "SOCIETA\' ALPHA SRL"') + 'Alpha SRL". Your System contains "SOCIETA\' ALPHA SRL"\n\n') def test_14_xml_import(self): # check: no tax code found , write inconsisteance and anyway # create draft - cr, uid = self.cr, self.uid res = self.run_wizard('test14', 'IT02780790107_11007.xml') invoice_id = res.get('domain')[0][2][0] - invoice = self.invoice_model.browse(cr, uid, invoice_id) - self.assertEqual(invoice.supplier_invoice_number, '136') + invoice = self.invoice_model.browse(invoice_id) + self.assertEqual(invoice.reference, '136') self.assertEqual(invoice.partner_id.name, 'SOCIETA\' ALPHA SRL') self.assertEqual(invoice.amount_untaxed, 25.00) self.assertEqual(invoice.amount_tax, 0.0) - # check: filling check_total invoice field with summary data take from - # ''DatitRiepilogo' - self.assertEqual(invoice.check_total, 56.50) self.assertEqual( invoice.inconsistencies, u'DatiAnagrafici.Anagrafica.Denominazione contains "Societa\' ' - 'Alpha SRL". Your System contains "SOCIETA\' ALPHA SRL"\n' + 'Alpha SRL". Your System contains "SOCIETA\' ALPHA SRL"\n\n' u'XML contains tax with percentage "15.55"' ' but it does not exist in your system\n' 'XML contains tax with percentage "15.55"' ' but it does not exist in your system') + + def test_15_xml_import(self): + self.wt = self.create_wt() + res = self.run_wizard('test15', 'IT05979361218_009.xml') + invoice_id = res.get('domain')[0][2][0] + invoice = self.invoice_model.browse(invoice_id) + self.assertAlmostEquals(invoice.withholding_tax_amount, 1) + self.assertAlmostEquals(invoice.amount_total, 6.1) + self.assertAlmostEquals(invoice.amount_net_pay, 5.1) + + def test_16_xml_import(self): + # file B2B downloaded from + # http://www.fatturapa.gov.it/export/fatturazione/it/a-3.htm + res = self.run_wizard('test16', 'IT01234567890_FPR03.xml') + invoice_ids = res.get('domain')[0][2] + invoices = self.invoice_model.browse(invoice_ids) + self.assertEqual(len(invoices), 2) + for invoice in invoices: + self.assertEqual(invoice.inconsistencies, '') + self.assertEqual(invoice.partner_id.name, "SOCIETA' ALPHA SRL") + self.assertTrue(invoice.reference in ('456', '123')) + if invoice.reference == '123': + self.assertTrue(len(invoice.invoice_line_ids) == 2) + for line in invoice.invoice_line_ids: + self.assertFalse(line.product_id) + if invoice.reference == '456': + self.assertTrue(len(invoice.invoice_line_ids) == 1) + for line in invoice.invoice_line_ids: + self.assertFalse(line.product_id) + + partner = invoice.partner_id + partner.e_invoice_default_product_id = ( + self.imac.product_variant_ids[0].id) + # I create a supplier code to be matched in XML + self.env['product.supplierinfo'].create({ + 'name': partner.id, + 'product_tmpl_id': self.headphones.id, + 'product_code': 'ART123', + }) + res = self.run_wizard('test17', 'IT01234567890_FPR03.xml') + invoice_ids = res.get('domain')[0][2] + invoices = self.invoice_model.browse(invoice_ids) + for invoice in invoices: + self.assertTrue(invoice.reference in ('456', '123')) + if invoice.reference == '123': + self.assertEqual( + invoice.invoice_line_ids[0].product_id.id, + self.headphones.product_variant_ids[0].id + ) + else: + for line in invoice.invoice_line_ids: + self.assertEqual( + line.product_id.id, + self.imac.product_variant_ids[0].id + ) + + # change Livello di dettaglio Fatture elettroniche to Minimo + partner.e_invoice_detail_level = '0' + res = self.run_wizard('test17', 'IT01234567890_FPR03.xml') + invoice_ids = res.get('domain')[0][2] + invoices = self.invoice_model.browse(invoice_ids) + self.assertTrue(len(invoices) == 2) + for invoice in invoices: + self.assertTrue(len(invoice.invoice_line_ids) == 0) diff --git a/l10n_it_fatturapa_in/views/account_view.xml b/l10n_it_fatturapa_in/views/account_view.xml index 5074a2a50ac5..9e230db3620a 100644 --- a/l10n_it_fatturapa_in/views/account_view.xml +++ b/l10n_it_fatturapa_in/views/account_view.xml @@ -1,147 +1,265 @@ - - + - - fatturapa.attachment.in.form - fatturapa.attachment.in - -
-
+ + fatturapa.attachment.in.form + fatturapa.attachment.in + + +
+ - + - - - - -
- on - -
+ + + + + -
-
- - -
- + + + + + + + + + + + + +
+
+ + +
+ +
+
+ + fatturapa.attachment.in.tree + fatturapa.attachment.in + + + + + + + + + + + + + fatturapa.attachment.in.search + fatturapa.attachment.in + + + + + + + + + Incoming Fattura Elettronica files + fatturapa.attachment.in + form + tree,form + {'search_default_to_register': True} + + + + + + account.invoice.line.fatturapa.in + account.invoice.line + + + + - - - fatturapa.attachment.in.tree - fatturapa.attachment.in - - - - - + + + + + account.invoice.fatturapa_in + account.invoice + + + + + + + + + - - - Incoming fatturaPA files - fatturapa.attachment.in - form - tree,form - - - - - - account.invoice.line.fatturapa.in - account.invoice.line - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + - + + + + + - - - + + + + - + +
+ + + + + + + + + + +
- - - + + + + - - + + + + + + -
-
-
- - - account.invoice.fatturapa_in - account.invoice - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -152,139 +270,73 @@ - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + -
-
-
+ + + + fatturapa.article.code.tree + fatturapa.article.code + + + + + + + + + discount.rise.price.tree + discount.rise.price + + + + + + + + + + einvoice.line.other.data.tree + einvoice.line.other.data + + + + + + + + + + diff --git a/l10n_it_fatturapa_in/views/company_view.xml b/l10n_it_fatturapa_in/views/company_view.xml new file mode 100644 index 000000000000..964a412864d0 --- /dev/null +++ b/l10n_it_fatturapa_in/views/company_view.xml @@ -0,0 +1,25 @@ + + + + + view_account_config_settings_ftpa_in + account.config.settings + + + +
+
+
+
+
+
+
+
+
+
diff --git a/l10n_it_fatturapa_in/views/partner_view.xml b/l10n_it_fatturapa_in/views/partner_view.xml index 171671e26fb4..81e10e2a3218 100644 --- a/l10n_it_fatturapa_in/views/partner_view.xml +++ b/l10n_it_fatturapa_in/views/partner_view.xml @@ -6,18 +6,20 @@ res.partner - - - - - - + + + + - - - + + + + + + + - + diff --git a/l10n_it_fatturapa_in/wizard/__init__.py b/l10n_it_fatturapa_in/wizard/__init__.py index a45fc832329f..313c912d6f15 100644 --- a/l10n_it_fatturapa_in/wizard/__init__.py +++ b/l10n_it_fatturapa_in/wizard/__init__.py @@ -1,22 +1,4 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 AgileBG SAGL -# Copyright (C) 2015 innoviu Srl -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## from . import wizard_import_fatturapa +from . import link_to_existing_invoice diff --git a/l10n_it_fatturapa_in/wizard/link_to_existing_invoice.py b/l10n_it_fatturapa_in/wizard/link_to_existing_invoice.py new file mode 100644 index 000000000000..879f7943e3fe --- /dev/null +++ b/l10n_it_fatturapa_in/wizard/link_to_existing_invoice.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +from odoo import models, api, fields +from odoo.tools.translate import _ +from odoo.exceptions import UserError + + +class WizardLinkToInvoice(models.TransientModel): + _name = "wizard.link.to.invoice" + _description = "Link to Supplier Invoice" + invoice_id = fields.Many2one( + 'account.invoice', string="Invoice", required=True) + + @api.multi + def link(self): + self.ensure_one() + active_ids = self.env.context.get('active_ids') + if len(active_ids) != 1: + raise UserError(_("You can select only 1 XML file to link")) + self.invoice_id.fatturapa_attachment_in_id = active_ids[0] diff --git a/l10n_it_fatturapa_in/wizard/link_to_existing_invoice.xml b/l10n_it_fatturapa_in/wizard/link_to_existing_invoice.xml new file mode 100644 index 000000000000..18509d0aea3e --- /dev/null +++ b/l10n_it_fatturapa_in/wizard/link_to_existing_invoice.xml @@ -0,0 +1,34 @@ + + + + + wizard_link_supplier_invoice + wizard.link.to.invoice + +
+ + + + +
+
+
+
+
+
+ + + +
diff --git a/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py b/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py index c252b594faf9..2045ba3528b7 100644 --- a/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py +++ b/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa.py @@ -1,99 +1,104 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2015 AgileBG SAGL -# Copyright (C) 2015 innoviu Srl -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## + import base64 -import os -import shlex -import subprocess -from openerp.osv import orm -from openerp.tools.translate import _ import logging +from odoo import models, api, fields +from odoo.tools import float_is_zero +from odoo.tools.translate import _ +from odoo.exceptions import UserError - -from openerp.addons.l10n_it_fatturapa.bindings import fatturapa_v_1_1 -from openerp.addons.base_iban import base_iban -from lxml import etree +from odoo.addons.l10n_it_fatturapa.bindings import fatturapa_v_1_2 +from odoo.addons.base_iban.models.res_partner_bank import pretty_iban _logger = logging.getLogger(__name__) -class WizardImportFatturapa(orm.TransientModel): +class WizardImportFatturapa(models.TransientModel): _name = "wizard.import.fatturapa" _description = "Import FatturaPA" - def saveAttachment(self, cr, uid, context=None): - if not context: - context = {} + e_invoice_detail_level = fields.Selection([ + ('0', 'Minimo'), + # ('1', 'Aliquote'), + ('2', 'Massimo'), + ], string="Livello di dettaglio Fatture elettroniche", + help="Livello minimo: La fattura passiva viene creata senza righe; " + "sara' l'utente a doverle creare in base a quanto indicato dal " + "fornitore nella fattura elettronica\n" + # "Livello Aliquote: viene creata una riga fattura per ogni " + # "aliquota presente nella fattura elettronica\n" + "Livello Massimo: tutte le righe presenti nella fattura " + "elettronica vengono create come righe della fattura passiva", + required=True + ) - return False + @api.model + def default_get(self, fields): + res = super(WizardImportFatturapa, self).default_get(fields) + res['e_invoice_detail_level'] = '2' + fatturapa_attachment_ids = self.env.context.get('active_ids', False) + fatturapa_attachment_obj = self.env['fatturapa.attachment.in'] + partners = self.env['res.partner'] + for fatturapa_attachment_id in fatturapa_attachment_ids: + fatturapa_attachment = fatturapa_attachment_obj.browse( + fatturapa_attachment_id) + if fatturapa_attachment.in_invoice_ids: + raise UserError( + _("File %s is linked to invoices yet") + % fatturapa_attachment.name) + partners |= fatturapa_attachment.xml_supplier_id + if len(partners) == 1: + res['e_invoice_detail_level'] = ( + partners[0].e_invoice_detail_level) + return res - def CountryByCode(self, cr, uid, CountryCode, context=None): - country_model = self.pool['res.country'] - return country_model.search( - cr, uid, [('code', '=', CountryCode)], context=context) + def CountryByCode(self, CountryCode): + country_model = self.env['res.country'] + return country_model.search([('code', '=', CountryCode)]) - def ProvinceByCode(self, cr, uid, provinceCode, context=None): - province_model = self.pool['res.province'] - return province_model.search( - cr, uid, [('code', '=', provinceCode)], context=context) + def ProvinceByCode(self, provinceCode): + province_model = self.env['res.country.state'] + return province_model.search([ + ('code', '=', provinceCode), + ('country_id.code', '=', 'IT') + ]) - def check_partner_base_data( - self, cr, uid, partner_id, DatiAnagrafici, context=None - ): - if context is None: - context = {} - partner = self.pool['res.partner'].browse( - cr, uid, partner_id, context=context) + def log_inconsistency(self, message): + inconsistencies = self.env.context.get('inconsistencies', '') + if inconsistencies: + inconsistencies += '\n' + inconsistencies += message + # we can't set + # self = self.with_context(inconsistencies=inconsistencies) + # because self is a locale variable. + # We use __dict__ to modify attributes of self + self.__dict__.update( + self.with_context(inconsistencies=inconsistencies).__dict__ + ) + + def check_partner_base_data(self, partner_id, DatiAnagrafici): + partner = self.env['res.partner'].browse(partner_id) if ( DatiAnagrafici.Anagrafica.Denominazione and partner.name != DatiAnagrafici.Anagrafica.Denominazione ): - if context.get('inconsistencies'): - context['inconsistencies'] += '\n' - context['inconsistencies'] += ( - _( - "DatiAnagrafici.Anagrafica.Denominazione contains \"%s\"." - " Your System contains \"%s\"" - ) - % (DatiAnagrafici.Anagrafica.Denominazione, partner.name) - ) + self.log_inconsistency(_( + "DatiAnagrafici.Anagrafica.Denominazione contains \"%s\"." + " Your System contains \"%s\"" + ) % (DatiAnagrafici.Anagrafica.Denominazione, partner.name)) if ( DatiAnagrafici.Anagrafica.Nome and partner.firstname != DatiAnagrafici.Anagrafica.Nome ): - if context.get('inconsistencies'): - context['inconsistencies'] += '\n' - context['inconsistencies'] += ( - _( - "DatiAnagrafici.Anagrafica.Nome contains \"%s\"." - " Your System contains \"%s\"" - ) - % (DatiAnagrafici.Anagrafica.Nome, partner.firstname) - ) + self.log_inconsistency(_( + "DatiAnagrafici.Anagrafica.Nome contains \"%s\"." + " Your System contains \"%s\"" + ) % (DatiAnagrafici.Anagrafica.Nome, partner.firstname)) if ( DatiAnagrafici.Anagrafica.Cognome and partner.lastname != DatiAnagrafici.Anagrafica.Cognome ): - if context.get('inconsistencies'): - context['inconsistencies'] += '\n' - context['inconsistencies'] += ( + self.log_inconsistency( _( "DatiAnagrafici.Anagrafica.Cognome contains \"%s\"." " Your System contains \"%s\"" @@ -101,10 +106,10 @@ def check_partner_base_data( % (DatiAnagrafici.Anagrafica.Cognome, partner.lastname) ) - def getPartnerBase(self, cr, uid, DatiAnagrafici, context=None): + def getPartnerBase(self, DatiAnagrafici): if not DatiAnagrafici: return False - partner_model = self.pool['res.partner'] + partner_model = self.env['res.partner'] cf = DatiAnagrafici.CodiceFiscale or False vat = False if DatiAnagrafici.IdFiscaleIVA: @@ -112,63 +117,37 @@ def getPartnerBase(self, cr, uid, DatiAnagrafici, context=None): DatiAnagrafici.IdFiscaleIVA.IdPaese, DatiAnagrafici.IdFiscaleIVA.IdCodice ) - partner_ids = partner_model.search( - cr, uid, - ['|', - ('vat', '=', vat or 0), - ('fiscalcode', '=', cf or 0), - ], - context=context) + partners = partner_model.search([ + '|', + ('vat', '=', vat or 0), + ('fiscalcode', '=', cf or 0), + ]) commercial_partner = False - if len(partner_ids) > 1: - for partner in partner_model.browse( - cr, uid, partner_ids, context=context - ): + if len(partners) > 1: + for partner in partners: if ( commercial_partner and partner.commercial_partner_id.id != commercial_partner ): - raise orm.except_orm( - _('Error !'), + raise UserError( _("Two distinct partners with " "Vat %s and Fiscalcode %s already present in db" % (vat, cf)) ) - commercial_partner = partner.commercial_partner_id.id - if not partner_ids: - if DatiAnagrafici.Anagrafica.Denominazione: - partner_ids = partner_model.search( - cr, uid, - [('name', '=', DatiAnagrafici.Anagrafica.Denominazione)], - context=context) - elif ( - DatiAnagrafici.Anagrafica.Nome and - DatiAnagrafici.Anagrafica.Cognome - ): - partner_ids = partner_model.search( - cr, uid, - [ - ('firstname', '=', DatiAnagrafici.Anagrafica.Nome), - ('lastname', '=', DatiAnagrafici.Anagrafica.Cognome), - ], - context=context) - if partner_ids: - commercial_partner = partner_ids[0] - self.check_partner_base_data( - cr, uid, commercial_partner, DatiAnagrafici, context=context) - return commercial_partner + if partners: + commercial_partner_id = partners[0].id + self.check_partner_base_data(commercial_partner_id, DatiAnagrafici) + return commercial_partner_id else: # partner to be created country_id = False if DatiAnagrafici.IdFiscaleIVA: CountryCode = DatiAnagrafici.IdFiscaleIVA.IdPaese - country_ids = self.CountryByCode( - cr, uid, CountryCode, context=context) - if country_ids: - country_id = country_ids[0] + countries = self.CountryByCode(CountryCode) + if countries: + country_id = countries[0].id else: - raise orm.except_orm( - _('Error !'), + raise UserError( _("Country Code %s not found in system") % CountryCode ) vals = { @@ -188,14 +167,12 @@ def getPartnerBase(self, cr, uid, DatiAnagrafici, context=None): if DatiAnagrafici.Anagrafica.Denominazione: vals['name'] = DatiAnagrafici.Anagrafica.Denominazione - return partner_model.create(cr, uid, vals, context=context) + return partner_model.create(vals).id - def getCedPrest(self, cr, uid, cedPrest, context=None): - partner_model = self.pool['res.partner'] - partner_id = self.getPartnerBase( - cr, uid, cedPrest.DatiAnagrafici, context=context) - fiscalPosModel = self.pool['fatturapa.fiscal_position'] - vals = {} + def getCedPrest(self, cedPrest): + partner_model = self.env['res.partner'] + partner_id = self.getPartnerBase(cedPrest.DatiAnagrafici) + fiscalPosModel = self.env['fatturapa.fiscal_position'] if partner_id: vals = { 'street': cedPrest.Sede.Indirizzo, @@ -205,15 +182,24 @@ def getCedPrest(self, cr, uid, cedPrest, context=None): } if cedPrest.DatiAnagrafici.ProvinciaAlbo: ProvinciaAlbo = cedPrest.DatiAnagrafici.ProvinciaAlbo - prov_ids = self.ProvinceByCode( - cr, uid, ProvinciaAlbo, context=context) - if not prov_ids: - raise orm.except_orm( - _('Error !'), - _('ProvinciaAlbo ( %s ) not present in system') % - ProvinciaAlbo - ) - vals['register_province'] = prov_ids[0] + prov = self.ProvinceByCode(ProvinciaAlbo) + if not prov: + self.log_inconsistency( + _('ProvinciaAlbo ( %s ) not present in system') + % ProvinciaAlbo + ) + else: + vals['register_province'] = prov[0].id + if cedPrest.Sede.Provincia: + Provincia = cedPrest.Sede.Provincia + prov_sede = self.ProvinceByCode(Provincia) + if not prov_sede: + self.log_inconsistency( + _('Provincia ( %s ) not present in system') + % Provincia + ) + else: + vals['state_id'] = prov_sede[0].id vals['register_code'] = ( cedPrest.DatiAnagrafici.NumeroIscrizioneAlbo) @@ -222,34 +208,31 @@ def getCedPrest(self, cr, uid, cedPrest, context=None): if cedPrest.DatiAnagrafici.RegimeFiscale: rfPos = cedPrest.DatiAnagrafici.RegimeFiscale - FiscalPosIds = fiscalPosModel.search( - cr, uid, - [('code', '=', rfPos)], - context=context + FiscalPos = fiscalPosModel.search( + [('code', '=', rfPos)] ) - if not FiscalPosIds: - raise orm.except_orm( - _('Error!'), + if not FiscalPos: + raise UserError( _('RegimeFiscale %s is not present in your system') % rfPos ) else: - vals['register_fiscalpos'] = FiscalPosIds[0] + vals['register_fiscalpos'] = FiscalPos[0].id if cedPrest.IscrizioneREA: REA = cedPrest.IscrizioneREA vals['rea_code'] = REA.NumeroREA - office_id = False - office_ids = self.ProvinceByCode( - cr, uid, REA.Ufficio, context=context) - if not office_ids: - raise orm.except_orm( - _('Error !'), - _('REA Office Code ( %s ) not present in system') % - REA.Ufficio - ) - office_id = office_ids[0] - vals['rea_office'] = office_id + offices = self.ProvinceByCode(REA.Ufficio) + if not offices: + self.log_inconsistency( + _( + 'REA Office (Province) Code ( %s ) not present in ' + 'system' + ) % REA.Ufficio + ) + else: + office_id = offices[0].id + vals['rea_office'] = office_id vals['rea_capital'] = REA.CapitaleSociale or 0.0 vals['rea_member_type'] = REA.SocioUnico or False vals['rea_liquidation_state'] = REA.StatoLiquidazione or False @@ -258,73 +241,61 @@ def getCedPrest(self, cr, uid, cedPrest, context=None): vals['phone'] = cedPrest.Contatti.Telefono vals['email'] = cedPrest.Contatti.Email vals['fax'] = cedPrest.Contatti.Fax - partner_model.write(cr, uid, partner_id, vals, context=context) + partner_model.browse(partner_id).write(vals) return partner_id - def getCarrirerPartner(self, cr, uid, Carrier, context=None): - partner_model = self.pool['res.partner'] - partner_id = self.getPartnerBase( - cr, uid, Carrier.DatiAnagraficiVettore, context=context) - vals = {} + def getCarrirerPartner(self, Carrier): + partner_model = self.env['res.partner'] + partner_id = self.getPartnerBase(Carrier.DatiAnagraficiVettore) if partner_id: vals = { 'license_number': Carrier.DatiAnagraficiVettore.NumeroLicenzaGuida or '', } - partner_model.write(cr, uid, partner_id, vals, context=context) + partner_model.browse(partner_id).write(vals) return partner_id - def _prepareInvoiceLine( - self, cr, uid, credit_account_id, line, context=None - ): - account_tax_model = self.pool['account.tax'] + def _prepare_generic_line_data(self, line): + retLine = {} + account_tax_model = self.env['account.tax'] # check if a default tax exists and generate def_purchase_tax object - ir_values = self.pool.get('ir.values') - company_id = self.pool.get('res.company')._company_default_get( - cr, uid, 'account.invoice.line', context=context - ) + ir_values = self.env['ir.values'] + company_id = self.env['res.company']._company_default_get( + 'account.invoice.line').id supplier_taxes_ids = ir_values.get_default( - cr, uid, 'product.product', 'supplier_taxes_id', - company_id=company_id - ) + 'product.product', 'supplier_taxes_id', company_id=company_id) def_purchase_tax = False if supplier_taxes_ids: - def_purchase_tax = account_tax_model.browse( - cr, uid, supplier_taxes_ids, context=context)[0] + def_purchase_tax = account_tax_model.browse(supplier_taxes_ids)[0] if float(line.AliquotaIVA) == 0.0 and line.Natura: - account_tax_ids = account_tax_model.search( - cr, uid, + account_taxes = account_tax_model.search( [ - ('type_tax_use', 'in', ('purchase', 'all')), - ('non_taxable_nature', '=', line.Natura), + ('type_tax_use', '=', 'purchase'), + ('kind_id.code', '=', line.Natura), ('amount', '=', 0.0), - ], context=context) - if not account_tax_ids: - raise orm.except_orm( - _('Error!'), + ]) + if not account_taxes: + raise UserError( _('No tax with percentage ' - '%s and nature %s found') + '%s and nature %s found. Please configure this tax') % (line.AliquotaIVA, line.Natura)) - if len(account_tax_ids) > 1: - raise orm.except_orm( - _('Error!'), + if len(account_taxes) > 1: + raise UserError( _('Too many taxes with percentage ' '%s and nature %s found') % (line.AliquotaIVA, line.Natura)) else: - account_tax_ids = account_tax_model.search( - cr, uid, + account_taxes = account_tax_model.search( [ - ('type_tax_use', 'in', ('purchase', 'all')), - ('amount', '=', float(line.AliquotaIVA) / 100), + ('type_tax_use', '=', 'purchase'), + ('amount', '=', float(line.AliquotaIVA)), ('price_include', '=', False), # partially deductible VAT must be set by user - ('child_ids', '=', False), - ], context=context) - if not account_tax_ids: - if context.get('inconsistencies'): - context['inconsistencies'] += '\n' - context['inconsistencies'] += ( + ('children_tax_ids', '=', False), + ] + ) + if not account_taxes: + self.log_inconsistency( _( 'XML contains tax with percentage "%s" ' 'but it does not exist in your system' @@ -332,7 +303,7 @@ def _prepareInvoiceLine( ) # check if there are multiple taxes with # same percentage - if len(account_tax_ids) > 1: + if len(account_taxes) > 1: # just logging because this is an usual case: see split payment _logger.warning(_( "Line '%s': Too many taxes with percentage equals " @@ -343,44 +314,93 @@ def _prepareInvoiceLine( # set taxes list equal to supplier_taxes_id, loaded before if ( def_purchase_tax and - def_purchase_tax.amount == (float(line.AliquotaIVA) / 100) + def_purchase_tax.amount == (float(line.AliquotaIVA)) ): - account_tax_ids = supplier_taxes_ids - retLine = { + account_taxes = def_purchase_tax + if account_taxes: + retLine['invoice_line_tax_ids'] = [(6, 0, [account_taxes[0].id])] + return retLine + + def get_line_product(self, line, partner): + product = None + supplier_info = self.env['product.supplierinfo'] + if len(line.CodiceArticolo) == 1: + supplier_code = line.CodiceArticolo[0].CodiceValore + supplier_infos = supplier_info.search([ + ('product_code', '=', supplier_code), + ('name', '=', partner.id) + ]) + if supplier_infos: + products = supplier_infos.mapped('product_id') + if len(products) == 1: + product = products[0] + else: + templates = supplier_infos.mapped('product_tmpl_id') + if len(templates) == 1: + product = templates.product_variant_ids[0] + if not product and partner.e_invoice_default_product_id: + product = partner.e_invoice_default_product_id + return product + + def adjust_accounting_data(self, product, line_vals): + if product.product_tmpl_id.property_account_expense_id: + line_vals['account_id'] = ( + product.product_tmpl_id.property_account_expense_id.id) + elif ( + product.product_tmpl_id.categ_id.property_account_expense_categ_id + ): + line_vals['account_id'] = ( + product.product_tmpl_id.categ_id. + property_account_expense_categ_id.id + ) + account = self.env['account.account'].browse(line_vals['account_id']) + new_tax = None + if len(product.product_tmpl_id.supplier_taxes_id) == 1: + new_tax = product.product_tmpl_id.supplier_taxes_id[0] + elif len(account.tax_ids) == 1: + new_tax = account.tax_ids[0] + if new_tax: + line_tax_id = ( + line_vals.get('invoice_line_tax_ids') and + line_vals['invoice_line_tax_ids'][0][2][0] + ) + line_tax = self.env['account.tax'].browse(line_tax_id) + if new_tax.id != line_tax_id: + if new_tax._get_tax_amount() != line_tax._get_tax_amount(): + self.log_inconsistency(_( + "XML contains tax %s. Product %s has tax %s. Using " + "the XML one" + ) % (line_tax.name, product.name, new_tax.name)) + else: + # If product has the same amount of the one in XML, + # I use it. Typical case: 22% det 50% + line_vals['invoice_line_tax_ids'] = [ + (6, 0, [new_tax.id])] + + def _prepareInvoiceLine(self, credit_account_id, line, wt_found=False): + retLine = self._prepare_generic_line_data(line) + retLine.update({ 'name': line.Descrizione, 'sequence': int(line.NumeroLinea), 'account_id': credit_account_id, - } - if account_tax_ids: - retLine['invoice_line_tax_id'] = [(6, 0, [account_tax_ids[0]])] + }) if line.PrezzoUnitario: retLine['price_unit'] = float(line.PrezzoUnitario) if line.Quantita: retLine['quantity'] = float(line.Quantita) - if line.TipoCessionePrestazione: - retLine['service_type'] = line.TipoCessionePrestazione - if line.TipoCessionePrestazione: - retLine['service_type'] = line.TipoCessionePrestazione - if line.UnitaMisura: - retLine['ftpa_uom'] = line.UnitaMisura - if line.DataInizioPeriodo: - retLine['service_start'] = line.DataInizioPeriodo - if line.DataFinePeriodo: - retLine['service_end'] = line.DataFinePeriodo if ( line.PrezzoTotale and line.PrezzoUnitario and line.Quantita and line.ScontoMaggiorazione ): - retLine['discount'] = self._computeDiscount( - cr, uid, line, context=context) + retLine['discount'] = self._computeDiscount(line) if line.RiferimentoAmministrazione: retLine['admin_ref'] = line.RiferimentoAmministrazione + if wt_found and line.Ritenuta: + retLine['invoice_line_tax_wt_ids'] = [(6, 0, [wt_found.id])] return retLine - def _prepareRelDocsLine( - self, cr, uid, invoice_id, line, type, context=None - ): + def _prepareRelDocsLine(self, invoice_id, line, type): res = [] lineref = line.RiferimentoNumeroLinea or False IdDoc = line.IdDocumento or 'Error' @@ -393,15 +413,14 @@ def _prepareRelDocsLine( if lineref: for numline in lineref: invoice_lineid = False - invoice_line_model = self.pool['account.invoice.line'] - invoice_line_ids = invoice_line_model.search( - cr, uid, + invoice_line_model = self.env['account.invoice.line'] + invoice_lines = invoice_line_model.search( [ ('invoice_id', '=', invoice_id), ('sequence', '=', int(numline)), - ], context=context) - if invoice_line_ids: - invoice_lineid = invoice_line_ids[0] + ]) + if invoice_lines: + invoice_lineid = invoice_lines[0].id val = { 'type': type, 'name': IdDoc, @@ -430,10 +449,7 @@ def _prepareRelDocsLine( res.append(val) return res - def _prepareWelfareLine( - self, cr, uid, invoice_id, line, context=None - ): - res = [] + def _prepareWelfareLine(self, invoice_id, line): TipoCassa = line.TipoCassa or False AlCassa = line.AlCassa and (float(line.AlCassa)/100) or None ImportoContributoCassa = ( @@ -445,17 +461,26 @@ def _prepareWelfareLine( line.AliquotaIVA and (float(line.AliquotaIVA)/100) or None) Ritenuta = line.Ritenuta or '' Natura = line.Natura or False + kind_id = False + if Natura: + kind = self.env['account.tax.kind'].search([ + ('code', '=', Natura) + ]) + if not kind: + self.log_inconsistency( + _("Tax kind %s not found") % Natura + ) + else: + kind_id = kind[0].id + RiferimentoAmministrazione = line.RiferimentoAmministrazione or '' - WelfareTypeModel = self.pool['welfare.fund.type'] + WelfareTypeModel = self.env['welfare.fund.type'] if not TipoCassa: - raise orm.except_orm( - _('Error!'), + raise UserError( _('TipoCassa is not defined ') ) - WelfareTypeId = WelfareTypeModel.search( - cr, uid, - [('name', '=', TipoCassa)], - context=context + WelfareType = WelfareTypeModel.search( + [('name', '=', TipoCassa)] ) res = { @@ -464,38 +489,32 @@ def _prepareWelfareLine( 'welfare_taxable': ImponibileCassa, 'welfare_Iva_tax': AliquotaIVA, 'subjected_withholding': Ritenuta, - 'fund_nature': Natura or False, + 'kind_id': kind_id, 'pa_line_code': RiferimentoAmministrazione, 'invoice_id': invoice_id, } - if not WelfareTypeId: - raise orm.except_orm( - _('Error'), + if not WelfareType: + raise UserError( _('TipoCassa %s is not present in your system') % TipoCassa) else: - res['name'] = WelfareTypeId[0] + res['name'] = WelfareType[0].id return res - def _prepareDiscRisePriceLine( - self, cr, uid, id, line, context=None - ): - res = [] + def _prepareDiscRisePriceLine(self, id, line): Tipo = line.Tipo or False Percentuale = line.Percentuale and float(line.Percentuale) or 0.0 Importo = line.Importo and float(line.Importo) or 0.0 res = { 'percentage': Percentuale, 'amount': Importo, - context.get('drtype'): id, + self.env.context.get('drtype'): id, } res['name'] = Tipo return res - def _computeDiscount( - self, cr, uid, DettaglioLinea, context=None - ): + def _computeDiscount(self, DettaglioLinea): line_total = float(DettaglioLinea.PrezzoTotale) line_unit = line_total / float(DettaglioLinea.Quantita) discount = ( @@ -503,14 +522,13 @@ def _computeDiscount( ) * 100.0 return discount - def _addGlobalDiscount( - self, cr, uid, invoice_id, DatiGeneraliDocumento, context=None - ): + def _addGlobalDiscount(self, invoice_id, DatiGeneraliDocumento): discount = 0.0 - if DatiGeneraliDocumento.ScontoMaggiorazione: - invoice = self.pool['account.invoice'].browse( - cr, uid, invoice_id, context=context) - invoice.button_compute(context=context, set_total=True) + if ( + DatiGeneraliDocumento.ScontoMaggiorazione and + self.e_invoice_detail_level == '2' + ): + invoice = self.env['account.invoice'].browse(invoice_id) for DiscRise in DatiGeneraliDocumento.ScontoMaggiorazione: if DiscRise.Percentuale: amount = ( @@ -525,8 +543,7 @@ def _addGlobalDiscount( discount -= float(DiscRise.Importo) elif DiscRise.Tipo == 'MG': discount += float(DiscRise.Importo) - journal = self.get_purchase_journal( - cr, uid, invoice.company_id, context=context) + journal = self.get_purchase_journal(invoice.company_id) credit_account_id = journal.default_credit_account_id.id line_vals = { 'invoice_id': invoice_id, @@ -536,29 +553,59 @@ def _addGlobalDiscount( 'price_unit': discount, 'quantity': 1, } - self.pool['account.invoice.line'].create( - cr, uid, line_vals, context=context) + if self.env.user.company_id.sconto_maggiorazione_product_id: + sconto_maggiorazione_product = ( + self.env.user.company_id.sconto_maggiorazione_product_id) + line_vals['product_id'] = sconto_maggiorazione_product.id + line_vals['name'] = sconto_maggiorazione_product.name + self.adjust_accounting_data( + sconto_maggiorazione_product, line_vals + ) + self.env['account.invoice.line'].create(line_vals) return True - def _createPayamentsLine( - self, cr, uid, payment_id, line, partner_id, - context=None - ): - PaymentModel = self.pool['fatturapa.payment.detail'] - PaymentMethodModel = self.pool['fatturapa.payment_method'] + def add_dati_bollo(self, invoice, DatiGeneraliDocumento): + # 2.1.1.6 + Stamps = DatiGeneraliDocumento.DatiBollo + if Stamps: + invoice.virtual_stamp = Stamps.BolloVirtuale + invoice.stamp_amount = float(Stamps.ImportoBollo) + if self.e_invoice_detail_level == '2': + journal = self.get_purchase_journal(invoice.company_id) + credit_account_id = journal.default_credit_account_id.id + line_vals = { + 'invoice_id': invoice.id, + 'name': _( + "Bollo assolto ai sensi del decreto MEF 17 giugno " + "2014 (art. 6)" + ), + 'account_id': credit_account_id, + 'price_unit': invoice.stamp_amount, + 'quantity': 1, + } + if self.env.user.company_id.dati_bollo_product_id: + dati_bollo_product = ( + self.env.user.company_id.dati_bollo_product_id) + line_vals['product_id'] = dati_bollo_product.id + line_vals['name'] = dati_bollo_product.name + self.adjust_accounting_data( + dati_bollo_product, line_vals + ) + self.env['account.invoice.line'].create(line_vals) + + def _createPayamentsLine(self, payment_id, line, partner_id): + PaymentModel = self.env['fatturapa.payment.detail'] + PaymentMethodModel = self.env['fatturapa.payment_method'] details = line.DettaglioPagamento or False if details: for dline in details: - BankModel = self.pool['res.bank'] - PartnerBankModel = self.pool['res.partner.bank'] - method_id = PaymentMethodModel.search( - cr, uid, - [('code', '=', dline.ModalitaPagamento)], - context=context + BankModel = self.env['res.bank'] + PartnerBankModel = self.env['res.partner.bank'] + method = PaymentMethodModel.search( + [('code', '=', dline.ModalitaPagamento)] ) - if not method_id: - raise orm.except_orm( - _('Error!'), + if not method: + raise UserError( _( 'ModalitaPagamento %s not defined in your system' % dline.ModalitaPagamento @@ -566,7 +613,7 @@ def _createPayamentsLine( ) val = { 'recipient': dline.Beneficiario, - 'fatturapa_pm_id': method_id[0], + 'fatturapa_pm_id': method[0].id, 'payment_term_start': dline.DataRiferimentoTerminiPagamento or False, 'payment_days': @@ -611,45 +658,36 @@ def _createPayamentsLine( bankid = False payment_bank_id = False if dline.BIC: - bankids = BankModel.search( - cr, uid, - [('bic', '=', dline.BIC.strip())], context=context + banks = BankModel.search( + [('bic', '=', dline.BIC.strip())] ) - if not bankids: + if not banks: if not dline.IstitutoFinanziario: - if context.get('inconsistencies'): - context['inconsistencies'] += '\n' - context['inconsistencies'] += ( + self.log_inconsistency( _("Name of Bank with BIC \"%s\" is not set." " Can't create bank") % dline.BIC ) else: bankid = BankModel.create( - cr, uid, { 'name': dline.IstitutoFinanziario, 'bic': dline.BIC, - }, - context=context - ) + } + ).id else: - bankid = bankids[0] + bankid = banks[0].id if dline.IBAN: SearchDom = [ - ('state', '=', 'iban'), ( 'acc_number', '=', - base_iban._pretty_iban(dline.IBAN.strip()) + pretty_iban(dline.IBAN.strip()) ), ('partner_id', '=', partner_id), ] payment_bank_id = False - payment_bank_ids = PartnerBankModel.search( - cr, uid, SearchDom, context=context) - if not payment_bank_ids and not bankid: - if context.get('inconsistencies'): - context['inconsistencies'] += '\n' - context['inconsistencies'] += ( + payment_banks = PartnerBankModel.search(SearchDom) + if not payment_banks and not bankid: + self.log_inconsistency( _( 'BIC is required and not exist in Xml\n' 'Curr bank data is: \n' @@ -661,93 +699,139 @@ def _createPayamentsLine( dline.IstitutoFinanziario or '' ) ) - - elif not payment_bank_ids and bankid: + elif not payment_banks and bankid: payment_bank_id = PartnerBankModel.create( - cr, uid, { - 'state': 'iban', 'acc_number': dline.IBAN.strip(), 'partner_id': partner_id, - 'bank': bankid, + 'bank_id': bankid, 'bank_name': dline.IstitutoFinanziario, 'bank_bic': dline.BIC - }, - context=context - ) - if payment_bank_ids: - payment_bank_id = payment_bank_ids[0] + } + ).id + if payment_banks: + payment_bank_id = payment_banks[0].id if payment_bank_id: val['payment_bank'] = payment_bank_id - PaymentModel.create(cr, uid, val, context=context) + PaymentModel.create(val) return True - def get_purchase_journal(self, cr, uid, company, context=None): - journal_model = self.pool['account.journal'] - journal_ids = journal_model.search( - cr, uid, + # TODO sul partner? + def set_StabileOrganizzazione(self, CedentePrestatore, invoice): + if CedentePrestatore.StabileOrganizzazione: + invoice.efatt_stabile_organizzazione_indirizzo = ( + CedentePrestatore.StabileOrganizzazione.Indirizzo) + invoice.efatt_stabile_organizzazione_civico = ( + CedentePrestatore.StabileOrganizzazione.NumeroCivico) + invoice.efatt_stabile_organizzazione_cap = ( + CedentePrestatore.StabileOrganizzazione.CAP) + invoice.efatt_stabile_organizzazione_comune = ( + CedentePrestatore.StabileOrganizzazione.Comune) + invoice.efatt_stabile_organizzazione_provincia = ( + CedentePrestatore.StabileOrganizzazione.Provincia) + invoice.efatt_stabile_organizzazione_nazione = ( + CedentePrestatore.StabileOrganizzazione.Nazione) + + def get_purchase_journal(self, company): + journal_model = self.env['account.journal'] + journals = journal_model.search( [ ('type', '=', 'purchase'), ('company_id', '=', company.id) ], - limit=1, context=context) - if not journal_ids: - raise orm.except_orm( - _('Error!'), + limit=1) + if not journals: + raise UserError( _( 'Define a purchase journal ' 'for this company: "%s" (id:%d).' ) % (company.name, company.id) ) - purchase_journal = journal_model.browse( - cr, uid, journal_ids[0], context=context) - return purchase_journal + return journals[0] + + def create_e_invoice_line(self, line): + vals = { + 'line_number': int(line.NumeroLinea or 0), + 'service_type': line.TipoCessionePrestazione, + 'name': line.Descrizione, + 'qty': float(line.Quantita or 0), + 'uom': line.UnitaMisura, + 'period_start_date': line.DataInizioPeriodo, + 'period_end_date': line.DataFinePeriodo, + 'unit_price': float(line.PrezzoUnitario or 0), + 'total_price': float(line.PrezzoTotale or 0), + 'tax_amount': float(line.AliquotaIVA or 0), + 'wt_amount': line.Ritenuta, + 'tax_kind': line.Natura, + 'admin_ref': line.RiferimentoAmministrazione, + } + einvoiceline = self.env['einvoice.line'].create(vals) + if line.CodiceArticolo: + for caline in line.CodiceArticolo: + self.env['fatturapa.article.code'].create( + { + 'name': caline.CodiceTipo or '', + 'code_val': caline.CodiceValore or '', + 'e_invoice_line_id': einvoiceline.id + } + ) + if line.ScontoMaggiorazione: + for DiscRisePriceLine in line.ScontoMaggiorazione: + DiscRisePriceVals = self.with_context( + drtype='e_invoice_line_id' + )._prepareDiscRisePriceLine( + einvoiceline.id, DiscRisePriceLine + ) + self.env['discount.rise.price'].create(DiscRisePriceVals) + if line.AltriDatiGestionali: + for dato in line.AltriDatiGestionali: + self.env['einvoice.line.other.data'].create( + { + 'name': dato.TipoDato, + 'text_ref': dato.RiferimentoTesto, + 'num_ref': float(dato.RiferimentoNumero or 0), + 'date_ref': dato.RiferimentoData, + 'e_invoice_line_id': einvoiceline.id + } + ) + return einvoiceline def invoiceCreate( - self, cr, uid, fatt, fatturapa_attachment, FatturaBody, - partner_id, context=None + self, fatt, fatturapa_attachment, FatturaBody, partner_id ): - if context is None: - context = {} - partner_model = self.pool['res.partner'] - invoice_model = self.pool['account.invoice'] - currency_model = self.pool['res.currency'] - invoice_line_model = self.pool['account.invoice.line'] - ftpa_doctype_poll = self.pool['fatturapa.document_type'] - rel_docs_model = self.pool['fatturapa.related_document_type'] - WelfareFundLineModel = self.pool['welfare.fund.data.line'] - DiscRisePriceModel = self.pool['discount.rise.price'] - SalModel = self.pool['faturapa.activity.progress'] - DdTModel = self.pool['fatturapa.related_ddt'] - PaymentDataModel = self.pool['fatturapa.payment.data'] - PaymentTermsModel = self.pool['fatturapa.payment_term'] - SummaryDatasModel = self.pool['faturapa.summary.data'] + partner_model = self.env['res.partner'] + invoice_model = self.env['account.invoice'] + currency_model = self.env['res.currency'] + invoice_line_model = self.env['account.invoice.line'] + ftpa_doctype_model = self.env['fiscal.document.type'] + rel_docs_model = self.env['fatturapa.related_document_type'] + WelfareFundLineModel = self.env['welfare.fund.data.line'] + SalModel = self.env['faturapa.activity.progress'] + DdTModel = self.env['fatturapa.related_ddt'] + PaymentDataModel = self.env['fatturapa.payment.data'] + PaymentTermsModel = self.env['fatturapa.payment_term'] + SummaryDatasModel = self.env['faturapa.summary.data'] - company = self.pool['res.users'].browse( - cr, uid, uid, context=context).company_id - partner = partner_model.browse(cr, uid, partner_id, context=context) - pay_acc_id = partner.property_account_payable.id + company = self.env.user.company_id + partner = partner_model.browse(partner_id) + pay_acc_id = partner.property_account_payable_id.id # currency 2.1.1.2 - currency_id = currency_model.search( - cr, uid, + currency = currency_model.search( [ ( 'name', '=', FatturaBody.DatiGenerali.DatiGeneraliDocumento.Divisa ) - ], - context=context) - if not currency_id: - raise orm.except_orm( - _('Error!'), + ]) + if not currency: + raise UserError( _( 'No currency found with code %s' % FatturaBody.DatiGenerali.DatiGeneraliDocumento.Divisa ) ) - purchase_journal = self.get_purchase_journal( - cr, uid, company, context=context) + purchase_journal = self.get_purchase_journal(company) credit_account_id = purchase_journal.default_credit_account_id.id invoice_lines = [] comment = '' @@ -756,179 +840,197 @@ def invoiceCreate( invtype = 'in_invoice' docType = FatturaBody.DatiGenerali.DatiGeneraliDocumento.TipoDocumento if docType: - docType_ids = ftpa_doctype_poll.search( - cr, uid, + docType_record = ftpa_doctype_model.search( [ ('code', '=', docType) - ], - context=context + ] ) - if docType_ids: - docType_id = docType_ids[0] + if docType_record: + docType_id = docType_record[0].id else: - raise orm.except_orm( - _("Error"), + raise UserError( _("tipoDocumento %s not handled") % docType) - if docType == 'TD04' or docType == 'TD05': + if docType == 'TD04': invtype = 'in_refund' # 2.1.1.11 causLst = FatturaBody.DatiGenerali.DatiGeneraliDocumento.Causale if causLst: for item in causLst: comment += item + '\n' - # 2.2.1 - CodeArts = self.pool['fatturapa.article.code'] - for line in FatturaBody.DatiBeniServizi.DettaglioLinee: - invoice_line_data = self._prepareInvoiceLine( - cr, uid, credit_account_id, line, context=context) - invoice_line_id = invoice_line_model.create( - cr, uid, invoice_line_data, context=context) - - if line.CodiceArticolo: - for caline in line.CodiceArticolo: - CodeArts.create( - cr, uid, - { - 'name': caline.CodiceTipo or '', - 'code_val': caline.CodiceValore or '', - 'invoice_line_id': invoice_line_id - }, - context=context - ) - if line.ScontoMaggiorazione: - context['drtype'] = 'invoice_line_id' - for DiscRisePriceLine in line.ScontoMaggiorazione: - DiscRisePriceVals = self._prepareDiscRisePriceLine( - cr, uid, invoice_line_id, DiscRisePriceLine, - context=context - ) - DiscRisePriceModel.create( - cr, uid, DiscRisePriceVals, context=context) - invoice_lines.append(invoice_line_id) invoice_data = { - 'doc_type': docType_id, + 'fiscal_document_type_id': docType_id, 'date_invoice': FatturaBody.DatiGenerali.DatiGeneraliDocumento.Data, - 'supplier_invoice_number': + 'reference': FatturaBody.DatiGenerali.DatiGeneraliDocumento.Numero, 'sender': fatt.FatturaElettronicaHeader.SoggettoEmittente or False, 'account_id': pay_acc_id, 'type': invtype, 'partner_id': partner_id, - 'currency_id': currency_id[0], + 'currency_id': currency[0].id, 'journal_id': purchase_journal.id, - 'invoice_line': [(6, 0, invoice_lines)], # 'origin': xmlData.datiOrdineAcquisto, - 'fiscal_position': False, - 'payment_term': False, + 'fiscal_position_id': False, + 'payment_term_id': False, 'company_id': company.id, 'fatturapa_attachment_in_id': fatturapa_attachment.id, 'comment': comment } + + # 2.1.1.10 + if FatturaBody.DatiGenerali.DatiGeneraliDocumento.Arrotondamento: + invoice_data['efatt_rounding'] = float( + FatturaBody.DatiGenerali.DatiGeneraliDocumento.Arrotondamento + ) + # 2.1.1.12 + if FatturaBody.DatiGenerali.DatiGeneraliDocumento.Art73: + invoice_data['art73'] = True + # 2.1.1.5 Withholding = FatturaBody.DatiGenerali.\ DatiGeneraliDocumento.DatiRitenuta + wt_found = None if Withholding: - invoice_data['withholding_amount'] = Withholding.ImportoRitenuta + wts = self.env['withholding.tax'].search([ + ('causale_pagamento_id.code', '=', + Withholding.CausalePagamento) + ]) + if not wts: + raise UserError(_( + "Supplier invoice contains withholding tax with " + "CausalePagamento %s, " + "but such a tax is not found in your system. Please " + "set it" + ) % Withholding.CausalePagamento) + wt_found = False + for wt in wts: + if wt.tax == float(Withholding.AliquotaRitenuta): + wt_found = wt + break + if not wt_found: + raise UserError(_( + "No withholding tax found with Causale %s and rate %s" + ) % ( + Withholding.CausalePagamento, Withholding.AliquotaRitenuta + )) invoice_data['ftpa_withholding_type'] = Withholding.TipoRitenuta - invoice_data['ftpa_withholding_rate'] = float( - Withholding.AliquotaRitenuta)/100 - invoice_data['ftpa_withholding_payment_reason'] = Withholding.\ - CausalePagamento - # 2.1.1.6 - Stamps = FatturaBody.DatiGenerali.\ - DatiGeneraliDocumento.DatiBollo - if Stamps: - invoice_data['virtual_stamp'] = Stamps.BolloVirtuale - invoice_data['stamp_amount'] = float(Stamps.ImportoBollo) - invoice_id = invoice_model.create( - cr, uid, invoice_data, context=context) + # 2.2.1 + e_invoice_line_ids = [] + for line in FatturaBody.DatiBeniServizi.DettaglioLinee: + if self.e_invoice_detail_level == '2': + invoice_line_data = self._prepareInvoiceLine( + credit_account_id, line, wt_found) + product = self.get_line_product(line, partner) + if product: + invoice_line_data['product_id'] = product.id + self.adjust_accounting_data(product, invoice_line_data) + invoice_line_id = invoice_line_model.create( + invoice_line_data).id + invoice_lines.append(invoice_line_id) + einvoiceline = self.create_e_invoice_line(line) + e_invoice_line_ids.append(einvoiceline.id) + invoice_data['invoice_line_ids'] = [(6, 0, invoice_lines)] + invoice_data['e_invoice_line_ids'] = [(6, 0, e_invoice_line_ids)] + invoice = invoice_model.create(invoice_data) + invoice._onchange_invoice_line_wt_ids() + invoice.write(invoice._convert_to_write(invoice._cache)) + invoice_id = invoice.id + + self.add_dati_bollo( + invoice, FatturaBody.DatiGenerali.DatiGeneraliDocumento) - invoice = invoice_model.browse(cr, uid, invoice_id, context=context) # 2.1.1.7 Walfares = FatturaBody.DatiGenerali.\ DatiGeneraliDocumento.DatiCassaPrevidenziale - if Walfares: + if Walfares and self.e_invoice_detail_level == '2': for walfareLine in Walfares: WalferLineVals = self._prepareWelfareLine( - cr, uid, invoice_id, walfareLine, context=context) - WelfareFundLineModel.create( - cr, uid, WalferLineVals, context=context) - # 2.1.1.8 - DiscountRises = FatturaBody.DatiGenerali.\ - DatiGeneraliDocumento.ScontoMaggiorazione - if DiscountRises: - context['drtype'] = 'invoice_id' - for DiscRisePriceLine in DiscountRises: - DiscRisePriceVals = self._prepareDiscRisePriceLine( - cr, uid, invoice_id, DiscRisePriceLine, context=context) - DiscRisePriceModel.create( - cr, uid, DiscRisePriceVals, context=context) + invoice_id, walfareLine) + WelfareFundLineModel.create(WalferLineVals) + line_vals = self._prepare_generic_line_data(walfareLine) + line_vals.update({ + 'name': _( + "Cassa Previdenziale: %s") % walfareLine.TipoCassa, + 'price_unit': float(walfareLine.ImportoContributoCassa), + 'invoice_id': invoice.id, + 'account_id': credit_account_id, + }) + if walfareLine.Ritenuta: + if not wt_found: + raise UserError(_( + "CassaPrevidenziale %s has Ritenuta but no " + "withholding tax was found in the system" + % walfareLine.TipoCassa)) + line_vals['invoice_line_tax_wt_ids'] = [ + (6, 0, [wt_found.id])] + if self.env.user.company_id.cassa_previdenziale_product_id: + cassa_previdenziale_product = ( + self.env.user.company_id. + cassa_previdenziale_product_id + ) + line_vals['product_id'] = cassa_previdenziale_product.id + line_vals['name'] = cassa_previdenziale_product.name + self.adjust_accounting_data( + cassa_previdenziale_product, line_vals + ) + self.env['account.invoice.line'].create(line_vals) # 2.1.2 relOrders = FatturaBody.DatiGenerali.DatiOrdineAcquisto if relOrders: for order in relOrders: doc_datas = self._prepareRelDocsLine( - cr, uid, invoice_id, order, 'order', context=context) + invoice_id, order, 'order') if doc_datas: for doc_data in doc_datas: - rel_docs_model.create( - cr, uid, doc_data, context=context) + rel_docs_model.create(doc_data) # 2.1.3 relContracts = FatturaBody.DatiGenerali.DatiContratto if relContracts: for contract in relContracts: doc_datas = self._prepareRelDocsLine( - cr, uid, invoice_id, contract, 'contract', context=context) + invoice_id, contract, 'contract') if doc_datas: for doc_data in doc_datas: - rel_docs_model.create( - cr, uid, doc_data, context=context) + rel_docs_model.create(doc_data) # 2.1.4 relAgreements = FatturaBody.DatiGenerali.DatiConvenzione if relAgreements: for agreement in relAgreements: doc_datas = self._prepareRelDocsLine( - cr, uid, invoice_id, agreement, - 'agreement', context=context) + invoice_id, agreement, 'agreement') if doc_datas: for doc_data in doc_datas: - rel_docs_model.create( - cr, uid, doc_data, context=context) + rel_docs_model.create(doc_data) # 2.1.5 relReceptions = FatturaBody.DatiGenerali.DatiRicezione if relReceptions: for reception in relReceptions: doc_datas = self._prepareRelDocsLine( - cr, uid, invoice_id, reception, - 'reception', context=context) + invoice_id, reception, 'reception') if doc_datas: for doc_data in doc_datas: - rel_docs_model.create( - cr, uid, doc_data, context=context) + rel_docs_model.create(doc_data) # 2.1.6 RelInvoices = FatturaBody.DatiGenerali.DatiFattureCollegate if RelInvoices: for invoice in RelInvoices: doc_datas = self._prepareRelDocsLine( - cr, uid, invoice_id, invoice, 'invoice', context=context) + invoice_id, invoice, 'invoice') if doc_datas: for doc_data in doc_datas: - rel_docs_model.create( - cr, uid, doc_data, context=context) + rel_docs_model.create(doc_data) # 2.1.7 SalDatas = FatturaBody.DatiGenerali.DatiSAL if SalDatas: for SalDataLine in SalDatas: SalModel.create( - cr, uid, { 'fatturapa_activity_progress': ( SalDataLine.RiferimentoFase or 0), 'invoice_id': invoice_id - }, context=context + } ) # 2.1.8 DdtDatas = FatturaBody.DatiGenerali.DatiDDT @@ -936,38 +1038,34 @@ def invoiceCreate( for DdtDataLine in DdtDatas: if not DdtDataLine.RiferimentoNumeroLinea: DdTModel.create( - cr, uid, { 'name': DdtDataLine.NumeroDDT or '', 'date': DdtDataLine.DataDDT or False, 'invoice_id': invoice_id - }, context=context + } ) else: for numline in DdtDataLine.RiferimentoNumeroLinea: - invoice_line_ids = invoice_line_model.search( - cr, uid, + invoice_lines = invoice_line_model.search( [ ('invoice_id', '=', invoice_id), ('sequence', '=', int(numline)), - ], context=context) + ]) invoice_lineid = False - if invoice_line_ids: - invoice_lineid = invoice_line_ids[0] + if invoice_lines: + invoice_lineid = invoice_lines[0].id DdTModel.create( - cr, uid, { 'name': DdtDataLine.NumeroDDT or '', 'date': DdtDataLine.DataDDT or False, 'invoice_id': invoice_id, 'invoice_line_id': invoice_lineid - }, context=context + } ) # 2.1.9 Delivery = FatturaBody.DatiGenerali.DatiTrasporto if Delivery: - delivery_id = self.getCarrirerPartner( - cr, uid, Delivery, context=context) + delivery_id = self.getCarrirerPartner(Delivery) delivery_dict = { 'carrier_id': delivery_id, 'transport_vehicle': Delivery.MezzoTrasporto or '', @@ -981,6 +1079,7 @@ def invoiceCreate( 'transport_date': Delivery.DataInizioTrasporto or False, 'delivery_datetime': Delivery.DataOraConsegna or False, 'delivery_address': '', + 'ftpa_incoterms': Delivery.TipoResa, } if Delivery.IndirizzoResa: @@ -994,16 +1093,7 @@ def invoiceCreate( Delivery.IndirizzoResa.Nazione or '' ) ) - if Delivery.TipoResa: - StockModel = self.pool['stock.incoterms'] - stock_incoterm_id = StockModel.search( - cr, uid, [('code', '=', Delivery.TipoResa)], - context=context - ) - if stock_incoterm_id: - delivery_dict['incoterm'] = stock_incoterm_id[0] - invoice_model.write( - cr, uid, invoice_id, delivery_dict, context=context) + invoice.write(delivery_dict) # 2.2.2 Summary_datas = FatturaBody.DatiBeniServizi.DatiRiepilogo if Summary_datas: @@ -1011,7 +1101,7 @@ def invoiceCreate( summary_line = { 'tax_rate': summary.AliquotaIVA or 0.0, 'non_taxable_nature': summary.Natura or False, - 'incidental charges': summary.SpeseAccessorie or 0.0, + 'incidental_charges': summary.SpeseAccessorie or 0.0, 'rounding': summary.Arrotondamento or 0.0, 'amount_untaxed': summary.ImponibileImporto or 0.0, 'amount_tax': summary.Imposta or 0.0, @@ -1019,8 +1109,7 @@ def invoiceCreate( 'law_reference': summary.RiferimentoNormativo or '', 'invoice_id': invoice_id, } - SummaryDatasModel.create( - cr, uid, summary_line, context=context) + SummaryDatasModel.create(summary_line) # 2.1.10 ParentInvoice = FatturaBody.DatiGenerali.FatturaPrincipale @@ -1031,8 +1120,7 @@ def invoiceCreate( 'related_invoice_date': ParentInvoice.DataFatturaPrincipale or False } - invoice_model.write( - cr, uid, invoice_id, parentinv_vals, context=context) + invoice.write(parentinv_vals) # 2.3 Vehicle = FatturaBody.DatiVeicoli if Vehicle: @@ -1040,52 +1128,40 @@ def invoiceCreate( 'vehicle_registration': Vehicle.Data or False, 'total_travel': Vehicle.TotalePercorso or '', } - invoice_model.write( - cr, uid, invoice_id, veicle_vals, context=context) + invoice.write(veicle_vals) # 2.4 PaymentsData = FatturaBody.DatiPagamento if PaymentsData: for PaymentLine in PaymentsData: cond = PaymentLine.CondizioniPagamento or False if not cond: - raise orm.except_orm( - _('Error!'), + raise UserError( _('Payment method Code not found in document') ) - term_id = False - term_ids = PaymentTermsModel.search( - cr, uid, [('code', '=', cond)], context=context) - if not term_ids: - raise orm.except_orm( - _('Error!'), + terms = PaymentTermsModel.search([('code', '=', cond)]) + if not terms: + raise UserError( _('Payment method Code %s is incorrect') % cond ) else: - term_id = term_ids[0] + term_id = terms[0].id PayDataId = PaymentDataModel.create( - cr, uid, { 'payment_terms': term_id, 'invoice_id': invoice_id - }, - context=context - ) - self._createPayamentsLine( - cr, uid, PayDataId, PaymentLine, partner_id, - context=context - ) + } + ).id + self._createPayamentsLine(PayDataId, PaymentLine, partner_id) # 2.5 AttachmentsData = FatturaBody.Allegati if AttachmentsData: - AttachModel = self.pool['fatturapa.attachments'] + AttachModel = self.env['fatturapa.attachments'] for attach in AttachmentsData: if not attach.NomeAttachment: - raise orm.except_orm( - _('Error!'), - _('Attachment Name is Required') - ) + name = _("Attachment without name") + else: + name = attach.NomeAttachment content = attach.Attachment - name = attach.NomeAttachment _attach_dict = { 'name': name, 'datas': base64.b64encode(str(content)), @@ -1095,50 +1171,22 @@ def invoiceCreate( 'format': attach.FormatoAttachment or '', 'invoice_id': invoice_id, } - AttachModel.create( - cr, uid, _attach_dict, context=context) + AttachModel.create(_attach_dict) self._addGlobalDiscount( - cr, uid, invoice_id, - FatturaBody.DatiGenerali.DatiGeneraliDocumento, context=context) + invoice_id, FatturaBody.DatiGenerali.DatiGeneraliDocumento) # compute the invoice - invoice_model.button_compute( - cr, uid, [invoice_id], context=context, - set_total=True) + invoice.compute_taxes() return invoice_id - def check_CessionarioCommittente( - self, cr, uid, company, FatturaElettronicaHeader, context=None - ): - if ( - company.partner_id.ipa_code != - FatturaElettronicaHeader.DatiTrasmissione.CodiceDestinatario - ): - raise orm.except_orm( - _('Error'), - _('XML IPA code (%s) different from company IPA code (%s)') - % ( - FatturaElettronicaHeader.DatiTrasmissione. - CodiceDestinatario, company.partner_id.ipa_code)) - - def compute_xml_amount_untaxed(self, cr, uid, DatiRiepilogo, context=None): + def compute_xml_amount_untaxed(self, DatiRiepilogo): amount_untaxed = 0.0 for Riepilogo in DatiRiepilogo: amount_untaxed += float(Riepilogo.ImponibileImporto) return amount_untaxed - def check_invoice_amount( - self, cr, uid, invoice, FatturaElettronicaBody, context=None - ): - if context is None: - context = {} - - invoice.write( - { - 'check_total': FatturaElettronicaBody.DatiGenerali. - DatiGeneraliDocumento.ImportoTotaleDocumento - }, context=context) + def check_invoice_amount(self, invoice, FatturaElettronicaBody): if ( FatturaElettronicaBody.DatiGenerali.DatiGeneraliDocumento. ScontoMaggiorazione and @@ -1151,10 +1199,10 @@ def check_invoice_amount( ImportoTotaleDocumento = float( FatturaElettronicaBody.DatiGenerali.DatiGeneraliDocumento. ImportoTotaleDocumento) - if invoice.amount_total != ImportoTotaleDocumento: - if context.get('inconsistencies'): - context['inconsistencies'] += '\n' - context['inconsistencies'] += ( + if not float_is_zero( + invoice.amount_total-ImportoTotaleDocumento, precision_digits=2 + ): + self.log_inconsistency( _('Invoice total %s is different from ' 'ImportoTotaleDocumento %s') % (invoice.amount_total, ImportoTotaleDocumento) @@ -1162,212 +1210,98 @@ def check_invoice_amount( else: # else, we can only check DatiRiepilogo if # DatiGeneraliDocumento.ScontoMaggiorazione is not present, - # because otherwise DatiRiepilogo and openerp invoice total would + # because otherwise DatiRiepilogo and odoo invoice total would # differ amount_untaxed = self.compute_xml_amount_untaxed( - cr, uid, - FatturaElettronicaBody.DatiBeniServizi.DatiRiepilogo, - context=context) - if invoice.amount_untaxed != amount_untaxed: - if context.get('inconsistencies'): - context['inconsistencies'] += '\n' - context['inconsistencies'] += ( + FatturaElettronicaBody.DatiBeniServizi.DatiRiepilogo) + if not float_is_zero( + invoice.amount_untaxed-amount_untaxed, precision_digits=2 + ): + self.log_inconsistency( _('Computed amount untaxed %s is different from' ' DatiRiepilogo %s') % (invoice.amount_untaxed, amount_untaxed) ) - def strip_xml_content(self, xml): - root = etree.XML(xml) - for elem in root.iter('*'): - if elem.text is not None: - elem.text = elem.text.strip() - return etree.tostring(root) - - def remove_xades_sign(self, xml): - root = etree.XML(xml) - for elem in root.iter('*'): - if elem.tag.find('Signature') > -1: - elem.getparent().remove(elem) - break - return etree.tostring(root) + def get_invoice_obj(self, fatturapa_attachment): + xml_string = fatturapa_attachment.get_xml_string() + return fatturapa_v_1_2.CreateFromDocument(xml_string) - def check_file_is_pem(self, p7m_file): - file_is_pem = True - strcmd = ( - 'openssl asn1parse -inform PEM -in %s' - ) % (p7m_file) - cmd = shlex.split(strcmd) - try: - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) - stdoutdata, stderrdata = proc.communicate() - if proc.wait() != 0: - file_is_pem = False - except Exception as e: - raise orm.except_orm( - _('Errore'), - _( - 'Check PEM file %s' - ) % e.args - ) - return file_is_pem - - def parse_pem_2_der(self, pem_file, tmp_der_file): - strcmd = ( - 'openssl asn1parse -in %s -out %s' - ) % (pem_file, tmp_der_file) - cmd = shlex.split(strcmd) - try: - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) - stdoutdata, stderrdata = proc.communicate() - if proc.wait() != 0: - _logger.warning(stdoutdata) - raise Exception(stderrdata) - except Exception as e: - raise orm.except_orm( - _('Errore'), - _( - 'Parsing PEM to DER file %s' - ) % e.args - ) - if not os.path.isfile(tmp_der_file): - raise orm.except_orm( - _('Errore'), - _( - 'ASN.1 structure is not parsable in DER' - ) - ) - return tmp_der_file - - def decrypt_to_xml(self, signed_file, xml_file): - strcmd = ( - 'openssl smime -decrypt -verify -inform' - ' DER -in %s -noverify -out %s' - ) % (signed_file, xml_file) - cmd = shlex.split(strcmd) - try: - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) - stdoutdata, stderrdata = proc.communicate() - if proc.wait() != 0: - _logger.warning(stdoutdata) - raise Exception(stderrdata) - except Exception as e: - raise orm.except_orm( - _('Errore'), - _( - 'Signed Xml file %s' - ) % e.args - ) - if not os.path.isfile(xml_file): - raise orm.except_orm( - _('Errore'), - _( - 'Signed Xml file not decryptable' - ) - ) - return xml_file - - def importFatturaPA(self, cr, uid, ids, context=None): - if not context: - context = {} - context['inconsistencies'] = '' - fatturapa_attachment_obj = self.pool['fatturapa.attachment.in'] - fatturapa_attachment_ids = context.get('active_ids', False) - invoice_model = self.pool['account.invoice'] + @api.multi + def importFatturaPA(self): + fatturapa_attachment_obj = self.env['fatturapa.attachment.in'] + fatturapa_attachment_ids = self.env.context.get('active_ids', False) + invoice_model = self.env['account.invoice'] new_invoices = [] for fatturapa_attachment_id in fatturapa_attachment_ids: - ctx = context.copy() + self.__dict__.update( + self.with_context(inconsistencies='').__dict__ + ) fatturapa_attachment = fatturapa_attachment_obj.browse( - cr, uid, fatturapa_attachment_id, context=ctx) + fatturapa_attachment_id) if fatturapa_attachment.in_invoice_ids: - raise orm.except_orm( - _("Error"), _("File is linked to invoices yet")) - # decrypt p7m file - if fatturapa_attachment.datas_fname.lower().endswith('.p7m'): - temp_file_name = ( - '/tmp/%s' % fatturapa_attachment.datas_fname.lower()) - temp_der_file_name = ( - '/tmp/%s_tmp' % fatturapa_attachment.datas_fname.lower()) - with open(temp_file_name, 'w') as p7m_file: - p7m_file.write(fatturapa_attachment.datas.decode('base64')) - xml_file_name = os.path.splitext(temp_file_name)[0] - - # check if temp_file_name is a PEM file - file_is_pem = self.check_file_is_pem(temp_file_name) - - # if temp_file_name is a PEM file - # parse it in a DER file - if file_is_pem: - temp_file_name = self.parse_pem_2_der( - temp_file_name, temp_der_file_name) - - # decrypt signed DER file in XML readable - xml_file_name = self.decrypt_to_xml( - temp_file_name, xml_file_name) - - with open(xml_file_name, 'r') as fatt_file: - file_content = fatt_file.read() - xml_string = file_content - elif fatturapa_attachment.datas_fname.lower().endswith('.xml'): - xml_string = fatturapa_attachment.datas.decode('base64') - xml_string = self.remove_xades_sign(xml_string) - xml_string = self.strip_xml_content(xml_string) - fatt = fatturapa_v_1_1.CreateFromDocument(xml_string) + raise UserError( + _("File is linked to invoices yet")) + fatt = self.get_invoice_obj(fatturapa_attachment) cedentePrestatore = fatt.FatturaElettronicaHeader.CedentePrestatore # 1.2 - partner_id = self.getCedPrest( - cr, uid, cedentePrestatore, context=ctx) + partner_id = self.getCedPrest(cedentePrestatore) # 1.3 TaxRappresentative = fatt.FatturaElettronicaHeader.\ RappresentanteFiscale # 1.5 Intermediary = fatt.FatturaElettronicaHeader.\ TerzoIntermediarioOSoggettoEmittente + + generic_inconsistencies = '' + if self.env.context.get('inconsistencies'): + generic_inconsistencies = ( + self.env.context['inconsistencies'] + '\n\n') + # 2 for fattura in fatt.FatturaElettronicaBody: + + # reset inconsistencies + self.__dict__.update( + self.with_context(inconsistencies='').__dict__ + ) + invoice_id = self.invoiceCreate( - cr, uid, fatt, fatturapa_attachment, fattura, - partner_id, context=ctx) + fatt, fatturapa_attachment, fattura, partner_id) + invoice = invoice_model.browse(invoice_id) + self.set_StabileOrganizzazione(cedentePrestatore, invoice) if TaxRappresentative: tax_partner_id = self.getPartnerBase( - cr, uid, TaxRappresentative.DatiAnagrafici, - context=ctx) - invoice_model.write( - cr, uid, invoice_id, + TaxRappresentative.DatiAnagrafici) + invoice.write( { 'tax_representative_id': tax_partner_id - }, context=ctx + } ) if Intermediary: Intermediary_id = self.getPartnerBase( - cr, uid, Intermediary.DatiAnagrafici, context=ctx) - invoice_model.write( - cr, uid, invoice_id, + Intermediary.DatiAnagrafici) + invoice.write( { 'intermediary': Intermediary_id - }, context=ctx + } ) new_invoices.append(invoice_id) - invoice = invoice_model.browse(cr, uid, invoice_id, ctx) - self.check_CessionarioCommittente( - cr, uid, invoice.company_id, fatt.FatturaElettronicaHeader, - context=ctx) - self.check_invoice_amount( - cr, uid, invoice, - fattura, - context=ctx) + self.check_invoice_amount(invoice, fattura) - if ctx.get('inconsistencies'): - invoice.write( - {'inconsistencies': ctx['inconsistencies']}, - context=ctx) + if self.env.context.get('inconsistencies'): + invoice_inconsistencies = ( + self.env.context['inconsistencies']) + else: + invoice_inconsistencies = '' + invoice.inconsistencies = ( + generic_inconsistencies + invoice_inconsistencies) return { 'view_type': 'form', - 'name': "PA Supplier Invoices", + 'name': "Supplier Electronic Invoices", 'view_mode': 'tree,form', 'res_model': 'account.invoice', 'type': 'ir.actions.act_window', 'domain': [('id', 'in', new_invoices)], - 'context': context } diff --git a/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa_view.xml b/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa_view.xml index ad207b533b44..37b90b8c86da 100644 --- a/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa_view.xml +++ b/l10n_it_fatturapa_in/wizard/wizard_import_fatturapa_view.xml @@ -1,27 +1,24 @@ - + - Import FatturaPA + Import Fattura Elettronica wizard.import.fatturapa -
- - - - - -