[ADD] rating_project, rating_project_issue : using the rating mixin, tasks and issues are rated when their stage changed. A email template is sent to the customer of the object.
This commit is contained in:
@@ -44,6 +44,8 @@ class project_configuration(osv.osv_memory):
|
||||
'module_project_issue': fields.boolean("Track issues and bugs",
|
||||
help='Provides management of issues/bugs in projects.\n'
|
||||
'-This installs the module project_issue.'),
|
||||
'module_rating_project': fields.boolean('Allow customers to rate provided services',
|
||||
help="This allows customers to give rating on provided services"),
|
||||
'time_unit': fields.many2one('product.uom', 'Working time unit', required=True,
|
||||
help="""This will set the unit of measure used in projects and tasks."""),
|
||||
'module_project_issue_sheet': fields.boolean("Invoice working time on issues",
|
||||
|
||||
@@ -80,6 +80,10 @@
|
||||
<field name="module_project_issue" class="oe_inline"/>
|
||||
<label for="module_project_issue"/>
|
||||
</div>
|
||||
<div>
|
||||
<field name="module_rating_project" class="oe_inline"/>
|
||||
<label for="module_rating_project"/>
|
||||
</div>
|
||||
<div name="module_project_issue_sheet">
|
||||
<field name="module_project_issue_sheet" class="oe_inline"/>
|
||||
<label for="module_project_issue_sheet"/>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Odoo, Open Source Management Solution
|
||||
# Copyright (C) 2014-Today Odoo SA (<http://www.odoo.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 models
|
||||
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': 'Project Rating',
|
||||
'version': '1.0',
|
||||
'category': 'Hidden',
|
||||
'description': """
|
||||
This module Allows a customer to give rating on Project.
|
||||
""",
|
||||
'author': 'Odoo SA',
|
||||
'website': 'http://odoo.com',
|
||||
'depends': [
|
||||
'rating',
|
||||
'project'
|
||||
],
|
||||
'data': [
|
||||
'data/project_data.xml',
|
||||
'views/project_view.xml',
|
||||
],
|
||||
'demo': ['data/project_demo.xml'],
|
||||
'installable': True,
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
|
||||
<record id="rating_project_request_email_template" model="mail.template">
|
||||
<field name="name">Rating Project Request</field>
|
||||
<field name="email_from">${object.rated_partner_id.email or ''}</field>
|
||||
<field name="subject">${object.res_name}</field>
|
||||
<field name="model_id" ref="rating.model_rating_rating"/>
|
||||
<field name="email_to" >${object.partner_id.email}</field>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html"><![CDATA[
|
||||
<body>
|
||||
<div style="max-width:600px; height:auto; margin-left:30px;">
|
||||
<div style="margin-left:30px;align=center;">
|
||||
Dear ${object.partner_id.name},
|
||||
</div><br>
|
||||
<div style="margin-left:30px;align=center;" width="60%">
|
||||
We hope the services provided have met your expectations.
|
||||
<br>If you have any more questions or comments, do not hesitate to reply to this e-mail.
|
||||
<br><br>Please, help us to improve ourself by rating the service we provide.
|
||||
</div><br>
|
||||
<table style="margin-left:50px;" width="70%">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/rating/${object.access_token}/10">
|
||||
<img alt="Great" src="rating/static/src/img/rating_10.png" title="It was great"/>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/rating/${object.access_token}/5">
|
||||
<img alt="Okay" src="rating/static/src/img/rating_5.png" title="It was okay"/>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/rating/${object.access_token}/0">
|
||||
<img alt="Bad" src="rating/static/src/img/rating_0.png" title="It wasn't good"/>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table><br>
|
||||
<h4 style="margin-left:30px;font-weight:normal;">Thank you </h4>
|
||||
<h4 style="margin-left:30px;font-weight:normal;">${object.rated_partner_id.name or ''} </h4>
|
||||
</div>
|
||||
</body>
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- add the email template as value for the project stage 2 -->
|
||||
<record id="project.project_stage_2" model="project.task.type">
|
||||
<field name="rating_template_id" ref="rating_project_request_email_template"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<record id="rating_task_1" model="rating.rating">
|
||||
<field name="res_model">project.task</field>
|
||||
<field name="res_id" ref="project.project_task_3"/>
|
||||
</record>
|
||||
<record id="rating_task_2" model="rating.rating">
|
||||
<field name="res_model">project.task</field>
|
||||
<field name="res_id" ref="project.project_task_8"/>
|
||||
</record>
|
||||
<record id="rating_task_3" model="rating.rating">
|
||||
<field name="res_model">project.task</field>
|
||||
<field name="res_id" ref="project.project_task_15"/>
|
||||
</record>
|
||||
<record id="rating_task_4" model="rating.rating">
|
||||
<field name="res_model">project.task</field>
|
||||
<field name="res_id" ref="project.project_task_18"/>
|
||||
</record>
|
||||
<record id="rating_task_5" model="rating.rating">
|
||||
<field name="res_model">project.task</field>
|
||||
<field name="res_id" ref="project.project_task_24"/>
|
||||
</record>
|
||||
|
||||
<function model="rating.rating" name="apply_rating" eval="(10, 'project.task', ref('project.project_task_3'))"/>
|
||||
<function model="rating.rating" name="apply_rating" eval="(0, 'project.task', ref('project.project_task_8'))"/>
|
||||
<function model="rating.rating" name="apply_rating" eval="(5, 'project.task', ref('project.project_task_15'))"/>
|
||||
<function model="rating.rating" name="apply_rating" eval="(10, 'project.task', ref('project.project_task_18'))"/>
|
||||
<function model="rating.rating" name="apply_rating" eval="(10, 'project.task', ref('project.project_task_24'))"/>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import project
|
||||
@@ -0,0 +1,70 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class ProjectTaskType(models.Model):
|
||||
|
||||
_inherit = 'project.task.type'
|
||||
|
||||
rating_template_id = fields.Many2one(
|
||||
'mail.template',
|
||||
string='Rating Email Template',
|
||||
domain=[('model', '=', 'rating.rating')],
|
||||
help="Select an email template. An email will be sent to the customer when the task reach this step.")
|
||||
|
||||
class Task(models.Model):
|
||||
|
||||
_name = 'project.task'
|
||||
_inherit = ['project.task', 'rating.mixin']
|
||||
|
||||
@api.multi
|
||||
def write(self, values):
|
||||
if 'stage_id' in values and values.get('stage_id'):
|
||||
template = self.env['project.task.type'].browse(values.get('stage_id')).rating_template_id
|
||||
if template:
|
||||
rated_partner_id = self.user_id.partner_id
|
||||
partner_id = self.partner_id
|
||||
if partner_id and rated_partner_id:
|
||||
self.rating_send_request(template, partner_id, rated_partner_id)
|
||||
return super(Task, self).write(values)
|
||||
|
||||
|
||||
class Project(models.Model):
|
||||
|
||||
_inherit = "project.project"
|
||||
|
||||
@api.one
|
||||
@api.depends('percentage_satisfaction_task')
|
||||
def _compute_percentage_satisfaction_project(self):
|
||||
self.percentage_satisfaction_project = self.percentage_satisfaction_task
|
||||
|
||||
@api.one
|
||||
@api.depends('tasks.rating_ids.rating')
|
||||
def _compute_percentage_satisfaction_task(self):
|
||||
activity = self.tasks.rating_get_grades()
|
||||
self.percentage_satisfaction_task = activity['great'] * 100 / sum(activity.values()) if sum(activity.values()) else -1
|
||||
|
||||
@api.one
|
||||
@api.depends('use_tasks')
|
||||
def _display_happy_customer(self):
|
||||
self.is_visible_happy_customer = self.use_tasks
|
||||
|
||||
|
||||
percentage_satisfaction_task = fields.Integer(
|
||||
compute='_compute_percentage_satisfaction_task', string='% Happy', store=True, default=-1)
|
||||
percentage_satisfaction_project = fields.Integer(
|
||||
compute="_compute_percentage_satisfaction_project", string="% Happy", store=True, default=-1)
|
||||
is_visible_happy_customer = fields.Boolean(
|
||||
compute="_display_happy_customer", string="Is Visible", store=True, default=True)
|
||||
|
||||
|
||||
@api.multi
|
||||
def action_view_task_rating(self):
|
||||
""" return the action to see all the rating about the tasks of the project """
|
||||
action = self.env['ir.actions.act_window'].for_xml_id('rating', 'action_view_rating')
|
||||
return dict(action, domain=[('rating', '!=', -1), ('res_id', 'in', self.tasks.ids), ('res_model', '=', 'project.task')])
|
||||
|
||||
@api.multi
|
||||
def action_view_all_rating(self):
|
||||
""" return the action to see all the rating about the all sort of activity of the project (tasks, issues, ...) """
|
||||
return self.action_view_task_rating()
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- project.project form view with rating satisfaction state button -->
|
||||
<record id="view_project_project_rating_form" model="ir.ui.view">
|
||||
<field name="name">project.project.rating.form.view</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="priority" eval="20"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='buttons']" position="inside">
|
||||
<button name="action_view_task_rating"
|
||||
attrs="{'invisible': ['|', ('use_tasks','=', False), ('percentage_satisfaction_task','=', -1)]}"
|
||||
class="oe_stat_button"
|
||||
type="object"
|
||||
icon="fa-smile-o">
|
||||
<field string="% Happy on task" name="percentage_satisfaction_task" widget="statinfo"/>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- inherit project.task.type form view to add email template for task -->
|
||||
<record id="view_project_task_type_rating_form" model="ir.ui.view">
|
||||
<field name="name">project.task.type.form.view.inherit</field>
|
||||
<field name="model">project.task.type</field>
|
||||
<field name="inherit_id" ref="project.task_type_edit"/>
|
||||
<field name="priority" eval="20"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='sequence']" position="after">
|
||||
<field name="rating_template_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_project_project_rating_kanban" model="ir.ui.view">
|
||||
<field name="name">rating.project.project.kanban.inherit</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.view_project_kanban"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="use_tasks" position="after">
|
||||
<field name="percentage_satisfaction_project" invisible="1"/>
|
||||
<field name="is_visible_happy_customer" invisible="1"/>
|
||||
</field>
|
||||
<xpath expr="//div[contains(@class, 'oe_kanban_project_list')]" position="after">
|
||||
<div class="row oe_margin_top_8 oe_kanban_project_list">
|
||||
<a t-if="record.is_visible_happy_customer.raw_value and record.percentage_satisfaction_project.raw_value > -1" name="action_view_all_rating" type="object" title="Percentage of happy people about this project">
|
||||
<img t-if="record.percentage_satisfaction_project.raw_value >= 0 and record.percentage_satisfaction_project.raw_value <= 30" class="rating" src="rating/static/src/img/rating_0.png" style="width:10%;height:10%"></img>
|
||||
<img t-if="record.percentage_satisfaction_project.raw_value > 30 and record.percentage_satisfaction_project.raw_value <= 69" class="rating" src="rating/static/src/img/rating_5.png" style="width:10%;height:10%"></img>
|
||||
<img t-if="record.percentage_satisfaction_project.raw_value >= 70" class="rating" src="rating/static/src/img/rating_10.png" style="width:10%;height:10%"></img>
|
||||
<img t-if="record.percentage_satisfaction_project.raw_value < 0" class="rating" src="rating/static/src/img/rating_-1.png" style="width:10%;height:10%"></img>
|
||||
<t t-if="record.percentage_satisfaction_project.raw_value >= 0">
|
||||
<t t-raw="record.percentage_satisfaction_project.raw_value"/> %
|
||||
</t>
|
||||
</a>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Odoo, Open Source Management Solution
|
||||
# Copyright (C) 2014-Today Odoo SA (<http://www.odoo.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 models
|
||||
@@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': 'Issue Rating',
|
||||
'version': '1.0',
|
||||
'category': 'Hidden',
|
||||
'description': """
|
||||
This module allows a customer to give rating on Project Issue.
|
||||
""",
|
||||
'author': 'Odoo SA',
|
||||
'website': 'http://odoo.com',
|
||||
'depends': [
|
||||
'rating_project',
|
||||
'project_issue'
|
||||
],
|
||||
'data': [
|
||||
'views/project_issue_view.xml',
|
||||
],
|
||||
'demo': [
|
||||
'data/project_issue_demo.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install' : True,
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<record id="rating_issue_1" model="rating.rating">
|
||||
<field name="res_model">project.issue</field>
|
||||
<field name="res_id" ref="project_issue.crm_case_outputincorrect0"/>
|
||||
</record>
|
||||
<record id="rating_issue_2" model="rating.rating">
|
||||
<field name="res_model">project.issue</field>
|
||||
<field name="res_id" ref="project_issue.crm_case_addmenustothemodule0"/>
|
||||
</record>
|
||||
<record id="rating_issue_3" model="rating.rating">
|
||||
<field name="res_model">project.issue</field>
|
||||
<field name="res_id" ref="project_issue.crm_case_improvereportsinhrms0"/>
|
||||
</record>
|
||||
|
||||
<function model="rating.rating" name="apply_rating" eval="(10, 'project.issue',
|
||||
ref('project_issue.crm_case_outputincorrect0'))"/>
|
||||
<function model="rating.rating" name="apply_rating" eval="(0, 'project.issue',
|
||||
ref('project_issue.crm_case_addmenustothemodule0'))"/>
|
||||
<function model="rating.rating" name="apply_rating" eval="(5, 'project.issue',
|
||||
ref('project_issue.crm_case_improvereportsinhrms0'))"/>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import project_issue
|
||||
@@ -0,0 +1,96 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class ProjectIssue(models.Model):
|
||||
|
||||
_name = "project.issue"
|
||||
_inherit = ['project.issue', 'rating.mixin']
|
||||
|
||||
@api.multi
|
||||
def write(self, values):
|
||||
if 'stage_id' in values and values.get('stage_id'):
|
||||
template = self.env['project.task.type'].browse(values.get('stage_id')).rating_template_id
|
||||
if template:
|
||||
rated_partner_id = self.user_id.partner_id
|
||||
partner_id = self.partner_id
|
||||
if partner_id and rated_partner_id:
|
||||
self.rating_send_request(template, partner_id, rated_partner_id)
|
||||
return super(ProjectIssue, self).write(values)
|
||||
|
||||
|
||||
class Project(models.Model):
|
||||
|
||||
_inherit = "project.project"
|
||||
|
||||
@api.multi
|
||||
@api.depends('percentage_satisfaction_task', 'percentage_satisfaction_issue')
|
||||
def _compute_percentage_satisfaction_project(self):
|
||||
super(Project, self)._compute_percentage_satisfaction_project()
|
||||
Rating = self.env['rating.rating']
|
||||
for record in self.filtered(lambda record: record.use_tasks or record.use_issues):
|
||||
if record.use_tasks or record.use_issues:
|
||||
# built the domain according the project parameters (use tasks and/or issues)
|
||||
res_models = []
|
||||
domain = []
|
||||
if record.use_tasks:
|
||||
res_models.append('project.task')
|
||||
domain += ['&', ('res_model', '=', 'project.task'), ('res_id', 'in', record.tasks.ids)]
|
||||
if record.use_issues:
|
||||
res_models.append('project.issue')
|
||||
domain += ['&', ('res_model', '=', 'project.issue'), ('res_id', 'in', record.issue_ids.ids)]
|
||||
if len(res_models) == 2:
|
||||
domain = ['|'] + domain
|
||||
domain = ['&', ('rating', '>=', 0)] + domain
|
||||
# get the number of rated tasks and issues with a read_group (more perfomant !)
|
||||
grouped_data = Rating.read_group(domain, ['res_model'], ['res_model'])
|
||||
# compute the number of each model and total number
|
||||
res = dict.fromkeys(res_models, 0)
|
||||
for data in grouped_data:
|
||||
res[data['res_model']] += data['res_model_count']
|
||||
nbr_rated_task = res.get('project.task', 0)
|
||||
nbr_rated_issue = res.get('project.issue', 0)
|
||||
nbr_project_rating = nbr_rated_issue + nbr_rated_task
|
||||
# compute the weighted arithmetic average
|
||||
ratio_task = float(nbr_rated_task) / float(nbr_project_rating) if nbr_project_rating else 0
|
||||
ratio_issue = float(nbr_rated_issue) / float(nbr_project_rating) if nbr_project_rating else 0
|
||||
record.percentage_satisfaction_project = round((ratio_task*record.percentage_satisfaction_task)+(ratio_issue*record.percentage_satisfaction_issue)) if nbr_project_rating else -1
|
||||
else:
|
||||
record.percentage_satisfaction_project = -1
|
||||
|
||||
@api.one
|
||||
@api.depends('issue_ids.rating_ids.rating')
|
||||
def _compute_percentage_satisfaction_issue(self):
|
||||
project_issue = self.env['project.issue'].search([('project_id', '=', self.id)])
|
||||
activity = project_issue.rating_get_grades()
|
||||
self.percentage_satisfaction_issue = activity['great'] * 100 / sum(activity.values()) if sum(activity.values()) else -1
|
||||
|
||||
@api.one
|
||||
@api.depends('use_tasks', 'use_issues')
|
||||
def _display_happy_customer(self):
|
||||
self.is_visible_happy_customer = self.use_tasks if self.use_tasks else self.use_issues
|
||||
|
||||
percentage_satisfaction_issue = fields.Integer(compute='_compute_percentage_satisfaction_issue', string='% Happy', store=True, default=-1)
|
||||
|
||||
@api.multi
|
||||
def action_view_issue_rating(self):
|
||||
""" return the action to see all the rating about the issues of the project """
|
||||
action = self.env['ir.actions.act_window'].for_xml_id('rating', 'action_view_rating')
|
||||
issues = self.env['project.issue'].search([('project_id', 'in', self.ids)])
|
||||
return dict(action, domain=[('res_id', 'in', issues.ids), ('res_model', '=', 'project.issue')])
|
||||
|
||||
@api.multi
|
||||
def action_view_all_rating(self):
|
||||
action = super(Project, self).action_view_all_rating()
|
||||
task_domain = action['domain'][1:] # remove the (rating != -1) condition
|
||||
domain = []
|
||||
if self.use_tasks: # add task domain, if neeeded
|
||||
domain = ['&'] + task_domain
|
||||
if self.use_issues: # add issue domain if needed
|
||||
issues = self.env['project.issue'].search([('project_id', 'in', self.ids)])
|
||||
domain = domain + ['&', ('res_id', 'in', issues.ids), ('res_model', '=', 'project.issue')]
|
||||
if self.use_tasks and self.use_issues:
|
||||
domain = ['|'] + domain
|
||||
domain = [('rating', '!=', -1)] + domain # prepend the condition to avoid empty rating
|
||||
return dict(action, domain=domain)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- inherit get state button on project -->
|
||||
<record id="project_issue_view_rating" model="ir.ui.view">
|
||||
<field name="name">project.issue.view.rating</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="priority" eval="20"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='buttons']" position="inside">
|
||||
<button name="action_view_issue_rating"
|
||||
attrs="{'invisible': ['|', ('use_issues','=', False), ('percentage_satisfaction_issue','=', -1)]}"
|
||||
class="oe_stat_button"
|
||||
type="object"
|
||||
icon="fa-smile-o">
|
||||
<field string="% Happy on issue" name="percentage_satisfaction_issue" widget="statinfo"/>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
Reference in New Issue
Block a user