[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 <sad@odoo.com>
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Co-authored-by: Aaron Bohy <aab@odoo.com>
This commit is contained in:
Tommy (tong)
2021-11-10 11:28:15 +00:00
committed by Aaron Bohy
co-authored by Aaron Bohy
parent 8fdd6f095d
commit 114a5885ba
3 changed files with 55 additions and 8 deletions
@@ -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,
@@ -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;
@@ -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`<RPCErrorDialog title="'Strange Error'"/>`;
CustomDialog.components = { RPCErrorDialog };
class NormalDialog extends Component {}
NormalDialog.template = tags.xml`<RPCErrorDialog title="'Normal Error'"/>`;
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) => {