[FIX] web: many2x fail for a good reason
Before this commit, when the "Create" button of a m2x is clicked and an error is returned by the server, a form view dialog is opened to create the record. We want to know if the error is caused by a missing required field but not by any other type of error. So we open the form view dialog only if the error is of type ValidationError otherwise we display an error dialog. closes odoo/odoo#116954 X-original-commit: 49bae69c602d1587fe159719667ff8dd0fb23984 Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -255,12 +255,21 @@ export class Many2XAutocomplete extends Component {
|
||||
try {
|
||||
await this.props.quickCreate(request, params);
|
||||
} catch (e) {
|
||||
if (e && e.name === "RPC_ERROR") {
|
||||
if (
|
||||
e &&
|
||||
e.name === "RPC_ERROR" &&
|
||||
e.exceptionName === "odoo.exceptions.ValidationError"
|
||||
) {
|
||||
const context = this.getCreationContext(request);
|
||||
return this.openMany2X({ context });
|
||||
}
|
||||
// Compatibility with legacy code
|
||||
if (e && e.message && e.message.name === "RPC_ERROR") {
|
||||
if (
|
||||
e &&
|
||||
e.message &&
|
||||
e.message.name === "RPC_ERROR" &&
|
||||
e.message.exceptionName === "odoo.exceptions.ValidationError"
|
||||
) {
|
||||
// The event.preventDefault() is necessary because we still use the legacy
|
||||
e.event.preventDefault();
|
||||
const context = this.getCreationContext(request);
|
||||
|
||||
@@ -1480,7 +1480,9 @@ QUnit.module("Fields", (hooks) => {
|
||||
arch: '<form><field name="timmy" widget="many2many_tags"/></form>',
|
||||
mockRPC(route, args) {
|
||||
if (args.method === "name_create") {
|
||||
throw new RPCError("Something went wrong");
|
||||
const error = new RPCError("Something went wrong");
|
||||
error.exceptionName = "odoo.exceptions.ValidationError";
|
||||
throw error;
|
||||
}
|
||||
if (args.method === "create") {
|
||||
assert.deepEqual(args.args[0], {
|
||||
|
||||
@@ -2967,19 +2967,64 @@ QUnit.module("Fields", (hooks) => {
|
||||
await click(target, ".modal .modal-footer .btn-primary");
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"failing quick create on a many2one because ValidationError",
|
||||
async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
registry.category("services").add("error", errorService);
|
||||
|
||||
// remove the override in qunit.js that swallows unhandledrejection errors
|
||||
// s.t. we let the error service handle them
|
||||
const originalOnUnhandledRejection = window.onunhandledrejection;
|
||||
window.onunhandledrejection = () => {};
|
||||
registerCleanup(() => {
|
||||
window.onunhandledrejection = originalOnUnhandledRejection;
|
||||
});
|
||||
|
||||
serverData.views = {
|
||||
"product,false,form": '<form><field name="name" /></form>',
|
||||
};
|
||||
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: '<form><field name="product_id" /></form>',
|
||||
mockRPC(route, { args, method }) {
|
||||
if (method === "name_create") {
|
||||
const error = new RPCError("Something went wrong");
|
||||
error.exceptionName = "odoo.exceptions.ValidationError";
|
||||
throw error;
|
||||
}
|
||||
if (method === "create") {
|
||||
assert.deepEqual(args[0], { name: "xyz" });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
await editInput(target, ".o_field_widget[name='product_id'] input", "abcd");
|
||||
await click(target.querySelector(".o_field_widget[name='product_id'] .dropdown-item"));
|
||||
await nextTick(); // wait for the error service to ensure that there's no error dialog
|
||||
assert.containsNone(target, ".o_error_dialog");
|
||||
assert.containsOnce(target, ".modal .o_form_view");
|
||||
assert.strictEqual(
|
||||
target.querySelector(".modal .o_field_widget[name='name'] input").value,
|
||||
"abcd"
|
||||
);
|
||||
|
||||
await editInput(target, ".modal .o_field_widget[name='name'] input", "xyz");
|
||||
await click(target, ".modal .o_form_button_save");
|
||||
assert.strictEqual(
|
||||
target.querySelector(".o_field_widget[name='product_id'] input").value,
|
||||
"xyz"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("failing quick create on a many2one", async function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
registry.category("services").add("error", errorService);
|
||||
|
||||
// remove the override in qunit.js that swallows unhandledrejection errors
|
||||
// s.t. we let the error service handle them
|
||||
const originalOnUnhandledRejection = window.onunhandledrejection;
|
||||
window.onunhandledrejection = () => {};
|
||||
registerCleanup(() => {
|
||||
window.onunhandledrejection = originalOnUnhandledRejection;
|
||||
});
|
||||
|
||||
serverData.views = {
|
||||
"product,false,form": '<form><field name="name" /></form>',
|
||||
};
|
||||
@@ -2991,75 +3036,66 @@ QUnit.module("Fields", (hooks) => {
|
||||
arch: '<form><field name="product_id" /></form>',
|
||||
mockRPC(route, { args, method }) {
|
||||
if (method === "name_create") {
|
||||
throw new RPCError("Something went wrong");
|
||||
}
|
||||
if (method === "create") {
|
||||
assert.deepEqual(args[0], { name: "xyz" });
|
||||
return new RPCError("Something went wrong");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
await editInput(target, ".o_field_widget[name='product_id'] input", "abcd");
|
||||
await click(target.querySelector(".o_field_widget[name='product_id'] .dropdown-item"));
|
||||
await nextTick(); // wait for the error service to ensure that there's no error dialog
|
||||
assert.containsNone(target, ".o_error_dialog");
|
||||
assert.containsOnce(target, ".modal .o_form_view");
|
||||
assert.strictEqual(
|
||||
target.querySelector(".modal .o_field_widget[name='name'] input").value,
|
||||
"abcd"
|
||||
);
|
||||
|
||||
await editInput(target, ".modal .o_field_widget[name='name'] input", "xyz");
|
||||
await click(target, ".modal .o_form_button_save");
|
||||
assert.strictEqual(
|
||||
target.querySelector(".o_field_widget[name='product_id'] input").value,
|
||||
"xyz"
|
||||
);
|
||||
await nextTick(); // wait for the error service
|
||||
assert.containsOnce(target, ".o_error_dialog");
|
||||
assert.containsNone(target, ".modal .o_form_view");
|
||||
});
|
||||
|
||||
QUnit.test("failing quick create on a many2one inside a one2many", async function (assert) {
|
||||
assert.expect(4);
|
||||
QUnit.test(
|
||||
"failing quick create on a many2one inside a one2many because ValidationError",
|
||||
async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
serverData.views = {
|
||||
"partner,false,list": `
|
||||
serverData.views = {
|
||||
"partner,false,list": `
|
||||
<tree editable="bottom">
|
||||
<field name="product_id" />
|
||||
</tree>`,
|
||||
"product,false,form": '<form><field name="name" /></form>',
|
||||
};
|
||||
"product,false,form": '<form><field name="name" /></form>',
|
||||
};
|
||||
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: '<form><field name="p" /></form>',
|
||||
mockRPC(route, { args, method }) {
|
||||
if (method === "name_create") {
|
||||
throw new RPCError("Something went wrong");
|
||||
}
|
||||
if (method === "create") {
|
||||
assert.deepEqual(args[0], { name: "xyz" });
|
||||
}
|
||||
},
|
||||
});
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: '<form><field name="p" /></form>',
|
||||
mockRPC(route, { args, method }) {
|
||||
if (method === "name_create") {
|
||||
const error = new RPCError("Something went wrong");
|
||||
error.exceptionName = "odoo.exceptions.ValidationError";
|
||||
throw error;
|
||||
}
|
||||
if (method === "create") {
|
||||
assert.deepEqual(args[0], { name: "xyz" });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
await click(target, ".o_field_x2many_list_row_add a");
|
||||
await editInput(target, ".o_field_widget[name='product_id'] input", "abcd");
|
||||
await click(target.querySelector(".o_field_widget[name='product_id'] .dropdown-item"));
|
||||
await click(target, ".o_field_x2many_list_row_add a");
|
||||
await editInput(target, ".o_field_widget[name='product_id'] input", "abcd");
|
||||
await click(target.querySelector(".o_field_widget[name='product_id'] .dropdown-item"));
|
||||
|
||||
assert.containsOnce(target, ".modal .o_form_view");
|
||||
assert.strictEqual(
|
||||
target.querySelector(".modal .o_field_widget[name='name'] input").value,
|
||||
"abcd"
|
||||
);
|
||||
assert.containsOnce(target, ".modal .o_form_view");
|
||||
assert.strictEqual(
|
||||
target.querySelector(".modal .o_field_widget[name='name'] input").value,
|
||||
"abcd"
|
||||
);
|
||||
|
||||
await editInput(target, ".modal .o_field_widget[name='name'] input", "xyz");
|
||||
await click(target, ".modal .o_form_button_save");
|
||||
assert.strictEqual(
|
||||
target.querySelector(".o_field_widget[name='product_id'] input").value,
|
||||
"xyz"
|
||||
);
|
||||
});
|
||||
await editInput(target, ".modal .o_field_widget[name='name'] input", "xyz");
|
||||
await click(target, ".modal .o_form_button_save");
|
||||
assert.strictEqual(
|
||||
target.querySelector(".o_field_widget[name='product_id'] input").value,
|
||||
"xyz"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test("slow create on a many2one", async function (assert) {
|
||||
serverData.views = {
|
||||
|
||||
Reference in New Issue
Block a user