summaryrefslogtreecommitdiff
path: root/addons/gamification/views
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/gamification/views
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/gamification/views')
-rw-r--r--addons/gamification/views/badge.xml202
-rw-r--r--addons/gamification/views/challenge.xml230
-rw-r--r--addons/gamification/views/gamification.xml7
-rw-r--r--addons/gamification/views/gamification_karma_rank_views.xml94
-rw-r--r--addons/gamification/views/gamification_karma_tracking_views.xml63
-rw-r--r--addons/gamification/views/goal.xml300
-rw-r--r--addons/gamification/views/mail_templates.xml55
-rw-r--r--addons/gamification/views/res_users_views.xml17
8 files changed, 968 insertions, 0 deletions
diff --git a/addons/gamification/views/badge.xml b/addons/gamification/views/badge.xml
new file mode 100644
index 00000000..522179c3
--- /dev/null
+++ b/addons/gamification/views/badge.xml
@@ -0,0 +1,202 @@
+<odoo>
+ <!-- Badge views -->
+ <record id="gamification_badge_view_search" model="ir.ui.view">
+ <field name="name">gamification.badge.view.search</field>
+ <field name="model">gamification.badge</field>
+ <field name="arch" type="xml">
+ <search string="Search Badge">
+ <field name="name"/>
+ <separator/>
+ <filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
+ </search>
+ </field>
+ </record>
+
+ <record id="badge_list_action" model="ir.actions.act_window">
+ <field name="name">Badges</field>
+ <field name="res_model">gamification.badge</field>
+ <field name="view_mode">kanban,tree,form</field>
+ <field name="search_view_id" ref="gamification_badge_view_search"/>
+ <field name="help" type="html">
+ <p class="o_view_nocontent_smiling_face">
+ Create a new badge
+ </p><p>
+ A badge is a symbolic token granted to a user as a sign of reward.
+ It can be deserved automatically when some conditions are met or manually by users.
+ Some badges are harder than others to get with specific conditions.
+ </p>
+ </field>
+ </record>
+
+
+ <record id="badge_list_view" model="ir.ui.view">
+ <field name="name">Badge List</field>
+ <field name="model">gamification.badge</field>
+ <field name="arch" type="xml">
+ <tree string="Badge List">
+ <field name="name"/>
+ <field name="granted_count"/>
+ <field name="stat_this_month"/>
+ <field name="stat_my"/>
+ <field name="rule_auth"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="badge_form_view" model="ir.ui.view">
+ <field name="name">Badge Form</field>
+ <field name="model">gamification.badge</field>
+ <field name="arch" type="xml">
+ <form string="Badge">
+ <header>
+ <button string="Grant this Badge" type="action" name="%(action_grant_wizard)d" class="oe_highlight" attrs="{'invisible': [('remaining_sending','=',0)]}" />
+ </header>
+ <sheet>
+ <div class="oe_button_box" name="button_box"/>
+ <widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
+ <field name="image_1920" widget="image" class="oe_avatar" options="{'preview_image': 'image_128'}"/>
+ <div class="oe_title">
+ <label for="name" class="oe_edit_only"/>
+ <h1>
+ <field name="name" placeholder="Badge Name"/>
+ </h1>
+ </div>
+ <group>
+ <field name="description" nolabel="1" placeholder="Badge Description"/>
+ </group>
+ <group string="Granting">
+ <div class="oe_grey" colspan="2">
+ Security rules to define who is allowed to manually grant badges. Not enforced for administrator.
+ </div>
+ <group>
+ <field name="active" invisible="1"/>
+ <field name="rule_auth" widget="radio"/>
+ <field name="rule_auth_user_ids" attrs="{'invisible': [('rule_auth','!=','users')]}" widget="many2many_tags" />
+ <field name="rule_auth_badge_ids" attrs="{'invisible': [('rule_auth','!=','having')]}" widget="many2many_tags" />
+ <field name="rule_max" attrs="{'invisible': [('rule_auth','=','nobody')]}" />
+ <field name="rule_max_number" attrs="{'invisible': ['|',('rule_max','=',False),('rule_auth','=','nobody')]}"/>
+ <label for="stat_my_monthly_sending"/>
+ <div>
+ <field name="stat_my_monthly_sending" attrs="{'invisible': [('rule_auth','=','nobody')]}" />
+ <div attrs="{'invisible': [('remaining_sending','=',-1)]}" class="oe_grey">
+ You can still grant <field name="remaining_sending" class="oe_inline"/> badges this month
+ </div>
+ <div attrs="{'invisible': [('remaining_sending','!=',-1)]}" class="oe_grey">
+ No monthly sending limit
+ </div>
+ </div>
+ </group>
+ </group>
+ <group string="Rewards for challenges">
+ <field name="challenge_ids" mode="kanban" widget="many2many" nolabel="1" context="{'default_reward_id': active_id}" />
+ <field name="level"/>
+ </group>
+ <group id="badge_statistics" string="Statistics">
+ <group>
+ <field name="granted_count"/>
+ <field name="stat_this_month"/>
+ <field name="granted_users_count"/>
+ </group>
+ <group>
+ <field name="stat_my"/>
+ <field name="stat_my_this_month"/>
+ </group>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+
+ <record id="badge_kanban_view" model="ir.ui.view" >
+ <field name="name">Badge Kanban View</field>
+ <field name="model">gamification.badge</field>
+ <field name="arch" type="xml">
+ <kanban class="o_kanban_badge">
+ <field name="id"/>
+ <field name="name"/>
+ <field name="description"/>
+ <field name="stat_my"/>
+ <field name="granted_count"/>
+ <field name="stat_this_month"/>
+ <field name="unique_owner_ids"/>
+ <field name="stat_my_monthly_sending"/>
+ <field name="remaining_sending" />
+ <field name="rule_max_number" />
+ <templates>
+ <t t-name="kanban-box">
+ <div t-attf-class="o_kanban_gamification oe_kanban_global_click #{record.stat_my.raw_value ? 'oe_kanban_color_5' : 'oe_kanban_color_white'}">
+ <div class="o_kanban_image">
+ <img t-att-src="kanban_image('gamification.badge', 'image_1024', record.id.raw_value)" t-att-title="record.name.value" t-att-alt="record.name.value"/>
+ </div>
+ <div class="oe_kanban_details">
+ <strong class="o_kanban_record_title"><field name="name"/></strong>
+ <span class="oe_grey">
+ <t t-if="record.remaining_sending.value != -1">
+ <t t-esc="record.stat_my_monthly_sending.value"/>/<t t-esc="record.rule_max_number.value"/>
+ </t>
+ <t t-if="record.remaining_sending.value == -1">
+ <t t-esc="record.stat_my_monthly_sending.value"/>/∞
+ </t>
+ </span>
+ <div t-if="record.remaining_sending.value == 0" class="oe_grey">Can not grant</div>
+ <div>
+ <strong><t t-esc="record.granted_count.raw_value"/></strong> granted,
+ <strong><t t-esc="record.stat_this_month.raw_value"/></strong> this month
+ </div>
+ <div t-if="record.description.value" class="o_kanban_badge_description">
+ <em><field name="description"/></em>
+ <div>
+ <t t-foreach="record.unique_owner_ids.raw_value.slice(0,11)" t-as="owner">
+ <img class="oe_kanban_avatar o_image_24_cover" t-att-src="kanban_image('res.users', 'image_128', owner)" t-att-data-member_id="owner" alt="Owner"/>
+ </t>
+ </div>
+ </div>
+ <div t-if="record.remaining_sending.value != 0 and !selection_mode" class="o_kanban_button">
+ <button type="action" name="%(action_grant_wizard)d" class="oe_highlight btn btn-primary">Grant</button>
+ </div>
+ </div>
+ </div>
+ </t>
+ </templates>
+ </kanban>
+ </field>
+ </record>
+
+
+ <!-- Badge user viewss -->
+
+ <record id="badge_user_kanban_view" model="ir.ui.view" >
+ <field name="name">Badge User Kanban View</field>
+ <field name="model">gamification.badge.user</field>
+ <field name="arch" type="xml">
+ <kanban class="oe_background_grey">
+ <field name="badge_name"/>
+ <field name="badge_id"/>
+ <field name="user_id"/>
+ <field name="comment"/>
+ <field name="create_date"/>
+ <templates>
+ <t t-name="kanban-box">
+ <div class="oe_kanban_card oe_kanban_global_click oe_kanban_badge oe_kanban_color_white o_kanban_gamification">
+ <div class="o_kanban_content">
+ <div class="o_kanban_image">
+ <a type="open"><img t-att-src="kanban_image('gamification.badge', 'image_1024', record.badge_id.raw_value)" t-att-title="record.badge_name.value" t-att-alt="record.badge_name.value" /></a>
+ </div>
+ <div class="oe_kanban_details">
+ <h4 class="mt0 mb0">
+ <a class="o_kanban_record_title" type="open"><t t-esc="record.badge_name.raw_value" /></a>
+ </h4>
+ <t t-if="record.comment.raw_value">
+ <p class="o_kanban_record_subtitle"><em><field name="comment"/></em></p>
+ </t>
+ <p>Granted by <a type="open"><field name="create_uid" /></a> the <t t-esc="moment(record.create_date.raw_value).format('L')" /></p>
+ </div>
+ </div>
+ </div>
+ </t>
+ </templates>
+ </kanban>
+ </field>
+ </record>
+</odoo>
diff --git a/addons/gamification/views/challenge.xml b/addons/gamification/views/challenge.xml
new file mode 100644
index 00000000..66a4b400
--- /dev/null
+++ b/addons/gamification/views/challenge.xml
@@ -0,0 +1,230 @@
+<odoo>
+ <record id="challenge_list_view" model="ir.ui.view">
+ <field name="name">Challenges List</field>
+ <field name="model">gamification.challenge</field>
+ <field name="arch" type="xml">
+ <tree string="Goal definitions" decoration-info="state == 'draft'" decoration-muted="state == 'done'">
+ <field name="name"/>
+ <field name="period"/>
+ <field name="manager_id"/>
+ <field name="state"/>
+ </tree>
+ </field>
+ </record>
+
+ <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,form</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 class="o_view_nocontent_empty_folder">
+ No goal found
+ </p><p>
+ There is no goal associated to this challenge matching your search.
+ Make sure that your challenge is active and assigned to at least one user.
+ </p>
+ </field>
+ </record>
+
+ <record id="challenge_form_view" model="ir.ui.view">
+ <field name="name">Challenge Form</field>
+ <field name="model">gamification.challenge</field>
+ <field name="arch" type="xml">
+ <form string="Goal definitions">
+ <header>
+ <button string="Start Challenge" type="object" name="action_start" states="draft" class="oe_highlight"/>
+ <button string="Refresh Challenge" type="object" name="action_check" states="inprogress"/>
+ <button string="Send Report" type="object" name="action_report_progress" states="inprogress,done" groups="base.group_no_one"/>
+ <field name="state" widget="statusbar" options="{'clickable': '1'}"/>
+ </header>
+ <sheet>
+ <!-- action buttons -->
+ <div class="oe_button_box" name="button_box">
+ <button type="action"
+ name="%(goals_from_challenge_act)d"
+ class="oe_stat_button"
+ icon="fa-gift"
+ attrs="{'invisible': [('state','=','draft')]}">
+ <div class="o_field_widget o_stat_info">
+ <span class="o_stat_text">Related</span>
+ <span class="o_stat_text">Goals</span>
+ </div>
+ </button>
+ </div>
+
+ <div class="oe_title">
+ <label for="name" class="oe_edit_only"/>
+ <h1>
+ <field name="name" placeholder="e.g. Monthly Sales Objectives"/>
+ </h1>
+ <label for="user_domain" class="oe_edit_only" string="Assign Challenge To"/>
+ <div>
+ <field name="user_domain" widget="domain" options="{'model': 'res.users'}" />
+ <field name="user_ids" widget="many2many_tags" />
+ </div>
+ </div>
+
+ <group>
+ <group>
+ <field name="period" attrs="{'readonly':[('state','!=','draft')]}"/>
+ <field name="visibility_mode" widget="radio" colspan="1" />
+ </group>
+ <group>
+ <field name="manager_id"/>
+ <field name="start_date" attrs="{'readonly':[('state','!=','draft')]}"/>
+ <field name="end_date" attrs="{'readonly':[('state','!=','draft')]}"/>
+ </group>
+ </group>
+ <notebook>
+ <page string="Goals" name="goals">
+ <field name="line_ids" nolabel="1" colspan="4">
+ <tree string="Line List" editable="bottom" >
+ <field name="sequence" widget="handle"/>
+ <field name="definition_id" />
+ <field name="condition"/>
+ <field name="target_goal" string="Target"/>
+ <field name="definition_full_suffix"/>
+ </tree>
+ </field>
+ <field name="description" placeholder="Describe the challenge: what is does, who it targets, why it matters..."/>
+ </page>
+ <page string="Reward" name="reward">
+ <group>
+ <field name="reward_id" attrs="{'required': [('reward_realtime','=', True)]}" />
+ <field name="reward_first_id" />
+ <field name="reward_second_id" attrs="{'invisible': [('reward_first_id','=', False)]}" />
+ <field name="reward_third_id" attrs="{'invisible': ['|',('reward_first_id','=', False),('reward_second_id','=', False)]}" />
+ <field name="reward_failure" attrs="{'invisible': [('reward_first_id','=', False)]}" />
+ <field name="reward_realtime" />
+ </group>
+ <div class="oe_grey">
+ <p>Badges are granted when a challenge is finished. This is either at the end of a running period (eg: end of the month for a monthly challenge), at the end date of a challenge (if no periodicity is set) or when the challenge is manually closed.</p>
+ </div>
+ </page>
+ <page string="Advanced Options" name="advanced_options">
+ <group string="Subscriptions">
+ <field name="invited_user_ids" widget="many2many_tags" />
+ </group>
+ <group string="Notification Messages">
+ <div class="oe_grey" colspan="4">
+ <p>Depending on the Display mode, reports will be individual or shared.</p>
+ </div>
+ <group colspan="4">
+ <field name="report_message_frequency"/>
+ <field name="report_template_id" attrs="{'invisible': [('report_message_frequency','=','never')]}" />
+ <field name="report_message_group_id" attrs="{'invisible': [('report_message_frequency','=','never')]}" />
+ </group>
+ </group>
+ <group string="Reminders for Manual Goals">
+ <label for="remind_update_delay" />
+ <div>
+ <field name="remind_update_delay" class="oe_inline"/> days
+ </div>
+ </group>
+ <group string="Category" groups="base.group_no_one">
+ <field name="challenge_category" widget="radio" />
+ </group>
+ </page>
+ </notebook>
+
+ </sheet>
+ <div class="oe_chatter">
+ <field name="message_follower_ids"/>
+ <field name="message_ids"/>
+ </div>
+ </form>
+ </field>
+ </record>
+
+ <record model="ir.ui.view" id="view_challenge_kanban">
+ <field name="name">Challenge Kanban</field>
+ <field name="model">gamification.challenge</field>
+ <field name="arch" type="xml">
+ <kanban string="Challenges" class="oe_background_grey">
+ <field name="line_ids"/>
+ <field name="user_ids"/>
+ <templates>
+ <t t-name="kanban-box">
+ <div t-attf-class="oe_kanban_card o_kanban_gamification oe_kanban_global_click">
+ <div class="o_kanban_content">
+ <strong>
+ <h4 class="o_kanban_record_title"><field name="name"/></h4>
+ <div class="oe_kanban_project_list o_kanban_record_subtitle">
+ <a type="action" name="%(goals_from_challenge_act)d" style="margin-right: 10px" tabindex="-1">
+ <span t-if="record.line_ids.raw_value.length gt 1"><t t-esc="record.line_ids.raw_value.length"/> Goals</span>
+ <span t-if="record.line_ids.raw_value.length lt 2"><t t-esc="record.line_ids.raw_value.length"/> Goal</span>
+ </a>
+ </div>
+ </strong>
+ <t t-foreach="record.user_ids.raw_value.slice(0,11)" t-as="member">
+ <img class="o_kanban_badge_avatars" t-att-src="kanban_image('res.users', 'image_128', member)" t-att-data-member_id="member" alt="Member"/>
+ </t>
+ </div>
+ </div>
+ </t>
+ </templates>
+ </kanban>
+ </field>
+ </record>
+
+ <record id="challenge_list_action" model="ir.actions.act_window">
+ <field name="name">Challenges</field>
+ <field name="res_model">gamification.challenge</field>
+ <field name="view_mode">kanban,tree</field>
+ <field name="context">{'search_default_inprogress':True, 'default_inprogress':True}</field>
+ <field name="help" type="html">
+ <p class="o_view_nocontent_smiling_face">
+ Create a new challenge
+ </p><p>
+ Assign a list of goals to chosen users to evaluate them.
+ The challenge can use a period (weekly, monthly...) for automatic creation of goals.
+ The goals are created for the specified users or member of the group.
+ </p>
+ </field>
+ </record>
+ <!-- Specify form view ID to avoid selecting view_challenge_wizard -->
+ <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="challenge_list_action"/>
+ <field name="view_id" ref="view_challenge_kanban"/>
+ </record>
+ <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="challenge_list_action"/>
+ <field name="view_id" ref="challenge_form_view"/>
+ </record>
+
+ <!-- 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="Challenge Lines" >
+ <field name="definition_id"/>
+ <field name="target_goal" string="Target"/>
+ </tree>
+ </field>
+ </record>
+
+
+ <record id="challenge_search_view" model="ir.ui.view">
+ <field name="name">Challenge Search</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_challenges" string="HR Challenges"
+ domain="[('challenge_category', '=', 'hr')]"/>
+ <field name="name"/>
+ <group expand="0" string="Group By">
+ <filter string="State" name="state" domain="[]" context="{'group_by':'state'}"/>
+ <filter string="Period" name="period" domain="[]" context="{'group_by':'period'}"/>
+ </group>
+ </search>
+ </field>
+ </record>
+</odoo>
diff --git a/addons/gamification/views/gamification.xml b/addons/gamification/views/gamification.xml
new file mode 100644
index 00000000..08341ac8
--- /dev/null
+++ b/addons/gamification/views/gamification.xml
@@ -0,0 +1,7 @@
+<odoo>
+ <template id="assets_backend" name="gamification assets" inherit_id="web.assets_backend">
+ <xpath expr="." position="inside">
+ <link rel="stylesheet" type="text/scss" href="/gamification/static/src/scss/gamification.scss"/>
+ </xpath>
+ </template>
+</odoo>
diff --git a/addons/gamification/views/gamification_karma_rank_views.xml b/addons/gamification/views/gamification_karma_rank_views.xml
new file mode 100644
index 00000000..bee0f28f
--- /dev/null
+++ b/addons/gamification/views/gamification_karma_rank_views.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <data>
+ <!-- ACTIONS -->
+ <record id="action_current_rank_users" model="ir.actions.act_window">
+ <field name="name">Users</field>
+ <field name="res_model">res.users</field>
+ <field name="view_mode">tree,form</field>
+ <field name="domain">[('rank_id', '=', active_id)]</field>
+ </record>
+
+ <!-- Ranks views -->
+ <record id="gamification_karma_ranks_action" model="ir.actions.act_window">
+ <field name="name">Ranks</field>
+ <field name="res_model">gamification.karma.rank</field>
+ <field name="view_mode">tree,form</field>
+ <field name="help" type="html">
+ <p class="o_view_nocontent_smiling_face">
+ Create a new rank
+ </p><p>
+ A rank correspond to a fixed karma level. The more you have karma, the more your rank is high.
+ This is used to quickly know which user is new or old or highly or not active.
+ </p>
+ </field>
+ </record>
+
+ <record id="gamification_karma_ranks_view_search" model="ir.ui.view">
+ <field name="name">gamification.karma.ranks.view.search</field>
+ <field name="model">gamification.karma.rank</field>
+ <field name="arch" type="xml">
+ <search string="Search Ranks">
+ <field name="name"/>
+ <field name="karma_min"/>
+ <field name="description"/>
+ <field name="user_ids"/>
+ </search>
+ </field>
+ </record>
+
+ <record id="gamification_karma_ranks_view_tree" model="ir.ui.view">
+ <field name="name">gamification.karma.ranks.view.tree</field>
+ <field name="model">gamification.karma.rank</field>
+ <field name="arch" type="xml">
+ <tree string="Ranks List">
+ <field name="name"/>
+ <field name="karma_min"/>
+ <field name="rank_users_count"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="gamification_karma_rank_view_form" model="ir.ui.view">
+ <field name="name">gamification.karma.rank.view.form</field>
+ <field name="model">gamification.karma.rank</field>
+ <field name="arch" type="xml">
+ <form string="Rank">
+ <sheet>
+ <div class="oe_button_box" name="button_box">
+ <button type="action" class="oe_stat_button" icon="fa-users" name="%(action_current_rank_users)d">
+ <div class="o_form_field o_stat_info">
+ <span class="o_stat_value">
+ <field name="rank_users_count" />
+ </span>
+ <span class="o_stat_text">Users</span>
+ </div>
+ </button>
+ </div>
+ <field name="image_1920" widget="image" class="oe_avatar" options="{'preview_image': 'image_128'}"/>
+ <div class="oe_title">
+ <label for="name" class="oe_edit_only"/>
+ <h1>
+ <field name="name" placeholder="e.g. Master Chief"/>
+ </h1>
+ </div>
+ <group>
+ <field name="karma_min"/>
+ <field name="create_date" invisible="1"/>
+ </group>
+ <notebook>
+ <page string="Description" name="description">
+ <field name="description" placeholder="e.g. A Master Chief knows quite everything on the forum! You cannot beat him!"/>
+ </page>
+ <page string="Motivational" name="motivational">
+ <field name="description_motivational" placeholder="e.g. Reach this rank to gain a free mug !"/>
+ </page>
+ </notebook>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <menuitem id="gamification_karma_ranks_menu" parent="gamification_menu" action="gamification_karma_ranks_action" sequence="40"/>
+ </data>
+</odoo>
diff --git a/addons/gamification/views/gamification_karma_tracking_views.xml b/addons/gamification/views/gamification_karma_tracking_views.xml
new file mode 100644
index 00000000..998d0ff9
--- /dev/null
+++ b/addons/gamification/views/gamification_karma_tracking_views.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo><data>
+ <record id="gamification_karma_tracking_view_search" model="ir.ui.view">
+ <field name="name">gamification.karma.tracking.view.search</field>
+ <field name="model">gamification.karma.tracking</field>
+ <field name="arch" type="xml">
+ <search string="Search Trackings">
+ <field name="user_id"/>
+ <field name="tracking_date"/>
+ <filter string="Consolidated" name="filter_consolidated"
+ domain="[('consolidated', '=', True)]"/>
+ <group string="Group By" expand="1">
+ <filter string="User" name="group_by_user_id"
+ context="{'group_by': 'user_id'}"/>
+ </group>
+ </search>
+ </field>
+ </record>
+
+ <record id="gamification_karma_tracking_view_tree" model="ir.ui.view">
+ <field name="name">gamification.karma.tracking.view.tree</field>
+ <field name="model">gamification.karma.tracking</field>
+ <field name="arch" type="xml">
+ <tree string="Trackings">
+ <field name="user_id"/>
+ <field name="tracking_date"/>
+ <field name="old_value"/>
+ <field name="new_value"/>
+ <field name="consolidated"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="gamification_karma_tracking_view_form" model="ir.ui.view">
+ <field name="name">gamification.karma.tracking.view.form</field>
+ <field name="model">gamification.karma.tracking</field>
+ <field name="arch" type="xml">
+ <form string="Tracking">
+ <sheet>
+ <group>
+ <field name="user_id"/>
+ <field name="tracking_date"/>
+ <field name="old_value"/>
+ <field name="new_value"/>
+ <field name="consolidated"/>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="gamification_karma_tracking_action" model="ir.actions.act_window">
+ <field name="name">Trackings</field>
+ <field name="res_model">gamification.karma.tracking</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem id="gamification_karma_tracking_menu"
+ parent="gamification_menu"
+ action="gamification_karma_tracking_action"
+ sequence="50"/>
+ </data>
+</odoo>
diff --git a/addons/gamification/views/goal.xml b/addons/gamification/views/goal.xml
new file mode 100644
index 00000000..bfba69b5
--- /dev/null
+++ b/addons/gamification/views/goal.xml
@@ -0,0 +1,300 @@
+<odoo>
+ <!-- Goal views -->
+ <record id="goal_list_action" model="ir.actions.act_window">
+ <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_definition': True}</field>
+ <field name="help" type="html">
+ <p class="o_view_nocontent_smiling_face">
+ Create a new goal
+ </p><p>
+ A goal is defined by a user and a goal definition.
+ Goals can be created automatically by using challenges.
+ </p>
+ </field>
+ </record>
+
+ <record id="goal_list_view" model="ir.ui.view">
+ <field name="name">Goal List</field>
+ <field name="model">gamification.goal</field>
+ <field name="arch" type="xml">
+ <tree string="Goal List" decoration-danger="state == 'failed'" decoration-success="state == 'reached'" decoration-muted="state == 'canceled'" create="false">
+ <field name="definition_id" invisible="1" />
+ <field name="user_id" invisible="1" />
+ <field name="start_date"/>
+ <field name="end_date"/>
+ <field name="current"/>
+ <field name="target_goal"/>
+ <field name="completeness" widget="progressbar"/>
+ <field name="state" invisible="1"/>
+ <field name="line_id" invisible="1"/>
+ </tree>
+ </field>
+ </record>
+
+ <record id="goal_form_view" model="ir.ui.view">
+ <field name="name">Goal Form</field>
+ <field name="model">gamification.goal</field>
+ <field name="arch" type="xml">
+ <form string="Goal" create="false">
+ <header>
+ <button string="Start goal" type="object" name="action_start" states="draft" class="oe_highlight"/>
+
+ <button string="Goal Reached" type="object" name="action_reach" states="inprogress" />
+ <button string="Goal Failed" type="object" name="action_fail" states="inprogress"/>
+ <button string="Reset Completion" type="object" name="action_cancel" states="failed,reached" groups="base.group_no_one" />
+ <field name="state" widget="statusbar" statusbar_visible="draft,inprogress,reached" />
+ </header>
+ <sheet>
+ <group>
+ <group string="Reference">
+ <field name="definition_id" attrs="{'readonly':[('state','!=','draft')]}"/>
+ <field name="user_id" attrs="{'readonly':[('state','!=','draft')]}"/>
+ <field name="challenge_id" />
+ </group>
+ <group string="Schedule">
+ <field name="start_date" attrs="{'readonly':[('state','!=','draft')]}"/>
+ <field name="end_date" />
+ <field name="computation_mode" invisible="1"/>
+
+ <label for="remind_update_delay" attrs="{'invisible':[('computation_mode','!=', 'manually')]}"/>
+ <div attrs="{'invisible':[('computation_mode','!=', 'manually')]}">
+ <field name="remind_update_delay" class="oe_inline"/>
+ days
+ </div>
+ <field name="last_update" groups="base.group_no_one"/>
+ </group>
+ <group string="Data" colspan="4">
+ <label for="target_goal" />
+ <div>
+ <field name="target_goal" attrs="{'readonly':[('state','!=','draft')]}" 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_goal" class="oe_link" attrs="{'invisible':['|',('computation_mode', '=', 'manually'),('state', '=', 'draft')]}" />
+ <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>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record id="goal_search_view" model="ir.ui.view">
+ <field name="name">Goal Search</field>
+ <field name="model">gamification.goal</field>
+ <field name="arch" type="xml">
+ <search string="Search Goals">
+ <filter name="my" string="My Goals" domain="[('user_id', '=', uid)]"/>
+ <separator/>
+ <filter name="draft" string="Draft" domain="[('state', '=', 'draft')]"/>
+ <filter name="inprogress" string="Running"
+ domain="[
+ '|',
+ ('state', '=', 'inprogress'),
+ '&amp;',
+ ('state', 'in', ('done', 'failed')),
+ ('end_date', '>=', context_today().strftime('%%Y-%%m-%%d'))
+ ]"/>
+ <filter name="closed" string="Done"
+ domain="[
+ ('state', 'in', ('reached', 'failed')),
+ '|',
+ ('end_date', '=', False),
+ ('end_date', '&lt;', context_today().strftime('%%Y-%%m-%%d'))
+ ]"/>
+ <separator/>
+
+ <field name="user_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_definition" string="Goal Definition" domain="[]" context="{'group_by':'definition_id'}"/>
+ <filter string="State" name="state" domain="[]" context="{'group_by':'state'}"/>
+ <filter string="End Date" name="enddate" domain="[]" context="{'group_by':'end_date'}"/>
+ </group>
+ </search>
+ </field>
+ </record>
+
+ <record id="goal_kanban_view" model="ir.ui.view" >
+ <field name="name">Goal Kanban View</field>
+ <field name="model">gamification.goal</field>
+ <field name="arch" type="xml">
+ <kanban class="oe_background_grey" create="false">
+ <field name="definition_id"/>
+ <field name="user_id"/>
+ <field name="current"/>
+ <field name="completeness"/>
+ <field name="state"/>
+ <field name="target_goal"/>
+ <field name="definition_description"/>
+ <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">
+ <ul class="oe_kanban_tooltip">
+ <li><t t-esc="record.definition_description.value" /></li>
+ </ul>
+ </t>
+ <t t-name="kanban-box">
+ <div t-attf-class="oe_kanban_card oe_kanban_global_click o_kanban_gamification #{record.end_date.raw_value &lt; record.last_update.raw_value &amp; record.state.raw_value == 'failed' ? 'oe_kanban_color_2' : ''} #{record.end_date.raw_value &lt; record.last_update.raw_value &amp; record.state.raw_value == 'reached' ? 'oe_kanban_color_5' : ''}">
+ <div class="o_kanban_content">
+ <p><strong><h4 class="oe_goal_name text-center" tooltip="kanban-tooltip"><field name="definition_id" /></h4></strong></p>
+ <div class="float-left">
+ <img class="o_image_24_cover" t-att-src="kanban_image('res.users', 'image_128', record.user_id.raw_value)" t-att-title="record.user_id.value" t-att-alt="record.user_id.value"/>
+ </div>
+ <field name="user_id" />
+ <div class="o_goal_state_block">
+ <t t-if="record.definition_display.raw_value == 'boolean'">
+ <div class="o_goal_state text-center">
+ <t t-if="record.state.raw_value=='reached'"><i role="img" class="o_green fa fa-check fa-3x" title="Goal Reached" aria-label="Goal Reached"/></t>
+ <t t-if="record.state.raw_value=='inprogress'"><i role="img" class="fa fa-clock-o fa-3x" title="Goal in Progress" aria-label="Goal in Progress"/></t>
+ <t t-if="record.state.raw_value=='failed'"><i role="img" class="o_red fa fa-times fa-3x" title="Goal Failed" aria-label="Goal Failed"/></t>
+ </div>
+ </t>
+ <t t-if="record.definition_display.raw_value == 'progress'">
+ <t t-if="record.definition_condition.raw_value =='higher'">
+ <field name="current" widget="gauge" options="{'max_field': 'target_goal', 'label_field': 'definition_suffix', 'style': 'width:160px; height: 120px;'}" />
+ </t>
+ <t t-if="record.definition_condition.raw_value != 'higher'">
+ <div t-attf-class="o_goal_state #{record.current.raw_value == record.target_goal.raw_value+1 ? 'o_orange' : record.current.raw_value &gt; record.target_goal.raw_value ? 'o_red' : 'o_green'}">
+ <t t-esc="record.current.raw_value" />
+ </div>
+ <em>Target: less than <t t-esc="record.target_goal.raw_value" /></em>
+ </t>
+ </t>
+
+ </div>
+ <p class="text-center">
+ <t t-if="record.start_date.value">
+ From <t t-esc="record.start_date.value" />
+ </t>
+ <t t-if="record.end_date.value">
+ To <t t-esc="record.end_date.value" />
+ </t>
+ </p>
+ </div>
+ </div>
+ </t>
+ </templates>
+ </kanban>
+ </field>
+ </record>
+
+
+ <!-- Goal definitions view -->
+
+ <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="o_view_nocontent_smiling_face">
+ Create a new goal definition
+ </p><p>
+ A goal definition is a technical specification of a condition to reach.
+ The dates, values to reach or users are defined in goal instance.
+ </p>
+ </field>
+ </record>
+
+ <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 Definitions">
+ <field name="name"/>
+ <field name="computation_mode"/>
+ </tree>
+ </field>
+ </record>
+
+
+ <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 definitions">
+ <sheet>
+ <label for="name" class="oe_edit_only"/>
+ <h1>
+ <field name="name"/>
+ </h1>
+ <label for="description" class="oe_edit_only"/>
+ <div>
+ <field name="description" class="oe_inline"/>
+ </div>
+
+ <group string="How is the goal computed?" name="compute_details">
+
+ <field widget="radio" name="computation_mode"/>
+
+ <!-- Hide the fields below if manually -->
+ <field name="model_id" class="oe_inline"
+ attrs="{'invisible':[('computation_mode','not in',('sum', 'count'))], 'required':[('computation_mode','in',('sum', 'count'))]}"/>
+ <field name="model_inherited_ids" invisible="1"/>
+ <field name="field_id" class="oe_inline"
+ attrs="{'invisible':[('computation_mode','!=','sum')], 'required':[('computation_mode','=','sum')]}"/>
+ <field name="field_date_id" class="oe_inline" attrs="{'invisible':[('computation_mode','not in',('sum', 'count'))]}"/>
+ <field name="domain" attrs="{'invisible':[('computation_mode','not in',('sum', 'count'))], 'required':[('computation_mode','in',('sum', 'count'))]}" class="oe_inline"/>
+ <field name="compute_code" attrs="{'invisible':[('computation_mode','!=','python')], 'required':[('computation_mode','=','python')]}"/>
+ <field name="condition" widget="radio"/>
+ </group>
+ <group string="Optimisation" name="optimisation" attrs="{'invisible': [('computation_mode', 'not in', ('sum', 'count'))]}">
+ <field name="batch_mode" />
+ <div colspan="2">In batch mode, the domain is evaluated globally. If enabled, do not use keyword 'user' in above filter domain.</div>
+ <field name="batch_distinctive_field" attrs="{'invisible': [('batch_mode', '=', False)], 'required': [('batch_mode', '=', True)]}"
+ domain="[('model_id', '=', model_id)]" class="oe_inline" />
+ <field name="batch_user_expression" attrs="{'invisible': [('batch_mode', '=', False)], 'required': [('batch_mode', '=', True)]}" class="oe_inline"
+ placeholder="e.g. user.partner_id.id"/>
+ </group>
+ <group string="Formatting Options" name="format_options">
+ <field name="display_mode" widget="radio" />
+ <field name="suffix" placeholder="e.g. days" class="oe_inline"/>
+ <field name="monetary"/>
+ </group>
+ <group string="Clickable Goals" name="clickable_goals" attrs="{'invisible': [('computation_mode', '=', 'manually')]}">
+ <field name="action_id" class="oe_inline"/>
+ <field name="res_id_field" attrs="{'invisible': [('action_id', '=', False)]}" class="oe_inline"/>
+ </group>
+
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <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 Definitions">
+ <field name="name"/>
+ <field name="model_id"/>
+ <field name="field_id"/>
+ <group expand="0" string="Group By">
+ <filter string="Model" name="model" domain="[]" context="{'group_by':'model_id'}"/>
+ <filter string="Computation Mode" name="computationmode" domain="[]" context="{'group_by':'computation_mode'}"/>
+ </group>
+ </search>
+ </field>
+ </record>
+
+ <!-- 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_challenge_menu" parent="gamification_menu" action="challenge_list_action" sequence="0"/>
+ <menuitem id="gamification_goal_menu" parent="gamification_menu" action="goal_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"/>
+</odoo>
diff --git a/addons/gamification/views/mail_templates.xml b/addons/gamification/views/mail_templates.xml
new file mode 100644
index 00000000..e8a6a6a3
--- /dev/null
+++ b/addons/gamification/views/mail_templates.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <data>
+ <record id="mail_template_data_new_rank_reached" model="mail.template">
+ <field name="name">User: New rank reached</field>
+ <field name="model_id" ref="base.model_res_users"/>
+ <field name="subject">New rank: ${object.rank_id.name}</field>
+ <field name="email_to"></field>
+ <field name="partner_to">${object.partner_id.id}</field>
+ <field name="body_html" type="html">
+<div style="background:#F0F0F0;color:#515166;padding:10px 0px;font-family:Arial,Helvetica,sans-serif;font-size:14px;">
+<table style="width:600px;margin:0px auto;background:white;border:1px solid #e1e1e1;">
+ <tbody>
+ <tr>
+ <td style="padding:15px 20px 10px 20px;">
+ <p>
+ Congratulations
+ <span>${object.name or ''}</span>!
+ </p>
+ <p>
+ You just reached a new rank : <strong>${object.rank_id.name}</strong>
+ </p>
+ % if object.next_rank_id.name
+ <p>Continue your work to become a <strong>${object.next_rank_id.name}</strong> !</p>
+ % endif
+ <div style="margin: 16px 0px 16px 0px;">
+ % set gamification_redirection_data = object.get_gamification_redirection_data()
+ % for data in gamification_redirection_data
+ % set url = data['url']
+ % set label = data['label']
+ <a href="${url}" style="background-color: #875A7B; padding: 8px 16px 8px 16px; text-decoration: none; color: #fff; border-radius: 5px; font-size:13px;">${label}</a>
+ % endfor
+ </div>
+ </td>
+ <td style="padding:15px 20px 10px 20px;">
+ <p style="text-align: center;">
+ <img src="/web/image/gamification.karma.rank/${object.rank_id.id}/image_128"/>
+ </p>
+ </td>
+ </tr>
+ % if user.signature
+ <tr>
+ <td style="padding:15px 20px 10px 20px;">
+ ${user.signature | safe}
+ </td>
+ </tr>
+ % endif
+ </tbody>
+ </table>
+</div></field>
+ <field name="lang">${object.lang}</field>
+ <field name="auto_delete" eval="True"/>
+ </record>
+ </data>
+</odoo>
diff --git a/addons/gamification/views/res_users_views.xml b/addons/gamification/views/res_users_views.xml
new file mode 100644
index 00000000..c0c20cad
--- /dev/null
+++ b/addons/gamification/views/res_users_views.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+<data>
+
+ <record id="res_users_view_form" model="ir.ui.view">
+ <field name="name">res.users.view.form.inherit.gamification</field>
+ <field name="model">res.users</field>
+ <field name="inherit_id" ref="base.view_users_form"/>
+ <field name="arch" type="xml">
+ <group name="messaging" position="inside">
+ <field name="karma"/>
+ </group>
+ </field>
+ </record>
+
+</data>
+</odoo>