Esempio n. 1
0
 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
Esempio n. 2
0
 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
Esempio n. 3
0
    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))
Esempio n. 4
0
 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))
Esempio n. 5
0
    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)'
                      ))
Esempio n. 6
0
    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
Esempio n. 7
0
    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)
Esempio n. 8
0
 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
Esempio n. 9
0
    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
            }
        }
Esempio n. 10
0
 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)
Esempio n. 11
0
    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)]]))
Esempio n. 12
0
 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
Esempio n. 13
0
    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)
Esempio n. 14
0
 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
Esempio n. 15
0
 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)
Esempio n. 16
0
    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)
Esempio n. 17
0
 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
Esempio n. 18
0
 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'])]
     ])
Esempio n. 19
0
    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])
Esempio n. 20
0
 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
Esempio n. 21
0
 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))
Esempio n. 22
0
    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)]])
Esempio n. 23
0
    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)])
Esempio n. 24
0
    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]
Esempio n. 25
0
    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)
                                    ],
                               ])])
Esempio n. 26
0
    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)]])
Esempio n. 27
0
    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
Esempio n. 28
0
 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))
Esempio n. 29
0
 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))
Esempio n. 30
0
    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