140 lines
5.6 KiB
Python
140 lines
5.6 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()),
|
||
|
})
|
||
|
|
||
|
trackings = self.search([
|
||
|
('tracking_date', '>=', from_date),
|
||
|
('tracking_date', '<=', end_date),
|
||
|
('consolidated', '!=', True)]
|
||
|
)
|
||
|
# HACK: the unlink() AND the flush_all() must have that key in their context!
|
||
|
trackings = trackings.with_context(skip_karma_computation=True)
|
||
|
trackings.unlink()
|
||
|
trackings.env.flush_all()
|
||
|
return True
|