File: gamification_karma_tracking.py

package info (click to toggle)
odoo 18.0.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 878,716 kB
  • sloc: javascript: 927,937; python: 685,670; xml: 388,524; sh: 1,033; sql: 415; makefile: 26
file content (139 lines) | stat: -rw-r--r-- 5,760 bytes parent folder | download
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