Activity log for bug #1018908

Date Who What changed Old value New value Message
2012-06-28 16:03:33 Xavier Fernandez http://www.smile.fr bug added bug
2012-06-28 16:03:52 Xavier Fernandez http://www.smile.fr description This is quite a tricky bug that 2 fields.function stored in database, linked with a 'multi' argument and of two different types: integer and many2one. Something like that: _columns = { 'm2o_field_id': fields.function(_get_infos, method=True, type='many2one', relation='some.object', string='some string', store=True), 'integer_field': fields.function(_get_infos, method=True, type='integer', string='some other string', store=True), } Lets say, _store_set_values(self, cr, uid, ids, fields, context):" is called with fields= ['m2o_field_id', 'integer_field'], ids = [my_id] in orm.py, line 3824, you have: todo = {} keys = [] for f in fields: if self._columns[f]._multi not in keys: keys.append(self._columns[f]._multi) todo.setdefault(self._columns[f]._multi, []) todo[self._columns[f]._multi].append(f) for key in keys: val = todo[key] if key: # uid == 1 for accessing objects having rules defined on store fields result = self._columns[val[0]].get(cr, self, ids, val, 1, context=context) so val will contain either ['m2o_field_id', 'integer_field'] or ['integer_field', 'm2o_field_id'] depending on the order they are called and the fields.get function will be called with val[0] which is either an integer field or a many2one field. Now if you go to the get function of fields.function, you have this type of code: fields.py, line 817 if self._type == "many2one" : # Filtering only integer/long values if passed res_ids = [x for x in res.values() if x and isinstance(x, (int,long))] if res_ids: obj_model = obj.pool.get(self._obj) dict_names = dict(obj_model.name_get(cr, user, res_ids, context)) for r in res.keys(): if res[r] and res[r] in dict_names: res[r] = (res[r], dict_names[res[r]]) if self._type == "integer": for r in res.keys(): # Converting value into string so that it does not affect XML-RPC Limits if isinstance(res[r],dict): # To treat integer values with _multi attribute for record in res[r].keys(): res[r][record] = str(res[r][record]) else: res[r] = str(res[r]) Either way, the function _get_infos will return something like that: {my_id:{ 'integer_field': 200, 'm2o_field_id': 42, }} but the result in _store_set_values will have either (depending on the order): - if val[0] is a many2one: result ={my_id:{ 'integer_field': 200, 'm2o_field_id': 42, }} (no_action) or - if val[0] is an integer: result ={my_id:{ 'integer_field': '200', 'm2o_field_id': '42', }} (integer field transforms into string) And in _store_set_values, you have: in orm.py, line 3834 for id, value in result.items(): #some code for v in value: if v not in val: continue if self._columns[v]._type in ('many2one', 'one2one'): try: value[v] = value[v][0] except: pass So we will store either: { 'integer_field': 200, 'm2o_field_id': 42, } => OK or { 'integer_field': '200', 'm2o_field_id': '4', #instead of 42 } => KO depending on the order... server 6.0, revno 3626 This is quite a tricky bug that requires 2 fields.function stored in database, linked with a 'multi' argument and of two different types: integer and many2one. Something like that: _columns = {   'm2o_field_id': fields.function(_get_infos, method=True, type='many2one', relation='some.object', string='some string', store=True),   'integer_field': fields.function(_get_infos, method=True, type='integer', string='some other string', store=True), } Lets say, _store_set_values(self, cr, uid, ids, fields, context):" is called with fields= ['m2o_field_id', 'integer_field'], ids = [my_id] in orm.py, line 3824, you have:         todo = {}         keys = []         for f in fields:             if self._columns[f]._multi not in keys:                 keys.append(self._columns[f]._multi)             todo.setdefault(self._columns[f]._multi, [])             todo[self._columns[f]._multi].append(f)         for key in keys:             val = todo[key]             if key:                 # uid == 1 for accessing objects having rules defined on store fields                 result = self._columns[val[0]].get(cr, self, ids, val, 1, context=context) so val will contain either ['m2o_field_id', 'integer_field'] or ['integer_field', 'm2o_field_id'] depending on the order they are called and the fields.get function will be called with val[0] which is either an integer field or a many2one field. Now if you go to the get function of fields.function, you have this type of code: fields.py, line 817         if self._type == "many2one" :             # Filtering only integer/long values if passed             res_ids = [x for x in res.values() if x and isinstance(x, (int,long))]             if res_ids:                 obj_model = obj.pool.get(self._obj)                 dict_names = dict(obj_model.name_get(cr, user, res_ids, context))                 for r in res.keys():                     if res[r] and res[r] in dict_names:                         res[r] = (res[r], dict_names[res[r]])         if self._type == "integer":             for r in res.keys():                 # Converting value into string so that it does not affect XML-RPC Limits                 if isinstance(res[r],dict): # To treat integer values with _multi attribute                     for record in res[r].keys():                         res[r][record] = str(res[r][record])                 else:                     res[r] = str(res[r]) Either way, the function _get_infos will return something like that: {my_id:{ 'integer_field': 200, 'm2o_field_id': 42, }} but the result in _store_set_values will have either (depending on the order): - if val[0] is a many2one: result ={my_id:{ 'integer_field': 200, 'm2o_field_id': 42, }} (no_action) or - if val[0] is an integer: result ={my_id:{ 'integer_field': '200', 'm2o_field_id': '42', }} (integer field transforms into string) And in _store_set_values, you have: in orm.py, line 3834 for id, value in result.items(): #some code     for v in value:         if v not in val:             continue         if self._columns[v]._type in ('many2one', 'one2one'):             try:                 value[v] = value[v][0]             except:                 pass So we will store either: { 'integer_field': 200, 'm2o_field_id': 42, } => OK or { 'integer_field': '200', 'm2o_field_id': '4', #instead of 42 } => KO depending on the order... server 6.0, revno 3626
2012-06-28 16:33:17 Xavier Fernandez http://www.smile.fr bug added subscriber Corentin Pouhet-Brunerie - http://www.Smile.fr
2012-06-28 16:33:37 Xavier Fernandez http://www.smile.fr bug added subscriber Sam http://www.smile.fr
2012-08-20 10:33:51 Vinay Rana (OpenERP) openobject-server: assignee OpenERP Publisher's Warranty Team (openerp-opw)
2012-08-20 10:35:00 Vinay Rana (OpenERP) tags maintenance
2012-08-27 15:40:55 Olivier Dony (Odoo) openobject-server: importance Undecided Low
2012-08-27 15:40:55 Olivier Dony (Odoo) openobject-server: status New In Progress
2012-08-27 15:40:55 Olivier Dony (Odoo) openobject-server: milestone 6.0.4
2012-08-27 15:42:39 Olivier Dony (Odoo) attachment added opw_578249.patch https://bugs.launchpad.net/openobject-server/+bug/1018908/+attachment/3279225/+files/opw_578249.patch
2012-08-29 08:51:02 Launchpad Janitor branch linked lp:~openerp-dev/openobject-server/6.0-opw-578249-rha
2012-08-29 11:47:25 Rifakat Husen (OpenERP) openobject-server: status In Progress Fix Committed