From 38067dffc9be8a14010118132c622f3749a7edc0 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 17 Oct 2012 12:28:21 +0200 Subject: [PATCH 1/5] [FIX] osv/orm: compute the _fct_inv() of stored functional fields at the record creation. Compute also the _fct_inv() of related fields (because there is no reason not to do it). That last patch revert a 'fix' of lp bug 544087 introduced in revision 4182, i don't get the purpose of it but that bug is not repdocutible anymore... bzr revid: qdp-launchpad@openerp.com-20121017102821-tjx7gqiz86v7sn54 --- openerp/osv/orm.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 62d12ef20ee..1db2feeca88 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -4357,9 +4357,12 @@ class BaseModel(object): upd0 = upd0 + ',"' + field + '"' upd1 = upd1 + ',' + self._columns[field]._symbol_set[0] upd2.append(self._columns[field]._symbol_set[1](vals[field])) - else: - if not isinstance(self._columns[field], fields.related): + #for the function fields that receive a value, we set them directly in the database + #(they may be required), but we also need to trigger the _fct_inv() + if (hasattr(self._columns[field], '_fnct_inv')): upd_todo.append(field) + else: + upd_todo.append(field) if field in self._columns \ and hasattr(self._columns[field], 'selection') \ and vals[field]: From ece82902a45bc3c503f1071a831903aec92553c8 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Thu, 18 Oct 2012 09:27:33 +0200 Subject: [PATCH 2/5] [TEST] attempt to detect what the hell that crazy bug is coming from bzr revid: qdp-launchpad@openerp.com-20121018072733-78g195u6yeq0m7jj --- openerp/osv/orm.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 62d12ef20ee..13d508d48a3 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -4358,8 +4358,7 @@ class BaseModel(object): upd1 = upd1 + ',' + self._columns[field]._symbol_set[0] upd2.append(self._columns[field]._symbol_set[1](vals[field])) else: - if not isinstance(self._columns[field], fields.related): - upd_todo.append(field) + upd_todo.append(field) if field in self._columns \ and hasattr(self._columns[field], 'selection') \ and vals[field]: From 536cb8775c7f5511f7e70595c19a0260dfbc1937 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Thu, 18 Oct 2012 20:43:23 +0200 Subject: [PATCH 3/5] [TEST] removing values at record creation in yaml bzr revid: qdp-launchpad@openerp.com-20121018184323-5kq9fb54slij3ioo --- openerp/tools/yaml_import.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/openerp/tools/yaml_import.py b/openerp/tools/yaml_import.py index 7e1c7152b0f..1a81db949ee 100644 --- a/openerp/tools/yaml_import.py +++ b/openerp/tools/yaml_import.py @@ -425,7 +425,19 @@ class YamlInterpreter(object): continue field_value = self._eval_field(model, field_name, expression, default=False) record_dict[field_name] = field_value - + if 'line_cr_ids' in record_dict and record_dict['line_cr_ids']: + for item in record_dict['line_cr_ids']: + if item[2] and 'date_original' in item[2]: + del(item[2]['date_original']) + if item[2] and 'date_original' in item[2]: + del(item[2]['date_due']) + if 'line_dr_ids' in record_dict and record_dict['line_dr_ids']: + for item in record_dict['line_dr_ids']: + if item[2] and 'date_original' in item[2]: + del(item[2]['date_original']) + if item[2] and 'date_original' in item[2]: + del(item[2]['date_due']) + print "ICICICICICICI", record_dict return record_dict def process_ref(self, node, column=None): From 820c2551bba2332677e64899950c53ed9f0e4b1d Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Fri, 19 Oct 2012 13:06:04 +0200 Subject: [PATCH 4/5] [IMP] tools, yaml_import: the values given to the creation should only include the fields that aren't readonly in the view. Because that's what clients do bzr revid: qdp-launchpad@openerp.com-20121019110604-1gvfcgqvwd1izh71 --- openerp/tools/yaml_import.py | 56 +++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/openerp/tools/yaml_import.py b/openerp/tools/yaml_import.py index 1a81db949ee..501ab30d879 100644 --- a/openerp/tools/yaml_import.py +++ b/openerp/tools/yaml_import.py @@ -330,7 +330,7 @@ class YamlInterpreter(object): def _create_record(self, model, fields, view_info=False, parent={}, default=True): """This function processes the !record tag in yalm files. It simulates the record creation through an xml view (either specified on the !record tag or the default one for this object), including the calls to - on_change() functions. + on_change() functions, and sending only values for fields that aren't set as readonly. :param model: model instance :param fields: dictonary mapping the field names and their values :param view_info: result of fields_view_get() called on the object @@ -339,6 +339,13 @@ class YamlInterpreter(object): :return: dictionary mapping the field names and their values, ready to use when calling the create() function :rtype: dict """ + def _get_right_one2many_view(fg, field_name, view_type): + one2many_view = fg[field_name]['views'].get(view_type) + # if the view is not defined inline, we call fields_view_get() + if not one2many_view: + one2many_view = self.pool.get(fg[field_name]['relation']).fields_view_get(self.cr, SUPERUSER_ID, False, view_type, self.context) + return one2many_view + def process_val(key, val): if fg[key]['type']=='many2one': if type(val) in (tuple,list): @@ -347,7 +354,28 @@ class YamlInterpreter(object): if val is False: val = [] if len(val) and type(val[0]) == dict: + #we want to return only the fields that aren't readonly + #For that, we need to first get the right tree view to consider for the field `key´ + one2many_tree_view = _get_right_one2many_view(fg, key, 'tree') + for rec in val: + #make a copy for the iteration, as we will alterate the size of `rec´ dictionary + rec_copy = rec.copy() + for field_key in rec_copy: + #seek in the view for the field `field_key´ and removing it from `key´ values, as this column is readonly in the tree view + subfield_obj = etree.fromstring(one2many_tree_view['arch'].encode('utf-8')).xpath("//field[@name='%s']"%(field_key)) + if subfield_obj and (subfield_obj[0].get('modifiers', '{}').find('"readonly": true') >= 0): + #TODO: currently we only support if readonly is True in the modifiers. Some improvement may be done in + #order to support also modifiers that look like {"readonly": [["state", "not in", ["draft", "confirm"]]]} + del(rec[field_key]) + + #now that unwanted values have been removed from val, we can encapsulate it in a tuple as returned value val = map(lambda x: (0,0,x), val) + + #we want to return only the fields that aren't readonly + if el.get('modifiers', '{}').find('"readonly": true') >= 0: + #TODO: currently we only support if readonly is True in the modifiers. Some improvement may be done in + #order to support also modifiers that look like {"readonly": [["state", "not in", ["draft", "confirm"]]]} + return False return val view = view_info and etree.fromstring(view_info['arch'].encode('utf-8')) or False @@ -373,13 +401,14 @@ class YamlInterpreter(object): one2many_form_view = None if (view is not False) and (fg[field_name]['type']=='one2many'): # for one2many fields, we want to eval them using the inline form view defined on the parent - one2many_form_view = view_info['fields'][field_name]['views'].get('form') - # if the form view is not defined inline, we call fields_view_get() - if not one2many_form_view: - one2many_form_view = self.pool.get(fg[field_name]['relation']).fields_view_get(self.cr, SUPERUSER_ID, False, 'form', self.context) + one2many_form_view = _get_right_one2many_view(fg, field_name, 'form') field_value = self._eval_field(model, field_name, fields[field_name], one2many_form_view or view_info, parent=record_dict, default=default) - record_dict[field_name] = field_value + + #call process_val to not update record_dict if values were given for readonly fields + val = process_val(field_name, field_value) + if val: + record_dict[field_name] = val #if (field_name in defaults) and defaults[field_name] == field_value: # print '*** You can remove these lines:', field_name, field_value @@ -405,7 +434,7 @@ class YamlInterpreter(object): ctx['parent'] = parent2(parent) for a in fg: if a not in ctx: - ctx[a]=process_val(a, defaults.get(a, False)) + ctx[a] = process_val(a, defaults.get(a, False)) # Evaluation args args = map(lambda x: eval(x, ctx), match.group(2).split(',')) @@ -425,19 +454,6 @@ class YamlInterpreter(object): continue field_value = self._eval_field(model, field_name, expression, default=False) record_dict[field_name] = field_value - if 'line_cr_ids' in record_dict and record_dict['line_cr_ids']: - for item in record_dict['line_cr_ids']: - if item[2] and 'date_original' in item[2]: - del(item[2]['date_original']) - if item[2] and 'date_original' in item[2]: - del(item[2]['date_due']) - if 'line_dr_ids' in record_dict and record_dict['line_dr_ids']: - for item in record_dict['line_dr_ids']: - if item[2] and 'date_original' in item[2]: - del(item[2]['date_original']) - if item[2] and 'date_original' in item[2]: - del(item[2]['date_due']) - print "ICICICICICICI", record_dict return record_dict def process_ref(self, node, column=None): From e6e4e8d4c102f477c95415154a1411be54126f2a Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 22 Oct 2012 14:31:00 +0200 Subject: [PATCH 5/5] [REV] osv/orm: revert of a previous patch that was unifying the behavior for fields.related and fields.function at creation time because it's a bit dangereous to treat it right now, and may need the add of a new field attribute. "I'll be back", said the patch bzr revid: qdp-launchpad@openerp.com-20121022123100-wwr7lnmpqebddxon --- openerp/osv/orm.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 1db2feeca88..4c3330c97b7 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -4359,10 +4359,20 @@ class BaseModel(object): upd2.append(self._columns[field]._symbol_set[1](vals[field])) #for the function fields that receive a value, we set them directly in the database #(they may be required), but we also need to trigger the _fct_inv() - if (hasattr(self._columns[field], '_fnct_inv')): + if (hasattr(self._columns[field], '_fnct_inv')) and not isinstance(self._columns[field], fields.related): + #TODO: this way to special case the related fields is really creepy but it shouldn't be changed at + #one week of the release candidate. It seems the only good way to handle correctly this is to add an + #attribute to make a field `really readonly´ and thus totally ignored by the create()... otherwise + #if, for example, the related has a default value (for usability) then the fct_inv is called and it + #may raise some access rights error. Changing this is a too big change for now, and is thus postponed + #after the release but, definitively, the behavior shouldn't be different for related and function + #fields. upd_todo.append(field) else: - upd_todo.append(field) + #TODO: this `if´ statement should be removed because there is no good reason to special case the fields + #related. See the above TODO comment for further explanations. + if not isinstance(self._columns[field], fields.related): + upd_todo.append(field) if field in self._columns \ and hasattr(self._columns[field], 'selection') \ and vals[field]: