Example #1
0
    def _call_kw(self, model, method, args, kwargs):
        user = request.env.user
        if not user.has_group(SECURITY_GROUP) \
                or not request.env.company.printnode_enabled or not user.printnode_enabled:
            return super(DataSetProxy, self)._call_kw(model, method, args, kwargs)

        # We have a list of methods which will never be handled in 'printnode.action.button'.
        # In that case just will be returned a 'super method'.
        su = request.env['ir.config_parameter'].sudo()
        methods_list = su.get_param('printnode_base.skip_methods', '').split(',')
        # In addition, we need to choose only 'call_kw_multi' sub method, so
        # let's filter this like in standard Odoo function 'def call_kw()'.
        method_ = getattr(type(request.env[model]), method)
        api_ = getattr(method, '_api', None)
        if (method in methods_list) or (api_ in ('model', 'model_create')):
            return super(DataSetProxy, self)._call_kw(model, method, args, kwargs)

        actions = request.env['printnode.action.button'].search([
            ('model_id.model', '=', model),
            ('method_id.method', '=', method),
        ])
        post_ids, pre_ids = [], []

        for action in actions.filtered(lambda a: a.active and a.report_id):
            (post_ids, pre_ids)[action.preprint].append(action.id)

        printnode_object_ids = args[0] if args else None

        self._execute_printnode_jobs(pre_ids, printnode_object_ids)

        # We need to update variables 'post_ids' and 'printnode_object_id' from context.
        args_, kwargs_ = deepcopy(args[1:]), deepcopy(kwargs)
        context_, *_rest = api.split_context(method_, args_, kwargs_)
        if isinstance(context_, dict):
            post_ids += context_.get('printnode_action_ids', [])
            object_ids_from_kwargs = context_.get('printnode_object_ids')
            printnode_object_ids = object_ids_from_kwargs or printnode_object_ids

        result = super(DataSetProxy, self)._call_kw(model, method, args, kwargs)

        # If we had gotten 'result' as another one wizard or something - we need to save our
        # variables 'printnode_action_ids' and 'printnode_object_ids' in context and do printing
        # after the required 'super method' will be performed.
        if post_ids and result and isinstance(result, dict) and 'context' in result:
            new_context = dict(result.get('context'))
            if not new_context.get('printnode_action_ids'):
                new_context.update({'printnode_action_ids': post_ids})
            if not new_context.get('printnode_object_ids'):
                new_context.update({'printnode_object_ids': printnode_object_ids})
            result['context'] = new_context
            return result

        if not post_ids:
            return result

        self._execute_printnode_jobs(post_ids, printnode_object_ids)

        return result
Example #2
0
def format_python_xml(model_name, method_name, args, kwargs, result):
    global CREATED_IDS
    data_to_format = []
    data_formated = []
    data_to_xml = []
    model = request.env[model_name].sudo()
    method = getattr(type(model), method_name)
    if getattr(method, '_api', None) in ['model', 'model_create']:
        ids = []
        vals = args[0]
    else:
        ids, args = args[0], args[1:]
        vals = args[0]
    context, args, kwargs = api.split_context(method, args, kwargs)
    if method_name == 'unlink':
        for xml_id in CREATED_IDS['delete_ids']:
            data_to_format.append((xml_id, {}, model_name, method_name))
    if method_name == 'write':
        values = add_groups_values(model_name, vals)
        for id in ids:
            xml_id = generate_xml_id(id, model_name, test_type='demo')
            data_to_format.append((xml_id, values, model_name, method_name))
    if method_name in ['create', 'name_create']:
        values = get_values_from_context(model, context)
        if method_name == 'name_create':
            values[model._rec_name] = vals
            result = result[0]
        else:
            values.update(vals)
        values = add_groups_values(model_name, values)
        xml_id = generate_xml_id(result, model_name, test_type='demo')
        data_to_format.append((xml_id, values, model_name, 'create'))

    while data_to_format:
        xml_id, vals, modelname, methodname = data_to_format.pop(0)
        formated_element = generate_formated_element(xml_id, vals, modelname,
                                                     methodname,
                                                     data_to_format)
        if formated_element:
            data_formated.append(formated_element)

    for element in data_formated:
        xml_id, vals, modelname, methodname = element
        data_to_xml.append(
            generate_xml_element(xml_id, vals, modelname, methodname))

    # Depending on server configuration, we sometime receive bytes instead of str
    # We have to make sure that join will be called with a list of str to avoid issues
    return '\n'.join([str(datum) for datum in data_to_xml])
Example #3
0
def call_kw(model, name, args, kwargs):
    res = call_kw_org(model, name, args, kwargs)
    user = model.env.user
    if user.track_user_activity and "user.activity.log" != model._name:
        method_args = args
        # Borrow the original logic to identify the ids and args
        # https://github.com/odoo/odoo/blob/e66e2e2fe4a7c748278c3bb71c2fe10ad36e1245/odoo/api.py#L668-L689
        method = getattr(type(model), name)
        if getattr(method, "_api", None) == "model":
            recs = model
        else:
            ids, method_args = args[0], args[1:]
            recs = model.browse(ids)
        method_args = split_context(method, method_args, kwargs)
        if recs or method_args:
            model.env["user.activity.log"].create_activity_log(
                model, name, recs, method_args)
    return res
Example #4
0
def _eval_xml(self, node, env):
    if node.tag in ('field','value'):
        t = node.get('type','char')
        f_model = node.get('model')
        if node.get('search'):
            f_search = node.get("search")
            f_use = node.get("use",'id')
            f_name = node.get("name")
            idref2 = {}
            if f_search:
                idref2 = _get_idref(self, env, f_model, self.idref)
            q = safe_eval(f_search, idref2)
            ids = env[f_model].search(q).ids
            if f_use != 'id':
                ids = [x[f_use] for x in env[f_model].browse(ids).read([f_use])]
            _fields = env[f_model]._fields
            if (f_name in _fields) and _fields[f_name].type == 'many2many':
                return ids
            f_val = False
            if len(ids):
                f_val = ids[0]
                if isinstance(f_val, tuple):
                    f_val = f_val[0]
            return f_val
        a_eval = node.get('eval')
        if a_eval:
            idref2 = _get_idref(self, env, f_model, self.idref)
            try:
                return safe_eval(a_eval, idref2)
            except Exception:
                logging.getLogger('odoo.tools.convert.init').error(
                    'Could not eval(%s) for %s in %s', a_eval, node.get('name'), env.context)
                raise
        def _process(s):
            matches = re.finditer(br'[^%]%\((.*?)\)[ds]'.decode('utf-8'), s)
            done = set()
            for m in matches:
                found = m.group()[1:]
                if found in done:
                    continue
                done.add(found)
                id = m.groups()[0]
                if not id in self.idref:
                    self.idref[id] = self.id_get(id)
                # So funny story: in Python 3, bytes(n: int) returns a
                # bytestring of n nuls. In Python 2 it obviously returns the
                # stringified number, which is what we're expecting here
                s = s.replace(found, pycompat.text_type(self.idref[id]))
            s = s.replace('%%', '%') # Quite weird but it's for (somewhat) backward compatibility sake
            return s

        if t == 'xml':
            _fix_multiple_roots(node)
            return '<?xml version="1.0"?>\n'\
                +_process("".join(etree.tostring(n, encoding='unicode') for n in node))
        if t == 'html':
            return _process("".join(etree.tostring(n, encoding='unicode') for n in node))

        data = node.text
        if node.get('file'):
            with file_open(node.get('file'), 'rb') as f:
                data = f.read()

        if t == 'base64':
            return base64.b64encode(data)

        # after that, only text content makes sense
        data = pycompat.to_text(data)
        if t == 'file':
            from ..modules import module
            path = data.strip()
            if not module.get_module_resource(self.module, path):
                raise IOError("No such file or directory: '%s' in %s" % (
                    path, self.module))
            return '%s,%s' % (self.module, path)

        if t == 'char':
            return data

        if t == 'int':
            d = data.strip()
            if d == 'None':
                return None
            return int(d)

        if t == 'float':
            return float(data.strip())

        if t in ('list','tuple'):
            res=[]
            for n in node.iterchildren(tag='value'):
                res.append(_eval_xml(self, n, env))
            if t=='tuple':
                return tuple(res)
            return res
    elif node.tag == "function":
        a_eval = node.get('eval')
        if a_eval:
            self.idref['ref'] = self.id_get
            # ensure the args are a list (sometimes folks eval a tuple which
            # is inconvenient when trying to concatenate w/ a list)
            args = list(safe_eval(a_eval, self.idref))
        else:
            args = [
                r for r in (_eval_xml(self, n, env) for n in node)
                if r is not None
            ]

        model = env[node.get('model')]
        method_name = node.get('name')
        method = getattr(model, method_name)

        # this mess is necessary to merge @context and a possible positional
        # context parameter, as <function> works on the old API so ids and
        # context are just args
        ids, args = [], list(args)
        if getattr(method, '_api', None) not in ('model', 'model_create'):
            ids, args = args[:1], args[1:]
        context, args, kwargs = api.split_context(method, args, {})
        kwargs['context'] = {**env.context, **(context or {})}

        return odoo.api.call_kw(model, method_name, ids + args, kwargs)
    elif node.tag == "test":
        return node.text
Example #5
0
def format_python(model_name, method_name, args, kwargs, result=None):
    fields_to_replace_in_context = []
    args_to_replace = {}
    stack_pre_call = []
    stack_post_call = []
    env_call = ''
    context_call = ''

    def append_call(variable_name, element, todo, replace_in_context):
        element_output = '%s = %s' % (variable_name, element)
        if todo:
            stack_pre_call.append(
                '# TODO: Check or Find %s link (external id or otherwise)' %
                (variable_name))
        stack_pre_call.append(element_output)
        if replace_in_context:
            fields_to_replace_in_context.append(variable_name)

    model = request.env[model_name].sudo()
    method = getattr(type(model), method_name)

    # Object calling
    if getattr(method, '_api', None) in ['model', 'model_create']:
        if method_name in ['create', 'name_create']:
            env_call = 'record = self.env[\'%s\']' % (model._name)
        else:
            env_call = 'self.env[\'%s\']' % (model._name)
    else:
        ids, args = args[0], args[1:]
        ids_name, todo_ids = get_env_ref_multi(ids, model_name)
        if method_name == 'copy':
            append_call('record_ids', ids_name, todo_ids, False)
            env_call = 'record = self.env[\'%s\'].browse(record_ids)' % (
                model._name)
        else:
            append_call('record_ids', ids_name, todo_ids, False)
            env_call = 'self.env[\'%s\'].browse(record_ids)' % (model._name)
    # Context
    context, args, kwargs = api.split_context(method, args, kwargs)
    if context and 'active_id' in context:
        active_id_name, todo_active_id = get_env_ref_single(
            context['active_id'], context['active_model'])
        append_call('active_id', active_id_name, todo_active_id, True)
        active_ids_name, todo_active_ids = get_env_ref_multi(
            context['active_ids'], context['active_model'])
        append_call('active_ids', active_ids_name, todo_active_ids, True)

    # Sudo
    sudo_name = ''
    if context:
        user_id_name, todo_user_id = get_env_ref_single(
            context['uid'], 'res.users')
        append_call('uid', user_id_name, todo_user_id, True)
        if context.get('uid') != SUPERUSER_ID:
            sudo_name = '.with_user(uid)'

    if context:
        for field in fields_to_replace_in_context:
            context[field] = 'FIELD_%s_TO_REPLACE' % field
        context_call = '.with_context(%s)' % pprint.pformat(context)
        for field in fields_to_replace_in_context:
            context_call = context_call.replace(
                "u'FIELD_%s_TO_REPLACE'" % field, field)
            context_call = context_call.replace(
                "'FIELD_%s_TO_REPLACE'" % field, field)

    # args and kwargs
    if method_name in ['create', 'write']:
        args[0] = add_groups_values(model_name, args[0])
        replace_idtoxml(model_name, args[0], args_to_replace)
        for field in args_to_replace:
            args[0][field] = 'FIELD_%s_TO_REPLACE' % field
    args_name = ', '.join(
        ['\'%s\'' % a if isinstance(a, str) else '%s' % ustr(a) for a in args])
    for field in args_to_replace:
        args_name = args_name.replace("u'FIELD_%s_TO_REPLACE'" % field,
                                      args_to_replace[field])
        args_name = args_name.replace("'FIELD_%s_TO_REPLACE'" % field,
                                      args_to_replace[field])
    kwargs_name = ', '.join([
        '%s=%s' %
        (k, '\'%s\'' % kwargs[k] if isinstance(kwargs[k], str) else '%s' %
         ustr(kwargs[k])) for k in kwargs
    ])
    args_name += ', %s' % (kwargs_name) if kwargs_name else ''
    method_call = '%s%s%s.%s(%s)' % (env_call, context_call, sudo_name,
                                     method_name, args_name)
    if method_name in ['create', 'copy', 'name_create'] and result:
        if method_name == 'name_create':
            result = result[0]
        stack_post_call.append(
            generate_xml_id(result, model_name, result_name='record'))

    # CONCATENATION
    return format_call_stack(stack_pre_call, stack_post_call, method_call)
Example #6
0
def _eval_xml(self, node, env):
    if node.tag in ('field', 'value'):
        t = node.get('type', 'char')
        f_model = node.get('model')
        if node.get('search'):
            f_search = node.get("search")
            f_use = node.get("use", 'id')
            f_name = node.get("name")
            idref2 = {}
            if f_search:
                idref2 = _get_idref(self, env, f_model, self.idref)
            q = safe_eval(f_search, idref2)
            ids = env[f_model].search(q).ids
            if f_use != 'id':
                ids = [
                    x[f_use] for x in env[f_model].browse(ids).read([f_use])
                ]
            _fields = env[f_model]._fields
            if (f_name in _fields) and _fields[f_name].type == 'many2many':
                return ids
            f_val = False
            if len(ids):
                f_val = ids[0]
                if isinstance(f_val, tuple):
                    f_val = f_val[0]
            return f_val
        a_eval = node.get('eval')
        if a_eval:
            idref2 = _get_idref(self, env, f_model, self.idref)
            try:
                return safe_eval(a_eval, idref2)
            except Exception:
                logging.getLogger('odoo.tools.convert.init').error(
                    'Could not eval(%s) for %s in %s', a_eval,
                    node.get('name'), env.context)
                raise

        def _process(s):
            matches = re.finditer(br'[^%]%\((.*?)\)[ds]'.decode('utf-8'), s)
            done = set()
            for m in matches:
                found = m.group()[1:]
                if found in done:
                    continue
                done.add(found)
                id = m.groups()[0]
                if not id in self.idref:
                    self.idref[id] = self.id_get(id)
                # So funny story: in Python 3, bytes(n: int) returns a
                # bytestring of n nuls. In Python 2 it obviously returns the
                # stringified number, which is what we're expecting here
                s = s.replace(found, str(self.idref[id]))
            s = s.replace(
                '%%', '%'
            )  # Quite weird but it's for (somewhat) backward compatibility sake
            return s

        if t == 'xml':
            _fix_multiple_roots(node)
            return '<?xml version="1.0"?>\n'\
                +_process("".join(etree.tostring(n, encoding='unicode') for n in node))
        if t == 'html':
            return _process("".join(
                etree.tostring(n, encoding='unicode') for n in node))

        data = node.text
        if node.get('file'):
            with file_open(node.get('file'), 'rb') as f:
                data = f.read()

        if t == 'base64':
            return base64.b64encode(data)

        # after that, only text content makes sense
        data = pycompat.to_text(data)
        if t == 'file':
            from ..modules import module
            path = data.strip()
            if not module.get_module_resource(self.module, path):
                raise IOError("No such file or directory: '%s' in %s" %
                              (path, self.module))
            return '%s,%s' % (self.module, path)

        if t == 'char':
            return data

        if t == 'int':
            d = data.strip()
            if d == 'None':
                return None
            return int(d)

        if t == 'float':
            return float(data.strip())

        if t in ('list', 'tuple'):
            res = []
            for n in node.iterchildren(tag='value'):
                res.append(_eval_xml(self, n, env))
            if t == 'tuple':
                return tuple(res)
            return res
    elif node.tag == "function":
        a_eval = node.get('eval')
        if a_eval:
            self.idref['ref'] = self.id_get
            # ensure the args are a list (sometimes folks eval a tuple which
            # is inconvenient when trying to concatenate w/ a list)
            args = list(safe_eval(a_eval, self.idref))
        else:
            args = [
                r for r in (_eval_xml(self, n, env) for n in node)
                if r is not None
            ]

        model = env[node.get('model')]
        method_name = node.get('name')
        method = getattr(model, method_name)

        # this mess is necessary to merge @context and a possible positional
        # context parameter, as <function> works on the old API so ids and
        # context are just args
        ids, args = [], list(args)
        if getattr(method, '_api', None) not in ('model', 'model_create'):
            ids, args = args[:1], args[1:]
        context, args, kwargs = api.split_context(method, args, {})
        kwargs['context'] = {**env.context, **(context or {})}

        return odoo.api.call_kw(model, method_name, ids + args, kwargs)
    elif node.tag == "test":
        return node.text