summaryrefslogtreecommitdiff
path: root/addons/gamification
diff options
context:
space:
mode:
Diffstat (limited to 'addons/gamification')
-rw-r--r--addons/gamification/__manifest__.py4
-rw-r--r--addons/gamification/data/cron.xml13
-rw-r--r--addons/gamification/data/gamification_karma_rank_demo.xml9
-rw-r--r--addons/gamification/data/gamification_karma_tracking_demo.xml83
-rw-r--r--addons/gamification/models/__init__.py1
-rw-r--r--addons/gamification/models/gamification_karma_tracking.py69
-rw-r--r--addons/gamification/models/res_users.py88
-rw-r--r--addons/gamification/security/ir.model.access.csv4
-rw-r--r--addons/gamification/tests/__init__.py1
-rw-r--r--addons/gamification/tests/test_karma_tracking.py195
-rw-r--r--addons/gamification/views/gamification_karma_tracking_views.xml63
11 files changed, 512 insertions, 18 deletions
diff --git a/addons/gamification/__manifest__.py b/addons/gamification/__manifest__.py
index 0270a25a56b..314dcf070a2 100644
--- a/addons/gamification/__manifest__.py
+++ b/addons/gamification/__manifest__.py
@@ -33,9 +33,11 @@ Both goals and badges are flexibles and can be adapted to a large range of modul
'data/gamification_karma_rank_data.xml',
'views/gamification.xml',
'views/gamification_karma_rank_views.xml',
+ 'views/gamification_karma_tracking_views.xml',
'views/mail_templates.xml'
],
'demo': [
- 'data/gamification_karma_rank_demo.xml'
+ 'data/gamification_karma_rank_demo.xml',
+ 'data/gamification_karma_tracking_demo.xml',
],
}
diff --git a/addons/gamification/data/cron.xml b/addons/gamification/data/cron.xml
index 0ed59d39e11..4e59205647b 100644
--- a/addons/gamification/data/cron.xml
+++ b/addons/gamification/data/cron.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record forcecreate="True" id="ir_cron_check_challenge" model="ir.cron">
@@ -10,5 +11,17 @@
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
</record>
+
+ <record id="ir_cron_consolidate_last_month" model="ir.cron">
+ <field name="name">Gamification: Karma tracking consolidation</field>
+ <field name="model_id" ref="model_gamification_karma_tracking"/>
+ <field name="state">code</field>
+ <field name="code">model._consolidate_last_month()</field>
+ <field name="active" eval="True"/>
+ <field name="interval_number">1</field>
+ <field name="interval_type">months</field>
+ <field name="numbercall">-1</field>
+ <field name="nextcall" eval="(DateTime.now() + relativedelta(day=1, months=1)).strftime('%Y-%m-%d 04:00:00')" />
+ </record>
</data>
</odoo>
diff --git a/addons/gamification/data/gamification_karma_rank_demo.xml b/addons/gamification/data/gamification_karma_rank_demo.xml
index 839e8750047..848e7fd68d0 100644
--- a/addons/gamification/data/gamification_karma_rank_demo.xml
+++ b/addons/gamification/data/gamification_karma_rank_demo.xml
@@ -1,13 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo><data noupdate="1">
- <!-- Set demo karma for test tour as demo user-->
- <record id="base.user_demo" model="res.users">
- <field name="karma">20</field>
- </record>
- <record id="base.demo_user0" model="res.users">
- <field name="karma">10</field>
- </record>
-
<!--Ranks-->
<record id="rank_student" model="gamification.karma.rank">
<field name="description_motivational" type="html">
@@ -44,5 +36,4 @@
</div>
</field>
</record>
-
</data></odoo>
diff --git a/addons/gamification/data/gamification_karma_tracking_demo.xml b/addons/gamification/data/gamification_karma_tracking_demo.xml
new file mode 100644
index 00000000000..01f4d8ac929
--- /dev/null
+++ b/addons/gamification/data/gamification_karma_tracking_demo.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo><data noupdate="1">
+
+ <!--base.user_demo-->
+ <record id="karma_tracking_user_demo_1st_day_last_month" model="gamification.karma.tracking">
+ <field name="user_id" ref="base.user_demo"/>
+ <field name="old_value">0</field>
+ <field name="new_value">1000</field>
+ <field name="tracking_date" eval="(DateTime.now() - relativedelta(day=1, months=1)).strftime('%Y-%m-%d')"/>
+ </record>
+ <record id="karma_tracking_user_demo_2nd_day_last_month" model="gamification.karma.tracking">
+ <field name="user_id" ref="base.user_demo"/>
+ <field name="old_value">1000</field>
+ <field name="new_value">1500</field>
+ <field name="tracking_date" eval="(DateTime.now() - relativedelta(day=2, months=1)).strftime('%Y-%m-%d')"/>
+ </record>
+ <record id="karma_tracking_user_demo_5th_day_last_month" model="gamification.karma.tracking">
+ <field name="user_id" ref="base.user_demo"/>
+ <field name="old_value">1500</field>
+ <field name="new_value">2000</field>
+ <field name="tracking_date" eval="(DateTime.now() - relativedelta(day=5, months=1)).strftime('%Y-%m-%d')"/>
+ </record>
+ <record id="karma_tracking_user_demo_20th_day_last_month" model="gamification.karma.tracking">
+ <field name="user_id" ref="base.user_demo"/>
+ <field name="old_value">2000</field>
+ <field name="new_value">2050</field>
+ <field name="tracking_date" eval="(DateTime.now() - relativedelta(day=20, months=1)).strftime('%Y-%m-%d')"/>
+ </record>
+ <record id="base.user_demo" model="res.users">
+ <field name="karma">2500</field>
+ </record>
+
+ <!--base.demo_user0 -->
+ <record id="karma_tracking_user_portal_2nd_day_last_month" model="gamification.karma.tracking">
+ <field name="user_id" ref="base.demo_user0"/>
+ <field name="old_value">0</field>
+ <field name="new_value">5</field>
+ <field name="tracking_date" eval="(DateTime.now() - relativedelta(day=2, months=1)).strftime('%Y-%m-%d')"/>
+ </record>
+ <record id="karma_tracking_user_portal_3rd_day_last_month" model="gamification.karma.tracking">
+ <field name="user_id" ref="base.demo_user0"/>
+ <field name="old_value">5</field>
+ <field name="new_value">10</field>
+ <field name="tracking_date" eval="(DateTime.now() - relativedelta(day=3, months=1)).strftime('%Y-%m-%d')"/>
+ </record>
+ <record id="karma_tracking_user_portal_10th_day_last_month" model="gamification.karma.tracking">
+ <field name="user_id" ref="base.demo_user0"/>
+ <field name="old_value">10</field>
+ <field name="new_value">20</field>
+ <field name="tracking_date" eval="(DateTime.now() - relativedelta(day=10, months=1)).strftime('%Y-%m-%d')"/>
+ </record>
+ <record id="karma_tracking_user_portal_today_0" model="gamification.karma.tracking">
+ <field name="user_id" ref="base.demo_user0"/>
+ <field name="old_value">20</field>
+ <field name="new_value">25</field>
+ <field name="tracking_date" eval="(DateTime.now()).strftime('%Y-%m-%d')"/>
+ </record>
+ <record id="base.demo_user0" model="res.users">
+ <field name="karma">30</field>
+ </record>
+
+ <!--base.user_admin (already have a tracking to 2500)-->
+ <record id="karma_tracking_user_admin_1st_day_last_month" model="gamification.karma.tracking">
+ <field name="user_id" ref="base.user_admin"/>
+ <field name="old_value">0</field>
+ <field name="new_value">2000</field>
+ <field name="tracking_date" eval="(DateTime.now() - relativedelta(day=1, months=1)).strftime('%Y-%m-%d')"/>
+ </record>
+ <record id="karma_tracking_user_admin_5th_day_last_month" model="gamification.karma.tracking">
+ <field name="user_id" ref="base.user_admin"/>
+ <field name="old_value">2000</field>
+ <field name="new_value">2250</field>
+ <field name="tracking_date" eval="(DateTime.now() - relativedelta(day=5, months=1)).strftime('%Y-%m-%d')"/>
+ </record>
+ <record id="karma_tracking_user_admin_today" model="gamification.karma.tracking">
+ <field name="user_id" ref="base.user_admin"/>
+ <field name="old_value">2250</field>
+ <field name="new_value">2500</field>
+ <field name="tracking_date" eval="(DateTime.now()).strftime('%Y-%m-%d')"/>
+ </record>
+
+</data>
+</odoo>
diff --git a/addons/gamification/models/__init__.py b/addons/gamification/models/__init__.py
index 926a5af2a07..659fcff70a1 100644
--- a/addons/gamification/models/__init__.py
+++ b/addons/gamification/models/__init__.py
@@ -5,4 +5,5 @@ from . import goal
from . import challenge
from . import badge
from . import gamification_karma_rank
+from . import gamification_karma_tracking
from . import res_users
diff --git a/addons/gamification/models/gamification_karma_tracking.py b/addons/gamification/models/gamification_karma_tracking.py
new file mode 100644
index 00000000000..f7b184ad24d
--- /dev/null
+++ b/addons/gamification/models/gamification_karma_tracking.py
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import calendar
+
+from dateutil.relativedelta import relativedelta
+
+from odoo import api, fields, models
+
+
+class KarmaTracking(models.Model):
+ _name = 'gamification.karma.tracking'
+ _description = 'Track Karma Changes'
+ _rec_name = 'user_id'
+ _order = 'tracking_date DESC'
+
+ user_id = fields.Many2one('res.users', 'User', index=True, readonly=True, required=True, ondelete='cascade')
+ old_value = fields.Integer('Old Karma Value', required=True, readonly=True)
+ new_value = fields.Integer('New Karma Value', required=True, readonly=True)
+ consolidated = fields.Boolean('Consolidated')
+ tracking_date = fields.Date(default=fields.Date.context_today)
+
+ @api.model
+ def _consolidate_last_month(self):
+ """ Consolidate last month. Used by a cron to cleanup tracking records. """
+ previous_month_start = fields.Date.today() + relativedelta(months=-1, day=1)
+ return self._process_consolidate(previous_month_start)
+
+ def _process_consolidate(self, from_date):
+ """ Consolidate trackings into a single record for a given month, starting
+ at a from_date (included). End date is set to last day of current month
+ using a smart calendar.monthrange construction. """
+ end_date = from_date + relativedelta(day=calendar.monthrange(from_date.year, from_date.month)[1])
+ select_query = """
+SELECT user_id,
+(
+ SELECT old_value from gamification_karma_tracking old_tracking
+ WHERE old_tracking.user_id = gamification_karma_tracking.user_id
+ AND tracking_date::timestamp BETWEEN %(from_date)s AND %(to_date)s
+ AND consolidated IS NOT TRUE
+ ORDER BY tracking_date ASC LIMIT 1
+), (
+ SELECT new_value from gamification_karma_tracking new_tracking
+ WHERE new_tracking.user_id = gamification_karma_tracking.user_id
+ AND tracking_date::timestamp BETWEEN %(from_date)s AND %(to_date)s
+ AND consolidated IS NOT TRUE
+ ORDER BY tracking_date DESC LIMIT 1
+)
+FROM gamification_karma_tracking
+WHERE tracking_date::timestamp BETWEEN %(from_date)s AND %(to_date)s
+AND consolidated IS NOT TRUE
+GROUP BY user_id """
+ self.env.cr.execute(select_query, {
+ 'from_date': from_date,
+ 'to_date': end_date,
+ })
+ results = self.env.cr.dictfetchall()
+ if results:
+ for result in results:
+ result['consolidated'] = True
+ result['tracking_date'] = fields.Date.to_string(from_date)
+ self.create(results)
+
+ self.search([
+ ('tracking_date', '>=', from_date),
+ ('tracking_date', '<=', end_date),
+ ('consolidated', '!=', True)]
+ ).unlink()
+ return True
diff --git a/addons/gamification/models/res_users.py b/addons/gamification/models/res_users.py
index 3e8b6d8e1cd..3dc95de74a1 100644
--- a/addons/gamification/models/res_users.py
+++ b/addons/gamification/models/res_users.py
@@ -3,16 +3,12 @@
from odoo import api, fields, models
-import logging
-
-_logger = logging.getLogger(__name__)
-
class Users(models.Model):
_inherit = 'res.users'
-
karma = fields.Integer('Karma', default=0)
+ karma_tracking_ids = fields.One2many('gamification.karma.tracking', 'user_id', string='Karma Changes', groups="base.group_system")
badge_ids = fields.One2many('gamification.badge.user', 'user_id', string='Badges', copy=False)
gold_badge = fields.Integer('Gold badges count', compute="_get_user_badge_level")
silver_badge = fields.Integer('Silver badges count', compute="_get_user_badge_level")
@@ -46,11 +42,28 @@ class Users(models.Model):
@api.model_create_multi
def create(self, values_list):
res = super(Users, self).create(values_list)
+
+ karma_trackings = []
+ for user in res:
+ if user.karma:
+ karma_trackings.append({'user_id': user.id, 'old_value': 0, 'new_value': user.karma})
+ if karma_trackings:
+ self.env['gamification.karma.tracking'].sudo().create(karma_trackings)
+
res._recompute_rank()
return res
def write(self, vals):
+ karma_trackings = []
+ if 'karma' in vals:
+ for user in self:
+ if user.karma != vals['karma']:
+ karma_trackings.append({'user_id': user.id, 'old_value': user.karma, 'new_value': vals['karma']})
+
result = super(Users, self).write(vals)
+
+ if karma_trackings:
+ self.env['gamification.karma.tracking'].sudo().create(karma_trackings)
if 'karma' in vals:
self._recompute_rank()
return result
@@ -60,6 +73,68 @@ class Users(models.Model):
user.karma += karma
return True
+ def _get_tracking_karma_gain_position(self, user_domain, from_date=None, to_date=None):
+ """ Get absolute position in term of gained karma for users. First a ranking
+ of all users is done given a user_domain; then the position of each user
+ belonging to the current record set is extracted.
+
+ Example: in website profile, search users with name containing Norbert. Their
+ positions should not be 1 to 4 (assuming 4 results), but their actual position
+ in the karma gain ranking (with example user_domain being karma > 1,
+ website published True).
+
+ :param user_domain: general domain (i.e. active, karma > 1, website, ...)
+ to compute the absolute position of the current record set
+ :param from_date: compute karma gained after this date (included) or from
+ beginning of time;
+ :param to_date: compute karma gained before this date (included) or until
+ end of time;
+
+ :return list: [{
+ 'user_id': user_id (belonging to current record set),
+ 'karma_gain_total': integer, karma gained in the given timeframe,
+ 'karma_position': integer, ranking position
+ }, {..}] ordered by karma_position desc
+ """
+ if not self:
+ return []
+
+ where_query = self.env['res.users']._where_calc(user_domain)
+ user_from_clause, user_where_clause, where_clause_params = where_query.get_sql()
+
+ params = []
+ if from_date:
+ date_from_condition = 'AND tracking.tracking_date::timestamp >= timestamp %s'
+ params.append(from_date)
+ if to_date:
+ date_to_condition = 'AND tracking.tracking_date::timestamp <= timestamp %s'
+ params.append(to_date)
+ params.append(tuple(self.ids))
+
+ query = """
+SELECT final.user_id, final.karma_gain_total, final.karma_position
+FROM (
+ SELECT intermediate.user_id, intermediate.karma_gain_total, row_number() OVER (ORDER BY intermediate.karma_gain_total DESC) AS karma_position
+ FROM (
+ SELECT "res_users".id as user_id, COALESCE(SUM("tracking".new_value - "tracking".old_value), 0) as karma_gain_total
+ FROM %(user_from_clause)s
+ LEFT JOIN "gamification_karma_tracking" as "tracking"
+ ON "res_users".id = "tracking".user_id AND "res_users"."active" = TRUE
+ WHERE %(user_where_clause)s %(date_from_condition)s %(date_to_condition)s
+ GROUP BY "res_users".id
+ ORDER BY karma_gain_total DESC
+ ) intermediate
+) final
+WHERE final.user_id IN %%s""" % {
+ 'user_from_clause': user_from_clause,
+ 'user_where_clause': user_where_clause or (not from_date and not to_date and 'TRUE') or '',
+ 'date_from_condition': date_from_condition if from_date else '',
+ 'date_to_condition': date_to_condition if to_date else ''
+ }
+
+ self.env.cr.execute(query, tuple(where_clause_params + params))
+ return self.env.cr.dictfetchall()
+
def _rank_changed(self):
"""
Method that can be called on a batch of users with the same new rank
@@ -68,7 +143,7 @@ class Users(models.Model):
if template:
for u in self:
if u.rank_id.karma_min > 0:
- template.send_mail(u.id, force_send=len(self) == 1, notif_layout='mail.mail_notification_light')
+ template.send_mail(u.id, force_send=False, notif_layout='mail.mail_notification_light')
def _recompute_rank(self):
"""
@@ -161,7 +236,6 @@ class Users(models.Model):
'next_rank_id': lower_rank.id,
})
-
def _get_next_rank(self):
""" For fresh users with 0 karma that don't have a rank_id and next_rank_id yet
this method returns the first karma rank (by karma ascending). This acts as a
diff --git a/addons/gamification/security/ir.model.access.csv b/addons/gamification/security/ir.model.access.csv
index 41f36a87a5f..728360ab386 100644
--- a/addons/gamification/security/ir.model.access.csv
+++ b/addons/gamification/security/ir.model.access.csv
@@ -27,4 +27,6 @@ badge_user_portal,"Badge-user Portal",gamification.model_gamification_badge_user
badge_user_public,"Badge-user Public",gamification.model_gamification_badge_user,base.group_public,1,0,0,0
gamification_karma_rank_access_all,gamification.karma.rank.access.all,gamification.model_gamification_karma_rank,,1,0,0,0
-gamification_karma_rank_access_user_manager,gamification.karma.rank.access.user.manager,gamification.model_gamification_karma_rank,base.group_erp_manager,1,1,1,1
+gamification_karma_rank_access_user_manager,gamification.karma.rank.access.user.manager,gamification.model_gamification_karma_rank,base.group_system,1,1,1,1
+gamification_karma_tracking_access_all,gamification.karma.tracking.access.all,gamification.model_gamification_karma_tracking,,0,0,0,0
+gamification_karma_tracking_access_user_manager,gamification.karma.tracking.access.user.manager,gamification.model_gamification_karma_tracking,base.group_system,1,1,1,1
diff --git a/addons/gamification/tests/__init__.py b/addons/gamification/tests/__init__.py
index a6a599bf6c8..963887eb670 100644
--- a/addons/gamification/tests/__init__.py
+++ b/addons/gamification/tests/__init__.py
@@ -3,3 +3,4 @@
from . import test_challenge
from . import test_recompute_rank
+from . import test_karma_tracking
diff --git a/addons/gamification/tests/test_karma_tracking.py b/addons/gamification/tests/test_karma_tracking.py
new file mode 100644
index 00000000000..145b745b436
--- /dev/null
+++ b/addons/gamification/tests/test_karma_tracking.py
@@ -0,0 +1,195 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from datetime import date
+from dateutil.relativedelta import relativedelta
+from unittest.mock import patch
+
+from odoo import exceptions, fields
+from odoo.tests import common
+
+
+class TestKarmaTrackingCommon(common.SavepointCase):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestKarmaTrackingCommon, cls).setUpClass()
+ cls.test_user = cls.env['res.users'].with_context(no_reset_password=True, mail_create_nosubscribe=True).create({
+ 'name': 'Test User',
+ 'login': 'test',
+ 'email': 'test@example.com',
+ 'karma': 0,
+ 'groups_id': [(4, cls.env.ref('base.group_user').id)]
+ })
+ cls.test_user_2 = cls.env['res.users'].with_context(no_reset_password=True, mail_create_nosubscribe=True).create({
+ 'name': 'Test User 2',
+ 'login': 'test2',
+ 'email': 'test2@example.com',
+ 'karma': 0,
+ 'groups_id': [(4, cls.env.ref('base.group_user').id)]
+ })
+ cls.env['gamification.karma.tracking'].search([]).unlink()
+
+ cls.test_date = fields.Date.today() + relativedelta(month=4, day=1)
+
+ @classmethod
+ def _create_trackings(cls, user, karma, steps, date, days_delta=1):
+ old_value = user.karma
+ for step in range(steps):
+ new_value = old_value + karma
+ cls.env['gamification.karma.tracking'].create([{
+ 'user_id': user.id,
+ 'old_value': old_value,
+ 'new_value': new_value,
+ 'consolidated': False,
+ 'tracking_date': fields.Date.to_string(date)
+ }])
+ old_value = new_value
+ date = date + relativedelta(days=days_delta)
+
+ def test_computation_gain(self):
+ self._create_trackings(self.test_user, 20, 2, self.test_date, days_delta=30)
+ self._create_trackings(self.test_user_2, 10, 20, self.test_date, days_delta=2)
+
+ results = (self.test_user | self.test_user_2)._get_tracking_karma_gain_position([])
+ self.assertEqual(results[0]['user_id'], self.test_user_2.id)
+ self.assertEqual(results[0]['karma_gain_total'], 200)
+ self.assertEqual(results[0]['karma_position'], 1)
+ self.assertEqual(results[1]['user_id'], self.test_user.id)
+ self.assertEqual(results[1]['karma_gain_total'], 40)
+ self.assertEqual(results[1]['karma_position'], 2)
+
+ results = (self.test_user | self.test_user_2)._get_tracking_karma_gain_position([], to_date=self.test_date + relativedelta(day=2))
+ self.assertEqual(results[0]['user_id'], self.test_user.id)
+ self.assertEqual(results[0]['karma_gain_total'], 20)
+ self.assertEqual(results[0]['karma_position'], 1)
+ self.assertEqual(results[1]['user_id'], self.test_user_2.id)
+ self.assertEqual(results[1]['karma_gain_total'], 10)
+ self.assertEqual(results[1]['karma_position'], 2)
+
+ results = (self.test_user | self.test_user_2)._get_tracking_karma_gain_position([], from_date=self.test_date + relativedelta(months=1, day=1))
+ self.assertEqual(results[0]['user_id'], self.test_user_2.id)
+ self.assertEqual(results[0]['karma_gain_total'], 50)
+ self.assertEqual(results[0]['karma_position'], 1)
+ self.assertEqual(results[1]['user_id'], self.test_user.id)
+ self.assertEqual(results[1]['karma_gain_total'], 20)
+ self.assertEqual(results[1]['karma_position'], 2)
+
+ results = self.env['res.users']._get_tracking_karma_gain_position([])
+ self.assertEqual(len(results), 0)
+
+ def test_consolidation_cron(self):
+ self.patcher = patch('odoo.addons.gamification.models.gamification_karma_tracking.fields.Date', wraps=fields.Date)
+ self.mock_datetime = self.patcher.start()
+ self.mock_datetime.today.return_value = date(self.test_date.year, self.test_date.month + 1, self.test_date.day)
+
+ self._create_trackings(self.test_user, 20, 2, self.test_date, days_delta=30)
+ self._create_trackings(self.test_user_2, 10, 20, self.test_date, days_delta=2)
+ self.env['gamification.karma.tracking']._consolidate_last_month()
+ consolidated = self.env['gamification.karma.tracking'].search([
+ ('user_id', 'in', (self.test_user | self.test_user_2).ids),
+ ('consolidated', '=', True),
+ ('tracking_date', '=', self.test_date)
+ ])
+ self.assertEqual(len(consolidated), 2)
+ unconsolidated = self.env['gamification.karma.tracking'].search([
+ ('user_id', 'in', (self.test_user | self.test_user_2).ids),
+ ('consolidated', '=', False),
+ ])
+ self.assertEqual(len(unconsolidated), 6) # 5 for test user 2, 1 for test user
+
+ self.patcher.stop()
+
+ def test_consolidation_monthly(self):
+ Tracking = self.env['gamification.karma.tracking']
+ base_test_user_karma = self.test_user.karma
+ base_test_user_2_karma = self.test_user_2.karma
+ self._create_trackings(self.test_user, 20, 2, self.test_date, days_delta=30)
+ self._create_trackings(self.test_user_2, 10, 20, self.test_date, days_delta=2)
+
+ Tracking._process_consolidate(self.test_date)
+ consolidated = Tracking.search([
+ ('user_id', '=', self.test_user_2.id),
+ ('consolidated', '=', True),
+ ('tracking_date', '=', self.test_date)
+ ])
+ self.assertEqual(len(consolidated), 1)
+ self.assertEqual(consolidated.old_value, base_test_user_2_karma) # 15 2-days span, from 1 to 29 included = 15 steps -> 150 karma
+ self.assertEqual(consolidated.new_value, base_test_user_2_karma + 150) # 15 2-days span, from 1 to 29 included = 15 steps -> 150 karma
+
+ remaining = Tracking.search([
+ ('user_id', '=', self.test_user_2.id),
+ ('consolidated', '=', False)
+ ])
+ self.assertEqual(len(remaining), 5) # 15 steps consolidated, remaining 5
+ self.assertEqual(remaining[0].tracking_date, self.test_date + relativedelta(months=1, day=9)) # ordering: last first
+ self.assertEqual(remaining[-1].tracking_date, self.test_date + relativedelta(months=1, day=1))
+
+ Tracking._process_consolidate(self.test_date + relativedelta(months=1))
+ consolidated = Tracking.search([
+ ('user_id', '=', self.test_user_2.id),
+ ('consolidated', '=', True),
+ ])
+ self.assertEqual(len(consolidated), 2)
+ self.assertEqual(consolidated[0].new_value, base_test_user_2_karma + 200) # 5 remaining 2-days span, from 1 to 9 included = 5 steps -> 50 karma
+ self.assertEqual(consolidated[0].old_value, base_test_user_2_karma + 150) # coming from previous iteration
+ self.assertEqual(consolidated[0].tracking_date, self.test_date + relativedelta(months=1)) # tracking set at beginning of month
+ self.assertEqual(consolidated[-1].new_value, base_test_user_2_karma + 150) # previously created one still present
+ self.assertEqual(consolidated[-1].old_value, base_test_user_2_karma) # previously created one still present
+
+ remaining = Tracking.search([
+ ('user_id', '=', self.test_user_2.id),
+ ('consolidated', '=', False)
+ ])
+ self.assertFalse(remaining)
+
+ # current user not-in-details tests
+ current_user_trackings = Tracking.search([
+ ('user_id', '=', self.test_user.id),
+ ])
+ self.assertEqual(len(current_user_trackings), 2)
+ self.assertEqual(current_user_trackings[0].new_value, base_test_user_karma + 40)
+ self.assertEqual(current_user_trackings[-1].old_value, base_test_user_karma)
+
+ def test_user_as_erp_manager(self):
+ self.test_user.write({'groups_id': [
+ (4, self.env.ref('base.group_partner_manager').id),
+ (4, self.env.ref('base.group_erp_manager').id)
+ ]})
+ user = self.env['res.users'].with_user(self.test_user).create({
+ 'name': 'Test Ostérone', 'karma': '32',
+ 'login': 'dummy', 'email': 'dummy@example.com',
+ })
+ with self.assertRaises(exceptions.AccessError):
+ user.read(['karma_tracking_ids'])
+
+ user.write({'karma': 60})
+ user.add_karma(10)
+ self.assertEqual(user.karma, 70)
+ trackings = self.env['gamification.karma.tracking'].sudo().search([('user_id', '=', user.id)])
+ self.assertEqual(len(trackings), 3) # create + write + add_karma
+
+ def test_user_tracking(self):
+ self.test_user.write({'groups_id': [
+ (4, self.env.ref('base.group_partner_manager').id),
+ (4, self.env.ref('base.group_system').id)
+ ]})
+ user = self.env['res.users'].with_user(self.test_user).create({
+ 'name': 'Test Ostérone', 'karma': '32',
+ 'login': 'dummy', 'email': 'dummy@example.com',
+ })
+ self.assertEqual(user.karma, 32)
+ self.assertEqual(len(user.karma_tracking_ids), 1)
+ self.assertEqual(user.karma_tracking_ids.old_value, 0)
+ self.assertEqual(user.karma_tracking_ids.new_value, 32)
+
+ user.write({'karma': 60})
+ user.add_karma(10)
+ self.assertEqual(user.karma, 70)
+ self.assertEqual(len(user.karma_tracking_ids), 3)
+ self.assertEqual(user.karma_tracking_ids[2].old_value, 60)
+ self.assertEqual(user.karma_tracking_ids[2].new_value, 70)
+ self.assertEqual(user.karma_tracking_ids[1].old_value, 32)
+ self.assertEqual(user.karma_tracking_ids[1].new_value, 60)
+ self.assertEqual(user.karma_tracking_ids[0].old_value, 0)
+ self.assertEqual(user.karma_tracking_ids[0].new_value, 32)
diff --git a/addons/gamification/views/gamification_karma_tracking_views.xml b/addons/gamification/views/gamification_karma_tracking_views.xml
new file mode 100644
index 00000000000..998d0ff91ec
--- /dev/null
+++ b/addons/gamification/views/gamification_karma_tracking_views.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo><data>
+ <record id="gamification_karma_tracking_view_search" model="ir.ui.view">
+ <field name="name">gamification.karma.tracking.view.search</field>
+ <field name="model">gamification.karma.tracking</field>
+ <field name="arch" type="xml">
+ <search string="Search Trackings">
+ <field name="user_id"/>
+ <field name="tracking_date"/>
+ <filter string="Consolidated" name="filter_consolidated"
+ domain="[('consolidated', '=', True)]"/>
+ <group string="Group By" expand="1">
+ <filter string="User" name="group_by_user_id"
+ context="{'group_by': 'user_id'}"/>
+ </group>
+ </search>
+ </field>
+ </record>
+
+ <record id="gamification_karma_tracking_view_tree" model="ir.ui.view">
+ <field name="name">gamification.karma.tracking.view.tree</field>
+ <field name="model">gamification.karma.tracking</field>
+ <field name="arch" type="xml">
+ <tree string="Trackings">
+ <field name="user_id"/>
+ <field name="tracking_date"/>
+ <field name="old_value"/>
+ <field name="new_value"/>
+ <field name="consolidated"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="gamification_karma_tracking_view_form" model="ir.ui.view">
+ <field name="name">gamification.karma.tracking.view.form</field>
+ <field name="model">gamification.karma.tracking</field>
+ <field name="arch" type="xml">
+ <form string="Tracking">
+ <sheet>
+ <group>
+ <field name="user_id"/>
+ <field name="tracking_date"/>
+ <field name="old_value"/>
+ <field name="new_value"/>
+ <field name="consolidated"/>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="gamification_karma_tracking_action" model="ir.actions.act_window">
+ <field name="name">Trackings</field>
+ <field name="res_model">gamification.karma.tracking</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem id="gamification_karma_tracking_menu"
+ parent="gamification_menu"
+ action="gamification_karma_tracking_action"
+ sequence="50"/>
+ </data>
+</odoo>