diff --git a/l10n_it_fatturapa_pec/__manifest__.py b/l10n_it_fatturapa_pec/__manifest__.py index 3a3656afd990..691265480969 100644 --- a/l10n_it_fatturapa_pec/__manifest__.py +++ b/l10n_it_fatturapa_pec/__manifest__.py @@ -22,6 +22,7 @@ 'views/account.xml', 'views/fatturapa_attachment_out.xml', 'wizard/send_pec_view.xml', + 'views/fetchmail_view.xml', ], 'installable': True } diff --git a/l10n_it_fatturapa_pec/models/__init__.py b/l10n_it_fatturapa_pec/models/__init__.py index c18e6f441c6e..0669881ef328 100644 --- a/l10n_it_fatturapa_pec/models/__init__.py +++ b/l10n_it_fatturapa_pec/models/__init__.py @@ -3,3 +3,4 @@ from . import account from . import fatturapa_attachment_out from . import mail_thread +from . import fetchmail diff --git a/l10n_it_fatturapa_pec/models/fatturapa_attachment_out.py b/l10n_it_fatturapa_pec/models/fatturapa_attachment_out.py index 92fcab6e1ef3..acc37ea90551 100644 --- a/l10n_it_fatturapa_pec/models/fatturapa_attachment_out.py +++ b/l10n_it_fatturapa_pec/models/fatturapa_attachment_out.py @@ -43,7 +43,7 @@ class FatturaPAAttachmentOut(models.Model): def reset_to_ready(self): for att in self: if att.state != 'sender_error': - raise UserError(_("Yo can only reset 'sender error' files")) + raise UserError(_("You can only reset 'sender error' files")) att.state = 'ready' @api.model diff --git a/l10n_it_fatturapa_pec/models/fetchmail.py b/l10n_it_fatturapa_pec/models/fetchmail.py new file mode 100644 index 000000000000..40c78d2f0ccb --- /dev/null +++ b/l10n_it_fatturapa_pec/models/fetchmail.py @@ -0,0 +1,134 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Lorenzo Battistini +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +import logging +from odoo import models, api, fields + +_logger = logging.getLogger(__name__) +MAX_POP_MESSAGES = 50 + + +class Fetchmail(models.Model): + _inherit = 'fetchmail.server' + last_pec_error_message = fields.Text( + "Last PEC error message", readonly=True) + + @api.multi + def fetch_mail(self): + for server in self: + if not server.is_fatturapa_pec: + super(Fetchmail, server).fetch_mail() + else: + additional_context = { + 'fetchmail_cron_running': True + } + # Setting fetchmail_cron_running to avoid to disable cron while + # cron is running (otherwise it would be done by setting + # server.state = 'draft', + # see _update_cron method) + server = server.with_context(**additional_context) + MailThread = self.env['mail.thread'] + _logger.info( + 'start checking for new e-invoices on %s server %s', + server.type, server.name) + additional_context['fetchmail_server_id'] = server.id + additional_context['server_type'] = server.type + imap_server = None + pop_server = None + if server.type == 'imap': + try: + imap_server = server.connect() + imap_server.select() + result, data = imap_server.search(None, '(UNSEEN)') + for num in data[0].split(): + result, data = imap_server.fetch(num, '(RFC822)') + imap_server.store(num, '-FLAGS', '\\Seen') + try: + MailThread.with_context( + **additional_context + ).message_process( + server.object_id.model, data[0][1], + save_original=server.original, + strip_attachments=(not server.attach) + ) + # 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. + # Setting to draft prevents new e-invoices to + # be sent via PEC + server.state = 'draft' + server.last_pec_error_message = str(e) + break + 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() + 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.state = 'draft' + server.last_pec_error_message = str(e) + finally: + if imap_server: + imap_server.close() + imap_server.logout() + elif server.type == 'pop': + try: + while True: + pop_server = server.connect() + (num_messages, total_size) = pop_server.stat() + pop_server.list() + for num in range( + 1, min(MAX_POP_MESSAGES, num_messages) + 1 + ): + (header, messages, octets) = pop_server.retr( + num) + message = '\n'.join(messages) + try: + MailThread.with_context( + **additional_context + ).message_process( + server.object_id.model, message, + save_original=server.original, + strip_attachments=(not server.attach) + ) + pop_server.dele(num) + # 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 + server.state = 'draft' + server.last_pec_error_message = str(e) + break + 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 + server.state = 'draft' + server.last_pec_error_message = str(e) + finally: + if pop_server: + pop_server.quit() + server.write({'date': fields.Datetime.now()}) + return True diff --git a/l10n_it_fatturapa_pec/views/fetchmail_view.xml b/l10n_it_fatturapa_pec/views/fetchmail_view.xml new file mode 100644 index 000000000000..9e03f1ba33f5 --- /dev/null +++ b/l10n_it_fatturapa_pec/views/fetchmail_view.xml @@ -0,0 +1,20 @@ + + + + + view_email_server_form_e_invoice + fetchmail.server + + + + + + + + + + {'invisible': [('is_fatturapa_pec', '=', True)]} + + + +