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 @@
+
@@ -10,5 +11,17 @@
-1
+
+
+ Gamification: Karma tracking consolidation
+
+ code
+ model._consolidate_last_month()
+
+ 1
+ months
+ -1
+
+
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 @@
-
-
- 20
-
-
- 10
-
-
@@ -44,5 +36,4 @@
-
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 @@
+
+
+
+
+
+
+ 0
+ 1000
+
+
+
+
+ 1000
+ 1500
+
+
+
+
+ 1500
+ 2000
+
+
+
+
+ 2000
+ 2050
+
+
+
+ 2500
+
+
+
+
+
+ 0
+ 5
+
+
+
+
+ 5
+ 10
+
+
+
+
+ 10
+ 20
+
+
+
+
+ 20
+ 25
+
+
+
+ 30
+
+
+
+
+
+ 0
+ 2000
+
+
+
+
+ 2000
+ 2250
+
+
+
+
+ 2250
+ 2500
+
+
+
+
+
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 @@
+
+
+
+ gamification.karma.tracking.view.search
+ gamification.karma.tracking
+
+
+
+
+
+
+
+
+
+
+
+
+
+ gamification.karma.tracking.view.tree
+ gamification.karma.tracking
+
+
+
+
+
+
+
+
+
+
+
+
+ gamification.karma.tracking.view.form
+ gamification.karma.tracking
+
+
+
+
+
+
+ Trackings
+ gamification.karma.tracking
+ tree,form
+
+
+
+
+
diff --git a/addons/website_profile/controllers/main.py b/addons/website_profile/controllers/main.py
index eef5d1d4dc8..703fc250f96 100644
--- a/addons/website_profile/controllers/main.py
+++ b/addons/website_profile/controllers/main.py
@@ -8,7 +8,10 @@ import werkzeug.urls
import werkzeug.wrappers
import math
-from odoo import http, modules, tools
+from dateutil.relativedelta import relativedelta
+from operator import itemgetter
+
+from odoo import fields, http, modules, tools
from odoo.http import request
from odoo.osv import expression
@@ -205,12 +208,13 @@ class WebsiteProfile(http.Controller):
@http.route(['/profile/users',
'/profile/users/page/'], type='http', auth="public", website=True, sitemap=True)
- def view_all_users_page(self, page=1, **searches):
+ def view_all_users_page(self, page=1, **kwargs):
User = request.env['res.users']
dom = [('karma', '>', 1), ('website_published', '=', True)]
# Searches
- search_term = searches.get('search')
+ search_term = kwargs.get('search')
+ group_by = kwargs.get('group_by', False)
if search_term:
dom = expression.AND([['|', ('name', 'ilike', search_term), ('company_id.name', 'ilike', search_term)], dom])
@@ -225,12 +229,24 @@ class WebsiteProfile(http.Controller):
user_values = self._prepare_all_users_values(users)
# Get karma position for users (only website_published)
- position_domain = [('karma', '>', 1), ('website_published', '=', True)]
- position_map = self._get_users_karma_position(position_domain, users.ids)
- for user in user_values:
- user['position'] = position_map.get(user['id'], 0)
+ if group_by:
+ position_domain = [('karma', '>', 1), ('website_published', '=', True)]
+ position_map = self._get_user_tracking_karma_gain_position(position_domain, users.ids, group_by)
+ max_position = max([user_data['karma_position'] for user_data in position_map.values()], default=1)
+ for user in user_values:
+ user_data = position_map.get(user['id'], dict())
+ user['position'] = user_data.get('karma_position', max_position + 1)
+ user['karma_gain'] = user_data.get('karma_gain_total', 0)
+ user_values.sort(key=itemgetter('position'))
+ else:
+ position_domain = [('karma', '>', 1), ('website_published', '=', True)]
+ position_map = self._get_users_karma_position(position_domain, users.ids)
+ for user in user_values:
+ user['position'] = position_map.get(user['id'], 0)
+ user['karma_gain'] = False
values = {
+ 'group_by': group_by or 'all',
'top3_users': user_values[:3] if not search_term and page == 1 else None,
'users': user_values[3:] if not search_term and page == 1 else user_values,
'pager': pager
@@ -244,8 +260,7 @@ class WebsiteProfile(http.Controller):
if not user_ids:
return {}
- Users = request.env['res.users']
- where_query = Users._where_calc(domain)
+ where_query = request.env['res.users']._where_calc(domain)
from_clause, where_clause, where_clause_params = where_query.get_sql()
# we search on every user in the DB to get the real positioning (not the one inside the subset)
@@ -264,6 +279,19 @@ class WebsiteProfile(http.Controller):
return {item['id']: item['karma_position'] for item in request.env.cr.dictfetchall()}
+ def _get_user_tracking_karma_gain_position(self, domain, user_ids, group_by):
+ """ Helper method computing boundaries to give to _get_tracking_karma_gain_position.
+ See that method for more details. """
+ to_date = fields.Date.today()
+ if group_by == 'week':
+ from_date = to_date - relativedelta(weeks=1)
+ elif group_by == 'month':
+ from_date = to_date - relativedelta(months=1)
+ else:
+ from_date = None
+ results = request.env['res.users'].browse(user_ids)._get_tracking_karma_gain_position(domain, from_date=from_date, to_date=to_date)
+ return dict((item['user_id'], dict(item)) for item in results)
+
# User and validation
# --------------------------------------------------
diff --git a/addons/website_profile/views/website_profile.xml b/addons/website_profile/views/website_profile.xml
index 629119b98d0..9a8dacb8e2a 100644
--- a/addons/website_profile/views/website_profile.xml
+++ b/addons/website_profile/views/website_profile.xml
@@ -481,7 +481,15 @@
@@ -519,6 +527,9 @@
Unpublished
+
+ + XP
+