[FIX] web: "Set Defaults" feature from the debug menu

Since odoo/odoo#99660
the `depends` field attribute is no longer passed
from the server to the web client.

Because of this, the "Set Defaults" feature
of the debug menu is completely unusable,
as the list of fields on which to set a default is empty because of it.

The use of this `depends` field attribute has been introduced in
revision odoo/odoo@ce9bbf6c10
In the commit description, we can read that setting a default
on computed fields having depends has been disabled
because the defaults set were being overwritten by the call to onchange.
Note that only the fact the field has depends is required,
the actual list of field names is not used, just the fact the list is
not empty.

However, since revision
odoo/odoo@488e334fc8,
available since Odoo 14.0,
this is no longer the case, the defaults are no longer being overwritten
by the call to `onchange`, since the `default_get` has been integrated
into the `onchange`.

A video attached to the pull request of this revision
shows the behavior difference.

Hence, setting a default on a computed fields having depends
(with an inverse method, hence not readonly)
can be allowed again in this "Set defaults" debug feature,
therefore avoiding to have to send back the `depends` field attributes
to the web client.

opw-3031290
opw-3038711
opw-3055292

X-original-commit: 48ac799288e76a0256b9ce0712a70ed5abc0f62e
Part-of: odoo/odoo#105251
This commit is contained in:
Denis Ledoux
2022-11-21 14:56:53 +01:00
parent 071eb95dd6
commit 5631887594
7 changed files with 114 additions and 11 deletions
+5
View File
@@ -17,4 +17,9 @@ You can track your vendors, customers and other contacts.
],
'application': True,
'license': 'LGPL-3',
'assets': {
'web.assets_tests': [
'contacts/static/tests/tours/**/*',
],
}
}
@@ -0,0 +1,70 @@
odoo.define('debug_menu_set_defaults.tour', function (require) {
"use strict";
var tour = require('web_tour.tour');
tour.register('debug_menu_set_defaults', {
test: true,
url: '/web?debug=1',
},
[
...tour.stepUtils.goToAppSteps('contacts.menu_contacts', "Open the contacts menu"),
{
content: "Create a new contact",
trigger: '.o-kanban-button-new',
},
{
content: "Check that Company is checked by default, and not Individual",
trigger: '.o_field_widget[name="company_type"] input[data-value="company"]:checked',
run: function () {},
},
{
content: "Select the individual radio button",
trigger: '.o_field_widget[name="company_type"] input[data-value="person"]',
},
{
content: "Open the debug menu",
trigger: '.o_debug_manager button',
},
{
content: "Click the Set Defaults menu",
trigger: '.o_debug_manager .dropdown-item:contains(Set Defaults)',
},
{
content: "Choose Company Type = Individual",
trigger: '#formview_default_fields',
run: function () {
const element_field = document.querySelector('select#formview_default_fields');
element_field.value = 'company_type';
element_field.dispatchEvent(new Event("change"));
},
},
{
content: "Save the new default",
trigger: 'footer button:contains(Save default)',
},
{
content: "Discard the contact creation",
trigger: 'button.o_form_button_cancel',
},
{
trigger: '.o-kanban-button-new',
},
{
content: "Check that Individual is checked instead of Company",
trigger: '.o_field_widget[name="company_type"] input[data-value="person"]:checked',
run: function () {},
},
{
content: "Discard the contact creation",
trigger: 'button.o_form_button_cancel',
},
{
content: "Wait for discard",
trigger: '.o_control_panel .o-kanban-button-new',
run() {},
},
]
);
});
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_ui
+33
View File
@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from ast import literal_eval
import odoo.tests
@odoo.tests.tagged('-at_install', 'post_install')
class TestUi(odoo.tests.HttpCase):
def test_set_defaults(self):
"""Tests the "Set Defaults" feature of the debug menu on the res.partner form.
Set a user-defined default on the computed (with inverse) field `company_type`
so the default "Company" becomes "Indivdual".
"""
# Ensure the requirements of the test:
# The tour assumptions are currently that `res.partner.company_type` is a non-readonly computed field
# currently defaulting to "company" in the `res.partner` form.
# If the below assertions change in the future, the tour needs to be adapted, as well as these assertions.
company_type_field = self.env['res.partner']._fields['company_type']
self.assertTrue(company_type_field.compute)
self.assertFalse(company_type_field.readonly)
action_context = literal_eval(self.env.ref('contacts.action_contacts').context)
self.assertTrue(action_context.get('default_is_company'))
# Make sure there is currently no user-defined default on res.partner.company_type
# so "Company" is the default value for the field res.partner.company_type
self.env['ir.default'].search([
('field_id', '=', self.env.ref('base.field_res_partner__company_type').id),
]).unlink()
self.assertEqual(self.env['res.partner'].with_context(**action_context).new().company_type, "company")
self.start_tour("/web", 'debug_menu_set_defaults', login="admin")
@@ -133,9 +133,7 @@ class SetDefaultDialog extends Component {
fieldInfo.type === "one2many" ||
fieldInfo.type === "many2many" ||
fieldInfo.type === "binary" ||
fieldsInfo[fieldName].options.isPassword ||
fieldInfo.depends === undefined ||
fieldInfo.depends.length !== 0
fieldsInfo[fieldName].options.isPassword
) {
return false;
}
+1 -3
View File
@@ -236,9 +236,7 @@ class SetDefaultDialog extends Component {
fieldInfo.type === "one2many" ||
fieldInfo.type === "many2many" ||
fieldInfo.type === "binary" ||
this.fieldsInfo[fieldName].options.isPassword ||
fieldInfo.depends === undefined ||
fieldInfo.depends.length !== 0
this.fieldsInfo[fieldName].options.isPassword
) {
return false;
}
@@ -536,9 +536,6 @@ QUnit.module("DebugMenu", (hooks) => {
fields: {},
records: [{ id: 18 }],
};
serverData.models.partner.fields.m2o.depends = [];
serverData.models.partner.fields.foo.depends = [];
serverData.models.partner.fields.o2m.depends = [];
serverData.models.partner.records = [{ id: 1, display_name: "p1", foo: "hello" }];
const mockRPC = async (route, args) => {
@@ -585,7 +582,6 @@ QUnit.module("DebugMenu", (hooks) => {
fields: {},
records: [{ id: 18 }],
};
serverData.models.partner.fields.foo.depends = [];
serverData.models.partner.records = [{ id: 1, display_name: "p1", foo: "hello" }];
const mockRPC = async (route, args) => {
@@ -635,7 +631,6 @@ QUnit.module("DebugMenu", (hooks) => {
fields: {},
records: [{ id: 18 }],
};
serverData.models.partner.fields.foo.depends = [];
serverData.models.partner.records = [{ id: 1, display_name: "p1", foo: "hello" }];
const mockRPC = async (route, args) => {