diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index 0642fd6842c..f59cf96a881 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -268,6 +268,8 @@ var BasicModel = AbstractModel.extend({ * @param {boolean} [options.env=false] if true, will only return res_id * (if record) or res_ids (if list) * @param {boolean} [options.raw=false] if true, will not follow relations + * @param {boolean} [options.noUnsetNumeric=false] if true, will set numeric + * values to 0 if not set * @returns {Object} */ get: function (id, options) { @@ -311,6 +313,13 @@ var BasicModel = AbstractModel.extend({ if (!field) { continue; } + if (options.noUnsetNumeric) { + if (field.type === 'float' || + field.type === 'integer' || + field.type === 'monetary') { + element.data[fieldName] = element.data[fieldName] || 0; + } + } // get relational datapoint if (field.type === 'many2one') { @@ -1792,7 +1801,7 @@ var BasicModel = AbstractModel.extend({ * @returns {Object} */ _getEvalContext: function (element) { - var evalContext = this.get(element.id, {raw: true}).data; + var evalContext = this.get(element.id, {raw: true, noUnsetNumeric: true}).data; evalContext.active_model = element.model; if (evalContext.id) { evalContext.active_id = evalContext.id; diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js index 2aa4479648b..1db0718545e 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -51,44 +51,6 @@ return AbstractRenderer.extend({ } }); }, - /** - * Helper method, used to get an object with the 'raw' field values. It is - * important when we want to evaluate if a record matches a given domain. - * - * A basic model record is a tree structure, but we sometimes need 'pure' - * data, so for example, [1,4] for the value of a one2many, not - * [{Object}, {Object}]. - * - * @param {Object} record - * @returns {Object} - */ - _getFieldValues: function (record) { - var result = {}; - _.each(record.getFieldNames(), function (name) { - var field = record.fields[name]; - var value = record.data[name]; - result[name] = value; - if (!value) { - return; - } - else if (field.type === 'many2one') { - result[name] = value.data ? value.data.id || false : false; - } - else if (field.type === 'one2many' || field.type === 'many2many') { - if (value) { - result[name] = _.pluck(value.data, 'res_id'); - } else { - result[name] = []; - } - } - else if (field.type === 'boolean') { - // we want an explicit false value, not null if it is unset - result[name] = value || false; - } - }); - result.id = record.data.id; - return result; - }, /** * Render the view * diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js index 0927e72f72e..926d093206f 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -29,7 +29,7 @@ return BasicRenderer.extend({ this.idsForLabels = {}; this.widgets = []; this.mode = params.mode; - this.field_values = this._getFieldValues(this.state); + this.field_values = this.state.getEvalContext(); }, //-------------------------------------------------------------------------- @@ -136,7 +136,7 @@ return BasicRenderer.extend({ // only update the given fields return this.updateWidgets(params.fieldNames, state); } - this.field_values = this._getFieldValues(state); + this.field_values = state.getEvalContext(); return this._super.apply(this, arguments); }, /** @@ -152,7 +152,7 @@ return BasicRenderer.extend({ */ updateWidgets: function (fields, state, event) { this.state = state; - this.field_values = this._getFieldValues(this.state); + this.field_values = this.state.getEvalContext(); var defs = []; _.each(this.widgets, function (widget) { if (_.contains(fields, widget.name) || widget.resetOnAnyFieldChange) { diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js index b71daa6659f..1e24aaeb879 100644 --- a/addons/web/static/src/js/views/list/list_editable_renderer.js +++ b/addons/web/static/src/js/views/list/list_editable_renderer.js @@ -215,7 +215,7 @@ ListRenderer.include({ return true; } if ('readonly' in node.modifiers) { - var fieldValues = this._getFieldValues(record); + var fieldValues = record.getEvalContext(); return new Domain(node.modifiers.readonly).compute(fieldValues); } return false; diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js index 8cfb9ced65b..c51cae980da 100644 --- a/addons/web/static/src/js/views/list/list_renderer.js +++ b/addons/web/static/src/js/views/list/list_renderer.js @@ -223,7 +223,7 @@ var ListRenderer = BasicRenderer.extend({ */ _isInvisible: function (record, node) { if ('invisible' in node.modifiers) { - var fieldValues = this._getFieldValues(record); + var fieldValues = record.getEvalContext(); return new Domain(node.modifiers.invisible).compute(fieldValues); } return false; diff --git a/addons/web/static/test/views/form_tests.js b/addons/web/static/test/views/form_tests.js index d630cfd7e01..40ea74f8890 100644 --- a/addons/web/static/test/views/form_tests.js +++ b/addons/web/static/test/views/form_tests.js @@ -363,6 +363,31 @@ QUnit.module('Views', { form.destroy(); }); + QUnit.test('invisible attrs with zero value in domain and unset value in data', function (assert) { + assert.expect(1); + + this.data.partner.fields.int_field.type = 'monetary'; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
', + }); + + assert.notOk(form.$('div.hello').is(':visible'), + "attrs invisible should have been computed and applied"); + form.destroy(); + }); + QUnit.test('rendering stat buttons', function (assert) { assert.expect(3);