123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- # -*- coding: utf-8 -*-
- # Part of Odoo. See LICENSE file for full copyright and licensing details.
- from collections import defaultdict
- from odoo import api, fields, models, _
- from odoo.exceptions import UserError
- class AccountAnalyticAccount(models.Model):
- _name = 'account.analytic.account'
- _inherit = ['mail.thread']
- _description = 'Analytic Account'
- _order = 'plan_id, name asc'
- _check_company_auto = True
- _rec_names_search = ['name', 'code', 'partner_id']
- name = fields.Char(
- string='Analytic Account',
- index='trigram',
- required=True,
- tracking=True,
- )
- code = fields.Char(
- string='Reference',
- index='btree',
- tracking=True,
- )
- active = fields.Boolean(
- 'Active',
- help="Deactivate the account.",
- default=True,
- tracking=True,
- )
- plan_id = fields.Many2one(
- 'account.analytic.plan',
- string='Plan',
- check_company=True,
- required=True,
- )
- root_plan_id = fields.Many2one(
- 'account.analytic.plan',
- string='Root Plan',
- check_company=True,
- compute="_compute_root_plan",
- store=True,
- )
- color = fields.Integer(
- 'Color Index',
- related='plan_id.color',
- )
- line_ids = fields.One2many(
- 'account.analytic.line',
- 'account_id',
- string="Analytic Lines",
- )
- company_id = fields.Many2one(
- 'res.company',
- string='Company',
- default=lambda self: self.env.company,
- )
- # use auto_join to speed up name_search call
- partner_id = fields.Many2one(
- 'res.partner',
- string='Customer',
- auto_join=True,
- tracking=True,
- check_company=True,
- )
- balance = fields.Monetary(
- compute='_compute_debit_credit_balance',
- string='Balance',
- groups='account.group_account_readonly',
- )
- debit = fields.Monetary(
- compute='_compute_debit_credit_balance',
- string='Debit',
- groups='account.group_account_readonly',
- )
- credit = fields.Monetary(
- compute='_compute_debit_credit_balance',
- string='Credit',
- groups='account.group_account_readonly',
- )
- currency_id = fields.Many2one(
- related="company_id.currency_id",
- string="Currency",
- )
- @api.constrains('company_id')
- def _check_company_consistency(self):
- analytic_accounts = self.filtered('company_id')
- if not analytic_accounts:
- return
- self.flush_recordset(['company_id'])
- self.env['account.analytic.line'].flush_model(['account_id', 'company_id'])
- self._cr.execute('''
- SELECT line.account_id
- FROM account_analytic_line line
- JOIN account_analytic_account account ON line.account_id = account.id
- WHERE line.company_id != account.company_id and account.company_id IS NOT NULL
- AND account.id IN %s
- ''', [tuple(self.ids)])
- if self._cr.fetchone():
- raise UserError(_("You can't set a different company on your analytic account since there are some analytic items linked to it."))
- def name_get(self):
- res = []
- for analytic in self:
- name = analytic.name
- if analytic.code:
- name = f'[{analytic.code}] {name}'
- if analytic.partner_id.commercial_partner_id.name:
- name = f'{name} - {analytic.partner_id.commercial_partner_id.name}'
- res.append((analytic.id, name))
- return res
- def copy_data(self, default=None):
- default = dict(default or {})
- default.setdefault('name', _("%s (copy)", self.name))
- return super().copy_data(default)
- @api.model
- def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
- """
- Override read_group to calculate the sum of the non-stored fields that depend on the user context
- """
- res = super(AccountAnalyticAccount, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
- accounts = self.env['account.analytic.account']
- for line in res:
- if '__domain' in line:
- accounts = self.search(line['__domain'])
- if 'balance' in fields:
- line['balance'] = sum(accounts.mapped('balance'))
- if 'debit' in fields:
- line['debit'] = sum(accounts.mapped('debit'))
- if 'credit' in fields:
- line['credit'] = sum(accounts.mapped('credit'))
- return res
- @api.depends('line_ids.amount')
- 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']))
- 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
- @api.depends('plan_id', 'plan_id.parent_path')
- def _compute_root_plan(self):
- for account in self:
- account.root_plan_id = int(account.plan_id.parent_path[:-1].split('/')[0]) if account.plan_id.parent_path else None
|