diff options
| author | Martin Trigaux <mat@openerp.com> | 2013-12-20 15:45:21 +0100 |
|---|---|---|
| committer | Martin Trigaux <mat@openerp.com> | 2013-12-20 15:45:21 +0100 |
| commit | f77aefc07ace66587bc13f7d2fa55755968437c5 (patch) | |
| tree | ac8d29d536f2181258fb6cb6d76b5f8da8807afd /addons | |
| parent | 90dfa5895d61fae037046aea2b64b25d9903df15 (diff) | |
[REF] gamification: cleaning methods and reports
bzr revid: mat@openerp.com-20131220144521-wyu1gx8bcitu6nk4
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/gamification/data/goal_base.xml | 64 | ||||
| -rw-r--r-- | addons/gamification/models/challenge.py | 215 | ||||
| -rw-r--r-- | addons/gamification/models/goal.py | 1 | ||||
| -rw-r--r-- | addons/gamification/models/res_users.py | 99 | ||||
| -rw-r--r-- | addons/gamification/static/src/css/gamification.css | 6 | ||||
| -rw-r--r-- | addons/gamification/static/src/js/gamification.js | 55 | ||||
| -rw-r--r-- | addons/gamification/static/src/xml/gamification.xml | 78 | ||||
| -rw-r--r-- | addons/gamification/templates/badge_received.mako | 17 | ||||
| -rw-r--r-- | addons/gamification/templates/base.mako | 13 | ||||
| -rw-r--r-- | addons/gamification/templates/group_progress.mako | 38 | ||||
| -rw-r--r-- | addons/gamification/templates/personal_progress.mako | 31 | ||||
| -rw-r--r-- | addons/gamification/templates/reminder.mako | 17 | ||||
| -rw-r--r-- | addons/gamification/views/challenge.xml | 7 | ||||
| -rw-r--r-- | addons/gamification/views/goal.xml | 2 |
14 files changed, 263 insertions, 380 deletions
diff --git a/addons/gamification/data/goal_base.xml b/addons/gamification/data/goal_base.xml index 2b21fbc947f..48dd770bbcc 100644 --- a/addons/gamification/data/goal_base.xml +++ b/addons/gamification/data/goal_base.xml @@ -7,7 +7,7 @@ <field name="name">Set your Timezone</field> <field name="description">Configure your profile and specify your timezone</field> <field name="computation_mode">count</field> - <field name="display_mode">checkbox</field> + <field name="display_mode">boolean</field> <field name="model_id" eval="ref('base.model_res_users')" /> <field name="domain">[('id','=',user.id),('partner_id.tz', '!=', False)]</field> <field name="action_id" eval="ref('base.action_res_users_my')" /> @@ -18,7 +18,7 @@ <field name="name">Set your Company Data</field> <field name="description">Write some information about your company (specify at least a name)</field> <field name="computation_mode">count</field> - <field name="display_mode">checkbox</field> + <field name="display_mode">boolean</field> <field name="model_id" eval="ref('base.model_res_company')" /> <field name="domain">[('user_ids', 'in', [user.id]), ('name', '=', 'Your Company')]</field> <field name="condition">lower</field> @@ -29,7 +29,7 @@ <record model="gamification.goal.definition" id="definition_base_company_logo"> <field name="name">Set your Company Logo</field> <field name="computation_mode">count</field> - <field name="display_mode">checkbox</field> + <field name="display_mode">boolean</field> <field name="model_id" eval="ref('base.model_res_company')" /> <field name="domain">[('user_ids', 'in', user.id),('logo', '!=', False)]</field> <field name="action_id" eval="ref('base.action_res_company_form')" /> @@ -50,7 +50,7 @@ <record model="gamification.goal.definition" id="definition_base_invite"> <field name="name">Invite new Users</field> <field name="description">Create at least another user</field> - <field name="display_mode">checkbox</field> + <field name="display_mode">boolean</field> <field name="computation_mode">count</field> <field name="model_id" eval="ref('base.model_res_users')" /> <field name="domain">[('id', '!=', user.id)]</field> @@ -146,24 +146,24 @@ <th>Current</th> <th>Completeness</th> </tr> - % for goal in ctx["goals"]: + % for line in ctx["challenge_lines"]: <tr - % if goal.completeness >= 100: + % if line['completeness'] >= 100: style="font-weight:bold;" % endif > - <td>${goal.definition_id.name}</td> - <td>${goal.target_goal} - % if goal.definition_suffix: - ${goal.definition_suffix} + <td>${line['name']}</td> + <td>${line['target']} + % if line['suffix']: + ${line['suffix']} % endif </td> - <td>${goal.current} - % if goal.definition_suffix: - ${goal.definition_suffix} + <td>${line['current']} + % if line['suffix']: + ${line['suffix']} % endif </td> - <td>${goal.completeness} %</td> + <td>${line['completeness']} %</td> </tr> % endfor </table>]]></field> @@ -177,10 +177,10 @@ </header> <p class="oe_grey">${object.report_header or ''}</p> - % for line in ctx['lines_boards']: + % for line in ctx["challenge_lines"]: <table width="100%" border="1"> <tr> - <th colspan="4">${line.goal_definition.name}</th> + <th colspan="4">${line['name']}</th> </tr> <tr> <th>#</th> @@ -188,23 +188,21 @@ <th>Completeness</th> <th>Current</th> </tr> - % for idx, goal in line.board_goals: - % if idx < 3 or goal.user_id.id == user.id: - <tr - % if goal.completeness >= 100: - style="font-weight:bold;" - % endif - > - <td>${idx+1}</td> - <td>${goal.user_id.name}</td> - <td>${goal.completeness}%</td> - <td>${goal.current}/${goal.target_goal} - % if goal.definition_suffix: - ${goal.definition_suffix} - % endif - </td> - </tr> - % endif + % for goal in line['goals']: + <tr + % if goal.completeness >= 100: + style="font-weight:bold;" + % endif + > + <td>${goal['rank']}</td> + <td>${goal['name']}</td> + <td>${goal['completeness']}%</td> + <td>${goal['current']}/${line['target']} + % if line['suffix']: + ${line['suffix']} + % endif + </td> + </tr> % endfor </table> diff --git a/addons/gamification/models/challenge.py b/addons/gamification/models/challenge.py index 0f3e64626cb..7cbd784b9bf 100644 --- a/addons/gamification/models/challenge.py +++ b/addons/gamification/models/challenge.py @@ -19,17 +19,18 @@ # ############################################################################## +from openerp import SUPERUSER_ID from openerp.osv import fields, osv from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DF from openerp.tools.translate import _ -# from templates import TemplateHelper - from datetime import date, datetime, timedelta import calendar import logging _logger = logging.getLogger(__name__) +# display top 3 in ranking, could be db variable +MAX_VISIBILITY_RANKING = 3 def start_end_date_for_period(period, default_start_date=False, default_end_date=False): """Return the start and end date for a goal period based on today @@ -107,7 +108,7 @@ class gamification_challenge(osv.Model): ('other', 'Settings / Gamification Tools'), ] - _sort = 'end_date, start_date, name, id' + _order = 'end_date, start_date, name, id' _columns = { 'name': fields.char('Challenge Name', required=True, translate=True), 'description': fields.text('Description', translate=True), @@ -444,89 +445,137 @@ class gamification_challenge(osv.Model): ##### JS utilities ##### - def get_board_goal_info(self, cr, uid, challenge, subset_goal_ids=False, context=None): - """Get the list of latest goals for a challenge, sorted by user ranking for each line""" - + def _get_serialized_challenge_lines(self, cr, uid, challenge, user_id=False, restrict_goal_ids=False, restrict_top=False, context=None): + """Return a serialised version of the goals information + + :challenge: browse record of challenge to compute + :user_id: res.users id of the user retrieving progress (False if no distinction, only for ranking challenges) + :restrict_goal_ids: <list(int)> compute only the results for this subset if gamification.goal ids, if False retrieve every goal of current running challenge + :restrict_top: <int> for challenge lines where visibility_mode == 'ranking', retrieve only these bests results and itself, if False retrieve all + restrict_goal_ids has priority over restrict_top + + format list + # if visibility_mode == 'ranking' + { + 'name': <gamification.goal.description name>, + 'description': <gamification.goal.description description>, + 'condition': <reach condition {lower,higher}>, + 'computation_mode': <target computation {manually,count,sum,python}>, + 'monetary': <{True,False}>, + 'suffix': <value suffix>, + 'action': <{True,False}>, + 'display_mode': <{progress,boolean}>, + 'target': <challenge line target>, + 'own_goal_id': <gamification.goal id where user_id == uid>, + 'goals': [ + { + 'id': <gamification.goal id>, + 'rank': <user ranking>, + 'user_id': <res.users id>, + 'name': <res.users name>, + 'state': <gamification.goal state {draft,inprogress,inprogress_update,reached,failed,canceled}>, + 'completeness': <percentage>, + 'current': <current value>, + } + ] + }, + # if visibility_mode == 'personal' + { + 'id': <gamification.goal id>, + 'name': <gamification.goal.description name>, + 'description': <gamification.goal.description description>, + 'condition': <reach condition {lower,higher}>, + 'computation_mode': <target computation {manually,count,sum,python}>, + 'monetary': <{True,False}>, + 'suffix': <value suffix>, + 'action': <{True,False}>, + 'display_mode': <{progress,boolean}>, + 'target': <challenge line target>, + 'state': <gamification.goal state {draft,inprogress,inprogress_update,reached,failed,canceled}>, + 'completeness': <percentage>, + 'current': <current value>, + } + """ goal_obj = self.pool.get('gamification.goal') - lines_boards = [] (start_date, end_date) = start_end_date_for_period(challenge.period) + res_lines = [] for line in challenge.line_ids: - + line_data = { + 'name': line.definition_id.name, + 'description': line.definition_id.description, + 'condition': line.definition_id.condition, + 'computation_mode': line.definition_id.computation_mode, + 'monetary': line.definition_id.monetary, + 'suffix': line.definition_id.suffix, + 'action': True if line.definition_id.action_id else False, + 'display_mode': line.definition_id.display_mode, + 'target': line.target_goal, + } domain = [ ('line_id', '=', line.id), - ('state', 'in', ('inprogress', 'inprogress_update', - 'reached', 'failed')), + ('state', '!=', 'draft'), ] - - if subset_goal_ids: - goal_ids = goal_obj.search(cr, uid, domain, context=context) - common_goal_ids = [goal for goal in goal_ids if goal in subset_goal_ids] + if restrict_goal_ids: + domain.append(('ids', 'in', restrict_goal_ids)) else: # if no subset goals, use the dates for restriction if start_date: domain.append(('start_date', '=', start_date)) if end_date: domain.append(('end_date', '=', end_date)) - common_goal_ids = goal_obj.search(cr, uid, domain, context=context) - - board_goals = [goal for goal in goal_obj.browse(cr, uid, common_goal_ids, context=context)] - - if len(board_goals) == 0: - # line has no generated goals - continue - - # 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)) - lines_boards.append({'goal_definition': line.definition_id, 'board_goals': sorted_board, 'target_goal': line.target_goal}) - return lines_boards - - def get_indivual_goal_info(self, cr, uid, user_id, challenge, subset_goal_ids=False, context=None): - """Get the list of latest goals of a user for a challenge""" - domain = [ - ('challenge_id', '=', challenge.id), - ('user_id', '=', user_id), - ('state', 'in', ('inprogress', 'inprogress_update', - 'reached', 'failed')), - ] - goal_obj = self.pool.get('gamification.goal') - (start_date, end_date) = start_end_date_for_period(challenge.period) - 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)) - if end_date: - domain.append(('end_date', '=', end_date)) - related_goal_ids = goal_obj.search(cr, uid, domain, context=context) - - if len(related_goal_ids) == 0: - return False - - goals = [] - all_done = True - for goal in goal_obj.browse(cr, uid, related_goal_ids, context=context): - if goal.end_date: - if goal.end_date < fields.date.today(): - # do not include goals of previous challenge run - continue - else: - all_done = False + if challenge.visibility_mode == 'personal': + if not user_id: + raise osv.except_osv(_('Error!'),_("Retrieving progress for personal challenge without user information")) + domain.append(('user_id', '=', user_id)) + sorting = goal_obj._order + limit = 1 + # initialise in case search returns no results + line_data.update({ + 'id': 0, + 'current': 0, + 'completeness': 0, + 'state': 'draft', + }) else: - if goal.state == 'inprogress' or goal.state == 'inprogress_update': - all_done = False - - goals.append(goal) + line_data.update({ + 'own_goal_id': False, + 'goals': [], + }) + sorting = "completeness desc, current desc" + limit = False + + goal_ids = goal_obj.search(cr, uid, domain, order=sorting, limit=limit, context=context) + ranking = 0 + for goal in goal_obj.browse(cr, uid, goal_ids, context=context): + if challenge.visibility_mode == 'personal': + # limit=1 so only one result + line_data.update({ + 'id': goal.id, + 'current': goal.current, + 'completeness': goal.completeness, + 'state': goal.state, + }) + else: + ranking += 1 + if user_id and goal.user_id.id == user_id: + line_data['own_goal_id'] = goal.id + elif restrict_top and ranking > restrict_top: + # not own goal, over top, skipping + continue - if all_done: - # skip challenges where all goal are done or failed - return False - else: - return goals + line_data['goals'].append({ + 'id': goal.id, + 'user_id': goal.user_id.id, + 'name': goal.user_id.name, + 'rank': ranking, + 'current': goal.current, + 'completeness': goal.completeness, + 'state': goal.state, + }) + res_lines.append(line_data) + return res_lines ##### Reporting ##### @@ -550,11 +599,11 @@ class gamification_challenge(osv.Model): temp_obj = self.pool.get('email.template') ctx = context.copy() if challenge.visibility_mode == 'ranking': - lines_boards = self.get_board_goal_info(cr, uid, challenge, subset_goal_ids, context) + lines_boards = self._get_serialized_challenge_lines(cr, uid, challenge, user_id=False, restrict_goal_ids=subset_goal_ids, restrict_top=False, context=context) - ctx.update({'lines_boards': lines_boards}) - template_id = self.pool['ir.model.data'].get_object(cr, uid, 'gamification', 'email_template_goal_progress_group', context) - body_html = temp_obj.render_template(cr, uid, template_id.body_html, 'gamification.challenge', challenge.id, context=context) + ctx.update({'challenge_lines': lines_boards}) + template_id = self.pool.get('ir.model.data').get_object(cr, uid, 'gamification', 'email_template_goal_progress_group', context) + body_html = temp_obj.render_template(cr, uid, template_id.body_html, 'gamification.challenge', challenge.id, context=ctx) # body_html = template_env.get_template('group_progress.mako').render({'object': challenge, 'lines_boards': lines_boards, 'uid': uid}) @@ -572,14 +621,14 @@ class gamification_challenge(osv.Model): else: # generate individual reports for user in users or challenge.user_ids: - goals = self.get_indivual_goal_info(cr, uid, user.id, challenge, subset_goal_ids, context=context) + goals = self._get_serialized_challenge_lines(cr, uid, challenge, user.id, restrict_goal_ids=subset_goal_ids, context=context) if not goals: continue - ctx.update({'goals': goals}) + ctx.update({'challenge_lines': goals}) template_id = self.pool['ir.model.data'].get_object(cr, uid, 'gamification', 'email_template_goal_progress_perso', context) - body_html = temp_obj.render_template(cr, user.id, template_id.body_html, 'gamification.challenge', challenge.id, context=context) - # send message only to users + body_html = temp_obj.render_template(cr, user.id, template_id.body_html, 'gamification.challenge', challenge.id, context=ctx) + # send message only to users, not on the challenge self.message_post(cr, uid, 0, body=body_html, partner_ids=[(4, user.partner_id.id)], @@ -600,7 +649,7 @@ class gamification_challenge(osv.Model): user = self.pool.get('res.users').browse(cr, uid, user_id, context=context) message = "%s has joined the challenge" % user.name self.message_post(cr, uid, challenge_ids, body=message, context=context) - self.write(cr, uid, challenge_ids, {'invited_user_ids': [(3, user_id)], 'user_ids': [(4, user_id)]}, context=context) + self.write(cr, SUPERUSER_ID, challenge_ids, {'invited_user_ids': [(3, user_id)], 'user_ids': [(4, user_id)]}, context=context) return self.generate_goals_from_challenge(cr, uid, challenge_ids, context=context) def discard_challenge(self, cr, uid, challenge_ids, context=None, user_id=None): @@ -608,7 +657,7 @@ class gamification_challenge(osv.Model): user_id = user_id or uid user = self.pool.get('res.users').browse(cr, uid, user_id, context=context) message = "%s has refused the challenge" % user.name - self.message_post(cr, uid, challenge_ids, body=message, context=context) + self.message_post(cr, SUPERUSER_ID, challenge_ids, body=message, context=context) return self.write(cr, uid, challenge_ids, {'invited_user_ids': (3, user_id)}, context=context) def reply_challenge_wizard(self, cr, uid, challenge_id, context=None): @@ -710,7 +759,7 @@ class gamification_challenge(osv.Model): for goal in goal_obj.browse(cr, uid, goal_ids, context=context): if goal.state != 'reached': all_reached = False - if goal.definition_condition == 'higher': + if goal.condition == 'higher': # can be over 100 total_completness += 100.0 * goal.current / goal.target_goal elif goal.state == 'reached': @@ -761,7 +810,7 @@ class gamification_challenge_line(osv.Model): goal_definition = goal_definition.browse(cr, uid, definition_id, context=context) ret = { 'value': { - 'definition_condition': goal_definition.condition, + 'condition': goal_definition.condition, 'definition_full_suffix': goal_definition.full_suffix } } @@ -781,7 +830,7 @@ class gamification_challenge_line(osv.Model): required=True), 'sequence': fields.integer('Sequence', help='Sequence number for ordering'), - 'definition_condition': fields.related('definition_id', 'condition', type="selection", + 'condition': fields.related('definition_id', 'condition', type="selection", readonly=True, string="Condition", selection=[('lower', '<='), ('higher', '>=')]), 'definition_suffix': fields.related('definition_id', 'suffix', type="char", readonly=True, string="Unit"), 'definition_monetary': fields.related('definition_id', 'monetary', type="boolean", readonly=True, string="Monetary"), diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py index 5464b51a4ea..52eebb63857 100644 --- a/addons/gamification/models/goal.py +++ b/addons/gamification/models/goal.py @@ -76,6 +76,7 @@ class gamification_goal_definition(osv.Model): 'display_mode': fields.selection([ ('progress', 'Progressive (using numerical values)'), ('checkbox', 'Checkbox (done or not-done)'), + ('boolean', 'Exclusive (done or not-done)'), ], string="Displayed as", required=True), 'model_id': fields.many2one('ir.model', diff --git a/addons/gamification/models/res_users.py b/addons/gamification/models/res_users.py index d831ab2ea25..408ddddf082 100644 --- a/addons/gamification/models/res_users.py +++ b/addons/gamification/models/res_users.py @@ -20,7 +20,7 @@ ############################################################################## from openerp.osv import osv - +from challenge import MAX_VISIBILITY_RANKING class res_users_gamification_group(osv.Model): """ Update of res.users class @@ -58,14 +58,23 @@ class res_users_gamification_group(osv.Model): challenge_obj.write(cr, uid, challenge_ids, {'user_ids': [(4, write_res)]}, context=context) return write_res - def get_goals_todo_info(self, cr, uid, context=None): - """Return the list of goals assigned to the user, grouped by challenge + # def get_goals_todo_info(self, cr, uid, context=None): + + def get_serialised_gamification_summary(self, cr, uid, context=None): + return self._serialised_goals_summary(cr, uid, user_id=uid, context=context) - This method intends to return processable data in javascript in the - goal_list_to_do template. The output format is not constant as the - required information is different between individual and board goal - definitions - :return: list of dictionnaries for each goal to display + def _serialised_goals_summary(self, cr, uid, user_id, context=None): + """Return a serialised list of goals assigned to the user, grouped by challenge + + [ + { + 'id': <gamification.challenge id>, + 'name': <gamification.challenge name>, + 'visibility_mode': <visibility {ranking,personal}>, + 'currency': <res.currency id>, + 'lines': [(see gamification_challenge._get_serialized_challenge_lines() format)] + }, + ] """ all_goals_info = [] challenge_obj = self.pool.get('gamification.challenge') @@ -74,78 +83,14 @@ class res_users_gamification_group(osv.Model): challenge_ids = challenge_obj.search(cr, uid, [('user_ids', 'in', uid), ('state', '=', 'inprogress')], context=context) for challenge in challenge_obj.browse(cr, uid, challenge_ids, context=context): # serialize goals info to be able to use it in javascript - serialized_goals_info = { + all_goals_info.append({ 'id': challenge.id, 'name': challenge.name, 'visibility_mode': challenge.visibility_mode, - 'currency': user.company_id.currency_id.id - } + 'currency': user.company_id.currency_id.id, + 'lines': challenge_obj._get_serialized_challenge_lines(cr, uid, challenge, user_id, restrict_top=MAX_VISIBILITY_RANKING, context=context), + }) - if challenge.visibility_mode == 'ranking': - # board report should be grouped by line for all users - goals_info = challenge_obj.get_board_goal_info(cr, uid, challenge, subset_goal_ids=False, context=context) - - if not goals_info: - # challenge with no valid lines - continue - - serialized_goals_info['lines'] = [] - for line_board in goals_info: - vals = {'definition_name': line_board['goal_definition'].name, - 'definition_description': line_board['goal_definition'].description, - 'definition_condition': line_board['goal_definition'].condition, - 'computation_mode': line_board['goal_definition'].computation_mode, - 'definition_monetary': line_board['goal_definition'].monetary, - 'definition_suffix': line_board['goal_definition'].suffix, - 'definition_action': True if line_board['goal_definition'].action_id else False, - 'definition_display': line_board['goal_definition'].display_mode, - 'target_goal': line_board['target_goal'], - 'goals': []} - for goal in line_board['board_goals']: - # Keep only the Top 3 and the current user - if goal[0] > 2 and goal[1].user_id.id != uid: - continue - - vals['goals'].append({ - 'rank': goal[0] + 1, - 'id': goal[1].id, - 'user_id': goal[1].user_id.id, - 'user_name': goal[1].user_id.name, - 'state': goal[1].state, - 'completeness': goal[1].completeness, - 'current': goal[1].current, - 'target_goal': goal[1].target_goal, - }) - if uid == goal[1].user_id.id: - vals['own_goal_id'] = goal[1].id - serialized_goals_info['lines'].append(vals) - - else: - # individual report are simply a list of goal - goals_info = challenge_obj.get_indivual_goal_info(cr, uid, uid, challenge, subset_goal_ids=False, context=context) - - if not goals_info: - continue - - serialized_goals_info['goals'] = [] - for goal in goals_info: - serialized_goals_info['goals'].append({ - 'id': goal.id, - 'definition_name': goal.definition_id.name, - 'definition_description': goal.definition_description, - 'definition_condition': goal.definition_id.condition, - 'definition_monetary': goal.definition_id.monetary, - 'definition_suffix': goal.definition_id.suffix, - 'definition_action': True if goal.definition_id.action_id else False, - 'definition_display': goal.definition_id.display_mode, - 'state': goal.state, - 'completeness': goal.completeness, - 'computation_mode': goal.computation_mode, - 'current': goal.current, - 'target_goal': goal.target_goal, - }) - - all_goals_info.append(serialized_goals_info) return all_goals_info def get_challenge_suggestions(self, cr, uid, context=None): @@ -171,7 +116,9 @@ class res_groups_gamification_group(osv.Model): _name = 'res.groups' _inherit = 'res.groups' + # No need to overwrite create as very unlikely to be the value in the autojoin_group_id field def write(self, cr, uid, ids, vals, context=None): + """Overwrite to autosubscribe users if add users to a group marked as autojoin, these will be added to the challenge""" write_res = super(res_groups_gamification_group, self).write(cr, uid, ids, vals, context=context) if vals.get('users'): # form: {'group_ids': [(3, 10), (3, 3), (4, 10), (4, 3)]} or {'group_ids': [(6, 0, [ids]} diff --git a/addons/gamification/static/src/css/gamification.css b/addons/gamification/static/src/css/gamification.css index cc20afede80..fd39b130fad 100644 --- a/addons/gamification/static/src/css/gamification.css +++ b/addons/gamification/static/src/css/gamification.css @@ -73,7 +73,7 @@ width: 280px; border-radius: 2px; } -.openerp .oe_mail_wall .oe_mail_wall_aside > .oe_gamification_goal { +.openerp .oe_mail_wall .oe_mail_wall_aside .oe_gamification_challenge_list { background-color: #EDEDF6; } .openerp .oe_mail_wall_aside .oe_gamification_suggestion { @@ -188,7 +188,7 @@ width: 24px; padding-right: 5px; } -.openerp .oe_mail_wall .oe_mail_wall_aside .oe_goal .oe_update_plan.oe_e, +.openerp .oe_mail_wall .oe_mail_wall_aside .oe_goal .oe_update_challenge.oe_e, .openerp .oe_mail_wall .oe_mail_wall_aside .oe_goal .oe_goal_action.oe_e { visibility: hidden; font-size: 25px; @@ -196,7 +196,7 @@ /*margin-right: 15px;*/ position: relative; } -.openerp .oe_mail_wall .oe_mail_wall_aside .oe_goal div:hover > .oe_update_plan, +.openerp .oe_mail_wall .oe_mail_wall_aside .oe_goal div:hover > .oe_update_challenge, .openerp .oe_mail_wall .oe_mail_wall_aside .oe_goal div:hover > .oe_goal_action, .openerp .oe_mail_wall .oe_mail_wall_aside .oe_goal th:hover > .oe_goal_action { visibility: visible; diff --git a/addons/gamification/static/src/js/gamification.js b/addons/gamification/static/src/js/gamification.js index 9e34d8f09fc..cf5b2228b08 100644 --- a/addons/gamification/static/src/js/gamification.js +++ b/addons/gamification/static/src/js/gamification.js @@ -2,12 +2,12 @@ openerp.gamification = function(instance) { var QWeb = instance.web.qweb; instance.gamification.Sidebar = instance.web.Widget.extend({ - template: 'gamification.user_wall_sidebar', + template: 'gamification.UserWallSidebar', init: function (parent, action) { var self = this; this._super(parent, action); this.deferred = $.Deferred(); - this.res_user = new instance.web.DataSetSearch(this, 'res.users'); + // this.res_user = new instance.web.DataSetSearch(this, 'res.users'); this.goals_info = {}; this.challenge_suggestions = {}; }, @@ -51,54 +51,53 @@ openerp.gamification = function(instance) { }); } }, - renderElement: function() { + start: function() { var self = this; this._super.apply(this, arguments); self.get_goal_todo_info(); self.get_challenge_suggestions(); }, - render_template: function(target,template) { - var self = this; - target.append(QWeb.render(template,{'widget': self})); - }, + // render_template: function(target,template) { + // var self = this; + // target.append(QWeb.render(template,{'widget': self})); + // }, render_template_replace: function(target,template) { var self = this; target.html(QWeb.render(template,{'widget': self})); }, get_goal_todo_info: function() { var self = this; - var goals_info = this.res_user.call('get_goals_todo_info', {}).then(function(res) { - self.goals_info['info'] = res; - }); - $.when(goals_info).done(function() { - if(self.goals_info.info.length > 0){ - self.render_template_replace(self.$el.filter(".oe_gamification_goal"),'gamification.goal_list_to_do'); - self.render_money_fields(self.goals_info.info[0].currency); - self.render_user_avatars(); + var challenges = new instance.web.Model('res.users').call('get_serialised_gamification_summary', []).then(function(result) { + if (result.length === 0) { + self.$el.find(".oe_gamification_challenge_list").hide(); } else { - self.$el.filter(".oe_gamification_goal").hide(); + _.each(result, function(item){ + console.log(item); + var $item = $(QWeb.render("gamification.ChallengeSummary", {challenge: item})); + self.render_money_fields($item); + self.render_user_avatars($item); + self.$el.find('.oe_gamification_challenge_list').append($item); + }); } }); }, get_challenge_suggestions: function() { var self = this; - var challenge_suggestions = this.res_user.call('get_challenge_suggestions', {}).then(function(res) { - self.challenge_suggestions['info'] = res; - }); - $.when(challenge_suggestions).done(function() { - if(self.challenge_suggestions.info.length > 0){ - self.render_template_replace(self.$el.filter(".oe_gamification_suggestion"),'gamification.challenge_suggestions'); + var challenge_suggestions = new instance.web.Model('res.users').call('get_challenge_suggestions', []).then(function(result) { + if (result.length === 0) { + self.$el.find(".oe_gamification_suggestion").hide(); } else { - self.$el.filter(".oe_gamification_suggestion").hide(); + var $item = $(QWeb.render("gamification.ChallengeSuggestion", {challenges: result})); + self.$el.find('.oe_gamification_suggestion').append($item); } }); }, - render_money_fields: function(currency_id) { + render_money_fields: function(item) { var self = this; - self.dfm = new instance.web.form.DefaultFieldManager(self); // Generate a FieldMonetary for each .oe_goal_field_monetary - self.$(".oe_goal_field_monetary").each(function() { + item.find(".oe_goal_field_monetary").each(function() { + var currency_id = parseInt( $(this).attr('data-id'), 10); money_field = new instance.web.form.FieldMonetary(self.dfm, { attrs: { modifiers: '{"readonly": true}' @@ -110,9 +109,9 @@ openerp.gamification = function(instance) { money_field.replace($(this)); }); }, - render_user_avatars: function() { + render_user_avatars: function(item) { var self = this; - self.$(".oe_user_avatar").each(function() { + item.find(".oe_user_avatar").each(function() { var user_id = parseInt( $(this).attr('data-id'), 10); var url = instance.session.url('/web/binary/image', {model: 'res.users', field: 'image_small', id: user_id}); $(this).attr("src", url); diff --git a/addons/gamification/static/src/xml/gamification.xml b/addons/gamification/static/src/xml/gamification.xml index 19c622dcb97..6316ca886f0 100644 --- a/addons/gamification/static/src/xml/gamification.xml +++ b/addons/gamification/static/src/xml/gamification.xml @@ -1,10 +1,12 @@ <templates> - <t t-name="gamification.user_wall_sidebar" class="oe_gamification_user_wall_sidebar"> - <div class="oe_gamification_suggestion"><em>No challenge suggestions</em></div> - <div class="oe_gamification_goal"><em>Your goal list is empty</em></div> + <t t-name="gamification.UserWallSidebar" class="oe_gamification_user_wall_sidebar"> + <div> + <div class="oe_gamification_suggestion"></div> + <div class="oe_gamification_challenge_list"></div> + </div> </t> - <t t-name="gamification.goal_list_to_do"> - <div t-foreach="widget.goals_info.info" t-as="challenge" class="oe_goal"> + <t t-name="gamification.ChallengeSummary"> + <div class="oe_goal"> <div> <a class="oe_update_challenge oe_e" rol="button" t-attf-id="{challenge.id}">e</a> <h4><t t-esc="challenge.name" /></h4> @@ -12,29 +14,29 @@ <t t-if="challenge.visibility_mode == 'personal'"> <div class="oe_table oe_goals_list"> - <div t-foreach="challenge.goals" t-as="goal" t-attf-class="oe_row oe_goal_outer_box #{goal.state == 'reached' ? 'oe_goal_reached' : ''} #{goal.definition_display != 'progress' ? 'oe_no_progress' : ''}"> - <t t-if="goal.definition_display == 'progress'"> + <div t-foreach="challenge.lines" t-as="line" t-attf-class="oe_row oe_goal_outer_box #{line.state == 'reached' ? 'oe_goal_reached' : ''} #{line.display_mode != 'progress' ? 'oe_no_progress' : ''}"> + <t t-if="line.display_mode == 'progress'"> <div class="oe_goal_progress_background"></div> - <div class="oe_goal_progress" t-attf-style="#{goal.definition_display == 'progress' ? 'width: '+goal.completeness+'%;' : 'width:0;'}"></div> - <div class="oe_cell oe_goal_current"><t t-esc="goal.current" /></div> + <div class="oe_goal_progress" t-attf-style="#{line.display_mode == 'progress' ? 'width: '+line.completeness+'%;' : 'width:0;'}"></div> + <div class="oe_cell oe_goal_current"><t t-esc="line.current" /></div> </t> <div class="oe_cell"> - <t t-if="goal.computation_mode != 'manually' and !goal.definition_action"> - <span t-att-title="goal.definition_description"><t t-esc="goal.definition_name" /></span> + <t t-if="line.computation_mode != 'manually' and !line.action"> + <span t-att-title="line.description"><t t-esc="line.name" /></span> </t> - <t t-if="goal.definition_action or goal.computation_mode == 'manually'"> - <span t-att-title="goal.definition_description"><a class="oe_goal_action" t-att-id="goal.id"><t t-esc="goal.definition_name" /></a></span> + <t t-if="line.action or line.computation_mode == 'manually'"> + <span t-att-title="line.description"><a class="oe_goal_action" t-att-id="line.id"><t t-esc="line.name" /></a></span> </t> - <t t-if="goal.definition_display == 'progress'"><br/> + <t t-if="line.display_mode == 'progress'"><br/> <div class="oe_grey"> - <t t-if="goal.definition_condition == 'higher'"> + <t t-if="line.definition_condition == 'higher'"> Target: </t> - <t t-if="goal.definition_condition == 'lower'"> + <t t-if="line.definition_condition == 'lower'"> Target: <= </t> - <span t-attf-class="#{goal.definition_monetary ? 'oe_goal_field_monetary' : ''}"><t t-esc="goal.target_goal"/></span> - <t t-if="goal.definition_suffix"><t t-esc="goal.definition_suffix"/></t> + <span t-attf-class="#{line.monetary ? 'oe_goal_field_monetary' : ''}" t-attf-data-id="#{line.monetary ? challenge.currency : ''}"><t t-esc="line.target"/></span> + <t t-if="line.suffix"><t t-esc="line.suffix"/></t> </div> </t> </div> @@ -45,8 +47,8 @@ <t t-if="challenge.visibility_mode == 'ranking'"> <div t-foreach="challenge.lines" t-as="line" class="oe_goals_list oe_table"> <div class="oe_row"> - <div class="oe_cell oe_thead" colspan="3" t-attf-title="#{line.definition_description ? line.definition_description : ''}"> - <strong><t t-esc="line.definition_name"/></strong> + <div class="oe_cell oe_thead" colspan="3" t-attf-title="#{line.description ? line.description : ''}"> + <strong><t t-esc="line.name"/></strong> <br/> <div class="oe_grey"> <t t-if="line.definition_condition == 'higher'"> @@ -55,39 +57,39 @@ <t t-if="line.definition_condition == 'lower'"> Target: <= </t> - <span t-attf-class="#{line.definition_monetary ? 'oe_goal_field_monetary' : ''}"><t t-esc="line.target_goal" /></span><t t-if="line.definition_suffix"> <t t-esc="line.definition_suffix"/></t> + <span t-attf-class="#{line.monetary ? 'oe_goal_field_monetary' : ''}" t-attf-data-id="#{line.monetary ? challenge.currency : ''}"><t t-esc="line.target" /></span><t t-if="line.suffix"> <t t-esc="line.suffix"/></t> </div> </div> </div> <div t-foreach="line.goals" t-as="goal" t-attf-class="#{goal.id == line.own_goal_id ? 'oe_bold' : ''}"> - <div t-attf-class="oe_row oe_goal_outer_box #{goal.state == 'reached' ? 'oe_goal_reached' : ''} #{line.definition_display != 'progress' ? 'oe_no_progress' : ''}"> - <t t-if="line.definition_display == 'progress'"> + <div t-attf-class="oe_row oe_goal_outer_box #{goal.state == 'reached' ? 'oe_goal_reached' : ''} #{line.display_mode != 'progress' ? 'oe_no_progress' : ''}"> + <t t-if="line.display_mode == 'progress'"> <div class="oe_goal_progress_background"></div> - <div class="oe_goal_progress" t-attf-style="#{line.definition_display == 'progress' ? 'width: '+goal.completeness+'%;' : 'width:0;'}"></div> + <div class="oe_goal_progress" t-attf-style="#{line.display_mode == 'progress' ? 'width: '+goal.completeness+'%;' : 'width:0;'}"></div> </t> <div class="oe_cell col0"><t t-esc="goal.rank" /></div> - <div class="oe_cell col1"><img class="oe_user_avatar" t-attf-alt="#{goal.user_name}" t-attf-data-id="#{goal.user_id}"/></div> + <div class="oe_cell col1"><img class="oe_user_avatar" t-attf-alt="#{goal.name}" t-attf-data-id="#{goal.user_id}"/></div> <div class="oe_cell col2"> - <t t-if="line.definition_display == 'progress'"> + <t t-if="line.display_mode == 'progress'"> <!-- progress, action on current value --> - <t t-esc="goal.user_name"/><br/> - <t t-if="goal.id != line.own_goal_id or (line.computation_mode != 'manually' and !line.definition_action)"> - <span t-attf-class="#{line.definition_monetary ? 'oe_goal_field_monetary' : ''}"><t t-esc="goal.current" /></span><t t-if="line.definition_suffix"> <t t-esc="line.definition_suffix"/></t> + <t t-esc="goal.name"/><br/> + <t t-if="goal.id != line.own_goal_id or (line.computation_mode != 'manually' and !line.action)"> + <span t-attf-class="#{line.monetary ? 'oe_goal_field_monetary' : ''}" t-attf-data-id="#{line.monetary ? challenge.currency : ''}"><t t-esc="goal.current" /></span><t t-if="line.suffix"> <t t-esc="line.suffix"/></t> </t> - <t t-if="goal.id == line.own_goal_id and (line.definition_action or line.computation_mode == 'manually')"> + <t t-if="goal.id == line.own_goal_id and (line.action or line.computation_mode == 'manually')"> <a class="oe_goal_action" t-att-id="line.own_goal_id"> - <span t-attf-class="#{line.definition_monetary ? 'oe_goal_field_monetary' : ''}"><t t-esc="goal.current" /></span><t t-if="line.definition_suffix"> <t t-esc="line.definition_suffix"/></t> + <span t-attf-class="#{line.monetary ? 'oe_goal_field_monetary' : ''}" t-attf-data-id="#{line.monetary ? challenge.currency : ''}"><t t-esc="goal.current" /></span><t t-if="line.suffix"> <t t-esc="line.suffix"/></t> </a> </t> </t> - <t t-if="line.definition_display != 'progress'"> + <t t-if="line.display_mode != 'progress'"> <!-- not progress, action on user name --> - <t t-if="goal.id != line.own_goal_id or (line.computation_mode != 'manually' and !line.definition_action)"> - <t t-esc="goal.user_name"/> + <t t-if="goal.id != line.own_goal_id or (line.computation_mode != 'manually' and !line.action)"> + <t t-esc="goal.name"/> </t> - <t t-if="goal.id == line.own_goal_id and (line.definition_action or line.computation_mode == 'manually')"> - <a class="oe_goal_action" t-att-id="line.own_goal_id"><t t-esc="goal.user_name"/></a> + <t t-if="goal.id == line.own_goal_id and (line.action or line.computation_mode == 'manually')"> + <a class="oe_goal_action" t-att-id="line.own_goal_id"><t t-esc="goal.name"/></a> </t> </t> </div> @@ -98,10 +100,10 @@ </div> </t> - <t t-name="gamification.challenge_suggestions"> + <t t-name="gamification.ChallengeSuggestion"> <div class="oe_goal"> <h4>Invited Challenges</h4> - <ul t-foreach="widget.challenge_suggestions.info" t-as="challenge" class="oe_goals_list"> + <ul t-foreach="challenges" t-as="challenge" class="oe_goals_list"> <li> <strong><a class="oe_challenge_reply" t-attf-title="#{challenge.description.value ? challenge.description.value : ''}" t-attf-id="{challenge.id}" title="more details..."><t t-esc="challenge.name"/></a></strong> </li> diff --git a/addons/gamification/templates/badge_received.mako b/addons/gamification/templates/badge_received.mako deleted file mode 100644 index b846ab7ff4f..00000000000 --- a/addons/gamification/templates/badge_received.mako +++ /dev/null @@ -1,17 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <style type="text_css">${css}</style> - </head> - <body> - <p>Congratulation, you have received the badge <strong>${badge_user.badge_id.name}</strong> ! - % if user_from - This badge was granted by <strong>${user_from.name}</strong>. - % endif - </p> - - % if badge_user.comment - <p><em>${badge_user.comment}</em></p> - % endif - </body> -</html>
\ No newline at end of file diff --git a/addons/gamification/templates/base.mako b/addons/gamification/templates/base.mako deleted file mode 100644 index d5bb0c24c99..00000000000 --- a/addons/gamification/templates/base.mako +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <style type="text_css">${css}</style> -</head> -<body> - <header> - <strong>${object.name}</strong> - </header> - <p class="oe_grey">${object.report_header or ''}</p> -<% block body %><% endblock %> - -</body>
\ No newline at end of file diff --git a/addons/gamification/templates/group_progress.mako b/addons/gamification/templates/group_progress.mako deleted file mode 100644 index 5d71c36032f..00000000000 --- a/addons/gamification/templates/group_progress.mako +++ /dev/null @@ -1,38 +0,0 @@ -<% extends 'base.mako' %> - -<% block body %> - % for line in lines_boards: - <table width="100%" border="1"> - <tr> - <th colspan="4">${line.goal_definition.name}</th> - </tr> - <tr> - <th>#</th> - <th>Person</th> - <th>Completeness</th> - <th>Current</th> - </tr> - % for idx, goal in line.board_goals: - % if idx < 3 or goal.user_id.id == uid: - <tr - % if goal.completeness >= 100: - style="font-weight:bold;" - % endif - > - <td>${idx+1}</td> - <td>${goal.user_id.name}</td> - <td>${goal.completeness}%</td> - <td>${goal.current}/${goal.target_goal} - % if goal.definition_suffix: - ${goal.definition_suffix} - % endif - </td> - </tr> - % endif - % endfor - </table> - - <br/><br/> - - % endfor -<% endblock %>
\ No newline at end of file diff --git a/addons/gamification/templates/personal_progress.mako b/addons/gamification/templates/personal_progress.mako deleted file mode 100644 index 85d2fbb2b16..00000000000 --- a/addons/gamification/templates/personal_progress.mako +++ /dev/null @@ -1,31 +0,0 @@ -<% extends 'base.mako' %> - -<% block body %><table width="100%" border="1"> - <tr> - <th>Goal</th> - <th>Target</th> - <th>Current</th> - <th>Completeness</th> - </tr> - % for goal in goals: - <tr - % if goal.completeness >= 100: - style="font-weight:bold;" - % endif - > - <td>${goal.definition_id.name}</td> - <td>${goal.target_goal} - % if goal.definition_suffix: - ${goal.definition_suffix} - % endif - </td> - <td>${goal.current} - % if goal.definition_suffix: - ${goal.definition_suffix} - % endif - </td> - <td>${goal.completeness} %</td> - </tr> - % endfor - </table> -<% endblock %>
\ No newline at end of file diff --git a/addons/gamification/templates/reminder.mako b/addons/gamification/templates/reminder.mako deleted file mode 100644 index 4d44861a0bc..00000000000 --- a/addons/gamification/templates/reminder.mako +++ /dev/null @@ -1,17 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <style type="text_css">${css}</style> -</head> -<body> - <header> - <strong>Reminder ${object.name}</strong> - </header> - - <p class="oe_grey">${object.report_header or ''}</p> - - <p>You have not updated your progress for the goal ${object.definition_id.name} (currently reached at ${object.completeness}%) for at least ${object.remind_update_delay} days. Do not forget to do it.</p> - - <p>If you have not changed your score yet, you can use the button "The current value is up to date" to indicate so.</p> -</body> -</html> diff --git a/addons/gamification/views/challenge.xml b/addons/gamification/views/challenge.xml index 5403630b5b6..973194738cd 100644 --- a/addons/gamification/views/challenge.xml +++ b/addons/gamification/views/challenge.xml @@ -76,7 +76,7 @@ <tree string="Line List" version="7.0" editable="bottom" > <field name="sequence" widget="handle"/> <field name="definition_id" on_change="on_change_definition_id(definition_id)" /> - <field name="definition_condition"/> + <field name="condition"/> <field name="target_goal"/> <field name="definition_full_suffix"/> </tree> @@ -101,6 +101,9 @@ <field name="invited_user_ids" widget="many2many_tags" /> </group> <group string="Notification Messages"> + <div class="oe_grey"> + <p>Depending on the Diasplay mode, reports will be individual or shared.</p> + </div> <field name="report_message_frequency" /> <field name="report_header" placeholder="e.g. The following message contains the current progress of the sale team..." attrs="{'invisible': [('report_message_frequency','=','never')]}" /> <field name="report_message_group_id" attrs="{'invisible': [('report_message_frequency','=','never')]}" /> @@ -247,7 +250,7 @@ <tree string="Challenge Lines" version="7.0" editable="bottom" > <field name="sequence" widget="handle"/> <field name="definition_id"/> - <field name="definition_condition"/> + <field name="condition"/> <field name="target_goal"/> <field name="definition_full_suffix"/> </tree> diff --git a/addons/gamification/views/goal.xml b/addons/gamification/views/goal.xml index dbb208ad5fd..d76b41882df 100644 --- a/addons/gamification/views/goal.xml +++ b/addons/gamification/views/goal.xml @@ -154,7 +154,7 @@ </div> <field name="user_id" /> <div class="oe_goal_state_block"> - <t t-if="record.definition_display.raw_value == 'checkbox'"> + <t t-if="record.definition_display.raw_value == 'boolean'"> <div class="oe_goal_state oe_e"> <t t-if="record.state.raw_value=='reached'"><span class="oe_green" title="Goal Reached">W</span></t> <t t-if="record.state.raw_value=='inprogress' || record.state.raw_value=='inprogress_update'"><span title="Goal in Progress">N</span></t> |
