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') ] 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) 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 _search_rule(self, route_ids, product_id, warehouse_id, domain): """ First find a rule among the ones defined on the procurement group, then try on the routes defined for the product, finally fallback on the default behavior """ if warehouse_id: domain = expression.AND([[ '|', ('warehouse_id', '=', warehouse_id.id), ('warehouse_id', '=', False) ], domain]) Rule = self.env['stock.rule'] res = self.env['stock.rule'] if route_ids: res = Rule.search(expression.AND([[('route_id', 'in', route_ids.ids)], domain]), order='route_sequence, sequence', limit=1) if not res: product_routes = product_id.route_ids | product_id.categ_id.total_route_ids if product_routes: res = Rule.search(expression.AND([[ ('route_id', 'in', product_routes.ids) ], domain]), order='route_sequence, sequence', limit=1) if not res and warehouse_id: warehouse_routes = warehouse_id.route_ids if warehouse_routes: res = Rule.search(expression.AND([[ ('route_id', 'in', warehouse_routes.ids) ], domain]), order='route_sequence, sequence', limit=1) return res
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): args = args or [] if self.env.context.get('country_id'): args = expression.AND([ args, [('country_id', '=', self.env.context.get('country_id'))] ]) if operator == 'ilike' and not (name or '').strip(): first_domain = [] domain = [] else: first_domain = [('code', '=ilike', name)] domain = [('name', operator, name)] first_state_ids = self._search( expression.AND([first_domain, args]), limit=limit, access_rights_uid=name_get_uid) if first_domain else [] state_ids = first_state_ids + [ state_id for state_id in self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid) if not state_id in first_state_ids ] return models.lazy_name_get( self.browse(state_ids).with_user(name_get_uid))
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): args = args or [] domain = [] if name: domain = ['|', ('name', operator, name), ('partner_ref', operator, name)] purchase_order_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid) return models.lazy_name_get(self.browse(purchase_order_ids).with_user(name_get_uid))
def _check_current_contract(self): """ Two contracts in state [incoming | open | close] cannot overlap """ for contract in self.filtered( lambda c: c.state not in ['draft', 'cancel'] or c.state == 'draft' and c.kanban_state == 'done'): domain = [ ('id', '!=', contract.id), ('employee_id', '=', contract.employee_id.id), '|', ('state', 'in', ['open', 'close']), '&', ('state', '=', 'draft'), ('kanban_state', '=', 'done') # replaces incoming ] if not contract.date_end: start_domain = [] end_domain = [ '|', ('date_end', '>=', contract.date_start), ('date_end', '=', False) ] else: start_domain = [('date_start', '<=', contract.date_end)] end_domain = [ '|', ('date_end', '>', contract.date_start), ('date_end', '=', False) ] domain = expression.AND([domain, start_domain, end_domain]) if self.search_count(domain): raise ValidationError( _('An employee can only have one contract at the same time. (Excluding Draft and Cancelled contracts)' ))
def _get_crm_utm_domain(self): """ We want all records that match the UTMs """ domain = [] if self.campaign_id: domain = expression.AND( [domain, [('campaign_id', '=', self.campaign_id.id)]]) if self.source_id: domain = expression.AND( [domain, [('source_id', '=', self.source_id.id)]]) if self.medium_id: domain = expression.AND( [domain, [('medium_id', '=', self.medium_id.id)]]) if not domain: domain = expression.AND([domain, [(0, '=', 1)]]) 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 rating_get_repartition(self, add_stats=False, domain=None): """ get the repatition of rating grade for the given res_ids. :param add_stats : flag to add stat to the result :type add_stats : boolean :param domain : optional extra domain of the rating to include/exclude in repartition :return dictionnary if not add_stats, the dict is like - key is the rating value (integer) - value is the number of object (res_model, res_id) having the value otherwise, key is the value of the information (string) : either stat name (avg, total, ...) or 'repartition' containing the same dict if add_stats was False. """ base_domain = expression.AND( [self._rating_domain(), [('rating', '>=', 1)]]) if domain: base_domain += domain data = self.env['rating.rating'].read_group(base_domain, ['rating'], ['rating', 'res_id']) # init dict with all posible rate value, except 0 (no value for the rating) values = dict.fromkeys(range(1, 11), 0) values.update((d['rating'], d['rating_count']) for d in data) # add other stats if add_stats: rating_number = sum(values.values()) result = { 'repartition': values, 'avg': sum(float(key * values[key]) for key in values) / rating_number if rating_number > 0 else 0, 'total': sum(it['rating_count'] for it in data), } return result return values
def action_time_off_analysis(self): domain = [('holiday_type', '=', 'employee')] if self.env.context.get('active_ids'): domain = expression.AND([ domain, [('employee_id', 'in', self.env.context.get('active_ids', []))] ]) return { 'name': _('Time Off Analysis'), 'type': 'ir.actions.act_window', 'res_model': 'hr.leave.report', 'view_mode': 'tree,form,pivot', 'search_view_id': self.env.ref('hr_holidays.view_hr_holidays_filter_report').id, 'domain': domain, 'context': { 'search_default_group_type': True, 'search_default_year': True } }
def _get_records_from_sms(self, sms_sms_ids=None, additional_domain=None): if not self.ids and sms_sms_ids: domain = [('sms_sms_id_int', 'in', sms_sms_ids)] else: domain = [('id', 'in', self.ids)] if additional_domain: domain = expression.AND([domain, additional_domain]) return self.search(domain)
def _get_contracts(self, date_from, date_to, states=['open'], kanban_state=False): """ Returns the contracts of the employee between date_from and date_to """ state_domain = [('state', 'in', states)] if kanban_state: state_domain = expression.AND( [state_domain, [('kanban_state', 'in', kanban_state)]]) return self.env['hr.contract'].search( expression.AND([[('employee_id', 'in', self.ids)], state_domain, [('date_start', '<=', date_to), '|', ('date_end', '=', False), ('date_end', '>=', date_from)]]))
def _task_get_page_view_values(self, task, access_token, **kwargs): values = super(ProjectCustomerPortal, self)._task_get_page_view_values( task, access_token, **kwargs) domain = request.env[ 'account.analytic.line']._timesheet_get_portal_domain() domain = expression.AND([domain, [('task_id', '=', task.id)]]) timesheets = request.env['account.analytic.line'].sudo().search(domain) values['timesheets'] = timesheets return values
def _notify_chat(self): records = self.search([('mode', '=', 'chat'), ('active', '=', True)]) today = fields.Date.today() now = fields.Datetime.now() for alert in records: notification_to = now.astimezone(pytz.timezone(alert.tz)).replace( second=0, microsecond=0, tzinfo=None) notification_from = notification_to - timedelta(minutes=5) send_at = datetime.combine( fields.Date.today(), float_to_time(alert.notification_time, alert.notification_moment)) if alert.available_today and send_at > notification_from and send_at <= notification_to: order_domain = [('state', '!=', 'cancelled')] if alert.location_ids.ids: order_domain = expression.AND([ order_domain, [('user_id.last_lunch_location_id', 'in', alert.location_ids.ids)] ]) if alert.recipients != 'everyone': weeks = 1 if alert.recipients == 'last_month': weeks = 4 else: # last_year weeks = 52 delta = timedelta(weeks=weeks) order_domain = expression.AND( [order_domain, [('date', '>=', today - delta)]]) orders = self.env['lunch.order'].search(order_domain).mapped( 'user_id') partner_ids = [user.partner_id.id for user in orders] if partner_ids: self.env['mail.thread'].message_notify( body=alert.message, partner_ids=partner_ids)
def _domain_product_id(self): if not self._is_inventory_mode(): return domain = [('type', '=', 'product')] if self.env.context.get('product_tmpl_id'): domain = expression.AND([ domain, [('product_tmpl_id', '=', self.env.context['product_tmpl_id'])] ]) return domain
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): # TDE FIXME: currently overriding the domain; however as it includes a # search on a m2o and one on a m2m, probably this will quickly become # difficult to compute - check if performance optimization is required if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'): args = args or [] domain = ['|', ('attribute_id', operator, name), ('value_ids', operator, name)] attribute_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid) return models.lazy_name_get(self.browse(attribute_ids).with_user(name_get_uid)) return super(ProductTemplateAttributeLine, self)._name_search(name=name, args=args, operator=operator, limit=limit, name_get_uid=name_get_uid)
def _get_number_of_attempts_lefts(self, partner, email, invite_token): """ Returns the number of attempts left. """ self.ensure_one() domain = [('survey_id', '=', self.id), ('test_entry', '=', False), ('state', '=', 'done')] if partner: domain = expression.AND( [domain, [('partner_id', '=', partner.id)]]) else: domain = expression.AND([domain, [('email', '=', email)]]) if invite_token: domain = expression.AND( [domain, [('invite_token', '=', invite_token)]]) return self.attempts_limit - self.env[ 'survey.user_input'].search_count(domain)
def _invoice_get_page_view_values(self, invoice, access_token, **kwargs): values = super(PortalAccount, self)._invoice_get_page_view_values( invoice, access_token, **kwargs) domain = request.env[ 'account.analytic.line']._timesheet_get_portal_domain() domain = expression.AND( [domain, [('timesheet_invoice_id', '=', invoice.id)]]) values['timesheets'] = request.env['account.analytic.line'].sudo( ).search(domain) return values
def _timesheet_get_portal_domain(self): """ Only the timesheets with a product invoiced on delivered quantity are concerned. since in ordered quantity, the timesheet quantity is not invoiced, thus there is no meaning of showing invoice with ordered quantity. """ domain = super(AccountAnalyticLine, self)._timesheet_get_portal_domain() return expression.AND([ domain, [('timesheet_invoice_type', 'in', ['billable_time', 'non_billable'])] ])
def _gather(self, product_id, location_id, lot_id=None, package_id=None, owner_id=None, strict=False): self.env['stock.quant'].flush( ['location_id', 'owner_id', 'package_id', 'lot_id', 'product_id']) self.env['product.product'].flush(['virtual_available']) removal_strategy = self._get_removal_strategy(product_id, location_id) removal_strategy_order = self._get_removal_strategy_order( removal_strategy) domain = [ ('product_id', '=', product_id.id), ] if not strict: if lot_id: domain = expression.AND([[('lot_id', '=', lot_id.id)], domain]) if package_id: domain = expression.AND([[('package_id', '=', package_id.id)], domain]) if owner_id: domain = expression.AND([[('owner_id', '=', owner_id.id)], domain]) domain = expression.AND([[('location_id', 'child_of', location_id.id)], domain]) else: domain = expression.AND([[('lot_id', '=', lot_id and lot_id.id or False)], domain]) domain = expression.AND([[ ('package_id', '=', package_id and package_id.id or False) ], domain]) domain = expression.AND([[ ('owner_id', '=', owner_id and owner_id.id or False) ], domain]) domain = expression.AND([[('location_id', '=', location_id.id)], domain]) # Copy code of _search for special NULLS FIRST/LAST order self.check_access_rights('read') query = self._where_calc(domain) self._apply_ir_rules(query, 'read') from_clause, where_clause, where_clause_params = query.get_sql() where_str = where_clause and (" WHERE %s" % where_clause) or '' query_str = 'SELECT "%s".id FROM ' % self._table + from_clause + where_str + " ORDER BY " + removal_strategy_order self._cr.execute(query_str, where_clause_params) res = self._cr.fetchall() # No uniquify list necessary as auto_join is not applied anyways... return self.browse([x[0] for x in res])
def open_at_date(self): tree_view_id = self.env.ref('stock.view_stock_product_tree').id form_view_id = self.env.ref('stock.product_form_view_procurement_button').id domain = [('type', '=', 'product')] product_id = self.env.context.get('product_id', False) product_tmpl_id = self.env.context.get('product_tmpl_id', False) if product_id: domain = expression.AND([domain, [('id', '=', product_id)]]) elif product_tmpl_id: domain = expression.AND([domain, [('product_tmpl_id', '=', product_tmpl_id)]]) # We pass `to_date` in the context so that `qty_available` will be computed across # moves until date. action = { 'type': 'ir.actions.act_window', 'views': [(tree_view_id, 'tree'), (form_view_id, 'form')], 'view_mode': 'tree,form', 'name': _('Products'), 'res_model': 'product.product', 'domain': domain, 'context': dict(self.env.context, to_date=self.inventory_datetime), } return action
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): if operator not in ('ilike', 'like', '=', '=like', '=ilike'): return super(AccountAnalyticAccount, self)._name_search(name, args, operator, limit, name_get_uid=name_get_uid) args = args or [] if operator == 'ilike' and not (name or '').strip(): domain = [] else: # `partner_id` is in auto_join and the searches using ORs with auto_join fields doesn't work # we have to cut the search in two searches ... https://github.com/coffice/coffice/issues/25175 partner_ids = self.env['res.partner']._search([('name', operator, name)], limit=limit, access_rights_uid=name_get_uid) domain = ['|', '|', ('code', operator, name), ('name', operator, name), ('partner_id', 'in', partner_ids)] analytic_account_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid) return models.lazy_name_get(self.browse(analytic_account_ids).with_user(name_get_uid))
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 _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 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 _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 _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 _make_infos(self, user, **kwargs): res = dict(kwargs) is_manager = request.env.user.has_group('lunch.group_lunch_manager') currency = user.company_id.currency_id res.update({ 'username': user.sudo().name, 'userimage': '/web/image?model=res.users&id=%s&field=image_128' % user.id, 'wallet': request.env['lunch.cashmove'].get_wallet_balance(user, False), 'is_manager': is_manager, 'locations': request.env['lunch.location'].search_read([], ['name']), 'currency': { 'symbol': currency.symbol, 'position': currency.position }, }) user_location = user.last_lunch_location_id has_multi_company_access = not user_location.company_id or user_location.company_id.id in request._context.get( 'allowed_company_ids', request.env.company.ids) if not user_location or not has_multi_company_access: user.last_lunch_location_id = user_location = request.env[ 'lunch.location'].search([], limit=1) alert_domain = expression.AND([ [('available_today', '=', True)], [('location_ids', 'in', user_location.id)], [('mode', '=', 'alert')], ]) res.update({ 'user_location': (user_location.id, user_location.name), 'alerts': request.env['lunch.alert'].search_read(alert_domain, ['message']), }) return res
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): args = args or [] if operator == 'ilike' and not (name or '').strip(): domain = [] else: domain = [ '|', ('name', operator, name), ('driver_id.name', operator, name) ] rec = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid) return models.lazy_name_get(self.browse(rec).with_user(name_get_uid))
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): """ search full name and barcode """ args = args or [] if operator == 'ilike' and not (name or '').strip(): domain = [] else: domain = [ '|', ('barcode', operator, name), ('complete_name', operator, name) ] location_ids = self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid) return models.lazy_name_get( self.browse(location_ids).with_user(name_get_uid))
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