[REF] user related field goal -> plan

bzr revid: mat@openerp.com-20130312141531-vp1gfrc5xvh5dd8s
This commit is contained in:
Martin Trigaux 2013-03-12 15:15:31 +01:00
parent 710560e71f
commit 226343cf63
2 changed files with 114 additions and 117 deletions

View File

@ -116,20 +116,24 @@ class gamification_goal(osv.Model):
return ret
_columns = {
'type_id' : fields.many2one('gamification.goal.type',
'type_id': fields.many2one('gamification.goal.type',
string='Goal Type',
required=True,
ondelete="cascade"),
'user_id' : fields.many2one('res.users', string='User', required=True),
'user_id': fields.many2one('res.users', string='User', required=True),
'planline_id' : fields.many2one('gamification.goal.planline',
string='Goal Planline',
ondelete="cascade"),
'start_date' : fields.date('Start Date'),
'end_date' : fields.date('End Date'), # no start and end = always active
'target_goal' : fields.float('To Reach',
'plan_id': fields.related('planline_id', 'plan_id',
string="Plan",
type='many2one',
store=True),
'start_date': fields.date('Start Date'),
'end_date': fields.date('End Date'), # no start and end = always active
'target_goal': fields.float('To Reach',
required=True,
track_visibility = 'always'), # no goal = global index
'current' : fields.float('Current',
'current': fields.float('Current',
required=True,
track_visibility = 'always'),
'completeness': fields.function(_get_completeness,
@ -150,7 +154,7 @@ class gamification_goal(osv.Model):
'computation_mode': fields.related('type_id','computation_mode',
type='char',
string="Type computation mode"),
'remind_update_delay' : fields.integer('Remind delay',
'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 is specified."),
'last_update' : fields.date('Last Update',
help="In case of manual goal, reminders are sent if the goal as not been updated for a while (defined in goal plan). Ignored in case of non-manual goal or goal not linked to a plan."),
@ -173,7 +177,6 @@ class gamification_goal(osv.Model):
}
_order = 'last_update desc, end_date, type_id'
def update(self, cr, uid, ids, context=None):
"""Update the goals to recomputes values and change of states
@ -182,9 +185,9 @@ class gamification_goal(osv.Model):
If a goal reaches the target value, the status is set to reached
If the end date is passed (at least +1 day, time not considered) without
the target value being reached, the goal is set as failed."""
for goal in self.browse(cr, uid, ids, context=context or {}):
if goal.state in ('draft','canceled'):
if goal.state in ('draft', 'canceled'):
# skip if goal draft or canceled
continue
if goal.last_update and goal.end_date and goal.last_update > goal.end_date:
@ -192,11 +195,11 @@ class gamification_goal(osv.Model):
continue
if goal.type_id.computation_mode == 'manually':
towrite = {'current':goal.current}
towrite = {'current': goal.current}
# check for remind to update
if goal.remind_update_delay and goal.last_update:
delta_max = timedelta(days=goal.remind_update_delay)
last_update = datetime.strptime(goal.last_update,'%Y-%m-%d').date()
last_update = datetime.strptime(goal.last_update, '%Y-%m-%d').date()
if date.today() - last_update > delta_max and goal.state == 'inprogress':
towrite['state'] = 'inprogress_update'
@ -214,7 +217,7 @@ class gamification_goal(osv.Model):
field_date_name = goal.type_id.field_date_id.name
domain = safe_eval(goal.type_id.domain,
{'user_id': goal.user_id.id})
{'user_id': goal.user_id.id})
if goal.start_date:
domain.append((field_date_name, '>=', goal.start_date))
if goal.end_date:
@ -223,8 +226,12 @@ class gamification_goal(osv.Model):
if goal.type_id.computation_mode == 'sum':
field_name = goal.type_id.field_id.name
res = obj.read_group(cr, uid, domain, [field_name],
[''], context=context)
towrite = {'current': res[0][field_name]}
[''], context=context)
if res[0][field_name]:
towrite = {'current': res[0][field_name]}
else:
# avoid false when no result
towrite = {'current': 0}
else: # computation mode = count
res = obj.search(cr, uid, domain, context=context)
@ -240,7 +247,7 @@ class gamification_goal(osv.Model):
# check goal failure
elif goal.end_date and fields.date.today() > goal.end_date:
towrite['state'] = 'failed'
self.write(cr, uid, [goal.id], towrite, context=context)
return True
@ -268,7 +275,7 @@ class gamification_goal(osv.Model):
"""Reset the completion after setting a goal as reached or failed.
This is only the current state, if the date and/or target criterias
match the conditions for a change of state, this will be applied at the
match the conditions for a change of state, this will be applied at the
next goal update."""
return self.write(cr, uid, ids, {'state': 'inprogress'}, context=context)
@ -277,22 +284,22 @@ class gamification_goal(osv.Model):
context = context or {}
context['just_created'] = True
return super(gamification_goal, self).create(cr, uid, vals, context=context)
def write(self, cr, uid, ids, vals, context=None):
"""Overwrite the write method to update the last_update field to today
If the current value is changed and the report frequency is set to On
If the current value is changed and the report frequency is set to On
change, q report is generated"""
for goal in self.browse(cr, uid, ids, vals):
vals['last_update'] = fields.date.today()
vals['last_update'] = fields.date.today()
for goal in self.browse(cr, uid, ids, context=context):
if 'current' in vals:
if 'just_created' in context:
# new goals should not be reported
continue
if goal.planline_id and goal.planline_id.plan_id.report_message_frequency == 'onchange':
if goal.plan_id and goal.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, users=[goal.user_id], context=context)
plan_obj.report_progress(cr, uid, goal.plan_id, users=[goal.user_id], context=context)
return super(gamification_goal, self).write(cr, uid, ids, vals, context=context)

View File

@ -206,7 +206,9 @@ class gamification_goal_plan(osv.Model):
if not context: context = {}
# start planned plans
planned_plan_ids = self.search(cr, uid, [('state', '=', 'draft'),('start_date','=',fields.date.today())])
planned_plan_ids = self.search(cr, uid, [
('state', '=', 'draft'),
('start_date', '=', fields.date.today())])
self.action_start(cr, uid, planned_plan_ids, context=context)
if not ids:
@ -217,21 +219,20 @@ class gamification_goal_plan(osv.Model):
yesterday = date.today() - timedelta(days=1)
# TOCHECK conflict with date rule in goal update() function
goal_ids = goal_obj.search(cr, uid, [
'&',
('state', 'not in', ('draft','canceled')),
'|',
('end_date', '>=', yesterday.isoformat()),
('end_date', '=', False)
], context=context)
'&',
('state', 'not in', ('draft', 'canceled')),
'|',
('end_date', '>=', yesterday.isoformat()),
('end_date', '=', False)
], context=context)
goal_obj.update(cr, uid, goal_ids, context=context)
return self._update_all(cr, uid, ids, context=context)
def _update_all(self, cr, uid, ids, context=None):
"""Update the plans and related goals
:param list(int) ids: the ids of the plans to update, if False will
:param list(int) ids: the ids of the plans to update, if False will
update only plans in progress."""
if not context: context = {}
goal_obj = self.pool.get('gamification.goal')
@ -240,22 +241,20 @@ class gamification_goal_plan(osv.Model):
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)
]))
closed_goals_to_report = goal_obj.search(cr, uid, [
('plan_id', '=', plan.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)
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)
self.write(cr, uid, plan.id, {'last_report_date': fields.date.today}, context=context)
def action_start(self, cr, uid, ids, context=None):
@ -298,12 +297,8 @@ class gamification_goal_plan(osv.Model):
Change the state of the plan to draft
Cancel the related goals"""
self.write(cr, uid, ids, {'state': 'draft'}, context=context)
for plan in self.browse(cr, uid, ids, context):
for planline in plan.planline_ids:
goal_obj = self.pool.get('gamification.goal')
goal_ids = goal_obj.search(cr, uid, [('planline_id', '=', planline.id)], context=context)
goal_obj.write(cr, uid, goal_ids, {'state': 'canceled'}, context=context)
goal_ids = self.pool.get('gamification.goal').search(cr, uid, [('plan_id', 'in', ids)], context=context)
self.pool.get('gamification.goal').write(cr, uid, goal_ids, {'state': 'canceled'}, context=context)
return True
@ -314,6 +309,7 @@ class gamification_goal_plan(osv.Model):
# get ids of related goals
goal_obj = self.pool.get('gamification.goal')
related_goal_ids = []
goal_ids = goal_obj.search(cr, uid, [('plan_id', 'in', ids)], context=context)
for plan in self.browse(cr, uid, ids, context=context):
for planline in plan.planline_ids:
goal_ids = goal_obj.search(cr, uid, [('planline_id', '=', planline.id)], context=context)
@ -339,23 +335,22 @@ class gamification_goal_plan(osv.Model):
def generate_goals_from_plan(self, cr, uid, ids, context=None):
"""Generate the list of goals linked to a plan.
If goals already exist for this planline, the planline is skipped. This
If goals already exist for this planline, the planline is skipped. This
can be called after each change in the user or planline list.
:param list(int) ids: the list of plan concerned"""
for plan in self.browse(cr, uid, ids, context):
(start_date, end_date) = start_end_date_for_period(plan.period)
for planline in plan.planline_ids:
for user in plan.user_ids:
goal_obj = self.pool.get('gamification.goal')
domain = [('planline_id', '=', planline.id),
('user_id', '=', user.id)]
domain = [('planline_id', '=', planline.id), ('user_id', '=', user.id)]
if start_date:
domain.append(('start_date', '=', start_date))
# goal existing for this planline ?
# goal already existing for this planline ?
if len(goal_obj.search(cr, uid, domain, context=context)) > 0:
# resume canceled goals
@ -363,18 +358,18 @@ class gamification_goal_plan(osv.Model):
canceled_goal_ids = goal_obj.search(cr, uid, domain, context=context)
goal_obj.write(cr, uid, canceled_goal_ids, {'state': 'inprogress'}, context=context)
goal_obj.update(cr, uid, canceled_goal_ids, context=context)
# skip to next user
continue
values = {
'type_id':planline.type_id.id,
'planline_id':planline.id,
'user_id':user.id,
'target_goal':planline.target_goal,
'state':'inprogress',
'type_id': planline.type_id.id,
'planline_id': planline.id,
'user_id': user.id,
'target_goal': planline.target_goal,
'state': 'inprogress',
}
if start_date:
values['start_date'] = start_date.isoformat()
if end_date:
@ -384,19 +379,18 @@ class gamification_goal_plan(osv.Model):
values['remind_update_delay'] = planline.plan_id.remind_update_delay
new_goal_id = goal_obj.create(cr, uid, values, context)
goal_obj.update(cr, uid, [new_goal_id], context=context)
return True
def plan_subscribe_users(self, cr, uid, ids, new_user_ids, context=None):
""" Add the following users to plans
:param ids: ids of plans to which the users will be added
:param new_user_ids: ids of the users to add"""
for plan in self.browse(cr,uid, ids, context):
for plan in self.browse(cr, uid, ids, context):
subscription = [user.id for user in plan.user_ids]
subscription.extend(new_user_ids)
# remove duplicates
@ -405,20 +399,21 @@ class gamification_goal_plan(osv.Model):
self.write(cr, uid, ids, {'user_ids': [(4, user) for user in unified_subscription]}, context=context)
return True
def report_progress(self, cr, uid, plan, context=None, users=False, subset_goal_ids=False):
"""Post report about the progress of the goals
:param plan: the plan object that need to be reported
:param list(res.users) users: the list of users that are concerned by
:param users: the list(res.users) of users that are concerned by
the report. If False, will send the report to every user concerned
(goal users and group that receive a copy). Only used for plan with
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
:param goal_ids: the list(int) 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."""
periods.
:param subset_goal_ids: a list(int) of goal ids to restrict the report
"""
context = context or {}
goal_obj = self.pool.get('gamification.goal')
template_env = TemplateHelper()
@ -430,16 +425,16 @@ class gamification_goal_plan(osv.Model):
planlines_boards = []
for planline in plan.planline_ids:
domain = [
('planline_id', '=', planline.id),
('state', 'in', ('inprogress', 'inprogress_update',
'reached', 'failed')),
'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]
common_goal_ids = [goal for goal in goal_ids if goal in subset_goal_ids]
else:
# if no subset goals, use the dates for restriction
if start_date:
@ -447,7 +442,7 @@ class gamification_goal_plan(osv.Model):
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({
@ -459,10 +454,10 @@ class gamification_goal_plan(osv.Model):
# 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})
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})
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])],
@ -473,52 +468,48 @@ 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:
related_goal_ids = []
for planline in plan.planline_ids:
domain = [
('planline_id', '=', planline.id),
('user_id', '=', user.id),
('state', 'in', ('inprogress', 'inprogress_update',
'reached', 'failed')),
]
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] )
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()))
related_goal_ids.extend( goal_obj.search(cr, uid, domain, context=context) )
domain = [
('plan_id', '=', plan.id),
('user_id', '=', user.id),
('state', 'in', ('inprogress', 'inprogress_update',
'reached', 'failed')),
]
if subset_goal_ids:
# use the domain for safety, don't want irrelevant report if wrong argument
goal_ids = goal_obj.search(cr, uid, domain, context=context)
related_goal_ids = [goal 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()))
related_goal_ids = goal_obj.search(cr, uid, domain, context=context)
if len(related_goal_ids) == 0:
continue
variables = {
'object':plan,
'user':user,
'goals':goal_obj.browse(cr, uid, related_goal_ids, context=context)
'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])],
context=context,
subtype='mail.mt_comment')
body=body_html,
partner_ids=[(4, 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')
body=body_html,
context=context,
subtype='mail.mt_comment')
return True
@ -534,7 +525,6 @@ class gamification_goal_planline(osv.Model):
_description = 'Gamification generic goal for plan'
_order = "sequence_type"
def _get_planline_types(self, cr, uid, ids, context=None):
"""Return the ids of planline items related to the gamification.goal.type
objects in 'ids (used to update the value of 'sequence_type')'"""
@ -548,16 +538,16 @@ class gamification_goal_planline(osv.Model):
return result.keys()
_columns = {
'plan_id' : fields.many2one('gamification.goal.plan',
'plan_id': fields.many2one('gamification.goal.plan',
string='Plan',
ondelete="cascade"),
'type_id' : fields.many2one('gamification.goal.type',
'type_id': fields.many2one('gamification.goal.type',
string='Goal Type',
required=True,
ondelete="cascade"),
'target_goal' : fields.float('Target Value to Reach',
'target_goal': fields.float('Target Value to Reach',
required=True),
'sequence_type' : fields.related('type_id','sequence',
'sequence_type': fields.related('type_id', 'sequence',
type='integer',
string='Sequence',
readonly=True,