def _search_full_name(self, operator, operand): lst = True if isinstance(operand, bool): domains = [[('name', operator, operand)], [('category_id.name', operator, operand)]] if operator in expression.NEGATIVE_TERM_OPERATORS == (not operand): return expression.AND(domains) else: return expression.OR(domains) if isinstance(operand, pycompat.string_types): lst = False operand = [operand] where = [] for group in operand: values = [v for v in group.split('/') if v] group_name = values.pop().strip() category_name = values and '/'.join(values).strip() or group_name group_domain = [('name', operator, lst and [group_name] or group_name)] category_domain = [('category_id.name', operator, lst and [category_name] or category_name)] if operator in expression.NEGATIVE_TERM_OPERATORS and not values: category_domain = expression.OR( [category_domain, [('category_id', '=', False)]]) if (operator in expression.NEGATIVE_TERM_OPERATORS) == (not values): sub_where = expression.AND([group_domain, category_domain]) else: sub_where = expression.OR([group_domain, category_domain]) if operator in expression.NEGATIVE_TERM_OPERATORS: where = expression.AND([where, sub_where]) else: where = expression.OR([where, sub_where]) return where
def _domain_move_lines(self, search_str): """ Returns the domain from the search_str search :param search_str: search string """ if not search_str: return [] str_domain = self._str_domain_for_mv_line(search_str) if search_str[0] in ['-', '+']: try: amounts_str = search_str.split('|') for amount_str in amounts_str: amount = amount_str[0] == '-' and float( amount_str) or float(amount_str[1:]) amount_domain = [ '|', ('amount_residual', '=', amount), '|', ('amount_residual_currency', '=', amount), '|', (amount_str[0] == '-' and 'credit' or 'debit', '=', float(amount_str[1:])), ('amount_currency', '=', amount), ] str_domain = expression.OR([str_domain, amount_domain]) except: pass else: try: amount = float(search_str) amount_domain = [ '|', ('amount_residual', '=', amount), '|', ('amount_residual_currency', '=', amount), '|', ('amount_residual', '=', -amount), '|', ('amount_residual_currency', '=', -amount), '&', ('account_id.internal_type', '=', 'liquidity'), '|', '|', '|', ('debit', '=', amount), ('credit', '=', amount), ('amount_currency', '=', amount), ('amount_currency', '=', -amount), ] str_domain = expression.OR([str_domain, amount_domain]) except: pass return str_domain
def _remove_membership(self, partner_ids): """ Unlink (!!!) the relationships between the passed partner_ids and the channels and their slides (done in the unlink of slide.channel.partner model). Remove earned karma when completed quizz """ if not partner_ids: raise ValueError( "Do not use this method with an empty partner_id recordset") earned_karma = self._get_earned_karma(partner_ids) users = self.env['res.users'].sudo().search([ ('partner_id', 'in', list(earned_karma)), ]) for user in users: if earned_karma[user.partner_id.id]: user.add_karma(-1 * earned_karma[user.partner_id.id]) removed_channel_partner_domain = [] for channel in self: removed_channel_partner_domain = expression.OR([ removed_channel_partner_domain, [('partner_id', 'in', partner_ids), ('channel_id', '=', channel.id)] ]) self.message_unsubscribe(partner_ids=partner_ids) if removed_channel_partner_domain: self.env['slide.channel.partner'].sudo().search( removed_channel_partner_domain).unlink()
def get_mention_suggestions(self, search, limit=8, channel_id=None): """ Return 'limit'-first partners' id, name and email such that the name or email matches a 'search' string. Prioritize users, and then extend the research to all partners. If channel_id is given, only members of this channel are returned. """ search_dom = expression.OR([[('name', 'ilike', search)], [('email', 'ilike', search)]]) search_dom = expression.AND([[('active', '=', True), ('type', '!=', 'private')], search_dom]) if channel_id: search_dom = expression.AND([[('channel_ids', 'in', channel_id)], search_dom]) # Search users domain = expression.AND([[('user_ids.id', '!=', False), ('user_ids.active', '=', True)], search_dom]) users = self.search(domain, limit=limit) # Search partners if less than 'limit' users found partners = self.env['res.partner'] if len(users) < limit: partners = self.search(expression.AND([[('id', 'not in', users.ids) ], search_dom]), limit=limit) return [ [partner.mail_partner_format() for partner in users], [partner.mail_partner_format() for partner in partners], ]
def _domain_move_lines_for_manual_reconciliation(self, account_id, partner_id=False, excluded_ids=None, search_str=False): """ Create domain criteria that are relevant to manual reconciliation. """ domain = [ '&', '&', ('reconciled', '=', False), ('account_id', '=', account_id), '|', ('move_id.state', '=', 'posted'), '&', ('move_id.state', '=', 'draft'), ('move_id.journal_id.post_at', '=', 'bank_rec'), ] domain = expression.AND([domain, [('balance', '!=', 0.0)]]) if partner_id: domain = expression.AND( [domain, [('partner_id', '=', partner_id)]]) if excluded_ids: domain = expression.AND([[('id', 'not in', excluded_ids)], domain]) if search_str: str_domain = self._domain_move_lines(search_str=search_str) str_domain = expression.OR( [str_domain, [('partner_id.name', 'ilike', search_str)]]) domain = expression.AND([domain, str_domain]) # filter on account.move.line having the same company as the given account account = self.env['account.account'].browse(account_id) domain = expression.AND( [domain, [('company_id', '=', account.company_id.id)]]) return domain
def _get_failing(self, for_records, mode='read'): """ Returns the rules for the mode for the current user which fail on the specified records. Can return any global rule and/or all local rules (since local rules are OR-ed together, the entire group succeeds or fails, while global rules get AND-ed and can each fail) """ Model = for_records.browse(()).sudo() eval_context = self._eval_context() all_rules = self._get_rules(Model._name, mode=mode).sudo() # first check if the group rules fail for any record (aka if # searching on (records, group_rules) filters out some of the records) group_rules = all_rules.filtered(lambda r: r.groups and r.groups & self.env.user.groups_id) group_domains = expression.OR([ safe_eval(r.domain_force, eval_context) if r.domain_force else [] for r in group_rules ]) # if all records get returned, the group rules are not failing if Model.search_count(expression.AND([[('id', 'in', for_records.ids)], group_domains])) == len(for_records): group_rules = self.browse(()) # failing rules are previously selected group rules or any failing global rule 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) return all_rules.filtered(lambda r: r in group_rules or (not r.groups and is_failing(r))).with_user(self.env.user)
def _get_search_domain(self, search_in, search): search_domain = super()._get_search_domain(search_in, search) if search_in in ('sol', 'all'): search_domain = expression.OR( [search_domain, [('so_line', 'ilike', search)]]) if search_in in ('sol_id', 'invoice_id'): search = int(search) if search.isdigit() else 0 if search_in == 'sol_id': search_domain = expression.OR( [search_domain, [('so_line.id', '=', search)]]) if search_in == 'invoice_id': invoice = request.env['account.move'].browse(search) domain = request.env[ 'account.analytic.line']._timesheet_get_sale_domain( invoice.mapped('invoice_line_ids.sale_line_ids'), invoice) search_domain = expression.OR([search_domain, domain]) return search_domain
def _any_is_configured(self, company_id): domain = expression.OR([[ ('property_tax_payable_account_id', '!=', False) ], [('property_tax_receivable_account_id', '!=', False)], [('property_advance_tax_payment_account_id', '!=', False)]]) group_with_config = self.with_company(company_id).search_count(domain) return group_with_config > 0
def _search_ids(model, values): ids = set() domain = [] for item in values: if isinstance(item, int): ids.add(item) else: domain = expression.OR([[('name', 'ilike', item)], domain]) if domain: ids |= set(self.env[model].search(domain).ids) return ids
def get_mention_suggestions(self, search, limit=8): """ Return 'limit'-first channels' id, name and public fields such that the name matches a 'search' string. Exclude channels of type chat (DM), and private channels the current user isn't registered to. """ domain = expression.AND([[('name', 'ilike', search)], [('channel_type', '=', 'channel')], expression.OR( [[('public', '!=', 'private')], [('channel_partner_ids', 'in', [self.env.user.partner_id.id])]])]) return self.search_read(domain, ['id', 'name', 'public'], limit=limit)
def _retrieve_partner(self, name=None, phone=None, mail=None, vat=None): '''Search all partners and find one that matches one of the parameters. :param name: The name of the partner. :param phone: The phone or mobile of the partner. :param mail: The mail of the partner. :param vat: The vat number of the partner. :returns: A partner or an empty recordset if not found. ''' domains = [] for value, domain in ( (name, [('name', 'ilike', name)]), (phone, expression.OR([[('phone', '=', phone)], [('mobile', '=', phone)]])), (mail, [('email', '=', mail)]), (vat, [('vat', 'like', vat)]), ): if value is not None: domains.append(domain) domain = expression.OR(domains) return self.env['res.partner'].search(domain, limit=1)
def _remove_copied_views(self): """ Remove the copies of the views installed by the modules in `self`. Those copies do not have an external id so they will not be cleaned by `_module_data_uninstall`. This is why we rely on `key` instead. It is important to remove these copies because using them will crash if they rely on data that don't exist anymore if the module is removed. """ domain = expression.OR([[('key', '=like', m.name + '.%')] for m in self]) orphans = self.env['ir.ui.view'].with_context(**{'active_test': False, MODULE_UNINSTALL_FLAG: True}).search(domain) orphans.unlink()
def _count_attachments(self): domains = [[('res_model', '=', 'account.move'), ('res_id', '=', self.id)]] statement_ids = self.line_ids.mapped('statement_id') payment_ids = self.line_ids.mapped('payment_id') if statement_ids: domains.append([('res_model', '=', 'account.bank.statement'), ('res_id', 'in', statement_ids)]) if payment_ids: domains.append([('res_model', '=', 'account.payment'), ('res_id', 'in', payment_ids)]) return self.env['ir.attachment'].search_count(expression.OR(domains))
def search_with_phone_mail(extra_domain): domains = [] if phone: domains.append([('phone', '=', phone)]) domains.append([('mobile', '=', phone)]) if mail: domains.append([('email', '=', mail)]) if not domains: return None domain = expression.OR(domains) if extra_domain: domain = expression.AND([domain, extra_domain]) return self.env['res.partner'].search(domain, limit=1)
def _search_available_today(self, operator, value): if (not operator in ['=', '!=']) or (not value in [True, False]): return [] searching_for_true = (operator == '=' and value) or (operator == '!=' and not value) today = fields.Date.context_today(self) fieldname = 'recurrency_%s' % (WEEKDAY_TO_NAME[today.weekday()]) return expression.AND([[(fieldname, operator, value)], expression.OR([ [('until', '=', False)], [('until', '>' if searching_for_true else '<', today) ], ])])
def unlink(self): """ Override unlink method : Remove attendee from a channel, then also remove slide.slide.partner related to. """ removed_slide_partner_domain = [] for channel_partner in self: # find all slide link to the channel and the partner removed_slide_partner_domain = expression.OR([ removed_slide_partner_domain, [('partner_id', '=', channel_partner.partner_id.id), ('slide_id', 'in', channel_partner.channel_id.slide_ids.ids)] ]) if removed_slide_partner_domain: self.env['slide.slide.partner'].search( removed_slide_partner_domain).unlink() return super(ChannelUsersRelation, self).unlink()
def _search_is_available_at(self, operator, value): supported_operators = ['in', 'not in', '=', '!='] if not operator in supported_operators: return expression.TRUE_DOMAIN if isinstance(value, int): value = [value] if operator in expression.NEGATIVE_TERM_OPERATORS: return expression.AND([[ ('supplier_id.available_location_ids', 'not in', value) ], [('supplier_id.available_location_ids', '!=', False)]]) return expression.OR([[ ('supplier_id.available_location_ids', 'in', value) ], [('supplier_id.available_location_ids', '=', False)]])
def _search_available_today(self, operator, value): if (not operator in ['=', '!=']) or (not value in [True, False]): return [] searching_for_true = (operator == '=' and value) or (operator == '!=' and not value) now = fields.Datetime.now().replace(tzinfo=pytz.UTC).astimezone( pytz.timezone(self.env.user.tz or 'UTC')) fieldname = 'recurrency_%s' % (WEEKDAY_TO_NAME[now.weekday()]) recurrency_domain = expression.OR([[ ('recurrency_end_date', '=', False) ], [('recurrency_end_date', '>' if searching_for_true else '<', now)]]) return expression.AND( [recurrency_domain, [(fieldname, operator, value)]])
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): if not args: args = [] if name: positive_operators = ['=', 'ilike', '=ilike', 'like', '=like'] product_ids = [] if operator in positive_operators: product_ids = list(self._search([('default_code', '=', name)] + args, limit=limit, access_rights_uid=name_get_uid)) if not product_ids: product_ids = list(self._search([('barcode', '=', name)] + args, limit=limit, access_rights_uid=name_get_uid)) if not product_ids and operator not in expression.NEGATIVE_TERM_OPERATORS: # Do not merge the 2 next lines into one single search, SQL search performance would be abysmal # on a database with thousands of matching products, due to the huge merge+unique needed for the # OR operator (and given the fact that the 'name' lookup results come from the ir.translation table # Performing a quick memory merge of ids in Python will give much better performance product_ids = list(self._search(args + [('default_code', operator, name)], limit=limit)) if not limit or len(product_ids) < limit: # we may underrun the limit because of dupes in the results, that's fine limit2 = (limit - len(product_ids)) if limit else False product2_ids = self._search(args + [('name', operator, name), ('id', 'not in', product_ids)], limit=limit2, access_rights_uid=name_get_uid) product_ids.extend(product2_ids) elif not product_ids and operator in expression.NEGATIVE_TERM_OPERATORS: domain = expression.OR([ ['&', ('default_code', operator, name), ('name', operator, name)], ['&', ('default_code', '=', False), ('name', operator, name)], ]) domain = expression.AND([args, domain]) product_ids = list(self._search(domain, limit=limit, access_rights_uid=name_get_uid)) if not product_ids and operator in positive_operators: ptrn = re.compile('(\[(.*?)\])') res = ptrn.search(name) if res: product_ids = list(self._search([('default_code', '=', res.group(2))] + args, limit=limit, access_rights_uid=name_get_uid)) # still no results, partner in context: search on supplier info as last hope to find something if not product_ids and self._context.get('partner_id'): suppliers_ids = self.env['product.supplierinfo']._search([ ('name', '=', self._context.get('partner_id')), '|', ('product_code', operator, name), ('product_name', operator, name)], access_rights_uid=name_get_uid) if suppliers_ids: product_ids = self._search([('product_tmpl_id.seller_ids', 'in', suppliers_ids)], limit=limit, access_rights_uid=name_get_uid) else: product_ids = self._search(args, limit=limit, access_rights_uid=name_get_uid) return product_ids
def _compute_debit_credit_balance(self): Curr = self.env['res.currency'] analytic_line_obj = self.env['account.analytic.line'] domain = [('account_id', 'in', self.ids), ('company_id', 'in', [False] + self.env.companies.ids)] if self._context.get('from_date', False): domain.append(('date', '>=', self._context['from_date'])) if self._context.get('to_date', False): domain.append(('date', '<=', self._context['to_date'])) if self._context.get('tag_ids'): tag_domain = expression.OR([[('tag_ids', 'in', [tag])] for tag in self._context['tag_ids']]) domain = expression.AND([domain, tag_domain]) user_currency = self.env.company.currency_id credit_groups = analytic_line_obj.read_group( domain=domain + [('amount', '>=', 0.0)], fields=['account_id', 'currency_id', 'amount'], groupby=['account_id', 'currency_id'], lazy=False, ) data_credit = defaultdict(float) for l in credit_groups: data_credit[l['account_id'][0]] += Curr.browse( l['currency_id'][0])._convert(l['amount'], user_currency, self.env.company, fields.Date.today()) debit_groups = analytic_line_obj.read_group( domain=domain + [('amount', '<', 0.0)], fields=['account_id', 'currency_id', 'amount'], groupby=['account_id', 'currency_id'], lazy=False, ) data_debit = defaultdict(float) for l in debit_groups: data_debit[l['account_id'][0]] += Curr.browse( l['currency_id'][0])._convert(l['amount'], user_currency, self.env.company, fields.Date.today()) for account in self: account.debit = abs(data_debit.get(account.id, 0.0)) account.credit = data_credit.get(account.id, 0.0) account.balance = account.credit - account.debit
def get_mention_suggestions(self, search, limit=8): """ Return 'limit'-first partners' id, name and email such that the name or email matches a 'search' string. Prioritize users, and then extend the research to all partners. """ search_dom = expression.OR([[('name', 'ilike', search)], [('email', 'ilike', search)]]) fields = ['id', 'name', 'email'] # Search users domain = expression.AND([[('user_ids.id', '!=', False)], search_dom]) users = self.search_read(domain, fields, limit=limit) # Search partners if less than 'limit' users found partners = [] if len(users) < limit: partners = self.search_read(search_dom, fields, limit=limit) # Remove duplicates partners = [p for p in partners if not len([u for u in users if u['id'] == p['id']])] return [users, partners]
def _get_quantity_in_progress(self, location_ids=False, warehouse_ids=False): if not location_ids: location_ids = [] if not warehouse_ids: warehouse_ids = [] qty_by_product_location, qty_by_product_wh = super()._get_quantity_in_progress(location_ids, warehouse_ids) domain = [] rfq_domain = [ ('state', 'in', ('draft', 'sent', 'to approve')), ('product_id', 'in', self.ids) ] if location_ids: domain = expression.AND([rfq_domain, [ '|', ('order_id.picking_type_id.default_location_dest_id', 'in', location_ids), '&', ('move_dest_ids', '=', False), ('orderpoint_id.location_id', 'in', location_ids) ]]) if warehouse_ids: wh_domain = expression.AND([rfq_domain, [ '|', ('order_id.picking_type_id.warehouse_id', 'in', warehouse_ids), '&', ('move_dest_ids', '=', False), ('orderpoint_id.warehouse_id', 'in', warehouse_ids) ]]) domain = expression.OR([domain, wh_domain]) groups = self.env['purchase.order.line'].read_group(domain, ['product_id', 'product_qty', 'order_id', 'product_uom', 'orderpoint_id'], ['order_id', 'product_id', 'product_uom', 'orderpoint_id'], lazy=False) for group in groups: if group.get('orderpoint_id'): location = self.env['stock.warehouse.orderpoint'].browse(group['orderpoint_id'][:1]).location_id else: order = self.env['purchase.order'].browse(group['order_id'][0]) location = order.picking_type_id.default_location_dest_id product = self.env['product.product'].browse(group['product_id'][0]) uom = self.env['uom.uom'].browse(group['product_uom'][0]) product_qty = uom._compute_quantity(group['product_qty'], product.uom_id, round=False) qty_by_product_location[(product.id, location.id)] += product_qty qty_by_product_wh[(product.id, location.get_warehouse().id)] += product_qty return qty_by_product_location, qty_by_product_wh
def _retrieve_product(self, name=None, default_code=None, barcode=None): '''Search all products and find one that matches one of the parameters. :param name: The name of the product. :param default_code: The default_code of the product. :param barcode: The barcode of the product. :returns: A product or an empty recordset if not found. ''' domains = [] for value, domain in ( (name, ('name', 'ilike', name)), (default_code, ('default_code', '=', default_code)), (barcode, ('barcode', '=', barcode)), ): if value is not None: domains.append([domain]) domain = expression.OR(domains) return self.env['product.product'].search(domain, limit=1)
def action_customize_digest_remove(self): ir_model_fields_obj = self.env['ir.model.fields'] ir_ui_view_obj = self.env['ir.ui.view'] if self.remove_type == 'group': find_view_id = self.available_group_name \ and self.available_group_name.split('_', 1)[0] or False view_ids = ir_ui_view_obj.search([ ('inherit_id', 'child_of', int(find_view_id))], order="id desc") field_list = [] for view_id in view_ids: root = ET.fromstring(view_id.arch_base) for child in root.iter('group'): name = child.find('field') if name.attrib and name.attrib.get('name', False): field_list.append(name.attrib.get('name', False)) field_ids = ir_model_fields_obj.search([ ('name', 'in', field_list)]) view_ids.unlink() for field_id in field_ids: ir_model_fields_obj.search([ ('depends', '=', field_id.name)]).unlink() field_ids.unlink() else: domain = expression.OR([('arch_db', 'like', record.name) ] for record in self.field_id) view_ids = ir_ui_view_obj.search(domain) for view_id in view_ids: root = ET.fromstring(view_id.arch_base) for child in root.iter('field'): if child.attrib and child.attrib.get( 'name', False) == self.field_id.name: view_id.unlink() ir_model_fields_obj.search([ ('depends', '=', self.field_id.name)]).unlink() self.field_id.unlink() return { 'type': 'ir.actions.client', 'tag': 'reload', }
def test_bundle_sends_bus(self): """ Tests two things: - Messages are posted to the bus when assets change i.e. their hash has been recomputed and differ from the attachment's - The interface deals with those bus messages by displaying one notification """ db_name = self.env.registry.db_name bundle_xml_ids = ('web.assets_common', 'web.assets_backend') domain = [] for bundle in bundle_xml_ids: domain = expression.OR([ domain, [('name', 'ilike', bundle + '%')] ]) # start from a clean slate self.env['ir.attachment'].search(domain).unlink() self.env.registry._clear_cache() sendones = [] def patched_sendone(self, channel, message): """ Control API and number of messages posted to the bus """ sendones.append((channel, message)) self.patch(type(self.env['bus.bus']), 'sendone', patched_sendone) self.start_tour('/web', "bundle_changed_notification", login='******', timeout=180) # One sendone for each asset bundle and for each CSS / JS self.assertEqual(len(sendones), 4) for sent in sendones: channel = sent[0] message = sent[1] self.assertEqual(channel, (db_name, 'bundle_changed')) self.assertEqual(len(message), 2) self.assertTrue(message[0] in bundle_xml_ids) self.assertTrue(isinstance(message[1], str))
def _recompute_qty_to_invoice(self, start_date, end_date): """ Recompute the qty_to_invoice field for product containing timesheets Search the existed timesheets between the given period in parameter. Retrieve the unit_amount of this timesheet and then recompute the qty_to_invoice for each current product. :param start_date: the start date of the period :param end_date: the end date of the period """ lines_by_timesheet = self.filtered( lambda sol: sol.product_id and sol.product_id. _is_delivered_timesheet()) domain = lines_by_timesheet._timesheet_compute_delivered_quantity_domain( ) refund_account_moves = self.order_id.invoice_ids.filtered( lambda am: am.state == 'posted' and am.move_type == 'out_refund' ).reversed_entry_id timesheet_domain = [ '|', ('timesheet_invoice_id', '=', False), ('timesheet_invoice_id.state', '=', 'cancel') ] if refund_account_moves: credited_timesheet_domain = [ ('timesheet_invoice_id.state', '=', 'posted'), ('timesheet_invoice_id', 'in', refund_account_moves.ids) ] timesheet_domain = expression.OR( [timesheet_domain, credited_timesheet_domain]) domain = expression.AND([domain, timesheet_domain]) if start_date: domain = expression.AND([domain, [('date', '>=', start_date)]]) if end_date: domain = expression.AND([domain, [('date', '<=', end_date)]]) mapping = lines_by_timesheet.sudo( )._get_delivered_quantity_by_analytic(domain) for line in lines_by_timesheet: line.qty_to_invoice = mapping.get(line.id, 0.0)
def _get_ranges(self): domain_1 = [ '&', ('type_id', '=', self.date_range_type_id.id), '|', '&', ('date_start', '>=', self.date_start), ('date_start', '<=', self.date_end), '&', ('date_end', '>=', self.date_start), ('date_end', '<=', self.date_end), ] domain_2 = [ '&', ('type_id', '=', self.date_range_type_id.id), '&', ('date_start', '<=', self.date_start), ('date_end', '>=', self.date_start), ] domain = expression.OR([domain_1, domain_2]) ranges = self.env['date.range'].search(domain) return ranges
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 if not group_domains: return expression.AND(global_domains) return expression.AND(global_domains + [expression.OR(group_domains)])
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 if not group_domains: return expression.AND(global_domains) return expression.AND(global_domains + [expression.OR(group_domains)])
def _analytic_compute_delivered_quantity_domain(self): domain = super(SaleOrderLine, self)._analytic_compute_delivered_quantity_domain() domain = expression.AND([domain, [('project_id', '=', False)]]) timesheet_domain = self._timesheet_compute_delivered_quantity_domain() return expression.OR([domain, timesheet_domain])