Skip to content

Commit

Permalink
Merge 09a0f44 into a3ca0dd
Browse files Browse the repository at this point in the history
  • Loading branch information
eLBati committed Dec 19, 2019
2 parents a3ca0dd + 09a0f44 commit 75d66e3
Show file tree
Hide file tree
Showing 5 changed files with 1,325 additions and 144 deletions.
93 changes: 52 additions & 41 deletions l10n_it_fatturapa_pec/models/fetchmail.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def fetch_mail(self):
additional_context['server_type'] = server.type
imap_server = None
pop_server = None
error_raised = False
error_messages = list()
if server.type == 'imap':
try:
imap_server = server.connect()
Expand All @@ -67,27 +67,15 @@ def fetch_mail(self):
# if message is processed without exceptions
server.last_pec_error_message = ''
except Exception as e:
_logger.info(
'Failed to process mail from %s server '
'%s. Resetting server status',
server.type, server.name, exc_info=True
)
# Here is where we need to intervene.
server.last_pec_error_message = str(e)
error_raised = True
server.manage_pec_failure(e, error_messages)
continue
imap_server.store(num, '+FLAGS', '\\Seen')
# We need to commit because message is processed:
# Possible next exceptions, out of try, should not
# rollback processed messages
self._cr.commit() # pylint: disable=invalid-commit
except Exception as e:
_logger.info(
"General failure when trying to fetch mail from "
"%s server %s.",
server.type, server.name, exc_info=True)
server.last_pec_error_message = str(e)
error_raised = True
server.manage_pec_failure(e, error_messages)
finally:
if imap_server:
imap_server.close()
Expand Down Expand Up @@ -116,32 +104,21 @@ def fetch_mail(self):
# See the comments in the IMAP part
server.last_pec_error_message = ''
except Exception as e:
_logger.info(
'Failed to process mail from %s server'
'%s. Resetting server status',
server.type, server.name, exc_info=True
)
# See the comments in the IMAP part
error_raised = True
server.last_pec_error_message = str(e)
server.manage_pec_failure(
e, error_messages)
continue
# pylint: disable=invalid-commit
self._cr.commit()
if num_messages < MAX_POP_MESSAGES:
break
pop_server.quit()
except Exception as e:
_logger.info(
"General failure when trying to fetch mail from %s"
" server %s.",
server.type, server.name, exc_info=True)
# See the comments in the IMAP part
error_raised = True
server.last_pec_error_message = str(e)
server.manage_pec_failure(e, error_messages)
finally:
if pop_server:
pop_server.quit()
if error_raised:
if error_messages:
server.notify_or_log(error_messages)
server.pec_error_count += 1
max_retry = self.env['ir.config_parameter'].get_param(
'fetchmail.pec.max.retry')
Expand All @@ -158,26 +135,60 @@ def fetch_mail(self):
server.write({'date': fields.Datetime.now()})
return True

@api.multi
def manage_pec_failure(self, exception, error_messages):
self.ensure_one()
_logger.info(
"Failure when fetching emails "
"using {serv_type} server {serv_name}.".format(
serv_type=self.type,
serv_name=self.name),
exc_info=True)

exception_msg = str(exception)
# `str` on Odoo exceptions does not return
# a nice representation of the error
odoo_exc_string = getattr(exception, 'name', None)
if odoo_exc_string:
exception_msg = odoo_exc_string

self.last_pec_error_message = exception_msg
error_messages.append(exception_msg)
return True

def notify_about_server_reset(self):
self.ensure_one()
self.notify_or_log(
_("PEC server %s has been reset."
"Last error message is '%s'")
% (self.name, self.last_pec_error_message))

@api.multi
def notify_or_log(self, message):
"""
Send an email to partners in
self.e_inv_notify_partner_ids containing message.
:param: message
:type message: list of str, or str
"""
self.ensure_one()
if isinstance(message, list):
message = "<br/>".join(message)

if self.e_inv_notify_partner_ids:
self.env['mail.mail'].create({
'subject': _(
"Fetchmail PEC server [%s] reset"
) % self.name,
'body_html': _(
"<p>"
"PEC server %s has been reset. Last error message is</p>"
"<p><strong>%s</strong></p>"
) % (self.name, self.last_pec_error_message),
'subject': _("Fetchmail PEC server [%s] error") % self.name,
'body_html': message,
'recipient_ids': [(
6, 0,
self.e_inv_notify_partner_ids.ids
)]
})
_logger.info(
'Notifying partners %s about PEC server %s reset'
'Notifying partners %s about PEC server %s error'
% (self.e_inv_notify_partner_ids.ids, self.name)
)
else:
_logger.error(
"Can't notify anyone about PEC server %s reset" % self.name)
"Can't notify anyone about PEC server %s error" % self.name)
181 changes: 79 additions & 102 deletions l10n_it_fatturapa_pec/models/mail_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io

from odoo import api, models, _
from odoo.exceptions import UserError

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -52,55 +53,10 @@ def message_route(self, message, message_dict, model=None, thread_id=None,
response_attachments = [x for x in message_dict['attachments']
if response_regex.match(x.fname)]
if response_attachments and fatturapa_attachments:
# this is an electronic invoice
if len(response_attachments) > 1:
_logger.info(
'More than 1 message found in mail of incoming '
'invoice')
message_dict['model'] = 'fatturapa.attachment.in'
message_dict['record_name'] = message_dict['subject']
message_dict['res_id'] = 0
attachment_ids = self._message_post_process_attachments(
message_dict['attachments'], [], message_dict)
for attachment in self.env['ir.attachment'].browse(
[att_id for m, att_id in attachment_ids]):
if fatturapa_regex.match(attachment.name):
self.create_fatturapa_attachment_in(attachment)

message_dict['attachment_ids'] = attachment_ids
self.clean_message_dict(message_dict)

# model and res_id are only needed by
# _message_post_process_attachments: we don't attach to
del message_dict['model']
del message_dict['res_id']

# message_create_from_mail_mail to avoid to notify message
# (see mail.message.create)
self.env['mail.message'].with_context(
message_create_from_mail_mail=True).create(message_dict)
_logger.info('Routing FatturaPA PEC E-Mail with Message-Id: {}'
.format(message.get('Message-Id')))
return []

return self.manage_pec_fe_attachments(
message, message_dict, response_attachments)
else:
# this is an SDI notification
message_dict = self.env['fatturapa.attachment.out']\
.parse_pec_response(message_dict)

message_dict['record_name'] = message_dict['subject']
attachment_ids = self._message_post_process_attachments(
message_dict['attachments'], [], message_dict)
message_dict['attachment_ids'] = attachment_ids
self.clean_message_dict(message_dict)

# message_create_from_mail_mail to avoid to notify message
# (see mail.message.create)
self.env['mail.message'].with_context(
message_create_from_mail_mail=True).create(message_dict)
_logger.info('Routing FatturaPA PEC E-Mail with Message-Id: {}'
.format(message.get('Message-Id')))
return []
return self.manage_pec_sdi_notification(message, message_dict)

elif self._context.get('fetchmail_server_id', False):
# This is not an email coming from SDI
Expand All @@ -109,73 +65,94 @@ def message_route(self, message, message_dict, model=None, thread_id=None,
if fetchmail_server.is_fatturapa_pec:
att = self.find_attachment_by_subject(message_dict['subject'])
if att:
# This a PEC response (CONSEGNA o ACCETTAZIONE)
# related to a message sent to SDI by us
message_dict['model'] = 'fatturapa.attachment.out'
message_dict['res_id'] = att.id
self.clean_message_dict(message_dict)
self.env['mail.message'].with_context(
message_create_from_mail_mail=True).create(
message_dict)
else:
_logger.info(
'Can\'t route PEC E-Mail with Message-Id: {}'.format(
message.get('Message-Id'))
)
if fetchmail_server.e_inv_notify_partner_ids:
self.env['mail.mail'].create({
'subject': _(
"PEC message [%s] not processed"
) % message.get('Subject'),
'body_html': _(
"<p>"
"PEC message with Message-Id %s has been read "
"but not processed, as not related to an "
"e-invoice.</p>"
"<p>Please check PEC mailbox %s, at server %s,"
" with user %s</p>"
) % (
message.get('Message-Id'),
fetchmail_server.name, fetchmail_server.server,
fetchmail_server.user
),
'recipient_ids': [(
6, 0,
fetchmail_server.e_inv_notify_partner_ids.ids
)]
})
_logger.info(
'Notifying partners %s about message with '
'Message-Id: %s' % (
fetchmail_server.e_inv_notify_partner_ids.ids,
message.get('Message-Id')))
else:
_logger.error(
'Can\'t notify anyone about not processed '
'PEC E-Mail with Message-Id: {}'.format(
message.get('Message-Id')))
return []

return self.manage_pec_sdi_response(att, message_dict)
raise UserError(_(
"PEC message with Message-Id %s has been read "
"but not processed, as not related to an "
"e-invoice.\n"
"Please check PEC mailbox %s, at server %s,"
" with user %s."
) % (
message.get('Message-Id'),
fetchmail_server.name, fetchmail_server.server,
fetchmail_server.user
))
return super(MailThread, self).message_route(
message, message_dict, model=model, thread_id=thread_id,
custom_values=custom_values)

def manage_pec_sdi_response(self, att, message_dict):
# This is a PEC response (CONSEGNA o ACCETTAZIONE)
# related to a message sent to SDI by us
message_dict['model'] = 'fatturapa.attachment.out'
message_dict['res_id'] = att.id
self.clean_message_dict(message_dict)
self.env['mail.message'].with_context(
message_create_from_mail_mail=True).create(
message_dict)
return []

def manage_pec_sdi_notification(self, message, message_dict):
# this is an SDI notification
message_dict = self.env['fatturapa.attachment.out'] \
.parse_pec_response(message_dict)
message_dict['record_name'] = message_dict['subject']
attachment_ids = self._message_post_process_attachments(
message_dict['attachments'], [], message_dict)
message_dict['attachment_ids'] = attachment_ids
self.clean_message_dict(message_dict)
# message_create_from_mail_mail to avoid to notify message
# (see mail.message.create)
self.env['mail.message'].with_context(
message_create_from_mail_mail=True).create(message_dict)
_logger.info('Routing FatturaPA PEC E-Mail with Message-Id: {}'
.format(message.get('Message-Id')))
return []

def manage_pec_fe_attachments(self, message, message_dict,
response_attachments):
# this is an electronic invoice
if len(response_attachments) > 1:
_logger.info(
'More than 1 message found in mail of incoming invoice')
message_dict['model'] = 'fatturapa.attachment.in'
message_dict['record_name'] = message_dict['subject']
message_dict['res_id'] = 0
attachment_ids = self._message_post_process_attachments(
message_dict['attachments'], [], message_dict)
for attachment in self.env['ir.attachment'].browse(
[att_id for m, att_id in attachment_ids]):
if fatturapa_regex.match(attachment.name):
self.create_fatturapa_attachment_in(attachment)
message_dict['attachment_ids'] = attachment_ids
self.clean_message_dict(message_dict)
# model and res_id are only needed by
# _message_post_process_attachments: we don't attach to
del message_dict['model']
del message_dict['res_id']
# message_create_from_mail_mail to avoid to notify message
# (see mail.message.create)
self.env['mail.message'].with_context(
message_create_from_mail_mail=True).create(message_dict)
_logger.info('Routing FatturaPA PEC E-Mail with Message-Id: {}'
.format(message.get('Message-Id')))
return []

def find_attachment_by_subject(self, subject):
attachment_out_model = self.env['fatturapa.attachment.out']
if 'CONSEGNA: ' in subject:
att_name = subject.replace('CONSEGNA: ', '')
fatturapa_attachment_out = self.env[
'fatturapa.attachment.out'
].search([('datas_fname', '=', att_name)])
fatturapa_attachment_out = attachment_out_model \
.search([('datas_fname', '=', att_name)])
if len(fatturapa_attachment_out) == 1:
return fatturapa_attachment_out
if 'ACCETTAZIONE: ' in subject:
att_name = subject.replace('ACCETTAZIONE: ', '')
fatturapa_attachment_out = self.env[
'fatturapa.attachment.out'
].search([('datas_fname', '=', att_name)])
fatturapa_attachment_out = attachment_out_model \
.search([('datas_fname', '=', att_name)])
if len(fatturapa_attachment_out) == 1:
return fatturapa_attachment_out
return False
return attachment_out_model.browse()

def create_fatturapa_attachment_in(self, attachment):
decoded = base64.b64decode(attachment.datas)
Expand Down
Loading

0 comments on commit 75d66e3

Please sign in to comment.