Skip to content

Commit

Permalink
ADD backport from 10.0 of l10n_it_sdi_channel
Browse files Browse the repository at this point in the history
ADD backport from 10.0 of l10n_it_fatturapa_pec
  • Loading branch information
Andrea Colangelo authored and eLBati committed Dec 6, 2018
1 parent 57c8bfd commit 6e1e80d
Show file tree
Hide file tree
Showing 35 changed files with 1,994 additions and 0 deletions.
91 changes: 91 additions & 0 deletions l10n_it_fatturapa_pec/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
=========================================================
Italian Localization - FatturaPA - Emission - PEC Support
=========================================================

.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! 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_pec
: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_pec
: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 you to send and receive electronic invoice XML file version 1.2
http://www.fatturapa.gov.it/export/fatturazione/en/sdi.htm
via PEC

Notifications from SDI are parsed and transmission state is tracked.

**Table of contents**

.. contents::
:local:

Configuration
=============

See `l10n_it_sdi_channel` module

Usage
=====

In electronic invoice out attachment you can click "Send Via PEC" button.

Supplier electronic invoices are automatically created, fetched from PEC mailbox.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/l10n-italy/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 <https://github.com/OCA/l10n-italy/issues/new?body=module:%20l10n_it_fatturapa_pec%0Aversion:%2010.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
~~~~~~~

* Openforce Srls Unipersonale

Contributors
~~~~~~~~~~~~

* Andrea Colangelo <andreacolangelo@openforce.it>
* Sergio Corato <info@efatto.it>
* Lorenzo Battistini <https://github.com/eLBati>

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 <https://github.com/OCA/l10n-italy/tree/10.0/l10n_it_fatturapa_pec>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
4 changes: 4 additions & 0 deletions l10n_it_fatturapa_pec/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import models
26 changes: 26 additions & 0 deletions l10n_it_fatturapa_pec/__openerp__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Author(s): Andrea Colangelo (andreacolangelo@openforce.it)
# Copyright 2018 Openforce Srls Unipersonale (www.openforce.it)
# Copyright 2018 Sergio Corato (https://efatto.it)
# Copyright 2018 Lorenzo Battistini <https://github.com/eLBati>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
'name': 'Italian Localization - FatturaPA - Emission - PEC Support',
'version': '10.0.1.0.0',
'category': 'Localization/Italy',
'summary': 'Send electronic invoices via PEC',
'author': 'Openforce Srls Unipersonale, Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/l10n-italy',
'license': 'LGPL-3',
'depends': [
'fetchmail',
'l10n_it_fatturapa_out',
# 'l10n_it_fatturapa_in', Enable this dep as soon as the module is ready
'l10n_it_sdi_channel',
],
'data': [
'views/account.xml',
'views/fatturapa_attachment_out.xml',
],
'installable': True
}
6 changes: 6 additions & 0 deletions l10n_it_fatturapa_pec/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import account
from . import fatturapa_attachment_out
from . import mail_thread
36 changes: 36 additions & 0 deletions l10n_it_fatturapa_pec/models/account.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
# Author(s): Andrea Colangelo (andreacolangelo@openforce.it)
# Copyright © 2018 Openforce Srls Unipersonale (www.openforce.it)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).


from openerp import api, fields, models


class AccountInvoice(models.Model):
_inherit = 'account.invoice'

fatturapa_state = fields.Selection(
[('ready', 'Ready to Send'),
('sent', 'Sent'),
('delivered', 'Delivered'),
('error', 'Error')],
string='E-invoice State',
compute='compute_fatturapa_state',
store='true',
)

@api.multi
@api.depends('fatturapa_attachment_out_id.state')
def compute_fatturapa_state(self):
mapping = {
'ready': 'ready',
'sent': 'sent',
'validated': 'delivered',
'sender_error': 'error',
'recipient_error': 'error',
'rejected': 'error'
}
for record in self:
record.fatturapa_state = \
mapping.get(record.fatturapa_attachment_out_id.state)
183 changes: 183 additions & 0 deletions l10n_it_fatturapa_pec/models/fatturapa_attachment_out.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# -*- coding: utf-8 -*-
# Author(s): Andrea Colangelo (andreacolangelo@openforce.it)
# Copyright © 2018 Openforce Srls Unipersonale (www.openforce.it)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import logging
import re

from lxml import etree

from openerp import api, fields, models

_logger = logging.getLogger(__name__)

RESPONSE_MAIL_REGEX = '[A-Z]{2}[a-zA-Z0-9]{11,16}_[a-zA-Z0-9]{,5}_[A-Z]{2}_' \
'[a-zA-Z0-9]{,3}'


class FatturaPAAttachmentOut(models.Model):
_inherit = 'fatturapa.attachment.out'

state = fields.Selection([('ready', 'Ready to Send'),
('sent', 'Sent'),
('validated', 'Delivered'),
('sender_error', 'Sender Error'),
('recipient_error', 'Recipient Error'),
('rejected', 'Rejected (PA)')],
string='State',
default='ready',)

last_sdi_response = fields.Text(
string='Last Response from Exchange System', default='No response yet')

@api.multi
def send_via_pec(self):
self.ensure_one()
mail_message = self.env['mail.message'].create({
'model': self._name,
'res_id': self.id,
'subject': self.name,
'body': 'XML file for FatturaPA {} sent to Exchange System to the'
' email address {}.'
.format(
self.name,
self.env.user.company_id.email_exchange_system),
'attachment_ids': [(6, 0, self.ir_attachment_id.ids)],
'email_from': self.env.user.company_id.email_from_for_fatturaPA,
'mail_server_id': self.env.user.company_id.sdi_channel_id.
pec_server_id.id,
})
mail = self.env['mail.mail'].create({
'mail_message_id': mail_message.id,
'body_html': mail_message.body,
'email_to': self.env.user.company_id.email_exchange_system,
})

if mail:
res = mail.send(raise_exception=True)

if res:
self.state = 'sent'

@api.multi
def parse_pec_response(self, message_dict):
message_dict['model'] = self._name
message_dict['res_id'] = 0

regex = re.compile(RESPONSE_MAIL_REGEX)
attachments = [x for x in message_dict['attachments']
if regex.match(x.fname)]

for attachment in attachments:
response_name = attachment.fname
message_type = response_name.split('_')[2]
if attachment.fname.lower().endswith('.zip'):
# not implemented, case of AT, todo
continue
root = etree.fromstring(attachment.content)
file_name = root.find('NomeFile')
fatturapa_attachment_out = False

if file_name is not None:
file_name = file_name.text
fatturapa_attachment_out = self.search(
['|',
('datas_fname', '=', file_name),
('datas_fname', '=', file_name.replace('.p7m', ''))])
if len(fatturapa_attachment_out) > 1:
_logger.info('More than 1 out invoice found for incoming'
'message')
fatturapa_attachment_out = fatturapa_attachment_out[0]
if not fatturapa_attachment_out:
if message_type == 'MT': # Metadati
# out invoice not found, so it is an incoming invoice
return message_dict
else:
_logger.info('Error: FatturaPA {} not found.'.format(
file_name))
# TODO Send a mail warning
return message_dict

if fatturapa_attachment_out:
id_sdi = root.find('IdentificativoSdI')
receipt_dt = root.find('DataOraRicezione')
message_id = root.find('MessageId')
id_sdi = id_sdi.text if id_sdi is not None else False
receipt_dt = receipt_dt.text if receipt_dt is not None \
else False
message_id = message_id.text if message_id is not None \
else False
if message_type == 'NS': # 2A. Notifica di Scarto
error_list = root.find('ListaErrori').text
fatturapa_attachment_out.write({
'state': 'sender_error',
'last_sdi_response': 'SdI ID: {}; '
'Message ID: {}; Receipt date: {}; '
'Error: {}'.format(
id_sdi, message_id, receipt_dt, error_list)
})
elif message_type == 'MC': # 3A. Mancata consegna
missed_delivery_note = root.find('Descrizione').text
fatturapa_attachment_out.write({
'state': 'recipient_error',
'last_sdi_response': 'SdI ID: {}; '
'Message ID: {}; Receipt date: {}; '
'Missed delivery note: {}'.format(
id_sdi, message_id, receipt_dt,
missed_delivery_note)
})
elif message_type == 'RC': # 3B. Ricevuta di Consegna
delivery_dt = root.find('DataOraConsegna').text
fatturapa_attachment_out.write({
'state': 'validated',
'last_sdi_response': 'SdI ID: {}; '
'Message ID: {}; Receipt date: {}; '
'Delivery date: {}'.format(
id_sdi, message_id, receipt_dt, delivery_dt)
})
elif message_type == 'NE': # 4A. Notifica Esito per PA
esito_committente = root.find('EsitoCommittente')
if esito_committente is not None:
# more than one esito?
id_sdi_esito = esito_committente.find(
'IdentificativoSdI')
esito = esito_committente.find(
'Esito')
if esito is not None:
if esito.text == 'EC01':
state = 'validated'
elif esito.text == 'EC02':
state = 'rejected'
fatturapa_attachment_out.write({
'state': state,
'last_sdi_response': 'SdI ID: {}; '
'Message ID: {}; Response: {}; '.format(
id_sdi, message_id, esito.text)
})
elif message_type == 'DT': # 5. Decorrenza Termini per PA
description = root.find('Descrizione')
if description is not None:
fatturapa_attachment_out.write({
'state': 'validated',
'last_sdi_response': 'SdI ID: {}; '
'Message ID: {}; Receipt date: {}; '
'Description: {}'.format(
id_sdi, message_id, receipt_dt,
description.text)
})
# not implemented - todo
elif message_type == 'AT': # 6. Avvenuta Trasmissione per PA
description = root.find('Descrizione')
if description is not None:
fatturapa_attachment_out.write({
'state': 'validated',
'last_sdi_response': 'SdI ID: {}; '
'Message ID: {}; Receipt date: {}; '
'Description: {}'.format(
id_sdi, message_id, receipt_dt,
description.text)
})

message_dict['res_id'] = fatturapa_attachment_out.id
return message_dict

0 comments on commit 6e1e80d

Please sign in to comment.