Beispiel #1
0
    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
Beispiel #3
0
    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)
Beispiel #5
0
    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
Beispiel #6
0
 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
Beispiel #7
0
    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,
            )
Beispiel #8
0
    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
Beispiel #12
0
    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.")
Beispiel #14
0
    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")
Beispiel #15
0
    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")
Beispiel #16
0
    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)
Beispiel #19
0
    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)
Beispiel #20
0
    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)
Beispiel #22
0
 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
Beispiel #23
0
 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
Beispiel #24
0
 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),
     )
Beispiel #25
0
    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
Beispiel #28
0
    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
Beispiel #29
0
    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
Beispiel #31
0
    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
Beispiel #32
0
 def get_context(self, node, eval_dict):
     context = self.context.copy()
     if node.context:
         context.update(eval(node.context, eval_dict))
     return context
Beispiel #33
0
    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)
Beispiel #34
0
    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
Beispiel #35
0
    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 get_context(self, node, eval_dict):
     context = self.context.copy()
     if node.context:
         context.update(eval(node.context, eval_dict))
     return context
Beispiel #37
0
 def process_eval(self, node):
     return eval(node.expression, self.eval_context)
Beispiel #38
0
    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,
            )
Beispiel #39
0
    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)
        }
Beispiel #40
0
    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