Purpose ======= Some users found a way to farm karma points, so we want to be able to track the source of the karma gain / loss. Specifications ============== Now, we added a reference field `origin_ref` which store the record responsible for the karma gain / loss (e.g. a slide we just completed). In addition to this origin, we also have a new field to store the reason (e.g. "Slide completed") so we know exactly what happened and how the user gains his karma. Before, the `old_value` of the karma tracking has to be set manually, but now it's done automatically based on the value of the previous tracking of the same user. That way, it will simplify other part of the code. Add the karma reason in the website modules. Adapt those modules due to the changes in gamification. Task-2234179 closes odoo/odoo#76430 Related: odoo/enterprise#23702 Related: odoo/upgrade#3299 Signed-off-by: Warnon Aurélien (awa) <awa@odoo.com> Co-authored-by: std-odoo <std@odoo.com>
136 lines
5.4 KiB
Python
136 lines
5.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
from odoo import _, api, fields, models
|
|
from odoo.tools import date_utils
|
|
|
|
|
|
class KarmaTracking(models.Model):
|
|
_name = 'gamification.karma.tracking'
|
|
_description = 'Track Karma Changes'
|
|
_rec_name = 'user_id'
|
|
_order = 'tracking_date desc, id desc'
|
|
|
|
def _get_origin_selection_values(self):
|
|
return [('res.users', _('User'))]
|
|
|
|
user_id = fields.Many2one('res.users', 'User', index=True, required=True, ondelete='cascade')
|
|
old_value = fields.Integer('Old Karma Value', readonly=True)
|
|
new_value = fields.Integer('New Karma Value', required=True)
|
|
gain = fields.Integer('Gain', compute='_compute_gain', readonly=False)
|
|
consolidated = fields.Boolean('Consolidated')
|
|
|
|
tracking_date = fields.Datetime(default=fields.Datetime.now, readonly=True, index=True)
|
|
reason = fields.Text(default=lambda self: _('Add Manually'), string='Description')
|
|
origin_ref = fields.Reference(
|
|
string='Source',
|
|
selection=lambda self: self._get_origin_selection_values(),
|
|
default=lambda self: f'res.users,{self.env.user.id}',
|
|
)
|
|
origin_ref_model_name = fields.Selection(
|
|
string='Source Type', selection=lambda self: self._get_origin_selection_values(),
|
|
compute='_compute_origin_ref_model_name', store=True)
|
|
|
|
@api.depends('old_value', 'new_value')
|
|
def _compute_gain(self):
|
|
for karma in self:
|
|
karma.gain = karma.new_value - (karma.old_value or 0)
|
|
|
|
@api.depends('origin_ref')
|
|
def _compute_origin_ref_model_name(self):
|
|
for karma in self:
|
|
if not karma.origin_ref:
|
|
karma.origin_ref_model_name = False
|
|
continue
|
|
|
|
karma.origin_ref_model_name = karma.origin_ref._name
|
|
|
|
@api.model_create_multi
|
|
def create(self, values_list):
|
|
# fill missing old value with current user karma
|
|
users = self.env['res.users'].browse([
|
|
values['user_id']
|
|
for values in values_list
|
|
if 'old_value' not in values and values.get('user_id')
|
|
])
|
|
karma_per_users = {user.id: user.karma for user in users}
|
|
|
|
for values in values_list:
|
|
if 'old_value' not in values and values.get('user_id'):
|
|
values['old_value'] = karma_per_users[values['user_id']]
|
|
|
|
if 'gain' in values and 'old_value' in values:
|
|
values['new_value'] = values['old_value'] + values['gain']
|
|
del values['gain']
|
|
|
|
return super().create(values_list)
|
|
|
|
@api.model
|
|
def _consolidate_cron(self):
|
|
"""Consolidate the trackings 2 months ago. Used by a cron to cleanup tracking records."""
|
|
from_date = date_utils.start_of(fields.Datetime.today(), 'month') - relativedelta(months=2)
|
|
return self._process_consolidate(from_date)
|
|
|
|
def _process_consolidate(self, from_date, end_date=None):
|
|
"""Consolidate the karma trackings.
|
|
|
|
The consolidation keeps, for each user, the oldest "old_value" and the most recent
|
|
"new_value", creates a new karma tracking with those values and removes all karma
|
|
trackings between those dates. The origin / reason is changed on the consolidated
|
|
records, so this information is lost in the process.
|
|
"""
|
|
self.env['gamification.karma.tracking'].flush_model()
|
|
|
|
if not end_date:
|
|
end_date = date_utils.end_of(date_utils.end_of(from_date, 'month'), 'day')
|
|
|
|
select_query = """
|
|
WITH old_tracking AS (
|
|
SELECT DISTINCT ON (user_id) user_id, old_value, tracking_date
|
|
FROM gamification_karma_tracking
|
|
WHERE tracking_date BETWEEN %(from_date)s
|
|
AND %(end_date)s
|
|
AND consolidated IS NOT TRUE
|
|
ORDER BY user_id, tracking_date ASC, id ASC
|
|
)
|
|
INSERT INTO gamification_karma_tracking (
|
|
user_id,
|
|
old_value,
|
|
new_value,
|
|
tracking_date,
|
|
origin_ref,
|
|
consolidated,
|
|
reason)
|
|
SELECT DISTINCT ON (nt.user_id)
|
|
nt.user_id,
|
|
ot.old_value AS old_value,
|
|
nt.new_value AS new_value,
|
|
ot.tracking_date AS from_tracking_date,
|
|
%(origin_ref)s AS origin_ref,
|
|
TRUE,
|
|
%(reason)s
|
|
FROM gamification_karma_tracking AS nt
|
|
JOIN old_tracking AS ot
|
|
ON ot.user_id = nt.user_id
|
|
WHERE nt.tracking_date BETWEEN %(from_date)s
|
|
AND %(end_date)s
|
|
AND nt.consolidated IS NOT TRUE
|
|
ORDER BY nt.user_id, nt.tracking_date DESC, id DESC
|
|
"""
|
|
|
|
self.env.cr.execute(select_query, {
|
|
'from_date': from_date,
|
|
'end_date': end_date,
|
|
'origin_ref': f'res.users,{self.env.user.id}',
|
|
'reason': _('Consolidation from %s to %s', from_date.date(), end_date.date()),
|
|
})
|
|
|
|
self.search([
|
|
('tracking_date', '>=', from_date),
|
|
('tracking_date', '<=', end_date),
|
|
('consolidated', '!=', True)]
|
|
).with_context(skip_karma_computation=True).unlink()
|
|
return True
|