gamification/models/gamification_goal_definition.py
2024-11-01 14:01:27 +03:00

137 lines
6.9 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _, exceptions
from odoo.tools.safe_eval import safe_eval
DOMAIN_TEMPLATE = "[('store', '=', True), '|', ('model_id', '=', model_id), ('model_id', 'in', model_inherited_ids)%s]"
class GoalDefinition(models.Model):
"""Goal definition
A goal definition contains the way to evaluate an objective
Each module wanting to be able to set goals to the users needs to create
a new gamification_goal_definition
"""
_name = 'gamification.goal.definition'
_description = 'Gamification Goal Definition'
name = fields.Char("Goal Definition", required=True, translate=True)
description = fields.Text("Goal Description")
monetary = fields.Boolean("Monetary Value", default=False, help="The target and current value are defined in the company currency.")
suffix = fields.Char("Suffix", help="The unit of the target and current values", translate=True)
full_suffix = fields.Char("Full Suffix", compute='_compute_full_suffix', help="The currency and suffix field")
computation_mode = fields.Selection([
('manually', "Recorded manually"),
('count', "Automatic: number of records"),
('sum', "Automatic: sum on a field"),
('python', "Automatic: execute a specific Python code"),
], default='manually', string="Computation Mode", required=True,
help="Define how the goals will be computed. The result of the operation will be stored in the field 'Current'.")
display_mode = fields.Selection([
('progress', "Progressive (using numerical values)"),
('boolean', "Exclusive (done or not-done)"),
], default='progress', string="Displayed as", required=True)
model_id = fields.Many2one('ir.model', string='Model')
model_inherited_ids = fields.Many2many('ir.model', related='model_id.inherited_model_ids')
field_id = fields.Many2one(
'ir.model.fields', string='Field to Sum',
domain=DOMAIN_TEMPLATE % ''
)
field_date_id = fields.Many2one(
'ir.model.fields', string='Date Field', help='The date to use for the time period evaluated',
domain=DOMAIN_TEMPLATE % ", ('ttype', 'in', ('date', 'datetime'))"
)
domain = fields.Char(
"Filter Domain", required=True, default="[]",
help="Domain for filtering records. General rule, not user depending,"
" e.g. [('state', '=', 'done')]. The expression can contain"
" reference to 'user' which is a browse record of the current"
" user if not in batch mode.")
batch_mode = fields.Boolean("Batch Mode", help="Evaluate the expression in batch instead of once for each user")
batch_distinctive_field = fields.Many2one('ir.model.fields', string="Distinctive field for batch user", help="In batch mode, this indicates which field distinguishes one user from the other, e.g. user_id, partner_id...")
batch_user_expression = fields.Char("Evaluated expression for batch mode", help="The value to compare with the distinctive field. The expression can contain reference to 'user' which is a browse record of the current user, e.g. user.id, user.partner_id.id...")
compute_code = fields.Text("Python Code", help="Python code to be executed for each user. 'result' should contains the new current value. Evaluated user can be access through object.user_id.")
condition = fields.Selection([
('higher', "The higher the better"),
('lower', "The lower the better")
], default='higher', required=True, string="Goal Performance",
help="A goal is considered as completed when the current value is compared to the value to reach")
action_id = fields.Many2one('ir.actions.act_window', string="Action", help="The action that will be called to update the goal value.")
res_id_field = fields.Char("ID Field of user", help="The field name on the user profile (res.users) containing the value for res_id for action.")
@api.depends('suffix', 'monetary') # also depends of user...
def _compute_full_suffix(self):
for goal in self:
items = []
if goal.monetary:
items.append(self.env.company.currency_id.symbol or u'¤')
if goal.suffix:
items.append(goal.suffix)
goal.full_suffix = u' '.join(items)
def _check_domain_validity(self):
# take admin as should always be present
for definition in self:
if definition.computation_mode not in ('count', 'sum'):
continue
Obj = self.env[definition.model_id.model]
try:
domain = safe_eval(definition.domain, {
'user': self.env.user.with_user(self.env.user)
})
# dummy search to make sure the domain is valid
Obj.search_count(domain)
except (ValueError, SyntaxError) as e:
msg = e
if isinstance(e, SyntaxError):
msg = (e.msg + '\n' + e.text)
raise exceptions.UserError(_("The domain for the definition %s seems incorrect, please check it.\n\n%s", definition.name, msg))
return True
def _check_model_validity(self):
""" make sure the selected field and model are usable"""
for definition in self:
try:
if not (definition.model_id and definition.field_id):
continue
Model = self.env[definition.model_id.model]
field = Model._fields.get(definition.field_id.name)
if not (field and field.store):
raise exceptions.UserError(_(
"The model configuration for the definition %(name)s seems incorrect, please check it.\n\n%(field_name)s not stored",
name=definition.name,
field_name=definition.field_id.name
))
except KeyError as e:
raise exceptions.UserError(_(
"The model configuration for the definition %(name)s seems incorrect, please check it.\n\n%(error)s not found",
name=definition.name,
error=e
))
@api.model_create_multi
def create(self, vals_list):
definitions = super(GoalDefinition, self).create(vals_list)
definitions.filtered_domain([
('computation_mode', 'in', ['count', 'sum']),
])._check_domain_validity()
definitions.filtered_domain([
('field_id', '=', 'True'),
])._check_model_validity()
return definitions
def write(self, vals):
res = super(GoalDefinition, self).write(vals)
if vals.get('computation_mode', 'count') in ('count', 'sum') and (vals.get('domain') or vals.get('model_id')):
self._check_domain_validity()
if vals.get('field_id') or vals.get('model_id') or vals.get('batch_mode'):
self._check_model_validity()
return res