def add_args_to_product_search(self, args=[]): args = expression.normalize_domain(args) if self.area_id: area_domain = [('product_brand_id.restricted_area_ids', 'not in', [self.area_id.id])] args = expression.AND([args, area_domain]) # Si el partner tiene marcas permitidas, se usan las del partner, si no las de la zona allowed_brand_ids = self.allowed_brand_ids.ids or self.area_id.allowed_brand_ids.ids or [] # Las restriccionees de las marcas se suma SIEMPRE restricted_brand_ids = self.restricted_brand_ids.ids + self.area_id.restricted_brand_ids.ids if allowed_brand_ids and restricted_brand_ids: [ allowed_brand_ids.remove(i) for i in restricted_brand_ids if i in allowed_brand_ids ] if allowed_brand_ids: args = expression.AND([ args, [ '|', ('product_brand_id', '=', False), ('product_brand_id', 'in', allowed_brand_ids) ] ]) elif restricted_brand_ids: args = expression.AND([ args, [ '|', ('product_brand_id', '=', False), ('product_brand_id', 'not in', restricted_brand_ids) ] ]) args = expression.normalize_domain(args) if self.allowed_categories_ids or self.restricted_categories_ids: a_categ = [] r_categ = [] for categ in self.allowed_categories_ids: a_categ += categ.search([('id', 'child_of', categ.id)]).ids for categ in self.restricted_categories_ids: r_categ += categ.search([('id', 'child_of', categ.id)]).ids if a_categ and r_categ: [a_categ.remove(i) for i in r_categ if i in a_categ] if a_categ: args = expression.AND([ args, [ '|', ('categ_id', '=', False), ('categ_id', 'in', a_categ) ] ]) elif r_categ: args = expression.AND( [args, [('categ_id', 'not in', r_categ)]]) args = expression.normalize_domain(args) #print (args) return args
def _paginate_search(self, default_page=1, default_per_page=5, order=None, **params): """ Build a domain and search on it. As we use expression (from Odoo), manuals domains get from "scope" and "domain" keys are normalized to avoid issues. :param default_page: int :param default_per_page: int :param params: dict :return: dict """ domain = self._get_base_search_domain() if params.get("scope"): scope_domain = self._scope_to_domain(params.pop("scope")) scope_domain = expression.normalize_domain(scope_domain) domain = expression.AND([domain, scope_domain]) if params.get("domain"): custom_domain = expression.normalize_domain(params.pop("domain")) domain = expression.AND([domain, custom_domain]) total_count = self._exposed_model.search_count(domain) page = params.pop("page", default_page) per_page = params.pop("per_page", default_per_page) records = self._exposed_model.search( domain, limit=per_page, offset=per_page * (page - 1), order=self._get_search_order(order, **params), ) return {"size": total_count, "data": self._to_json(records, **params)}
def force_storage_to_db_for_special_fields(self, new_cr=False): """Migrate special attachments from Object Storage back to database The access to a file stored on the objects storage is slower than a local disk or database access. For attachments like image_small that are accessed in batch for kanban views, this is too slow. We store this type of attachment in the database. This method can be used when migrating a filestore where all the files, including the special files (assets, image_small, ...) have been pushed to the Object Storage and we want to write them back in the database. It is not called anywhere, but can be called by RPC or scripts. """ storage = self._storage() if storage not in self._get_stores(): return domain = AND(( normalize_domain([ ("store_fname", "=like", "{}://%".format(storage)), # for res_field, see comment in # _force_storage_to_object_storage "|", ("res_field", "=", False), ("res_field", "!=", False), ]), normalize_domain( self._store_in_db_instead_of_object_storage_domain()))) with self.do_in_new_env(new_cr=new_cr) as new_env: model_env = new_env["ir.attachment"].with_context( prefetch_fields=False) attachment_ids = model_env.search(domain).ids if not attachment_ids: return total = len(attachment_ids) start_time = time.time() _logger.info( "Moving %d attachments from %s to" " DB for fast access", total, storage) current = 0 for attachment_id in attachment_ids: current += 1 # if we browse attachments outside of the loop, the first # access to 'datas' will compute all the 'datas' fields at # once, which means reading hundreds or thousands of files at # once, exhausting memory attachment = model_env.browse(attachment_id) # this write will read the datas from the Object Storage and # write them back in the DB (the logic for location to write is # in the 'datas' inverse computed field) attachment.write({"datas": attachment.datas}) # as the file will potentially be dropped on the bucket, # we should commit the changes here new_env.cr.commit() if current % 100 == 0 or total - current == 0: _logger.info("attachment %s/%s after %.2fs", current, total, time.time() - start_time)
def get_reinvoice_rule(self, line, supplier): associate_id = line.invoice_id.associate_shipping_id or line.invoice_id.associate_id product_id = line.product_id domain = expression.normalize_domain([ ('supplier_id', '=', supplier and supplier.id or False), ('affiliate', '=', associate_id.affiliate), '|', ('supplier_discount', '=', line.discount), ('order_type', '!=', '0_apply_discount') ]) #COMO USAN ARTICULOS GENERICOS NO TIENEN MARCA #if product_id.product_brand_id: # domain = expression.normalize_domain(domain) # domain = expression.AND([domain, ['|', ('brand_id', '=', product_id.product_brand_id.id), ('brand_id', '=', False)]]) domain_data = [('supplier_id', '=', supplier.id), '|', ('supplier_code', '=', associate_id.supplier_code), ('supplier_str', '=', associate_id.supplier_str)] supplier_data = self.env['res.partner'].search( domain_data, limit=1, order='external asc, supplier_str desc') if supplier_data: if supplier_data.supplier_customer_ranking_id: domain = expression.normalize_domain(domain) domain = expression.AND([ domain, [('supplier_customer_ranking_id', '=', supplier_data.supplier_customer_ranking_id.id)] ]) domain = expression.normalize_domain(domain) domain = expression.AND([ domain, [ '|', ('partner_id', '=', associate_id.id), ('partner_id', '=', False) ] ]) rule = self.search( domain, order= 'partner_id asc, supplier_discount desc, customer_discount desc, order_type asc', limit=1) print("Regla: {}".format(rule.display_name)) if not rule: message = ( '{}\nNo se ha encontrado una regla de refactura para: Descuento: {}, Proveedor: {}, {} Asociado: {}' .format(line.invoice_id.name, line.discount, supplier.display_name, 'no ' if not associate_id.affiliate else '', associate_id and associate_id.display_name or '')) if product_id.product_brand_id: message = '{}, Marca: {}'.format( message, product_id.product_brand_id.name) if supplier_data and supplier_data.supplier_customer_ranking_id: message = '{}, Clasificación: {}'.format( message, supplier_data.supplier_customer_ranking_id.name) line.invoice_id.supplier_invoice_id.message_post(body=message) return rule and rule[0] or []
def _compute_domain(self): '''combine our domain with all domains to union/complement, this works recursively''' for this in self: if this.model_id not in self.env: this.domain = '[]' _logger.error( "Unknown model %s used in filter %d", this.model_id, this.id, ) continue domain = self._eval_domain(this.domain_this) for u in this.union_filter_ids: if u.model_id != this.model_id: _logger.warning( "Model mismatch in helper %d on filter %d!", u.model_id, this.model_id, ) continue if u.evaluate_before_join: matching_ids = ( self.env[this.model_id] .search(self._eval_domain(u.domain)) .ids ) domain = expression.OR([ domain, [('id', 'in', matching_ids)], ]) else: domain = expression.OR( [domain, self._eval_domain(u.domain)] ) for c in this.complement_filter_ids: if c.model_id != this.model_id: _logger.warning( "Model mismatch in helper %d on filter %d!", c.model_id, this.model_id, ) continue if c.evaluate_before_negate: matching_ids = ( self.env[this.model_id] .search(self._eval_domain(c.domain)) .ids ) domain = expression.AND([ domain, [('id', 'not in', matching_ids)], ]) else: domain = expression.AND([ domain, ["!"] + self._eval_domain(c["domain"]) ]) this.domain = repr(expression.normalize_domain(domain))
def _eval_domain(self, domain): """Parse a domain and normalize it, with a default if it's invalid.""" try: domain = safe_eval(domain) or [expression.FALSE_LEAF] except (SyntaxError, TypeError, ValueError, NameError): domain = [expression.FALSE_LEAF] return expression.normalize_domain(domain)
def _get_search_domain(self, search, category, attrib_values): domain = super(WebsiteSaleExtended, self)._get_search_domain(search, category, attrib_values) domain = expression.normalize_domain(domain) if search: domain_search = [] for srch in search.split(" "): domain_search += [ '|', '|', '|', ('public_categ_ids', 'ilike', srch), ('product_variant_ids', 'ilike', srch), ('public_categ_ids.public_categ_tag_ids', 'ilike', srch), ('product_variant_ids.attribute_value_ids', 'ilike', srch) ] domain = expression.OR([domain, domain_search]) if category: categories = request.env['product.public.category'] # Search sub-categories of first and second depth level sub_cat_l1 = categories.sudo().search( [('parent_id', '=', int(category))], order='sequence') sub_cat_l2 = categories.sudo().search( [('parent_id', 'in', sub_cat_l1.ids)], order='sequence') # Create new list of categories to show list_cat = [int(category)] list_cat.extend(sub_cat_l1.ids) list_cat.extend(sub_cat_l2.ids) # Search products from sub-categories of first and second depth level domain += [('public_categ_ids', 'in', list_cat)] return domain
def _get_base_search_domain(self): """ This method must provide a domain used to retrieve the requested invoice. This domain MUST TAKE CARE of restricting the access to the invoices visible for the current customer :return: Odoo domain """ # The partner must be set and not be the anonymous one if not self._is_logged_in(): return expression.FALSE_DOMAIN # here we only allow access to invoices linked to a sale order of the # current customer so_domain = [ ("partner_id", "=", self.partner.id), ("shopinvader_backend_id", "=", self.shopinvader_backend.id), ("typology", "=", "sale"), ] # invoice_ids on sale.order is a computed field... # to avoid to duplicate the logic, we search for the sale orders # and check if the invoice_id is into the list of sale.invoice_ids sales = self.env["sale.order"].search(so_domain) invoice_ids = sales.mapped("invoice_ids").ids states = self._get_allowed_invoice_states() return expression.normalize_domain([("id", "in", invoice_ids), ("state", "in", states)])
def search(self, args, offset=0, limit=None, order=None, count=False): new_args = expression.normalize_domain(args.copy()) ctx = self._context.copy() if self._context.get('delivery_route_group_id', False): group_ids = self.env['delivery.route.path.group'].search([ ('name', 'ilike', self._context['delivery_route_group_id']) ]) if group_ids: route_ids = [('delivery_route_path_id', 'in', group_ids.mapped('route_path_ids').ids)] new_args = expression.AND([route_ids, new_args]) if self._context.get('ghost_qty_done', False): ctx.update(ghost_qty_done=False) moves = self.env['stock.move'].with_context(ctx).search_read( new_args, ['id']) if moves: line_ids = [('id', 'in', [x['id'] for x in moves]), ('qty_done', '>', 0)] if line_ids: moves_qty = self.env['stock.move.line'].search_read( line_ids, ['move_id']) if moves_qty: new_args = expression.AND([ ('id', 'in', [x['move_id'][0] for x in moves_qty]), new_args ]) return super(StockMove, self.with_context(ctx)).search(new_args, offset=offset, limit=limit, order=order, count=count)
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 search(self, args, offset=0, limit=None, order=None, count=False): if self._context.get('para_hoy', False): today = fields.Date.today() hoy = ('date_expected', '>=', today) ayer = ('date_expected', '<', today) d_1 = expression.AND([[hoy], [ '&', ('picking_id', '!=', False), ('state', 'not in', ('draft', 'cancel')) ]]) d_2 = [ '&', ayer, ('state', 'in', ('assigned', 'confirmed', 'partially_available')) ] domain = expression.OR([d_1, d_2]) moves = self.env['stock.move'].read_group(domain, ['picking_id'], ['picking_id']) picking_ids = [ x['picking_id'][0] for x in moves if x['picking_id'] ] args_para_hoy = [('id', 'in', picking_ids)] args = expression.normalize_domain(args) args = expression.AND([args_para_hoy, args]) return super().search(args, offset=offset, limit=limit, order=order, count=count)
def _force_domain(self): eval_context = self._eval_context() for rule in self: if rule.domain_force: rule.domain = expression.normalize_domain(eval(rule.domain_force, eval_context)) else: rule.domain = []
def _compute_domain(self, model_name, mode="read"): if mode not in self._MODES: raise ValueError('Invalid mode: %r' % (mode,)) if self._uid == SUPERUSER_ID: return None query = """ SELECT r.id FROM ir_rule r JOIN ir_model m ON (r.model_id=m.id) WHERE m.model=%s AND r.active AND r.perm_{mode} AND (r.id IN (SELECT rule_group_id FROM rule_group_rel rg JOIN res_groups_users_rel gu ON (rg.group_id=gu.gid) WHERE gu.uid=%s) OR r.global) """.format(mode=mode) self._cr.execute(query, (model_name, self._uid)) rule_ids = [row[0] for row in self._cr.fetchall()] if not rule_ids: return [] # browse user and rules as SUPERUSER_ID to avoid access errors! eval_context = self._eval_context() user_groups = self.env.user.groups_id global_domains = [] # list of domains group_domains = [] # list of domains for rule in self.browse(rule_ids).sudo(): # evaluate the domain for the current user dom = safe_eval(rule.domain_force, eval_context) if rule.domain_force else [] dom = expression.normalize_domain(dom) if not rule.groups: global_domains.append(dom) elif rule.groups & user_groups: group_domains.append(dom) # combine global domains and group domains return expression.AND(global_domains + [expression.OR(group_domains)])
def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None): """Include education code in direct name or description search.""" args = expression.normalize_domain(args) for arg in args: if isinstance(arg, (list, tuple)): if (arg[0] == 'name' or arg[0] == 'display_name' or arg[0] == self._rec_name): index = args.index(arg) args = (args[:index] + ['|', ('education_code', arg[1], arg[2])] + args[index:]) break return super(EducationData, self)._search(args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid)
def validate_server_action(self): """ Context must have active_id :return: """ model_name = self.model_id.model eval_context = self._eval_context() active_id = self._context.get('active_id', False) if active_id and model_name: domain = self.filter_id.domain rule = expression.normalize_domain(safe_eval(domain, eval_context)) Query = self.env[model_name].sudo()._where_calc(rule, active_test=False) from_clause, where_clause, where_clause_params = Query.get_sql() where_str = where_clause and (" WHERE %s" % where_clause) or '' query_str = 'SELECT id FROM ' + from_clause + where_str self._cr.execute(query_str, where_clause_params) result = self._cr.fetchall() if active_id in [id[0] for id in result]: return True else: _logger.error( "Server Action was called without 'active_id' not executed") return False
def _force_domain(self): eval_context = self._eval_context() for rule in self: if rule.domain_force: rule.domain = expression.normalize_domain(safe_eval(rule.domain_force, eval_context)) else: rule.domain = []
def extend(domain): for index, item in enumerate(domain): if isinstance(item, list): field = get_field(item) if field.search and not field.related: extension = field.search(get_records(item), *item[1:]) domain = domain[:index] + normalize_domain(extension) + domain[index + 1:] return domain
def get_locations_domain(self): lcoation_domain = [ '|', '|', '|', ('location_dest_id.deposit', '=', True), ('location_dest_id.deposit', '=', True), ('location_id.scrap_location', '=', True), ('location_dest_id.scrap_location', '=', True) ] in_domain = expression.normalize_domain([ ('location_id.usage', '!=', 'internal'), ('location_dest_id.usage', '=', 'internal') ]) out_domain = expression.normalize_domain([ ('location_id.usage', '=', 'internal'), ('location_dest_id.usage', '!=', 'internal') ]) domain = expression.OR([lcoation_domain, in_domain, out_domain]) return expression.normalize_domain(domain)
def _get_move_line_domain(self, codes, date_start, date_end, map_line): """Add the possibility of getting move lines from moves generated from cash basis reconciliations so that the amounts appear on the payment date. This is needed as the cash basis move is not of the expected move type. Also adjust domains for the special case of 12% VAT for farming. """ domain = super(L10nEsAeatMod303Report, self)._get_move_line_domain( codes, date_start, date_end, map_line, ) for i, element in enumerate(domain): if element[0] == 'move_id.move_type': domain[i:i] = [ '|', ('move_id.tax_cash_basis_rec_id', '!=', False), ] break if map_line.field_number == 42: # Exclude here the VAT that is used as base for IRPF 2%, as it # has the tax_exigible field marked. domain += [ ('tax_ids', '=', False), ] elif map_line.field_number == 75: # And add it here domain_mandatory = [] domain_optional = [] domain_extra = [] for i, element in enumerate(domain): if element[0] == 'date' and element[1] == '<=': domain_mandatory = normalize_domain(domain[:i + 1]) domain_optional = normalize_domain(domain[i + 1:]) domain_extra = [ '&', ('tax_ids', '!=', False), ('tax_line_id.description', '=', 'P_IVA12_AGR'), ] break domain = AND([domain_mandatory] + [OR([domain_extra, domain_optional])]) return domain
def _get_search_domain(self, search, category, attrib_values): """ Modifica el domain original para mostrar los productos en funcion de los nuevos subdominios. domain_swp: controla que no se muestren los productos sin stock en conjunto con el cron act_stock_published de product.py. El resto de domains solo busca dentro de esos ids. attr_domain: para buscar productos dentro del contexto por filtros de atributos. search: pasa del contexto y realiza la busqueda por los terminos introducidos en el search box. """ # Set fuzzy search for more results request.env.cr.execute("SELECT set_limit(0.2);") domain_origin = super(WebsiteSaleExtended, self)._get_search_domain(search, category, attrib_values) # Search and filters work together if search and search != 0: for srch in shlex.split(search): if len(srch) > 2: domain_search = ['|', '|', '|', '|', '|', ('name', '%', srch), ('ref_template', 'ilike', srch), ('attribute_line_ids', 'ilike', srch), ('product_variant_ids.attribute_value_ids.range_search', 'ilike', srch), ('public_categ_ids.complete_name', 'ilike', srch), ('public_categ_ids.public_categ_tag_ids', 'ilike', srch)] domain_origin = expression.normalize_domain(domain_origin) domain_origin = expression.OR([domain_origin, domain_search]) # Only can put on context products with stock > 0 or with stock = 0 but published # search and filters and all domain have to respect this. So that we need add this like an AND website = request.website domain_swp = [('website_id', '=', website.id), ('stock_website_published', '=', True)] product_ids = request.env['template.stock.web'].sudo().search(domain_swp).mapped('product_id').ids domain_origin += [('id', 'in', product_ids)] # Hide all not published products in website for all employees that they do not web editors user = request.env.user is_editor_web = user.has_group('website.group_website_publisherl') \ or user.has_group('website.group_website_designer') if not is_editor_web: domain_editor = [('website_published', '=', True)] domain_origin = expression.normalize_domain(domain_origin) domain_origin = expression.AND([domain_origin, domain_editor]) return domain_origin
def _prepare_move_line_domain(self): """ Este método ya devuelve el domain permitiendo negativos, sin la condicíon de (debit/credit, >, 0). Se permite filtrar los efectos por fecha de inicio también, con lo que se reordena el domain de búsqueda. Pero como la fecha de inicio no debe aplicarse para los efectos de rectificativas, hay que desdoblar el domain en 2, uno con los efectos positivos sin fecha, o con fecha en rango, y otro con los negativos sin fecha o hasta la fecha dada. """ domain = super(AccountPaymentLineCreate, self).\ _prepare_move_line_domain() domain2 = domain.copy() # Copia domain para buscar los negativos if ('date_maturity', '=', False) in domain and self.start_due_date: # Modifico el dominio para que los encuentre efectos sin fecha # o cuyo vencimiento esté en el rango. Lo reordeno para que # sea sin fecha o con fecha en rango indx = domain.index(('date_maturity', '=', False)) t1 = domain.pop(indx) # date_maturyty = False t2 = domain.pop(indx - 1) # date_maturyty <= X t3 = ('date_maturity', '>=', self.start_due_date) domain.insert(indx - 1, t1) domain.insert(indx, t2) domain.insert(indx + 1, t3) if self.allow_negative: # Vuelvo a añadir la condición de solo efectos positivos, para # el domain 1, y la de solo negativos para el domain 2 if self.order_id.payment_type == 'outbound': domain.append(('credit', '>', 0)) domain2.append(('credit', '<=', 0)) elif self.order_id.payment_type == 'inbound': domain.append(('debit', '>', 0)) domain2.append(('debit', '<=', 0)) # Obtengo los domains normalizados para poder aplicar el OR d1 = expression.normalize_domain(domain) d2 = expression.normalize_domain(domain2) domain = expression.OR([d1, d2]) return domain
def _get(self, _id): domain = expression.normalize_domain(self._get_base_search_domain()) domain = expression.AND([domain, [("id", "=", _id)]]) record = self._exposed_model.search(domain) if not record: raise MissingError( _("The record %s %s does not exist") % (self._expose_model, _id)) else: return record
def _launch_sale_price_update(self, domain=False): """ Retrieve cart to update then apply the recalculation (could be used for a cron) :param domain: list/domain :return: bool """ domain = domain or [] if domain: domain = expression.normalize_domain(domain) sale_domain = expression.normalize_domain([("typology", "=", "cart"), ("state", "=", "draft")]) domain = expression.AND([domain, sale_domain]) sale_carts = self.env["sale.order"].search(domain) if sale_carts: description = "Recompute prices for carts (split: 1 job per cart)" return self.with_delay(description=description )._job_split_sale_price_update(sale_carts) return True
def _get_base_search_domain(self): """ This method must provide a domain used to retrieve the requested membership products. :return: Odoo domain """ # here we only allow access to membership products return expression.normalize_domain([("membership", "=", True)])
def associated_view(self): action_data = super(IrActionsReport, self).associated_view() domain = expression.normalize_domain(action_data['domain']) view_name = self.report_name.split('.')[1].split('_copy_')[0] domain = expression.OR([ domain, ['&', ('name', 'ilike', view_name), ('type', '=', 'qweb')] ]) action_data['domain'] = domain return action_data
def get_reinvoice_rule_for_txt(self, txt): shipping_id = txt.partner_shipping_id supplier_id = txt.partner_id domain = [('affiliate', '=', shipping_id.affiliate), ('supplier_id', '=', supplier_id.id)] domain_data = [('supplier_id', '=', supplier_id.id), '|', ('supplier_code', '=', shipping_id.supplier_code), ('supplier_str', '=', shipping_id.supplier_str)] supplier_data = self.env['res.partner'].search(domain_data, limit=1) if supplier_data: if supplier_data.supplier_customer_ranking_id: domain = expression.normalize_domain(domain) domain = expression.AND([ domain, [('supplier_customer_ranking_id', '=', supplier_data.supplier_customer_ranking_id.id)] ]) domain = expression.normalize_domain(domain) domain = expression.AND([ domain, [ '|', ('partner_id', '=', shipping_id.id), ('partner_id', '=', False) ] ]) else: domain = expression.normalize_domain(domain) domain = expression.AND([domain, [('partner_id', '=', False)]]) rule_ids = self.search( domain, order= 'partner_id asc, brand_id asc, supplier_discount desc, customer_discount desc, order_type asc' ) discount_ids = txt.invoice_line_txt_import_ids.mapped('descuento') rule_ids = rule_ids.filtered( lambda x: x.supplier_discount in discount_ids) print("{} {}".format(domain, rule_ids)) return rule_ids
def _compute_domain(self, model_name, mode="read"): if mode not in self._MODES: raise ValueError("Invalid mode: {!r}".format(mode)) if self._uid == SUPERUSER_ID: return None query = """ SELECT r.id FROM ir_rule r JOIN ir_model m ON (r.model_id=m.id) WHERE m.model=%s AND r.active AND r.perm_{mode} AND (r.id IN (SELECT rule_group_id FROM rule_group_rel rg JOIN res_groups_users_rel gu ON (rg.group_id=gu.gid) WHERE gu.uid=%s) OR r.global) """.format( mode=mode ) self._cr.execute(query, (model_name, self._uid)) rule_ids = [row[0] for row in self._cr.fetchall()] if not rule_ids: return [] # browse user and rules as SUPERUSER_ID to avoid access errors! eval_context = self._eval_context() user_groups = self.env.user.groups_id global_domains = [] # list of domains group_domains = [] # list of domains for rule in self.browse(rule_ids).sudo(): # BEGIN redefined part of original _compute_domain of odoo/base/addons/ir/ir_rule. # have to redefine all method to take in account new ir.rule ``backend_behaviour`` setting dom = [] if not eval_context.get("website_id") and rule.backend_behaviour: dom = ( [(1, "=", 1)] if rule.backend_behaviour == "true" else [(0, "=", 1)] ) else: # evaluate the domain for the current user dom = ( safe_eval(rule.domain_force, eval_context) if rule.domain_force else [] ) dom = expression.normalize_domain(dom) # END redefined part of original _compute_domain if not rule.groups: global_domains.append(dom) elif rule.groups & user_groups: group_domains.append(dom) # combine global domains and group domains if not group_domains: return expression.AND(global_domains) return expression.AND(global_domains + [expression.OR(group_domains)])
def _get_base_search_domain(self): portal_mode = self.shopinvader_backend.sale_order_portal_mode if not portal_mode: return super()._get_base_search_domain() domain = self._default_domain_for_partner_records(with_backend=False) state_domain = [("state", "in", self._portal_mode_sale_states())] backend_domain = [ "|", ("shopinvader_backend_id", "=", self.shopinvader_backend.id), ("shopinvader_backend_id", "=", False), ] domain = expression.AND([domain, state_domain, backend_domain]) return expression.normalize_domain(domain)
def get_team_id(self): team_id = super(ProjectTaskActionLine, self).get_team_id() if self.action_id and self.task_id: if self.action_id.team_type == 'd': for line in self.action_id.distribution_id.team_distribution_line_ids: rule = expression.normalize_domain(safe_eval(line.domain)) tasks = self.env['project.task'].search(rule) if self.task_id.id in tasks.ids: team_id = line.team_id.id or False break else: team_id = False return team_id
def _search_abandoned_cart(self, operator, value): abandoned_delay = self.website_id and self.website_id.cart_abandoned_delay or 1.0 abandoned_datetime = fields.Datetime.to_string(datetime.utcnow() - relativedelta(hours=abandoned_delay)) abandoned_domain = expression.normalize_domain([ ('date_order', '<=', abandoned_datetime), ('team_id.team_type', '=', 'website'), ('state', '=', 'draft'), ('partner_id', '!=', self.env.ref('base.public_partner').id), ('order_line', '!=', False) ]) # is_abandoned domain possibilities if (operator not in expression.NEGATIVE_TERM_OPERATORS and value) or (operator in expression.NEGATIVE_TERM_OPERATORS and not value): return abandoned_domain return expression.distribute_not(['!'] + abandoned_domain) # negative domain
def _search_abandoned_cart(self, operator, value): abandoned_delay = self.website_id and self.website_id.cart_abandoned_delay or 1.0 abandoned_datetime = fields.Datetime.to_string(datetime.utcnow() - relativedelta(hours=abandoned_delay)) abandoned_domain = expression.normalize_domain([ ('date_order', '<=', abandoned_datetime), ('team_id.team_type', '=', 'website'), ('state', '=', 'draft'), ('partner_id.id', '!=', self.env.ref('base.public_partner').id), ('order_line', '!=', False) ]) # is_abandoned domain possibilities if (operator not in expression.NEGATIVE_TERM_OPERATORS and value) or (operator in expression.NEGATIVE_TERM_OPERATORS and not value): return abandoned_domain return expression.distribute_not(abandoned_domain) # negative domain
def action_unlink_empty_cards(self, force_purge=True): if force_purge: abandoned_domain = expression.normalize_domain([ ('team_id.team_type', '=', 'website'), ('state', '=', 'draft'), ('partner_id', '!=', self.env.ref('base.public_partner').id), ('order_line', '=', False) ]) records = self.search(abandoned_domain) else: records = self.filtered(lambda r: r.is_empty_cart) _logger.info("PURGE %s" % records) for record in records: record.unlink() return self
def _compute_domain(self, model_name, mode="read"): if mode not in self._MODES: raise ValueError('Invalid mode: %r' % (mode,)) if self._uid == SUPERUSER_ID: return None query = """ SELECT r.id FROM ir_rule r JOIN ir_model m ON (r.model_id=m.id) WHERE m.model=%s AND r.active AND r.perm_{mode} AND (r.id IN (SELECT rule_group_id FROM rule_group_rel rg JOIN res_groups_users_rel gu ON (rg.group_id=gu.gid) WHERE gu.uid=%s) OR r.global) """.format(mode=mode) self._cr.execute(query, (model_name, self._uid)) rule_ids = [row[0] for row in self._cr.fetchall()] if not rule_ids: return [] # read 'domain' as self._uid to have the correct eval context for the rules. rules = self.browse(rule_ids) rule_domain = {vals['id']: vals['domain'] for vals in rules.read(['domain'])} # browse user and rules as SUPERUSER_ID to avoid access errors! user = self.env.user global_domains = [] # list of domains group_domains = defaultdict(list) # {group: list of domains} for rule in rules.sudo(): dom = expression.normalize_domain(rule_domain[rule.id]) for group in rule.groups: if group in user.groups_id: group_domains[group].append(dom) if not rule.groups: global_domains.append(dom) # combine global domains and group domains if group_domains: group_domain = expression.OR(map(expression.OR, group_domains.values())) else: group_domain = [] domain = expression.AND(global_domains + [group_domain]) return domain
def _compute_domain(self, model_name, mode="read"): rules = self._get_rules(model_name, mode=mode) if not rules: return # browse user and rules as SUPERUSER_ID to avoid access errors! eval_context = self._eval_context() user_groups = self.env.user.groups_id global_domains = [] # list of domains group_domains = [] # list of domains for rule in rules.sudo(): # evaluate the domain for the current user dom = safe_eval(rule.domain_force, eval_context) if rule.domain_force else [] dom = expression.normalize_domain(dom) if not rule.groups: global_domains.append(dom) elif rule.groups & user_groups: group_domains.append(dom) # combine global domains and group domains return expression.AND(global_domains + [expression.OR(group_domains)])
def _process_fvg(self, model, fvg): """ Post-processes to augment the fields_view_get with: * an id field (may not be present if not in the view but needed) * pre-processed modifiers (map of modifier name to json-loaded domain) * pre-processed onchanges list """ fvg['fields']['id'] = {'type': 'id'} # pre-resolve modifiers & bind to arch toplevel modifiers = fvg['modifiers'] = {} contexts = fvg['contexts'] = {} for f in etree.fromstring(fvg['arch']).iter('field'): fname = f.get('name') modifiers[fname] = { modifier: domain if isinstance(domain, bool) else normalize_domain(domain) for modifier, domain in json.loads(f.get('modifiers', '{}')).items() } ctx = f.get('context') if ctx: contexts[fname] = ctx fvg['modifiers']['id'] = {'required': False, 'readonly': True} fvg['onchange'] = model._onchange_spec(fvg)
def is_failing(r, ids=for_records.ids): dom = safe_eval(r.domain_force, eval_context) if r.domain_force else [] return Model.search_count(expression.AND([ [('id', 'in', ids)], expression.normalize_domain(dom) ])) < len(ids)