[REF] gamification: pretty much changing half of the code to make tde happy...
bzr revid: mat@openerp.com-20131217161541-oxsgy7gmko2x6qui
This commit is contained in:
parent
3e028490f6
commit
122c15c48d
|
@ -19,8 +19,5 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import goal
|
||||
import goal_type_data
|
||||
import plan
|
||||
import res_users
|
||||
import badge
|
||||
import models
|
||||
import data
|
||||
|
|
|
@ -30,7 +30,7 @@ Gamification process
|
|||
The Gamification module provides ways to evaluate and motivate the users of OpenERP.
|
||||
|
||||
The users can be evaluated using goals and numerical objectives to reach.
|
||||
**Goals** are assigned through **plans** to evaluate and compare members of a team with each others and through time.
|
||||
**Goals** are assigned through **challenges** to evaluate and compare members of a team with each others and through time.
|
||||
|
||||
For non-numerical achievements, **badges** can be granted to users. From a simple "thank you" to an exceptional achievement, a badge is an easy way to exprimate gratitude to a user for their good work.
|
||||
|
||||
|
@ -38,24 +38,23 @@ Both goals and badges are flexibles and can be adapted to a large range of modul
|
|||
""",
|
||||
|
||||
'data': [
|
||||
'plan_view.xml',
|
||||
'badge_view.xml',
|
||||
'goal_view.xml',
|
||||
'cron.xml',
|
||||
'views/challenge.xml',
|
||||
'views/badge.xml',
|
||||
'views/goal.xml',
|
||||
'data/cron.xml',
|
||||
'security/gamification_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'goal_base_data.xml',
|
||||
'badge_data.xml',
|
||||
'data/goal_base.xml',
|
||||
'data/badge.xml',
|
||||
],
|
||||
'test': [
|
||||
'test/goal_demo.yml'
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'auto_install': True,
|
||||
'auto_install': False,
|
||||
|
||||
'css': ['static/src/css/gamification.css'],
|
||||
'js': [
|
||||
'static/src/js/gamification.js',
|
||||
],
|
||||
'js': ['static/src/js/gamification.js',],
|
||||
'qweb': ['static/src/xml/gamification.xml'],
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013 OpenERP SA (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import goal_definition
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record forcecreate="True" id="ir_cron_check_plan"
|
||||
<record forcecreate="True" id="ir_cron_check_challenge"
|
||||
model="ir.cron">
|
||||
<field name="name">Run Goal Plan Checker</field>
|
||||
<field name="name">Run Goal Challenge Checker</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall" />
|
||||
<field name="model">gamification.goal.plan</field>
|
||||
<field name="model">gamification.challenge</field>
|
||||
<field name="function">_cron_update</field>
|
||||
<field name="args">()</field>
|
||||
</record>
|
|
@ -2,8 +2,8 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- goal types -->
|
||||
<record model="gamification.goal.type" id="type_base_timezone">
|
||||
<!-- goal definitions -->
|
||||
<record model="gamification.goal.definition" id="definition_base_timezone">
|
||||
<field name="name">Set your Timezone</field>
|
||||
<field name="description">Configure your profile and specify your timezone</field>
|
||||
<field name="computation_mode">count</field>
|
||||
|
@ -14,7 +14,7 @@
|
|||
<field name="res_id_field">user.id</field>
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.type" id="type_base_avatar">
|
||||
<record model="gamification.goal.definition" id="definition_base_avatar">
|
||||
<field name="name">Set your Avatar</field>
|
||||
<field name="description">In your user preference</field>
|
||||
<field name="computation_mode">manually</field>
|
||||
|
@ -25,7 +25,7 @@
|
|||
</record>
|
||||
|
||||
|
||||
<record model="gamification.goal.type" id="type_base_company_data">
|
||||
<record model="gamification.goal.definition" id="definition_base_company_data">
|
||||
<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>
|
||||
|
@ -37,7 +37,7 @@
|
|||
<field name="res_id_field">user.company_id.id</field>
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.type" id="type_base_company_logo">
|
||||
<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>
|
||||
|
@ -58,7 +58,7 @@
|
|||
<field name="help">Create and manage users that will connect to the system. Users can be deactivated should there be a period of time during which they will/should not connect to the system. You can assign them groups in order to give them specific access to the applications they need to use in the system.</field>
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.type" id="type_base_invite">
|
||||
<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>
|
||||
|
@ -68,7 +68,7 @@
|
|||
<field name="action_id" eval="ref('action_new_simplified_res_users')" />
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.type" id="type_nbr_following">
|
||||
<record model="gamification.goal.definition" id="definition_nbr_following">
|
||||
<field name="name">Mail Group Following</field>
|
||||
<field name="description">Follow mail groups to receive news</field>
|
||||
<field name="computation_mode">python</field>
|
||||
|
@ -77,8 +77,8 @@
|
|||
</record>
|
||||
|
||||
|
||||
<!-- plans -->
|
||||
<record model="gamification.goal.plan" id="plan_base_discover">
|
||||
<!-- challenges -->
|
||||
<record model="gamification.challenge" id="challenge_base_discover">
|
||||
<field name="name">Complete your Profile</field>
|
||||
<field name="period">once</field>
|
||||
<field name="visibility_mode">progressbar</field>
|
||||
|
@ -88,7 +88,7 @@
|
|||
<field name="category">other</field>
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.plan" id="plan_base_configure">
|
||||
<record model="gamification.challenge" id="challenge_base_configure">
|
||||
<field name="name">Setup your Company</field>
|
||||
<field name="period">once</field>
|
||||
<field name="visibility_mode">progressbar</field>
|
||||
|
@ -98,32 +98,32 @@
|
|||
<field name="category">other</field>
|
||||
</record>
|
||||
|
||||
<!-- planlines -->
|
||||
<record model="gamification.goal.planline" id="planline_base_discover1">
|
||||
<field name="type_id" eval="ref('type_base_timezone')" />
|
||||
<!-- lines -->
|
||||
<record model="gamification.challenge.line" id="line_base_discover1">
|
||||
<field name="definition_id" eval="ref('definition_base_timezone')" />
|
||||
<field name="target_goal">1</field>
|
||||
<field name="plan_id" eval="ref('plan_base_discover')" />
|
||||
<field name="challenge_id" eval="ref('challenge_base_discover')" />
|
||||
</record>
|
||||
<record model="gamification.goal.planline" id="planline_base_discover2">
|
||||
<field name="type_id" eval="ref('type_base_avatar')" />
|
||||
<record model="gamification.challenge.line" id="line_base_discover2">
|
||||
<field name="definition_id" eval="ref('definition_base_avatar')" />
|
||||
<field name="target_goal">1</field>
|
||||
<field name="plan_id" eval="ref('plan_base_discover')" />
|
||||
<field name="challenge_id" eval="ref('challenge_base_discover')" />
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.planline" id="planline_base_admin2">
|
||||
<field name="type_id" eval="ref('type_base_company_logo')" />
|
||||
<record model="gamification.challenge.line" id="line_base_admin2">
|
||||
<field name="definition_id" eval="ref('definition_base_company_logo')" />
|
||||
<field name="target_goal">1</field>
|
||||
<field name="plan_id" eval="ref('plan_base_configure')" />
|
||||
<field name="challenge_id" eval="ref('challenge_base_configure')" />
|
||||
</record>
|
||||
<record model="gamification.goal.planline" id="planline_base_admin1">
|
||||
<field name="type_id" eval="ref('type_base_company_data')" />
|
||||
<record model="gamification.challenge.line" id="line_base_admin1">
|
||||
<field name="definition_id" eval="ref('definition_base_company_data')" />
|
||||
<field name="target_goal">0</field>
|
||||
<field name="plan_id" eval="ref('plan_base_configure')" />
|
||||
<field name="challenge_id" eval="ref('challenge_base_configure')" />
|
||||
</record>
|
||||
<record model="gamification.goal.planline" id="planline_base_admin3">
|
||||
<field name="type_id" eval="ref('type_base_invite')" />
|
||||
<record model="gamification.challenge.line" id="line_base_admin3">
|
||||
<field name="definition_id" eval="ref('definition_base_invite')" />
|
||||
<field name="target_goal">1</field>
|
||||
<field name="plan_id" eval="ref('plan_base_configure')" />
|
||||
<field name="challenge_id" eval="ref('challenge_base_configure')" />
|
||||
</record>
|
||||
</data>
|
||||
|
||||
|
@ -141,7 +141,7 @@
|
|||
|
||||
<p class="oe_grey">${object.report_header or ''}</p>
|
||||
|
||||
<p>You have not updated your progress for the goal ${object.type_id.name} (currently reached at ${object.completeness}%) for at least ${object.remind_update_delay} days. Do not forget to do it.</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>
|
||||
]]></field>
|
||||
|
@ -168,15 +168,15 @@
|
|||
style="font-weight:bold;"
|
||||
% endif
|
||||
>
|
||||
<td>${goal.type_id.name}</td>
|
||||
<td>${goal.definition_id.name}</td>
|
||||
<td>${goal.target_goal}
|
||||
% if goal.type_suffix:
|
||||
${goal.type_suffix}
|
||||
% if goal.definition_suffix:
|
||||
${goal.definition_suffix}
|
||||
% endif
|
||||
</td>
|
||||
<td>${goal.current}
|
||||
% if goal.type_suffix:
|
||||
${goal.type_suffix}
|
||||
% if goal.definition_suffix:
|
||||
${goal.definition_suffix}
|
||||
% endif
|
||||
</td>
|
||||
<td>${goal.completeness} %</td>
|
||||
|
@ -193,10 +193,10 @@
|
|||
</header>
|
||||
<p class="oe_grey">${object.report_header or ''}</p>
|
||||
|
||||
% for planline in ctx['planlines_boards']:
|
||||
% for line in ctx['lines_boards']:
|
||||
<table width="100%" border="1">
|
||||
<tr>
|
||||
<th colspan="4">${planline.goal_type.name}</th>
|
||||
<th colspan="4">${line.goal_definition.name}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
|
@ -204,7 +204,7 @@
|
|||
<th>Completeness</th>
|
||||
<th>Current</th>
|
||||
</tr>
|
||||
% for idx, goal in planline.board_goals:
|
||||
% for idx, goal in line.board_goals:
|
||||
% if idx < 3 or goal.user_id.id == user.id:
|
||||
<tr
|
||||
% if goal.completeness >= 100:
|
||||
|
@ -215,8 +215,8 @@
|
|||
<td>${goal.user_id.name}</td>
|
||||
<td>${goal.completeness}%</td>
|
||||
<td>${goal.current}/${goal.target_goal}
|
||||
% if goal.type_suffix:
|
||||
${goal.type_suffix}
|
||||
% if goal.definition_suffix:
|
||||
${goal.definition_suffix}
|
||||
% endif
|
||||
</td>
|
||||
</tr>
|
|
@ -22,14 +22,14 @@
|
|||
from openerp.osv import osv
|
||||
|
||||
|
||||
class gamification_goal_type_data(osv.Model):
|
||||
"""Goal type data
|
||||
class gamification_goal_definition_data(osv.Model):
|
||||
"""Goal definition data
|
||||
|
||||
Methods for more complex goals not possible with the 'sum' and 'count' mode.
|
||||
Each method should return the value that will be set in the 'current' field
|
||||
of a user's goal. The return type must be a float or integer.
|
||||
of a user's goal. The return definition must be a float or integer.
|
||||
"""
|
||||
_inherit = 'gamification.goal.type'
|
||||
_inherit = 'gamification.goal.definition'
|
||||
|
||||
def number_following(self, cr, uid, xml_id="mail.thread", context=None):
|
||||
"""Return the number of 'xml_id' objects the user is following
|
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013 OpenERP SA (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import goal
|
||||
import challenge
|
||||
import res_users
|
||||
import badge
|
|
@ -141,11 +141,11 @@ class gamification_badge(osv.Model):
|
|||
'remaining_sending': fields.function(_remaining_sending_calc, type='integer',
|
||||
string='Remaining Sending Allowed', help="If a maxium is set"),
|
||||
|
||||
'plan_ids': fields.one2many('gamification.goal.plan', 'reward_id',
|
||||
'challenge_ids': fields.one2many('gamification.challenge', 'reward_id',
|
||||
string="Reward of Challenges"),
|
||||
|
||||
'goal_type_ids': fields.many2many('gamification.goal.type',
|
||||
string='Goals Linked',
|
||||
'goal_definition_ids': fields.many2many('gamification.goal.definition', 'badge_unlocked_definition_rel',
|
||||
string='Rewarded by',
|
||||
help="The users that have succeeded theses goals will receive automatically the badge."),
|
||||
|
||||
'owner_ids': fields.one2many('gamification.badge.user', 'badge_id',
|
|
@ -61,19 +61,19 @@ def start_end_date_for_period(period, default_start_date=False, default_end_date
|
|||
return (start_date, end_date)
|
||||
|
||||
|
||||
class gamification_goal_plan(osv.Model):
|
||||
"""Gamification goal plan
|
||||
class gamification_challenge(osv.Model):
|
||||
"""Gamification challenge
|
||||
|
||||
Set of predifined goals to be able to automate goal settings or
|
||||
quickly apply several goals manually to a group of users
|
||||
Set of predifined objectives assigned to people with rules for recurrence and
|
||||
rewards
|
||||
|
||||
If 'user_ids' is defined and 'period' is different than 'one', the set will
|
||||
be assigned to the users for each period (eg: every 1st of each month if
|
||||
'monthly' is selected)
|
||||
"""
|
||||
|
||||
_name = 'gamification.goal.plan'
|
||||
_description = 'Gamification goal plan'
|
||||
_name = 'gamification.challenge'
|
||||
_description = 'Gamification challenge'
|
||||
_inherit = 'mail.thread'
|
||||
|
||||
def _get_next_report_date(self, cr, uid, ids, field_name, arg, context=None):
|
||||
|
@ -82,32 +82,27 @@ class gamification_goal_plan(osv.Model):
|
|||
|
||||
:return: a string in DEFAULT_SERVER_DATE_FORMAT representing the date"""
|
||||
res = {}
|
||||
for plan in self.browse(cr, uid, ids, context):
|
||||
last = datetime.strptime(plan.last_report_date, DF).date()
|
||||
if plan.report_message_frequency == 'daily':
|
||||
for challenge in self.browse(cr, uid, ids, context):
|
||||
last = datetime.strptime(challenge.last_report_date, DF).date()
|
||||
if challenge.report_message_frequency == 'daily':
|
||||
next = last + timedelta(days=1)
|
||||
res[plan.id] = next.strftime(DF)
|
||||
elif plan.report_message_frequency == 'weekly':
|
||||
res[challenge.id] = next.strftime(DF)
|
||||
elif challenge.report_message_frequency == 'weekly':
|
||||
next = last + timedelta(days=7)
|
||||
res[plan.id] = next.strftime(DF)
|
||||
elif plan.report_message_frequency == 'monthly':
|
||||
res[challenge.id] = next.strftime(DF)
|
||||
elif challenge.report_message_frequency == 'monthly':
|
||||
month_range = calendar.monthrange(last.year, last.month)
|
||||
next = last.replace(day=month_range[1]) + timedelta(days=1)
|
||||
res[plan.id] = next.strftime(DF)
|
||||
elif plan.report_message_frequency == 'yearly':
|
||||
res[plan.id] = last.replace(year=last.year + 1).strftime(DF)
|
||||
res[challenge.id] = next.strftime(DF)
|
||||
elif challenge.report_message_frequency == 'yearly':
|
||||
res[challenge.id] = last.replace(year=last.year + 1).strftime(DF)
|
||||
# frequency == 'once', reported when closed only
|
||||
else:
|
||||
res[plan.id] = False
|
||||
res[challenge.id] = False
|
||||
|
||||
return res
|
||||
|
||||
def _planline_count(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = dict.fromkeys(ids, 0)
|
||||
for plan in self.browse(cr, uid, ids, context):
|
||||
res[plan.id] = len(plan.planline_ids)
|
||||
return res
|
||||
|
||||
_sort = 'end_date, start_date, name, id'
|
||||
_columns = {
|
||||
'name': fields.char('Challenge Name', required=True, translate=True),
|
||||
'description': fields.text('Description', translate=True),
|
||||
|
@ -123,10 +118,10 @@ class gamification_goal_plan(osv.Model):
|
|||
|
||||
'user_ids': fields.many2many('res.users', 'user_ids',
|
||||
string='Users',
|
||||
help="List of users to which the goal will be set"),
|
||||
help="List of users participating to the challenge"),
|
||||
'autojoin_group_id': fields.many2one('res.groups',
|
||||
string='Auto-subscription Group',
|
||||
help='Group of users whose members will automatically be added to the users'),
|
||||
help='Group of users whose members will be automatically added to user_ids once the challenge is started'),
|
||||
|
||||
'period': fields.selection([
|
||||
('once', 'Non recurring'),
|
||||
|
@ -143,14 +138,13 @@ class gamification_goal_plan(osv.Model):
|
|||
'end_date': fields.date('End Date',
|
||||
help="The day a new challenge will be automatically closed. If no periodicity is set, will use this date as the goal end date."),
|
||||
|
||||
'proposed_user_ids': fields.many2many('res.users', 'proposed_user_ids',
|
||||
'invited_user_ids': fields.many2many('res.users', 'invited_user_ids',
|
||||
string="Suggest to users"),
|
||||
|
||||
'planline_ids': fields.one2many('gamification.goal.planline', 'plan_id',
|
||||
string='Planline',
|
||||
'line_ids': fields.one2many('gamification.challenge.line', 'challenge_id',
|
||||
string='Lines',
|
||||
help="List of goals that will be set",
|
||||
required=True),
|
||||
'planline_count': fields.function(_planline_count, type='integer', string="Planlines"),
|
||||
|
||||
'reward_id': fields.many2one('gamification.badge', string="For Every Succeding User"),
|
||||
'reward_first_id': fields.many2one('gamification.badge', string="For 1st user"),
|
||||
|
@ -202,70 +196,53 @@ class gamification_goal_plan(osv.Model):
|
|||
'reward_failure': False,
|
||||
}
|
||||
|
||||
_sort = 'end_date, start_date, name'
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
"""Overwrite the write method to add the user of groups"""
|
||||
context = context or {}
|
||||
if not ids:
|
||||
return True
|
||||
|
||||
# unsubscribe removed users from the plan
|
||||
# users are not able to manually unsubscribe to challenges so should
|
||||
# do it for them when not concerned anymore
|
||||
if vals.get('user_ids'):
|
||||
for action_tuple in vals['user_ids']:
|
||||
if action_tuple[0] == 3:
|
||||
# form (3, ID), remove one
|
||||
self.message_unsubscribe_users(cr, uid, ids, [action_tuple[1]], context=context)
|
||||
if action_tuple[0] == 5:
|
||||
# form (5,), remove all
|
||||
for plan in self.browse(cr, uid, ids, context=context):
|
||||
self.message_unsubscribe_users(cr, uid, [plan.id], [user.id for user in plan.user_ids], context=context)
|
||||
if action_tuple[0] == 6:
|
||||
# form (6, False, [IDS]), replace by IDS
|
||||
for plan in self.browse(cr, uid, ids, context=context):
|
||||
removed_users = set([user.id for user in plan.user_ids]) - set(action_tuple[2])
|
||||
self.message_unsubscribe_users(cr, uid, [plan.id], list(removed_users), context=context)
|
||||
|
||||
write_res = super(gamification_goal_plan, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
# add users when change the group auto-subscription
|
||||
if 'autojoin_group_id' in vals:
|
||||
if vals.get('autojoin_group_id'):
|
||||
new_group = self.pool.get('res.groups').browse(cr, uid, vals['autojoin_group_id'], context=context)
|
||||
group_user_ids = [user.id for user in new_group.users]
|
||||
for plan in self.browse(cr, uid, ids, context=context):
|
||||
self.write(cr, uid, [plan.id], {'user_ids': [(4, user) for user in group_user_ids]}, context=context)
|
||||
|
||||
# subscribe new users to the plan
|
||||
if 'user_ids' in vals:
|
||||
for plan in self.browse(cr, uid, ids, context=context):
|
||||
self.message_subscribe_users(cr, uid, ids, [user.id for user in plan.user_ids], context=context)
|
||||
if 'user_ids' not in vals:
|
||||
vals['user_ids'] = []
|
||||
vals['user_ids'] += [(4, user.id) for user in new_group.users]
|
||||
|
||||
write_res = super(gamification_challenge, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
# subscribe new users to the challenge
|
||||
if vals.get('user_ids'):
|
||||
# done with browse after super if changes in groups
|
||||
for challenge in self.browse(cr, uid, ids, context=context):
|
||||
self.message_subscribe_users(cr, uid, [challenge.id], [user.id for user in challenge.user_ids], context=context)
|
||||
|
||||
return write_res
|
||||
|
||||
|
||||
##### Update #####
|
||||
|
||||
def _cron_update(self, cr, uid, context=None, ids=False):
|
||||
"""Daily cron check.
|
||||
|
||||
Start planned plans (in draft and with start_date = today)
|
||||
Create the goals for planlines not linked to goals (eg: modified the
|
||||
plan to add planlines)
|
||||
Update every plan running
|
||||
- Start planned challenges (in draft and with start_date = today)
|
||||
- Create the missing goals (eg: modified the challenge to add lines)
|
||||
- Update every running challenge
|
||||
"""
|
||||
if not context: context = {}
|
||||
|
||||
# start planned plans
|
||||
planned_plan_ids = self.search(cr, uid, [
|
||||
# start planned challenges
|
||||
planned_challenge_ids = self.search(cr, uid, [
|
||||
('state', '=', 'draft'),
|
||||
('start_date', '<=', fields.date.today())])
|
||||
self.action_start(cr, uid, planned_plan_ids, context=context)
|
||||
self.action_start(cr, uid, planned_challenge_ids, context=context)
|
||||
|
||||
# close planned plans
|
||||
planned_plan_ids = self.search(cr, uid, [
|
||||
# close planned challenges
|
||||
planned_challenge_ids = self.search(cr, uid, [
|
||||
('state', '=', 'inprogress'),
|
||||
('end_date', '>=', fields.date.today())])
|
||||
self.action_close(cr, uid, planned_plan_ids, context=context)
|
||||
self.action_close(cr, uid, planned_challenge_ids, context=context)
|
||||
|
||||
if not ids:
|
||||
ids = self.search(cr, uid, [('state', '=', 'inprogress')], context=context)
|
||||
|
@ -273,17 +250,17 @@ class gamification_goal_plan(osv.Model):
|
|||
return self._update_all(cr, uid, ids, context=context)
|
||||
|
||||
def _update_all(self, cr, uid, ids, context=None):
|
||||
"""Update the plans and related goals
|
||||
"""Update the challenges and related goals
|
||||
|
||||
:param list(int) ids: the ids of the plans to update, if False will
|
||||
update only plans in progress."""
|
||||
:param list(int) ids: the ids of the challenges to update, if False will
|
||||
update only challenges in progress."""
|
||||
if not context: context = {}
|
||||
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, [
|
||||
('plan_id', 'in', ids),
|
||||
('challenge_id', 'in', ids),
|
||||
'|',
|
||||
('state', 'in', ('inprogress', 'inprogress_update')),
|
||||
'&',
|
||||
|
@ -292,121 +269,123 @@ class gamification_goal_plan(osv.Model):
|
|||
('end_date', '>=', yesterday.strftime(DF)),
|
||||
('end_date', '=', False)
|
||||
], context=context)
|
||||
# update every running goal already generated linked to selected plans
|
||||
# update every running goal already generated linked to selected challenges
|
||||
goal_obj.update(cr, uid, goal_ids, context=context)
|
||||
|
||||
for plan in self.browse(cr, uid, ids, context=context):
|
||||
if plan.autojoin_group_id:
|
||||
# check in case of new users in plan, this happens if manager removed users in plan manually
|
||||
self.write(cr, uid, [plan.id], {'user_ids': [(4, user.id) for user in plan.autojoin_group_id.users]}, context=context)
|
||||
self.generate_goals_from_plan(cr, uid, [plan.id], context=context)
|
||||
for challenge in self.browse(cr, uid, ids, context=context):
|
||||
if challenge.autojoin_group_id:
|
||||
# check in case of new users in challenge, this happens if manager removed users in challenge manually
|
||||
self.write(cr, uid, [challenge.id], {'user_ids': [(4, user.id) for user in challenge.autojoin_group_id.users]}, context=context)
|
||||
self.generate_goals_from_challenge(cr, uid, [challenge.id], context=context)
|
||||
|
||||
# goals closed but still opened at the 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)
|
||||
('challenge_id', '=', challenge.id),
|
||||
('start_date', '>=', challenge.last_report_date),
|
||||
('end_date', '<=', challenge.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.report_progress(cr, uid, challenge, subset_goal_ids=closed_goals_to_report, context=context)
|
||||
|
||||
if fields.date.today() == plan.next_report_date:
|
||||
self.report_progress(cr, uid, plan, context=context)
|
||||
if fields.date.today() == challenge.next_report_date:
|
||||
self.report_progress(cr, uid, challenge, context=context)
|
||||
|
||||
self.check_challenge_reward(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def quick_update(self, cr, uid, plan_id, context=None):
|
||||
"""Update all the goals of a plan, no generation of new goals"""
|
||||
def quick_update(self, cr, uid, challenge_id, context=None):
|
||||
"""Update all the goals of a challenge, no generation of new goals"""
|
||||
if not context: context = {}
|
||||
goal_ids = self.pool.get('gamification.goal').search(cr, uid, [('plan_id', '=', plan_id)], context=context)
|
||||
goal_ids = self.pool.get('gamification.goal').search(cr, uid, [('challenge_id', '=', challenge_id)], context=context)
|
||||
self.pool.get('gamification.goal').update(cr, uid, goal_ids, context=context)
|
||||
return True
|
||||
|
||||
|
||||
##### User actions #####
|
||||
|
||||
def action_start(self, cr, uid, ids, context=None):
|
||||
"""Start a draft goal plan
|
||||
"""Start a draft challenge
|
||||
|
||||
Change the state of the plan to in progress and generate related goals
|
||||
Change the state of the challenge to in progress and generate related goals
|
||||
"""
|
||||
# subscribe users if autojoin group
|
||||
for plan in self.browse(cr, uid, ids, context=context):
|
||||
if plan.autojoin_group_id:
|
||||
self.write(cr, uid, [plan.id], {'user_ids': [(4, user.id) for user in plan.autojoin_group_id.users]}, context=context)
|
||||
for challenge in self.browse(cr, uid, ids, context=context):
|
||||
if challenge.autojoin_group_id:
|
||||
self.write(cr, uid, [challenge.id], {'user_ids': [(4, user.id) for user in challenge.autojoin_group_id.users]}, context=context)
|
||||
|
||||
self.write(cr, uid, plan.id, {'state': 'inprogress'}, context=context)
|
||||
self.message_post(cr, uid, plan.id, body="New challenge started.", context=context)
|
||||
return self.generate_goals_from_plan(cr, uid, ids, context=context)
|
||||
self.write(cr, uid, challenge.id, {'state': 'inprogress'}, context=context)
|
||||
self.message_post(cr, uid, challenge.id, body="New challenge started.", context=context)
|
||||
return self.generate_goals_from_challenge(cr, uid, ids, context=context)
|
||||
|
||||
def action_check(self, cr, uid, ids, context=None):
|
||||
"""Check a goal plan
|
||||
"""Check a challenge
|
||||
|
||||
Create goals that haven't been created yet (eg: if added users of planlines)
|
||||
Create goals that haven't been created yet (eg: if added users)
|
||||
Recompute the current value for each goal related"""
|
||||
return self._update_all(cr, uid, ids=ids, context=context)
|
||||
|
||||
def action_close(self, cr, uid, ids, context=None):
|
||||
"""Close a plan in progress
|
||||
"""Close a challenge in progress
|
||||
|
||||
Change the state of the plan to in done
|
||||
Change the state of the challenge to in done
|
||||
Does NOT close the related goals, this is handled by the goal itself"""
|
||||
self.check_challenge_reward(cr, uid, ids, force=True, context=context)
|
||||
return self.write(cr, uid, ids, {'state': 'done'}, context=context)
|
||||
|
||||
def action_reset(self, cr, uid, ids, context=None):
|
||||
"""Reset a closed goal plan
|
||||
"""Reset a closed challenge
|
||||
|
||||
Change the state of the plan to in progress
|
||||
Closing a plan does not affect the goals so neither does reset"""
|
||||
Change the state of the challenge to in progress
|
||||
Closing a challenge does not affect the goals so neither does reset"""
|
||||
return self.write(cr, uid, ids, {'state': 'inprogress'}, context=context)
|
||||
|
||||
def action_cancel(self, cr, uid, ids, context=None):
|
||||
"""Cancel a plan in progress
|
||||
"""Cancel a challenge in progress
|
||||
|
||||
Change the state of the plan to draft
|
||||
Change the state of the challenge to draft
|
||||
Cancel the related goals"""
|
||||
self.write(cr, uid, ids, {'state': 'draft'}, context=context)
|
||||
goal_ids = self.pool.get('gamification.goal').search(cr, uid, [('plan_id', 'in', ids)], context=context)
|
||||
goal_ids = self.pool.get('gamification.goal').search(cr, uid, [('challenge_id', 'in', ids)], context=context)
|
||||
self.pool.get('gamification.goal').write(cr, uid, goal_ids, {'state': 'canceled'}, context=context)
|
||||
|
||||
return True
|
||||
|
||||
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)
|
||||
for challenge in self.browse(cr, uid, ids, context):
|
||||
self.report_progress(cr, uid, challenge, context=context)
|
||||
return True
|
||||
|
||||
|
||||
##### Automatic actions #####
|
||||
|
||||
def generate_goals_from_plan(self, cr, uid, ids, context=None):
|
||||
"""Generate the list of goals linked to a plan.
|
||||
def generate_goals_from_challenge(self, cr, uid, ids, context=None):
|
||||
"""Generate the goals for each line and user.
|
||||
|
||||
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"""
|
||||
If goals already exist for this line and user, the line is skipped. This
|
||||
can be called after each change in the list of users or lines.
|
||||
:param list(int) ids: the list of challenge concerned"""
|
||||
|
||||
for plan in self.browse(cr, uid, ids, context):
|
||||
(start_date, end_date) = start_end_date_for_period(plan.period)
|
||||
for challenge in self.browse(cr, uid, ids, context):
|
||||
(start_date, end_date) = start_end_date_for_period(challenge.period)
|
||||
|
||||
# if no periodicity, use plan dates
|
||||
if not start_date and plan.start_date:
|
||||
start_date = plan.start_date
|
||||
if not end_date and plan.end_date:
|
||||
end_date = plan.end_date
|
||||
# if no periodicity, use challenge dates
|
||||
if not start_date and challenge.start_date:
|
||||
start_date = challenge.start_date
|
||||
if not end_date and challenge.end_date:
|
||||
end_date = challenge.end_date
|
||||
|
||||
for planline in plan.planline_ids:
|
||||
for user in plan.user_ids:
|
||||
for line in challenge.line_ids:
|
||||
for user in challenge.user_ids:
|
||||
|
||||
goal_obj = self.pool.get('gamification.goal')
|
||||
domain = [('planline_id', '=', planline.id), ('user_id', '=', user.id)]
|
||||
domain = [('line_id', '=', line.id), ('user_id', '=', user.id)]
|
||||
if start_date:
|
||||
domain.append(('start_date', '=', start_date))
|
||||
|
||||
# goal already existing for this planline ?
|
||||
# goal already existing for this line ?
|
||||
if len(goal_obj.search(cr, uid, domain, context=context)) > 0:
|
||||
|
||||
# resume canceled goals
|
||||
|
@ -419,10 +398,10 @@ class gamification_goal_plan(osv.Model):
|
|||
continue
|
||||
|
||||
values = {
|
||||
'type_id': planline.type_id.id,
|
||||
'planline_id': planline.id,
|
||||
'definition_id': line.definition_id.id,
|
||||
'line_id': line.id,
|
||||
'user_id': user.id,
|
||||
'target_goal': planline.target_goal,
|
||||
'target_goal': line.target_goal,
|
||||
'state': 'inprogress',
|
||||
}
|
||||
|
||||
|
@ -431,8 +410,8 @@ class gamification_goal_plan(osv.Model):
|
|||
if end_date:
|
||||
values['end_date'] = end_date
|
||||
|
||||
if planline.plan_id.remind_update_delay:
|
||||
values['remind_update_delay'] = planline.plan_id.remind_update_delay
|
||||
if challenge.remind_update_delay:
|
||||
values['remind_update_delay'] = challenge.remind_update_delay
|
||||
|
||||
new_goal_id = goal_obj.create(cr, uid, values, context)
|
||||
|
||||
|
@ -442,17 +421,17 @@ class gamification_goal_plan(osv.Model):
|
|||
|
||||
##### JS utilities #####
|
||||
|
||||
def get_board_goal_info(self, cr, uid, plan, subset_goal_ids=False, context=None):
|
||||
"""Get the list of latest goals for a plan, sorted by user ranking for each planline"""
|
||||
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"""
|
||||
|
||||
goal_obj = self.pool.get('gamification.goal')
|
||||
planlines_boards = []
|
||||
(start_date, end_date) = start_end_date_for_period(plan.period)
|
||||
lines_boards = []
|
||||
(start_date, end_date) = start_end_date_for_period(challenge.period)
|
||||
|
||||
for planline in plan.planline_ids:
|
||||
for line in challenge.line_ids:
|
||||
|
||||
domain = [
|
||||
('planline_id', '=', planline.id),
|
||||
('line_id', '=', line.id),
|
||||
('state', 'in', ('inprogress', 'inprogress_update',
|
||||
'reached', 'failed')),
|
||||
]
|
||||
|
@ -471,24 +450,24 @@ class gamification_goal_plan(osv.Model):
|
|||
board_goals = [goal for goal in goal_obj.browse(cr, uid, common_goal_ids, context=context)]
|
||||
|
||||
if len(board_goals) == 0:
|
||||
# planline has no generated goals
|
||||
# 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))
|
||||
planlines_boards.append({'goal_type': planline.type_id, 'board_goals': sorted_board, 'target_goal': planline.target_goal})
|
||||
return planlines_boards
|
||||
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, plan, subset_goal_ids=False, context=None):
|
||||
"""Get the list of latest goals of a user for a plan"""
|
||||
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 = [
|
||||
('plan_id', '=', plan.id),
|
||||
('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(plan.period)
|
||||
(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
|
||||
|
@ -510,7 +489,7 @@ class gamification_goal_plan(osv.Model):
|
|||
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 plan run
|
||||
# do not include goals of previous challenge run
|
||||
continue
|
||||
else:
|
||||
all_done = False
|
||||
|
@ -521,24 +500,24 @@ class gamification_goal_plan(osv.Model):
|
|||
goals.append(goal)
|
||||
|
||||
if all_done:
|
||||
# skip plans where all goal are done or failed
|
||||
# skip challenges where all goal are done or failed
|
||||
return False
|
||||
else:
|
||||
return goals
|
||||
|
||||
##### Reporting #####
|
||||
|
||||
def report_progress(self, cr, uid, plan, context=None, users=False, subset_goal_ids=False):
|
||||
def report_progress(self, cr, uid, challenge, 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 challenge: the challenge object that need to be reported
|
||||
: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
|
||||
(goal users and group that receive a copy). Only used for challenge with
|
||||
a visibility mode set to 'personal'.
|
||||
: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
|
||||
:param goal_ids: the list(int) of goal ids linked to the challenge for
|
||||
the report. If not specified, use the goals for the current challenge
|
||||
period. This parameter can be used to produce report for previous challenge
|
||||
periods.
|
||||
:param subset_goal_ids: a list(int) of goal ids to restrict the report
|
||||
"""
|
||||
|
@ -547,81 +526,81 @@ class gamification_goal_plan(osv.Model):
|
|||
# template_env = TemplateHelper()
|
||||
temp_obj = self.pool.get('email.template')
|
||||
ctx = context.copy()
|
||||
if plan.visibility_mode == 'board':
|
||||
planlines_boards = self.get_board_goal_info(cr, uid, plan, subset_goal_ids, context)
|
||||
if challenge.visibility_mode == 'board':
|
||||
lines_boards = self.get_board_goal_info(cr, uid, challenge, subset_goal_ids, context)
|
||||
|
||||
ctx.update({'planlines_boards': planlines_boards})
|
||||
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.goal.plan', plan.id, context=context)
|
||||
body_html = temp_obj.render_template(cr, uid, template_id.body_html, 'gamification.challenge', challenge.id, context=context)
|
||||
|
||||
# body_html = template_env.get_template('group_progress.mako').render({'object': plan, 'planlines_boards': planlines_boards, 'uid': uid})
|
||||
# body_html = template_env.get_template('group_progress.mako').render({'object': challenge, 'lines_boards': lines_boards, 'uid': uid})
|
||||
|
||||
# send to every follower of the plan
|
||||
self.message_post(cr, uid, plan.id,
|
||||
# send to every follower of the challenge
|
||||
self.message_post(cr, uid, challenge.id,
|
||||
body=body_html,
|
||||
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,
|
||||
if challenge.report_message_group_id:
|
||||
self.pool.get('mail.group').message_post(cr, uid, challenge.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:
|
||||
goals = self.get_indivual_goal_info(cr, uid, user.id, plan, subset_goal_ids, context=context)
|
||||
for user in users or challenge.user_ids:
|
||||
goals = self.get_indivual_goal_info(cr, uid, user.id, challenge, subset_goal_ids, context=context)
|
||||
if not goals:
|
||||
continue
|
||||
|
||||
ctx.update({'goals': 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.goal.plan', plan.id, context=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
|
||||
self.message_post(cr, uid, 0,
|
||||
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,
|
||||
if challenge.report_message_group_id:
|
||||
self.pool.get('mail.group').message_post(cr, uid, challenge.report_message_group_id.id,
|
||||
body=body_html,
|
||||
context=context,
|
||||
subtype='mail.mt_comment')
|
||||
return self.write(cr, uid, plan.id, {'last_report_date': fields.date.today()}, context=context)
|
||||
return self.write(cr, uid, challenge.id, {'last_report_date': fields.date.today()}, context=context)
|
||||
|
||||
##### Challenges #####
|
||||
|
||||
def accept_challenge(self, cr, uid, plan_ids, context=None, user_id=None):
|
||||
def accept_challenge(self, cr, uid, challenge_ids, context=None, user_id=None):
|
||||
"""The user accept the suggested challenge"""
|
||||
context = context or {}
|
||||
user_id = user_id or uid
|
||||
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, plan_ids, body=message, context=context)
|
||||
self.write(cr, uid, plan_ids, {'proposed_user_ids': [(3, user_id)], 'user_ids': [(4, user_id)]}, context=context)
|
||||
return self.generate_goals_from_plan(cr, uid, plan_ids, context=context)
|
||||
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)
|
||||
return self.generate_goals_from_challenge(cr, uid, challenge_ids, context=context)
|
||||
|
||||
def discard_challenge(self, cr, uid, plan_ids, context=None, user_id=None):
|
||||
def discard_challenge(self, cr, uid, challenge_ids, context=None, user_id=None):
|
||||
"""The user discard the suggested challenge"""
|
||||
context = context or {}
|
||||
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, plan_ids, body=message, context=context)
|
||||
return self.write(cr, uid, plan_ids, {'proposed_user_ids': (3, user_id)}, context=context)
|
||||
self.message_post(cr, uid, 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, plan_id, context=None):
|
||||
def reply_challenge_wizard(self, cr, uid, challenge_id, context=None):
|
||||
context = context or {}
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
act_obj = self.pool.get('ir.actions.act_window')
|
||||
result = mod_obj.get_object_reference(cr, uid, 'gamification', 'challenge_wizard')
|
||||
id = result and result[1] or False
|
||||
result = act_obj.read(cr, uid, [id], context=context)[0]
|
||||
result['res_id'] = plan_id
|
||||
result['res_id'] = challenge_id
|
||||
return result
|
||||
|
||||
def check_challenge_reward(self, cr, uid, plan_ids, force=False, context=None):
|
||||
def check_challenge_reward(self, cr, uid, challenge_ids, force=False, context=None):
|
||||
"""Actions for the end of a challenge
|
||||
|
||||
If a reward was selected, grant it to the correct users.
|
||||
|
@ -632,55 +611,55 @@ class gamification_goal_plan(osv.Model):
|
|||
(if no end date, a running challenge is never rewarded)
|
||||
"""
|
||||
context = context or {}
|
||||
for plan in self.browse(cr, uid, plan_ids, context=context):
|
||||
(start_date, end_date) = start_end_date_for_period(plan.period, plan.start_date, plan.end_date)
|
||||
for challenge in self.browse(cr, uid, challenge_ids, context=context):
|
||||
(start_date, end_date) = start_end_date_for_period(challenge.period, challenge.start_date, challenge.end_date)
|
||||
yesterday = date.today() - timedelta(days=1)
|
||||
if end_date == yesterday.strftime(DF) or force:
|
||||
# open chatter message
|
||||
message_body = _("The challenge %s is finished." % plan.name)
|
||||
message_body = _("The challenge %s is finished." % challenge.name)
|
||||
|
||||
# reward for everybody succeeding
|
||||
rewarded_users = []
|
||||
if plan.reward_id:
|
||||
for user in plan.user_ids:
|
||||
if challenge.reward_id:
|
||||
for user in challenge.user_ids:
|
||||
reached_goal_ids = self.pool.get('gamification.goal').search(cr, uid, [
|
||||
('plan_id', '=', plan.id),
|
||||
('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(plan.planline_ids):
|
||||
self.reward_user(cr, uid, user.id, plan.reward_id.id, context)
|
||||
if len(reached_goal_ids) == len(challenge.line_ids):
|
||||
self.reward_user(cr, uid, user.id, challenge.reward_id.id, context)
|
||||
rewarded_users.append(user)
|
||||
|
||||
if rewarded_users:
|
||||
message_body += _("<br/>Reward (badge %s) for every succeeding user was sent to %s." % (plan.reward_id.name, ", ".join([user.name for user in 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])))
|
||||
else:
|
||||
message_body += _("<br/>Nobody has succeeded to reach every goal, no badge is rewared for this challenge.")
|
||||
|
||||
# reward bests
|
||||
if plan.reward_first_id:
|
||||
(first_user, second_user, third_user) = self.get_top3_users(cr, uid, plan, context)
|
||||
if challenge.reward_first_id:
|
||||
(first_user, second_user, third_user) = self.get_top3_users(cr, uid, challenge, context)
|
||||
if first_user:
|
||||
self.reward_user(cr, uid, first_user.id, plan.reward_first_id.id, context)
|
||||
self.reward_user(cr, uid, first_user.id, challenge.reward_first_id.id, context)
|
||||
message_body += _("<br/>Special rewards were sent to the top competing users. The ranking for this challenge is :")
|
||||
message_body += "<br/> 1. %s - %s" % (first_user.name, plan.reward_first_id.name)
|
||||
message_body += "<br/> 1. %s - %s" % (first_user.name, challenge.reward_first_id.name)
|
||||
else:
|
||||
message_body += _("Nobody reached the required conditions to receive special badges.")
|
||||
|
||||
if second_user and plan.reward_second_id:
|
||||
self.reward_user(cr, uid, second_user.id, plan.reward_second_id.id, context)
|
||||
message_body += "<br/> 2. %s - %s" % (second_user.name, plan.reward_second_id.name)
|
||||
if third_user and plan.reward_third_id:
|
||||
self.reward_user(cr, uid, third_user.id, plan.reward_second_id.id, context)
|
||||
message_body += "<br/> 3. %s - %s" % (third_user.name, plan.reward_third_id.name)
|
||||
if second_user and challenge.reward_second_id:
|
||||
self.reward_user(cr, uid, second_user.id, challenge.reward_second_id.id, context)
|
||||
message_body += "<br/> 2. %s - %s" % (second_user.name, challenge.reward_second_id.name)
|
||||
if third_user and challenge.reward_third_id:
|
||||
self.reward_user(cr, uid, third_user.id, challenge.reward_second_id.id, context)
|
||||
message_body += "<br/> 3. %s - %s" % (third_user.name, challenge.reward_third_id.name)
|
||||
|
||||
self.message_post(cr, uid, plan.id, body=message_body, context=context)
|
||||
self.message_post(cr, uid, challenge.id, body=message_body, context=context)
|
||||
return True
|
||||
|
||||
def get_top3_users(self, cr, uid, plan, context=None):
|
||||
"""Get the top 3 users for a defined plan
|
||||
def get_top3_users(self, cr, uid, challenge, context=None):
|
||||
"""Get the top 3 users for a defined challenge
|
||||
|
||||
Ranking criterias:
|
||||
1. succeed every goal of the challenge
|
||||
|
@ -694,14 +673,14 @@ class gamification_goal_plan(osv.Model):
|
|||
higher one (eg: if 'second' == False, 'third' will be False)
|
||||
"""
|
||||
goal_obj = self.pool.get('gamification.goal')
|
||||
(start_date, end_date) = start_end_date_for_period(plan.period, plan.start_date, plan.end_date)
|
||||
(start_date, end_date) = start_end_date_for_period(challenge.period, challenge.start_date, challenge.end_date)
|
||||
challengers = []
|
||||
for user in plan.user_ids:
|
||||
for user in challenge.user_ids:
|
||||
all_reached = True
|
||||
total_completness = 0
|
||||
# every goal of the user for the running period
|
||||
goal_ids = goal_obj.search(cr, uid, [
|
||||
('plan_id', '=', plan.id),
|
||||
('challenge_id', '=', challenge.id),
|
||||
('user_id', '=', user.id),
|
||||
('start_date', '=', start_date),
|
||||
('end_date', '=', end_date)
|
||||
|
@ -709,7 +688,7 @@ class gamification_goal_plan(osv.Model):
|
|||
for goal in goal_obj.browse(cr, uid, goal_ids, context=context):
|
||||
if goal.state != 'reached':
|
||||
all_reached = False
|
||||
if goal.type_condition == 'higher':
|
||||
if goal.definition_condition == 'higher':
|
||||
# can be over 100
|
||||
total_completness += 100.0 * goal.current / goal.target_goal
|
||||
elif goal.state == 'reached':
|
||||
|
@ -719,13 +698,13 @@ class gamification_goal_plan(osv.Model):
|
|||
challengers.append({'user': user, 'all_reached': all_reached, 'total_completness': total_completness})
|
||||
sorted_challengers = sorted(challengers, key=lambda k: (k['all_reached'], k['total_completness']), reverse=True)
|
||||
|
||||
if len(sorted_challengers) == 0 or (not plan.reward_failure and not sorted_challengers[0]['all_reached']):
|
||||
if len(sorted_challengers) == 0 or (not challenge.reward_failure and not sorted_challengers[0]['all_reached']):
|
||||
# nobody succeeded
|
||||
return (False, False, False)
|
||||
if len(sorted_challengers) == 1 or (not plan.reward_failure and not sorted_challengers[1]['all_reached']):
|
||||
if len(sorted_challengers) == 1 or (not challenge.reward_failure and not sorted_challengers[1]['all_reached']):
|
||||
# only one user succeeded
|
||||
return (sorted_challengers[0]['user'], False, False)
|
||||
if len(sorted_challengers) == 2 or (not plan.reward_failure and not sorted_challengers[2]['all_reached']):
|
||||
if len(sorted_challengers) == 2 or (not challenge.reward_failure and not sorted_challengers[2]['all_reached']):
|
||||
# only one user succeeded
|
||||
return (sorted_challengers[0]['user'], sorted_challengers[1]['user'], False)
|
||||
return (sorted_challengers[0]['user'], sorted_challengers[1]['user'], sorted_challengers[2]['user'])
|
||||
|
@ -736,66 +715,50 @@ class gamification_goal_plan(osv.Model):
|
|||
return self.pool.get('gamification.badge').send_badge(cr, uid, badge_id, [user_badge_id], user_from=None, context=context)
|
||||
|
||||
|
||||
class gamification_goal_planline(osv.Model):
|
||||
"""Gamification goal planline
|
||||
class gamification_challenge_line(osv.Model):
|
||||
"""Gamification challenge line
|
||||
|
||||
Predifined goal for 'gamification_goal_plan'
|
||||
Predifined goal for 'gamification_challenge'
|
||||
These are generic list of goals with only the target goal defined
|
||||
Should only be created for the gamification_goal_plan object
|
||||
Should only be created for the gamification_challenge object
|
||||
"""
|
||||
|
||||
_name = 'gamification.goal.planline'
|
||||
_description = 'Gamification generic goal for plan'
|
||||
_order = "sequence, sequence_type, id"
|
||||
_name = 'gamification.challenge.line'
|
||||
_description = 'Gamification generic goal for challenge'
|
||||
_order = "sequence, id"
|
||||
|
||||
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')'"""
|
||||
|
||||
result = {}
|
||||
for goal_type in self.pool.get('gamification.goal.type').browse(cr, uid, ids, context=context):
|
||||
domain = [('type_id', '=', goal_type.id)]
|
||||
planline_ids = self.pool.get('gamification.goal.planline').search(cr, uid, domain, context=context)
|
||||
for p_id in planline_ids:
|
||||
result[p_id] = True
|
||||
return result.keys()
|
||||
|
||||
def on_change_type_id(self, cr, uid, ids, type_id=False, context=None):
|
||||
goal_type = self.pool.get('gamification.goal.type')
|
||||
if not type_id:
|
||||
return {'value': {'type_id': False}}
|
||||
goal_type = goal_type.browse(cr, uid, type_id, context=context)
|
||||
ret = {'value': {
|
||||
'type_condition': goal_type.condition,
|
||||
'type_full_suffix': goal_type.full_suffix}}
|
||||
def on_change_definition_id(self, cr, uid, ids, definition_id=False, context=None):
|
||||
goal_definition = self.pool.get('gamification.goal.definition')
|
||||
if not definition_id:
|
||||
return {'value': {'definition_id': False}}
|
||||
goal_definition = goal_definition.browse(cr, uid, definition_id, context=context)
|
||||
ret = {
|
||||
'value': {
|
||||
'definition_condition': goal_definition.condition,
|
||||
'definition_full_suffix': goal_definition.full_suffix
|
||||
}
|
||||
}
|
||||
return ret
|
||||
|
||||
_columns = {
|
||||
'name': fields.related('type_id', 'name', string="Name"),
|
||||
'plan_id': fields.many2one('gamification.goal.plan',
|
||||
string='Plan',
|
||||
'name': fields.related('definition_id', 'name', string="Name"),
|
||||
'challenge_id': fields.many2one('gamification.challenge',
|
||||
string='Challenge',
|
||||
required=True,
|
||||
ondelete="cascade"),
|
||||
'type_id': fields.many2one('gamification.goal.type',
|
||||
string='Goal Type',
|
||||
'definition_id': fields.many2one('gamification.goal.definition',
|
||||
string='Goal Definition',
|
||||
required=True,
|
||||
ondelete="cascade"),
|
||||
'target_goal': fields.float('Target Value to Reach',
|
||||
required=True),
|
||||
'sequence': fields.integer('Sequence',
|
||||
help='Sequence number for ordering'),
|
||||
'sequence_type': fields.related('type_id', 'sequence',
|
||||
type='integer',
|
||||
string='Sequence',
|
||||
readonly=True,
|
||||
store={
|
||||
'gamification.goal.type': (_get_planline_types, ['sequence'], 10),
|
||||
}),
|
||||
'type_condition': fields.related('type_id', 'condition', type="selection",
|
||||
'definition_condition': fields.related('definition_id', 'condition', type="selection",
|
||||
readonly=True, string="Condition", selection=[('lower', '<='), ('higher', '>=')]),
|
||||
'type_suffix': fields.related('type_id', 'suffix', type="char", readonly=True, string="Unit"),
|
||||
'type_monetary': fields.related('type_id', 'monetary', type="boolean", readonly=True, string="Monetary"),
|
||||
'type_full_suffix': fields.related('type_id', 'full_suffix', type="char", readonly=True, string="Suffix"),
|
||||
'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"),
|
||||
'definition_full_suffix': fields.related('definition_id', 'full_suffix', type="char", readonly=True, string="Suffix"),
|
||||
}
|
||||
|
||||
_default = {
|
|
@ -32,16 +32,15 @@ import logging
|
|||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class gamification_goal_type(osv.Model):
|
||||
"""Goal type definition
|
||||
class gamification_goal_definition(osv.Model):
|
||||
"""Goal definition
|
||||
|
||||
A goal type defining a way to set an objective and evaluate it
|
||||
A goal definition contains the way to evaluate an objective
|
||||
Each module wanting to be able to set goals to the users needs to create
|
||||
a new gamification_goal_type
|
||||
a new gamification_goal_definition
|
||||
"""
|
||||
_name = 'gamification.goal.type'
|
||||
_description = 'Gamification goal type'
|
||||
_order = 'sequence'
|
||||
_name = 'gamification.goal.definition'
|
||||
_description = 'Gamification goal definition'
|
||||
|
||||
def _get_suffix(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = dict.fromkeys(ids, '')
|
||||
|
@ -60,7 +59,7 @@ class gamification_goal_type(osv.Model):
|
|||
return res
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Goal Type', required=True, translate=True),
|
||||
'name': fields.char('Goal Definition', required=True, translate=True),
|
||||
'description': fields.text('Goal Description'),
|
||||
'monetary': fields.boolean('Monetary Value', help="The target and current value are defined in the company currency."),
|
||||
'suffix': fields.char('Suffix', help="The unit of the target and current values", translate=True),
|
||||
|
@ -92,7 +91,7 @@ class gamification_goal_type(osv.Model):
|
|||
help="Technical filters rules to apply. Use 'user.id' (without marks) to limit the search to the evaluated user.",
|
||||
required=True),
|
||||
'compute_code': fields.char('Compute Code',
|
||||
help="The name of the python method that will be executed to compute the current value. See the file gamification/goal_type_data.py for examples."),
|
||||
help="The name of the python method that will be executed to compute the current value. See the file gamification/goal_definition_data.py for examples."),
|
||||
'condition': fields.selection([
|
||||
('higher', 'The higher the better'),
|
||||
('lower', 'The lower the better')
|
||||
|
@ -100,7 +99,6 @@ class gamification_goal_type(osv.Model):
|
|||
string='Goal Performance',
|
||||
help='A goal is considered as completed when the current value is compared to the value to reach',
|
||||
required=True),
|
||||
'sequence': fields.integer('Sequence', help='Sequence number for ordering', required=True),
|
||||
'action_id': fields.many2one('ir.actions.act_window', string="Action",
|
||||
help="The action that will be called to update the goal value."),
|
||||
'res_id_field': fields.char("ID Field of user",
|
||||
|
@ -108,7 +106,6 @@ class gamification_goal_type(osv.Model):
|
|||
}
|
||||
|
||||
_defaults = {
|
||||
'sequence': 1,
|
||||
'condition': 'higher',
|
||||
'computation_mode': 'manually',
|
||||
'domain': "[]",
|
||||
|
@ -130,7 +127,7 @@ class gamification_goal(osv.Model):
|
|||
"""Return the percentage of completeness of the goal, between 0 and 100"""
|
||||
res = dict.fromkeys(ids, 0.0)
|
||||
for goal in self.browse(cr, uid, ids, context=context):
|
||||
if goal.type_condition == 'higher':
|
||||
if goal.definition_condition == 'higher':
|
||||
if goal.current >= goal.target_goal:
|
||||
res[goal.id] = 100.0
|
||||
else:
|
||||
|
@ -142,21 +139,21 @@ class gamification_goal(osv.Model):
|
|||
res[goal.id] = 0.0
|
||||
return res
|
||||
|
||||
def on_change_type_id(self, cr, uid, ids, type_id=False, context=None):
|
||||
goal_type = self.pool.get('gamification.goal.type')
|
||||
if not type_id:
|
||||
return {'value': {'type_id': False}}
|
||||
goal_type = goal_type.browse(cr, uid, type_id, context=context)
|
||||
return {'value': {'computation_mode': goal_type.computation_mode, 'type_condition': goal_type.condition}}
|
||||
def on_change_definition_id(self, cr, uid, ids, definition_id=False, context=None):
|
||||
goal_definition = self.pool.get('gamification.goal.definition')
|
||||
if not definition_id:
|
||||
return {'value': {'definition_id': False}}
|
||||
goal_definition = goal_definition.browse(cr, uid, definition_id, context=context)
|
||||
return {'value': {'computation_mode': goal_definition.computation_mode, 'definition_condition': goal_definition.condition}}
|
||||
|
||||
_columns = {
|
||||
'type_id': fields.many2one('gamification.goal.type', string='Goal Type', required=True, ondelete="cascade"),
|
||||
'definition_id': fields.many2one('gamification.goal.definition', string='Goal Definition', required=True, ondelete="cascade"),
|
||||
'user_id': fields.many2one('res.users', string='User', required=True),
|
||||
'planline_id': fields.many2one('gamification.goal.planline', string='Goal Planline', ondelete="cascade"),
|
||||
'plan_id': fields.related('planline_id', 'plan_id',
|
||||
string="Plan",
|
||||
'line_id': fields.many2one('gamification.challenge.line', string='Goal Line', ondelete="cascade"),
|
||||
'challenge_id': fields.related('line_id', 'challenge_id',
|
||||
string="Challenge",
|
||||
type='many2one',
|
||||
relation='gamification.goal.plan',
|
||||
relation='gamification.challenge',
|
||||
store=True),
|
||||
'start_date': fields.date('Start Date'),
|
||||
'end_date': fields.date('End Date'), # no start and end = always active
|
||||
|
@ -177,16 +174,16 @@ class gamification_goal(osv.Model):
|
|||
required=True,
|
||||
track_visibility='always'),
|
||||
|
||||
'computation_mode': fields.related('type_id', 'computation_mode', type='char', string="Type computation mode"),
|
||||
'computation_mode': fields.related('definition_id', 'computation_mode', type='char', string="Computation mode"),
|
||||
'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."),
|
||||
help="In case of manual goal, reminders are sent if the goal as not been updated for a while (defined in challenge). Ignored in case of non-manual goal or goal not linked to a challenge."),
|
||||
|
||||
'type_description': fields.related('type_id', 'description', type='char', string='Type Description', readonly=True),
|
||||
'type_condition': fields.related('type_id', 'condition', type='char', string='Type Condition', readonly=True),
|
||||
'type_suffix': fields.related('type_id', 'full_suffix', type="char", string="Suffix", readonly=True),
|
||||
'type_display': fields.related('type_id', 'display_mode', type="char", string="Display Mode", readonly=True),
|
||||
'definition_description': fields.related('definition_id', 'description', type='char', string='Definition Description', readonly=True),
|
||||
'definition_condition': fields.related('definition_id', 'condition', type='char', string='Definition Condition', readonly=True),
|
||||
'definition_suffix': fields.related('definition_id', 'full_suffix', type="char", string="Suffix", readonly=True),
|
||||
'definition_display': fields.related('definition_id', 'display_mode', type="char", string="Display Mode", readonly=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
|
@ -194,7 +191,7 @@ class gamification_goal(osv.Model):
|
|||
'state': 'draft',
|
||||
'start_date': fields.date.today,
|
||||
}
|
||||
_order = 'create_date desc, end_date desc, type_id, id'
|
||||
_order = 'create_date desc, end_date desc, definition_id, id'
|
||||
|
||||
def _check_remind_delay(self, cr, uid, goal, context=None):
|
||||
"""Verify if a goal has not been updated for some time and send a
|
||||
|
@ -230,26 +227,26 @@ class gamification_goal(osv.Model):
|
|||
# skip if goal draft or canceled
|
||||
continue
|
||||
|
||||
if goal.type_id.computation_mode == 'manually':
|
||||
if goal.definition_id.computation_mode == 'manually':
|
||||
towrite.update(self._check_remind_delay(cr, uid, goal, context))
|
||||
|
||||
elif goal.type_id.computation_mode == 'python':
|
||||
elif goal.definition_id.computation_mode == 'python':
|
||||
# execute the chosen method
|
||||
values = {'cr': cr, 'uid': goal.user_id.id, 'context': context, 'self': self.pool.get('gamification.goal.type')}
|
||||
result = safe_eval(goal.type_id.compute_code, values, {})
|
||||
values = {'cr': cr, 'uid': goal.user_id.id, 'context': context, 'self': self.pool.get('gamification.goal.definition')}
|
||||
result = safe_eval(goal.definition_id.compute_code, values, {})
|
||||
|
||||
if type(result) in (float, int, long) and result != goal.current:
|
||||
towrite['current'] = result
|
||||
else:
|
||||
_logger.exception(_('Unvalid return content from the evaluation of %s' % str(goal.type_id.compute_code)))
|
||||
# raise osv.except_osv(_('Error!'), _('Unvalid return content from the evaluation of %s' % str(goal.type_id.compute_code)))
|
||||
_logger.exception(_('Unvalid return content from the evaluation of %s' % str(goal.definition_id.compute_code)))
|
||||
# raise osv.except_osv(_('Error!'), _('Unvalid return content from the evaluation of %s' % str(goal.definition_id.compute_code)))
|
||||
|
||||
else: # count or sum
|
||||
obj = self.pool.get(goal.type_id.model_id.model)
|
||||
field_date_name = goal.type_id.field_date_id.name
|
||||
obj = self.pool.get(goal.definition_id.model_id.model)
|
||||
field_date_name = goal.definition_id.field_date_id.name
|
||||
|
||||
# eval the domain with user replaced by goal user object
|
||||
domain = safe_eval(goal.type_id.domain, {'user': goal.user_id})
|
||||
domain = safe_eval(goal.definition_id.domain, {'user': goal.user_id})
|
||||
|
||||
#add temporal clause(s) to the domain if fields are filled on the goal
|
||||
if goal.start_date and field_date_name:
|
||||
|
@ -257,8 +254,8 @@ class gamification_goal(osv.Model):
|
|||
if goal.end_date and field_date_name:
|
||||
domain.append((field_date_name, '<=', goal.end_date))
|
||||
|
||||
if goal.type_id.computation_mode == 'sum':
|
||||
field_name = goal.type_id.field_id.name
|
||||
if goal.definition_id.computation_mode == 'sum':
|
||||
field_name = goal.definition_id.field_id.name
|
||||
res = obj.read_group(cr, uid, domain, [field_name], [''], context=context)
|
||||
new_value = res and res[0][field_name] or 0.0
|
||||
|
||||
|
@ -270,7 +267,7 @@ class gamification_goal(osv.Model):
|
|||
towrite['current'] = new_value
|
||||
|
||||
# check goal target reached
|
||||
if (goal.type_id.condition == 'higher' and towrite.get('current', goal.current) >= goal.target_goal) or (goal.type_id.condition == 'lower' and towrite.get('current', goal.current) <= goal.target_goal):
|
||||
if (goal.definition_id.condition == 'higher' and towrite.get('current', goal.current) >= goal.target_goal) or (goal.definition_id.condition == 'lower' and towrite.get('current', goal.current) <= goal.target_goal):
|
||||
towrite['state'] = 'reached'
|
||||
|
||||
# check goal failure
|
||||
|
@ -323,7 +320,7 @@ class gamification_goal(osv.Model):
|
|||
vals['last_update'] = fields.date.today()
|
||||
result = super(gamification_goal, self).write(cr, uid, ids, vals, context=context)
|
||||
for goal in self.browse(cr, uid, ids, context=context):
|
||||
if goal.state != "draft" and ('type_id' in vals or 'user_id' in vals):
|
||||
if goal.state != "draft" and ('definition_id' in vals or 'user_id' in vals):
|
||||
# avoid drag&drop in kanban view
|
||||
raise osv.except_osv(_('Error!'), _('Can not modify the configuration of a started goal'))
|
||||
|
||||
|
@ -332,8 +329,8 @@ class gamification_goal(osv.Model):
|
|||
# new goals should not be reported
|
||||
continue
|
||||
|
||||
if goal.plan_id and goal.plan_id.report_message_frequency == 'onchange':
|
||||
self.pool.get('gamification.goal.plan').report_progress(cr, SUPERUSER_ID, goal.plan_id, users=[goal.user_id], context=context)
|
||||
if goal.challenge_id and goal.challenge_id.report_message_frequency == 'onchange':
|
||||
self.pool.get('gamification.challenge').report_progress(cr, SUPERUSER_ID, goal.challenge_id, users=[goal.user_id], context=context)
|
||||
return result
|
||||
|
||||
def get_action(self, cr, uid, goal_id, context=None):
|
||||
|
@ -344,13 +341,13 @@ class gamification_goal(osv.Model):
|
|||
"""
|
||||
goal = self.browse(cr, uid, goal_id, context=context)
|
||||
|
||||
if goal.type_id.action_id:
|
||||
if goal.definition_id.action_id:
|
||||
#open a the action linked on the goal
|
||||
action = goal.type_id.action_id.read()[0]
|
||||
action = goal.definition_id.action_id.read()[0]
|
||||
|
||||
if goal.type_id.res_id_field:
|
||||
if goal.definition_id.res_id_field:
|
||||
current_user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
action['res_id'] = safe_eval(goal.type_id.res_id_field, {'user': current_user})
|
||||
action['res_id'] = safe_eval(goal.definition_id.res_id_field, {'user': current_user})
|
||||
|
||||
# if one element to display, should see it in form mode if possible
|
||||
views = action['views']
|
||||
|
@ -364,7 +361,7 @@ class gamification_goal(osv.Model):
|
|||
if goal.computation_mode == 'manually':
|
||||
#open a wizard window to update the value manually
|
||||
action = {
|
||||
'name': _("Update %s") % goal.type_id.name,
|
||||
'name': _("Update %s") % goal.definition_id.name,
|
||||
'id': goal_id,
|
||||
'type': 'ir.actions.act_window',
|
||||
'views': [[False, 'form']],
|
||||
|
@ -378,7 +375,7 @@ class gamification_goal(osv.Model):
|
|||
|
||||
|
||||
class goal_manual_wizard(osv.TransientModel):
|
||||
"""Wizard type to update a manual goal"""
|
||||
"""Wizard to update a manual goal"""
|
||||
_name = 'gamification.goal.wizard'
|
||||
_columns = {
|
||||
'goal_id': fields.many2one("gamification.goal", string='Goal', required=True),
|
|
@ -24,7 +24,7 @@ from openerp.osv import osv
|
|||
|
||||
class res_users_gamification_group(osv.Model):
|
||||
""" Update of res.users class
|
||||
- if adding groups to an user, check gamification.goal.plan linked to
|
||||
- if adding groups to an user, check gamification.challenge linked to
|
||||
this group, and the user. This is done by overriding the write method.
|
||||
"""
|
||||
_name = 'res.users'
|
||||
|
@ -37,62 +37,62 @@ class res_users_gamification_group(osv.Model):
|
|||
user_group_ids = [command[1] for command in vals['groups_id'] if command[0] == 4]
|
||||
user_group_ids += [id for command in vals['groups_id'] if command[0] == 6 for id in command[2]]
|
||||
|
||||
goal_plan_obj = self.pool.get('gamification.goal.plan')
|
||||
plan_ids = goal_plan_obj.search(cr, uid, [('autojoin_group_id', 'in', user_group_ids)], context=context)
|
||||
if plan_ids:
|
||||
goal_plan_obj.write(cr, uid, plan_ids, {'user_ids': [(4, user_id) for user_id in ids]}, context=context)
|
||||
challenge_obj = self.pool.get('gamification.challenge')
|
||||
challenge_ids = challenge_obj.search(cr, uid, [('autojoin_group_id', 'in', user_group_ids)], context=context)
|
||||
if challenge_ids:
|
||||
challenge_obj.write(cr, uid, challenge_ids, {'user_ids': [(4, user_id) for user_id in ids]}, context=context)
|
||||
|
||||
if vals.get('image'):
|
||||
goal_type_id = self.pool.get('ir.model.data').get_object(cr, uid, 'gamification', 'type_base_avatar', context)
|
||||
goal_ids = self.pool.get('gamification.goal').search(cr, uid, [('type_id', '=', goal_type_id.id), ('user_id', 'in', ids)], context=context)
|
||||
goal_definition_id = self.pool.get('ir.model.data').get_object(cr, uid, 'gamification', 'definition_base_avatar', context)
|
||||
goal_ids = self.pool.get('gamification.goal').search(cr, uid, [('definition_id', '=', goal_definition_id.id), ('user_id', 'in', ids)], context=context)
|
||||
values = {'state': 'reached', 'current': 1}
|
||||
self.pool.get('gamification.goal').write(cr, uid, goal_ids, values, 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 plan
|
||||
"""Return the list of goals assigned to the user, grouped by challenge
|
||||
|
||||
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
|
||||
types
|
||||
definitions
|
||||
:return: list of dictionnaries for each goal to display
|
||||
"""
|
||||
all_goals_info = []
|
||||
plan_obj = self.pool.get('gamification.goal.plan')
|
||||
challenge_obj = self.pool.get('gamification.challenge')
|
||||
|
||||
plan_ids = plan_obj.search(cr, uid, [('user_ids', 'in', uid), ('state', '=', 'inprogress')], context=context)
|
||||
for plan in plan_obj.browse(cr, uid, plan_ids, context=context):
|
||||
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 = {
|
||||
'id': plan.id,
|
||||
'name': plan.name,
|
||||
'visibility_mode': plan.visibility_mode,
|
||||
'id': challenge.id,
|
||||
'name': challenge.name,
|
||||
'visibility_mode': challenge.visibility_mode,
|
||||
}
|
||||
user = self.browse(cr, uid, uid, context=context)
|
||||
serialized_goals_info['currency'] = user.company_id.currency_id.id
|
||||
|
||||
if plan.visibility_mode == 'board':
|
||||
# board report should be grouped by planline for all users
|
||||
goals_info = plan_obj.get_board_goal_info(cr, uid, plan, subset_goal_ids=False, context=context)
|
||||
if challenge.visibility_mode == 'board':
|
||||
# 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 len(goals_info) == 0:
|
||||
# plan with no valid planlines
|
||||
# challenge with no valid lines
|
||||
continue
|
||||
|
||||
serialized_goals_info['planlines'] = []
|
||||
for planline_board in goals_info:
|
||||
vals = {'type_name': planline_board['goal_type'].name,
|
||||
'type_description': planline_board['goal_type'].description,
|
||||
'type_condition': planline_board['goal_type'].condition,
|
||||
'computation_mode': planline_board['goal_type'].computation_mode,
|
||||
'type_monetary': planline_board['goal_type'].monetary,
|
||||
'type_suffix': planline_board['goal_type'].suffix,
|
||||
'type_action': True if planline_board['goal_type'].action_id else False,
|
||||
'type_display': planline_board['goal_type'].display_mode,
|
||||
'target_goal': planline_board['target_goal'],
|
||||
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 planline_board['board_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
|
||||
|
@ -109,11 +109,11 @@ class res_users_gamification_group(osv.Model):
|
|||
})
|
||||
if uid == goal[1].user_id.id:
|
||||
vals['own_goal_id'] = goal[1].id
|
||||
serialized_goals_info['planlines'].append(vals)
|
||||
serialized_goals_info['lines'].append(vals)
|
||||
|
||||
else:
|
||||
# individual report are simply a list of goal
|
||||
goals_info = plan_obj.get_indivual_goal_info(cr, uid, uid, plan, subset_goal_ids=False, context=context)
|
||||
goals_info = challenge_obj.get_indivual_goal_info(cr, uid, uid, challenge, subset_goal_ids=False, context=context)
|
||||
|
||||
if not goals_info:
|
||||
continue
|
||||
|
@ -122,13 +122,13 @@ class res_users_gamification_group(osv.Model):
|
|||
for goal in goals_info:
|
||||
serialized_goals_info['goals'].append({
|
||||
'id': goal.id,
|
||||
'type_name': goal.type_id.name,
|
||||
'type_description': goal.type_description,
|
||||
'type_condition': goal.type_id.condition,
|
||||
'type_monetary': goal.type_id.monetary,
|
||||
'type_suffix': goal.type_id.suffix,
|
||||
'type_action': True if goal.type_id.action_id else False,
|
||||
'type_display': goal.type_id.display_mode,
|
||||
'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,
|
||||
|
@ -140,23 +140,23 @@ class res_users_gamification_group(osv.Model):
|
|||
return all_goals_info
|
||||
|
||||
def get_challenge_suggestions(self, cr, uid, context=None):
|
||||
"""Return the list of goal plans suggested to the user"""
|
||||
plan_info = []
|
||||
goal_plan_obj = self.pool.get('gamification.goal.plan')
|
||||
plan_ids = goal_plan_obj.search(cr, uid, [('proposed_user_ids', 'in', uid), ('state', '=', 'inprogress')], context=context)
|
||||
for plan in goal_plan_obj.browse(cr, uid, plan_ids, context=context):
|
||||
"""Return the list of challenges suggested to the user"""
|
||||
challenge_info = []
|
||||
challenge_obj = self.pool.get('gamification.challenge')
|
||||
challenge_ids = challenge_obj.search(cr, uid, [('invited_user_ids', 'in', uid), ('state', '=', 'inprogress')], context=context)
|
||||
for challenge in challenge_obj.browse(cr, uid, challenge_ids, context=context):
|
||||
values = {
|
||||
'id': plan.id,
|
||||
'name': plan.name,
|
||||
'description': plan.description,
|
||||
'id': challenge.id,
|
||||
'name': challenge.name,
|
||||
'description': challenge.description,
|
||||
}
|
||||
plan_info.append(values)
|
||||
return plan_info
|
||||
challenge_info.append(values)
|
||||
return challenge_info
|
||||
|
||||
|
||||
class res_groups_gamification_group(osv.Model):
|
||||
""" Update of res.groups class
|
||||
- if adding users from a group, check gamification.goal.plan linked to
|
||||
- if adding users from a group, check gamification.challenge linked to
|
||||
this group, and the user. This is done by overriding the write method.
|
||||
"""
|
||||
_name = 'res.groups'
|
||||
|
@ -169,9 +169,9 @@ class res_groups_gamification_group(osv.Model):
|
|||
user_ids = [command[1] for command in vals['users'] if command[0] == 4]
|
||||
user_ids += [id for command in vals['users'] if command[0] == 6 for id in command[2]]
|
||||
|
||||
goal_plan_obj = self.pool.get('gamification.goal.plan')
|
||||
plan_ids = goal_plan_obj.search(cr, uid, [('autojoin_group_id', 'in', ids)], context=context)
|
||||
if plan_ids:
|
||||
goal_plan_obj.write(cr, uid, plan_ids, {'user_ids': [(4, user_id) for user_id in user_ids]}, context=context)
|
||||
challenge_obj = self.pool.get('gamification.challenge')
|
||||
challenge_ids = challenge_obj.search(cr, uid, [('autojoin_group_id', 'in', ids)], context=context)
|
||||
if challenge_ids:
|
||||
challenge_obj.write(cr, uid, challenge_ids, {'user_ids': [(4, user_id) for user_id in user_ids]}, context=context)
|
||||
return write_res
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -13,7 +13,7 @@
|
|||
</record>
|
||||
|
||||
<record id="goal_user_visibility" model="ir.rule">
|
||||
<field name="name">User can only see his/her goals or goal from the same plan in board visibility</field>
|
||||
<field name="name">User can only see his/her goals or goal from the same challenge in board visibility</field>
|
||||
<field name="model_id" ref="model_gamification_goal"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
|
@ -24,8 +24,8 @@
|
|||
'|',
|
||||
('user_id','=',user.id),
|
||||
'&',
|
||||
('plan_id.user_ids','in',user.id),
|
||||
('plan_id.visibility_mode','=','board')]</field>
|
||||
('challenge_id.user_ids','in',user.id),
|
||||
('challenge_id.visibility_mode','=','board')]</field>
|
||||
</record>
|
||||
|
||||
<record id="goal_gamification_manager_visibility" model="ir.rule">
|
||||
|
|
|
@ -3,14 +3,14 @@ id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
|
|||
goal_employee,"Goal Employee",model_gamification_goal,base.group_user,1,1,0,0
|
||||
goal_manager,"Goal Manager",model_gamification_goal,group_goal_manager,1,1,1,1
|
||||
|
||||
goal_type_employee,"Goal Type Employee",model_gamification_goal_type,base.group_user,1,0,0,0
|
||||
goal_type_manager,"Goal Type Manager",model_gamification_goal_type,group_goal_manager,1,1,1,1
|
||||
goal_definition_employee,"Goal Definition Employee",model_gamification_goal_definition,base.group_user,1,0,0,0
|
||||
goal_definition_manager,"Goal Definition Manager",model_gamification_goal_definition,group_goal_manager,1,1,1,1
|
||||
|
||||
plan_employee,"Goal Plan Employee",model_gamification_goal_plan,base.group_user,1,0,0,0
|
||||
plan_manager,"Goal Plan Manager",model_gamification_goal_plan,group_goal_manager,1,1,1,1
|
||||
challenge_employee,"Goal Challenge Employee",model_gamification_challenge,base.group_user,1,0,0,0
|
||||
challenge_manager,"Goal Challenge Manager",model_gamification_challenge,group_goal_manager,1,1,1,1
|
||||
|
||||
planline_employee,"Goal Planline Employee",model_gamification_goal_planline,base.group_user,1,0,0,0
|
||||
planline_manager,"Goal Planline Manager",model_gamification_goal_planline,group_goal_manager,1,1,1,1
|
||||
challenge_line_employee,"Challenge Line Employee",model_gamification_challenge_line,base.group_user,1,0,0,0
|
||||
challenge_line_manager,"Challenge Line Manager",model_gamification_challenge_line,group_goal_manager,1,1,1,1
|
||||
|
||||
badge_employee,"Badge Employee",model_gamification_badge,base.group_user,1,0,0,0
|
||||
badge_manager,"Badge Manager",model_gamification_badge,group_goal_manager,1,1,1,1
|
||||
|
|
|
|
@ -12,11 +12,11 @@ openerp.gamification = function(instance) {
|
|||
this.challenge_suggestions = {};
|
||||
},
|
||||
events: {
|
||||
// update a plan and related goals
|
||||
'click a.oe_update_plan': function(event) {
|
||||
// update a challenge and related goals
|
||||
'click a.oe_update_challenge': function(event) {
|
||||
var self = this;
|
||||
var plan_id = parseInt(event.currentTarget.id, 10);
|
||||
var goals_updated = new instance.web.Model('gamification.goal.plan').call('quick_update', [plan_id]);
|
||||
var challenge_id = parseInt(event.currentTarget.id, 10);
|
||||
var goals_updated = new instance.web.Model('gamification.challenge').call('quick_update', [challenge_id]);
|
||||
$.when(goals_updated).done(function() {
|
||||
self.get_goal_todo_info();
|
||||
});
|
||||
|
@ -40,12 +40,12 @@ openerp.gamification = function(instance) {
|
|||
// get more info about a challenge request
|
||||
'click a.oe_challenge_reply': function(event) {
|
||||
var self = this;
|
||||
var plan_id = parseInt(event.currentTarget.id, 10);
|
||||
var plan_action = new instance.web.Model('gamification.goal.plan').call('reply_challenge_wizard', [plan_id]).then(function(res) {
|
||||
plan_action['action'] = res;
|
||||
var challenge_id = parseInt(event.currentTarget.id, 10);
|
||||
var challenge_action = new instance.web.Model('gamification.challenge').call('reply_challenge_wizard', [challenge_id]).then(function(res) {
|
||||
challenge_action['action'] = res;
|
||||
});
|
||||
$.when(plan_action).done(function() {
|
||||
self.do_action(plan_action.action).done(function () {
|
||||
$.when(challenge_action).done(function() {
|
||||
self.do_action(challenge_action.action).done(function () {
|
||||
self.get_goal_todo_info();
|
||||
});
|
||||
});
|
||||
|
@ -132,7 +132,7 @@ openerp.gamification = function(instance) {
|
|||
instance.web_kanban.KanbanRecord.include({
|
||||
// open related goals when clicking on challenge kanban view
|
||||
on_card_clicked: function() {
|
||||
if (this.view.dataset.model === 'gamification.goal.plan') {
|
||||
if (this.view.dataset.model === 'gamification.challenge') {
|
||||
this.$('.oe_kanban_project_list a').first().click();
|
||||
} else {
|
||||
this._super.apply(this, arguments);
|
||||
|
|
|
@ -4,37 +4,37 @@
|
|||
<div class="oe_gamification_goal"><em>Your goal list is empty</em></div>
|
||||
</t>
|
||||
<t t-name="gamification.goal_list_to_do">
|
||||
<div t-foreach="widget.goals_info.info" t-as="plan" class="oe_goal">
|
||||
<div t-foreach="widget.goals_info.info" t-as="challenge" class="oe_goal">
|
||||
<div>
|
||||
<a class="oe_update_plan oe_e" rol="button" t-attf-id="{plan.id}">e</a>
|
||||
<h4><t t-esc="plan.name" /></h4>
|
||||
<a class="oe_update_challenge oe_e" rol="button" t-attf-id="{challenge.id}">e</a>
|
||||
<h4><t t-esc="challenge.name" /></h4>
|
||||
</div>
|
||||
|
||||
<t t-if="plan.visibility_mode == 'progressbar'">
|
||||
<t t-if="challenge.visibility_mode == 'progressbar'">
|
||||
<div class="oe_table oe_goals_list">
|
||||
<div t-foreach="plan.goals" t-as="goal" t-attf-class="oe_row oe_goal_outer_box #{goal.state == 'reached' ? 'oe_goal_reached' : ''} #{goal.type_display != 'progress' ? 'oe_no_progress' : ''}">
|
||||
<t t-if="goal.type_display == 'progress'">
|
||||
<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 class="oe_goal_progress_background"></div>
|
||||
<div class="oe_goal_progress" t-attf-style="#{goal.type_display == 'progress' ? 'width: '+goal.completeness+'%;' : 'width:0;'}"></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>
|
||||
</t>
|
||||
<div class="oe_cell">
|
||||
<t t-if="goal.computation_mode != 'manually' and !goal.type_action">
|
||||
<span t-att-title="goal.type_description"><t t-esc="goal.type_name" /></span>
|
||||
<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 t-if="goal.type_action or goal.computation_mode == 'manually'">
|
||||
<span t-att-title="goal.type_description"><a class="oe_goal_action" t-att-id="goal.id"><t t-esc="goal.type_name" /></a></span>
|
||||
<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 t-if="goal.type_display == 'progress'"><br/>
|
||||
<t t-if="goal.definition_display == 'progress'"><br/>
|
||||
<div class="oe_grey">
|
||||
<t t-if="goal.type_condition == 'higher'">
|
||||
<t t-if="goal.definition_condition == 'higher'">
|
||||
Target:
|
||||
</t>
|
||||
<t t-if="goal.type_condition == 'lower'">
|
||||
<t t-if="goal.definition_condition == 'lower'">
|
||||
Target: <=
|
||||
</t>
|
||||
<span t-attf-class="#{goal.type_monetary ? 'oe_goal_field_monetary' : ''}"><t t-esc="goal.target_goal"/></span>
|
||||
<t t-if="goal.type_suffix"><t t-esc="goal.type_suffix"/></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>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
|
@ -42,52 +42,52 @@
|
|||
</div>
|
||||
</t>
|
||||
|
||||
<t t-if="plan.visibility_mode == 'board'">
|
||||
<div t-foreach="plan.planlines" t-as="planline" class="oe_goals_list oe_table">
|
||||
<t t-if="challenge.visibility_mode == 'board'">
|
||||
<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="#{planline.type_description ? planline.type_description : ''}">
|
||||
<strong><t t-esc="planline.type_name"/></strong>
|
||||
<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>
|
||||
<br/>
|
||||
<div class="oe_grey">
|
||||
<t t-if="planline.type_condition == 'higher'">
|
||||
<t t-if="line.definition_condition == 'higher'">
|
||||
Target:
|
||||
</t>
|
||||
<t t-if="planline.type_condition == 'lower'">
|
||||
<t t-if="line.definition_condition == 'lower'">
|
||||
Target: <=
|
||||
</t>
|
||||
<span t-attf-class="#{planline.type_monetary ? 'oe_goal_field_monetary' : ''}"><t t-esc="planline.target_goal" /></span><t t-if="planline.type_suffix"> <t t-esc="planline.type_suffix"/></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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div t-foreach="planline.goals" t-as="goal" t-attf-class="#{goal.id == planline.own_goal_id ? 'oe_bold' : ''}">
|
||||
<div t-attf-class="oe_row oe_goal_outer_box #{goal.state == 'reached' ? 'oe_goal_reached' : ''} #{planline.type_display != 'progress' ? 'oe_no_progress' : ''}">
|
||||
<t t-if="planline.type_display == 'progress'">
|
||||
<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 class="oe_goal_progress_background"></div>
|
||||
<div class="oe_goal_progress" t-attf-style="#{planline.type_display == 'progress' ? 'width: '+goal.completeness+'%;' : 'width:0;'}"></div>
|
||||
<div class="oe_goal_progress" t-attf-style="#{line.definition_display == '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 col2">
|
||||
<t t-if="planline.type_display == 'progress'">
|
||||
<t t-if="line.definition_display == 'progress'">
|
||||
<!-- progress, action on current value -->
|
||||
<t t-esc="goal.user_name"/><br/>
|
||||
<t t-if="goal.id != planline.own_goal_id or (planline.computation_mode != 'manually' and !planline.type_action)">
|
||||
<span t-attf-class="#{planline.type_monetary ? 'oe_goal_field_monetary' : ''}"><t t-esc="goal.current" /></span><t t-if="planline.type_suffix"> <t t-esc="planline.type_suffix"/></t>
|
||||
<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 t-if="goal.id == planline.own_goal_id and (planline.type_action or planline.computation_mode == 'manually')">
|
||||
<a class="oe_goal_action" t-att-id="planline.own_goal_id">
|
||||
<span t-attf-class="#{planline.type_monetary ? 'oe_goal_field_monetary' : ''}"><t t-esc="goal.current" /></span><t t-if="planline.type_suffix"> <t t-esc="planline.type_suffix"/></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">
|
||||
<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>
|
||||
</a>
|
||||
</t>
|
||||
</t>
|
||||
<t t-if="planline.type_display != 'progress'">
|
||||
<t t-if="line.definition_display != 'progress'">
|
||||
<!-- not progress, action on user name -->
|
||||
<t t-if="goal.id != planline.own_goal_id or (planline.computation_mode != 'manually' and !planline.type_action)">
|
||||
<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 t-if="goal.id == planline.own_goal_id and (planline.type_action or planline.computation_mode == 'manually')">
|
||||
<a class="oe_goal_action" t-att-id="planline.own_goal_id"><t t-esc="goal.user_name"/></a>
|
||||
<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>
|
||||
</div>
|
||||
|
@ -100,7 +100,7 @@
|
|||
|
||||
<t t-name="gamification.challenge_suggestions">
|
||||
<div class="oe_goal">
|
||||
<h4>Proposed Challenges</h4>
|
||||
<h4>Invited Challenges</h4>
|
||||
<ul t-foreach="widget.challenge_suggestions.info" 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>
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
# We use a jinja2 sandboxed environment to render mako templates.
|
||||
# Note that the rendering does not cover all the mako syntax, in particular
|
||||
# arbitrary Python statements are not accepted, and not all expressions are
|
||||
# allowed: only "public" attributes (not starting with '_') of objects may
|
||||
# be accessed.
|
||||
# This is done on purpose: it prevents incidental or malicious execution of
|
||||
# Python code that may break the security of the server.
|
||||
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
from jinja2 import FileSystemLoader
|
||||
|
||||
from urllib import urlencode, quote as quote
|
||||
import os.path
|
||||
|
||||
#TODO: to check: new dependancies in openerp? fine or not?
|
||||
#TODO: to check: if it's ok, i think it would be better directly in the server (tools) so that other modules that doesn't depend on gamification can use it
|
||||
#TODO; someone else should check this code, i'm not the good one
|
||||
|
||||
class TemplateHelper(SandboxedEnvironment):
|
||||
|
||||
GAMIFICATION_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super(TemplateHelper, self).__init__(
|
||||
loader=FileSystemLoader(os.path.join(self.GAMIFICATION_PATH, 'templates/')),
|
||||
block_start_string="<%",
|
||||
block_end_string="%>",
|
||||
variable_start_string="${",
|
||||
variable_end_string="}",
|
||||
comment_start_string="<%doc>",
|
||||
comment_end_string="</%doc>",
|
||||
line_statement_prefix="%",
|
||||
line_comment_prefix="##",
|
||||
trim_blocks=True, # do not output newline after blocks
|
||||
autoescape=True, # XML/HTML automatic escaping
|
||||
)
|
||||
self.globals.update({
|
||||
'str': str,
|
||||
'quote': quote,
|
||||
'urlencode': urlencode,
|
||||
})
|
|
@ -1,10 +1,10 @@
|
|||
<% extends 'base.mako' %>
|
||||
|
||||
<% block body %>
|
||||
% for planline in planlines_boards:
|
||||
% for line in lines_boards:
|
||||
<table width="100%" border="1">
|
||||
<tr>
|
||||
<th colspan="4">${planline.goal_type.name}</th>
|
||||
<th colspan="4">${line.goal_definition.name}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<th>Completeness</th>
|
||||
<th>Current</th>
|
||||
</tr>
|
||||
% for idx, goal in planline.board_goals:
|
||||
% for idx, goal in line.board_goals:
|
||||
% if idx < 3 or goal.user_id.id == uid:
|
||||
<tr
|
||||
% if goal.completeness >= 100:
|
||||
|
@ -23,8 +23,8 @@
|
|||
<td>${goal.user_id.name}</td>
|
||||
<td>${goal.completeness}%</td>
|
||||
<td>${goal.current}/${goal.target_goal}
|
||||
% if goal.type_suffix:
|
||||
${goal.type_suffix}
|
||||
% if goal.definition_suffix:
|
||||
${goal.definition_suffix}
|
||||
% endif
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -13,15 +13,15 @@
|
|||
style="font-weight:bold;"
|
||||
% endif
|
||||
>
|
||||
<td>${goal.type_id.name}</td>
|
||||
<td>${goal.definition_id.name}</td>
|
||||
<td>${goal.target_goal}
|
||||
% if goal.type_suffix:
|
||||
${goal.type_suffix}
|
||||
% if goal.definition_suffix:
|
||||
${goal.definition_suffix}
|
||||
% endif
|
||||
</td>
|
||||
<td>${goal.current}
|
||||
% if goal.type_suffix:
|
||||
${goal.type_suffix}
|
||||
% if goal.definition_suffix:
|
||||
${goal.definition_suffix}
|
||||
% endif
|
||||
</td>
|
||||
<td>${goal.completeness} %</td>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<p class="oe_grey">${object.report_header or ''}</p>
|
||||
|
||||
<p>You have not updated your progress for the goal ${object.type_id.name} (currently reached at ${object.completeness}%) for at least ${object.remind_update_delay} days. Do not forget to do it.</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>
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
-
|
||||
In order to test process of the Goals, I assign the discovery goal plan to all users
|
||||
In order to test process of the Goals, I assign the discovery challenge to all users
|
||||
-
|
||||
!record {model: gamification.goal.plan, id: plan_base_discover}:
|
||||
!record {model: gamification.challenge, id: challenge_base_discover}:
|
||||
autojoin_group_id: base.group_user
|
||||
-
|
||||
I verify that the users of the group are added (at least admin and demo)
|
||||
-
|
||||
!assert {model: gamification.goal.plan, id: plan_base_discover, string: The autojoin function was not successful}:
|
||||
!assert {model: gamification.challenge, id: challenge_base_discover, string: The autojoin function was not successful}:
|
||||
- len(user_ids) >= 2
|
||||
-
|
||||
I start the goal plan and verify the change of state
|
||||
I start the challenge and verify the change of state
|
||||
-
|
||||
!python {model: gamification.goal.plan}: |
|
||||
plan = self.browse(cr, uid, ref('plan_base_discover'))
|
||||
self.action_start(cr, uid, [plan.id], context=context)
|
||||
assert plan.state == 'inprogress', "Plan failed the change of state"
|
||||
!python {model: gamification.challenge}: |
|
||||
challenge = self.browse(cr, uid, ref('challenge_base_discover'))
|
||||
self.action_start(cr, uid, [challenge.id], context=context)
|
||||
assert challenge.state == 'inprogress', "Challenge failed the change of state"
|
||||
-
|
||||
I verify the goals are generated correctly
|
||||
-
|
||||
!python {model: gamification.goal}: |
|
||||
goal_ids = self.search(cr, uid, [('plan_id', '=', ref('plan_base_discover'))], context=context)
|
||||
goal_ids = self.search(cr, uid, [('challenge_id', '=', ref('challenge_base_discover'))], context=context)
|
||||
assert len(goal_ids) >= 4, "Not enough goals have been generated"
|
||||
for goal in self.browse(cr, uid, goal_ids, context=context):
|
||||
assert goal.state != 'draft', "Draft goal have been generated"
|
||||
assert goal.planline_id.plan_id.id == ref('plan_base_discover'), "Linked planline incorrect"
|
||||
assert goal.line_id.challenge_id.id == ref('challenge_base_discover'), "Linked line incorrect"
|
||||
-
|
||||
I change timezone for demo user
|
||||
-
|
||||
|
@ -33,21 +33,21 @@
|
|||
I check the goal for demo user is successful
|
||||
-
|
||||
!python {model: gamification.goal}: |
|
||||
goal_ids = self.search(cr, uid, [('user_id', '=', ref('base.user_demo')),('type_id','=',ref('type_base_timezone'))])
|
||||
goal_ids = self.search(cr, uid, [('user_id', '=', ref('base.user_demo')),('definition_id','=',ref('definition_base_timezone'))])
|
||||
self.update(cr, uid, goal_ids, context=context)
|
||||
for goal in self.browse(cr, uid, goal_ids, context=context):
|
||||
assert goal.state == "reached", "Goal not successful %s" % goal.state
|
||||
-
|
||||
I add a reward to the challenge
|
||||
-
|
||||
!record {model: gamification.goal.plan, id: plan_base_discover}:
|
||||
!record {model: gamification.challenge, id: challenge_base_discover}:
|
||||
reward_first_id: gamification.badge_good_job
|
||||
reward_failure: True
|
||||
-
|
||||
I check the demo user received the badge
|
||||
-
|
||||
!python {model: gamification.goal.plan}: |
|
||||
plan = self.browse(cr, uid, ref('plan_base_discover'), context=context)
|
||||
self.action_close(cr, uid, [plan.id])
|
||||
!python {model: gamification.challenge}: |
|
||||
challenge = self.browse(cr, uid, ref('challenge_base_discover'), context=context)
|
||||
self.action_close(cr, uid, [challenge.id])
|
||||
badge_ids = self.pool.get('gamification.badge.user').search(cr, uid, [('badge_id', '=', ref('badge_good_job')), ('user_id', '=', ref('base.user_demo'))])
|
||||
assert badge_ids, "Demo users didn't received the badge"
|
|
@ -101,7 +101,7 @@
|
|||
</div>
|
||||
</group>
|
||||
<group string="Rewards for challenges">
|
||||
<field name="plan_ids" widget="many2many_kanban" nolabel="1" />
|
||||
<field name="challenge_ids" widget="many2many_kanban" nolabel="1" />
|
||||
</group>
|
||||
<group string="Statistics">
|
||||
<group>
|
|
@ -2,11 +2,11 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="goal_plan_list_view" model="ir.ui.view">
|
||||
<record id="challenge_list_view" model="ir.ui.view">
|
||||
<field name="name">Challenges List</field>
|
||||
<field name="model">gamification.goal.plan</field>
|
||||
<field name="model">gamification.challenge</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Goal types" colors="blue:state == 'draft';grey:state == 'done'">
|
||||
<tree string="Goal definitions" colors="blue:state == 'draft';grey:state == 'done'">
|
||||
<field name="name"/>
|
||||
<field name="period"/>
|
||||
<field name="manager_id"/>
|
||||
|
@ -15,11 +15,11 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<record id="goals_from_plan_act" model="ir.actions.act_window">
|
||||
<record id="goals_from_challenge_act" model="ir.actions.act_window">
|
||||
<field name="res_model">gamification.goal</field>
|
||||
<field name="name">Related Goals</field>
|
||||
<field name="view_mode">kanban,tree</field>
|
||||
<field name="context">{'search_default_group_by_type': True, 'search_default_inprogress': True, 'search_default_plan_id': active_id, 'default_plan_id': active_id}</field>
|
||||
<field name="context">{'search_default_group_by_definition': True, 'search_default_inprogress': True, 'search_default_challenge_id': active_id, 'default_challenge_id': active_id}</field>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
There is no goals associated to this challenge matching your search.
|
||||
|
@ -28,11 +28,11 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<record id="goal_plan_form_view" model="ir.ui.view">
|
||||
<record id="challenge_form_view" model="ir.ui.view">
|
||||
<field name="name">Challenge Form</field>
|
||||
<field name="model">gamification.goal.plan</field>
|
||||
<field name="model">gamification.challenge</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Goal types" version="7.0">
|
||||
<form string="Goal definitions" version="7.0">
|
||||
<header>
|
||||
<button string="Start Now" type="object" name="action_start" states="draft" class="oe_highlight"/>
|
||||
<button string="Refresh Challenge" type="object" name="action_check" states="inprogress"/>
|
||||
|
@ -57,7 +57,7 @@
|
|||
|
||||
<!-- action buttons -->
|
||||
<div class="oe_right oe_button_box">
|
||||
<button type="action" name="%(goals_from_plan_act)d" string="Related Goals" attrs="{'invisible': [('state','=','draft')]}" />
|
||||
<button type="action" name="%(goals_from_challenge_act)d" string="Related Goals" attrs="{'invisible': [('state','=','draft')]}" />
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
|
@ -72,13 +72,13 @@
|
|||
</group>
|
||||
<notebook>
|
||||
<page string="Goals">
|
||||
<field name="planline_ids" nolabel="1" colspan="4">
|
||||
<tree string="Planline List" version="7.0" editable="bottom" >
|
||||
<field name="line_ids" nolabel="1" colspan="4">
|
||||
<tree string="Line List" version="7.0" editable="bottom" >
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="type_id" on_change="on_change_type_id(type_id)" />
|
||||
<field name="type_condition"/>
|
||||
<field name="definition_id" on_change="on_change_definition_id(definition_id)" />
|
||||
<field name="definition_condition"/>
|
||||
<field name="target_goal"/>
|
||||
<field name="type_full_suffix"/>
|
||||
<field name="definition_full_suffix"/>
|
||||
</tree>
|
||||
</field>
|
||||
<field name="description" placeholder="Describe the challenge: what is does, who it targets, why it matters..."/>
|
||||
|
@ -98,7 +98,7 @@
|
|||
<page string="Advanced Options">
|
||||
<group string="Subscriptions">
|
||||
<field name="autojoin_group_id" />
|
||||
<field name="proposed_user_ids" widget="many2many_tags" />
|
||||
<field name="invited_user_ids" widget="many2many_tags" />
|
||||
</group>
|
||||
<group string="Notification Messages">
|
||||
<field name="report_message_frequency" />
|
||||
|
@ -126,13 +126,12 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_goal_plan_kanban">
|
||||
<record model="ir.ui.view" id="view_challenge_kanban">
|
||||
<field name="name">Challenge Kanban</field>
|
||||
<field name="model">gamification.goal.plan</field>
|
||||
<field name="model">gamification.challenge</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban version="7.0" class="oe_background_grey">
|
||||
<field name="planline_ids"/>
|
||||
<field name="planline_count"/>
|
||||
<kanban string="Challenges" class="oe_background_grey" version="7.0">
|
||||
<field name="line_ids"/>
|
||||
<field name="user_ids"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
|
@ -147,9 +146,9 @@
|
|||
|
||||
<h4><field name="name"/></h4>
|
||||
<div class="oe_kanban_project_list">
|
||||
<a type="action" name="%(goals_from_plan_act)d" style="margin-right: 10px">
|
||||
<span t-if="record.planline_count.raw_value gt 1"><field name="planline_count"/> Goals</span>
|
||||
<span t-if="record.planline_count.raw_value lt 2"><field name="planline_count"/> Goal</span>
|
||||
<a type="action" name="%(goals_from_challenge_act)d" style="margin-right: 10px">
|
||||
<span t-if="record.line_ids.length gt 1"><t t-esc="record.line_ids.length"/> Goals</span>
|
||||
<span t-if="record.line_ids.length lt 2"><t t-esc="record.line_ids.length"/> Goal</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="oe_kanban_badge_avatars">
|
||||
|
@ -165,9 +164,9 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<record id="goal_plan_list_action" model="ir.actions.act_window">
|
||||
<record id="challenge_list_action" model="ir.actions.act_window">
|
||||
<field name="name">Challenges</field>
|
||||
<field name="res_model">gamification.goal.plan</field>
|
||||
<field name="res_model">gamification.challenge</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="context">{'search_default_inprogress':True, 'default_inprogress':True}</field>
|
||||
<field name="help" type="html">
|
||||
|
@ -182,40 +181,40 @@
|
|||
</field>
|
||||
</record>
|
||||
<!-- Specify form view ID to avoid selecting view_challenge_wizard -->
|
||||
<record id="goal_plan_list_action_view1" model="ir.actions.act_window.view">
|
||||
<record id="challenge_list_action_view1" model="ir.actions.act_window.view">
|
||||
<field eval="1" name="sequence"/>
|
||||
<field name="view_mode">kanban</field>
|
||||
<field name="act_window_id" ref="goal_plan_list_action"/>
|
||||
<field name="view_id" ref="view_goal_plan_kanban"/>
|
||||
<field name="act_window_id" ref="challenge_list_action"/>
|
||||
<field name="view_id" ref="view_challenge_kanban"/>
|
||||
</record>
|
||||
<record id="goal_plan_list_action_view2" model="ir.actions.act_window.view">
|
||||
<record id="challenge_list_action_view2" model="ir.actions.act_window.view">
|
||||
<field eval="10" name="sequence"/>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="act_window_id" ref="goal_plan_list_action"/>
|
||||
<field name="view_id" ref="goal_plan_form_view"/>
|
||||
<field name="act_window_id" ref="challenge_list_action"/>
|
||||
<field name="view_id" ref="challenge_form_view"/>
|
||||
</record>
|
||||
|
||||
<!-- Planline -->
|
||||
<record id="goal_planline_list_view" model="ir.ui.view">
|
||||
<field name="name">Goal planline list</field>
|
||||
<field name="model">gamification.goal.planline</field>
|
||||
<!-- Line -->
|
||||
<record id="challenge_line_list_view" model="ir.ui.view">
|
||||
<field name="name">Challenge line list</field>
|
||||
<field name="model">gamification.challenge.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="planline list" >
|
||||
<field name="type_id"/>
|
||||
<tree string="Challenge Lines" >
|
||||
<field name="definition_id"/>
|
||||
<field name="target_goal"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="goal_plan_search_view" model="ir.ui.view">
|
||||
<record id="challenge_search_view" model="ir.ui.view">
|
||||
<field name="name">Challenge Search</field>
|
||||
<field name="model">gamification.goal.plan</field>
|
||||
<field name="model">gamification.challenge</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Challenges">
|
||||
<filter name="inprogress" string="Running Challenges"
|
||||
domain="[('state', '=', 'inprogress')]"/>
|
||||
<filter name="hr_plans" string="HR Challenges"
|
||||
<filter name="hr_challenges" string="HR Challenges"
|
||||
domain="[('category', '=', 'hr')]"/>
|
||||
<field name="name"/>
|
||||
<group expand="0" string="Group By...">
|
||||
|
@ -229,7 +228,7 @@
|
|||
|
||||
<record id="view_challenge_wizard" model="ir.ui.view">
|
||||
<field name="name">Challenge Wizard</field>
|
||||
<field name="model">gamification.goal.plan</field>
|
||||
<field name="model">gamification.challenge</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Challenge" version="7.0">
|
||||
<field name="reward_failure" invisible="1"/>
|
||||
|
@ -241,16 +240,16 @@
|
|||
<field name="start_date" readonly="1" />
|
||||
<field name="end_date" readonly="1" />
|
||||
<field name="user_ids" string="Participating" readonly="1" widget="many2many_tags" />
|
||||
<field name="proposed_user_ids" string="Invited" readonly="1" widget="many2many_tags" />
|
||||
<field name="invited_user_ids" string="Invited" readonly="1" widget="many2many_tags" />
|
||||
</group>
|
||||
<group string="Goals">
|
||||
<field name="planline_ids" nolabel="1" readonly="1" colspan="4">
|
||||
<tree string="Planline List" version="7.0" editable="bottom" >
|
||||
<field name="line_ids" nolabel="1" readonly="1" colspan="4">
|
||||
<tree string="Challenge Lines" version="7.0" editable="bottom" >
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="type_id"/>
|
||||
<field name="type_condition"/>
|
||||
<field name="definition_id"/>
|
||||
<field name="definition_condition"/>
|
||||
<field name="target_goal"/>
|
||||
<field name="type_full_suffix"/>
|
||||
<field name="definition_full_suffix"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
|
@ -281,7 +280,7 @@
|
|||
|
||||
<record id="challenge_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Challenge Description</field>
|
||||
<field name="res_model">gamification.goal.plan</field>
|
||||
<field name="res_model">gamification.challenge</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="view_challenge_wizard"/>
|
||||
<field name="target">new</field>
|
|
@ -7,14 +7,14 @@
|
|||
<field name="name">Goals</field>
|
||||
<field name="res_model">gamification.goal</field>
|
||||
<field name="view_mode">tree,form,kanban</field>
|
||||
<field name="context">{'search_default_group_by_user': True, 'search_default_group_by_type': True}</field>
|
||||
<field name="context">{'search_default_group_by_user': True, 'search_default_group_by_definition': True}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a goal.
|
||||
</p>
|
||||
<p>
|
||||
A goal is defined by a user and a goal type.
|
||||
Goals can be created automatically by using goal plans.
|
||||
A goal is defined by a user and a goal definition.
|
||||
Goals can be created automatically by using challenges.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -24,7 +24,7 @@
|
|||
<field name="model">gamification.goal</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Goal List" colors="red:state == 'failed';green:state == 'reached';grey:state == 'canceled'">
|
||||
<field name="type_id" invisible="1" />
|
||||
<field name="definition_id" invisible="1" />
|
||||
<field name="user_id" invisible="1" />
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
|
@ -32,7 +32,7 @@
|
|||
<field name="target_goal"/>
|
||||
<field name="completeness" widget="progressbar"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="planline_id" invisible="1"/>
|
||||
<field name="line_id" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -53,9 +53,9 @@
|
|||
<sheet>
|
||||
<group>
|
||||
<group string="Reference">
|
||||
<field name="type_id" on_change="on_change_type_id(type_id)" attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
<field name="definition_id" on_change="on_change_definition_id(definition_id)" attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
<field name="user_id" attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
<field name="plan_id" attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
<field name="challenge_id" attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
</group>
|
||||
<group string="Schedule">
|
||||
<field name="start_date" attrs="{'readonly':[('state','!=','draft')]}"/>
|
||||
|
@ -73,14 +73,14 @@
|
|||
<label for="target_goal" />
|
||||
<div>
|
||||
<field name="target_goal" attrs="{'readonly':[('state','!=','draft')]}" class="oe_inline"/>
|
||||
<field name="type_suffix" class="oe_inline"/>
|
||||
<field name="definition_suffix" class="oe_inline"/>
|
||||
</div>
|
||||
<label for="current" />
|
||||
<div>
|
||||
<field name="current" class="oe_inline"/>
|
||||
<button string="refresh" type="object" name="update" class="oe_link" attrs="{'invisible':['|',('computation_mode', '=', 'manually'),('state', '=', 'draft')]}" />
|
||||
<div class="oe_grey" attrs="{'invisible':[('type_id', '=', False)]}">
|
||||
Reached when current value is <strong><field name="type_condition" class="oe_inline"/></strong> than the target.
|
||||
<div class="oe_grey" attrs="{'invisible':[('definition_id', '=', False)]}">
|
||||
Reached when current value is <strong><field name="definition_condition" class="oe_inline"/></strong> than the target.
|
||||
</div>
|
||||
</div>
|
||||
</group>
|
||||
|
@ -112,11 +112,11 @@
|
|||
<separator/>
|
||||
|
||||
<field name="user_id"/>
|
||||
<field name="type_id"/>
|
||||
<field name="plan_id"/>
|
||||
<field name="definition_id"/>
|
||||
<field name="challenge_id"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter name="group_by_user" string="User" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter name="group_by_type" string="Goal Type" domain="[]" context="{'group_by':'type_id'}"/>
|
||||
<filter name="group_by_definition" string="Goal Definition" domain="[]" context="{'group_by':'definition_id'}"/>
|
||||
<filter string="State" domain="[]" context="{'group_by':'state'}"/>
|
||||
<filter string="End Date" domain="[]" context="{'group_by':'end_date'}"/>
|
||||
</group>
|
||||
|
@ -129,43 +129,43 @@
|
|||
<field name="model">gamification.goal</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban version="7.0" class="oe_background_grey">
|
||||
<field name="type_id"/>
|
||||
<field name="definition_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="current"/>
|
||||
<field name="completeness"/>
|
||||
<field name="state"/>
|
||||
<field name="target_goal"/>
|
||||
<field name="type_condition"/>
|
||||
<field name="type_suffix"/>
|
||||
<field name="type_display"/>
|
||||
<field name="definition_condition"/>
|
||||
<field name="definition_suffix"/>
|
||||
<field name="definition_display"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="last_update"/>
|
||||
<templates>
|
||||
<t t-name="kanban-tooltip">
|
||||
<field name="type_description"/>
|
||||
<field name="definition_description"/>
|
||||
</t>
|
||||
<t t-name="kanban-box">
|
||||
<div t-attf-class="oe_kanban_card oe_gamification_goal oe_kanban_goal #{record.end_date.raw_value < record.last_update.raw_value & record.state.raw_value == 'failed' ? 'oe_kanban_color_2' : ''} #{record.end_date.raw_value < record.last_update.raw_value & record.state.raw_value == 'reached' ? 'oe_kanban_color_5' : ''}">
|
||||
<div class="oe_kanban_content">
|
||||
<p><h4 class="oe_goal_name" tooltip="kanban-tooltip"><field name="type_id" /></h4></p>
|
||||
<p><h4 class="oe_goal_name" tooltip="kanban-tooltip"><field name="definition_id" /></h4></p>
|
||||
<div class="oe_kanban_left">
|
||||
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" />
|
||||
</div>
|
||||
<field name="user_id" />
|
||||
<div class="oe_goal_state_block">
|
||||
<t t-if="record.type_display.raw_value == 'checkbox'">
|
||||
<t t-if="record.definition_display.raw_value == 'checkbox'">
|
||||
<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>
|
||||
<t t-if="record.state.raw_value=='failed'"><span class="oe_red" title="Goal Failed">X</span></t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="record.type_display.raw_value == 'progress'">
|
||||
<t t-if="record.type_condition.raw_value =='higher'">
|
||||
<field name="current" widget="gauge" style="width:160px; height: 120px;" options="{'max_field': 'target_goal', 'label_field': 'type_suffix'}" />
|
||||
<t t-if="record.definition_display.raw_value == 'progress'">
|
||||
<t t-if="record.definition_condition.raw_value =='higher'">
|
||||
<field name="current" widget="gauge" style="width:160px; height: 120px;" options="{'max_field': 'target_goal', 'label_field': 'definition_suffix'}" />
|
||||
</t>
|
||||
<t t-if="record.type_condition.raw_value != 'higher'">
|
||||
<t t-if="record.definition_condition.raw_value != 'higher'">
|
||||
<div t-attf-class="oe_goal_state #{record.current.raw_value == record.target_goal.raw_value+1 ? 'oe_orange' : record.current.raw_value > record.target_goal.raw_value ? 'oe_red' : 'oe_green'}">
|
||||
<t t-esc="record.current.raw_value" />
|
||||
</div>
|
||||
|
@ -191,29 +191,28 @@
|
|||
</record>
|
||||
|
||||
|
||||
<!-- Goal types view -->
|
||||
<!-- Goal definitions view -->
|
||||
|
||||
<record id="goal_type_list_action" model="ir.actions.act_window">
|
||||
<field name="name">Goal Types</field>
|
||||
<field name="res_model">gamification.goal.type</field>
|
||||
<record id="goal_definition_list_action" model="ir.actions.act_window">
|
||||
<field name="name">Goal Definitions</field>
|
||||
<field name="res_model">gamification.goal.definition</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a goal type.
|
||||
Click to create a goal definition.
|
||||
</p>
|
||||
<p>
|
||||
A goal type is a technical model of goal defining a condition to reach.
|
||||
A goal definition is a technical model of goal defining a condition to reach.
|
||||
The dates, values to reach or users are defined in goal instance.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="goal_type_list_view" model="ir.ui.view">
|
||||
<field name="name">Goal Types List</field>
|
||||
<field name="model">gamification.goal.type</field>
|
||||
<record id="goal_definition_list_view" model="ir.ui.view">
|
||||
<field name="name">Goal Definitions List</field>
|
||||
<field name="model">gamification.goal.definition</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Goal types">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<tree string="Goal Definitions">
|
||||
<field name="name"/>
|
||||
<field name="computation_mode"/>
|
||||
</tree>
|
||||
|
@ -221,11 +220,11 @@
|
|||
</record>
|
||||
|
||||
|
||||
<record id="goal_type_form_view" model="ir.ui.view">
|
||||
<field name="name">Goal Types Form</field>
|
||||
<field name="model">gamification.goal.type</field>
|
||||
<record id="goal_definition_form_view" model="ir.ui.view">
|
||||
<field name="name">Goal Definitions Form</field>
|
||||
<field name="model">gamification.goal.definition</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Goal types" version="7.0">
|
||||
<form string="Goal definitions" version="7.0">
|
||||
<sheet>
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1>
|
||||
|
@ -263,11 +262,11 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<record id="goal_type_search_view" model="ir.ui.view">
|
||||
<field name="name">Goal Type Search</field>
|
||||
<field name="model">gamification.goal.type</field>
|
||||
<record id="goal_definition_search_view" model="ir.ui.view">
|
||||
<field name="name">Goal Definition Search</field>
|
||||
<field name="model">gamification.goal.definition</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Goal Types">
|
||||
<search string="Search Goal Definitions">
|
||||
<field name="name"/>
|
||||
<field name="model_id"/>
|
||||
<field name="field_id"/>
|
||||
|
@ -302,8 +301,8 @@
|
|||
<!-- menus in settings - technical feature required -->
|
||||
<menuitem id="gamification_menu" name="Gamification Tools" parent="base.menu_administration" groups="base.group_no_one" />
|
||||
<menuitem id="gamification_goal_menu" parent="gamification_menu" action="goal_list_action" sequence="0"/>
|
||||
<menuitem id="gamification_plan_menu" parent="gamification_menu" action="goal_plan_list_action" sequence="10"/>
|
||||
<menuitem id="gamification_type_menu" parent="gamification_menu" action="goal_type_list_action" sequence="20"/>
|
||||
<menuitem id="gamification_challenge_menu" parent="gamification_menu" action="challenge_list_action" sequence="10"/>
|
||||
<menuitem id="gamification_definition_menu" parent="gamification_menu" action="goal_definition_list_action" sequence="20"/>
|
||||
<menuitem id="gamification_badge_menu" parent="gamification_menu" action="badge_list_action" sequence="30"/>
|
||||
|
||||
</data>
|
|
@ -24,7 +24,7 @@
|
|||
'author': 'OpenERP SA',
|
||||
'category': 'hidden',
|
||||
'depends': ['gamification','sale_crm'],
|
||||
'description': """Example of goal types and plans that can be used related to the usage of the CRM Sale module.""",
|
||||
'description': """Example of goal definitions and challenges that can be used related to the usage of the CRM Sale module.""",
|
||||
|
||||
'data': ['sale_crm_goals.xml'],
|
||||
'demo': ['sale_crm_goals_demo.xml'],
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- goal types -->
|
||||
<record model="gamification.goal.type" id="type_crm_tot_invoices">
|
||||
<!-- goal definitions -->
|
||||
<record model="gamification.goal.definition" id="definition_crm_tot_invoices">
|
||||
<field name="name">Total Invoiced</field>
|
||||
<field name="description"></field>
|
||||
<field name="computation_mode">sum</field>
|
||||
|
@ -14,7 +14,7 @@
|
|||
<field name="domain">[('state','!=','cancel'),('user_id','=',user.id),('type','=','out_invoice')]</field>
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.type" id="type_crm_nbr_new_leads">
|
||||
<record model="gamification.goal.definition" id="definition_crm_nbr_new_leads">
|
||||
<field name="name">New Leads</field>
|
||||
<field name="description">Based on the creation date</field>
|
||||
<field name="computation_mode">count</field>
|
||||
|
@ -25,7 +25,7 @@
|
|||
<field name="domain">[('user_id','=',user.id), '|', ('type', '=', 'lead'), ('type', '=', 'opportunity')]</field>
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.type" id="type_crm_lead_delay_open">
|
||||
<record model="gamification.goal.definition" id="definition_crm_lead_delay_open">
|
||||
<field name="name">Time to Qualify a Lead</field>
|
||||
<field name="description">The average number of days to open the case (lower than)</field>
|
||||
<field name="computation_mode">sum</field>
|
||||
|
@ -37,7 +37,7 @@
|
|||
<field name="domain">[('user_id','=',user.id),('type', '=', 'lead')]</field>
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.type" id="type_crm_lead_delay_close">
|
||||
<record model="gamification.goal.definition" id="definition_crm_lead_delay_close">
|
||||
<field name="name">Days to Close a Deal</field>
|
||||
<field name="description">The average number of days to close the case (lower than)</field>
|
||||
<field name="computation_mode">sum</field>
|
||||
|
@ -50,7 +50,7 @@
|
|||
</record>
|
||||
|
||||
|
||||
<record model="gamification.goal.type" id="type_crm_nbr_call">
|
||||
<record model="gamification.goal.definition" id="definition_crm_nbr_call">
|
||||
<field name="name">Logged Calls</field>
|
||||
<field name="description">Log a certain number of calls to reach this goal</field>
|
||||
<field name="computation_mode">count</field>
|
||||
|
@ -60,7 +60,7 @@
|
|||
<field name="domain">[('user_id','=',user.id),('state','=','done')]</field>
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.type" id="type_crm_nbr_new_opportunities">
|
||||
<record model="gamification.goal.definition" id="definition_crm_nbr_new_opportunities">
|
||||
<field name="name">New Opportunities</field>
|
||||
<field name="description">Based on the opening date</field>
|
||||
<field name="computation_mode">count</field>
|
||||
|
@ -70,7 +70,7 @@
|
|||
<field name="domain">[('user_id','=',user.id),('type','=','opportunity')]</field>
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.type" id="type_crm_nbr_sale_order_created">
|
||||
<record model="gamification.goal.definition" id="definition_crm_nbr_sale_order_created">
|
||||
<field name="name">New Sales Orders</field>
|
||||
<field name="description">Based on the creation date</field>
|
||||
<field name="computation_mode">count</field>
|
||||
|
@ -80,7 +80,7 @@
|
|||
<field name="domain">[('user_id','=',user.id),('state','not in',('draft', 'sent', 'cancel'))]</field>
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.type" id="type_crm_nbr_paid_sale_order">
|
||||
<record model="gamification.goal.definition" id="definition_crm_nbr_paid_sale_order">
|
||||
<field name="name">Paid Sales Orders</field>
|
||||
<field name="description">Based on the invoice date</field>
|
||||
<field name="computation_mode">count</field>
|
||||
|
@ -89,7 +89,7 @@
|
|||
<field name="field_date_id" eval="ref('account.field_account_invoice_report_day')" />
|
||||
<field name="domain">[('state','=','paid'),('user_id','=',user.id),('type','=','out_invoice')]</field>
|
||||
</record>
|
||||
<record model="gamification.goal.type" id="type_crm_tot_paid_sale_order">
|
||||
<record model="gamification.goal.definition" id="definition_crm_tot_paid_sale_order">
|
||||
<field name="name">Total Paid Sales Orders</field>
|
||||
<field name="description">Based on the invoice date</field>
|
||||
<field name="computation_mode">count</field>
|
||||
|
@ -101,7 +101,7 @@
|
|||
</record>
|
||||
|
||||
|
||||
<record model="gamification.goal.type" id="type_crm_nbr_customer_refunds">
|
||||
<record model="gamification.goal.definition" id="definition_crm_nbr_customer_refunds">
|
||||
<field name="name">Customer Refunds</field>
|
||||
<field name="description">Refund the least customers (lower than)</field>
|
||||
<field name="computation_mode">count</field>
|
||||
|
@ -111,7 +111,7 @@
|
|||
<field name="field_date_id" eval="ref('account.field_account_invoice_report_day')" />
|
||||
<field name="domain">[('state','!=','cancel'),('user_id','=',user.id),('type','=','out_refund')]</field>
|
||||
</record>
|
||||
<record model="gamification.goal.type" id="type_crm_tot_customer_refunds">
|
||||
<record model="gamification.goal.definition" id="definition_crm_tot_customer_refunds">
|
||||
<field name="name">Total Customer Refunds</field>
|
||||
<field name="description">The total refunded value is a negative value. Validated when higher (min refunded).</field>
|
||||
<field name="computation_mode">sum</field>
|
||||
|
@ -125,8 +125,8 @@
|
|||
|
||||
|
||||
|
||||
<!-- plans -->
|
||||
<record model="gamification.goal.plan" id="plan_crm_sale">
|
||||
<!-- challenges -->
|
||||
<record model="gamification.challenge" id="challenge_crm_sale">
|
||||
<field name="name">Monthly Sales Targets</field>
|
||||
<field name="period">monthly</field>
|
||||
<field name="visibility_mode">board</field>
|
||||
|
@ -135,7 +135,7 @@
|
|||
<field name="report_header">The following message contains the current progress of the sale team based on several criterias. The progress is reinitialised each month and shared weekly.</field>
|
||||
</record>
|
||||
|
||||
<record model="gamification.goal.plan" id="plan_crm_marketing">
|
||||
<record model="gamification.challenge" id="challenge_crm_marketing">
|
||||
<field name="name">Lead Acquisition</field>
|
||||
<field name="period">monthly</field>
|
||||
<field name="visibility_mode">progressbar</field>
|
||||
|
@ -144,30 +144,30 @@
|
|||
<field name="report_header">The following message contains the current progress of the marketing team based on several criterias. The progress is reinitialised each month and shared weekly.</field>
|
||||
</record>
|
||||
|
||||
<!-- planlines -->
|
||||
<record model="gamification.goal.planline" id="planline_crm_sale1">
|
||||
<field name="type_id" eval="ref('type_crm_tot_invoices')" />
|
||||
<!-- lines -->
|
||||
<record model="gamification.challenge.line" id="line_crm_sale1">
|
||||
<field name="definition_id" eval="ref('definition_crm_tot_invoices')" />
|
||||
<field name="target_goal">20000</field>
|
||||
<field name="plan_id" eval="ref('plan_crm_sale')" />
|
||||
<field name="challenge_id" eval="ref('challenge_crm_sale')" />
|
||||
</record>
|
||||
|
||||
|
||||
<record model="gamification.goal.planline" id="planline_crm_marketing1">
|
||||
<field name="type_id" eval="ref('type_crm_nbr_new_leads')" />
|
||||
<record model="gamification.challenge.line" id="line_crm_marketing1">
|
||||
<field name="definition_id" eval="ref('definition_crm_nbr_new_leads')" />
|
||||
<field name="target_goal">7</field>
|
||||
<field name="plan_id" eval="ref('plan_crm_marketing')" />
|
||||
<field name="challenge_id" eval="ref('challenge_crm_marketing')" />
|
||||
<field name="sequence">1</field>
|
||||
</record>
|
||||
<record model="gamification.goal.planline" id="planline_crm_marketing2">
|
||||
<field name="type_id" eval="ref('type_crm_lead_delay_open')" />
|
||||
<record model="gamification.challenge.line" id="line_crm_marketing2">
|
||||
<field name="definition_id" eval="ref('definition_crm_lead_delay_open')" />
|
||||
<field name="target_goal">15</field>
|
||||
<field name="plan_id" eval="ref('plan_crm_marketing')" />
|
||||
<field name="challenge_id" eval="ref('challenge_crm_marketing')" />
|
||||
<field name="sequence">2</field>
|
||||
</record>
|
||||
<record model="gamification.goal.planline" id="planline_crm_marketing3">
|
||||
<field name="type_id" eval="ref('type_crm_nbr_new_opportunities')" />
|
||||
<record model="gamification.challenge.line" id="line_crm_marketing3">
|
||||
<field name="definition_id" eval="ref('definition_crm_nbr_new_opportunities')" />
|
||||
<field name="target_goal">5</field>
|
||||
<field name="plan_id" eval="ref('plan_crm_marketing')" />
|
||||
<field name="challenge_id" eval="ref('challenge_crm_marketing')" />
|
||||
<field name="sequence">3</field>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -2,17 +2,17 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- plans -->
|
||||
<record model="gamification.goal.plan" id="plan_crm_sale">
|
||||
<!-- challenges -->
|
||||
<record model="gamification.challenge" id="challenge_crm_sale">
|
||||
<field name="user_ids" eval="[(4,ref('base.user_demo'))]" />
|
||||
<field name="state">inprogress</field>
|
||||
</record>
|
||||
|
||||
<!-- goals -->
|
||||
<record model="gamification.goal" id="goal_crm_sale1">
|
||||
<field name="type_id" eval="ref('type_crm_tot_invoices')" />
|
||||
<field name="definition_id" eval="ref('definition_crm_tot_invoices')" />
|
||||
<field name="user_id" eval="ref('base.user_demo')" />
|
||||
<field name="planline_id" eval="ref('planline_crm_sale1')" />
|
||||
<field name="line_id" eval="ref('line_crm_sale1')" />
|
||||
<field name="start_date" eval="time.strftime('2013-03-01')" />
|
||||
<field name="end_date" eval="time.strftime('2013-03-31')" />
|
||||
<field name="target_goal">2000</field>
|
||||
|
|
|
@ -131,7 +131,7 @@ class hr_employee(osv.osv):
|
|||
"""Return the list of goals assigned to the employee"""
|
||||
res = {}
|
||||
for employee in self.browse(cr, uid, ids, context=context):
|
||||
res[employee.id] = self.pool.get('gamification.goal').search(cr,uid,[('user_id', '=', employee.user_id.id), ('plan_id.category', '=', 'hr')], context=context)
|
||||
res[employee.id] = self.pool.get('gamification.goal').search(cr,uid,[('user_id', '=', employee.user_id.id), ('challenge_id.category', '=', 'hr')], context=context)
|
||||
return res
|
||||
|
||||
def _get_employee_badges(self, cr, uid, ids, field_name, arg, context=None):
|
||||
|
|
|
@ -93,22 +93,22 @@
|
|||
<field name="name">Goals History</field>
|
||||
<field name="view_mode">tree,kanban</field>
|
||||
<field name="context">{'search_default_group_by_user': True, 'search_default_group_by_type': True}</field>
|
||||
<field name="domain">[('plan_id.category', '=', 'hr')]</field>
|
||||
<field name="domain">[('challenge_id.category', '=', 'hr')]</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a goal.
|
||||
</p>
|
||||
<p>
|
||||
A goal is defined by a user and a goal type.
|
||||
Goals can be created automatically by using goal plans.
|
||||
Goals can be created automatically by using challenges.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="goal_plan_list_action2" model="ir.actions.act_window">
|
||||
<record id="challenge_list_action2" model="ir.actions.act_window">
|
||||
<field name="name">Challenges</field>
|
||||
<field name="res_model">gamification.goal.plan</field>
|
||||
<field name="res_model">gamification.challenge</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="domain">[('category', '=', 'hr')]</field>
|
||||
<field name="context">{'search_default_inprogress':True, 'default_inprogress':True}</field>
|
||||
|
@ -123,23 +123,23 @@
|
|||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<record id="goal_plan_list_action2_view1" model="ir.actions.act_window.view">
|
||||
<record id="challenge_list_action2_view1" model="ir.actions.act_window.view">
|
||||
<field eval="1" name="sequence"/>
|
||||
<field name="view_mode">kanban</field>
|
||||
<field name="act_window_id" ref="goal_plan_list_action2"/>
|
||||
<field name="view_id" ref="gamification.view_goal_plan_kanban"/>
|
||||
<field name="act_window_id" ref="challenge_list_action2"/>
|
||||
<field name="view_id" ref="gamification.view_challenge_kanban"/>
|
||||
</record>
|
||||
<record id="goal_plan_list_action2_view2" model="ir.actions.act_window.view">
|
||||
<record id="challenge_list_action2_view2" model="ir.actions.act_window.view">
|
||||
<field eval="10" name="sequence"/>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="act_window_id" ref="goal_plan_list_action2"/>
|
||||
<field name="view_id" ref="gamification.goal_plan_form_view"/>
|
||||
<field name="act_window_id" ref="challenge_list_action2"/>
|
||||
<field name="view_id" ref="gamification.challenge_form_view"/>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_hr_gamification" parent="hr.menu_hr_root" name="Engagement" sequence="40"/>
|
||||
|
||||
<menuitem id="gamification_badge_menu_hr" parent="menu_hr_gamification" action="gamification.badge_list_action" />
|
||||
<menuitem id="gamification_plan_menu_hr" parent="menu_hr_gamification" action="goal_plan_list_action2" groups="base.group_hr_user"/>
|
||||
<menuitem id="gamification_challenge_menu_hr" parent="menu_hr_gamification" action="challenge_list_action2" groups="base.group_hr_user"/>
|
||||
<menuitem id="gamification_goal_menu_hr" parent="menu_hr_gamification" action="goals_menu_groupby_action2" groups="base.group_hr_user"/>
|
||||
|
||||
</data>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
plan_officer,"Goal Plan Officer",gamification.model_gamification_goal_plan,base.group_hr_user,1,1,1,1
|
||||
planline_officer,"Goal Planline Officer",gamification.model_gamification_goal_planline,base.group_hr_user,1,1,1,1
|
||||
challenge_officer,"Challenge Officer",gamification.model_gamification_challenge,base.group_hr_user,1,1,1,1
|
||||
challenge_line_officer,"Challenge Line Officer",gamification.model_gamification_challenge_line,base.group_hr_user,1,1,1,1
|
||||
badge_officer,"Badge Officer",gamification.model_gamification_badge,base.group_hr_user,1,1,1,1
|
||||
badge_user_officer,"Badge-user Officer",gamification.model_gamification_badge_user,base.group_hr_user,1,1,1,1
|
|
|
@ -1,7 +1,7 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
goal_portal,"Goal Portal",gamification.model_gamification_goal,portal.group_portal,1,1,0,0
|
||||
goal_type_portal,"Goal Type Portal",gamification.model_gamification_goal_type,portal.group_portal,1,0,0,0
|
||||
plan_portal,"Goal Plan Portal",gamification.model_gamification_goal_plan,portal.group_portal,1,0,0,0
|
||||
planline_portal,"Goal Planline Portal",gamification.model_gamification_goal_planline,portal.group_portal,1,0,0,0
|
||||
goal_definition_portal,"Goal Definition Portal",gamification.model_gamification_goal_definition,portal.group_portal,1,0,0,0
|
||||
challenge_portal,"Goal Challenge Portal",gamification.model_gamification_challenge,portal.group_portal,1,0,0,0
|
||||
challenge_line_portal,"Challenge Line Portal",gamification.model_gamification_challenge_line,portal.group_portal,1,0,0,0
|
||||
badge_portal,"Badge Portal",gamification.model_gamification_badge,portal.group_portal,1,0,0,0
|
||||
badge_user_portal,"Badge-user Portal",gamification.model_gamification_badge_user,portal.group_portal,1,1,1,0
|
||||
|
|
|
Loading…
Reference in New Issue