diff options
| author | Xavier Morel <xmo@openerp.com> | 2011-10-13 14:49:12 +0200 |
|---|---|---|
| committer | Xavier Morel <xmo@openerp.com> | 2011-10-13 14:49:12 +0200 |
| commit | 1635fcc56804cbfcbd7ec954d83b6b554027ba6c (patch) | |
| tree | 9fca5139997d18ef9cc9171339fed6602c6fc04b /addons/web/static/src/js/data.js | |
| parent | ce6c86ccc8134c56861b43b9c8b68be5ec13b1be (diff) | |
| parent | 88314e523a85ee2fcbfeedf84e8d4b3f9dedb51b (diff) | |
[FIX] incorrect BufferedDataSet behavior when reading an m2o field in cache coming from an edition (or creation), inconsistent with OpenERP m2o field read() contract
when read, m2o should really be pairs, or they're pain to display. Because Dataset.create and Dataset.write are async, perform name_get resolution during these and store the correct value in cache
bzr revid: xmo@openerp.com-20111013124912-wton5lidyvaezsj6
Diffstat (limited to 'addons/web/static/src/js/data.js')
| -rw-r--r-- | addons/web/static/src/js/data.js | 136 |
1 files changed, 106 insertions, 30 deletions
diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index ea0824fb1df..dd121ed9db7 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -610,44 +610,120 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({ on_default_get: function(res) { this.last_default_get = res; }, + /** + * Makes sure this dataset has the fields_get for its model stored locally, + * so create/write methods are able to determine if written fields are m2os + * and can name_get those fields if that's the case (in order to cache a + * correct m2o value for them) + * + * @returns {$.Deferred} whether the fields_get is done executing, provides the fields_get value to its callbacks + */ + ensure_has_fields: function () { + var self = this; + + if (this.fields_get) { + var d = $.Deferred(); + setTimeout(function () { d.resolve(self.fields_get, true); }, 0); + return d.promise(); + } else { + return self.call('fields_get', [], function (fields_get) { + self.fields_get = fields_get; + }); + } + }, + /** + * Relational fields may not be written in the same format they are read. + * + * Since the BufferedDataSet is a bit dumb, it returns what it's got stored + * in its cache, which for modified value is what it was given. This breaks + * some basic contracts of openerp such as m2o read being in the + * ``name_get`` format. + * + * Because create & write are supposed to be asynchronous, though, it + * should be easy to just name_get all incorrect values. + * + * @param {Object} data form-data to write to the cache + * @returns {$.Deferred} resolved with a fixed data dictionary + */ + fix_relational: function (data) { + var self = this; + var results = $.Deferred(); + this.ensure_has_fields().then(function (fields) { + var fields_to_fix = _(fields).chain() + .map(function (d, k) { return {key: k, descriptor: d}; }) + .filter(function (field) { + // keep m2o fields which are in the data dict + return field.descriptor.type === 'many2one' && + field.key in data; + }).pluck('key') + .value(); + var name_gets = _(fields_to_fix).map(function (field) { + return new openerp.web.DataSet(self, self.fields_get[field].relation) + .name_get([data[field]], null); + }); + // null-concat forces stupid bastard `when` to always return an + // array containing the Array-ified results of all the name_gets. + // otherwise, if there's a single field to fix it returns the + // results of the unique name_get directly. + $.when.apply(null, name_gets.concat([null])).then(function () { + var record = _.extend({}, data); + for(var i=0; i<fields_to_fix.length; ++i) { + // Each argument is [[name_get], success, jqXhr] and we + // want just the name_get pair + record[fields_to_fix[i]] = arguments[i][0][0]; + } + results.resolve(record); + }); + }); + return results; + }, create: function(data, callback, error_callback) { - var cached = {id:_.uniqueId(this.virtual_id_prefix), values: data, - defaults: this.last_default_get}; - this.to_create.push(_.extend(_.clone(cached), {values: _.clone(cached.values)})); - this.cache.push(cached); - this.on_change(); + var self = this; var prom = $.Deferred().then(callback); - prom.resolve({result: cached.id}); + this.fix_relational(data).then(function (fixed_m2o_data) { + var cached = { + id:_.uniqueId(self.virtual_id_prefix), + values: fixed_m2o_data, + defaults: self.last_default_get + }; + self.to_create.push(_.extend(_.clone(cached), { + values: _.clone(data)})); + self.cache.push(cached); + self.on_change(); + prom.resolve({result: cached.id}); + }); return prom.promise(); }, write: function (id, data, options, callback) { var self = this; - var record = _.detect(this.to_create, function(x) {return x.id === id;}); - record = record || _.detect(this.to_write, function(x) {return x.id === id;}); - var dirty = false; - if (record) { - for (var k in data) { - if (record.values[k] === undefined || record.values[k] !== data[k]) { - dirty = true; - break; + var to_return = $.Deferred().then(callback); + this.fix_relational(data).then(function (fixed_m2o_data) { + var record = _.detect(self.to_create, function(x) {return x.id === id;}); + record = record || _.detect(self.to_write, function(x) {return x.id === id;}); + var dirty = false; + if (record) { + for (var k in data) { + if (record.values[k] === undefined || record.values[k] !== data[k]) { + dirty = true; + break; + } } + _.extend(record.values, data); + } else { + dirty = true; + record = {id: id, values: data}; + self.to_write.push(record); } - $.extend(record.values, data); - } else { - dirty = true; - record = {id: id, values: data}; - self.to_write.push(record); - } - var cached = _.detect(this.cache, function(x) {return x.id === id;}); - if (!cached) { - cached = {id: id, values: {}}; - this.cache.push(cached); - } - $.extend(cached.values, record.values); - if (dirty) - this.on_change(); - var to_return = $.Deferred().then(callback); - to_return.resolve({result: true}); + var cached = _.detect(self.cache, function(x) {return x.id === id;}); + if (!cached) { + cached = {id: id, values: {}}; + this.cache.push(cached); + } + _.extend(cached.values, fixed_m2o_data); + if (dirty) + self.on_change(); + to_return.resolve({result: true}); + }); return to_return.promise(); }, unlink: function(ids, callback, error_callback) { |
