[FIX] web: prevent traceback during calendar popover processing

Before this commit, a traceback would occurs in sale_management calendar view when the user would try to display the popover of a sale_order.

```js
basic_model.js:2399 Uncaught (in promise) Error: for modifier "readonly": Unknown field state in domain
    at Class._evalModifiers (basic_model.js:2399)
    at calendar_popover.js:203
    at Function._.each._.forEach (underscore.js:145)
    at calendar_popover.js:180
    at async Promise.all (index 1)
_evalModifiers @ basic_model.js:2399
(anonymous) @ calendar_popover.js:203
_.each._.forEach @ underscore.js:145
(anonymous) @ calendar_popover.js:180
Promise.then (async)
_renderEventPopover @ calendar_renderer.js:861
eventClick @ calendar_renderer.js:416
Calendar.publiclyTrigger @ main.js:6981
EventClicking._this.handleSegClick @ main.js:6462
realHandler @ main.js:385
```

It would happen because the domain of the partner_id is ["state", "not in", ['draft', 'sent']] but the state field is invisible="1" in the view.
state was absent during of the evalContext in the _evalModifiers function.

closes odoo/odoo#72617

Taskid: 2524993
X-original-commit: 0d636c0f8dbcfb4b7adda26c0edc02a12b0c7e44
Signed-off-by: Michaël Mattiello <mcm-odoo@users.noreply.github.com>
Signed-off-by: Arnaud Joset <arj-odoo@users.noreply.github.com>
This commit is contained in:
Arnaud Joset
2021-06-23 11:15:21 +00:00
parent 0a87cd21fd
commit 4e006fb831
4 changed files with 16 additions and 4 deletions
@@ -31,6 +31,7 @@ var CalendarPopover = Widget.extend(WidgetAdapterMixin, StandaloneFieldManagerMi
this.event = eventInfo.event;
this.modelName = eventInfo.modelName;
this._canDelete = eventInfo.canDelete;
this.popoverFields = eventInfo.popoverFields;
},
/**
* @override
@@ -126,7 +127,7 @@ var CalendarPopover = Widget.extend(WidgetAdapterMixin, StandaloneFieldManagerMi
var self = this;
var fieldsToGenerate = [];
const fieldInformation = {};
var fields = _.keys(this.displayFields);
var fields = _.keys(this.popoverFields);
for (var i=0; i<fields.length; i++) {
var fieldName = fields[i];
var displayFieldInfo = self.displayFields[fieldName] || {attrs: {invisible: 1}};
@@ -139,6 +140,7 @@ var CalendarPopover = Widget.extend(WidgetAdapterMixin, StandaloneFieldManagerMi
string: displayFieldInfo.attrs.string || fieldInfo.string,
value: self.event.extendedProps.record[fieldName],
type: fieldInfo.type,
invisible: displayFieldInfo.attrs.invisible,
};
if (field.type === 'selection') {
field.selection = fieldInfo.selection;
@@ -200,7 +202,7 @@ var CalendarPopover = Widget.extend(WidgetAdapterMixin, StandaloneFieldManagerMi
// Only display the fields whose attributes does not make them invisible
let fieldClass = "list-group-item flex-shrink-0 d-flex flex-wrap";
if (fieldWidget.attrs && fieldWidget.attrs.modifiers) {
const fieldModifier = record.evalModifiers(fieldWidget.attrs.modifiers);
const fieldModifier = record.evalModifiers(_.pick(fieldWidget.attrs.modifiers, 'invisible'));
fieldClass += fieldModifier.invisible ? ' o_invisible_modifier' : '';
}
@@ -180,6 +180,7 @@ return AbstractRenderer.extend({
init: function (parent, state, params) {
this._super.apply(this, arguments);
this.displayFields = params.displayFields;
this.popoverFields = params.popoverFields;
this.model = params.model;
this.filters = [];
this.color_map = {};
@@ -807,6 +808,7 @@ return AbstractRenderer.extend({
event: eventData,
modelName: this.model,
canDelete: this.canDelete,
popoverFields: this.popoverFields,
};
var start = moment((eventData.extendedProps && eventData.extendedProps.r_start) || eventData.start);
@@ -69,6 +69,7 @@ var CalendarView = AbstractView.extend({
var mapping = {};
var fieldNames = fields.display_name ? ['display_name'] : [];
var displayFields = {};
let popoverFields = {};
_.each(fieldsToGather, function (field) {
if (arch.attrs[field]) {
@@ -87,6 +88,7 @@ var CalendarView = AbstractView.extend({
if (child.tag !== 'field') return;
var fieldName = child.attrs.name;
fieldNames.push(fieldName);
popoverFields[fieldName] = {attrs: child.attrs};
if (!child.attrs.invisible || child.attrs.filters) {
child.attrs.options = child.attrs.options ? pyUtils.py_eval(child.attrs.options) : {};
if (!child.attrs.invisible) {
@@ -177,6 +179,7 @@ var CalendarView = AbstractView.extend({
this.controllerParams.scales = scales;
this.rendererParams.displayFields = displayFields;
this.rendererParams.popoverFields = popoverFields;
this.rendererParams.model = viewInfo.model;
this.rendererParams.hideDate = utils.toBoolElse(attrs.hide_date || '', false);
this.rendererParams.hideTime = utils.toBoolElse(attrs.hide_time || '', false);
@@ -938,7 +938,7 @@ QUnit.module('Views', {
});
QUnit.test('render popover with modifiers', async function (assert) {
assert.expect(3);
assert.expect(5);
this.data.event.fields.priority = {string: "Priority", type: "selection", selection: [['0', 'Normal'], ['1', 'Important']],};
@@ -953,6 +953,10 @@ QUnit.module('Views', {
'all_day="allday" '+
'mode="week">'+
'<field name="priority" widget="priority" readonly="1"/>'+
'<field name="is_hatched" invisible="1"/>'+
'<field name="partner_id" attrs=\'{"invisible": [["is_hatched","=",False]]}\'/>'+
'<field name="start" attrs=\'{"invisible": [["is_hatched","=",True]]}\'/>'+
'</calendar>',
archs: archs,
viewOptions: {
@@ -964,7 +968,8 @@ QUnit.module('Views', {
assert.containsOnce(calendar, '.o_cw_popover', "should open a popover clicking on event");
assert.containsOnce(calendar, '.o_cw_popover .o_priority span.o_priority_star', "priority field should not be editable");
assert.strictEqual(calendar.$('.o_cw_popover li.o_invisible_modifier').text(), 'user : partner 1', "partner_id field should be invisible");
assert.containsOnce(calendar, '.o_cw_popover span.o_field_date', "The start date should be visible");
await testUtils.dom.click($('.o_cw_popover .o_cw_popover_close'));
assert.containsNone(calendar, '.o_cw_popover', "should close a popover");