From 2b46ae3ebc7132ac1f2bcb7101848db9493f0e90 Mon Sep 17 00:00:00 2001 From: Simone Rubino Date: Mon, 25 Jul 2022 17:48:22 +0200 Subject: [PATCH 1/4] [IMP] l10n_it_sdi_channel: Allow user to be notified of new e-bills or e-invoice notifications --- l10n_it_sdi_channel/__manifest__.py | 1 + .../data/mail_message_subtype_data.xml | 128 ++++++++++++++++++ l10n_it_sdi_channel/models/__init__.py | 3 +- .../models/fatturapa_attachment.py | 12 ++ .../models/fatturapa_attachment_out.py | 35 +++++ l10n_it_sdi_channel/models/sdi.py | 23 +++- l10n_it_sdi_channel/views/sdi_view.xml | 6 + 7 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 l10n_it_sdi_channel/data/mail_message_subtype_data.xml create mode 100644 l10n_it_sdi_channel/models/fatturapa_attachment.py diff --git a/l10n_it_sdi_channel/__manifest__.py b/l10n_it_sdi_channel/__manifest__.py index fcc300b98698..f2b8d7323f6f 100644 --- a/l10n_it_sdi_channel/__manifest__.py +++ b/l10n_it_sdi_channel/__manifest__.py @@ -26,6 +26,7 @@ "data": [ "security/ir.model.access.csv", "security/security.xml", + "data/mail_message_subtype_data.xml", "views/account_invoice_views.xml", "views/sdi_view.xml", "views/company_view.xml", diff --git a/l10n_it_sdi_channel/data/mail_message_subtype_data.xml b/l10n_it_sdi_channel/data/mail_message_subtype_data.xml new file mode 100644 index 000000000000..50d93b0d16c5 --- /dev/null +++ b/l10n_it_sdi_channel/data/mail_message_subtype_data.xml @@ -0,0 +1,128 @@ + + + + + + Ready to Send + fatturapa.attachment.out + + E-invoice Ready to Send + + + + Sent + fatturapa.attachment.out + + E-invoice Sent + + + + Sender Error + fatturapa.attachment.out + + E-invoice Sender Error + + + + Not delivered + fatturapa.attachment.out + + E-invoice Not Delivered + + + + Rejected (PA) + fatturapa.attachment.out + + E-invoice Rejected (PA) + + + + Delivered + fatturapa.attachment.out + + E-invoice Delivered + + + + Accepted + fatturapa.attachment.out + + E-invoice Accepted + + + + + E-bill received + fatturapa.attachment.in + + E-bill received + + + + + E-invoice Ready to Send + sdi.channel + + channel_id + + + + + E-invoice Sent + sdi.channel + + channel_id + + + + + E-invoice Sender Error + sdi.channel + + channel_id + + + + + E-invoice Not Delivered + sdi.channel + + channel_id + + + + + E-invoice Rejected (PA) + sdi.channel + + channel_id + + + + + E-invoice Delivered + sdi.channel + + channel_id + + + + + E-invoice Accepted + sdi.channel + + channel_id + + + + + E-bill received + sdi.channel + + channel_id + + diff --git a/l10n_it_sdi_channel/models/__init__.py b/l10n_it_sdi_channel/models/__init__.py index 69adaf704891..eea77ee484dc 100644 --- a/l10n_it_sdi_channel/models/__init__.py +++ b/l10n_it_sdi_channel/models/__init__.py @@ -1,6 +1,7 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from . import account_invoice -from . import fatturapa_attachment_out from . import company +from . import fatturapa_attachment +from . import fatturapa_attachment_out from . import sdi diff --git a/l10n_it_sdi_channel/models/fatturapa_attachment.py b/l10n_it_sdi_channel/models/fatturapa_attachment.py new file mode 100644 index 000000000000..9510c366d3fc --- /dev/null +++ b/l10n_it_sdi_channel/models/fatturapa_attachment.py @@ -0,0 +1,12 @@ +# Copyright 2022 Simone Rubino - TAKOBI +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class FatturaPAAttachment (models.AbstractModel): + _inherit = 'fatturapa.attachment' + + channel_id = fields.Many2one( + comodel_name='sdi.channel', + ) diff --git a/l10n_it_sdi_channel/models/fatturapa_attachment_out.py b/l10n_it_sdi_channel/models/fatturapa_attachment_out.py index 69b4af379da5..e3e42814008c 100644 --- a/l10n_it_sdi_channel/models/fatturapa_attachment_out.py +++ b/l10n_it_sdi_channel/models/fatturapa_attachment_out.py @@ -4,6 +4,20 @@ from odoo import _, api, fields, models from odoo.exceptions import UserError +STATE_SUBTYPE_MAPPING = { + 'ready': 'l10n_it_sdi_channel.e_invoice_ready', + 'sent': 'l10n_it_sdi_channel.e_invoice_sent', + 'sender_error': 'l10n_it_sdi_channel.e_invoice_sender_error', + 'recipient_error': 'l10n_it_sdi_channel.e_invoice_recipient_error', + 'rejected': 'l10n_it_sdi_channel.e_invoice_rejected', + 'validated': 'l10n_it_sdi_channel.e_invoice_validated', + 'accepted': 'l10n_it_sdi_channel.e_invoice_accepted', +} +""" +Map each state of fatturapa.attachment.out to +the mail.message.subtype that should be used to notify the user. +""" + class FatturaPAAttachmentOut (models.Model): _inherit = 'fatturapa.attachment.out' @@ -26,3 +40,24 @@ def send_to_sdi(self): sdi_channel = company.sdi_channel_id send_result = sdi_channel.send(self) return send_result + + @api.multi + def _track_subtype(self, init_values): + self.ensure_one() + if 'state' in init_values: + state_subtype = STATE_SUBTYPE_MAPPING.get(self.state) + if state_subtype: + return state_subtype + return super()._track_subtype(init_values) + + @api.model_create_multi + def create(self, vals_list): + attachments = super().create(vals_list) + sdi_channel = self.env.user.company_id.sdi_channel_id + if sdi_channel: + # Link the attachments to the channel + # to inherit channel's followers + attachments.update({ + 'channel_id': sdi_channel.id, + }) + return attachments diff --git a/l10n_it_sdi_channel/models/sdi.py b/l10n_it_sdi_channel/models/sdi.py index f8e7a0022cfd..c845f1a5c40b 100644 --- a/l10n_it_sdi_channel/models/sdi.py +++ b/l10n_it_sdi_channel/models/sdi.py @@ -9,7 +9,7 @@ from lxml import etree -from odoo import api, models, fields +from odoo import _, api, models, fields from odoo.fields import first FATTURAPA_IN_REGEX = '^(IT[a-zA-Z0-9]{11,16}|'\ @@ -25,6 +25,7 @@ class SdiChannel(models.Model): _name = "sdi.channel" + _inherit = "mail.thread" _description = "ES channel" name = fields.Char(string='Name', required=True) @@ -57,7 +58,6 @@ def send(self, attachment_out_ids): send_method = getattr(self, send_method_name) return send_method(attachment_out_ids) - @api.model def _prepare_attachment_in_values( self, file_name, @@ -94,9 +94,14 @@ def _prepare_attachment_in_values( 'datas_fname': file_name, 'datas': base64.encodebytes(file_content), }) + if len(self) == 1: + # Link the attachment to the channel + # to inherit channel's followers + attachment_values.update({ + 'channel_id': self.id, + }) return attachment_values - @api.model def _process_single_fe( self, file_name, @@ -137,7 +142,6 @@ def _process_single_fe( return attachments_values - @api.model def receive_fe( self, file_name_content_dict, @@ -179,7 +183,16 @@ def receive_fe( e_invoice_user = company.e_invoice_user_id if e_invoice_user: attachment_model = attachment_model.sudo(e_invoice_user.id) - return attachment_model.create(all_attachments_values) + + attachments = attachment_model.create(all_attachments_values) + for attachment in attachments: + attachment.message_post( + subject=_('Received new e-bill: {att_name}').format( + att_name=attachment.att_name, + ), + subtype='l10n_it_sdi_channel.e_bill_received', + ) + return attachments @api.model def _search_attachment_out_by_notification( diff --git a/l10n_it_sdi_channel/views/sdi_view.xml b/l10n_it_sdi_channel/views/sdi_view.xml index 4f962730f665..2dc6958ced38 100644 --- a/l10n_it_sdi_channel/views/sdi_view.xml +++ b/l10n_it_sdi_channel/views/sdi_view.xml @@ -29,6 +29,12 @@ +
+ +
From 5a1fbf4f8864f0190cef2270a02b0c1fa3aa3339 Mon Sep 17 00:00:00 2001 From: Simone Rubino Date: Mon, 25 Jul 2022 17:49:17 +0200 Subject: [PATCH 2/4] [IMP] l10n_it_fatturapa_sdicoop: Test notification for E-bill --- l10n_it_fatturapa_sdicoop/tests/__init__.py | 1 + .../tests/data/IT05979361218_001.xml | 119 ++++++++++++++++++ .../tests/test_notification.py | 72 +++++++++++ 3 files changed, 192 insertions(+) create mode 100644 l10n_it_fatturapa_sdicoop/tests/data/IT05979361218_001.xml create mode 100644 l10n_it_fatturapa_sdicoop/tests/test_notification.py diff --git a/l10n_it_fatturapa_sdicoop/tests/__init__.py b/l10n_it_fatturapa_sdicoop/tests/__init__.py index 6b95a3395eeb..b2e59b559a56 100644 --- a/l10n_it_fatturapa_sdicoop/tests/__init__.py +++ b/l10n_it_fatturapa_sdicoop/tests/__init__.py @@ -1,3 +1,4 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from . import test_account_invoice +from . import test_notification diff --git a/l10n_it_fatturapa_sdicoop/tests/data/IT05979361218_001.xml b/l10n_it_fatturapa_sdicoop/tests/data/IT05979361218_001.xml new file mode 100644 index 000000000000..3d1f8d65eb76 --- /dev/null +++ b/l10n_it_fatturapa_sdicoop/tests/data/IT05979361218_001.xml @@ -0,0 +1,119 @@ + + + + + + IT + 05979361218 + + 001 + FPA12 + UFPQ1O + + + + + IT + 05979361218 + + + SOCIETA' ALPHA BETA SRL + + Albo di test + TO + TO1258B + 2010-01-16 + RF02 + + + VIALE ROMA 543B + 07100 + SASSARI + SS + + + + + + 80213330584 + + AMMINISTRAZIONE BETA + + + + VIA TORINO 38-B + 00145 + ROMA + RM + IT + + + + + + + TD01 + EUR + 2015-02-16 + FT/2015/0006 + + TC22 + 0.00 + 3.00 + 3.00 + 0.00 + N4 + + Rif ordine MAPA: --- Nr. Identificativo Ordine 1234567 + + + 0.00 + 0.00 + + + + + 1 + Prodotto di test al giorno + 15.00 + Giorno(i) + 3.60 + 54.00 + 0.00 + N4 + + Vostro RIF + Riferimento + 3.00 + + + Vostro RIF + Riferimento2 + + + + 0.00 + N4 + 57.00 + 0.00 + Operazioni senza addebito imposta regime contribuenti minimi art.27 c.1-2 DL.98/11 + + + + TP01 + + MP05 + 2015-03-18 + 27.00 + + + MP05 + 2015-04-17 + 27.00 + + + + diff --git a/l10n_it_fatturapa_sdicoop/tests/test_notification.py b/l10n_it_fatturapa_sdicoop/tests/test_notification.py new file mode 100644 index 000000000000..a687e28724bc --- /dev/null +++ b/l10n_it_fatturapa_sdicoop/tests/test_notification.py @@ -0,0 +1,72 @@ +# Copyright 2022 Simone Rubino - TAKOBI +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.addons.l10n_it_fatturapa_in.tests.fatturapa_common import ( + FatturapaCommon, +) +from odoo.tests import new_test_user + + +class TestBillNotification (FatturapaCommon): + + def setUp(self): + super().setUp() + self.notified_user = new_test_user( + self.env, + login='Notify E-bill', + ) + self.sdicoop_channel = self.env.ref( + 'l10n_it_fatturapa_sdicoop.sdi_channel_sdicoop', + ) + + def test_e_bill_created_notify(self): + """ + When an E-bill is received, + the followers of the SdI channel are notified. + """ + # Arrange: Set the channel in the company, + # and a follower for the channel + company = self.env.user.company_id + notified_partner = self.notified_user.partner_id + company.sdi_channel_id = self.sdicoop_channel + company.sdi_channel_id.message_subscribe( + partner_ids=notified_partner.ids, + ) + # pre-condition: the partner is following the SdI channel + self.assertIn( + notified_partner, + company.sdi_channel_id.message_partner_ids, + ) + + # Act: Receive the E-bill + file_name = 'IT05979361218_001.xml' + file_path, file_content = self.getFile( + file_name, + module_name='l10n_it_fatturapa_sdicoop', + ) + attachment = company.sdi_channel_id.receive_fe( + { + file_name: file_content, + }, + {}, + ) + + # Assert: The SdI channel's follower is following the E-bill + self.assertIn( + notified_partner, + attachment.message_partner_ids, + ) + # There is a message of subtype E-bill received + received_e_bill_subtype = self.env.ref( + 'l10n_it_sdi_channel.e_bill_received', + ) + messages = attachment.message_ids + received_e_bill_message = messages.filtered( + lambda m: m.subtype_id == received_e_bill_subtype + ) + self.assertEqual(len(received_e_bill_message), 1) + # The message notifies the SdI channel's follower + self.assertIn( + notified_partner, + received_e_bill_message.needaction_partner_ids, + ) From 488286be4c0ee2adb4c208e4dda27ea9b035258c Mon Sep 17 00:00:00 2001 From: eLBati Date: Fri, 24 Jun 2022 07:49:28 +0200 Subject: [PATCH 3/4] Use related field for channel_id, avoid to directly write channel_id, avoid to call receive_fe on a specific channel, that could produce security errors in multi-company --- l10n_it_sdi_channel/models/fatturapa_attachment.py | 2 +- .../models/fatturapa_attachment_out.py | 12 ------------ l10n_it_sdi_channel/models/sdi.py | 9 +++------ 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/l10n_it_sdi_channel/models/fatturapa_attachment.py b/l10n_it_sdi_channel/models/fatturapa_attachment.py index 9510c366d3fc..693517ceeabf 100644 --- a/l10n_it_sdi_channel/models/fatturapa_attachment.py +++ b/l10n_it_sdi_channel/models/fatturapa_attachment.py @@ -8,5 +8,5 @@ class FatturaPAAttachment (models.AbstractModel): _inherit = 'fatturapa.attachment' channel_id = fields.Many2one( - comodel_name='sdi.channel', + comodel_name='sdi.channel', related="company_id.sdi_channel_id", store=True ) diff --git a/l10n_it_sdi_channel/models/fatturapa_attachment_out.py b/l10n_it_sdi_channel/models/fatturapa_attachment_out.py index e3e42814008c..71e7ec04e27e 100644 --- a/l10n_it_sdi_channel/models/fatturapa_attachment_out.py +++ b/l10n_it_sdi_channel/models/fatturapa_attachment_out.py @@ -49,15 +49,3 @@ def _track_subtype(self, init_values): if state_subtype: return state_subtype return super()._track_subtype(init_values) - - @api.model_create_multi - def create(self, vals_list): - attachments = super().create(vals_list) - sdi_channel = self.env.user.company_id.sdi_channel_id - if sdi_channel: - # Link the attachments to the channel - # to inherit channel's followers - attachments.update({ - 'channel_id': sdi_channel.id, - }) - return attachments diff --git a/l10n_it_sdi_channel/models/sdi.py b/l10n_it_sdi_channel/models/sdi.py index c845f1a5c40b..12fb4cb23ca5 100644 --- a/l10n_it_sdi_channel/models/sdi.py +++ b/l10n_it_sdi_channel/models/sdi.py @@ -58,6 +58,7 @@ def send(self, attachment_out_ids): send_method = getattr(self, send_method_name) return send_method(attachment_out_ids) + @api.model def _prepare_attachment_in_values( self, file_name, @@ -94,14 +95,9 @@ def _prepare_attachment_in_values( 'datas_fname': file_name, 'datas': base64.encodebytes(file_content), }) - if len(self) == 1: - # Link the attachment to the channel - # to inherit channel's followers - attachment_values.update({ - 'channel_id': self.id, - }) return attachment_values + @api.model def _process_single_fe( self, file_name, @@ -142,6 +138,7 @@ def _process_single_fe( return attachments_values + @api.model def receive_fe( self, file_name_content_dict, From 5a70e5f01e3dfbcd2677f76954ff8315f58bcc4f Mon Sep 17 00:00:00 2001 From: Simone Rubino Date: Mon, 25 Jul 2022 17:23:35 +0200 Subject: [PATCH 4/4] [FIX] l10n_it_sdi_channel: Subscribe to related channel --- .../models/fatturapa_attachment.py | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/l10n_it_sdi_channel/models/fatturapa_attachment.py b/l10n_it_sdi_channel/models/fatturapa_attachment.py index 693517ceeabf..c57cd6b4d0c7 100644 --- a/l10n_it_sdi_channel/models/fatturapa_attachment.py +++ b/l10n_it_sdi_channel/models/fatturapa_attachment.py @@ -8,5 +8,29 @@ class FatturaPAAttachment (models.AbstractModel): _inherit = 'fatturapa.attachment' channel_id = fields.Many2one( - comodel_name='sdi.channel', related="company_id.sdi_channel_id", store=True + comodel_name='sdi.channel', + related="company_id.sdi_channel_id", + store=True, ) + + def _message_auto_subscribe_followers( + self, updated_values, default_subtype_ids): + res = super()._message_auto_subscribe_followers( + updated_values, default_subtype_ids) + updated_channel_id = updated_values.get('channel_id') + if not updated_channel_id: + # SdI channel is not explicitly set, so SdI channel's followers + # won't be subscribed to current attachments. + # Attachments might have the SdI channel set anyway + # because it is a related field. + # Add the SdI channel's followers + # but only if all the attachments share the same SdI channel + channel = self.mapped('channel_id') + if all(attachment.channel_id == channel for attachment in self): + for partner_follower in channel.message_partner_ids: + res.append(( + partner_follower.id, + default_subtype_ids, + False, + )) + return res