[FIX] gamification send report at right frequency

bzr revid: mat@openerp.com-20130304112712-5qt8x9mikoqyg59o
This commit is contained in:
Martin Trigaux 2013-03-04 12:27:12 +01:00
parent 12c30843eb
commit e7ba23a4f7
3 changed files with 142 additions and 87 deletions

View File

@ -282,6 +282,6 @@ class gamification_goal(osv.Model):
if goal.planline_id and goal.planline_id.plan_id.report_message_frequency == 'onchange':
plan_obj = self.pool.get('gamification.goal.plan')
plan_obj.report_progress(cr, uid, [goal.planline_id.plan_id.id], users=[goal.user_id], context=context)
plan_obj.report_progress(cr, uid, goal.planline_id.plan_id, users=[goal.user_id], context=context)
return super(gamification_goal, self).write(cr, uid, ids, vals, context=context)

View File

@ -69,6 +69,26 @@ class gamification_goal_plan(osv.Model):
_description = 'Gamification goal plan'
_inherit = 'mail.thread'
def _get_next_report_date(self, cr, uid, ids, field_name, arg, context=None):
"""Return the next report date based on the last report date and report
period. Return a string in isoformat."""
res = {}
for plan in self.browse(cr, uid, ids, context):
last = datetime.strptime(plan.last_report_date,'%Y-%m-%d').date()
if plan.report_message_frequency == 'daily':
next = last + timedelta(days=1)
elif plan.report_message_frequency == 'weekly':
next = last + timedelta(days=7)
elif plan.report_message_frequency == 'monthly':
month_range = calendar.monthrange(last.year, last.month)
next = last.replace(day=month_range[1]) + timedelta(days=1)
elif plan.report_message_frequency == 'yearly':
next = last.replace(year=last.year + 1)
else: # frequency == 'once':
next = False
res[plan.id] = next.isoformat()
return res
_columns = {
'name' : fields.char('Plan Name', required=True, translate=True),
'user_ids' : fields.many2many('res.users',
@ -121,7 +141,11 @@ class gamification_goal_plan(osv.Model):
help='Group that will receive a copy of the report in addition to the user'),
'report_header' : fields.text('Report Header'),
'remind_update_delay' : fields.integer('Remind delay',
help="The number of days after which the user assigned to a manual goal will be reminded. Never reminded if no value or zero is specified.")
help="The number of days after which the user assigned to a manual goal will be reminded. Never reminded if no value or zero is specified."),
'last_report_date': fields.date('Last Report Date'),
'next_report_date': fields.function(_get_next_report_date,
type='date',
string='Next Report Date'),
}
_defaults = {
@ -129,6 +153,7 @@ class gamification_goal_plan(osv.Model):
'state': 'draft',
'visibility_mode' : 'progressbar',
'report_message_frequency' : 'onchange',
'last_report_date' : fields.date.today
}
def _check_nonzero_planline(self, cr, uid, ids, context=None):
@ -167,25 +192,44 @@ class gamification_goal_plan(osv.Model):
Create the goals for planlines not linked to goals (eg: modified the
plan to add planlines)
:param list(int) ids: the ids of the plans to update, if False will
update only goals in progress."""
update only plans in progress."""
if not context: context = {}
if not ids:
ids = self.search(cr, uid, [('state', '=', 'inprogress')])
self.generate_goals_from_plan(cr, uid, ids, context=context)
# update goals
goal_obj = self.pool.get('gamification.goal')
# we use yesterday to update the goals that just ended
yesterday = date.today() - timedelta(days=1)
goal_ids = goal_obj.search(cr, uid, [
'&',
('state', 'in', ('inprogress','inprogress_update', 'reached')),
'|',
('end_date', '>=', fields.date.today()),
('end_date', '>=', yesterday.isoformat()),
('end_date', '=', False)
], context=context)
goal_obj.update(cr, uid, goal_ids, context=context)
self.report_progress(cr, uid, ids, context=context)
for plan in self.browse(cr, uid, ids, context=context):
# goals closed but still opened at the last report date
closed_goals_to_report = []
for planline in plan.planline_ids:
closed_goals_to_report.extend( goal_obj.search(cr, uid, [
('planline_id','=',planline.id),
('start_date', '>=', plan.last_report_date),
('end_date', '<=', plan.last_report_date)
]) )
if len(closed_goals_to_report) > 0:
# some goals need a final report
self.report_progress(cr, uid, plan, subset_goal_ids=closed_goals_to_report, context=context)
self.write(cr, uid, plan.id, {'last_report_date':fields.date.today}, context=context)
if fields.date.today() == plan.next_report_date:
self.report_progress(cr, uid, plan, context=context)
self.write(cr, uid, plan.id, {'last_report_date':fields.date.today}, context=context)
def action_start(self, cr, uid, ids, context=None):
"""Start a draft goal plan
@ -199,7 +243,7 @@ class gamification_goal_plan(osv.Model):
Create goals that haven't been created yet (eg: if added users of planlines)
Recompute the current value for each goal related"""
return self._update_all(cr, uid, ids, context=context)
return self._update_all(cr, uid, ids=ids, context=context)
def action_close(self, cr, uid, ids, context=None):
@ -254,6 +298,12 @@ class gamification_goal_plan(osv.Model):
res['domain'] = [('id','in', related_goal_ids)]
return res
def action_report_progress(self, cr, uid, ids, context=None):
"""Manual report of a goal, does not influence automatic report frequency"""
for plan in self.browse(cr, uid, ids, context):
self.report_progress(cr, uid, plan, context=context)
return True
def generate_goals_from_plan(self, cr, uid, ids, context=None):
"""Generate the list of goals linked to a plan.
@ -324,55 +374,112 @@ class gamification_goal_plan(osv.Model):
return True
def report_progress(self, cr, uid, ids, context=None, users=False):
def report_progress(self, cr, uid, plan, context=None, users=False, subset_goal_ids=False):
"""Post report about the progress of the goals
:param list(int) ids: the list of plan ids that need to be reported
:param plan: the plan object that need to be reported
:param list(res.users) users: the list of users that are concerned by
the report. If False, will send the report to every user concerned
(goal users and group that recieves a copy). Only used for plan with
a visibility mode set to 'personal'."""
a visibility mode set to 'personal'.
:param list(int) goal_ids: the list of goal ids linked to the plan for
the report. If not specified, use the goals for the current plan
period. This parameter can be used to produce report for previous plan
periods."""
context = context or {}
goal_obj = self.pool.get('gamification.goal')
template_env = TemplateHelper()
for plan in self.browse(cr, uid, ids, context=context):
(start_date, end_date) = start_end_date_for_period(plan.period)
if plan.visibility_mode == 'board':
# generate a shared report
planlines_boards = []
if plan.visibility_mode == 'board':
# generate a shared report
planlines_boards = []
for planline in plan.planline_ids:
domain = [
('planline_id', '=', planline.id),
('state', 'in', ('inprogress', 'inprogress_update',
'reached', 'failed')),
]
if subset_goal_ids:
goal_ids = goal_obj.search(cr, uid, domain, context=context)
common_goal_ids = [goal.id for goal in goal_ids if goal in subset_goal_ids]
else:
# if no subset goals, use the dates for restriction
if start_date:
domain.append(('start_date', '=', start_date.isoformat()))
if end_date:
domain.append(('end_date', '=', end_date.isoformat()))
common_goal_ids = goal_obj.search(cr, uid, domain, context=context)
board_goals = []
for goal in goal_obj.browse(cr, uid, common_goal_ids, context=context):
board_goals.append({
'user': goal.user_id,
'current':goal.current,
'target_goal':goal.target_goal,
'completeness':goal.completeness,
})
# most complete first, current if same percentage (eg: if several 100%)
sorted_board = enumerate(sorted(board_goals, key=lambda k: (k['completeness'], k['current']), reverse=True))
planlines_boards.append({'goal_type':planline.type_id.name, 'board_goals':sorted_board})
body_html = template_env.get_template('group_progress.mako').render({'object':plan, 'planlines_boards':planlines_boards})
self.message_post(cr, uid, plan.id,
body=body_html,
partner_ids=[(6, 0, [user.partner_id.id for user in plan.user_ids])],
context=context,
subtype='mail.mt_comment')
if plan.report_message_group_id:
self.pool.get('mail.group').message_post(cr, uid, plan.report_message_group_id.id,
body=body_html,
context=context,
subtype='mail.mt_comment')
else:
# generate individual reports
for user in users or plan.user_ids:
related_goal_ids = []
for planline in plan.planline_ids:
(start_date, end_date) = start_end_date_for_period(plan.period)
domain = [
('planline_id', '=', planline.id),
('user_id', '=', user.id),
('state', 'in', ('inprogress', 'inprogress_update',
'reached', 'failed')),
]
if start_date:
domain.append(('start_date', '=', start_date.isoformat()))
if subset_goal_ids:
goal_ids = goal_obj.search(cr, uid, domain, context=context)
related_goal_ids.extend( [goal.id for goal in goal_ids if goal in subset_goal_ids] )
board_goals = []
goal_ids = goal_obj.search(cr, uid, domain, context=context)
for goal in goal_obj.browse(cr, uid, goal_ids, context=context):
board_goals.append({
'user': goal.user_id,
'current':goal.current,
'target_goal':goal.target_goal,
'completeness':goal.completeness,
})
else:
# if no subset goals, use the dates for restriction
if start_date:
domain.append(('start_date', '=', start_date.isoformat()))
if end_date:
domain.append(('end_date', '=', end_date.isoformat()))
# most complete first, current if same percentage (eg: if several 100%)
sorted_board = enumerate(sorted(board_goals, key=lambda k: (k['completeness'], k['current']), reverse=True))
planlines_boards.append({'goal_type':planline.type_id.name, 'board_goals':sorted_board})
related_goal_ids.extend( goal_obj.search(cr, uid, domain, context=context) )
body_html = template_env.get_template('group_progress.mako').render({'object':plan, 'planlines_boards':planlines_boards})
if len(related_goal_ids) == 0:
continue
variables = {
'object':plan,
'user':user,
'goals':goal_obj.browse(cr, uid, related_goal_ids, context=context)
}
body_html = template_env.get_template('personal_progress.mako').render(variables)
self.message_post(cr, uid, plan.id,
body=body_html,
partner_ids=[(6, 0, [user.partner_id.id for user in plan.user_ids])],
partner_ids=[(6, 0, [user.partner_id.id])],
context=context,
subtype='mail.mt_comment')
if plan.report_message_group_id:
@ -380,60 +487,8 @@ class gamification_goal_plan(osv.Model):
body=body_html,
context=context,
subtype='mail.mt_comment')
else:
# generate individual reports
for user in users or plan.user_ids:
goal_ids = self.get_current_related_goals(cr, uid, plan.id, user.id, context=context)
if len(goal_ids) == 0:
continue
variables = {
'object':plan,
'user':user,
'goals':goal_obj.browse(cr, uid, goal_ids, context=context)
}
body_html = template_env.get_template('personal_progress.mako').render(variables)
self.message_post(cr, uid, plan.id,
body=body_html,
partner_ids=[(6, 0, [user.partner_id.id])],
context=context,
subtype='mail.mt_comment')
if plan.report_message_group_id:
self.pool.get('mail.group').message_post(cr, uid, plan.report_message_group_id.id,
body=body_html,
context=context,
subtype='mail.mt_comment')
return True
def get_current_related_goals(self, cr, uid, plan_id, user_id, context=None):
"""Get the ids of goals linked to a plan for the current instance
If several goals are linked to the same planline and user, only the
latest instance of the plan is checked (eg: if the plan is monthly,
return the goals started the 1st of this month).
"""
plan = self.browse(cr, uid, plan_id, context=context)
(start_date, end_date) = start_end_date_for_period(plan.period)
goal_obj = self.pool.get('gamification.goal')
related_goal_ids = []
for planline in plan.planline_ids:
domain = [('planline_id', '=', planline.id),
('user_id', '=', user_id),
('state','in',('inprogress','inprogress_update','reached'))]
if start_date:
domain.append(('start_date', '=', start_date.isoformat()))
goal_ids = goal_obj.search(cr, uid, domain, context=context)
related_goal_ids.extend(goal_ids)
return related_goal_ids
class gamification_goal_planline(osv.Model):
"""Gamification goal planline
@ -477,4 +532,4 @@ class gamification_goal_planline(osv.Model):
store={
'gamification.goal.type': (_get_planline_types, ['sequence'], 10),
}),
}
}

View File

@ -49,7 +49,7 @@
<button string="Close Plan" type="object" name="action_close" states="inprogress" class="oe_highlight"/>
<button string="Reset to Draft" type="object" name="action_cancel" states="inprogress"/>
<button string="Reset Completion" type="object" name="action_reset" states="done"/>
<button string="Report Progress" type="object" name="report_progress" states="inprogress,done" groups="base.group_no_one"/>
<button string="Report Progress" type="object" name="action_report_progress" states="inprogress,done" groups="base.group_no_one"/>
<field name="state" widget="statusbar"/>
</header>
<sheet>