Files
odoo_source/addons/analytic/models/analytic_mixin.py
T
gawa-odoo 8bf6bee153 [IMP] analytic, *: block validation with mandatory plan
* = {account, sale, purchase, hr_expense}
When a plan is mandatory for SOL, POL or expenses, the flow should still be blocked when pressing the button, and not only when creating analytic lines.

We add the info in the context of the button, so automatic flows are still not blocked.

When the applicability rule requires a mandatory analytic distribution, raise an error upon :
- confirming PO,
- sending or confirming SO
- approving Expense Report by manager.

t-3040929

closes odoo/odoo#107166

X-original-commit: 8623a7850288828759db125b1054b0fed6b6b135
Signed-off-by: William André (wan) <wan@odoo.com>
2022-12-04 17:58:01 +01:00

71 lines
3.5 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api, _
from odoo.tools.float_utils import float_round, float_compare
from odoo.exceptions import ValidationError
class AnalyticMixin(models.AbstractModel):
_name = 'analytic.mixin'
_description = 'Analytic Mixin'
analytic_distribution = fields.Json(
'Analytic Distribution',
compute="_compute_analytic_distribution", store=True, copy=True, readonly=False,
precompute=True
)
analytic_precision = fields.Integer(
store=False,
default=lambda self: self.env['decimal.precision'].precision_get("Percentage Analytic"),
)
def init(self):
# Add a gin index for json search on the keys, on the models that actually have a table
query = ''' SELECT table_name
FROM information_schema.tables
WHERE table_name=%s '''
self.env.cr.execute(query, [self._table])
if self.env.cr.dictfetchone():
query = f"""
CREATE INDEX IF NOT EXISTS {self._table}_analytic_distribution_gin_index
ON {self._table} USING gin(analytic_distribution);
"""
self.env.cr.execute(query)
def _compute_analytic_distribution(self):
pass
def write(self, vals):
""" Format the analytic_distribution float value, so equality on analytic_distribution can be done """
decimal_precision = self.env['decimal.precision'].precision_get('Percentage Analytic')
vals = self._sanitize_values(vals, decimal_precision)
return super().write(vals)
@api.model_create_multi
def create(self, vals_list):
""" Format the analytic_distribution float value, so equality on analytic_distribution can be done """
decimal_precision = self.env['decimal.precision'].precision_get('Percentage Analytic')
vals_list = [self._sanitize_values(vals, decimal_precision) for vals in vals_list]
return super().create(vals_list)
def _validate_distribution(self, **kwargs):
if self.env.context.get('validate_analytic', False):
mandatory_plans_ids = [plan['id'] for plan in self.env['account.analytic.plan'].sudo().get_relevant_plans(**kwargs) if plan['applicability'] == 'mandatory']
if not mandatory_plans_ids:
return
decimal_precision = self.env['decimal.precision'].precision_get('Percentage Analytic')
distribution_by_root_plan = {}
for analytic_account_id, percentage in (self.analytic_distribution or {}).items():
root_plan = self.env['account.analytic.account'].browse(int(analytic_account_id)).root_plan_id
distribution_by_root_plan[root_plan.id] = distribution_by_root_plan.get(root_plan.id, 0) + percentage
for plan_id in mandatory_plans_ids:
if float_compare(distribution_by_root_plan.get(plan_id, 0), 100, precision_digits=decimal_precision) != 0:
raise ValidationError(_("One or more lines require a 100% analytic distribution."))
def _sanitize_values(self, vals, decimal_precision):
""" Normalize the float of the distribution """
if 'analytic_distribution' in vals:
vals['analytic_distribution'] = vals.get('analytic_distribution') and {
account_id: float_round(distribution, decimal_precision) for account_id, distribution in vals['analytic_distribution'].items()}
return vals