summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorCedric Snauwaert <csn@openerp.com>2015-01-14 09:47:15 +0100
committerOlivier Dony <odo@openerp.com>2015-04-09 19:05:44 +0200
commit9d87d15db6dd40a5a0162fb126c725a2f0a40414 (patch)
tree304ee05b40ea8fa4d3c0c6ba962534c479320d41 /addons/web/static/src
parent1ebd67355ae981d391fb4c2869027214554df136 (diff)
[ADD] new fields.Monetary + updated widgets
Enhance current widget="monetary" client-side feature and convert it to a first-class type of field, allowing proper server-side behavior. - fields: add field.Monetary, similar to fields.Float but supporting a `currency_field` attribute instead of the decimal_precision attribute. `currency_field` indicates the field holding the related currency on the same record. The symbol of that currency is used when displaying the field, and the rounding of the currency is applied instead of the usual decimal precision. - avoids application of a second decimal precision rounding, as was the case when the model field was a `fields.float`. - removes the need for adding explicit boilerplate to each view containing a monetary field, i.e.: widget="monetary" options="{'currency_field': 'currency_id'}" - res.currency: add new field decimal_places needed to round value at the correct decimal places - web: cache all currencies, rounding and symbols at webclient startup to speedup monetary fields - new widget monetary for list view + adapt widget monetary on form view Limitations: - if the currency_field is a related field, the server-side application of currency rounding will only work when the record already exists, not during creation (to be fixed) - this field is only supported in the new API
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/js/framework/formats.js2
-rw-r--r--addons/web/static/src/js/framework/session.js16
-rw-r--r--addons/web/static/src/js/views/form_widgets.js29
-rw-r--r--addons/web/static/src/js/views/graph_view.js2
-rw-r--r--addons/web/static/src/js/views/list_view.js25
-rw-r--r--addons/web/static/src/js/views/list_view_editable.js1
-rw-r--r--addons/web/static/src/js/views/pivot_view.js2
-rw-r--r--addons/web/static/src/js/views/search_filters.js1
-rw-r--r--addons/web/static/src/js/views/search_inputs.js1
-rw-r--r--addons/web/static/src/xml/base.xml4
10 files changed, 65 insertions, 18 deletions
diff --git a/addons/web/static/src/js/framework/formats.js b/addons/web/static/src/js/framework/formats.js
index a8dc52bee4a..9efd799a481 100644
--- a/addons/web/static/src/js/framework/formats.js
+++ b/addons/web/static/src/js/framework/formats.js
@@ -46,6 +46,7 @@ function format_value (value, descriptor, value_if_empty) {
case 'integer':
return utils.insert_thousand_seps(
_.str.sprintf('%d', value));
+ case 'monetary':
case 'float':
var digits = descriptor.digits ? descriptor.digits : [69,2];
digits = typeof digits === "string" ? py.eval(digits) : digits;
@@ -133,6 +134,7 @@ function parse_value (value, descriptor, value_if_empty) {
if (isNaN(tmp) || tmp % 1)
throw new Error(_.str.sprintf(_t("'%s' is not a correct integer"), value));
return tmp;
+ case 'monetary':
case 'float':
tmp = Number(value);
if (!isNaN(tmp))
diff --git a/addons/web/static/src/js/framework/session.js b/addons/web/static/src/js/framework/session.js
index 5f6d4c91ea2..8b084f640fd 100644
--- a/addons/web/static/src/js/framework/session.js
+++ b/addons/web/static/src/js/framework/session.js
@@ -40,6 +40,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
this.name = "instance0";
// TODO: session store in cookie should be optional
this.qweb_mutex = new utils.Mutex();
+ this.currencies = {};
},
setup: function(origin, options) {
// must be able to customize server
@@ -169,7 +170,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
var to_load = _.difference(result, self.module_list).join(',');
self.module_list = all_modules;
- var loaded = self.load_translations();
+ var loaded = $.when(self.load_currencies(), self.load_translations());
var locale = "/web/webclient/locale/" + self.user_context.lang || 'en_US';
var file_list = [ locale ];
if(to_load.length) {
@@ -190,6 +191,16 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
});
});
},
+ load_currencies: function() {
+ this.currencies = {};
+ var self = this;
+ return new openerp.web.Model("res.currency").query(["symbol", "position", "decimal_places"]).all()
+ .then(function(value) {
+ _.each(value, function(k){
+ self.currencies[k.id] = {'symbol': k.symbol, 'position': k.position, 'digits': [69,k.decimal_places]};
+ });
+ });
+ },
load_translations: function() {
return _t.database.load_translations(this, this.module_list, this.user_context.lang);
},
@@ -240,6 +251,9 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
this.module_loaded[mod] = true;
}
},
+ get_currency: function(currency_id) {
+ return this.currencies[currency_id];
+ },
get_file: function (options) {
if (this.override_session){
options.data.session_id = this.session_id;
diff --git a/addons/web/static/src/js/views/form_widgets.js b/addons/web/static/src/js/views/form_widgets.js
index 0757f581457..5f7e9afdf34 100644
--- a/addons/web/static/src/js/views/form_widgets.js
+++ b/addons/web/static/src/js/views/form_widgets.js
@@ -1439,18 +1439,18 @@ var FieldMonetary = FieldFloat.extend({
init: function() {
this._super.apply(this, arguments);
this.set({"currency": false});
- if (this.options.currency_field) {
- this.field_manager.on("field_changed:" + this.options.currency_field, this, function() {
- this.set({"currency": this.field_manager.get_field_value(this.options.currency_field)});
+ var currency_field = (this.options && this.options.currency_field) || this.currency_field || 'currency_id';
+ if (currency_field) {
+ this.field_manager.on("field_changed:" + currency_field, this, function() {
+ this.set({"currency": this.field_manager.get_field_value(currency_field)});
});
}
this.on("change:currency", this, this.get_currency_info);
this.get_currency_info();
- this.ci_dm = new utils.DropMisordered();
},
start: function() {
var tmp = this._super();
- this.on("change:currency_info", this, this.reinitialize);
+ this.on("change:currency_info", this, this.update);
return tmp;
},
get_currency_info: function() {
@@ -1459,16 +1459,23 @@ var FieldMonetary = FieldFloat.extend({
this.set({"currency_info": null});
return;
}
- return this.ci_dm.add(self.alive(new Model("res.currency").query(["symbol", "position"])
- .filter([["id", "=", self.get("currency")]]).first())).then(function(res) {
- self.set({"currency_info": res});
- });
+ return self.set({"currency_info": session.get_currency(self.get("currency"))});
+ },
+ update: function() {
+ if (this.view.options.is_list_editable){
+ return;
+ } else {
+ return this.reinitialize();
+ }
},
+ get_digits_precision: function() {
+ return this.node.attrs.digits || this.field.digits || (this.get('currency_info') && this.get('currency_info').digits);
+ },
parse_value: function(val, def) {
- return formats.parse_value(val, {type: "float", digits: (this.node.attrs || {}).digits || this.field.digits}, def);
+ return formats.parse_value(val, {type: "float", digits: this.get_digits_precision()}, def);
},
format_value: function(val, def) {
- return formats.format_value(val, {type: "float", digits: (this.node.attrs || {}).digits || this.field.digits}, def);
+ return formats.format_value(val, {type: "float", digits: this.get_digits_precision()}, def);
},
});
diff --git a/addons/web/static/src/js/views/graph_view.js b/addons/web/static/src/js/views/graph_view.js
index fd0120b6f2f..3d3e2e649d6 100644
--- a/addons/web/static/src/js/views/graph_view.js
+++ b/addons/web/static/src/js/views/graph_view.js
@@ -82,7 +82,7 @@ var GraphView = View.extend({
this.fields = fields;
_.each(fields, function (field, name) {
if ((name !== 'id') && (field.store === true)) {
- if (field.type === 'integer' || field.type === 'float') {
+ if (field.type === 'integer' || field.type === 'float' || field.type === 'monetary') {
self.measures[name] = field;
}
}
diff --git a/addons/web/static/src/js/views/list_view.js b/addons/web/static/src/js/views/list_view.js
index 031abfe13a3..44ed786e979 100644
--- a/addons/web/static/src/js/views/list_view.js
+++ b/addons/web/static/src/js/views/list_view.js
@@ -1820,7 +1820,7 @@ var Column = Class.extend({
return out;
},
to_aggregate: function () {
- if (this.type !== 'integer' && this.type !== 'float') {
+ if (this.type !== 'integer' && this.type !== 'float' && this.type !== 'monetary') {
return {};
}
var aggregation_func = this['group_operator'] || 'sum';
@@ -2060,6 +2060,26 @@ var ColumnUrl = Column.extend({
}
});
+var ColumnMonetary = Column.extend({
+
+ _format: function (row_data, options) {
+ //name of currency field is defined either by field attribute, in view options or we assume it is named currency_id
+ var currency_field = (this.options && this.options.currency_field) || this.currency_field || 'currency_id';
+ var currency_id = row_data[currency_field] && row_data[currency_field].value[0];
+ var currency = session.get_currency(currency_id);
+ var digits_precision = this.digits || (currency && currency.digits);
+ var value = formats.format_value(row_data[this.id].value || 0, {type: this.type, digits: digits_precision}, options.value_if_empty);
+ if (currency) {
+ if (currency.position === "after") {
+ value += ' ' + currency.symbol;
+ } else {
+ value = currency.symbol + ' ' + value;
+ }
+ }
+ return value;
+ },
+});
+
var ColumnToggleButton = Column.extend({
format: function (row_data, options) {
this._super(row_data, options);
@@ -2100,7 +2120,8 @@ list_widget_registry
.add('field.reference', ColumnReference)
.add('field.many2many', ColumnMany2Many)
.add('field.url', ColumnUrl)
- .add('button.toggle_button', ColumnToggleButton);
+ .add('button.toggle_button', ColumnToggleButton)
+ .add('field.monetary', ColumnMonetary);
function for_ (id, field, node) {
var description = _.extend({tag: node.tag}, field, node.attrs);
diff --git a/addons/web/static/src/js/views/list_view_editable.js b/addons/web/static/src/js/views/list_view_editable.js
index 48e75c76090..023cfed381e 100644
--- a/addons/web/static/src/js/views/list_view_editable.js
+++ b/addons/web/static/src/js/views/list_view_editable.js
@@ -45,6 +45,7 @@ var Editor = Widget.extend({
this.form = new (this.options.formView)(
this, this.delegate.dataset, false, {
initial_mode: 'edit',
+ is_list_editable: true,
disable_autofocus: true,
$buttons: $(),
$pager: $()
diff --git a/addons/web/static/src/js/views/pivot_view.js b/addons/web/static/src/js/views/pivot_view.js
index 47883175342..1b55895d847 100644
--- a/addons/web/static/src/js/views/pivot_view.js
+++ b/addons/web/static/src/js/views/pivot_view.js
@@ -173,7 +173,7 @@ var PivotView = View.extend({
this.fields = fields;
_.each(fields, function (field, name) {
if ((name !== 'id') && (field.store === true)) {
- if (field.type === 'integer' || field.type === 'float') {
+ if (field.type === 'integer' || field.type === 'float' || field.type === 'monetary') {
self.measures[name] = field;
}
if (_.contains(groupable_types, field.type)) {
diff --git a/addons/web/static/src/js/views/search_filters.js b/addons/web/static/src/js/views/search_filters.js
index 287e7932639..0409fa90a0d 100644
--- a/addons/web/static/src/js/views/search_filters.js
+++ b/addons/web/static/src/js/views/search_filters.js
@@ -300,6 +300,7 @@ core.search_filters_registry
.add('date', ExtendedSearchProposition.Date)
.add('integer', ExtendedSearchProposition.Integer)
.add('float', ExtendedSearchProposition.Float)
+ .add('monetary', ExtendedSearchProposition.Float)
.add('boolean', ExtendedSearchProposition.Boolean)
.add('selection', ExtendedSearchProposition.Selection)
.add('id', ExtendedSearchProposition.Id);
diff --git a/addons/web/static/src/js/views/search_inputs.js b/addons/web/static/src/js/views/search_inputs.js
index a89fa976a74..16f95340dd6 100644
--- a/addons/web/static/src/js/views/search_inputs.js
+++ b/addons/web/static/src/js/views/search_inputs.js
@@ -718,6 +718,7 @@ core.search_widgets_registry
.add('integer', IntegerField)
.add('id', IntegerField)
.add('float', FloatField)
+ .add('monetary', FloatField)
.add('selection', SelectionField)
.add('datetime', DateTimeField)
.add('date', DateField)
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 4338624a67b..c3316d0b413 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -676,7 +676,7 @@
t-if="!field.attrs.modifiers.tree_invisible"
t-att-data-id="record.id"
t-att-style="color_for(record) + style "
- t-attf-class="#{class} #{rank} #{(fields[field.attrs.name].type === 'float') or (fields[field.attrs.name].type === 'integer') ? 'oe_number' : ''}">
+ t-attf-class="#{class} #{rank} #{(fields[field.attrs.name].type === 'float') or (fields[field.attrs.name].type === 'integer') or (fields[field.attrs.name].type === 'monetary')? 'oe_number' : ''}">
<span t-if="!field.attrs.modifiers.invisible" >
<t t-esc="render(record[field.attrs.name], fields[field.attrs.name])" />
@@ -756,7 +756,7 @@
<input t-if="!options.radio" type="checkbox" name="radiogroup" t-att-checked="checked"/>
</th>
<t t-foreach="columns" t-as="column">
- <t t-set="number" t-value="column.type === 'integer' or column.type == 'float'"/>
+ <t t-set="number" t-value="column.type === 'integer' or column.type == 'float' or column.type == 'monetary'"/>
<t t-set="modifiers" t-value="column.modifiers_for(asData)"/>
<td t-if="!column.meta and column.invisible !== '1'" t-att-title="column.help"
t-attf-class="oe_list_field_cell oe_list_field_#{column.widget or column.type} #{number ? 'oe_number' : ''} #{column.tag === 'button' ? 'oe-button' : ''} #{modifiers.readonly ? 'oe_readonly' : ''} #{modifiers.required ? 'oe_required' : ''}"