[REF] gamification: performance improvements when running with a large number of users
- gamification.goal do not depends of mail.thread anymore (message posting and fields tracking was slow) - check reward works in batch mode - fix update method that did not reset variable in loop - when the cron is running commit after each goal definition update bzr revid: mat@openerp.com-20140506145623-476s3q3vxoybya77
This commit is contained in:
@@ -240,6 +240,11 @@ class gamification_challenge(osv.Model):
|
||||
|
||||
write_res = super(gamification_challenge, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
if vals.get('report_message_frequency', 'never') != 'never':
|
||||
# _recompute_challenge_users do not set users for challenges with no reports, subscribing them now
|
||||
for challenge in self.browse(cr, uid, ids, context=context):
|
||||
self.message_subscribe(cr, uid, [challenge.id], [user.partner_id.id for user in challenge.user_ids], context=context)
|
||||
|
||||
if vals.get('state') == 'inprogress':
|
||||
self._recompute_challenge_users(cr, uid, ids, context=context)
|
||||
self._generate_goals_from_challenge(cr, uid, ids, context=context)
|
||||
@@ -264,6 +269,9 @@ class gamification_challenge(osv.Model):
|
||||
- Create the missing goals (eg: modified the challenge to add lines)
|
||||
- Update every running challenge
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
# start scheduled challenges
|
||||
planned_challenge_ids = self.search(cr, uid, [
|
||||
('state', '=', 'draft'),
|
||||
@@ -281,6 +289,9 @@ class gamification_challenge(osv.Model):
|
||||
if not ids:
|
||||
ids = self.search(cr, uid, [('state', '=', 'inprogress')], context=context)
|
||||
|
||||
# in cron mode, will do intermediate commits
|
||||
# TODO in trunk: replace by parameter
|
||||
context.update({'commit_gamification': True})
|
||||
return self._update_all(cr, uid, ids, context=context)
|
||||
|
||||
def _update_all(self, cr, uid, ids, context=None):
|
||||
@@ -355,10 +366,12 @@ class gamification_challenge(osv.Model):
|
||||
if write_op:
|
||||
self.write(cr, uid, [challenge.id], {'user_ids': write_op}, context=context)
|
||||
|
||||
if to_remove_ids:
|
||||
self.message_unsubscribe_users(cr, uid, [challenge.id], to_remove_ids, context=None)
|
||||
if to_add_ids:
|
||||
self.message_subscribe_users(cr, uid, [challenge.id], to_add_ids, context=context)
|
||||
# TODO for trunk: use proper parameter
|
||||
if challenge.report_message_frequency != 'never':
|
||||
if to_remove_ids:
|
||||
self.message_unsubscribe_users(cr, uid, [challenge.id], to_remove_ids, context=context)
|
||||
if to_add_ids:
|
||||
self.message_subscribe_users(cr, uid, [challenge.id], to_add_ids, context=context)
|
||||
|
||||
return True
|
||||
|
||||
@@ -393,9 +406,9 @@ class gamification_challenge(osv.Model):
|
||||
:param list(int) ids: the list of challenge concerned"""
|
||||
|
||||
goal_obj = self.pool.get('gamification.goal')
|
||||
to_update = []
|
||||
for challenge in self.browse(cr, uid, ids, context=context):
|
||||
(start_date, end_date) = start_end_date_for_period(challenge.period)
|
||||
to_update = []
|
||||
|
||||
# if no periodicity, use challenge dates
|
||||
if not start_date and challenge.start_date:
|
||||
@@ -698,34 +711,35 @@ class gamification_challenge(osv.Model):
|
||||
rewarded_users = []
|
||||
challenge_ended = end_date == yesterday.strftime(DF) or force
|
||||
if challenge.reward_id and challenge_ended or challenge.reward_realtime:
|
||||
for user in challenge.user_ids:
|
||||
reached_goal_ids = self.pool.get('gamification.goal').search(cr, uid, [
|
||||
('challenge_id', '=', challenge.id),
|
||||
('user_id', '=', user.id),
|
||||
('start_date', '=', start_date),
|
||||
('end_date', '=', end_date),
|
||||
('state', '=', 'reached')
|
||||
], context=context)
|
||||
if len(reached_goal_ids) == len(challenge.line_ids):
|
||||
# not using start_date as intemportal goals have a start date but no end_date
|
||||
reached_goals = self.pool.get('gamification.goal').read_group(cr, uid, [
|
||||
('challenge_id', '=', challenge.id),
|
||||
('end_date', '=', end_date),
|
||||
('state', '=', 'reached')
|
||||
], fields=['user_id'], groupby=['user_id'], context=context)
|
||||
for reach_goals_user in reached_goals:
|
||||
if reach_goals_user['user_id_count'] == len(challenge.line_ids):
|
||||
# the user has succeeded every assigned goal
|
||||
user_id = reach_goals_user['user_id'][0]
|
||||
if challenge.reward_realtime:
|
||||
badges = self.pool['gamification.badge.user'].search(cr, uid, [
|
||||
('challenge_id', '=', challenge.id),
|
||||
('badge_id', '=', challenge.reward_id.id),
|
||||
('user_id', '=', user.id),
|
||||
('user_id', '=', user_id),
|
||||
], count=True, context=context)
|
||||
if badges > 0:
|
||||
# has already recieved the badge for this challenge
|
||||
continue
|
||||
self.reward_user(cr, uid, user.id, challenge.reward_id.id, challenge.id, context=context)
|
||||
rewarded_users.append(user)
|
||||
self.reward_user(cr, uid, user_id, challenge.reward_id.id, challenge.id, context=context)
|
||||
rewarded_users.append(user_id)
|
||||
|
||||
if challenge_ended:
|
||||
# open chatter message
|
||||
message_body = _("The challenge %s is finished." % challenge.name)
|
||||
|
||||
if rewarded_users:
|
||||
message_body += _("<br/>Reward (badge %s) for every succeeding user was sent to %s." % (challenge.reward_id.name, ", ".join([user.name for user in rewarded_users])))
|
||||
user_names = self.pool['res.users'].name_get(cr, uid, rewarded_users, context=context)
|
||||
message_body += _("<br/>Reward (badge %s) for every succeeding user was sent to %s." % (challenge.reward_id.name, ", ".join([name for (user_id, name) in user_names])))
|
||||
else:
|
||||
message_body += _("<br/>Nobody has succeeded to reach every goal, no badge is rewared for this challenge.")
|
||||
|
||||
|
||||
@@ -138,7 +138,6 @@ class gamification_goal(osv.Model):
|
||||
|
||||
_name = 'gamification.goal'
|
||||
_description = 'Gamification goal instance'
|
||||
_inherit = 'mail.thread'
|
||||
|
||||
def _get_completion(self, cr, uid, ids, field_name, arg, context=None):
|
||||
"""Return the percentage of completeness of the goal, between 0 and 100"""
|
||||
@@ -226,8 +225,7 @@ class gamification_goal(osv.Model):
|
||||
temp_obj = self.pool.get('email.template')
|
||||
template_id = self.pool['ir.model.data'].get_object(cr, uid, 'gamification', 'email_template_goal_reminder', context)
|
||||
body_html = temp_obj.render_template(cr, uid, template_id.body_html, 'gamification.goal', goal.id, context=context)
|
||||
|
||||
self.message_post(cr, uid, goal.id, body=body_html, partner_ids=[goal.user_id.partner_id.id], context=context, subtype='mail.mt_comment')
|
||||
self.pool['mail.thread'].message_post(cr, uid, 0, body=body_html, partner_ids=[goal.user_id.partner_id.id], context=context, subtype='mail.mt_comment')
|
||||
return {'to_update': True}
|
||||
return {}
|
||||
|
||||
@@ -241,9 +239,9 @@ class gamification_goal(osv.Model):
|
||||
the target value being reached, the goal is set as failed."""
|
||||
if context is None:
|
||||
context = {}
|
||||
commit = context.get('commit_gamification', False)
|
||||
|
||||
goals_by_definition = {}
|
||||
goals_to_write = {}
|
||||
all_goals = {}
|
||||
for goal in self.browse(cr, uid, ids, context=context):
|
||||
if goal.state in ('draft', 'canceled'):
|
||||
@@ -251,10 +249,10 @@ class gamification_goal(osv.Model):
|
||||
continue
|
||||
|
||||
goals_by_definition.setdefault(goal.definition_id, []).append(goal)
|
||||
goals_to_write[goal.id] = {}
|
||||
all_goals[goal.id] = goal
|
||||
|
||||
for definition, goals in goals_by_definition.items():
|
||||
goals_to_write = dict((goal.id, {}) for goal in goals)
|
||||
if definition.computation_mode == 'manually':
|
||||
for goal in goals:
|
||||
goals_to_write[goal.id].update(self._check_remind_delay(cr, uid, goal, context))
|
||||
@@ -345,22 +343,24 @@ class gamification_goal(osv.Model):
|
||||
if new_value != goal.current:
|
||||
goals_to_write[goal.id]['current'] = new_value
|
||||
|
||||
for goal_id, value in goals_to_write.items():
|
||||
if not value:
|
||||
continue
|
||||
goal = all_goals[goal_id]
|
||||
for goal_id, value in goals_to_write.items():
|
||||
if not value:
|
||||
continue
|
||||
goal = all_goals[goal_id]
|
||||
|
||||
# check goal target reached
|
||||
if (goal.definition_condition == 'higher' and value.get('current', goal.current) >= goal.target_goal) \
|
||||
or (goal.definition_condition == 'lower' and value.get('current', goal.current) <= goal.target_goal):
|
||||
value['state'] = 'reached'
|
||||
# check goal target reached
|
||||
if (goal.definition_condition == 'higher' and value.get('current', goal.current) >= goal.target_goal) \
|
||||
or (goal.definition_condition == 'lower' and value.get('current', goal.current) <= goal.target_goal):
|
||||
value['state'] = 'reached'
|
||||
|
||||
# check goal failure
|
||||
elif goal.end_date and fields.date.today() > goal.end_date:
|
||||
value['state'] = 'failed'
|
||||
value['closed'] = True
|
||||
if value:
|
||||
self.write(cr, uid, [goal.id], value, context=context)
|
||||
# check goal failure
|
||||
elif goal.end_date and fields.date.today() > goal.end_date:
|
||||
value['state'] = 'failed'
|
||||
value['closed'] = True
|
||||
if value:
|
||||
self.write(cr, uid, [goal.id], value, context=context)
|
||||
if commit:
|
||||
cr.commit()
|
||||
return True
|
||||
|
||||
def action_start(self, cr, uid, ids, context=None):
|
||||
|
||||
@@ -86,10 +86,6 @@
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
Reference in New Issue
Block a user