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 _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 _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 _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 _compute_debit_credit_balance(self): Curr = self.env['res.currency'] analytic_line_obj = self.env['account.analytic.line'] domain = [('account_id', 'in', self.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]) if self._context.get('company_ids'): domain.append(('company_id', 'in', self._context['company_ids'])) 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_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_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)]]) search_dom = expression.AND([[('active', '=', True)], search_dom]) fields = ['id', 'name', 'email'] # Search users domain = expression.AND([[('user_ids.id', '!=', False), ('user_ids.active', '=', True)], 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 _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 _domain_move_lines_for_reconciliation(self, st_line, aml_accounts, partner_id, excluded_ids=[], search_str=False, mode='rp'): """ Return the domain for account.move.line records which can be used for bank statement reconciliation. :param aml_accounts: :param partner_id: :param excluded_ids: :param search_str: :param mode: 'rp' for receivable/payable or 'other' """ AccountMoveLine = self.env['account.move.line'] #Always exclude the journal items that have been marked as 'to be checked' in a former bank statement reconciliation to_check_excluded = AccountMoveLine.search( AccountMoveLine._get_suspense_moves_domain()).ids excluded_ids.extend(to_check_excluded) domain_reconciliation = [ '&', '&', '&', ('statement_line_id', '=', False), ('account_id', 'in', aml_accounts), ('payment_id', '<>', False), ('balance', '!=', 0.0), ] # default domain matching domain_matching = [ '&', '&', ('reconciled', '=', False), ('account_id.reconcile', '=', True), ('balance', '!=', 0.0), ] domain = expression.OR([domain_reconciliation, domain_matching]) if partner_id: domain = expression.AND( [domain, [('partner_id', '=', partner_id)]]) if mode == 'rp': domain = expression.AND([ domain, [('account_id.internal_type', 'in', ['receivable', 'payable', 'liquidity'])] ]) else: domain = expression.AND([ domain, [('account_id.internal_type', 'not in', ['receivable', 'payable', 'liquidity'])] ]) # Domain factorized for all reconciliation use cases 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]) if excluded_ids: domain = expression.AND([[('id', 'not in', excluded_ids)], domain]) # filter on account.move.line having the same company as the statement line domain = expression.AND( [domain, [('company_id', '=', st_line.company_id.id)]]) # take only moves in valid state. Draft is accepted only when "Post At" is set # to "Bank Reconciliation" in the associated journal domain_post_at = [ '|', '&', ('move_id.state', '=', 'draft'), ('journal_id.post_at', '=', 'bank_rec'), ('move_id.state', 'not in', ['draft', 'cancel']), ] domain = expression.AND([domain, domain_post_at]) if st_line.company_id.account_bank_reconciliation_start: domain = expression.AND([ domain, [('date', '>=', st_line.company_id.account_bank_reconciliation_start)] ]) return domain
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 = self._search([('default_code', '=', name)] + args, limit=limit, access_rights_uid=name_get_uid) if not product_ids: product_ids = 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 = 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 = 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 = 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 models.lazy_name_get( self.browse(product_ids).with_user(name_get_uid))
def _default_sale_line_domain(self): domain = super(AccountAnalyticLine, self)._default_sale_line_domain() return expression.OR([domain, [('qty_delivered_method', '=', 'timesheet')]])