1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
# -*- 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 %(from_date)s to %(end_date)s', from_date=from_date.date(), end_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
|