From 114a5885baef46de65de96bad79f5ed54cdc06dc Mon Sep 17 00:00:00 2001 From: "Tommy (tong)" Date: Fri, 5 Nov 2021 09:09:02 +0000 Subject: [PATCH] [FIX] web: rpc error handling: use normal dialog if possible Before this commit, automated actions could not raise "normal" errors anymore (e.g. UserError). Indeed, since the wowl refactoring, it always shows the custom BaseAutomationErrorDialog when an error is thrown in an automated action, even if it is a standard error well-known by the framework. Before the wowl refactoring, those errors were handled normally if possible, and when it wasn't the case, the custom BaseAutomationErrorDialog was used. This commit restores that behavior. Complete steps to reproduce: - Install base_automation module - Install an app for the base_automation to trigger (e.g. Sales) - Turn on debug mode - Go to Automated Actions - Create an action with Action To Do is Execute Python Code and the Trigger is On Creation & Update - Set the model to your app (e.g. SalesOrder) - Put `raise UserError('Test')` in Python Code section - Go back to the app, try to create a new record in the model you set for the automated action to trigger - Compare the result with 14.0 closes odoo/odoo#79611 X-original-commit: d65d742de1b30a00b3ffd872c042e002736f7f6b Signed-off-by: Samuel Degueldre Signed-off-by: Aaron Bohy (aab) Co-authored-by: Aaron Bohy --- .../static/src/core/errors/error_handlers.js | 6 +++ .../static/src/core/network/rpc_service.js | 5 +- .../tests/core/errors/error_service_tests.js | 52 +++++++++++++++++-- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/addons/web/static/src/core/errors/error_handlers.js b/addons/web/static/src/core/errors/error_handlers.js index f0d63de995c..3a35daec50a 100644 --- a/addons/web/static/src/core/errors/error_handlers.js +++ b/addons/web/static/src/core/errors/error_handlers.js @@ -97,6 +97,12 @@ export function rpcErrorHandler(env, error, originalError) { ErrorComponent = errorDialogRegistry.get(exceptionName); } } + if (!ErrorComponent && originalError.data.context) { + const exceptionClass = originalError.data.context.exception_class; + if (errorDialogRegistry.contains(exceptionClass)) { + ErrorComponent = errorDialogRegistry.get(exceptionClass); + } + } env.services.dialog.add(ErrorComponent || RPCErrorDialog, { traceback: error.traceback, diff --git a/addons/web/static/src/core/network/rpc_service.js b/addons/web/static/src/core/network/rpc_service.js index 9ab20fc4f72..a7fbceef2d5 100644 --- a/addons/web/static/src/core/network/rpc_service.js +++ b/addons/web/static/src/core/network/rpc_service.js @@ -29,11 +29,8 @@ export function makeErrorFromResponse(reponse) { // Odoo returns error like this, in a error field instead of properly // using http error codes... const { code, data: errorData, message, type: subType } = reponse; - const { context: data_context, name: data_name } = errorData || {}; - const { exception_class } = data_context || {}; - const exception_class_name = exception_class || data_name; const error = new RPCError(); - error.exceptionName = exception_class_name; + error.exceptionName = errorData.name; error.subType = subType; error.data = errorData; error.message = message; diff --git a/addons/web/static/tests/core/errors/error_service_tests.js b/addons/web/static/tests/core/errors/error_service_tests.js index a0636dd2dc6..2b9d10c59e5 100644 --- a/addons/web/static/tests/core/errors/error_service_tests.js +++ b/addons/web/static/tests/core/errors/error_service_tests.js @@ -80,7 +80,7 @@ QUnit.test("handle RPC_ERROR of type='server' and no associated dialog class", a }); QUnit.test( - "handle RPC_ERROR of type='server' and associated custom dialog class", + "handle custom RPC_ERROR of type='server' and associated custom dialog class", async (assert) => { assert.expect(2); class CustomDialog extends Component {} @@ -89,17 +89,21 @@ QUnit.test( const error = new RPCError(); error.code = 701; error.message = "Some strange error occured"; - error.exceptionName = "strange_error"; + const errorData = { + context: { exception_class: "strange_error" }, + name: "strange_error", + }; + error.data = errorData; function addDialog(dialogClass, props) { assert.strictEqual(dialogClass, CustomDialog); assert.deepEqual(props, { name: "RPC_ERROR", type: "server", code: 701, - data: null, + data: errorData, subType: null, message: "Some strange error occured", - exceptionName: "strange_error", + exceptionName: null, traceback: error.stack, }); } @@ -111,6 +115,46 @@ QUnit.test( } ); +QUnit.test( + "handle normal RPC_ERROR of type='server' and associated custom dialog class", + async (assert) => { + assert.expect(2); + class CustomDialog extends Component {} + CustomDialog.template = tags.xml``; + CustomDialog.components = { RPCErrorDialog }; + class NormalDialog extends Component {} + NormalDialog.template = tags.xml``; + NormalDialog.components = { RPCErrorDialog }; + const error = new RPCError(); + error.code = 701; + error.message = "A normal error occured"; + const errorData = { + context: { exception_class: "strange_error" }, + }; + error.exceptionName = "normal_error"; + error.data = errorData; + function addDialog(dialogClass, props) { + assert.strictEqual(dialogClass, NormalDialog); + assert.deepEqual(props, { + name: "RPC_ERROR", + type: "server", + code: 701, + data: errorData, + subType: null, + message: "A normal error occured", + exceptionName: "normal_error", + traceback: error.stack, + }); + } + serviceRegistry.add("dialog", makeFakeDialogService(addDialog), { force: true }); + await makeTestEnv(); + errorDialogRegistry.add("strange_error", CustomDialog); + errorDialogRegistry.add("normal_error", NormalDialog); + const errorEvent = new PromiseRejectionEvent("error", { reason: error, promise: null }); + await unhandledRejectionCb(errorEvent); + } +); + QUnit.test("handle CONNECTION_LOST_ERROR", async (assert) => { patchWithCleanup(browser, { setTimeout: (callback, delay) => {