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
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])
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
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
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)
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