def get_filtered_partners_for_user(self, user): """Returns recordset with res.partner objects for a specific user, following the rules provided by self""" partner_obj = self.env['res.partner'] records = self.env['res.partner'] for f in self: if f.filter_type == 'python': shared_local_dict = {'env': self.env} if f.filter_level == 'user': shared_local_dict['user'] = user safe_eval(f.python_filter, shared_local_dict, mode="exec", nocopy=True) r = shared_local_dict['result'] else: r = partner_obj.search( safe_eval(f.domain_filter, locals_dict={'user': user}, nocopy=True)) records += r # Removes duplicates return partner_obj.browse(set(records.ids))
def get_warehouses(self, warehouse_id=None, domain=None): warehouse = self.env['stock.warehouse'].sudo() if warehouse_id: return warehouse.browse(warehouse_id) if domain: if not isinstance(domain, (list, tuple)): domain = tools.safe_eval(domain) else: domain = [] if 'allowed_company_ids' in self.env.context: domain.append(('company_id', 'in', self.env.context['allowed_company_ids'])) if self.env.context.get('warehouse_domain'): domain.extend(self.env.context.get('warehouse_domain')) irconfig_parameter = self.env['ir.config_parameter'].sudo() if irconfig_parameter.get_param('sale.order.planner.warehouse_domain'): domain.extend( tools.safe_eval( irconfig_parameter.get_param( 'sale.order.planner.warehouse_domain'))) return warehouse.search(domain)
def is_following_rules(self, partner, user=None): """Returns True if provided res.partner record follows filters in self""" partner_obj = self.env['res.partner'] for f in self: if f.filter_type == 'python': shared_local_dict = {'env': self.env} if f.filter_level == 'user': shared_local_dict['user'] = user safe_eval(f.python_filter, shared_local_dict, mode="exec", nocopy=True) if partner in shared_local_dict['result']: return True else: domain = safe_eval(f.domain_filter, locals_dict={'user': user}, nocopy=True) domain.insert(0, ('id', '=', partner.id)) if partner_obj.search(domain): return True return False
def generate_coupon(self): program = self 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, }) if self.generation_type == 'nbr_vehicles' and self.vehicles_domain: for vehicle in self.env['partner.vehicle'].search( safe_eval(self.vehicles_domain)): vals.update({'vehicle_id': vehicle.id}) self.env['sale.coupon'].create(vals)
def _etl_res_field_value(self, model_object, formio_component): """ :param model_object object: Model object :param formio_component object: formiodata Component object """ # TODO exception handling, if safe_eval(domain_str) or merge lists fail ? value = None properties = formio_component.properties or {} res_field_value = properties.get('res_field') noupdate_form_domain = properties.get('noupdate_form') res_field_noupdate_domain = properties.get('res_field_noupdate') update = True # first check formio.form whether to update if noupdate_form_domain: update = not self.filtered_domain(safe_eval(noupdate_form_domain)) # if still may update, then check the resource model object if update: if res_field_noupdate_domain: update = not model_object.filtered_domain(safe_eval(res_field_noupdate_domain)) if update: value = self._etl_odoo_field_val(model_object, res_field_value, formio_component) return value
def _from_vobject_code(self, child): self.ensure_one() context = { 'datetime': datetime, 'dateutil': dateutil, 'item': child, 'result': None, 'tools': tools, 'tz': tz, 'vobject': vobject, } tools.safe_eval(self.import_code, context, mode="exec", nocopy=True) return context.get('result', {})
def _to_vobject_code(self, record): self.ensure_one() context = { 'datetime': datetime, 'dateutil': dateutil, 'record': record, 'result': None, 'tools': tools, 'tz': tz, 'vobject': vobject, } tools.safe_eval(self.export_code, context, mode="exec", nocopy=True) return context.get('result', None)
def action_compute_value(self): for kpi in self: if kpi.value_method == 'kpi_quantity': # compute the number of KPI new_value = self.env['board.kpi.value'].create({ 'kpi_id': kpi.id, 'value': len(self.env['board.kpi'].search([])), }) elif kpi.value_method == 'code' and kpi.method_code: context = self._get_eval_context(kpi) try: tools.safe_eval(kpi.method_code.strip(), context, mode="exec", nocopy=True) except Exception as e: raise ValidationError("Wrong python code:" + str(e))
def _get_python_value(self, number_next): """ Use the python formula to get the value. :return: string """ eval_context = self._get_python_eval_context(number_next) return safe_eval(self.python_code.strip(), eval_context)
def from_json(self, json_value): """ Converts the JSON value to Odoo field value. :param json_value: JSON representation of the field :return: odoo data (dict) """ self.ensure_one() # Skip empty values if not json_value and not isinstance(json_value, (bool, int, float)): return {} # Skip invalid data if isinstance(json_value, str) and json_value.lower() in ( "null", "false", "none", "other", "unknown", ): return {} converted_value = json_value field_name = self.field_name if self.from_json_conversion: # Calls a conversion method defined in mapping converted_value = safe_eval( self.from_json_conversion, { "json_value": json_value, "self": self }, ) if self.relational_field_id: converted_value = self._json_to_relational_value(converted_value) field_name = self.relational_field_id.name return {field_name: converted_value}
def _add_delivery_cost_to_so(self): """Update delivery price in SO from picking data.""" res = super(StockPicking, self)._add_delivery_cost_to_so() get_param = self.env['ir.config_parameter'].sudo().get_param param = 'delivery_auto_refresh.refresh_after_picking' if not safe_eval(get_param(param, '0')): return res self.ensure_one() sale_order = self.sale_id if not sale_order or not self.carrier_id: # pragma: no cover return res so_line = sale_order.order_line.filtered(lambda x: x.is_delivery)[:1] if not so_line: # pragma: no cover return res total = weight = volume = quantity = 0 for move_line in self.move_line_ids.filtered('qty_done'): if not move_line.product_id: continue move = move_line.move_id qty = move.product_uom._compute_quantity( move_line.qty_done, move_line.product_id.uom_id, ) weight += (move_line.product_id.weight or 0.0) * qty volume += (move_line.product_id.volume or 0.0) * qty quantity += qty total += move.sale_line_id.price_unit * qty total = sale_order.currency_id._convert( total, sale_order.company_id.currency_id, sale_order.company_id, sale_order.date_order) so_line.price_unit = self.carrier_id._get_price_from_picking( total, weight, volume, quantity, ) return res
def onchange_domain(self): if self.res_model == 'recurring.contract': if self.partner_source == 'send_gifts_to': # We assume the payer and the correspondent speak same lang partner_source = 'correspondent_id' else: partner_source = self.partner_source if self.force_language and not self.language_added_in_domain: domain = self.selection_domain or '[]' domain = domain[:-1] + ", ('{}.lang', '=', '{}')]".format( partner_source, self.force_language) self.selection_domain = domain.replace('[, ', '[') self.language_added_in_domain = True if self.selection_domain: self.sponsorship_ids = self.env['recurring.contract'].search( safe_eval(self.selection_domain)) if self.partner_source == 'send_gifts_to': partners = self.env['res.partner'] for sponsorship in self.sponsorship_ids: partners += sponsorship.mapped( sponsorship.send_gifts_to) else: partners = self.sponsorship_ids.mapped(partner_source) self.partner_ids = partners if not self.force_language: self.language_added_in_domain = False else: super(GenerateCommunicationWizard, self).onchange_domain()
def name_search(self, name='', args=None, operator='ilike', limit=None): data = self.env.context.get('model_list') if data: args.append(('model', 'in', safe_eval(data))) ret_vat = super(IrModelFields, self).name_search( name=name, args=args, operator=operator, limit=limit) return ret_vat
def _evaluate_expression(self, record): """ Evaluate expression if set """ self.ensure_one() return not self.expression or tools.safe_eval(self.expression, { 'object': record, 'user': self.env.user })
def get_shipping_carriers(self, carrier_id=None, domain=None, warehouse_id=None): Carrier = self.env['delivery.carrier'].sudo() if carrier_id: return Carrier.browse(carrier_id) if domain: if not isinstance(domain, (list, tuple)): domain = tools.safe_eval(domain) if self.env.context.get('carrier_domain'): if not domain: domain = [] domain.extend(self.env.context.get('carrier_domain')) if domain: return Carrier.search(domain) # no domain, use global if warehouse_id: warehouse = self.env['stock.warehouse'].sudo().browse(warehouse_id) if warehouse.sale_planner_carrier_ids: return warehouse.sale_planner_carrier_ids.sudo() carrier_ids = sale_planner_carrier_ids(self.env, self.env.user.company_id) return Carrier.browse(carrier_ids)
def get_warehouses(self, warehouse_id=None, domain=None): warehouse = self.env['stock.warehouse'].sudo() if warehouse_id: return warehouse.browse(warehouse_id) if domain: if not isinstance(domain, (list, tuple)): domain = tools.safe_eval(domain) else: domain = [] if 'allowed_company_ids' in self.env.context: domain.append(('company_id', 'in', self.env.context['allowed_company_ids'])) if self.env.context.get('warehouse_domain'): if not domain: domain = [] domain.extend(self.env.context.get('warehouse_domain')) if domain: return warehouse.search(domain) # no domain, use global warehouse_ids = sale_planner_warehouse_ids(self.env, self.env.user.company_id) return warehouse.browse(warehouse_ids)
def action_sync(self): """Sync contacts in dynamic lists.""" Contact = self.env["mail.mass_mailing.contact"] Partner = self.env["res.partner"] # Skip non-dynamic lists dynamic = self.filtered("dynamic").with_context(syncing=True) for one in dynamic: sync_domain = safe_eval(one.sync_domain) + [("email", "!=", False)] desired_partners = Partner.search(sync_domain) # Remove undesired contacts when synchronization is full if one.sync_method == "full": Contact.search([ ("list_id", "=", one.id), ("partner_id", "not in", desired_partners.ids), ]).unlink() current_contacts = Contact.search([("list_id", "=", one.id)]) current_partners = current_contacts.mapped("partner_id") # Add new contacts for partner in desired_partners - current_partners: Contact.create({ "list_id": one.id, "partner_id": partner.id, }) # Invalidate cached contact count self.invalidate_cache(["contact_nbr"], dynamic.ids)
def _check_record_rules_result_count(self, result_ids, operation): try: super(Base, self)._check_record_rules_result_count( result_ids, operation) except AccessError: log_msg = "Validation error triggered by ir.rule(%s)" Rule = self.env['ir.rule'] rule_ids = Rule._get_rules_to_apply(self._name, operation) rules = Rule.sudo().with_context( lang=self.env.user.lang).browse(rule_ids) global_rules = rules.filtered(lambda rule: not rule.groups) for rule in global_rules: if not rule.domain_force: continue domain = tools.safe_eval(rule.domain_force, rule._eval_context()) domain = expression.normalize_domain([('id', 'in', self.ids)] + domain) records_count = self.search_count(domain) if records_count < len(self): _logger.info(log_msg % rule.id) if rule.error_message: raise UserError(rule.error_message) break else: group_rules = rules - global_rules _logger.info(log_msg % ','.join(map(str, group_rules.ids))) error_messages = group_rules.mapped('error_message') if all(error_messages): raise UserError("\n\n".join(error_messages)) raise
def _move_domain_get(self, domain=None): context = dict(self._context or {}) domain = domain and safe_eval(str(domain)) or [] date_field = 'date' if context.get('aged_balance'): date_field = 'date_maturity' if context.get('date_to'): domain += [(date_field, '<=', context['date_to'])] if context.get('date_from'): if not context.get('strict_range'): domain += ['|', (date_field, '>=', context['date_from']), ('account_id.user_type_id.include_initial_balance', '=', True)] elif context.get('initial_bal'): domain += [(date_field, '<', context['date_from'])] else: domain += [(date_field, '>=', context['date_from'])] if context.get('journal_ids'): domain += [('journal_id', 'in', context['journal_ids'])] state = context.get('state') if state and state.lower() != 'all': domain += [('move_id.state', '=', state)] if context.get('company_id'): domain += [('company_id', '=', context['company_id'])] if 'company_ids' in context: domain += [('company_id', 'in', context['company_ids'])] if context.get('reconcile_date'): domain += ['|', ('reconciled', '=', False), '|', ('matched_debit_ids.create_date', '>', context['reconcile_date']), ('matched_credit_ids.create_date', '>', context['reconcile_date'])] return domain
def to_json(self, odoo_value): """ Converts the value to its JSON representation. :return: JSON representation (dict) of the field value in JSON """ self.ensure_one() res = {self.json_name: odoo_value} if self.to_json_conversion: res[self.json_name] = safe_eval( self.to_json_conversion, { "odoo_value": odoo_value, "self": self, "fields": fields }, ) elif (self.field_id.ttype not in ("boolean", "float", "integer", "monetary") and not odoo_value): # Don't include null fields return {} elif self.field_id.ttype == "datetime": res[self.json_name] = fields.Datetime.to_string(odoo_value) elif self.field_id.ttype == "date": res[self.json_name] = fields.Date.to_string(odoo_value) return res
def onchange_template_id(self, template_id, composition_mode, model, res_id): values = super().onchange_template_id( template_id, composition_mode, model, res_id) if template_id and model == 'account.payment.group': payment_group = self.env[model].browse(res_id) if payment_group.partner_type != 'supplier': return values report = self.env.ref('l10n_ar_account_withholding.action_report_withholding_certificate', raise_if_not_found=False) if not report: return values attachment_ids = [] for payment in payment_group.payment_ids.filtered(lambda p: p.payment_method_code == 'withholding'): report_name = safe_eval(report.print_report_name, {'object': payment, 'time': time}) result, format = report.render(payment.ids) file = base64.b64encode(result) data_attach = { 'name': report_name, 'datas': file, 'res_model': 'mail.compose.message', 'res_id': 0, 'type': 'binary', } attachment_ids.append(self.env['ir.attachment'].create(data_attach).id) if values.get('value', False) and values['value'].get('attachment_ids', []) or attachment_ids: values_attachment_ids = values['value'].get('attachment_ids', False) and values['value']['attachment_ids'][0][2] or [] values['value']['attachment_ids'] = [(6, 0, values_attachment_ids + attachment_ids)] return values
def edit_workflow(self): self.ensure_one() # By default we want to edit current workflow edit = self # For live workflow we want to create working copy or reuse it. if self.is_live(): if len(self.edit_ids) == 0: edit = self.copy({ 'name': "Draft Version of '%s'" % (self.name,), 'state': 'draft', 'default_state_id': self.default_state_id.id, 'original_id': self.id }) pass else: edit = self.edit_ids[0] action = self.env['ir.actions.act_window'].for_xml_id( 'project_workflow', 'project_workflow_diagram_edit_action' ) ctx = safe_eval(action['context']) ctx['active_id'] = edit.id ctx['active_ids'] = [edit.id] action['res_id'] = edit.id action['context'] = ctx return action
def add_modules(self, cr, module_list, force=None): if force is None: force = [] packages = [] len_graph = len(self) # force additional dependencies for the upgrade process if given # in config file forced_deps = tools.config.get_misc('openupgrade', 'force_deps', '{}') forced_deps = tools.config.get_misc('openupgrade', 'force_deps_' + release.version, forced_deps) forced_deps = safe_eval(forced_deps) for module in module_list: # This will raise an exception if no/unreadable descriptor file. # NOTE The call to load_information_from_description_file is already # done by db.initialize, so it is possible to not do it again here. info = odoo.modules.module.load_information_from_description_file( module) if info and info['installable']: info['depends'].extend(forced_deps.get(module, [])) packages.append( (module, info) ) # TODO directly a dict, like in get_modules_with_version elif module != 'studio_customization': _logger.warning('module %s: not installable, skipped', module) dependencies = dict([(p, info['depends']) for p, info in packages]) current, later = set([p for p, info in packages]), set() while packages and current > later: package, info = packages[0] deps = info['depends'] # if all dependencies of 'package' are already in the graph, add 'package' in the graph if reduce(lambda x, y: x and y in self, deps, True): if not package in current: packages.pop(0) continue later.clear() current.remove(package) node = self.add_node(package, info) for kind in ('init', 'demo', 'update'): if package in tools.config[kind] or 'all' in tools.config[ kind] or kind in force: setattr(node, kind, True) else: later.add(package) packages.append((package, info)) packages.pop(0) self.update_from_db(cr) for package in later: unmet_deps = filter(lambda p: p not in self, dependencies[package]) _logger.error('module %s: Unmet dependencies: %s', package, ', '.join(unmet_deps)) return len(self) - len_graph
def accept_document(self): created = [] for r in self: vals = { "xml_file": r.xml.encode("ISO-8859-1"), "filename": r.dte_id.name, "pre_process": False, "document_id": r.id, "option": "accept", } val = self.env["sii.dte.upload_xml.wizard"].create(vals) created.extend(val.confirm(ret=True)) r.state = "accepted" xml_id = "account.action_invoice_tree2" result = self.env.ref("%s" % (xml_id)).read()[0] if created: domain = "" try: domain = safe_eval(result["domain"]) domain.append(("id", "in", created)) result["domain"] = domain except: _logger.warning("Problema con Result Domain") _logger.warning(result) # result['domain'] = 'konos.cl' return result
def rebuild_documents(self): self.ensure_one() domain = safe_eval(self.domain) elements = self.env[self.model].search(domain).ids documents = {r.odoo_id: r.id for r in self.document_ids} creates = [] rebuilds = [] # Delete unnecessary documents for element in elements: if element in documents: rebuilds.append(documents.pop(element)) else: creates.append(element) logging.info("Deleting") for document in documents: self.env['elasticsearch.document'].browse( documents[document]).unlink() logging.info("Creating") for create in creates: self.env['elasticsearch.document'].create({ 'odoo_id': create, 'index_id': self.id, 'model': self.model, }) logging.info("Updating") for rebuild in rebuilds: self.env['elasticsearch.document'].browse(rebuild).export_update() logging.info("Done")
def print_document(self, record_ids, data=None): """ Print a document, do not return the document file """ document, doc_format = self.with_context( must_skip_send_to_printer=True).render_qweb_pdf( record_ids, data=data) behaviour = self.behaviour() printer = behaviour.pop('printer', None) if not printer: raise exceptions.Warning( _('No printer configured to print this report.') ) if self.print_report_name: report_file_names = [ safe_eval(self.print_report_name, {"object": obj, "time": time}) for obj in self.env[self.model].browse(record_ids) ] title = " ".join(report_file_names) if len(title) > 80: title = title[:80] + "…" else: title = self.report_name behaviour["title"] = title # TODO should we use doc_format instead of report_type return printer.print_document(self, document, doc_format=self.report_type, **behaviour)
def action_sync(self): """Sync contacts in dynamic lists.""" Contact = self.env["mailing.contact"].with_context(syncing=True) Partner = self.env["res.partner"] # Skip non-dynamic lists dynamic = self.filtered("dynamic").with_context(syncing=True) for one in dynamic: sync_domain = [("email", "!=", False)] + safe_eval(one.sync_domain) desired_partners = Partner.search(sync_domain) # Detach or remove undesired contacts when synchronization is full if one.sync_method == "full": contact_to_detach = one.contact_ids.filtered( lambda r: r.partner_id not in desired_partners) one.contact_ids -= contact_to_detach contact_to_detach.filtered(lambda r: not r.list_ids).unlink() # Add new contacts current_partners = one.contact_ids.mapped("partner_id") contact_to_list = self.env["mailing.contact"] vals_list = [] for partner in desired_partners - current_partners: contacts_in_partner = partner.mass_mailing_contact_ids if contacts_in_partner: contact_to_list |= contacts_in_partner[0] else: vals_list.append({ "list_ids": [(4, one.id)], "partner_id": partner.id }) one.contact_ids |= contact_to_list Contact.create(vals_list) one.is_synced = True # Invalidate cached contact count self.invalidate_cache(["contact_nbr"], dynamic.ids)
def _get_param_auto_add_delivery_line(self): get_param = self.env["ir.config_parameter"].sudo().get_param param = "delivery_auto_refresh.auto_add_delivery_line" # When we have the context 'website_id' it means that we are doing the order from # e-commerce. So we don't want to add the delivery line automatically. if self.env.context.get("website_id"): return False return safe_eval(get_param(param, "0"))
def _get_aeroo_timezone(self, record): """Get the timezone to use in the report for a given record. :rtype: res.company """ return ( safe_eval(self.aeroo_tz_eval, self._get_aeroo_variable_eval_context(record)) if self.aeroo_tz_eval else None )
def _check_condition(self, res_id): self.ensure_one() if self.filter_domain: domain = [('id', '=', res_id)] domain += safe_eval(self.filter_domain, self._get_eval_context()) model = self.env[self.model_name] return bool(model.search_count(domain)) else: return True
def name_search(self, name='', args=None, operator='ilike', limit=None): data = self.env.context.get('model_list') if data: args.append(('model', 'in', safe_eval(data))) ret_vat = super(IrModelFields, self).name_search(name=name, args=args, operator=operator, limit=limit) return ret_vat
def onchange_domain(self): if self.force_language and not self.language_added_in_domain: domain = self.selection_domain or '[]' domain = domain[:-1] + ", ('lang', '=', '{}')]".format( self.force_language) self.selection_domain = domain.replace('[, ', '[') self.language_added_in_domain = True if self.selection_domain: self.partner_ids = self.env['res.partner'].search( safe_eval(self.selection_domain)) if not self.force_language: self.language_added_in_domain = False
def open_payments_action(self, payment_type, mode='tree'): if payment_type == 'outbound': action_ref = 'account.action_account_payments_payable' elif payment_type == 'transfer': action_ref = 'account.action_account_payments_transfer' else: action_ref = 'account.action_account_payments' [action] = self.env.ref(action_ref).read() action['context'] = dict(safe_eval(action.get('context')), default_journal_id=self.id, search_default_journal_id=self.id) if mode == 'form': action['views'] = [[False, 'form']] return action
def onchange_month(self): if self.month: domain = safe_eval(self.selection_domain) month_select = ('child_id.birthday_month', '=', self.month) index = 0 for filter in domain: if filter[0] == 'child_id.birthday_month': index = domain.index(filter) if index: domain[index] = month_select else: domain.append(month_select) self.selection_domain = str(domain)
def save_metric_value(self, metric_interfaces): """ Saves a metric value from the given interface Args: metric_interfaces (clouder.metric.interface): The interface to use Returns: None """ for iface in metric_interfaces: eval_context = iface.type_id._get_query_code_context(iface) try: safe_eval( iface.query_code, eval_context, mode='exec', nocopy=True, ) except Exception as e: raise UserError(_( 'Error while evaluating metrics query:' '\n %s \n %s' % (iface.name, e), )) if eval_context.get('value') is None: raise ValidationError(_( 'Metrics query did not set the `value` variable, which ' 'is used to indicate the value that should be saved for ' 'the query.', )) uom = eval_context.get('uom') or iface.uom_id iface.write({ 'metric_value_ids': [(0, 0, { 'value': eval_context['value'], 'date_start': eval_context.get('date_start'), 'date_end': eval_context.get('date_end'), 'uom_id': uom.id, })], })
def onchange_domain(self): if self.res_model == 'recurring.contract': if self.force_language and not self.language_added_in_domain: domain = self.selection_domain or '[]' domain = domain[:-1] + ", ('{}.lang', '=', '{}')]".format( self.partner_source, self.force_language) self.selection_domain = domain.replace('[, ', '[') self.language_added_in_domain = True if self.selection_domain: self.sponsorship_ids = self.env['recurring.contract'].search( safe_eval(self.selection_domain)) self.partner_ids = self.sponsorship_ids.mapped( self.partner_source) if not self.force_language: self.language_added_in_domain = False else: super(GenerateCommunicationWizard, self).onchange_domain()
def apply_domain(self): return { 'domain': {'invoice_line_ids': safe_eval(self.domain)} }
def onchange_domain(self): if self.selection_domain: self.sponsorship_ids = self.env['recurring.contract'].search( safe_eval(self.selection_domain))
def get_data(self, row, columns, records, nber_labels): """ Function called in the xml in order to get the datas for one page (in dynamic_label.xml). If multiple ids are given, the labels will be grouped by ids (therefore N Bob, then N Will, ...). :param int row: Number of row for one page of labels :param int columns: Number of columns of labels :param records: recordset used for the labels :param int nber_labels: Number of labels of each ids :returns: Data to print :rtype: list[page,row,columns,value] = dict """ label_print_obj = self.env['label.print'] label_print_data = label_print_obj.browse( self.env.context.get('label_print')) tot = nber_labels * len(records) tot_page = int(ceil(float(ceil(tot) / (columns*row)))) # return value result = [] for i in range(tot_page): result.append( [[[{'type': '', 'style': '', 'value': ''}] for i in range(columns)] for j in range(row)]) # current indices cur_row = 0 cur_col = 0 cur_page = 0 # loop over all the items for record in records: # value to add vals = [] # loop over each field for one label for field in label_print_data.sudo().field_ids: if field.python_expression and field.python_field: value = safe_eval(field.python_field, {'obj': record}) elif field.field_id.name: value = getattr(record, field.field_id.name) if not value: continue if isinstance(value, browse_record): model_obj = self.pool.get(value._name) value = safe_eval( "obj." + model_obj._rec_name, {'obj': value}) if not value: value = '' # always put the image or barcode in first in order # to make a column for it first = False if field.type == 'barcode': first = True # style is for CSS in HTML vals_dict = {'value': value, 'type': field.type, 'style': "font-size:" + str(field.fontsize)+"px;"} if first: vals.insert(0, vals_dict) else: vals.append(vals_dict) for i in range(nber_labels): result[cur_page][cur_row][cur_col] = deepcopy(vals) cur_col += 1 if cur_col >= columns: cur_col = 0 cur_row += 1 if cur_row >= row: cur_page += 1 cur_row = 0 return result