Odoo18-Base/addons/analytic/models/analytic_plan.py
2025-03-10 11:12:23 +07:00

220 lines
7.5 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from random import randint
class AccountAnalyticPlan(models.Model):
_name = 'account.analytic.plan'
_description = 'Analytic Plans'
_parent_store = True
_rec_name = 'complete_name'
_order = 'complete_name asc'
_check_company_auto = True
def _default_color(self):
return randint(1, 11)
name = fields.Char(required=True)
description = fields.Text(string='Description')
parent_id = fields.Many2one(
'account.analytic.plan',
string="Parent",
ondelete='cascade',
domain="[('id', '!=', id), ('company_id', 'in', [False, company_id])]",
check_company=True,
)
parent_path = fields.Char(
index='btree',
unaccent=False,
)
children_ids = fields.One2many(
'account.analytic.plan',
'parent_id',
string="Childrens",
)
children_count = fields.Integer(
'Children Plans Count',
compute='_compute_children_count',
)
complete_name = fields.Char(
'Complete Name',
compute='_compute_complete_name',
recursive=True,
store=True,
)
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.company,
)
account_ids = fields.One2many(
'account.analytic.account',
'plan_id',
string="Accounts",
)
account_count = fields.Integer(
'Analytic Accounts Count',
compute='_compute_analytic_account_count',
)
all_account_count = fields.Integer(
'All Analytic Accounts Count',
compute='_compute_all_analytic_account_count',
)
color = fields.Integer(
'Color',
default=_default_color,
)
default_applicability = fields.Selection(
selection=[
('optional', 'Optional'),
('mandatory', 'Mandatory'),
('unavailable', 'Unavailable'),
],
string="Default Applicability",
required=True,
default='optional',
readonly=False,
)
applicability_ids = fields.One2many(
'account.analytic.applicability',
'analytic_plan_id',
string='Applicability',
)
@api.depends('name', 'parent_id.complete_name')
def _compute_complete_name(self):
for plan in self:
if plan.parent_id:
plan.complete_name = '%s / %s' % (plan.parent_id.complete_name, plan.name)
else:
plan.complete_name = plan.name
@api.depends('account_ids')
def _compute_analytic_account_count(self):
for plan in self:
plan.account_count = len(plan.account_ids)
@api.depends('account_ids', 'children_ids')
def _compute_all_analytic_account_count(self):
for plan in self:
plan.all_account_count = self.env['account.analytic.account'].search_count([('plan_id', "child_of", plan.id)])
@api.depends('children_ids')
def _compute_children_count(self):
for plan in self:
plan.children_count = len(plan.children_ids)
def action_view_analytical_accounts(self):
result = {
"type": "ir.actions.act_window",
"res_model": "account.analytic.account",
"domain": [('plan_id', "child_of", self.id)],
"context": {'default_plan_id': self.id},
"name": _("Analytical Accounts"),
'view_mode': 'list,form',
}
return result
def action_view_children_plans(self):
result = {
"type": "ir.actions.act_window",
"res_model": "account.analytic.plan",
"domain": [('parent_id', '=', self.id)],
"context": {'default_parent_id': self.id,
'default_color': self.color},
"name": _("Analytical Plans"),
'view_mode': 'list,form',
}
return result
@api.model
def get_relevant_plans(self, **kwargs):
""" Returns the list of plans that should be available.
This list is computed based on the applicabilities of root plans. """
company_id = kwargs.get('company_id', self.env.company.id)
record_account_ids = kwargs.get('existing_account_ids', [])
all_plans = self.search([
('account_ids', '!=', False),
'|', ('company_id', '=', company_id), ('company_id', '=', False),
])
root_plans = self.browse({
int(plan.parent_path.split('/')[0])
for plan in all_plans
}).filtered(lambda p: p._get_applicability(**kwargs) != 'unavailable')
# If we have accounts that are already selected (before the applicability rules changed or from a model),
# we want the plans that were unavailable to be shown in the list (and in optional, because the previous
# percentage could be different from 0)
forced_plans = self.env['account.analytic.account'].browse(record_account_ids).exists().mapped(
'root_plan_id') - root_plans
return sorted([
{
"id": plan.id,
"name": plan.name,
"color": plan.color,
"applicability": plan._get_applicability(**kwargs) if plan in root_plans else 'optional',
"all_account_count": plan.all_account_count
}
for plan in root_plans + forced_plans
], key=lambda d: (d['applicability'], d['id']))
def _get_applicability(self, **kwargs):
""" Returns the applicability of the best applicability line or the default applicability """
self.ensure_one()
if 'applicability' in kwargs:
# For models for example, we want all plans to be visible, so we force the applicability
return kwargs['applicability']
else:
score = 0
applicability = self.default_applicability
for applicability_rule in self.applicability_ids:
score_rule = applicability_rule._get_score(**kwargs)
if score_rule > score:
applicability = applicability_rule.applicability
score = score_rule
return applicability
def _get_default(self):
plan = self.env['account.analytic.plan'].sudo().search(
['|', ('company_id', '=', False), ('company_id', '=', self.env.company.id)],
limit=1)
if plan:
return plan
else:
return self.env['account.analytic.plan'].create({
'name': 'Default',
'company_id': self.env.company.id,
})
class AccountAnalyticApplicability(models.Model):
_name = 'account.analytic.applicability'
_description = "Analytic Plan's Applicabilities"
analytic_plan_id = fields.Many2one('account.analytic.plan')
business_domain = fields.Selection(
selection=[
('general', 'Miscellaneous'),
],
required=True,
string='Domain',
)
applicability = fields.Selection([
('optional', 'Optional'),
('mandatory', 'Mandatory'),
('unavailable', 'Unavailable'),
],
required=True,
string="Applicability",
)
def _get_score(self, **kwargs):
""" Gives the score of an applicability with the parameters of kwargs """
self.ensure_one()
if not kwargs.get('business_domain'):
return 0
else:
return 1 if kwargs.get('business_domain') == self.business_domain else -1