summaryrefslogtreecommitdiff
path: root/addons/l10n_it_edi_sdicoop
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/l10n_it_edi_sdicoop
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/l10n_it_edi_sdicoop')
-rw-r--r--addons/l10n_it_edi_sdicoop/__init__.py14
-rw-r--r--addons/l10n_it_edi_sdicoop/__manifest__.py26
-rw-r--r--addons/l10n_it_edi_sdicoop/data/cron.xml13
-rw-r--r--addons/l10n_it_edi_sdicoop/i18n_extra/l10n_it_edi_sdicoop.pot213
-rw-r--r--addons/l10n_it_edi_sdicoop/models/__init__.py6
-rw-r--r--addons/l10n_it_edi_sdicoop/models/account_edi_format.py281
-rw-r--r--addons/l10n_it_edi_sdicoop/models/account_invoice.py24
-rw-r--r--addons/l10n_it_edi_sdicoop/models/res_config_settings.py25
-rw-r--r--addons/l10n_it_edi_sdicoop/views/l10n_it_view.xml75
-rw-r--r--addons/l10n_it_edi_sdicoop/views/res_config_settings_views.xml45
10 files changed, 722 insertions, 0 deletions
diff --git a/addons/l10n_it_edi_sdicoop/__init__.py b/addons/l10n_it_edi_sdicoop/__init__.py
new file mode 100644
index 00000000..c1eff7ed
--- /dev/null
+++ b/addons/l10n_it_edi_sdicoop/__init__.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from . import models
+
+from odoo import api, SUPERUSER_ID
+
+
+def _disable_pec_mail_post_init(cr, registry):
+ ''' Pec mail cannot be used in conjunction with SdiCoop, so disable the Pec fetchmail servers.
+ '''
+ env = api.Environment(cr, SUPERUSER_ID, {})
+
+ env['fetchmail.server'].search([('l10n_it_is_pec', '=', True)]).l10n_it_is_pec = False
+ env['res.company'].search([('l10n_it_mail_pec_server_id', '!=', None)]).l10n_it_mail_pec_server_id = None
diff --git a/addons/l10n_it_edi_sdicoop/__manifest__.py b/addons/l10n_it_edi_sdicoop/__manifest__.py
new file mode 100644
index 00000000..7d2dc79a
--- /dev/null
+++ b/addons/l10n_it_edi_sdicoop/__manifest__.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+{
+ 'name': 'Italy - E-invoicing (SdiCoop)',
+ 'version': '0.3',
+ 'depends': [
+ 'l10n_it_edi',
+ 'account_edi_extended',
+ 'account_edi_proxy_client',
+ ],
+ 'author': 'Odoo',
+ 'description': """
+E-invoice implementation for Italy with the web-service. Ability to send and receive document from SdiCoop. Files sent by SdiCoop are first stored on the proxy
+and then fetched by this module.
+ """,
+ 'category': 'Accounting/Localizations/EDI',
+ 'website': 'http://www.odoo.com/',
+ 'data': [
+ 'data/cron.xml',
+ 'views/l10n_it_view.xml',
+ 'views/res_config_settings_views.xml',
+ ],
+ 'post_init_hook': '_disable_pec_mail_post_init',
+ 'license': 'LGPL-3',
+}
diff --git a/addons/l10n_it_edi_sdicoop/data/cron.xml b/addons/l10n_it_edi_sdicoop/data/cron.xml
new file mode 100644
index 00000000..0515ecef
--- /dev/null
+++ b/addons/l10n_it_edi_sdicoop/data/cron.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <record id="ir_cron_receive_fattura_pa_invoice" model="ir.cron">
+ <field name="name">FatturaPA: Receive invoices from the exchange system</field>
+ <field name="interval_number">1</field>
+ <field name="interval_type">days</field>
+ <field name="numbercall">-1</field>
+ <field name="model_id" ref="account_edi.model_account_edi_format"/>
+ <field name="code">model._cron_receive_fattura_pa()</field>
+ <field name="doall" eval="False"/>
+ <field name="state">code</field>
+ </record>
+</odoo>
diff --git a/addons/l10n_it_edi_sdicoop/i18n_extra/l10n_it_edi_sdicoop.pot b/addons/l10n_it_edi_sdicoop/i18n_extra/l10n_it_edi_sdicoop.pot
new file mode 100644
index 00000000..c06e62ee
--- /dev/null
+++ b/addons/l10n_it_edi_sdicoop/i18n_extra/l10n_it_edi_sdicoop.pot
@@ -0,0 +1,213 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_it_edi_sdicoop
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-06-03 13:44+0000\n"
+"PO-Revision-Date: 2021-06-03 13:44+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_it_edi_sdicoop
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi_sdicoop.res_config_settings_view_form
+msgid "<span class=\"o_form_label\">Allow Odoo to process invoices</span>"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi_sdicoop.res_config_settings_view_form
+msgid "Already registered"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid "Attached file is empty"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi_sdicoop.res_config_settings_view_form
+msgid ""
+"By clicking this button, I hereby accept that Odoo may process my invoices"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model:ir.model,name:l10n_it_edi_sdicoop.model_res_config_settings
+msgid "Config Settings"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_edi_format__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_move__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_res_config_settings__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model:ir.model,name:l10n_it_edi_sdicoop.model_account_edi_format
+msgid "EDI format"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi_sdicoop.res_config_settings_view_form
+msgid "Electronic Document Invoicing"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid "Expiration of the maximum term for communication of acceptance/refusal"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model:ir.actions.server,name:l10n_it_edi_sdicoop.ir_cron_receive_fattura_pa_invoice_ir_actions_server
+#: model:ir.cron,cron_name:l10n_it_edi_sdicoop.ir_cron_receive_fattura_pa_invoice
+#: model:ir.cron,name:l10n_it_edi_sdicoop.ir_cron_receive_fattura_pa_invoice
+msgid "FatturaPA: Receive invoices from the exchange system"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_edi_format__id
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_move__id
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_res_config_settings__id
+msgid "ID"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"Invoices for PA are not managed by Odoo, you can download the document and "
+"send it on your own."
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_res_config_settings__is_edi_proxy_active
+msgid "Is Edi Proxy Active"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid "Italian invoice: %s"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model:ir.model,name:l10n_it_edi_sdicoop.model_account_move
+msgid "Journal Entry"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_bank_statement_line__l10n_it_edi_attachment_id
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_move__l10n_it_edi_attachment_id
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_payment__l10n_it_edi_attachment_id
+msgid "L10N It Edi Attachment"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_bank_statement_line__l10n_it_edi_transaction
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_move__l10n_it_edi_transaction
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_payment__l10n_it_edi_transaction
+msgid "L10N It Edi Transaction"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_edi_format____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_account_move____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi_sdicoop.field_res_config_settings____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"Please fill your codice fiscale to be able to receive invoices from "
+"FatturaPA"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi_sdicoop.res_config_settings_view_form
+msgid "Register"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid "Service momentarily unavailable"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"The E-invoice is not delivered to the addressee. The Exchange System is"
+" unable to deliver the file to the Public Administration."
+" The Exchange System will contact the PA to report the "
+"problem and request that they provide a solution. During"
+" the following 15 days, the Exchange System will try to forward the "
+"FatturaPA file to the Administration in question again."
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid "The invoice has been refused by the Exchange System"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"The invoice has been succesfully transmitted. The addressee has 15 days to "
+"accept or reject it."
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid "The invoice was refused by the addressee."
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"The invoice was successfully transmitted to the Public Administration and we"
+" are waiting for confirmation"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"The invoice was successfully transmitted to the Public Administration and we"
+" are waiting for confirmation."
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid "Unauthorized user"
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid "You are not allowed to check the status of this invoice."
+msgstr ""
+
+#. module: l10n_it_edi_sdicoop
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi_sdicoop/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"You must accept the terms and conditions in the settings to use FatturaPA."
+msgstr ""
diff --git a/addons/l10n_it_edi_sdicoop/models/__init__.py b/addons/l10n_it_edi_sdicoop/models/__init__.py
new file mode 100644
index 00000000..b297cf8a
--- /dev/null
+++ b/addons/l10n_it_edi_sdicoop/models/__init__.py
@@ -0,0 +1,6 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import account_invoice
+from . import account_edi_format
+from . import res_config_settings
diff --git a/addons/l10n_it_edi_sdicoop/models/account_edi_format.py b/addons/l10n_it_edi_sdicoop/models/account_edi_format.py
new file mode 100644
index 00000000..95db0ada
--- /dev/null
+++ b/addons/l10n_it_edi_sdicoop/models/account_edi_format.py
@@ -0,0 +1,281 @@
+# -*- coding:utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models, _, _lt
+from odoo.exceptions import UserError
+from odoo.addons.account_edi_proxy_client.models.account_edi_proxy_user import AccountEdiProxyError, SERVER_URL
+
+from lxml import etree
+import base64
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class AccountEdiFormat(models.Model):
+ _inherit = 'account.edi.format'
+
+ # -------------------------------------------------------------------------
+ # Import
+ # -------------------------------------------------------------------------
+
+ def _cron_receive_fattura_pa(self):
+ ''' Check the proxy for incoming invoices.
+ '''
+ if self.env['ir.config_parameter'].get_param('account_edi_proxy_client.demo', False):
+ return
+
+ proxy_users = self.env['account_edi_proxy_client.user'].search([('edi_format_id', '=', self.env.ref('l10n_it_edi.edi_fatturaPA').id)])
+ for proxy_user in proxy_users:
+ company = proxy_user.company_id
+ try:
+ res = proxy_user._make_request(SERVER_URL + '/api/l10n_it_edi/1/in/RicezioneInvoice',
+ params={'recipient_codice_fiscale': company.l10n_it_codice_fiscale})
+ except AccountEdiProxyError as e:
+ _logger.error('Error while receiving file from SdiCoop: %s', e)
+
+ proxy_acks = []
+ for id_transaction, fattura in res.items():
+ if self.env['ir.attachment'].search([('name', '=', fattura['filename']), ('res_model', '=', 'account.move')], limit=1):
+ # name should be unique, the invoice already exists
+ _logger.info('E-invoice already exist: %s', fattura['filename'])
+ proxy_acks.append(id_transaction)
+ continue
+
+ file = proxy_user._decrypt_data(fattura['file'], fattura['key'])
+
+ try:
+ tree = etree.fromstring(file)
+ except Exception:
+ # should not happen as the file has been checked by SdiCoop
+ _logger.info('Received file badly formatted, skipping: \n %s', file)
+ continue
+
+ invoice = self.env.ref('l10n_it_edi.edi_fatturaPA')._create_invoice_from_xml_tree(fattura['filename'], tree)
+ self.env['ir.attachment'].create({
+ 'name': fattura['filename'],
+ 'raw': file,
+ 'type': 'binary',
+ 'res_model': 'account.move',
+ 'res_id': invoice.id
+ })
+
+ proxy_acks.append(id_transaction)
+
+ if proxy_acks:
+ try:
+ proxy_user._make_request(SERVER_URL + '/api/l10n_it_edi/1/ack',
+ params={'transaction_ids': proxy_acks})
+ except AccountEdiProxyError as e:
+ _logger.error('Error while receiving file from SdiCoop: %s', e)
+
+ # -------------------------------------------------------------------------
+ # Export
+ # -------------------------------------------------------------------------
+
+ def _check_move_configuration(self, move):
+ # OVERRIDE
+ res = super()._check_move_configuration(move)
+ if self.code != 'fattura_pa':
+ return res
+
+ res.extend(self._l10n_it_edi_check_invoice_configuration(move))
+
+ if not self._get_proxy_user(move.company_id):
+ res.append(_("You must accept the terms and conditions in the settings to use FatturaPA."))
+
+ return res
+
+ def _needs_web_services(self):
+ self.ensure_one()
+ return self.code == 'fattura_pa' or super()._needs_web_services()
+
+ def _l10n_it_edi_is_required_for_invoice(self, invoice):
+ """ _is_required_for_invoice for SdiCoop.
+ OVERRIDE
+ """
+ return invoice.is_sale_document() and invoice.country_code == 'IT'
+
+ def _support_batching(self, move=None, state=None, company=None):
+ # OVERRIDE
+ if self.code == 'fattura_pa':
+ return state == 'to_send' and move.is_invoice()
+
+ return super()._support_batching(move=move, state=state, company=company)
+
+ def _l10n_it_post_invoices_step_1(self, invoices):
+ ''' Send the invoices to the proxy.
+ '''
+ to_return = {}
+
+ to_send = {}
+ for invoice in invoices:
+ xml = b"<?xml version='1.0' encoding='UTF-8'?>" + invoice._export_as_xml()
+ filename = self._l10n_it_edi_generate_electronic_invoice_filename(invoice)
+ attachment = self.env['ir.attachment'].create({
+ 'name': filename,
+ 'res_id': invoice.id,
+ 'res_model': invoice._name,
+ 'datas': base64.encodebytes(xml),
+ 'description': _('Italian invoice: %s', invoice.move_type),
+ 'type': 'binary',
+ })
+ invoice.l10n_it_edi_attachment_id = attachment
+
+ if len(invoice.commercial_partner_id.l10n_it_pa_index or '') == 6:
+ invoice.message_post(
+ body=(_("Invoices for PA are not managed by Odoo, you can download the document and send it on your own."))
+ )
+ to_return[invoice] = {'attachment': attachment}
+ else:
+ to_send[filename] = {
+ 'invoice': invoice,
+ 'data': {'filename': filename, 'xml': base64.b64encode(xml)}}
+
+ company = invoices.company_id
+ proxy_user = self._get_proxy_user(company)
+ if not proxy_user: # proxy user should exist, because there is a check in _check_move_configuration
+ return {invoice: {
+ 'error': _("You must accept the terms and conditions in the settings to use FatturaPA."),
+ 'blocking_level': 'error'} for invoice in invoices}
+
+ if self.env['ir.config_parameter'].get_param('account_edi_proxy_client.demo', False):
+ responses = {filename: {'id_transaction': 'demo'} for invoice in invoices}
+ else:
+ try:
+ responses = self._l10n_it_edi_upload([i['data'] for i in to_send.values()], proxy_user)
+ except AccountEdiProxyError as e:
+ return {invoice: {'error': e.message, 'blocking_level': 'error'} for invoice in invoices}
+
+ for filename, response in responses.items():
+ invoice = to_send[filename]['invoice']
+ to_return[invoice] = response
+ if 'id_transaction' in response:
+ invoice.l10n_it_edi_transaction = response['id_transaction']
+ to_return[invoice].update({
+ 'error': _('The invoice was successfully transmitted to the Public Administration and we are waiting for confirmation.'),
+ 'blocking_level': 'info',
+ })
+ return to_return
+
+ def _l10n_it_post_invoices_step_2(self, invoices):
+ ''' Check if the sent invoices have been processed by FatturaPA.
+ '''
+ to_check = {i.l10n_it_edi_transaction: i for i in invoices}
+ to_return = {}
+ company = invoices.company_id
+ proxy_user = self._get_proxy_user(company)
+ if not proxy_user: # proxy user should exist, because there is a check in _check_move_configuration
+ return {invoice: {
+ 'error': _("You must accept the terms and conditions in the settings to use FatturaPA."),
+ 'blocking_level': 'error'} for invoice in invoices}
+
+ if self.env['ir.config_parameter'].get_param('account_edi_proxy_client.demo', False):
+ # simulate success and bypass ack
+ return {invoice: {'attachment': invoice.l10n_it_edi_attachment_id} for invoice in invoices}
+ else:
+ try:
+ responses = proxy_user._make_request(SERVER_URL + '/api/l10n_it_edi/1/in/TrasmissioneFatture',
+ params={'ids_transaction': list(to_check.keys())})
+ except AccountEdiProxyError as e:
+ return {invoice: {'error': e.message, 'blocking_level': 'error'} for invoice in invoices}
+
+ proxy_acks = []
+ for id_transaction, response in responses.items():
+ invoice = to_check[id_transaction]
+ if 'error' in response:
+ to_return[invoice] = response
+ continue
+
+ state = response['state']
+ if state == 'awaiting_outcome':
+ to_return[invoice] = {
+ 'error': _('The invoice was successfully transmitted to the Public Administration and we are waiting for confirmation'),
+ 'blocking_level': 'info',
+ }
+ proxy_acks.append(id_transaction)
+ continue
+ elif state == 'not_found':
+ # Invoice does not exist on proxy. Either it does not belong to this proxy_user or it was not created correctly when
+ # it was sent to the proxy.
+ to_return[invoice] = {'error': _('You are not allowed to check the status of this invoice.'), 'blocking_level': 'error'}
+ continue
+
+ xml = proxy_user._decrypt_data(response['file'], response['key'])
+ response_tree = etree.fromstring(xml)
+ if state == 'ricevutaConsegna':
+ to_return[invoice] = {'error': _('The invoice has been succesfully transmitted. The addressee has 15 days to accept or reject it.')}
+ elif state == 'notificaScarto':
+ errors = [element.find('Descrizione').text for element in response_tree.xpath('//Errore')]
+ to_return[invoice] = {'error': self._format_error_message(_('The invoice has been refused by the Exchange System'), errors), 'blocking_level': 'error'}
+ elif state == 'notificaMancataConsegna':
+ to_return[invoice] = {
+ 'error': _('The E-invoice is not delivered to the addressee. The Exchange System is\
+ unable to deliver the file to the Public Administration. The Exchange System will\
+ contact the PA to report the problem and request that they provide a solution. \
+ During the following 15 days, the Exchange System will try to forward the FatturaPA\
+ file to the Administration in question again.'),
+ }
+ elif state == 'notificaEsito':
+ outcome = response_tree.find('Esito').text
+ if outcome == 'EC01':
+ to_return[invoice] = {'attachment': invoice.l10n_it_edi_attachment_id}
+ else: # ECO2
+ to_return[invoice] = {'error': _('The invoice was refused by the addressee.'), 'blocking_level': 'error'}
+ elif state == 'NotificaDecorrenzaTermini':
+ to_return[invoice] = {'error': _('Expiration of the maximum term for communication of acceptance/refusal'), 'blocking_level': 'error'}
+ proxy_acks.append(id_transaction)
+
+ try:
+ proxy_user._make_request(SERVER_URL + '/api/l10n_it_edi/1/ack',
+ params={'transaction_ids': proxy_acks})
+ except AccountEdiProxyError as e:
+ # Will be ignored and acked again next time.
+ _logger.error('Error while acking file to SdiCoop: %s', e)
+
+ return to_return
+
+ def _post_fattura_pa(self, invoices):
+ # OVERRIDE
+ if not invoices.l10n_it_edi_transaction:
+ return self._l10n_it_post_invoices_step_1(invoices)
+ else:
+ return self._l10n_it_post_invoices_step_2(invoices)
+
+ # -------------------------------------------------------------------------
+ # Proxy methods
+ # -------------------------------------------------------------------------
+
+ def _get_proxy_identification(self, company):
+ if self.code != 'fattura_pa':
+ return super()._get_proxy_identification()
+
+ if not company.l10n_it_codice_fiscale:
+ raise UserError(_('Please fill your codice fiscale to be able to receive invoices from FatturaPA'))
+
+ return self.env['res.partner']._l10n_it_normalize_codice_fiscale(company.l10n_it_codice_fiscale)
+
+ def _l10n_it_edi_upload(self, files, proxy_user):
+ '''Upload files to fatturapa.
+
+ :param files: A list of dictionary {filename, base64_xml}.
+ :returns: A dictionary.
+ * message: Message from fatturapa.
+ * transactionId: The fatturapa ID of this request.
+ * error: An eventual error.
+ * error_level: Info, warning, error.
+ '''
+ ERRORS = {
+ 'EI01': {'error': _lt('Attached file is empty'), 'blocking_level': 'error'},
+ 'EI02': {'error': _lt('Service momentarily unavailable'), 'blocking_level': 'warning'},
+ 'EI03': {'error': _lt('Unauthorized user'), 'blocking_level': 'error'},
+ }
+
+ result = proxy_user._make_request(SERVER_URL + '/api/l10n_it_edi/1/out/SdiRiceviFile', params={'files': files})
+
+ # Translate the errors.
+ for filename in result.keys():
+ if 'error' in result[filename]:
+ result[filename] = ERRORS.get(result[filename]['error'], {'error': result[filename]['error'], 'blocking_level': 'error'})
+
+ return result
diff --git a/addons/l10n_it_edi_sdicoop/models/account_invoice.py b/addons/l10n_it_edi_sdicoop/models/account_invoice.py
new file mode 100644
index 00000000..4221dbc0
--- /dev/null
+++ b/addons/l10n_it_edi_sdicoop/models/account_invoice.py
@@ -0,0 +1,24 @@
+# -*- coding:utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+import logging
+
+from odoo import fields, models
+
+
+_logger = logging.getLogger(__name__)
+
+DEFAULT_FACTUR_ITALIAN_DATE_FORMAT = '%Y-%m-%d'
+
+
+class AccountMove(models.Model):
+ _inherit = 'account.move'
+
+ l10n_it_edi_transaction = fields.Char(copy=False)
+ l10n_it_edi_attachment_id = fields.Many2one('ir.attachment', copy=False)
+
+ def send_pec_mail(self):
+ self.ensure_one()
+ # OVERRIDE
+ # With SdiCoop web-service, no need to send PEC mail.
+ # Set the state to 'other' because the invoice should not be managed par l10n_it_edi.
+ self.l10n_it_send_state = 'other'
diff --git a/addons/l10n_it_edi_sdicoop/models/res_config_settings.py b/addons/l10n_it_edi_sdicoop/models/res_config_settings.py
new file mode 100644
index 00000000..04d78743
--- /dev/null
+++ b/addons/l10n_it_edi_sdicoop/models/res_config_settings.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+
+from odoo import api, models, fields
+
+
+class ResConfigSettings(models.TransientModel):
+ _inherit = 'res.config.settings'
+
+ is_edi_proxy_active = fields.Boolean(compute='_compute_is_edi_proxy_active')
+
+ @api.depends('company_id.account_edi_proxy_client_ids', 'company_id.account_edi_proxy_client_ids.active')
+ def _compute_is_edi_proxy_active(self):
+ for config in self:
+ config.is_edi_proxy_active = config.company_id.account_edi_proxy_client_ids
+
+ def button_create_proxy_user(self):
+ # For now, only fattura_pa uses the proxy.
+ # To use it for more, we have to either make the activation of the proxy on a format basis
+ # or create a user per format here (but also when installing new formats)
+ fattura_pa = self.env.ref('l10n_it_edi.edi_fatturaPA')
+ edi_identification = fattura_pa._get_proxy_identification(self.company_id)
+ if not edi_identification:
+ return
+
+ self.env['account_edi_proxy_client.user']._register_proxy_user(self.company_id, fattura_pa, edi_identification)
diff --git a/addons/l10n_it_edi_sdicoop/views/l10n_it_view.xml b/addons/l10n_it_edi_sdicoop/views/l10n_it_view.xml
new file mode 100644
index 00000000..40ea1041
--- /dev/null
+++ b/addons/l10n_it_edi_sdicoop/views/l10n_it_view.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <record id="fetchmail_server_form_l10n_it_inherit" model="ir.ui.view">
+ <field name="name">fetchmail.server.form.l10n.it.inherit</field>
+ <field name="model">fetchmail.server</field>
+ <field name="priority">30</field>
+ <field name="inherit_id" ref="l10n_it_edi.fetchmail_server_form_l10n_it"/>
+ <field name="arch" type="xml">
+ <data>
+ <xpath expr="//field[@name='l10n_it_is_pec']" position="replace" />
+ </data>
+ </field>
+ </record>
+
+ <record id="res_company_form_l10n_it_inherit" model="ir.ui.view">
+ <field name="name">res.company.form.l10n.it.inherit</field>
+ <field name="model">res.company</field>
+ <field name="priority">30</field>
+ <field name="inherit_id" ref="l10n_it_edi.res_company_form_l10n_it"/>
+ <field name="arch" type="xml">
+ <data>
+ <xpath expr="//field[@name='l10n_it_mail_pec_server_id']" position="replace"/>
+ <xpath expr="//field[@name='l10n_it_address_send_fatturapa']" position="replace"/>
+ <xpath expr="//field[@name='l10n_it_address_recipient_fatturapa']" position="replace"/>
+ </data>
+ </field>
+ </record>
+
+ <record id="l10n_it_edi.invoice_supplier_tree_l10n_it" model="ir.ui.view">
+ <field name="arch" type="xml">
+ <!-- Remove the l10n_state_it field. Doing so
+ with xpath might replace other view elements that we shouldn't remove.-->
+ <data/>
+ </field>
+ </record>
+
+ <record id="l10n_it_edi.invoice_kanban_l10n_it" model="ir.ui.view">
+ <field name="arch" type="xml">
+ <!-- Remove the l10n_state_it field. Doing so
+ with xpath might replace other view elements that we shouldn't remove.-->
+ <data/>
+ </field>
+ </record>
+
+ <record id="l10n_it_edi.account_invoice_form_l10n_it" model="ir.ui.view">
+ <field name="arch" type="xml">
+ <!-- Remove the l10n_state_it field but keep other info tab.
+ Doing so with xpath might repace other view elements that we shouldn't remove. -->
+ <data>
+ <xpath expr="//page[@name='other_info']" position="after">
+ <page string="Electronic Invoicing"
+ name="electronic_invoicing"
+ attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund'))]}">
+ <group>
+ <group>
+ <field name="l10n_it_stamp_duty"/>
+ <field name="l10n_it_ddt_id"
+ attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
+ </group>
+ </group>
+ </page>
+ </xpath>
+ </data>
+ </field>
+ </record>
+
+
+ <record id="l10n_it_edi.view_account_invoice_filter_l10n_it" model="ir.ui.view">
+ <field name="arch" type="xml">
+ <!-- Remove the filters.-->
+ <data />
+ </field>
+ </record>
+
+</odoo>
diff --git a/addons/l10n_it_edi_sdicoop/views/res_config_settings_views.xml b/addons/l10n_it_edi_sdicoop/views/res_config_settings_views.xml
new file mode 100644
index 00000000..3929c555
--- /dev/null
+++ b/addons/l10n_it_edi_sdicoop/views/res_config_settings_views.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+
+ <record id="res_config_settings_view_form" model="ir.ui.view">
+ <field name="name">res.config.settings.view.form.inherit.proxy.user</field>
+ <field name="model">res.config.settings</field>
+ <field name="inherit_id" ref="account.res_config_settings_view_form"/>
+ <field name="arch" type="xml">
+ <xpath expr="//div[@id='account_vendor_bills']" position="after">
+ <div attrs="{'invisible':[('country_code', '!=', 'IT')]}">
+ <h2>Electronic Document Invoicing</h2>
+ <div class="row mt16 o_settings_container" id='account_edi'>
+ <div class="col-12 col-lg-6 o_setting_box">
+ <div class="o_setting_right_pane">
+ <span class="o_form_label">Allow Odoo to process invoices</span>
+ <div class="text-muted">
+ By clicking this button, I accept that Odoo may process my invoices.
+ </div>
+ <div class="content-group">
+ <field name="is_edi_proxy_active" invisible="True" />
+ <div class="row mt8">
+ <div class="col-lg-6" title="Register">
+ <button name="button_create_proxy_user"
+ type="object"
+ string="Register"
+ class="btn-primary" icon="fa-lg fa-check"
+ attrs="{'invisible':[('is_edi_proxy_active', '=', True)]}"/>
+ <button name="button_create_proxy_user"
+ type="object"
+ string="Already registered"
+ disabled="1"
+ class="btn-lnk" icon="fa-lg fa-check"
+ attrs="{'invisible':[('is_edi_proxy_active', '=', False)]}"/>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </xpath>
+ </field>
+ </record>
+
+</odoo>