diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js index 6eac12a2dba..79583894fdc 100644 --- a/addons/web/static/src/js/fields/abstract_field.js +++ b/addons/web/static/src/js/fields/abstract_field.js @@ -49,6 +49,12 @@ var AbstractField = Widget.extend({ * skip the widget when pressing tab */ readonly: false, + /** + * If this flag is set to true, the field widget will be reset on every + * change which is made in the view (if the view supports it). This is + * currently a form view feature. + */ + resetOnAnyFieldChange: false, /** * if true, the widget will replace a cell in an editable list view */ diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index ffba3158d43..1b96d585ac7 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -313,6 +313,7 @@ var FieldMonetary = InputField.extend({ className: 'o_form_field_monetary o_list_number', replace_element: true, supportedFieldTypes: ['float', 'monetary'], + resetOnAnyFieldChange: true, // Have to listen to currency changes /** * Float fields using a monetary widget have an additional currency_field @@ -331,18 +332,9 @@ var FieldMonetary = InputField.extend({ init: function () { this._super.apply(this, arguments); - // Options for _formatValue - this.nodeOptions.digits = [16,2]; - if (this.attrs.currency_field) { - this.nodeOptions.currency_field = this.attrs.currency_field; - } else { - this.nodeOptions.currency_field = this.field.currency_field || 'currency_id'; - } - if (this.record.data[this.nodeOptions.currency_field]) { - this.nodeOptions.currency_id = this.record.data[this.nodeOptions.currency_field].res_id; - } + this._setCurrency(); - if (this.mode === 'edit' && this.nodeOptions.currency_id) { + if (this.mode === 'edit' && this.currency) { this.tagName = 'div'; } }, @@ -372,7 +364,7 @@ var FieldMonetary = InputField.extend({ * @private */ _renderEdit: function () { - if (!this.nodeOptions.currency_id) { + if (!this.currency) { this._super.apply(this, arguments); return; } @@ -381,15 +373,35 @@ var FieldMonetary = InputField.extend({ // Prepare and add the input this._prepareInput().appendTo(this.$el); // prepare and add the currency symbol - var currency = session.get_currency(this.nodeOptions.currency_id); - var $currencySymbol = $('', {text: currency.symbol}); - if (currency.position === "after") { + var $currencySymbol = $('', {text: this.currency.symbol}); + if (this.currency.position === "after") { this.$el.append($currencySymbol); } else { this.$el.prepend($currencySymbol); } }, - + /** + * Re-gets the currency as its value may have changed. + * @see FieldMonetary.resetOnAnyFieldChange + * + * @override + * @private + */ + _reset: function () { + this._super.apply(this, arguments); + this._setCurrency(); + }, + /** + * Deduces the currency description from the field options and view state. + * The description is then available at this.currency. + * + * @private + */ + _setCurrency: function () { + var currencyField = this.attrs.currency_field || this.field.currency_field || 'currency_id'; + var currencyID = this.record.data[currencyField] && this.record.data[currencyField].res_id; + this.currency = session.get_currency(currencyID); + }, /** * FieldMonetary overrides _formatValue to use the format monetary method * in readonly. @@ -400,7 +412,10 @@ var FieldMonetary = InputField.extend({ */ _formatValue: function (value) { var format = field_utils.format[this.mode === 'edit' ? "float" : "monetary"]; - return format(value, this.field, this.nodeOptions); + return format(value, this.field, { + digits: [16, 2], + currency: this.currency, + }); }, }); diff --git a/addons/web/static/src/js/fields/field_utils.js b/addons/web/static/src/js/fields/field_utils.js index cc9580c4baf..e529e6080d6 100644 --- a/addons/web/static/src/js/fields/field_utils.js +++ b/addons/web/static/src/js/fields/field_utils.js @@ -100,8 +100,8 @@ function formatDateTime(value) { * should be used. * @param {Object} [options] additional options to override the values in the * python description of the field. - * @param {integer} [options.digit] the number of digit that should be used, - * instead of the default digit precision in the field. + * @param {integer[]} [options.digits] the number of digits that should be used, + * instead of the default digits precision in the field. * @returns {string} */ function formatFloat(value, field, options) { @@ -191,21 +191,50 @@ function formatMany2Many(value) { } } +/** + * Returns a string representing a monetary value. The result takes into account + * the user settings (to display the correct decimal separator, currency, ...). + * + * @param {float} value the value that should be formatted + * @param {Object} [field] + * a description of the field (returned by fields_get for example). It + * may contain a description of the number of digits that should be used. + * @param {Object} [options] + * additional options to override the values in the python description of + * the field. + * @param {Object} [options.currency] - the description of the currency to use + * @param {integer} [options.currency_id] + * the id of the 'res.currency' to use (ignored if options.currency) + * @param {string} [options.currency_field] + * the name of the field whose value is the currency id + * (ignore if options.currency or options.currency_id) + * Note: if not given it will default to the field currency_field value + * or to 'currency_id'. + * @param {Object} [options.data] + * a mapping of field name to field value, required with + * options.currency_field + * @param {integer[]} [options.digits] + * the number of digits that should be used, instead of the default + * digits precision in the field. Note: if the currency defines a + * precision, the currency's one is used. + * @returns {string} + */ function formatMonetary(value, field, options) { options = options || {}; - var currency_id = options.currency_id; - if (!currency_id && options.data) { - var currency_field = options.currency_field || field.currency_field || 'currency_id'; - currency_id = options.data[currency_field] && options.data[currency_field].res_id; - } - var currency = session.get_currency(currency_id); - var digits_precision = (currency && currency.digits) || [69,2]; - var precision = digits_precision[1]; - var formatted = _.str.sprintf('%.' + precision + 'f', value || 0).split('.'); - formatted[0] = utils.insert_thousand_seps(formatted[0]); - var l10n = core._t.database.parameters; - var formatted_value = formatted.join(l10n.decimal_point); + var currency = options.currency; + if (!currency) { + var currency_id = options.currency_id; + if (!currency_id && options.data) { + var currency_field = options.currency_field || field.currency_field || 'currency_id'; + currency_id = options.data[currency_field] && options.data[currency_field].res_id; + } + currency = session.get_currency(currency_id); + } + + var formatted_value = formatFloat(value, field, { + digits: (currency && currency.digits) || options.digits, + }); if (!currency) { return formatted_value; 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 f417b53885d..0212832929c 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -155,7 +155,7 @@ return BasicRenderer.extend({ this.field_values = this._getFieldValues(this.state); var defs = []; _.each(this.widgets, function (widget) { - if (_.contains(fields, widget.name)) { + if (_.contains(fields, widget.name) || widget.resetOnAnyFieldChange) { defs.push(widget.reset(state, event)); } }); diff --git a/addons/web/static/test/fields/basic_fields_tests.js b/addons/web/static/test/fields/basic_fields_tests.js index 8cea1900c7c..c56f694e1fe 100644 --- a/addons/web/static/test/fields/basic_fields_tests.js +++ b/addons/web/static/test/fields/basic_fields_tests.js @@ -100,10 +100,12 @@ QUnit.module('basic_fields', { }, records: [{ id: 1, + display_name: "$", symbol: "$", position: "before", }, { id: 2, + display_name: "€", symbol: "€", position: "after", }] @@ -1333,7 +1335,7 @@ QUnit.module('basic_fields', { }); QUnit.test('monetary field with real monetary field in model', function (assert) { - assert.expect(3); + assert.expect(4); this.data.partner.fields.qux.type = "monetary"; @@ -1350,7 +1352,7 @@ QUnit.module('basic_fields', { arch:'
' + '' + '' + - '' + + '' + '' + '' + '
', @@ -1372,6 +1374,12 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_form_field_monetary > input').length, 1, "After the onchange, the monetary should not have been duplicated"); + var $dropdown = form.$('.o_form_field_many2one input').autocomplete('widget'); + form.$('.o_form_field_many2one input').click(); + $dropdown.find('li:not(.o_m2o_dropdown_option):last').mouseenter().click(); + assert.strictEqual(form.$('.o_form_field_monetary > span').html(), "€", + "After currency change, the monetary field currency should have been updated"); + form.destroy(); });