From 4dc731f99c4ee5ad90635f09b0eb70c2025e151d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 13 Oct 2011 13:27:55 +0200 Subject: [PATCH] [FIX] BufferedDataSet to not break the m2o read contract of returning a name_get format BufferedDataSet simply shoves stuff read() or create()d in its cache, but m2o is asymmetric: client writes a single id, but reads a pair of [id, name]. Since create() and write() are async (by definition) it's the best place to check if the data being written contains any m2o field, and to fix those m2o values. bzr revid: xmo@openerp.com-20111013112755-krf9y5w232ol6r1e --- addons/web/static/src/js/data.js | 132 +++++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 31 deletions(-) diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index ea0824fb1df..0906a26050e 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -610,44 +610,114 @@ 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); + }); + $.when.apply(null, name_gets).then(function () { + var record = _.extend({}, data); + for(var i=0; i