def process_report(self, node): values = {} for dest, f in (("name", "string"), ("model", "model"), ("report_name", "name")): values[dest] = getattr(node, f) assert values[dest], "Attribute %s of report is empty !" % (f,) for field, dest in ( ("rml", "report_rml"), ("file", "report_rml"), ("xml", "report_xml"), ("xsl", "report_xsl"), ("attachment", "attachment"), ("attachment_use", "attachment_use"), ): if getattr(node, field): values[dest] = getattr(node, field) if node.auto: values["auto"] = eval(node.auto) if node.sxw: sxw_file = misc.file_open(node.sxw) try: sxw_content = sxw_file.read() values["report_sxw_content"] = sxw_content finally: sxw_file.close() if node.header: values["header"] = eval(node.header) values["multi"] = node.multi and eval(node.multi) xml_id = node.id self.validate_xml_id(xml_id) self._set_group_values(node, values) id = self.pool["ir.model.data"]._update( self.cr, SUPERUSER_ID, "ir.actions.report.xml", self.module, values, xml_id, noupdate=self.isnoupdate(node), mode=self.mode, ) self.id_map[xml_id] = int(id) if not node.menu or eval(node.menu): keyword = node.keyword or "client_print_multi" value = "ir.actions.report.xml,%s" % id replace = node.replace or True self.pool["ir.model.data"].ir_set( self.cr, SUPERUSER_ID, "action", keyword, values["name"], [values["model"]], value, replace=replace, isobject=True, xml_id=xml_id, )
def _eval_params(self, model, params): args = [] for i, param in enumerate(params): if isinstance(param, types.ListType): value = self._eval_params(model, param) elif is_ref(param): value = self.process_ref(param) elif is_eval(param): value = self.process_eval(param) elif isinstance(param, types.DictionaryType): # supports XML syntax param_model = self.get_model(param.get('model', model)) if 'search' in param: q = eval(param['search'], self.eval_context) ids = param_model.search(self.cr, self.uid, q) value = self._get_first_result(ids) elif 'eval' in param: local_context = {'obj': lambda x: param_model.browse(self.cr, self.uid, x, self.context)} local_context.update(self.id_map) value = eval(param['eval'], self.eval_context, local_context) else: raise YamlImportException('You must provide either a !ref or at least a "eval" or a "search" to function parameter #%d.' % i) else: value = param # scalar value args.append(value) return args
def _tag_wizard(self, cr, rec, data_node=None): string = rec.get("string",'').encode('utf8') model = rec.get("model",'').encode('utf8') name = rec.get("name",'').encode('utf8') xml_id = rec.get('id','').encode('utf8') self._test_xml_id(xml_id) multi = rec.get('multi','') and eval(rec.get('multi','False')) res = {'name': string, 'wiz_name': name, 'multi': multi, 'model': model} if rec.get('groups'): g_names = rec.get('groups','').split(',') groups_value = [] for group in g_names: if group.startswith('-'): group_id = self.id_get(cr, group[1:]) groups_value.append((3, group_id)) else: group_id = self.id_get(cr, group) groups_value.append((4, group_id)) res['groups_id'] = groups_value id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.wizard", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode) self.idref[xml_id] = int(id) # ir_set if (not rec.get('menu') or eval(rec.get('menu','False'))) and id: keyword = str(rec.get('keyword','') or 'client_action_multi') value = 'ir.actions.wizard,'+str(id) replace = rec.get("replace",'') or True self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, string, [model], value, replace=replace, isobject=True, xml_id=xml_id) elif self.mode=='update' and (rec.get('menu') and eval(rec.get('menu','False'))==False): # Special check for wizard having attribute menu=False on update value = 'ir.actions.wizard,'+str(id) self._remove_ir_values(cr, string, value, model)
def process_report(self, node): values = {} for dest, f in (('name','string'), ('model','model'), ('report_name','name')): values[dest] = getattr(node, f) assert values[dest], "Attribute %s of report is empty !" % (f,) for field,dest in (('rml','report_rml'),('file','report_rml'),('xml','report_xml'),('xsl','report_xsl'),('attachment','attachment'),('attachment_use','attachment_use')): if getattr(node, field): values[dest] = getattr(node, field) if node.auto: values['auto'] = eval(node.auto) if node.sxw: sxw_file = misc.file_open(node.sxw) try: sxw_content = sxw_file.read() values['report_sxw_content'] = sxw_content finally: sxw_file.close() if node.header: values['header'] = eval(node.header) values['multi'] = node.multi and eval(node.multi) xml_id = node.id self.validate_xml_id(xml_id) self._set_group_values(node, values) id = self.pool.get('ir.model.data')._update(self.cr, SUPERUSER_ID, "ir.actions.report.xml", \ self.module, values, xml_id, noupdate=self.isnoupdate(node), mode=self.mode) self.id_map[xml_id] = int(id) if not node.menu or eval(node.menu): keyword = node.keyword or 'client_print_multi' value = 'ir.actions.report.xml,%s' % id replace = node.replace or True self.pool.get('ir.model.data').ir_set(self.cr, SUPERUSER_ID, 'action', \ keyword, values['name'], [values['model']], value, replace=replace, isobject=True, xml_id=xml_id)
def _tag_report(self, cr, rec, data_node=None, mode=None): res = {} for dest,f in (('name','string'),('model','model'),('report_name','name')): res[dest] = rec.get(f,'').encode('utf8') assert res[dest], "Attribute %s of report is empty !" % (f,) for field,dest in (('rml','report_rml'),('file','report_rml'),('xml','report_xml'),('xsl','report_xsl'), ('attachment','attachment'),('attachment_use','attachment_use'), ('usage','usage'), ('report_type', 'report_type'), ('parser', 'parser')): if rec.get(field): res[dest] = rec.get(field).encode('utf8') if rec.get('auto'): res['auto'] = eval(rec.get('auto','False')) if rec.get('sxw'): sxw_content = misc.file_open(rec.get('sxw')).read() res['report_sxw_content'] = sxw_content if rec.get('header'): res['header'] = eval(rec.get('header','False')) res['multi'] = rec.get('multi') and eval(rec.get('multi','False')) xml_id = rec.get('id','').encode('utf8') self._test_xml_id(xml_id) if rec.get('groups'): g_names = rec.get('groups','').split(',') groups_value = [] for group in g_names: if group.startswith('-'): group_id = self.id_get(cr, group[1:]) groups_value.append((3, group_id)) else: group_id = self.id_get(cr, group) groups_value.append((4, group_id)) res['groups_id'] = groups_value if rec.get('paperformat'): pf_name = rec.get('paperformat') pf_id = self.id_get(cr,pf_name) res['paperformat_id'] = pf_id id = self.pool['ir.model.data']._update(cr, self.uid, "ir.actions.report.xml", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode) self.idref[xml_id] = int(id) if not rec.get('menu') or eval(rec.get('menu','False')): keyword = str(rec.get('keyword', 'client_print_multi')) value = 'ir.actions.report.xml,'+str(id) ir_values_id = self.pool['ir.values'].set_action(cr, self.uid, res['name'], keyword, res['model'], value) self.pool['ir.actions.report.xml'].write(cr, self.uid, id, {'ir_values_id': ir_values_id}) elif self.mode=='update' and eval(rec.get('menu','False'))==False: # Special check for report having attribute menu=False on update value = 'ir.actions.report.xml,'+str(id) self._remove_ir_values(cr, res['name'], value, res['model']) self.pool['ir.actions.report.xml'].write(cr, self.uid, id, {'ir_values_id': False}) return id
def process_ref(self, node, field=None): assert node.search or node.id, '!ref node should have a `search` attribute or `id` attribute' if node.search: if node.model: model_name = node.model elif field: model_name = field.comodel_name else: raise YamlImportException('You need to give a model for the search, or a field to infer it.') model = self.get_model(model_name) q = eval(node.search, self.eval_context) ids = model.search(self.cr, self.uid, q) if node.use: instances = model.browse(self.cr, self.uid, ids) value = [inst[node.use] for inst in instances] else: value = ids elif node.id: if field and field.type == 'reference': record = self.get_record(node.id) value = "%s,%s" % (record._name, record.id) else: value = self.get_id(node.id) else: value = None return value
def process_url(self, node): self.validate_xml_id(node.id) res = {"name": node.name, "url": node.url, "target": node.target} id = self.pool["ir.model.data"]._update( self.cr, SUPERUSER_ID, "ir.actions.act_url", self.module, res, node.id, mode=self.mode ) self.id_map[node.id] = int(id) # ir_set if (not node.menu or eval(node.menu)) and id: keyword = node.keyword or "client_action_multi" value = "ir.actions.act_url,%s" % id replace = node.replace or True self.pool["ir.model.data"].ir_set( self.cr, SUPERUSER_ID, "action", keyword, node.url, ["ir.actions.act_url"], value, replace=replace, noupdate=self.isnoupdate(node), isobject=True, xml_id=node.id, )
def process_workflow(self, node): workflow, values = node.items()[0] if self.isnoupdate(workflow) and self.mode != "init": return if workflow.ref: id = self.get_id(workflow.ref) else: if not values: raise YamlImportException("You must define a child node if you do not give a ref.") if not len(values) == 1: raise YamlImportException("Only one child node is accepted (%d given)." % len(values)) value = values[0] if not "model" in value and (not "eval" in value or not "search" in value): raise YamlImportException('You must provide a "model" and an "eval" or "search" to evaluate.') value_model = self.get_model(value["model"]) local_context = {"obj": lambda x: value_model.browse(self.cr, self.uid, x, context=self.context)} local_context.update(self.id_map) id = eval(value["eval"], self.eval_context, local_context) if workflow.uid is not None: uid = workflow.uid else: uid = self.uid self.cr.execute("select distinct signal, sequence, id from wkf_transition ORDER BY sequence,id") signals = [x["signal"] for x in self.cr.dictfetchall()] if workflow.action not in signals: raise YamlImportException("Incorrect action %s. No such action defined" % workflow.action) openerp.workflow.trg_validate(uid, workflow.model, id, workflow.action, self.cr)
def run(self, cr, uid, ids, context=None): "Run fix for 'other' type actions" act_ids = [] for action in self.browse(cr, uid, ids, context): obj_pool = self.pool.get(action.model_id.model) obj = obj_pool.browse(cr, uid, context['active_id'], context=context) cxt = { 'context': context, 'object': obj, 'time': time, 'cr': cr, 'pool': self.pool, 'uid': uid } expr = eval(str(action.condition), cxt) if not expr: continue if action.state == 'other': res = [] for act in action.child_ids: if not context.get('active_id'): context['active_id'] = context['active_ids'][0] result = self.run(cr, uid, [act.id], context) if result: res.append(result) return res else: act_ids.append(action.id) if act_ids: return super(IrActionsServer, self).run(cr, uid, act_ids, context) else: return False
def process_workflow(self, node): workflow, values = node.items()[0] if self.isnoupdate(workflow) and self.mode != 'init': return if workflow.ref: id = self.get_id(workflow.ref) else: if not values: raise YamlImportException('You must define a child node if you do not give a ref.') if not len(values) == 1: raise YamlImportException('Only one child node is accepted (%d given).' % len(values)) value = values[0] if not 'model' in value and (not 'eval' in value or not 'search' in value): raise YamlImportException('You must provide a "model" and an "eval" or "search" to evaluate.') value_model = self.get_model(value['model']) local_context = {'obj': lambda x: value_model.browse(self.cr, self.uid, x, context=self.context)} local_context.update(self.id_map) id = eval(value['eval'], self.eval_context, local_context) if workflow.uid is not None: uid = workflow.uid else: uid = self.uid self.cr.execute('select distinct signal from wkf_transition') signals=[x['signal'] for x in self.cr.dictfetchall()] if workflow.action not in signals: raise YamlImportException('Incorrect action %s. No such action defined' % workflow.action) import openerp.netsvc as netsvc wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, workflow.model, id, workflow.action, self.cr)
def _get_assertion_id(self, assertion): if assertion.id: ids = [self.get_id(assertion.id)] elif assertion.search: q = eval(assertion.search, self.eval_context) ids = self.pool.get(assertion.model).search(self.cr, self.uid, q, context=assertion.context) else: raise YamlImportException('Nothing to assert: you must give either an id or a search criteria.') return ids
def _tag_wizard(self, cr, rec, data_node=None): string = rec.get("string", "").encode("utf8") model = rec.get("model", "").encode("utf8") name = rec.get("name", "").encode("utf8") xml_id = rec.get("id", "").encode("utf8") self._test_xml_id(xml_id) multi = rec.get("multi", "") and eval(rec.get("multi", "False")) res = {"name": string, "wiz_name": name, "multi": multi, "model": model} if rec.get("groups"): g_names = rec.get("groups", "").split(",") groups_value = [] for group in g_names: if group.startswith("-"): group_id = self.id_get(cr, group[1:]) groups_value.append((3, group_id)) else: group_id = self.id_get(cr, group) groups_value.append((4, group_id)) res["groups_id"] = groups_value id = self.pool.get("ir.model.data")._update( cr, self.uid, "ir.actions.wizard", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode, ) self.idref[xml_id] = int(id) # ir_set if (not rec.get("menu") or eval(rec.get("menu", "False"))) and id: keyword = str(rec.get("keyword", "") or "client_action_multi") value = "ir.actions.wizard," + str(id) replace = rec.get("replace", "") or True self.pool.get("ir.model.data").ir_set( cr, self.uid, "action", keyword, string, [model], value, replace=replace, isobject=True, xml_id=xml_id ) elif self.mode == "update" and (rec.get("menu") and eval(rec.get("menu", "False")) == False): # Special check for wizard having attribute menu=False on update value = "ir.actions.wizard," + str(id) self._remove_ir_values(cr, string, value, model)
def process_delete(self, node): assert getattr(node, 'model'), "Attribute %s of delete tag is empty !" % ('model',) if self.pool.get(node.model): if node.search: ids = self.pool.get(node.model).search(self.cr, self.uid, eval(node.search, self.eval_context)) else: ids = [self.get_id(node.id)] if len(ids): self.pool.get(node.model).unlink(self.cr, self.uid, ids) else: self._log("Record not deleted.")
def _tag_url(self, cr, rec, data_node=None): url = rec.get("url", "").encode("utf8") target = rec.get("target", "").encode("utf8") name = rec.get("name", "").encode("utf8") xml_id = rec.get("id", "").encode("utf8") self._test_xml_id(xml_id) res = {"name": name, "url": url, "target": target} id = self.pool.get("ir.model.data")._update( cr, self.uid, "ir.actions.url", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode, ) self.idref[xml_id] = int(id) # ir_set if (not rec.get("menu") or eval(rec.get("menu", "False"))) and id: keyword = str(rec.get("keyword", "") or "client_action_multi") value = "ir.actions.url," + str(id) replace = rec.get("replace", "") or True self.pool.get("ir.model.data").ir_set( cr, self.uid, "action", keyword, url, ["ir.actions.url"], value, replace=replace, isobject=True, xml_id=xml_id, ) elif self.mode == "update" and (rec.get("menu") and eval(rec.get("menu", "False")) == False): # Special check for URL having attribute menu=False on update value = "ir.actions.url," + str(id) self._remove_ir_values(cr, url, value, "ir.actions.url")
def _tag_url(self, cr, rec, data_node=None): url = rec.get("url",'').encode('utf8') target = rec.get("target",'').encode('utf8') name = rec.get("name",'').encode('utf8') xml_id = rec.get('id','').encode('utf8') self._test_xml_id(xml_id) res = {'name': name, 'url': url, 'target':target} id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.url", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode) self.idref[xml_id] = int(id) # ir_set if (not rec.get('menu') or eval(rec.get('menu','False'))) and id: keyword = str(rec.get('keyword','') or 'client_action_multi') value = 'ir.actions.url,'+str(id) replace = rec.get("replace",'') or True self.pool.get('ir.model.data').ir_set(cr, self.uid, 'action', keyword, url, ["ir.actions.url"], value, replace=replace, isobject=True, xml_id=xml_id) elif self.mode=='update' and (rec.get('menu') and eval(rec.get('menu','False'))==False): # Special check for URL having attribute menu=False on update value = 'ir.actions.url,'+str(id) self._remove_ir_values(cr, url, value, "ir.actions.url")
def process_act_window(self, node): assert getattr(node, "id"), "Attribute %s of act_window is empty !" % ("id",) assert getattr(node, "name"), "Attribute %s of act_window is empty !" % ("name",) assert getattr(node, "res_model"), "Attribute %s of act_window is empty !" % ("res_model",) self.validate_xml_id(node.id) view_id = False if node.view: view_id = self.get_id(node.view) if not node.context: node.context = {} context = eval(str(node.context), self.eval_context) values = { "name": node.name, "type": node.type or "ir.actions.act_window", "view_id": view_id, "domain": node.domain, "context": context, "res_model": node.res_model, "src_model": node.src_model, "view_type": node.view_type or "form", "view_mode": node.view_mode or "tree,form", "usage": node.usage, "limit": node.limit, "auto_refresh": node.auto_refresh, "multi": getattr(node, "multi", False), } self._set_group_values(node, values) if node.target: values["target"] = node.target id = self.pool["ir.model.data"]._update( self.cr, SUPERUSER_ID, "ir.actions.act_window", self.module, values, node.id, mode=self.mode ) self.id_map[node.id] = int(id) if node.src_model: keyword = "client_action_relate" value = "ir.actions.act_window,%s" % id replace = node.replace or True self.pool["ir.model.data"].ir_set( self.cr, SUPERUSER_ID, "action", keyword, node.id, [node.src_model], value, replace=replace, noupdate=self.isnoupdate(node), isobject=True, xml_id=node.id, )
def process_ir_set(self, node): if not self.mode == 'init': return False _, fields = node.items()[0] res = {} for fieldname, expression in fields.items(): if is_eval(expression): value = eval(expression.expression, self.eval_context) else: value = expression res[fieldname] = value self.pool.get('ir.model.data').ir_set(self.cr, SUPERUSER_ID, res['key'], res['key2'], \ res['name'], res['models'], res['value'], replace=res.get('replace',True), \ isobject=res.get('isobject', False), meta=res.get('meta',None))
def process_url(self, node): self.validate_xml_id(node.id) res = {'name': node.name, 'url': node.url, 'target': node.target} id = self.pool.get('ir.model.data')._update(self.cr, SUPERUSER_ID, \ "ir.actions.act_url", self.module, res, node.id, mode=self.mode) self.id_map[node.id] = int(id) # ir_set if (not node.menu or eval(node.menu)) and id: keyword = node.keyword or 'client_action_multi' value = 'ir.actions.act_url,%s' % id replace = node.replace or True self.pool.get('ir.model.data').ir_set(self.cr, SUPERUSER_ID, 'action', \ keyword, node.url, ["ir.actions.act_url"], value, replace=replace, \ noupdate=self.isnoupdate(node), isobject=True, xml_id=node.id)
def process_workflow(self, node): workflow, values = node.items()[0] if self.isnoupdate(workflow) and self.mode != 'init': return if workflow.ref: id = self.get_id(workflow.ref) else: if not values: raise YamlImportException( 'You must define a child node if you do not give a ref.') if not len(values) == 1: raise YamlImportException( 'Only one child node is accepted (%d given).' % len(values)) value = values[0] if not 'model' in value and (not 'eval' in value or not 'search' in value): raise YamlImportException( 'You must provide a "model" and an "eval" or "search" to evaluate.' ) value_model = self.get_model(value['model']) local_context = { 'obj': lambda x: value_model.browse( self.cr, self.uid, x, context=self.context) } local_context.update(self.id_map) id = eval(value['eval'], self.eval_context, local_context) if workflow.uid is not None: uid = workflow.uid else: uid = self.uid self.cr.execute( 'select distinct signal, sequence, id from wkf_transition ORDER BY sequence,id' ) signals = [x['signal'] for x in self.cr.dictfetchall()] if workflow.action not in signals: raise YamlImportException( 'Incorrect action %s. No such action defined' % workflow.action) openerp.workflow.trg_validate(uid, workflow.model, id, workflow.action, self.cr)
def process_act_window(self, node): assert getattr(node, 'id'), "Attribute %s of act_window is empty !" % ('id',) assert getattr(node, 'name'), "Attribute %s of act_window is empty !" % ('name',) assert getattr(node, 'res_model'), "Attribute %s of act_window is empty !" % ('res_model',) self.validate_xml_id(node.id) view_id = False if node.view: view_id = self.get_id(node.view) if not node.context: node.context={} context = eval(str(node.context), self.eval_context) values = { 'name': node.name, 'type': node.type or 'ir.actions.act_window', 'view_id': view_id, 'domain': node.domain, 'context': context, 'res_model': node.res_model, 'src_model': node.src_model, 'view_type': node.view_type or 'form', 'view_mode': node.view_mode or 'tree,form', 'usage': node.usage, 'limit': node.limit, 'auto_refresh': node.auto_refresh, 'multi': getattr(node, 'multi', False), } self._set_group_values(node, values) if node.target: values['target'] = node.target id = self.pool['ir.model.data']._update(self.cr, SUPERUSER_ID, \ 'ir.actions.act_window', self.module, values, node.id, mode=self.mode) self.id_map[node.id] = int(id) if node.src_model: keyword = 'client_action_relate' value = 'ir.actions.act_window,%s' % id replace = node.replace or True self.pool['ir.model.data'].ir_set(self.cr, SUPERUSER_ID, 'action', keyword, \ node.id, [node.src_model], value, replace=replace, noupdate=self.isnoupdate(node), isobject=True, xml_id=node.id)
def process_act_window(self, node): assert getattr(node, 'id'), "Attribute %s of act_window is empty !" % ('id',) assert getattr(node, 'name'), "Attribute %s of act_window is empty !" % ('name',) assert getattr(node, 'res_model'), "Attribute %s of act_window is empty !" % ('res_model',) self.validate_xml_id(node.id) view_id = False if node.view: view_id = self.get_id(node.view) if not node.context: node.context={} context = eval(str(node.context), self.eval_context) values = { 'name': node.name, 'type': node.type or 'ir.actions.act_window', 'view_id': view_id, 'domain': node.domain, 'context': context, 'res_model': node.res_model, 'src_model': node.src_model, 'view_type': node.view_type or 'form', 'view_mode': node.view_mode or 'tree,form', 'usage': node.usage, 'limit': node.limit, 'auto_refresh': node.auto_refresh, 'multi': getattr(node, 'multi', False), } self._set_group_values(node, values) if node.target: values['target'] = node.target id = self.pool.get('ir.model.data')._update(self.cr, SUPERUSER_ID, \ 'ir.actions.act_window', self.module, values, node.id, mode=self.mode) self.id_map[node.id] = int(id) if node.src_model: keyword = 'client_action_relate' value = 'ir.actions.act_window,%s' % id replace = node.replace or True self.pool.get('ir.model.data').ir_set(self.cr, SUPERUSER_ID, 'action', keyword, \ node.id, [node.src_model], value, replace=replace, noupdate=self.isnoupdate(node), isobject=True, xml_id=node.id)
def process_ref(self, node, column=None): if node.search: if node.model: model_name = node.model elif column: model_name = column._obj else: raise YamlImportException('You need to give a model for the search, or a column to infer it.') model = self.get_model(model_name) q = eval(node.search, self.eval_context) ids = model.search(self.cr, self.uid, q) if node.use: instances = model.browse(self.cr, self.uid, ids) value = [inst[node.use] for inst in instances] else: value = ids elif node.id: value = self.get_id(node.id) else: value = None return value
def process_ref(self, node, column=None): assert node.search or node.id, '!ref node should have a `search` attribute or `id` attribute' if node.search: if node.model: model_name = node.model elif column: model_name = column._obj else: raise YamlImportException('You need to give a model for the search, or a column to infer it.') model = self.get_model(model_name) q = eval(node.search, self.eval_context) ids = model.search(self.cr, self.uid, q) if node.use: instances = model.browse(self.cr, self.uid, ids) value = [inst[node.use] for inst in instances] else: value = ids elif node.id: value = self.get_id(node.id) else: value = None return value
def process_ir_set(self, node): if not self.mode == "init": return False _, fields = node.items()[0] res = {} for fieldname, expression in fields.items(): if is_eval(expression): value = eval(expression.expression, self.eval_context) else: value = expression res[fieldname] = value self.pool["ir.model.data"].ir_set( self.cr, SUPERUSER_ID, res["key"], res["key2"], res["name"], res["models"], res["value"], replace=res.get("replace", True), isobject=res.get("isobject", False), meta=res.get("meta", None), )
def _create_record(self, model, fields, view_info=None, parent={}, default=True, context=None): """This function processes the !record tag in yaml 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, 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 :param parent: dictionary containing the values already computed for the parent, in case of one2many fields :param default: if True, the default values must be processed too or not :return: dictionary mapping the field names and their values, ready to use when calling the create() function :rtype: dict """ readonly_re = re.compile(r"""("readonly"|'readonly'): *true""") class dotdict(object): """ Dictionary class that allow to access a dictionary value by using '.'. This is needed to eval correctly statements like 'parent.fieldname' in context. """ def __init__(self, d): self._dict = d def __getattr__(self, attr): return self._dict.get(attr, False) def get_field_elems(view): """ return the field elements from a view as an OrderedDict """ def traverse(node, elems): if node.tag == 'field': elems[node.get('name')] = node else: for child in node: traverse(child, elems) elems = OrderedDict() traverse(etree.fromstring(encode(view['arch'])), elems) return elems def is_readonly(field_elem): """ return whether a given field is readonly """ # TODO: currently we only support if readonly is True in modifiers. # Some improvement may be done in order to support modifiers like # {"readonly": [["state", "not in", ["draft", "confirm"]]]} return readonly_re.search(field_elem.get('modifiers', '{}')) def get_2many_view(fg, field_name, view_type): """ return a view of the given type for the given field's comodel """ return fg[field_name]['views'].get(view_type) or \ self.pool[fg[field_name]['relation']].fields_view_get(self.cr, SUPERUSER_ID, False, view_type, self.context) def process_vals(fg, vals): """ sanitize the given field values """ result = {} for field_name, field_value in vals.iteritems(): if field_name not in fg: continue if fg[field_name]['type'] == 'many2one' and isinstance( field_value, (tuple, list)): field_value = field_value[0] elif fg[field_name]['type'] in ('one2many', 'many2many'): # 2many fields: sanitize field values of sub-records sub_fg = get_2many_view(fg, field_name, 'form')['fields'] def process(command): if isinstance(command, (tuple, list)) and command[0] in (0, 1): return (command[0], command[1], process_vals(sub_fg, command[2])) elif isinstance(command, dict): return process_vals(sub_fg, command) return command field_value = map(process, field_value or []) result[field_name] = field_value return result def post_process(fg, elems, vals): """ filter out readonly fields from vals """ result = {} for field_name, field_value in vals.iteritems(): if is_readonly(elems[field_name]): continue if fg[field_name]['type'] in ('one2many', 'many2many'): # 2many fields: filter field values of sub-records sub_view = get_2many_view(fg, field_name, 'form') sub_fg = sub_view['fields'] sub_elems = get_field_elems(sub_view) def process(command): if isinstance(command, (tuple, list)) and command[0] in (0, 1): return (command[0], command[1], post_process(sub_fg, sub_elems, command[2])) elif isinstance(command, dict): return (0, 0, post_process(sub_fg, sub_elems, command)) return command field_value = map(process, field_value or []) result[field_name] = field_value return result context = context or {} fields = fields or {} parent_values = { context['field_parent']: parent } if context.get('field_parent') else {} if view_info: fg = view_info['fields'] elems = get_field_elems(view_info) recs = model.browse(self.cr, SUPERUSER_ID, [], dict(self.context, **context)) onchange_spec = recs._onchange_spec(view_info) record_dict = {} if default: # gather the default values on the object. (Can't use `fields´ as parameter instead of {} because we may # have references like `base.main_company´ in the yaml file and it's not compatible with the function) defaults = recs.sudo(self.uid)._add_missing_default_values({}) # copy the default values in record_dict, only if they are in the view (because that's what the client does) # the other default values will be added later on by the create(). The other fields in the view that haven't any # default value are set to False because we may have references to them in other field's context record_dict = dict.fromkeys(fg, False) record_dict.update(process_vals(fg, defaults)) # execute onchange on default values first default_names = [name for name in elems if name in record_dict] result = recs.onchange(dict(record_dict, **parent_values), default_names, onchange_spec) record_dict.update(process_vals(fg, result.get('value', {}))) # fill in fields, and execute onchange where necessary for field_name, field_elem in elems.iteritems(): assert field_name in fg, "The field '%s' is defined in the form view but not on the object '%s'!" % ( field_name, model._name) if is_readonly(field_elem): # skip readonly fields continue if field_name not in fields: continue ctx = dict(context) form_view = view_info if fg[field_name]['type'] == 'one2many': # evaluate one2many fields using the inline form view defined in the parent form_view = get_2many_view(fg, field_name, 'form') ctx['field_parent'] = fg[field_name]['relation_field'] if default and field_elem.get('context'): ctx.update( eval(field_elem.get('context'), globals_dict={'parent': dotdict(parent)}, locals_dict=record_dict)) field_value = self._eval_field(model, field_name, fields[field_name], form_view, parent=record_dict, default=default, context=ctx) record_dict.update(process_vals(fg, {field_name: field_value})) # if field_name is given or has a default value, we evaluate its onchanges if not field_elem.attrib.get('on_change', False): continue result = recs.onchange(dict(record_dict, **parent_values), field_name, onchange_spec) record_dict.update( process_vals( fg, { key: val for key, val in result.get( 'value', {}).iteritems() if key not in fields # do not shadow values explicitly set in yaml })) record_dict = post_process(fg, elems, record_dict) else: record_dict = {} for field_name, expression in fields.iteritems(): if record_dict.get(field_name): continue field_value = self._eval_field(model, field_name, expression, parent=record_dict, default=False, context=context) record_dict[field_name] = field_value # filter returned values; indeed the last modification in the import process have added a default # value for all fields in the view; however some fields present in the view are not stored and # should not be sent to create. This bug appears with not stored function fields in the new API. return { key: val for key, val in record_dict.iteritems() if (key in model._columns or key in model._inherit_fields) }
def process_eval(self, node): return eval(node.expression, self.eval_context)
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, 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 :param parent: dictionary containing the values already computed for the parent, in case of one2many fields :param default: if True, the default values must be processed too or not :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): val = val[0] elif fg[key]['type'] == 'one2many': if val and isinstance(val, (list,tuple)) and isinstance(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') arch = etree.fromstring(one2many_tree_view['arch'].encode('utf-8')) for rec in val: # make a copy for the iteration, as we will alter `rec´ rec_copy = rec.copy() for field_key in rec_copy: # if field is missing in view or has a readonly modifier, drop it field_elem = arch.xpath("//field[@name='%s']" % field_key) if field_elem and (field_elem[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) elif fg[key]['type'] == 'many2many': if val and isinstance(val,(list,tuple)) and isinstance(val[0], (int,long)): val = [(6,0,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 if view_info: arch = etree.fromstring(view_info['arch'].decode('utf-8')) view = arch if len(arch) else False else: view = False fields = fields or {} if view is not False: fg = view_info['fields'] # gather the default values on the object. (Can't use `fields´ as parameter instead of {} because we may # have references like `base.main_company´ in the yaml file and it's not compatible with the function) defaults = default and model._add_missing_default_values(self.cr, SUPERUSER_ID, {}, context=self.context) or {} # copy the default values in record_dict, only if they are in the view (because that's what the client does) # the other default values will be added later on by the create(). record_dict = dict([(key, val) for key, val in defaults.items() if key in fg]) # Process all on_change calls nodes = [view] while nodes: el = nodes.pop(0) if el.tag=='field': field_name = el.attrib['name'] assert field_name in fg, "The field '%s' is defined in the form view but not on the object '%s'!" % (field_name, model._name) if field_name in fields: 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 = _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) #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 #if field_name has a default value or a value is given in the yaml file, we must call its on_change() elif field_name not in defaults: 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'] = SUPERUSER_ID ctx['parent'] = parent2(parent) for a in fg: if a not in ctx: ctx[a] = process_val(a, defaults.get(a, False)) # Evaluation args args = map(lambda x: eval(x, ctx), match.group(2).split(',')) result = getattr(model, match.group(1))(self.cr, SUPERUSER_ID, [], *args) for key, val in (result or {}).get('value', {}).items(): assert key in fg, "The returning field '%s' from your on_change call '%s' does not exist either on the object '%s', either in the view '%s' used for the creation" % (key, match.group(1), model._name, view_info['name']) record_dict[key] = process_val(key, val) #if (key in fields) and record_dict[key] == process_val(key, val): # print '*** You can remove these lines:', key, val else: nodes = list(el) + nodes else: record_dict = {} for field_name, expression in fields.items(): if field_name in record_dict: continue field_value = self._eval_field(model, field_name, expression, default=False) record_dict[field_name] = field_value return record_dict
def _create_record(self, model, fields, view_info=None, parent={}, default=True, context=None): """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, 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 :param parent: dictionary containing the values already computed for the parent, in case of one2many fields :param default: if True, the default values must be processed too or not :return: dictionary mapping the field names and their values, ready to use when calling the create() function :rtype: dict """ class dotdict(dict): """ Dictionary class that allow to access a dictionary value by using '.'. This is needed to eval correctly statements like 'parent.fieldname' in context. """ def __getattr__(self, attr): return self.get(attr) 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[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): val = val[0] elif fg[key]["type"] == "one2many": if val and isinstance(val, (list, tuple)) and isinstance(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") arch = etree.fromstring(one2many_tree_view["arch"].encode("utf-8")) for rec in val: # make a copy for the iteration, as we will alter `rec´ rec_copy = rec.copy() for field_key in rec_copy: # if field is missing in view or has a readonly modifier, drop it field_elem = arch.xpath("//field[@name='%s']" % field_key) if field_elem and (field_elem[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) elif fg[key]["type"] == "many2many": if val and isinstance(val, (list, tuple)) and isinstance(val[0], (int, long)): val = [(6, 0, 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 if context is None: context = {} if view_info: arch = etree.fromstring(view_info["arch"].decode("utf-8")) view = arch if len(arch) else False else: view = False fields = fields or {} if view is not False: fg = view_info["fields"] onchange_spec = model._onchange_spec(self.cr, SUPERUSER_ID, view_info, context=self.context) # gather the default values on the object. (Can't use `fields´ as parameter instead of {} because we may # have references like `base.main_company´ in the yaml file and it's not compatible with the function) missing_default_ctx = self.context.copy() missing_default_ctx.update(context) defaults = ( default and model._add_missing_default_values(self.cr, self.uid, {}, context=missing_default_ctx) or {} ) # copy the default values in record_dict, only if they are in the view (because that's what the client does) # the other default values will be added later on by the create(). The other fields in the view that haven't any # default value are set to False because we may have references to them in other field's context record_dict = default and {key: defaults.get(key, False) for key in fg} or {} # Process all on_change calls nodes = [view] while nodes: el = nodes.pop(0) if el.tag == "field": field_name = el.attrib["name"] assert field_name in fg, ( "The field '%s' is defined in the form view but not on the object '%s'!" % (field_name, model._name) ) if field_name in fields: 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 = _get_right_one2many_view(fg, field_name, "form") ctx = context.copy() if default and el.get("context"): browsable_parent = dotdict(parent) ctx_env = dict(parent=browsable_parent) evaluated_ctx = eval(el.get("context"), globals_dict=ctx_env, locals_dict=record_dict) ctx.update(evaluated_ctx) field_value = self._eval_field( model, field_name, fields[field_name], one2many_form_view or view_info, parent=record_dict, default=default, context=ctx, ) # 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 # if field_name has a default value or a value is given in the yaml file, we must call its on_change() elif field_name not in defaults: continue if not el.attrib.get("on_change", False): continue if el.attrib["on_change"] in ("1", "true"): # New-style on_change recs = model.browse(self.cr, SUPERUSER_ID, [], self.context) result = recs.onchange(record_dict, field_name, onchange_spec) else: 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"] = SUPERUSER_ID ctx["parent"] = parent2(parent) for a in fg: if a not in ctx: ctx[a] = process_val(a, defaults.get(a, False)) # Evaluation args args = map(lambda x: eval(x, ctx), match.group(2).split(",")) result = getattr(model, match.group(1))(self.cr, self.uid, [], *args) for key, val in (result or {}).get("value", {}).items(): if key in fg: if key not in fields: # do not shadow values explicitly set in yaml. record_dict[key] = process_val(key, val) else: _logger.debug( "The returning field '%s' from your on_change call '%s'" " does not exist either on the object '%s', either in" " the view '%s'", key, match.group(1), model._name, view_info["name"], ) else: nodes = list(el) + nodes else: record_dict = {} for field_name, expression in fields.items(): if record_dict.get(field_name): continue field_value = self._eval_field( model, field_name, expression, parent=record_dict, default=False, context=context ) record_dict[field_name] = field_value # filter returned values; indeed the last modification in the import process have added a default # value for all fields in the view; however some fields present in the view are not stored and # should not be sent to create. This bug appears with not stored function fields in the new API. record_dict = dict( (key, record_dict.get(key)) for key in record_dict if (key in model._columns or key in model._inherit_fields) ) return record_dict
def _tag_act_window(self, cr, rec, data_node=None, mode=None): name = rec.get('name', '').encode('utf-8') xml_id = rec.get('id', '').encode('utf8') self._test_xml_id(xml_id) type = rec.get('type', '').encode('utf-8') or 'ir.actions.act_window' view_id = False if rec.get('view_id'): view_id = self.id_get(cr, rec.get('view_id', '').encode('utf-8')) domain = rec.get('domain', '').encode('utf-8') or '[]' res_model = rec.get('res_model', '').encode('utf-8') src_model = rec.get('src_model', '').encode('utf-8') view_type = rec.get('view_type', '').encode('utf-8') or 'form' view_mode = rec.get('view_mode', '').encode('utf-8') or 'tree,form' usage = rec.get('usage', '').encode('utf-8') limit = rec.get('limit', '').encode('utf-8') auto_refresh = rec.get('auto_refresh', '').encode('utf-8') uid = self.uid # Act_window's 'domain' and 'context' contain mostly literals # but they can also refer to the variables provided below # in eval_context, so we need to eval() them before storing. # Among the context variables, 'active_id' refers to # the currently selected items in a list view, and only # takes meaning at runtime on the client side. For this # reason it must remain a bare variable in domain and context, # even after eval() at server-side. We use the special 'unquote' # class to achieve this effect: a string which has itself, unquoted, # as representation. active_id = unquote("active_id") active_ids = unquote("active_ids") active_model = unquote("active_model") def ref(str_id): return self.id_get(cr, str_id) # Include all locals() in eval_context, for backwards compatibility eval_context = { 'name': name, 'xml_id': xml_id, 'type': type, 'view_id': view_id, 'domain': domain, 'res_model': res_model, 'src_model': src_model, 'view_type': view_type, 'view_mode': view_mode, 'usage': usage, 'limit': limit, 'auto_refresh': auto_refresh, 'uid': uid, 'active_id': active_id, 'active_ids': active_ids, 'active_model': active_model, 'ref': ref, } context = self.get_context(data_node, rec, eval_context) try: domain = unsafe_eval(domain, eval_context) except NameError: # Some domains contain references that are only valid at runtime at # client-side, so in that case we keep the original domain string # as it is. We also log it, just in case. _logger.debug('Domain value (%s) for element with id "%s" does not parse '\ 'at server-side, keeping original string, in case it\'s meant for client side only', domain, xml_id or 'n/a', exc_info=True) res = { 'name': name, 'type': type, 'view_id': view_id, 'domain': domain, 'context': context, 'res_model': res_model, 'src_model': src_model, 'view_type': view_type, 'view_mode': view_mode, 'usage': usage, 'limit': limit, 'auto_refresh': auto_refresh, } if rec.get('groups'): g_names = rec.get('groups', '').split(',') groups_value = [] for group in g_names: if group.startswith('-'): group_id = self.id_get(cr, group[1:]) groups_value.append((3, group_id)) else: group_id = self.id_get(cr, group) groups_value.append((4, group_id)) res['groups_id'] = groups_value if rec.get('target'): res['target'] = rec.get('target', '') if rec.get('multi'): res['multi'] = eval(rec.get('multi', 'False')) id = self.pool['ir.model.data']._update( cr, self.uid, 'ir.actions.act_window', self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode) self.idref[xml_id] = int(id) if src_model: #keyword = 'client_action_relate' keyword = rec.get('key2', '').encode('utf-8') or 'client_action_relate' value = 'ir.actions.act_window,' + str(id) replace = rec.get('replace', '') or True self.pool['ir.model.data'].ir_set(cr, self.uid, 'action', keyword, xml_id, [src_model], value, replace=replace, isobject=True, xml_id=xml_id)
def _create_record(self, model, fields, view=False, parent={}, default=True): allfields = model.fields_get(self.cr, 1, context=self.context) if view is not False: defaults = default and model.default_get( self.cr, 1, allfields, context=self.context) or {} fg = model.fields_get(self.cr, 1, context=self.context) else: default = {} fg = {} record_dict = {} fields = fields or {} def process_val(key, val): if fg[key]['type'] == 'many2one': if type(val) in (tuple, list): val = val[0] elif fg[key]['type'] == 'one2many': if val and isinstance(val,(list,tuple)) and \ isinstance(val[0], dict): val = map(lambda x: (0, 0, x), val) elif fg[key]['type'] == 'many2many': if val and isinstance(val,(list,tuple)) and \ isinstance(val[0], (int,long)): val = [(6, 0, val)] return val # Process all on_change calls nodes = (view is not False) and [view] or [] while nodes: el = nodes.pop(0) if el.tag == 'field': field_name = el.attrib['name'] assert field_name in fg, "The field '%s' is defined in the form view but not on the object '%s'!" % ( field_name, model._name) if field_name in fields: view2 = None # if the form view is not inline, we call fields_view_get if (view is not False) and (fg[field_name]['type'] == 'one2many'): 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, default=default) record_dict[field_name] = field_value #if (field_name in defaults) and defaults[field_name] == field_value: # print '*** You can remove these lines:', field_name, field_value elif (field_name in defaults): if (field_name not in record_dict): record_dict[field_name] = process_val( 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] = process_val(a, defaults.get(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 or {}).get('value', {}).items(): if key not in fields: assert key in fg, "The returning field '%s' from your on_change call '%s' does not exist on the object '%s'" % ( key, match.group(1), model._name) record_dict[key] = process_val(key, val) #if (key in fields) and record_dict[key] == process_val(key, val): # print '*** You can remove these lines:', 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, default=False) record_dict[field_name] = field_value return record_dict
def _create_record(self, model, fields, view_info=None, 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, 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 :param parent: dictionary containing the values already computed for the parent, in case of one2many fields :param default: if True, the default values must be processed too or not :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[ 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): val = val[0] elif fg[key]['type'] == 'one2many': if val and isinstance(val, (list, tuple)) and isinstance( 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') arch = etree.fromstring( one2many_tree_view['arch'].encode('utf-8')) for rec in val: # make a copy for the iteration, as we will alter `rec´ rec_copy = rec.copy() for field_key in rec_copy: # if field is missing in view or has a readonly modifier, drop it field_elem = arch.xpath("//field[@name='%s']" % field_key) if field_elem and (field_elem[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) elif fg[key]['type'] == 'many2many': if val and isinstance(val, (list, tuple)) and isinstance( val[0], (int, long)): val = [(6, 0, 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 if view_info: arch = etree.fromstring(view_info['arch'].decode('utf-8')) view = arch if len(arch) else False else: view = False fields = fields or {} if view is not False: fg = view_info['fields'] onchange_spec = model._onchange_spec(self.cr, SUPERUSER_ID, view_info, context=self.context) # gather the default values on the object. (Can't use `fields´ as parameter instead of {} because we may # have references like `base.main_company´ in the yaml file and it's not compatible with the function) defaults = default and model._add_missing_default_values( self.cr, self.uid, {}, context=self.context) or {} # copy the default values in record_dict, only if they are in the view (because that's what the client does) # the other default values will be added later on by the create(). record_dict = dict([(key, val) for key, val in defaults.items() if key in fg]) # Process all on_change calls nodes = [view] while nodes: el = nodes.pop(0) if el.tag == 'field': field_name = el.attrib['name'] assert field_name in fg, "The field '%s' is defined in the form view but not on the object '%s'!" % ( field_name, model._name) if field_name in fields: 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 = _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) #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 #if field_name has a default value or a value is given in the yaml file, we must call its on_change() elif field_name not in defaults: continue if not el.attrib.get('on_change', False): continue if el.attrib['on_change'] in ('1', 'true'): # New-style on_change recs = model.browse(self.cr, SUPERUSER_ID, [], self.context) result = recs.onchange(record_dict, field_name, onchange_spec) else: match = re.match("([a-z_1-9A-Z]+)\((.*)\)", el.attrib['on_change'], re.DOTALL) 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'] = SUPERUSER_ID ctx['parent'] = parent2(parent) for a in fg: if a not in ctx: ctx[a] = process_val(a, defaults.get(a, False)) # Evaluation args args = map(lambda x: eval(x, ctx), match.group(2).split(',')) result = getattr(model, match.group(1))(self.cr, self.uid, [], *args) for key, val in (result or {}).get('value', {}).items(): if key in fg: if key not in fields: # do not shadow values explicitly set in yaml. record_dict[key] = process_val(key, val) else: _logger.debug( "The returning field '%s' from your on_change call '%s'" " does not exist either on the object '%s', either in" " the view '%s'", key, match.group(1), model._name, view_info['name']) else: nodes = list(el) + nodes else: record_dict = {} for field_name, expression in fields.items(): if field_name in record_dict: continue field_value = self._eval_field(model, field_name, expression, default=False) record_dict[field_name] = field_value return record_dict
def get_context(self, node, eval_dict): context = self.context.copy() if node.context: context.update(eval(node.context, eval_dict)) return context
def _tag_act_window(self, cr, rec, data_node=None, mode=None): name = rec.get('name','').encode('utf-8') xml_id = rec.get('id','').encode('utf8') self._test_xml_id(xml_id) type = rec.get('type','').encode('utf-8') or 'ir.actions.act_window' view_id = False if rec.get('view_id'): view_id = self.id_get(cr, rec.get('view_id','').encode('utf-8')) domain = rec.get('domain','').encode('utf-8') or '[]' res_model = rec.get('res_model','').encode('utf-8') src_model = rec.get('src_model','').encode('utf-8') view_type = rec.get('view_type','').encode('utf-8') or 'form' view_mode = rec.get('view_mode','').encode('utf-8') or 'tree,form' usage = rec.get('usage','').encode('utf-8') limit = rec.get('limit','').encode('utf-8') auto_refresh = rec.get('auto_refresh','').encode('utf-8') uid = self.uid # Act_window's 'domain' and 'context' contain mostly literals # but they can also refer to the variables provided below # in eval_context, so we need to eval() them before storing. # Among the context variables, 'active_id' refers to # the currently selected items in a list view, and only # takes meaning at runtime on the client side. For this # reason it must remain a bare variable in domain and context, # even after eval() at server-side. We use the special 'unquote' # class to achieve this effect: a string which has itself, unquoted, # as representation. active_id = unquote("active_id") active_ids = unquote("active_ids") active_model = unquote("active_model") def ref(str_id): return self.id_get(cr, str_id) # Include all locals() in eval_context, for backwards compatibility eval_context = { 'name': name, 'xml_id': xml_id, 'type': type, 'view_id': view_id, 'domain': domain, 'res_model': res_model, 'src_model': src_model, 'view_type': view_type, 'view_mode': view_mode, 'usage': usage, 'limit': limit, 'auto_refresh': auto_refresh, 'uid' : uid, 'active_id': active_id, 'active_ids': active_ids, 'active_model': active_model, 'ref' : ref, } context = self.get_context(data_node, rec, eval_context) try: domain = unsafe_eval(domain, eval_context) except NameError: # Some domains contain references that are only valid at runtime at # client-side, so in that case we keep the original domain string # as it is. We also log it, just in case. _logger.debug('Domain value (%s) for element with id "%s" does not parse '\ 'at server-side, keeping original string, in case it\'s meant for client side only', domain, xml_id or 'n/a', exc_info=True) res = { 'name': name, 'type': type, 'view_id': view_id, 'domain': domain, 'context': context, 'res_model': res_model, 'src_model': src_model, 'view_type': view_type, 'view_mode': view_mode, 'usage': usage, 'limit': limit, 'auto_refresh': auto_refresh, } if rec.get('groups'): g_names = rec.get('groups','').split(',') groups_value = [] for group in g_names: if group.startswith('-'): group_id = self.id_get(cr, group[1:]) groups_value.append((3, group_id)) else: group_id = self.id_get(cr, group) groups_value.append((4, group_id)) res['groups_id'] = groups_value if rec.get('target'): res['target'] = rec.get('target','') if rec.get('multi'): res['multi'] = eval(rec.get('multi', 'False')) id = self.pool['ir.model.data']._update(cr, self.uid, 'ir.actions.act_window', self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode) self.idref[xml_id] = int(id) if src_model: #keyword = 'client_action_relate' keyword = rec.get('key2','').encode('utf-8') or 'client_action_relate' value = 'ir.actions.act_window,'+str(id) replace = rec.get('replace','') or True self.pool['ir.model.data'].ir_set(cr, self.uid, 'action', keyword, xml_id, [src_model], value, replace=replace, isobject=True, xml_id=xml_id)
def _create_record(self, model, fields, view=False, parent={}, default=True): allfields = model.fields_get(self.cr, 1, context=self.context) if view is not False: defaults = default and model.default_get(self.cr, 1, allfields, context=self.context) or {} fg = model.fields_get(self.cr, 1, context=self.context) else: default = {} fg = {} record_dict = {} fields = fields or {} def process_val(key, val): if fg[key]['type']=='many2one': if type(val) in (tuple,list): val = val[0] elif (fg[key]['type']=='one2many'): if val is False: val = [] if len(val) and type(val[0]) == dict: val = map(lambda x: (0,0,x), val) return val # Process all on_change calls nodes = (view is not False) and [view] or [] while nodes: el = nodes.pop(0) if el.tag=='field': field_name = el.attrib['name'] assert field_name in fg, "The field '%s' is defined in the form view but not on the object '%s'!" % (field_name, model._name) if field_name in fields: view2 = None # if the form view is not inline, we call fields_view_get if (view is not False) and (fg[field_name]['type']=='one2many'): 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, default=default) record_dict[field_name] = field_value #if (field_name in defaults) and defaults[field_name] == field_value: # print '*** You can remove these lines:', field_name, field_value elif (field_name in defaults): if (field_name not in record_dict): record_dict[field_name] = process_val(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]=process_val(a, defaults.get(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 or {}).get('value', {}).items(): if key not in fields: assert key in fg, "The returning field '%s' from your on_change call '%s' does not exist on the object '%s'" % (key, match.group(1), model._name) record_dict[key] = process_val(key, val) #if (key in fields) and record_dict[key] == process_val(key, val): # print '*** You can remove these lines:', 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, default=False) record_dict[field_name] = field_value return record_dict
def _tag_report(self, cr, rec, data_node=None): res = {} for dest, f in (("name", "string"), ("model", "model"), ("report_name", "name")): res[dest] = rec.get(f, "").encode("utf8") assert res[dest], "Attribute %s of report is empty !" % (f,) for field, dest in ( ("rml", "report_rml"), ("file", "report_rml"), ("xml", "report_xml"), ("xsl", "report_xsl"), ("attachment", "attachment"), ("attachment_use", "attachment_use"), ("usage", "usage"), ): if rec.get(field): res[dest] = rec.get(field).encode("utf8") if rec.get("auto"): res["auto"] = eval(rec.get("auto", "False")) if rec.get("sxw"): sxw_content = misc.file_open(rec.get("sxw")).read() res["report_sxw_content"] = sxw_content if rec.get("header"): res["header"] = eval(rec.get("header", "False")) if rec.get("report_type"): res["report_type"] = rec.get("report_type") res["multi"] = rec.get("multi") and eval(rec.get("multi", "False")) xml_id = rec.get("id", "").encode("utf8") self._test_xml_id(xml_id) if rec.get("groups"): g_names = rec.get("groups", "").split(",") groups_value = [] for group in g_names: if group.startswith("-"): group_id = self.id_get(cr, group[1:]) groups_value.append((3, group_id)) else: group_id = self.id_get(cr, group) groups_value.append((4, group_id)) res["groups_id"] = groups_value id = self.pool.get("ir.model.data")._update( cr, self.uid, "ir.actions.report.xml", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode, ) self.idref[xml_id] = int(id) if not rec.get("menu") or eval(rec.get("menu", "False")): keyword = str(rec.get("keyword", "client_print_multi")) value = "ir.actions.report.xml," + str(id) replace = rec.get("replace", True) self.pool.get("ir.model.data").ir_set( cr, self.uid, "action", keyword, res["name"], [res["model"]], value, replace=replace, isobject=True, xml_id=xml_id, ) elif self.mode == "update" and eval(rec.get("menu", "False")) == False: # Special check for report having attribute menu=False on update value = "ir.actions.report.xml," + str(id) self._remove_ir_values(cr, res["name"], value, res["model"]) return id
def _tag_act_window(self, cr, rec, data_node=None, mode=None): name = rec.get("name", "").encode("utf-8") xml_id = rec.get("id", "").encode("utf8") self._test_xml_id(xml_id) type = rec.get("type", "").encode("utf-8") or "ir.actions.act_window" view_id = False if rec.get("view_id"): view_id = self.id_get(cr, rec.get("view_id", "").encode("utf-8")) domain = rec.get("domain", "").encode("utf-8") or "[]" res_model = rec.get("res_model", "").encode("utf-8") src_model = rec.get("src_model", "").encode("utf-8") view_type = rec.get("view_type", "").encode("utf-8") or "form" view_mode = rec.get("view_mode", "").encode("utf-8") or "tree,form" usage = rec.get("usage", "").encode("utf-8") limit = rec.get("limit", "").encode("utf-8") auto_refresh = rec.get("auto_refresh", "").encode("utf-8") uid = self.uid # Act_window's 'domain' and 'context' contain mostly literals # but they can also refer to the variables provided below # in eval_context, so we need to eval() them before storing. # Among the context variables, 'active_id' refers to # the currently selected items in a list view, and only # takes meaning at runtime on the client side. For this # reason it must remain a bare variable in domain and context, # even after eval() at server-side. We use the special 'unquote' # class to achieve this effect: a string which has itself, unquoted, # as representation. active_id = unquote("active_id") active_ids = unquote("active_ids") active_model = unquote("active_model") def ref(str_id): return self.id_get(cr, str_id) # Include all locals() in eval_context, for backwards compatibility eval_context = { "name": name, "xml_id": xml_id, "type": type, "view_id": view_id, "domain": domain, "res_model": res_model, "src_model": src_model, "view_type": view_type, "view_mode": view_mode, "usage": usage, "limit": limit, "auto_refresh": auto_refresh, "uid": uid, "active_id": active_id, "active_ids": active_ids, "active_model": active_model, "ref": ref, } context = self.get_context(data_node, rec, eval_context) try: domain = unsafe_eval(domain, eval_context) except NameError: # Some domains contain references that are only valid at runtime at # client-side, so in that case we keep the original domain string # as it is. We also log it, just in case. _logger.debug( 'Domain value (%s) for element with id "%s" does not parse ' "at server-side, keeping original string, in case it's meant for client side only", domain, xml_id or "n/a", exc_info=True, ) res = { "name": name, "type": type, "view_id": view_id, "domain": domain, "context": context, "res_model": res_model, "src_model": src_model, "view_type": view_type, "view_mode": view_mode, "usage": usage, "limit": limit, "auto_refresh": auto_refresh, } if rec.get("groups"): g_names = rec.get("groups", "").split(",") groups_value = [] for group in g_names: if group.startswith("-"): group_id = self.id_get(cr, group[1:]) groups_value.append((3, group_id)) else: group_id = self.id_get(cr, group) groups_value.append((4, group_id)) res["groups_id"] = groups_value if rec.get("target"): res["target"] = rec.get("target", "") if rec.get("multi"): res["multi"] = eval(rec.get("multi", "False")) id = self.pool["ir.model.data"]._update( cr, self.uid, "ir.actions.act_window", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode, ) self.idref[xml_id] = int(id) if src_model: # keyword = 'client_action_relate' keyword = rec.get("key2", "").encode("utf-8") or "client_action_relate" value = "ir.actions.act_window," + str(id) replace = rec.get("replace", "") or True self.pool["ir.model.data"].ir_set( cr, self.uid, "action", keyword, xml_id, [src_model], value, replace=replace, isobject=True, xml_id=xml_id, )
def _create_record(self, model, fields, view_info=None, parent={}, default=True, context=None): """This function processes the !record tag in yaml 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, 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 :param parent: dictionary containing the values already computed for the parent, in case of one2many fields :param default: if True, the default values must be processed too or not :return: dictionary mapping the field names and their values, ready to use when calling the create() function :rtype: dict """ readonly_re = re.compile(r"""("readonly"|'readonly'): *true""") class dotdict(object): """ Dictionary class that allow to access a dictionary value by using '.'. This is needed to eval correctly statements like 'parent.fieldname' in context. """ def __init__(self, d): self._dict = d def __getattr__(self, attr): return self._dict.get(attr, False) def get_field_elems(view): """ return the field elements from a view as an OrderedDict """ def traverse(node, elems): if node.tag == 'field': elems[node.get('name')] = node else: for child in node: traverse(child, elems) elems = OrderedDict() traverse(etree.fromstring(encode(view['arch'])), elems) return elems def is_readonly(field_elem): """ return whether a given field is readonly """ # TODO: currently we only support if readonly is True in modifiers. # Some improvement may be done in order to support modifiers like # {"readonly": [["state", "not in", ["draft", "confirm"]]]} return readonly_re.search(field_elem.get('modifiers', '{}')) def get_2many_view(fg, field_name, view_type): """ return a view of the given type for the given field's comodel """ return fg[field_name]['views'].get(view_type) or \ self.pool[fg[field_name]['relation']].fields_view_get(self.cr, SUPERUSER_ID, False, view_type, self.context) def process_vals(fg, vals): """ sanitize the given field values """ result = {} for field_name, field_value in vals.iteritems(): if field_name not in fg: continue if fg[field_name]['type'] == 'many2one' and isinstance(field_value, (tuple, list)): field_value = field_value[0] elif fg[field_name]['type'] in ('one2many', 'many2many'): # 2many fields: sanitize field values of sub-records sub_fg = get_2many_view(fg, field_name, 'form')['fields'] def process(command): if isinstance(command, (tuple, list)) and command[0] in (0, 1): return (command[0], command[1], process_vals(sub_fg, command[2])) elif isinstance(command, dict): return process_vals(sub_fg, command) return command field_value = map(process, field_value or []) result[field_name] = field_value return result def post_process(fg, elems, vals): """ filter out readonly fields from vals """ result = {} for field_name, field_value in vals.iteritems(): if is_readonly(elems[field_name]): continue if fg[field_name]['type'] in ('one2many', 'many2many'): # 2many fields: filter field values of sub-records sub_view = get_2many_view(fg, field_name, 'form') sub_fg = sub_view['fields'] sub_elems = get_field_elems(sub_view) def process(command): if isinstance(command, (tuple, list)) and command[0] in (0, 1): return (command[0], command[1], post_process(sub_fg, sub_elems, command[2])) elif isinstance(command, dict): return (0, 0, post_process(sub_fg, sub_elems, command)) return command field_value = map(process, field_value or []) result[field_name] = field_value return result context = context or {} fields = fields or {} parent_values = {context['field_parent']: parent} if context.get('field_parent') else {} if view_info: fg = view_info['fields'] elems = get_field_elems(view_info) recs = model.browse(self.cr, SUPERUSER_ID, [], dict(self.context, **context)) onchange_spec = recs._onchange_spec(view_info) record_dict = {} if default: # gather the default values on the object. (Can't use `fields´ as parameter instead of {} because we may # have references like `base.main_company´ in the yaml file and it's not compatible with the function) defaults = recs.sudo(self.uid)._add_missing_default_values({}) # copy the default values in record_dict, only if they are in the view (because that's what the client does) # the other default values will be added later on by the create(). The other fields in the view that haven't any # default value are set to False because we may have references to them in other field's context record_dict = dict.fromkeys(fg, False) record_dict.update(process_vals(fg, defaults)) # execute onchange on default values first default_names = [name for name in elems if name in record_dict] result = recs.onchange(dict(record_dict, **parent_values), default_names, onchange_spec) record_dict.update(process_vals(fg, result.get('value', {}))) # fill in fields, and execute onchange where necessary for field_name, field_elem in elems.iteritems(): assert field_name in fg, "The field '%s' is defined in the form view but not on the object '%s'!" % (field_name, model._name) if is_readonly(field_elem): # skip readonly fields continue if field_name not in fields: continue ctx = dict(context) form_view = view_info if fg[field_name]['type'] == 'one2many': # evaluate one2many fields using the inline form view defined in the parent form_view = get_2many_view(fg, field_name, 'form') ctx['field_parent'] = fg[field_name]['relation_field'] if default and field_elem.get('context'): ctx.update(eval(field_elem.get('context'), globals_dict={'parent': dotdict(parent)}, locals_dict=record_dict)) field_value = self._eval_field(model, field_name, fields[field_name], form_view, parent=record_dict, default=default, context=ctx) record_dict.update(process_vals(fg, {field_name: field_value})) # if field_name is given or has a default value, we evaluate its onchanges if not field_elem.attrib.get('on_change', False): continue result = recs.onchange(dict(record_dict, **parent_values), field_name, onchange_spec) record_dict.update(process_vals(fg, { key: val for key, val in result.get('value', {}).iteritems() if key not in fields # do not shadow values explicitly set in yaml })) record_dict = post_process(fg, elems, record_dict) else: record_dict = {} for field_name, expression in fields.iteritems(): if record_dict.get(field_name): continue field_value = self._eval_field(model, field_name, expression, parent=record_dict, default=False, context=context) record_dict[field_name] = field_value # filter returned values; indeed the last modification in the import process have added a default # value for all fields in the view; however some fields present in the view are not stored and # should not be sent to create. This bug appears with not stored function fields in the new API. return { key: val for key, val in record_dict.iteritems() if (key in model._columns or key in model._inherit_fields) }
def _tag_report(self, cr, rec, data_node=None, mode=None): res = {} for dest, f in (('name', 'string'), ('model', 'model'), ('report_name', 'name')): res[dest] = rec.get(f, '').encode('utf8') assert res[dest], "Attribute %s of report is empty !" % (f, ) for field, dest in (('rml', 'report_rml'), ('file', 'report_rml'), ('xml', 'report_xml'), ('xsl', 'report_xsl'), ('attachment', 'attachment'), ('attachment_use', 'attachment_use'), ('usage', 'usage'), ('report_type', 'report_type'), ('parser', 'parser')): if rec.get(field): res[dest] = rec.get(field).encode('utf8') if rec.get('auto'): res['auto'] = eval(rec.get('auto', 'False')) if rec.get('sxw'): sxw_content = misc.file_open(rec.get('sxw')).read() res['report_sxw_content'] = sxw_content if rec.get('header'): res['header'] = eval(rec.get('header', 'False')) res['multi'] = rec.get('multi') and eval(rec.get('multi', 'False')) xml_id = rec.get('id', '').encode('utf8') self._test_xml_id(xml_id) if rec.get('groups'): g_names = rec.get('groups', '').split(',') groups_value = [] for group in g_names: if group.startswith('-'): group_id = self.id_get(cr, group[1:]) groups_value.append((3, group_id)) else: group_id = self.id_get(cr, group) groups_value.append((4, group_id)) res['groups_id'] = groups_value id = self.pool['ir.model.data']._update( cr, self.uid, "ir.actions.report.xml", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode) self.idref[xml_id] = int(id) if not rec.get('menu') or eval(rec.get('menu', 'False')): keyword = str(rec.get('keyword', 'client_print_multi')) value = 'ir.actions.report.xml,' + str(id) replace = rec.get('replace', True) self.pool['ir.model.data'].ir_set(cr, self.uid, 'action', keyword, res['name'], [res['model']], value, replace=replace, isobject=True, xml_id=xml_id) elif self.mode == 'update' and eval(rec.get('menu', 'False')) == False: # Special check for report having attribute menu=False on update value = 'ir.actions.report.xml,' + str(id) self._remove_ir_values(cr, res['name'], value, res['model']) return id