From 54a1f89bdac626aadd2ab54596488e4e735ae2e7 Mon Sep 17 00:00:00 2001 From: "Claire Bretton (clbr)" Date: Tue, 24 Oct 2023 23:38:25 +0200 Subject: [PATCH] [IMP] account: Send & Print - use the bus to notify cron status - Add a notification when closing the wizard that states that invoices will be processed asynchronously. - Add notifications when the cron is done processing some invoices. This notification can either be a successful message or a warning when some invoices are in error state. The notification can redirect to concerned moves. closes odoo/odoo#149717 Task-id: 3568549 Signed-off-by: Laurent Smet (las) --- addons/account/__manifest__.py | 1 + addons/account/i18n/account.pot | 53 +++++++++++++++++++ addons/account/models/account_move.py | 38 +++++++++++++ .../services/account_notification_service.js | 31 +++++++++++ .../account/tests/test_account_move_send.py | 44 ++++++++++++--- addons/account/wizard/account_move_send.py | 19 +++++-- 6 files changed, 175 insertions(+), 11 deletions(-) create mode 100644 addons/account/static/src/services/account_notification_service.js diff --git a/addons/account/__manifest__.py b/addons/account/__manifest__.py index 20085f21c18..4402fa8fb22 100644 --- a/addons/account/__manifest__.py +++ b/addons/account/__manifest__.py @@ -90,6 +90,7 @@ You could use this simplified accounting in case you work with an (external) acc 'account/static/src/scss/account_journal_dashboard.scss', 'account/static/src/scss/account_searchpanel.scss', 'account/static/src/components/**/*', + 'account/static/src/services/*.js', 'account/static/src/js/tours/account.js', 'account/static/src/views/**/*.js', 'account/static/src/js/search/search_bar/search_bar.js', diff --git a/addons/account/i18n/account.pot b/addons/account/i18n/account.pot index fb59b004a7d..2189c7a15bd 100644 --- a/addons/account/i18n/account.pot +++ b/addons/account/i18n/account.pot @@ -7842,6 +7842,21 @@ msgstr "" msgid "Invoices Statistics" msgstr "" +#. module: account +#. odoo-python +#: code:addons/account/wizard/account_move_send.py:0 +#, python-format +msgid "Invoices are being sent in the background." +msgstr "" + +#. module: account +#. odoo-python +#: code:addons/account/models/account_move.py:0 +#: code:addons/account/models/account_move.py:0 +#, python-format +msgid "Invoices in error" +msgstr "" + #. module: account #. odoo-python #: code:addons/account/models/account_journal_dashboard.py:0 @@ -7849,6 +7864,20 @@ msgstr "" msgid "Invoices owed to you" msgstr "" +#. module: account +#. odoo-python +#: code:addons/account/models/account_move.py:0 +#, python-format +msgid "Invoices sent" +msgstr "" + +#. module: account +#. odoo-python +#: code:addons/account/models/account_move.py:0 +#, python-format +msgid "Invoices sent successfully." +msgstr "" + #. module: account #: model_terms:ir.ui.view,arch_db:account.account_journal_dashboard_kanban_view msgid "Invoices to Validate" @@ -9710,6 +9739,13 @@ msgstr "" msgid "One or more Bank Accounts set on this partner are also used by other" msgstr "" +#. module: account +#. odoo-python +#: code:addons/account/models/account_move.py:0 +#, python-format +msgid "One or more invoices couldn't be processed." +msgstr "" + #. module: account #: model:ir.ui.menu,name:account.root_payment_menu msgid "Online Payments" @@ -9779,8 +9815,11 @@ msgid "Oops" msgstr "" #. module: account +#. odoo-python +#: code:addons/account/models/account_move.py:0 #: model:ir.model.fields.selection,name:account.selection__account_invoice_report__state__posted #: model:ir.model.fields.selection,name:account.selection__account_journal__invoice_reference_type__none +#, python-format msgid "Open" msgstr "" @@ -12146,11 +12185,25 @@ msgid "" "money." msgstr "" +#. module: account +#. odoo-python +#: code:addons/account/wizard/account_move_send.py:0 +#, python-format +msgid "Sending invoices" +msgstr "" + #. module: account #: model_terms:ir.ui.view,arch_db:account.view_account_payment_search msgid "Sent" msgstr "" +#. module: account +#. odoo-python +#: code:addons/account/models/account_move.py:0 +#, python-format +msgid "Sent invoices" +msgstr "" + #. module: account #: model:mail.template,description:account.mail_template_data_payment_receipt msgid "" diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 17572bb1093..1eb10ee1508 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -4227,6 +4227,24 @@ class AccountMove(models.Model): """ Handle Send & Print async processing. :param job_count: maximum number of jobs to process if specified. """ + def get_account_notification(partner, moves, is_success): + return [ + partner, + 'account_notification', + { + 'type': 'success' if is_success else 'warning', + 'title': _('Invoices sent') if is_success else _('Invoices in error'), + 'message': _('Invoices sent successfully.') if is_success else _( + "One or more invoices couldn't be processed."), + 'action_button': { + 'name': _('Open'), + 'action_name': _('Sent invoices') if is_success else _('Invoices in error'), + 'model': 'account.move', + 'res_ids': moves.ids, + }, + }, + ] + limit = job_count + 1 to_process = self.env['account.move']._read_group( [('send_and_print_values', '!=', False)], @@ -4250,8 +4268,28 @@ class AccountMove(models.Model): else: raise + # Retrieve res.partner that executed the Send & Print wizard + sp_partner_ids = set(moves.mapped(lambda move: move.send_and_print_values.get('sp_partner_id'))) + sp_partners = self.env['res.partner'].browse(sp_partner_ids) + moves_map = { + partner: moves.filtered(lambda m: m.send_and_print_values['sp_partner_id'] == partner.id) + for partner in sp_partners + } + self.env['account.move.send']._process_send_and_print(moves) + notifications = [] + for partner, partner_moves in moves_map.items(): + partner_moves_error = partner_moves.filtered(lambda m: m.send_and_print_values and m.send_and_print_values.get('error')) + if partner_moves_error: + notifications.append(get_account_notification(partner, partner_moves_error, False)) + partner_moves_success = partner_moves - partner_moves_error + if partner_moves_success: + notifications.append(get_account_notification(partner, partner_moves_success, True)) + partner_moves_error.send_and_print_values = False + + self.env['bus.bus']._sendmany(notifications) + if need_retrigger: self.env.ref('account.ir_cron_account_move_send')._trigger() diff --git a/addons/account/static/src/services/account_notification_service.js b/addons/account/static/src/services/account_notification_service.js new file mode 100644 index 00000000000..eed568b94e1 --- /dev/null +++ b/addons/account/static/src/services/account_notification_service.js @@ -0,0 +1,31 @@ +/** @odoo-module **/ + +import { _t } from "@web/core/l10n/translation"; +import { registry } from "@web/core/registry"; + + +export const accountNotificationService = { + dependencies: ["bus_service", "notification", "action"], + + start(env, { bus_service, notification, action }) { + bus_service.subscribe("account_notification", ({ message, sticky, title, type, action_button}) => { + const buttons = [{ + name: action_button.name, + primary: false, + onClick: () => { + action.doAction({ + name: _t(action_button.action_name), + type: 'ir.actions.act_window', + res_model: action_button.model, + domain: [["id", "in", action_button.res_ids]], + views: [[false, 'list'], [false, 'form']], + target: 'current', + }); + }, + }]; + notification.add(message, { sticky, title, type, buttons }); + }); + } +}; + +registry.category("services").add("accountNotification", accountNotificationService); diff --git a/addons/account/tests/test_account_move_send.py b/addons/account/tests/test_account_move_send.py index 492bc039def..b5c87992c99 100644 --- a/addons/account/tests/test_account_move_send.py +++ b/addons/account/tests/test_account_move_send.py @@ -1,16 +1,15 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +import json from datetime import date -from dateutil.relativedelta import relativedelta -from freezegun import freeze_time from unittest.mock import patch -from odoo import Command, fields +from odoo import Command from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.addons.mail.tests.common import MailCommon from odoo.exceptions import UserError -from odoo.tests.common import Form, users, warmup +from odoo.tests.common import users, warmup from odoo.tests import tagged from odoo.tools import formataddr, mute_logger @@ -581,7 +580,8 @@ class TestAccountMoveSend(TestAccountMoveSendCommon): # Process. results = wizard.action_send_and_print() - self.assertEqual(results['type'], 'ir.actions.act_window_close') + self.assertEqual(results['type'], 'ir.actions.client') + self.assertEqual(results['params']['next']['type'], 'ir.actions.act_window_close') self.assertRecordValues(wizard, [{'mode': 'invoice_multi'}]) # Awaiting the CRON. @@ -996,5 +996,35 @@ class TestAccountMoveSend(TestAccountMoveSendCommon): self.assertFalse(invoices.invoice_pdf_report_id) self.assertEqual(invoices.mapped(lambda inv: bool(inv.send_and_print_values)), [True] * len(invoices)) self.env.ref('account.ir_cron_account_move_send').method_direct_trigger() # force processing - self.assertEqual(len(invoices.invoice_pdf_report_id), 4) - self.assertEqual(invoices.mapped(lambda inv: inv.send_and_print_values), [False] * len(invoices)) + self.assertTrue(all(invoice.invoice_pdf_report_id for invoice in invoices)) + self.assertTrue(all(not invoice.send_and_print_values for invoice in invoices)) + + def test_cron_notifications(self): + invoice_success = self.init_invoice("out_invoice", amounts=[1000], post=True) + invoice_error = self.init_invoice("out_invoice", amounts=[1000], post=True) + wizard = self.create_send_and_print(invoice_success + invoice_error) + wizard.checkbox_download = False + sp_partner = self.env.user.partner_id + wizard.action_send_and_print() + + def _hook_invoice_document_before_pdf_report_render(self, invoice, invoice_data): + if invoice == invoice_error: + invoice_data['error'] = 'blblblbl' + + self.assertTrue(invoice_success.send_and_print_values) + self.assertEqual(invoice_success.send_and_print_values.get('sp_partner_id'), sp_partner.id) + + with patch( + 'odoo.addons.account.wizard.account_move_send.AccountMoveSend._hook_invoice_document_before_pdf_report_render', + _hook_invoice_document_before_pdf_report_render, + ): + self.env.ref('account.ir_cron_account_move_send').method_direct_trigger() # force processing + + bus = self.env['bus.bus'].sudo().search( + [('channel', 'like', f'"res.partner",{sp_partner.id}')], + order='id desc', + limit=1, + ) + self.assertEqual(json.loads(bus.message)['payload']['type'], 'success') + self.assertEqual(json.loads(bus.message)['payload']['action_button']['res_ids'], invoice_success.ids) + # FIXME @las I only manage to get the latest message, and not the previous one with the invoices in error T_T any idea ? diff --git a/addons/account/wizard/account_move_send.py b/addons/account/wizard/account_move_send.py index 04c4ced7fae..4cd18956480 100644 --- a/addons/account/wizard/account_move_send.py +++ b/addons/account/wizard/account_move_send.py @@ -671,8 +671,10 @@ class AccountMoveSend(models.TransientModel): self._hook_if_success(success, from_cron=from_cron, allow_fallback_pdf=allow_fallback_pdf) # Update send and print values of moves - for move in moves: - if move.send_and_print_values: + for move, move_data in moves_data.items(): + if from_cron and move_data.get('error'): + move.send_and_print_values = {'error': True} + else: move.send_and_print_values = False to_download = {move: move_data for move, move_data in moves_data.items() if move_data.get('download')} @@ -704,9 +706,18 @@ class AccountMoveSend(models.TransientModel): if process_later: # Set sending information on moves for move in self.move_ids: - move.send_and_print_values = self._get_wizard_values() + move.send_and_print_values = {'sp_partner_id': self.env.user.partner_id.id, **self._get_wizard_values()} self.env.ref('account.ir_cron_account_move_send')._trigger() - return {'type': 'ir.actions.act_window_close'} + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'info', + 'title': _('Sending invoices'), + 'message': _('Invoices are being sent in the background.'), + 'next': {'type': 'ir.actions.act_window_close'}, + }, + } return self._process_send_and_print( self.move_ids,