From aefa8b8c65b6627b02678d2cbd74c95722f93203 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sun, 13 Nov 2011 23:30:56 +0100 Subject: [PATCH] [IMP] Allows to put a view argument in a YAML record and OpenERP will call all the on_change and default_get correctly. This increases a lot the coverage and reduce lines of test to develop. Put the XML_ID of the view of False so that OpenERP will find the first form view itself. Example to create a PO with all on_change: !record {model: purchase.order, id: purchase_new, view: False}: partner_id: base.res_partner_asus order_line: - product_id: product.product_product_pc1 product_qty: 5.0 bzr revid: fp@tinyerp.com-20111113223056-g65pf5vzg7dwkks1 --- openerp/tools/yaml_import.py | 88 ++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 8 deletions(-) diff --git a/openerp/tools/yaml_import.py b/openerp/tools/yaml_import.py index 91cdda1b896..78dadfa3c11 100644 --- a/openerp/tools/yaml_import.py +++ b/openerp/tools/yaml_import.py @@ -11,6 +11,8 @@ import misc from config import config import yaml_tag import yaml +import re +from lxml import etree # YAML import needs both safe and unsafe eval, but let's # default to /safe/. @@ -164,9 +166,11 @@ class YamlInterpreter(object): self.logger.log(logging.ERROR, 'id: %s is to long (max: 64)', id) def get_id(self, xml_id): - if not xml_id: - raise YamlImportException("The xml_id should be a non empty string.") - if isinstance(xml_id, types.IntType): + if xml_id is False: + return False + #if not xml_id: + # raise YamlImportException("The xml_id should be a non empty string.") + elif isinstance(xml_id, types.IntType): id = xml_id elif xml_id in self.id_map: id = self.id_map[xml_id] @@ -307,6 +311,11 @@ class YamlInterpreter(object): import openerp.osv as osv record, fields = node.items()[0] model = self.get_model(record.model) + + view_id = record.view + if record.view: + view_id = self.pool.get('ir.model.data')._get_id(self.cr, 1, self.module, record.view) + if model.is_transient(): record_dict=self.create_osv_memory_record(record, fields) else: @@ -321,22 +330,85 @@ class YamlInterpreter(object): if not self._coerce_bool(record.forcecreate): return None - record_dict = self._create_record(model, fields) - self.logger.debug("RECORD_DICT %s" % record_dict) + #context = self.get_context(record, self.eval_context) context = record.context #TOFIX: record.context like {'withoutemployee':True} should pass from self.eval_context. example: test_project.yml in project module + if view_id is not None: + view = model.fields_view_get(self.cr, 1, view_id, 'form', context) + view_id = etree.fromstring(view['arch'].encode('utf-8')) + + record_dict = self._create_record(model, fields, view_id) + self.logger.debug("RECORD_DICT %s" % record_dict) id = self.pool.get('ir.model.data')._update(self.cr, 1, record.model, \ self.module, record_dict, record.id, noupdate=self.isnoupdate(record), mode=self.mode, context=context) self.id_map[record.id] = int(id) if config.get('import_partial'): self.cr.commit() - def _create_record(self, model, fields): + def _create_record(self, model, fields, view=None, parent={}): + allfields = model.fields_get(self.cr, 1, context=self.context) + defaults = model.default_get(self.cr, 1, allfields, context=self.context) record_dict = {} fields = fields or {} + fg = model.fields_get(self.cr, 1, context=self.context) + + # Process all on_change calls + nodes = view and [view] or [] + while nodes: + el = nodes.pop(0) + if el.tag=='field': + field_name = el.attrib['name'] + if field_name in fields: + view2 = None + # if the form view is not inline, we call fields_view_get + if (fg[field_name]['type']=='one2many') and view: + view2 = view.find("field[@name='%s']/form"%(field_name,)) + if not view2: + view2 = self.pool.get(fg[field_name]['relation']).fields_view_get(self.cr, 1, False, 'form', self.context) + view2 = etree.fromstring(view2['arch'].encode('utf-8')) + + field_value = self._eval_field(model, field_name, fields[field_name], view2, parent=record_dict) + record_dict[field_name] = field_value + elif (field_name in defaults) and (field_name not in record_dict): + record_dict[field_name] = defaults[field_name] + else: + continue + + if not el.attrib.get('on_change', False): + continue + match = re.match("([a-z_1-9A-Z]+)\((.*)\)", el.attrib['on_change']) + assert match, "Unable to parse the on_change '%s'!" % (el.attrib['on_change'], ) + + # creating the context + class parent2(object): + def __init__(self, d): + self.d = d + def __getattr__(self, name): + return self.d.get(name, False) + + ctx = record_dict.copy() + ctx['context'] = self.context + ctx['uid'] = 1 + ctx['parent'] = parent2(parent) + for a in fg: + if a not in ctx: + ctx[a]=False + + # Evaluation args + args = map(lambda x: eval(x, ctx), match.group(2).split(',')) + result = getattr(model, match.group(1))(self.cr, 1, [], *args) + for key, val in result.get('value', {}).items(): + if key not in fields: + record_dict[key] = val + else: + nodes = list(el) + nodes + for field_name, expression in fields.items(): + if field_name in record_dict: + continue field_value = self._eval_field(model, field_name, expression) record_dict[field_name] = field_value + return record_dict def process_ref(self, node, column=None): @@ -365,7 +437,7 @@ class YamlInterpreter(object): def process_eval(self, node): return eval(node.expression, self.eval_context) - def _eval_field(self, model, field_name, expression): + def _eval_field(self, model, field_name, expression, view=None, parent={}): # TODO this should be refactored as something like model.get_field() in bin/osv if field_name in model._columns: column = model._columns[field_name] @@ -386,7 +458,7 @@ class YamlInterpreter(object): value = self.get_id(expression) elif column._type == "one2many": other_model = self.get_model(column._obj) - value = [(0, 0, self._create_record(other_model, fields)) for fields in expression] + value = [(0, 0, self._create_record(other_model, fields, view, parent)) for fields in expression] elif column._type == "many2many": ids = [self.get_id(xml_id) for xml_id in expression] value = [(6, 0, ids)]