From 355cb456034981f9b4bf24c47f63589593c40779 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 24 Dec 2019 13:01:23 +0000 Subject: [PATCH] [IMP] base_automation, web: give possibility to disable/edit failing automated actions If an automated action raises an exception, in the traceback modal: - For admins, display Disable & Edit automated action buttons to be able to directly know with wihch automated action the error occurred, and to give the possibility to edit or disable it quickly, - For regular users, just add a paragraph to tell with which automated action the error occurred, so they can give this useful information to their administrator This is specially useful for databases which have just been upgraded to a newer version, and for which the server action is failing because its code is no longer supported. closes odoo/odoo#44513 X-original-commit: 8f3940c132bbbc99e47fa3f0cba0e768159d9af2 Signed-off-by: Denis Ledoux (dle) --- .../base_automation/i18n/base_automation.pot | 58 ++++++++++++++ .../base_automation/models/base_automation.py | 23 +++++- .../src/js/base_automation_error_dialog.js | 78 +++++++++++++++++++ .../src/xml/base_automation_error_dialog.xml | 36 +++++++++ .../tests/base_automation_error_dialog.js | 72 +++++++++++++++++ .../views/base_automation_view.xml | 12 +++ .../static/src/js/services/crash_manager.js | 18 +++-- addons/web/static/src/xml/crash_manager.xml | 8 +- odoo/http.py | 3 +- 9 files changed, 297 insertions(+), 11 deletions(-) create mode 100644 addons/base_automation/static/src/js/base_automation_error_dialog.js create mode 100644 addons/base_automation/static/src/xml/base_automation_error_dialog.xml create mode 100644 addons/base_automation/static/tests/base_automation_error_dialog.js diff --git a/addons/base_automation/i18n/base_automation.pot b/addons/base_automation/i18n/base_automation.pot index 6ffef9642c9..1fd7eb6f1f4 100644 --- a/addons/base_automation/i18n/base_automation.pot +++ b/addons/base_automation/i18n/base_automation.pot @@ -15,6 +15,15 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#. module: base_automation +#. openerp-web +#: code:addons/base_automation/static/src/xml/base_automation_error_dialog.xml:0 +#, python-format +msgid "" +"\"\n" +" (ID:" +msgstr "" + #. module: base_automation #: model:ir.model.fields,field_description:base_automation.field_base_automation__help msgid "Action Description" @@ -174,6 +183,24 @@ msgstr "" msgid "Delay type" msgstr "" +#. module: base_automation +#. openerp-web +#: code:addons/base_automation/static/src/xml/base_automation_error_dialog.xml:0 +#, python-format +msgid "Disable Action" +msgstr "" + +#. module: base_automation +#. openerp-web +#: code:addons/base_automation/static/src/xml/base_automation_error_dialog.xml:0 +#, python-format +msgid "" +"Disabling this automated action will enable you to continue your workflow\n" +" but any data created after this could potentially be corrupted,\n" +" as you are effectively disabling a customization that may set\n" +" important and/or required fields." +msgstr "" + #. module: base_automation #: model:ir.model.fields,field_description:base_automation.field_base_automation__display_name msgid "Display Name" @@ -189,6 +216,13 @@ msgstr "" msgid "Due type" msgstr "" +#. module: base_automation +#. openerp-web +#: code:addons/base_automation/static/src/xml/base_automation_error_dialog.xml:0 +#, python-format +msgid "Edit action" +msgstr "" + #. module: base_automation #: model:ir.model.fields,field_description:base_automation.field_base_automation__template_id msgid "Email Template" @@ -424,6 +458,15 @@ msgid "" "updated.If empty, all fields are watched." msgstr "" +#. module: base_automation +#. openerp-web +#: code:addons/base_automation/static/src/xml/base_automation_error_dialog.xml:0 +#, python-format +msgid "" +"The error occurred during the execution of the automated action\n" +" \"" +msgstr "" + #. module: base_automation #: model:ir.model.fields,field_description:base_automation.field_base_automation__trigger msgid "Trigger" @@ -530,3 +573,18 @@ msgid "" "Write Python code that the action will execute. Some variables are available" " for use; help about python expression is given in the help tab." msgstr "" + +#. module: base_automation +#. openerp-web +#: code:addons/base_automation/static/src/xml/base_automation_error_dialog.xml:0 +#, python-format +msgid "" +"You can ask an administrator to disable or correct this automated action." +msgstr "" + +#. module: base_automation +#. openerp-web +#: code:addons/base_automation/static/src/xml/base_automation_error_dialog.xml:0 +#, python-format +msgid "You can disable this automated action or edit it to solve the issue." +msgstr "" diff --git a/addons/base_automation/models/base_automation.py b/addons/base_automation/models/base_automation.py index 17be94a5664..e587db98996 100644 --- a/addons/base_automation/models/base_automation.py +++ b/addons/base_automation/models/base_automation.py @@ -209,6 +209,16 @@ class BaseAutomation(models.Model): else: return records, None + @api.model + def _add_postmortem_action(self, e): + if self.user_has_groups('base.group_user'): + e.context = {} + e.context['exception_class'] = 'base_automation' + e.context['base_automation'] = { + 'id': self.id, + 'name': self.name, + } + def _process(self, records, domain_post=None): """ Process action ``self`` on the ``records`` that have not been done yet. """ # filter out the records on which self has already been done @@ -242,7 +252,11 @@ class BaseAutomation(models.Model): 'active_id': record.id, 'domain_post': domain_post, } - self.action_server_id.with_context(**ctx).run() + try: + self.action_server_id.with_context(**ctx).run() + except Exception as e: + self._add_postmortem_action(e) + raise e def _check_trigger_fields(self, record): """ Return whether any of the trigger fields has been modified on ``record``. """ @@ -367,7 +381,12 @@ class BaseAutomation(models.Model): action_rule = self.env['base.automation'].browse(action_rule_id) result = {} server_action = action_rule.action_server_id.with_context(active_model=self._name, onchange_self=self) - res = server_action.run() + try: + res = server_action.run() + except Exception as e: + action_rule._add_postmortem_action(e) + raise e + if res: if 'value' in res: res['value'].pop('id', None) diff --git a/addons/base_automation/static/src/js/base_automation_error_dialog.js b/addons/base_automation/static/src/js/base_automation_error_dialog.js new file mode 100644 index 00000000000..3fa4cf0cc06 --- /dev/null +++ b/addons/base_automation/static/src/js/base_automation_error_dialog.js @@ -0,0 +1,78 @@ +odoo.define('base_automation.BaseAutomatioErrorDialog', function (require) { + "use strict"; + + const CrashManager = require('web.CrashManager'); + const ErrorDialog = CrashManager.ErrorDialog; + const ErrorDialogRegistry = require('web.ErrorDialogRegistry'); + const session = require('web.session'); + + const BaseAutomationErrorDialog = ErrorDialog.extend({ + xmlDependencies: (ErrorDialog.prototype.xmlDependencies || []).concat( + ['/base_automation/static/src/xml/base_automation_error_dialog.xml'] + ), + template: 'CrashManager.BaseAutomationError', + events: { + 'click .o_disable_action_button': '_onDisableAction', + 'click .o_edit_action_button': '_onEditAction', + }, + /** + * Assign the `base_automation` object based on the error data, + * which is then used by the `CrashManager.BaseAutomationError` template + * and the events defined above. + * @override + * @param {Object} error + * @param {string} error.data.context.base_automation.id the ID of the failing automated action + * @param {string} error.data.context.base_automation.name the name of the failing automated action + */ + init: function (parent, options, error) { + this._super.apply(this, arguments); + this.base_automation = error.data.context.base_automation; + this.is_admin = session.is_admin; + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * This method is called when the user clicks on the 'Disable action' button + * displayed when a crash occurs in the evaluation of an automated action. + * Then, we write `active` to `False` on the automated action to disable it. + * + * @private + * @param {MouseEvent} ev + */ + _onDisableAction: function (ev) { + ev.preventDefault(); + this._rpc({ + model: 'base.automation', + method: 'write', + args: [[this.base_automation.id], { + active: false, + }], + }).then(this.destroy.bind(this)); + }, + /** + * This method is called when the user clicks on the 'Edit action' button + * displayed when a crash occurs in the evaluation of an automated action. + * Then, we redirect the user to the automated action form. + * + * @private + * @param {MouseEvent} ev + */ + _onEditAction: function (ev) { + ev.preventDefault(); + this.do_action({ + name: 'Automated Actions', + res_model: 'base.automation', + res_id: this.base_automation.id, + views: [[false, 'form']], + type: 'ir.actions.act_window', + view_mode: 'form', + }); + }, + }); + + ErrorDialogRegistry.add('base_automation', BaseAutomationErrorDialog); + +}); diff --git a/addons/base_automation/static/src/xml/base_automation_error_dialog.xml b/addons/base_automation/static/src/xml/base_automation_error_dialog.xml new file mode 100644 index 00000000000..e45c59117ec --- /dev/null +++ b/addons/base_automation/static/src/xml/base_automation_error_dialog.xml @@ -0,0 +1,36 @@ + + + + + + +

+ The error occurred during the execution of the automated action + "" + (ID: ). +
+

+

+ You can ask an administrator to disable or correct this automated action. +

+

+ You can disable this automated action or edit it to solve the issue.
+ Disabling this automated action will enable you to continue your workflow + but any data created after this could potentially be corrupted, + as you are effectively disabling a customization that may set + important and/or required fields. +

+
+
+ + + + + + +
+
diff --git a/addons/base_automation/static/tests/base_automation_error_dialog.js b/addons/base_automation/static/tests/base_automation_error_dialog.js new file mode 100644 index 00000000000..af2e9ff6d4d --- /dev/null +++ b/addons/base_automation/static/tests/base_automation_error_dialog.js @@ -0,0 +1,72 @@ +odoo.define('base_automation.BaseAutomatioErrorDialogTests', function (require) { +'use strict'; + + const CrashManager = require('web.CrashManager').CrashManager; + const session = require('web.session'); + + QUnit.module('base_automation', {}, function () { + + QUnit.module('Error Dialog'); + + QUnit.test('Error due to an automated action', async function (assert) { + assert.expect(4); + + let baseAutomationName = 'Test base automation error dialog'; + let error = { + type: 'Odoo Client Error', + message: 'Message', + data: { + debug: 'Traceback', + context: { + exception_class: 'base_automation', + base_automation: { + id: 1, + name: baseAutomationName, + }, + }, + }, + }; + // Force the user session to be admin, to display the disable and edit action buttons, + // then reset back to the origin value after the test. + let isAdmin = session.is_admin; + session.is_admin = true; + + let crashManager = new CrashManager(); + let dialog = crashManager.show_error(error); + + await dialog._opened; + + assert.containsOnce(document.body, '.modal .o_clipboard_button'); + assert.containsOnce(document.body, '.modal .o_disable_action_button'); + assert.containsOnce(document.body, '.modal .o_edit_action_button'); + assert.ok(dialog.$el.text().indexOf(baseAutomationName) !== -1); + + session.is_admin = isAdmin; + crashManager.destroy(); + }); + + QUnit.test('Error not due to an automated action', async function (assert) { + assert.expect(3); + + let error = { + type: 'Odoo Client Error', + message: 'Message', + data: { + debug: 'Traceback', + }, + }; + let crashManager = new CrashManager(); + let dialog = crashManager.show_error(error); + + await dialog._opened; + + assert.containsOnce(document.body, '.modal .o_clipboard_button'); + assert.containsNone(document.body, '.modal .o_disable_action_button'); + assert.containsNone(document.body, '.modal .o_edit_action_button'); + + crashManager.destroy(); + }); + + }); + +}); diff --git a/addons/base_automation/views/base_automation_view.xml b/addons/base_automation/views/base_automation_view.xml index e999edb9e2e..8902d8362f4 100644 --- a/addons/base_automation/views/base_automation_view.xml +++ b/addons/base_automation/views/base_automation_view.xml @@ -123,4 +123,16 @@ +