def _satisfy_condition(self, localdict): """ @param contract_id: id of hr.contract to be tested @return: returns True if the given rule match the condition for the given contract. Return False otherwise. """ self.ensure_one() if self.condition_select == 'none': return True elif self.condition_select == 'range': try: result = safe_eval(self.condition_range, localdict) return self.condition_range_min <= result and result <= self.condition_range_max or False except: raise UserError( _('Wrong range condition defined for salary rule %s (%s).') % (self.name, self.code)) else: # python code try: safe_eval(self.condition_python, localdict, mode='exec', nocopy=True) return 'result' in localdict and localdict['result'] or False except: raise UserError( _('Wrong python condition defined for salary rule %s (%s).' ) % (self.name, self.code))
def compute_all(self, price_unit, currency=None, quantity=1.0, product=None, partner=None): taxes = self.filtered(lambda r: r.amount_type != 'code') company = self.env.user.company_id for tax in self.filtered(lambda r: r.amount_type == 'code'): localdict = self._context.get('tax_computation_context', {}) localdict.update({ 'price_unit': price_unit, 'quantity': quantity, 'product': product, 'partner': partner, 'company': company }) safe_eval(tax.python_applicable, localdict, mode="exec", nocopy=True) if localdict.get('result', False): taxes += tax return super(AccountTaxPython, taxes).compute_all(price_unit, currency, quantity, product, partner)
def get_google_drive_config(self, res_model, res_id): ''' Function called by the js, when no google doc are yet associated with a record, with the aim to create one. It will first seek for a google.docs.config associated with the model `res_model` to find out what's the template of google doc to copy (this is usefull if you want to start with a non-empty document, a type or a name different than the default values). If no config is associated with the `res_model`, then a blank text document with a default name is created. :param res_model: the object for which the google doc is created :param ids: the list of ids of the objects for which the google doc is created. This list is supposed to have a length of 1 element only (batch processing is not supported in the code, though nothing really prevent it) :return: the config id and config name ''' # TO DO in master: fix my signature and my model if isinstance(res_model, str): res_model = self.env['ir.model'].search([('model', '=', res_model)]).id if not res_id: raise UserError(_("Creating google drive may only be done by one at a time.")) # check if a model is configured with a template configs = self.search([('model_id', '=', res_model)]) config_values = [] for config in configs.sudo(): if config.filter_id: if config.filter_id.user_id and config.filter_id.user_id.id != self.env.user.id: #Private continue domain = [('id', 'in', [res_id])] + safe_eval(config.filter_id.domain) additionnal_context = safe_eval(config.filter_id.context) google_doc_configs = self.env[config.filter_id.model_id].with_context(**additionnal_context).search(domain) if google_doc_configs: config_values.append({'id': config.id, 'name': config.name}) else: config_values.append({'id': config.id, 'name': config.name}) return config_values
def transfer_node_to_modifiers(node, modifiers, context=None, in_tree_view=False): if node.get('attrs'): modifiers.update(safe_eval(node.get('attrs'))) if node.get('states'): if 'invisible' in modifiers and isinstance(modifiers['invisible'], list): # TODO combine with AND or OR, use implicit AND for now. modifiers['invisible'].append( ('state', 'not in', node.get('states').split(','))) else: modifiers['invisible'] = [('state', 'not in', node.get('states').split(','))] for a in ('invisible', 'readonly', 'required'): if node.get(a): v = bool(safe_eval(node.get(a), {'context': context or {}})) if in_tree_view and a == 'invisible': # Invisible in a tree view has a specific meaning, make it a # new key in the modifiers attribute. modifiers['column_invisible'] = v elif v or (a not in modifiers or not isinstance(modifiers[a], list)): # Don't set the attribute to False if a dynamic value was # provided (i.e. a domain from attrs or states). modifiers[a] = v
def run_action_code_multi(self, action, eval_context=None): safe_eval(action.sudo().code.strip(), eval_context, mode="exec", nocopy=True) # nocopy allows to return 'action' if 'action' in eval_context: return eval_context['action']
def execute_code(self, code_exec): def reconciled_inv(): """ returns the list of invoices that are set as reconciled = True """ return self.env['account.invoice'].search([('reconciled', '=', True)]).ids def order_columns(item, cols=None): """ This function is used to display a dictionary as a string, with its columns in the order chosen. :param item: dict :param cols: list of field names :returns: a list of tuples (fieldname: value) in a similar way that would dict.items() do except that the returned values are following the order given by cols :rtype: [(key, value)] """ if cols is None: cols = list(item) return [(col, item.get(col)) for col in cols if col in item] localdict = { 'cr': self.env.cr, 'uid': self.env.uid, 'reconciled_inv': reconciled_inv, # specific function used in different tests 'result': None, # used to store the result of the test 'column_order': None, # used to choose the display order of columns (in case you are returning a list of dict) '_': _, } safe_eval(code_exec, localdict, mode="exec", nocopy=True) result = localdict['result'] column_order = localdict.get('column_order', None) if not isinstance(result, (tuple, list, set)): result = [result] if not result: result = [_('The test was passed successfully')] else: def _format(item): if isinstance(item, dict): return ', '.join([ "%s: %s" % (tup[0], tup[1]) for tup in order_columns(item, column_order) ]) else: return item result = [_format(rec) for rec in result] return result
def button_show_meetings(self): self.ensure_one() action = self.env.ref('calendar.action_calendar_event') action_dict = action.read()[0] if action else {} action_dict['context'] = safe_eval(action_dict.get('context', '{}')) action_dict['context'].update({ 'search_default_teacher_id': self.id, 'default_teacher_id': self.id, }) domain = expression.AND([[('teacher_id', 'in', self.ids)], safe_eval(action.domain or '[]')]) action_dict.update({'domain': domain}) return action_dict
def button_generate_view_issues(self): self.ensure_one() action = self.env.ref( 'issue_education_kanban_view.res_partner_education_issue_action') action_dict = action.read()[0] if action else {} action_dict['context'] = safe_eval(action_dict.get('context', '{}')) action_dict['context'].update({ 'education_schedule_id': self.id, 'school_id': self.center_id.id, }) domain = expression.AND([[('id', 'in', self.student_ids.ids)], safe_eval(action.domain or '[]')]) action_dict.update({'domain': domain}) return action_dict
def button_open_school_claims(self): self.ensure_one() action = self.env.ref('issue_education.action_school_claim') action_dict = action.read()[0] if action else {} action_dict['context'] = safe_eval( action_dict.get('context', '{}')) action_dict['context'].update({ 'default_student_id': self.id, }) domain = expression.AND([ [('student_id', 'in', self.ids)], safe_eval(action.domain or '[]')]) action_dict.update({'domain': domain}) return action_dict
def button_open_students(self): action = self.env.ref('base.action_partner_form') action_dict = action.read()[0] if action else {} domain = expression.AND([ [('id', 'in', self.mapped('student_ids').ids)], safe_eval(action.domain or '[]') ]) context = safe_eval(action.context or '[]') context.pop('search_default_customer') action_dict.update({ 'display_name': _('Students'), 'domain': domain, 'context': context, }) return action_dict
def _get_price_from_picking(self, total, weight, volume, quantity): price = 0.0 criteria_found = False price_dict = { 'price': total, 'volume': volume, 'weight': weight, 'wv': volume * weight, 'quantity': quantity } for line in self.price_rule_ids: test = safe_eval( line.variable + line.operator + str(line.max_value), price_dict) if test: price = line.list_base_price + line.list_price * price_dict[ line.variable_factor] criteria_found = True break if not criteria_found: raise UserError( _("No price rule matching this order; delivery cost cannot be computed." )) return price
def postprocess_pdf_report(self, record, buffer): '''Hook to handle post processing during the pdf report generation. The basic behavior consists to create a new attachment containing the pdf base64 encoded. :param record_id: The record that will own the attachment. :param pdf_content: The optional name content of the file to avoid reading both times. :return: A modified buffer if the previous one has been modified, None otherwise. ''' attachment_name = safe_eval(self.attachment, { 'object': record, 'time': time }) if not attachment_name: return None attachment_vals = { 'name': attachment_name, 'datas': base64.encodestring(buffer.getvalue()), 'res_model': self.model, 'res_id': record.id, 'type': 'binary', } try: self.env['ir.attachment'].create(attachment_vals) except AccessError: _logger.info("Cannot save PDF report %r as attachment", attachment_vals['name']) else: _logger.info('The PDF document %s is now saved in the database', attachment_vals['name']) return buffer
def action_view_task(self): self.ensure_one() list_view_id = self.env.ref('project.view_task_tree2').id form_view_id = self.env.ref('project.view_task_form2').id action = {'type': 'ir.actions.act_window_close'} task_projects = self.tasks_ids.mapped('project_id') if len(task_projects) == 1 and len( self.tasks_ids ) > 1: # redirect to task of the project (with kanban stage, ...) action = self.env.ref( 'project.act_project_project_2_project_task_all').read()[0] if action.get('context'): eval_context = self.env[ 'ir.actions.actions']._get_eval_context() eval_context.update({'active_id': task_projects.id}) action['context'] = safe_eval(action['context'], eval_context) else: action = self.env.ref('project.action_view_task').read()[0] action['context'] = { } # erase default context to avoid default filter if len(self.tasks_ids) > 1: # cross project kanban task action['views'] = [[False, 'kanban'], [list_view_id, 'tree'], [form_view_id, 'form'], [False, 'graph'], [False, 'calendar'], [False, 'pivot']] elif len(self.tasks_ids) == 1: # single task -> form view action['views'] = [(form_view_id, 'form')] action['res_id'] = self.tasks_ids.id # filter on the task of the current SO action.setdefault('context', {}) action['context'].update({'search_default_sale_order_id': self.id}) return action
def create_sale_order_for_student(self): today = fields.Date.context_today(self) date_from = today.replace(month=1, day=1) next_year = today.year + 1 date_to = today.replace(year=next_year, month=12, day=31) academic_years = self.env['education.academic_year'].search([ ('date_start', '>=', date_from), ('date_end', '<=', date_to), ]) if not academic_years: raise Warning(_('There are no valid academic years')) sales = self.env['sale.order'] futures = self.mapped('future_student_ids').filtered( lambda l: l.child_id and not l.sale_order_id and l.academic_year_id in academic_years) if not futures: raise Warning(_('There are not future student to register.')) for future in futures: vals = future.crm_lead_id._get_vals_for_sale_order(future) future.sale_order_id = sales.create(vals) future.sale_order_id.onchange_sale_order_template_id() future.child_id.educational_category = 'student' future.crm_lead_id._put_payer_information_in_sale_order( future, future.sale_order_id) sales += future.sale_order_id action = self.env.ref('sale.action_quotations_with_onboarding') action_dict = action.read()[0] if action else {} domain = expression.AND([ [('id', 'in', sales.ids)], safe_eval(action.domain or '[]')]) action_dict.update({ 'domain': domain, }) return action_dict
def _check_alias_defaults(self): try: dict(safe_eval(self.alias_defaults)) except Exception: raise ValidationError( _('Invalid expression, it must be a literal python dictionary definition e.g. "{\'field\': \'value\'}"' ))
def action_launch(self): """ Launch Action of Wizard""" self.ensure_one() self.write({'state': 'done'}) # Load action action_type = self.action_id.type action = self.env[action_type].browse(self.action_id.id) result = action.read()[0] if action_type != 'ir.actions.act_window': return result result.setdefault('context', '{}') # Open a specific record when res_id is provided in the context ctx = safe_eval(result['context'], {'user': self.env.user}) if ctx.get('res_id'): result['res_id'] = ctx.pop('res_id') # disable log for automatic wizards ctx['disable_log'] = True result['context'] = ctx return result
def test_01_safe_eval(self): """ Try a few common expressions to verify they work with safe_eval """ expected = (1, {"a": 9 * 2}, (True, False, None)) actual = safe_eval('(1, {"a": 9 * 2}, (True, False, None))') self.assertEqual( actual, expected, "Simple python expressions are not working with safe_eval")
def generate_coupon(self): """Generates the number of coupons entered in wizard field nbr_coupons """ program = self.env['sale.coupon.program'].browse( self.env.context.get('active_id')) vals = {'program_id': program.id} if self.generation_type == 'nbr_coupon' and self.nbr_coupons > 0: for count in range(0, self.nbr_coupons): self.env['sale.coupon'].create(vals) if self.generation_type == 'nbr_customer' and self.partners_domain: for partner in self.env['res.partner'].search( safe_eval(self.partners_domain)): vals.update({'partner_id': partner.id}) coupon = self.env['sale.coupon'].create(vals) subject = '%s, a coupon has been generated for you' % ( partner.name) template = self.env.ref( 'sale_coupon.mail_template_sale_coupon', raise_if_not_found=False) if template: template.send_mail(coupon.id, email_values={ 'email_to': partner.email, 'email_from': self.env.user.email or '', 'subject': subject, })
def _is_valid_partner(self, partner): if self.rule_partners_domain: domain = safe_eval( self.rule_partners_domain) + [('id', '=', partner.id)] return bool(self.env['res.partner'].search_count(domain)) else: return True
def format(self, percent, value, grouping=False, monetary=False): """ Format() will return the language-specific output for float values""" self.ensure_one() if percent[0] != '%': raise ValueError( _("format() must be given exactly one %char format specifier")) formatted = percent % value # floats and decimal ints need special action! if grouping: lang_grouping, thousands_sep, decimal_point = self._data_get( monetary) eval_lang_grouping = safe_eval(lang_grouping) if percent[-1] in 'eEfFgG': parts = formatted.split('.') parts[0] = intersperse(parts[0], eval_lang_grouping, thousands_sep)[0] formatted = decimal_point.join(parts) elif percent[-1] in 'diu': formatted = intersperse(formatted, eval_lang_grouping, thousands_sep)[0] return formatted
def button_show_tutored_students(self): self.ensure_one() self = self.with_context(search_default_teacher_id=self.id, default_teacher_id=self.id) action = self.env.ref( 'hr_school.action_hr_employee_supervised_year_form') action_dict = action.read()[0] if action else {} action_dict['context'] = safe_eval(action_dict.get('context', '{}')) action_dict['context'].update({ 'search_default_teacher_id': self.id, 'default_teacher_id': self.id }) domain = expression.AND([[('teacher_id', '=', self.id)], safe_eval(action.domain or '[]')]) action_dict.update({'domain': domain}) return action_dict
def _filter_post_export_domain(self, records): """ Filter the records that satisfy the postcondition of action ``self``. """ if self.filter_domain and records: domain = [('id', 'in', records.ids)] + safe_eval( self.filter_domain, self._get_eval_context()) return records.search(domain), domain else: return records, None
def process_attrs(expr, get, key, val): """ parse `expr` and collect field names in lhs of conditions. """ for domain in safe_eval(expr).values(): if not isinstance(domain, list): continue for arg in domain: if isinstance(arg, (tuple, list)): process_expr(str(arg[0]), get, key, expr)
def _is_valid_product(self, product): # NOTE: if you override this method, think of also overriding _get_valid_products if self.rule_products_domain: domain = safe_eval( self.rule_products_domain) + [('id', '=', product.id)] return bool(self.env['product.product'].search_count(domain)) else: return True
def _onchange_filter_id(self): if self.filter_id: domain = safe_eval(self.filter_id.domain) domain+=['|',('website_id', '=',None),('website_id', '=', self.slider_id.website_id.id),('website_published','=',True)] product_count = self.env['product.template'].sudo().search_count(domain) if product_count < 1: self.filter_id=False raise UserError(_('Sorry! You can not set filter which is content zero product.'))
def get_alias_values(self): has_group_use_lead = self.env.user.has_group('crm.group_use_lead') values = super(Team, self).get_alias_values() values['alias_defaults'] = defaults = safe_eval(self.alias_defaults or "{}") defaults[ 'type'] = 'lead' if has_group_use_lead and self.use_leads else 'opportunity' defaults['team_id'] = self.id return values
def open_calendar_event(self): action = self.env.ref('calendar.action_calendar_event') action_dict = action.read()[0] if action else {} res_model_id = self.env['ir.model']._get_id(self._name) domain = expression.AND([ [('res_id', '=', self.id), ('res_model_id', '=', res_model_id)], safe_eval(action.domain or '[]')]) action_dict.update({'domain': domain}) return action_dict
def button_open_schedule(self): action = self.env.ref('education.action_education_schedule_from_group') action_dict = action.read()[0] if action else {} domain = expression.AND([ [('id', 'in', self.mapped('schedule_ids').ids)], safe_eval(action.domain or '[]')]) action_dict.update({ 'domain': domain, }) return action_dict
def button_account_analytic_line_action(self): self.ensure_one() action = self.env.ref('analytic.account_analytic_line_action_entries') action_dict = action.read()[0] if action else {} action_dict['context'] = safe_eval(action_dict.get('context', '{}'), {'datetime': datetime}) action_dict['context'].update({ 'search_default_claim_id': self.id, 'default_claim_id': self.id, 'default_account_id': self.analytic_account_id.id, }) domain = expression.AND([[('account_id', '=', self.analytic_account_id.id)], safe_eval(action.domain or '[]')]) action_dict.update({'domain': domain}) return action_dict
def _fetch_attachment(self): """ This method will check if we have any existent attachement matching the model and res_ids and create them if not found. """ self.ensure_one() obj = self.env[self.model].browse(self.res_id) if not self.attachment_id: report = self.report_template if not report: report_name = self.env.context.get('report_name') report = self.env['ir.actions.report']._get_report_from_name( report_name) if not report: return False else: self.write({'report_template': report.id}) # report = self.env.ref('account.account_invoices') if report.print_report_name: report_name = safe_eval(report.print_report_name, {'object': obj}) elif report.attachment: report_name = safe_eval(report.attachment, {'object': obj}) else: report_name = 'Document' filename = "%s.%s" % (report_name, "pdf") pdf_bin, _ = report.with_context( snailmail_layout=not self.cover).render_qweb_pdf(self.res_id) attachment = self.env['ir.attachment'].create({ 'name': filename, 'datas': base64.b64encode(pdf_bin), 'res_model': 'snailmail.letter', 'res_id': self.id, 'type': 'binary', # override default_type from context, possibly meant for another model! }) self.write({'attachment_id': attachment.id}) return self.attachment_id