[MERGE] rating: cleaning and improvements

- add form and list view for rating
- better use in livechat rating
- better filters
- improve kanban rating view
- remove rating when uninstalling module
- ...
This commit is contained in:
Jérome Maes
2017-01-09 16:34:25 +01:00
15 changed files with 307 additions and 178 deletions
+2 -5
View File
@@ -86,14 +86,13 @@ class LivechatController(http.Controller):
# limit the creation : only ONE rating per session
values = {
'rating': rate,
'consumed': True
'consumed': True,
'feedback': reason,
}
if not channel.rating_ids:
values.update({
'res_id': channel.id,
'res_model': 'mail.channel',
'rating': rate,
'feedback': reason,
})
# find the partner (operator)
if channel.channel_partner_ids:
@@ -101,8 +100,6 @@ class LivechatController(http.Controller):
# create the rating
rating = Rating.sudo().create(values)
else:
if reason:
values['feedback'] = reason
rating = channel.rating_ids[0]
rating.write(values)
return rating.id
+10 -21
View File
@@ -10,10 +10,10 @@
<field name="name"/>
<group expand="0" string="Group By...">
<filter name="group_by_channel" string="Channel" domain="[]" context="{'group_by':'livechat_channel_id'}"/>
<separator orientation="vertical" />
<separator orientation="vertical"/>
<filter name="group_by_day" string="Creation date (day)" domain="[]" context="{'group_by':'create_date:day'}"/>
<filter name="group_by_week" string="Creation date (week)" domain="[]" context="{'group_by':'create_date:week'}"/>
<filter name="group_by_month" string="Creation date (month)" domain="[]" context="{'group_by':'create_date:month'}" />
<filter name="group_by_month" string="Creation date (month)" domain="[]" context="{'group_by':'create_date:month'}"/>
<filter name="group_by_year" string="Creation date (year)" domain="[]" context="{'group_by':'create_date:year'}"/>
</group>
</search>
@@ -27,7 +27,7 @@
<tree string="History" create="false">
<field name="create_date" string="Session Date"/>
<field name="name" string="Attendees"/>
<field name="rating_count" string="Has a Rating"/>
<field name="rating_last_value" string="Rating"/>
</tree>
</field>
</record>
@@ -44,24 +44,13 @@
<field name="create_date" readonly="1" string="Session Date"/>
</group>
<group>
<field name="rating_ids" mode="kanban" nolabel="1">
<kanban>
<field name="rating"/>
<field name="feedback"/>
<field name="res_name"/>
<field name="create_date"/>
<templates>
<t t-name="kanban-box">
<div class="oe_group_details" style="min-height: 40px">
<img t-attf-src="rating/static/src/img/rating_#{record.rating.raw_value and record.rating.raw_value or 0}.png" class="oe_kanban_image" style="float:left; margin-right: 10px;"/>
<span t-if="record.feedback.raw_value">
<t t-esc="record.feedback.raw_value"/>
</span>
</div>
</t>
</templates>
</kanban>
</field>
<group>
<label for="rating_last_image" string="Rating"/>
<div>
<field name="rating_last_image" widget="image" class="oe_avatar" options='{"preview_image": "image_thumb"}' readonly="1" nolabel="1"/>
<field name="rating_last_feedback" nolabel="1"/>
</div>
</group>
</group>
</group>
<field name="message_ids" type="tree">
+62 -10
View File
@@ -3,7 +3,9 @@
import uuid
from odoo import api, fields, models, tools
from odoo import api, fields, models, tools, _
from odoo.modules.module import get_resource_path
class Rating(models.Model):
@@ -26,17 +28,37 @@ class Rating(models.Model):
def new_access_token(self):
return uuid.uuid4().hex
res_name = fields.Char(string='Resource Name', compute='_compute_res_name', store=True, help="The name of the rated resource.")
res_model = fields.Char(string='Document Model', required=True, help="Model name of the rated object", index=True)
res_name = fields.Char(string='Resource name', compute='_compute_res_name', store=True, help="The name of the rated resource.")
res_model_id = fields.Many2one('ir.model', 'Related Document Model', index=True, ondelete='cascade', help='Model of the followed resource')
res_model = fields.Char(string='Document Model', related='res_model_id.model', store=True, index=True, readonly=True)
res_id = fields.Integer(string='Document ID', required=True, help="Identifier of the rated object", index=True)
rated_partner_id = fields.Many2one('res.partner', string="Rated Partner", help="Owner of the rated resource")
rated_partner_id = fields.Many2one('res.partner', string="Rated person", help="Owner of the rated resource")
partner_id = fields.Many2one('res.partner', string='Customer', help="Author of the rating")
rating = fields.Float(string="Rating", group_operator="avg", default=0, help="Rating value: 0=Unhappy, 10=Happy")
feedback = fields.Text('Feedback reason', help="Reason of the rating")
rating_image = fields.Binary('Image', compute='_compute_rating_image')
rating_text = fields.Char(string='Rating', compute='_compute_rating_text')
feedback = fields.Text('Comment', help="Reason of the rating")
message_id = fields.Many2one('mail.message', string="Linked message", help="Associated message when posting a review. Mainly used in website addons.", index=True)
access_token = fields.Char('Security Token', default=new_access_token, help="Access token to set the rating of the value")
consumed = fields.Boolean(string="Filled Rating", help="Enabled if the rating has been filled.")
@api.multi
@api.depends('rating')
def _compute_rating_image(self):
for rating in self:
try:
image_path = get_resource_path('rating', 'static/src/img', 'rating_%s.png' % (int(rating.rating),))
rating.rating_image = open(image_path, 'rb').read().encode('base64')
except (IOError, OSError):
rating.rating_image = False
@api.multi
@api.depends('rating')
def _compute_rating_text(self):
text = {10: _('Satisfied'), 5: _('Not satisfied'), 1: _('Highly dissatisfied')}
for rating in self:
rating.rating_text = text[rating.rating] or _('No rating yet')
@api.multi
def reset(self):
for record in self:
@@ -47,13 +69,24 @@ class Rating(models.Model):
'consumed': False,
})
def action_open_rated_object(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'res_model': self.res_model,
'res_id': self.res_id,
'views': [[False, 'form']]
}
class RatingMixin(models.AbstractModel):
_name = 'rating.mixin'
_description = "Rating Mixin"
rating_ids = fields.One2many('rating.rating', 'res_id', string='Rating', domain=lambda self: [('res_model', '=', self._name)])
rating_ids = fields.One2many('rating.rating', 'res_id', string='Rating', domain=lambda self: [('res_model', '=', self._name)], auto_join=True)
rating_last_value = fields.Float('Rating Last Value', related='rating_ids.rating', store=True)
rating_last_feedback = fields.Text('Rating Last Feedback', related='rating_ids.feedback')
rating_last_image = fields.Binary('Rating Last Image', related='rating_ids.rating_image')
rating_count = fields.Integer('Rating count', compute="_compute_rating_count")
@api.multi
@@ -67,6 +100,20 @@ class RatingMixin(models.AbstractModel):
for record in self:
record.rating_count = result[record.id]
def write(self, values):
""" If the rated ressource name is modified, we should update the rating res_name too. """
result = super(RatingMixin, self).write(values)
if self._rec_name in values:
self.rating_ids._compute_res_name()
return result
def unlink(self):
""" When removing a record, its rating should be deleted too. """
record_ids = self.ids
result = super(RatingMixin, self).unlink()
self.env['rating.rating'].sudo().search([('res_model', '=', self._name), ('res_id', 'in', record_ids)]).unlink()
return result
def rating_get_partner_id(self):
if hasattr(self, 'partner_id') and self.partner_id:
return self.partner_id
@@ -83,18 +130,23 @@ class RatingMixin(models.AbstractModel):
rated_partner = self.rating_get_rated_partner_id()
ratings = self.rating_ids.filtered(lambda x: x.partner_id.id == partner.id and not x.consumed)
if not ratings:
rating = self.env['rating.rating'].create({'partner_id': partner.id, 'rated_partner_id': rated_partner.id, 'res_model': self._name, 'res_id': self.id})
record_model_id = self.env['ir.model'].sudo().search([('model', '=', self._name)], limit=1).id
rating = self.env['rating.rating'].create({
'partner_id': partner.id,
'rated_partner_id': rated_partner.id,
'res_model_id': record_model_id,
'res_id': self.id
})
else:
rating = ratings[0]
return rating.access_token
@api.multi
def rating_send_request(self, template, partner=None, rated_partner=None, reuse_rating=True, force_send=True):
def rating_send_request(self, template, lang=False, force_send=True):
""" This method send rating request by email, using a template given
in parameter. """
partner = (partner or self.env['res.partner']).sudo()
lang = lang or 'en_US'
for record in self:
lang = partner.lang or 'en_US'
template.with_context(lang=lang).send_mail(record.id, force_send=force_send)
@api.multi
-16
View File
@@ -1,16 +0,0 @@
odoo.define('rating.kanban', function(require) {
"use strict";
var KanbanRecord = require('web_kanban.Record');
KanbanRecord.include({
on_card_clicked: function() {
if (this.model === 'rating.rating') {
this.$('a').first().click();
} else {
this._super.apply(this, arguments);
}
},
});
});
+42 -47
View File
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<!-- Bundle for Rating Widget (in assets common to be used in website modules) -->
<template id="assets_common" inherit_id="web.assets_common" name="Rating common assets">
@@ -10,13 +9,6 @@
</xpath>
</template>
<!-- backend assets -->
<template id="assets_backend" name="rating assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/rating/static/src/js/rating.js"></script>
</xpath>
</template>
<!-- Rating Star Widget (Generic widget)
:param String rating_input_name : the name of the input field to send the rating
:param Float rating_default_value : the rate to initialize the widget with
@@ -95,51 +87,54 @@
</template>
<!-- External page : thanks message -->
<template id="rating_external_page_view">
<head>
<link rel='stylesheet' href='/web/static/lib/bootstrap/css/bootstrap.css'/>
<link rel='stylesheet' href='/web/static/lib/fontawesome/css/font-awesome.css'/>
</head>
<div class="container">
<div class="text-center" style="margin-top:128px">
<i class="fa fa-check-circle fa-5x text-success" />
<template id="rating_external_page_view" name="Rating Page Done">
<t t-call="web.layout">
<t t-set="head">
<link rel='stylesheet' href='/web/static/lib/bootstrap/css/bootstrap.css'/>
<link rel='stylesheet' href='/web/static/lib/fontawesome/css/font-awesome.css'/>
</t>
<div class="container">
<div class="text-center" style="margin-top:128px">
<i class="fa fa-check-circle fa-5x text-success" />
</div>
<h2 class="text-center">We appreciate your feedback!</h2>
<div class="text-center">
<a t-att-href="web_base_url" class="btn btn-primary">Go to our website</a>
</div>
</div>
<h2 class="text-center">We appreciate your feedback!</h2>
<div class="text-center">
<a t-att-href="web_base_url" class="btn btn-primary">Go to our website</a>
</div>
</div>
</t>
</template>
<!-- External page: rate and submit feedback -->
<template id="rating_external_page_submit">
<head>
<link rel='stylesheet' href='/web/static/lib/bootstrap/css/bootstrap.css'/>
</head>
<div class="container">
<div clas="row">
<h1 class="text-center">Thanks! We appreciate your feedback.</h1>
<h4 class="text-center text-muted" style="margin-bottom: 32px;">Your rating has been submitted.</h4>
<div class="pull-left">
<img t-attf-src='/rating/static/src/img/rating_#{rate}.png'/>
<template id="rating_external_page_submit" name="Rating Page Submit">
<t t-call="web.layout">
<t t-set="head">
<link rel='stylesheet' href='/web/static/lib/bootstrap/css/bootstrap.css'/>
</t>
<div class="container">
<div clas="row">
<h1 class="text-center">Thanks! We appreciate your feedback.</h1>
<h4 class="text-center text-muted" style="margin-bottom: 32px;">Your rating has been submitted.</h4>
<div class="pull-left">
<img t-attf-src='/rating/static/src/img/rating_#{rate}.png'/>
</div>
<div style="margin-left: 80px;">
you are <b t-esc="rate_name"></b><br/>
on our services on "<b t-esc="rating.res_name"></b>"<br/>
<t t-if="rating.rated_partner_id">by <b t-esc="rating.rated_partner_id.name"></b>.</t>
</div>
<div class="clearfix"></div>
<p style="margin-top:32px;">
Would be great if you can provide more information:
</p>
<form class="form-horizontal" t-attf-action="/rating/#{token}/#{rate}/submit_feedback" method="post">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<textarea class="form-control" name="feedback" rows="8" t-att-value="rating.feedback"></textarea>
<button type="submit" class="btn btn-primary" style="margin-top:8px;">Send Feedback</button>
</form>
</div>
<div style="margin-left: 80px;">
you are <b t-esc="rate_name"></b><br/>
on our services on "<b t-esc="rating.res_name"></b>"<br/>
<t t-if="rating.rated_partner_id">by <b t-esc="rating.rated_partner_id.name"></b>.</t>
</div>
<div class="clearfix"></div>
<p style="margin-top:32px;">
Would be great if you can provide more information:
</p>
<form class="form-horizontal" t-attf-action="/rating/#{token}/#{rate}/submit_feedback" method="post">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<textarea class="form-control" name="feedback" rows="8" t-att-value="rating.feedback"></textarea>
<button type="submit" class="btn btn-primary" style="margin-top:8px;">Send Feedback</button>
</form>
</div>
</div>
</t>
</template>
</data>
</odoo>
+87 -20
View File
@@ -1,24 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record model="ir.ui.view" id="view_rating_rating_kanban">
<record id="rating_rating_view_tree" model="ir.ui.view">
<field name="name">rating.rating.tree</field>
<field name="model">rating.rating</field>
<field name="arch" type="xml">
<tree string="Rating" create="false" edit="false">
<field name="res_name"/>
<field name="rated_partner_id"/>
<field name="partner_id"/>
<field name="rating_text"/>
<field name="feedback"/>
<field name="create_date" string="Submitted on"/>
</tree>
</field>
</record>
<record id="rating_rating_view_form" model="ir.ui.view">
<field name="name">rating.rating.form</field>
<field name="model">rating.rating</field>
<field name="arch" type="xml">
<form string="Rating" create="false" edit="false">
<sheet>
<group>
<group>
<field name="res_name"/>
<field name="rated_partner_id"/>
<field name="partner_id"/>
<field name="rating" invisible="1"/>
<field name="create_date" string="Submitted on"/>
</group>
<group>
<div colspan="2" class="text-center">
<field name="rating_image" widget='image'/>
<div class="mt4">
<strong><field name="rating_text"/></strong>
</div>
</div>
</group>
<field name="feedback" nolabel="1" attrs="{'invisible': [('feedback','=',False)]}"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="rating_rating_view_kanban" model="ir.ui.view">
<field name="name">rating.rating.kanban</field>
<field name="model">rating.rating</field>
<field name="arch" type="xml">
<kanban create="false" class="oe_background_grey">
<kanban create="false">
<field name="rating"/>
<field name="res_name"/>
<field name="feedback"/>
<field name="partner_id"/>
<templates>
<t t-name="kanban-box">
<div t-att-title="record.feedback.raw_value ? 'Feedback:\n' + record.feedback.raw_value : ''">
<img t-attf-src="/rating/static/src/img/rating_#{record.rating.raw_value}.png"
data-html="true" data-placement="bottom" class="pull-left"/>
<div style="margin-left: 80px">
<div><b><field name="rated_partner_id"/></b></div>
<div><span class="text-muted">by </span><field name="partner_id"/></div>
<div t-if="record.res_name.raw_value"><span class="text-muted">for </span><field name="res_name"/></div>
<div><span class="text-muted">on </span><field name="create_date"/></div>
<div class="oe_kanban_global_click">
<div class="o_kanban_image">
<img t-attf-src="/rating/static/src/img/rating_#{record.rating.raw_value}.png" />
</div>
<div class="oe_kanban_details">
<strong>
<field name="rated_partner_id" />
</strong>
<ul>
<li>
<span class="o_text_overflow">
by
<span t-att-title="record.partner_id.value">
<field name="partner_id" />
</span>
</span>
</li>
<li>
<span class="o_text_overflow">
for
<a type="object" name="action_open_rated_object" t-att-title="record.res_name.raw_value">
<field name="res_name" />
</a>
</span>
</li>
<li>
on <field name="create_date" />
</li>
</ul>
<i t-if="record.feedback.raw_value" class="fa fa-comment pull-right mt4" t-attf-title="Feedback:\n#{record.feedback.raw_value}" />
</div>
</div>
</t>
@@ -27,7 +94,7 @@
</field>
</record>
<record model="ir.ui.view" id="view_rating_rating_pivot">
<record id="rating_rating_view_pivot" model="ir.ui.view">
<field name="name">rating.rating.pivot</field>
<field name="model">rating.rating</field>
<field name="arch" type="xml">
@@ -39,7 +106,7 @@
</field>
</record>
<record model="ir.ui.view" id="view_rating_rating_graph">
<record id="rating_rating_view_graph" model="ir.ui.view">
<field name="name">rating.rating.graph</field>
<field name="model">rating.rating</field>
<field name="arch" type="xml">
@@ -50,7 +117,7 @@
</field>
</record>
<record model="ir.ui.view" id="view_rating_rating_search">
<record id="rating_rating_view_search" model="ir.ui.view">
<field name="name">rating.rating.search</field>
<field name="model">rating.rating</field>
<field name="arch" type="xml">
@@ -60,9 +127,9 @@
<field name="partner_id"/>
<field name="res_name"/>
<field name="res_id"/>
<filter string="Happy" domain="[('rating', '&gt;=', 7)]"/>
<filter string="Okay" domain="[('rating', '&gt;', 3), ('rating', '&lt;', 7)]"/>
<filter string="Unhappy" domain="[('rating', '&gt;=', 1), ('rating', '&lt;=',3)]"/>
<filter string="Satisfied" name="rating_happy" domain="[('rating', '=', 10)]"/>
<filter string="Not satisfied" name="rating_okay" domain="[('rating', '=', 5)]"/>
<filter string="Highly dissatisfied" name="rating_unhappy" domain="[('rating', '=', 1)]"/>
<separator/>
<filter string="My Ratings" domain="[('rated_partner_id.user_ids', 'in', [uid])]"/>
<group expand="0" string="Group By">
@@ -81,13 +148,13 @@
<record id="action_view_rating" model="ir.actions.act_window">
<field name="name">Rating</field>
<field name="res_model">rating.rating</field>
<field name="view_mode">kanban,graph,pivot</field>
<field name="domain">[('consumed','=',True)]</field>
<field name="view_mode">kanban,tree,graph,pivot,form</field>
<field name="domain">[('consumed','=',True)]</field>
<field name="help" type="html">
<p>
There is no rating for this object at the moment.
</p>
</field>
</record>
</data>
</odoo>
-1
View File
@@ -14,7 +14,6 @@ This module Allows a customer to give rating on Project.
'data': [
'data/project_data.xml',
'views/project_view.xml',
'views/project_dashboard.xml',
],
'demo': ['data/project_demo.xml'],
'installable': True,
+5 -5
View File
@@ -2,31 +2,31 @@
<odoo>
<data noupdate="1">
<record id="rating_task_1" model="rating.rating">
<field name="res_model">project.task</field>
<field name="res_model_id" ref="project.model_project_task"/>
<field name="rated_partner_id" ref="base.partner_root"/>
<field name="partner_id" ref="portal.demo_user0_res_partner"/>
<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_model_id" ref="project.model_project_task"/>
<field name="rated_partner_id" ref="base.partner_demo"/>
<field name="partner_id" ref="base.partner_demo"/>
<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_model_id" ref="project.model_project_task"/>
<field name="rated_partner_id" ref="base.partner_root"/>
<field name="partner_id" ref="base.partner_root"/>
<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_model_id" ref="project.model_project_task"/>
<field name="rated_partner_id" ref="base.partner_root"/>
<field name="partner_id" ref="base.partner_root"/>
<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_model_id" ref="project.model_project_task"/>
<field name="rated_partner_id" ref="base.partner_root"/>
<field name="partner_id" ref="base.res_partner_4"/>
<field name="res_id" ref="project.project_task_24"/>
+5 -5
View File
@@ -33,15 +33,14 @@ class Task(models.Model):
def write(self, values):
res = super(Task, self).write(values)
if 'stage_id' in values and values.get('stage_id'):
self.filtered(lambda x: x.project_id.rating_status == 'stage')._send_task_rating_mail()
self.filtered(lambda x: x.project_id.rating_status == 'stage')._send_task_rating_mail(force_send=True)
return res
def _send_task_rating_mail(self):
def _send_task_rating_mail(self, force_send=False):
for task in self:
rating_template = task.stage_id.rating_template_id
if rating_template:
force_send = self.env.context.get('force_send', True)
task.rating_send_request(rating_template, partner=task.partner_id, reuse_rating=False, force_send=force_send)
task.rating_send_request(rating_template, lang=task.partner_id.lang, force_send=force_send)
def rating_get_partner_id(self):
res = super(Task, self).rating_get_partner_id()
@@ -53,6 +52,7 @@ class Task(models.Model):
def rating_apply(self, rate, token=None, feedback=None, subtype=None):
return super(Task, self).rating_apply(rate, token=token, feedback=feedback, subtype="rating_project.mt_task_rating")
class Project(models.Model):
_inherit = "project.project"
@@ -61,7 +61,7 @@ class Project(models.Model):
@api.model
def _send_rating_all(self):
projects = self.search([('rating_status', '=', 'periodic'), ('rating_request_deadline', '<=', fields.Datetime.now())])
projects.with_context(force_send=False)._send_rating_mail()
projects._send_rating_mail()
projects._compute_rating_request_deadline()
def _send_rating_mail(self):
@@ -1,35 +0,0 @@
<odoo>
<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="rating_status" invisible="1"/>
</field>
<xpath expr="//div[contains(@class, 'o_kanban_primary_left')]" position="inside">
<div t-if="record.rating_status.raw_value != 'no'" class="mt8 text-primary" title="Percentage of happy ratings over the past 30 days. Get rating details from the More menu.">
<b>
<i class="fa fa-smile-o"/>
<t t-if="record.percentage_satisfaction_project.value == -1">
No rating yet
</t>
<t t-if="record.percentage_satisfaction_project.value != -1">
<t t-esc="record.percentage_satisfaction_project.value"/>%
</t>
</b>
</div>
</xpath>
<xpath expr="//div[contains(@class, 'o_kanban_card_manage_section')]" position="inside">
<div t-if="record.rating_status.raw_value != 'no'">
<a name="action_view_all_rating" type="object">
Customer Ratings
</a>
</div>
</xpath>
</field>
</record>
</odoo>
+58 -2
View File
@@ -5,7 +5,7 @@
<record id="rating_rating_action_task" model="ir.actions.act_window">
<field name="name">Customer Ratings</field>
<field name="res_model">rating.rating</field>
<field name="view_mode">kanban,pivot,graph</field>
<field name="view_mode">kanban,tree,pivot,graph,form</field>
<field name="domain">[('res_model', '=', 'project.task'), ('res_id', '=', active_id), ('consumed', '=', True)]</field>
<field name="help" type="html">
<p>
@@ -14,6 +14,18 @@
</field>
</record>
<record id="rating_rating_view_search" model="ir.ui.view">
<field name="name">rating.rating.search.inherit</field>
<field name="model">rating.rating</field>
<field name="inherit_id" ref="rating.rating_rating_view_search" />
<field name="arch" type="xml">
<xpath expr="//filter[@name='rating_unhappy']" position="after">
<separator />
<filter string="Rating for tasks" name="rating_tasks" domain="[('res_model', '=', 'project.task')]" />
</xpath>
</field>
</record>
<record id="project_task_view_form_inherit_rating" model="ir.ui.view">
<field name="name">project.task.view.form.inherit.rating</field>
<field name="model">project.task</field>
@@ -29,6 +41,18 @@
</field>
</record>
<record id="project_task_view_search" model="ir.ui.view">
<field name="name">project.task.search.inherit</field>
<field name="model">project.task</field>
<field name="inherit_id" ref="project.view_task_search_form" />
<field name="arch" type="xml">
<xpath expr="//group" position="before">
<separator/>
<filter string="Rated tasks" domain="[('rating_last_value', '!=', 0.0)]" />
</xpath>
</field>
</record>
<record id="project_task_view_kanban_inherit_rating" model="ir.ui.view">
<field name="name">project.task.view.kanban.inherit.rating</field>
<field name="model">project.task</field>
@@ -79,6 +103,38 @@
</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="rating_status" invisible="1"/>
</field>
<xpath expr="//div[contains(@class, 'o_kanban_primary_left')]" position="inside">
<div t-if="record.rating_status.raw_value != 'no'" class="mt8 text-primary" title="Percentage of happy ratings over the past 30 days. Get rating details from the More menu.">
<b>
<i class="fa fa-smile-o"/>
<t t-if="record.percentage_satisfaction_project.value == -1">
No rating yet
</t>
<t t-if="record.percentage_satisfaction_project.value != -1">
<t t-esc="record.percentage_satisfaction_project.value"/>%
</t>
</b>
</div>
</xpath>
<xpath expr="//div[contains(@class, 'o_kanban_card_manage_section')]" position="inside">
<div t-if="record.rating_status.raw_value != 'no'">
<a name="action_view_all_rating" type="object">
Customer Ratings
</a>
</div>
</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>
@@ -96,7 +152,7 @@
<record id="rating_rating_action_project" model="ir.actions.act_window">
<field name="name">Customer Ratings</field>
<field name="res_model">rating.rating</field>
<field name="view_mode">kanban,pivot,graph</field>
<field name="view_mode">kanban,tree,pivot,graph,form</field>
<field name="domain">[('res_model','in',['project.task', 'project.issue']), ('consumed', '=', True)]</field>
<field name="help" type="html">
<p>
@@ -2,19 +2,19 @@
<odoo>
<data noupdate="1">
<record id="rating_issue_1" model="rating.rating">
<field name="res_model">project.issue</field>
<field name="res_model_id" ref="project_issue.model_project_issue"/>
<field name="rated_partner_id" ref="base.partner_demo"/>
<field name="partner_id" ref="base.partner_demo"/>
<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_model_id" ref="project_issue.model_project_issue"/>
<field name="rated_partner_id" ref="base.partner_demo"/>
<field name="partner_id" ref="base.res_partner_12"/>
<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_model_id" ref="project_issue.model_project_issue"/>
<field name="rated_partner_id" ref="base.partner_root"/>
<field name="partner_id" ref="base.res_partner_3"/>
<field name="res_id" ref="project_issue.crm_case_improvereportsinhrms0"/>
@@ -15,14 +15,14 @@ class ProjectIssue(models.Model):
def write(self, values):
res = super(ProjectIssue, self).write(values)
if 'stage_id' in values and values.get('stage_id'):
self.filtered(lambda x: x.project_id.rating_status == 'stage')._send_issue_rating_mail()
self.filtered(lambda x: x.project_id.rating_status == 'stage')._send_issue_rating_mail(force_send=True)
return res
def _send_issue_rating_mail(self):
def _send_issue_rating_mail(self, force_send=False):
for issue in self:
rating_template = issue.stage_id.rating_template_id
if rating_template:
issue.rating_send_request(rating_template, partner=issue.partner_id, reuse_rating=False)
issue.rating_send_request(rating_template, lang=issue.partner_id.lang, force_send=force_send)
@api.multi
def rating_apply(self, rate, token=None, feedback=None, subtype=None):
@@ -88,9 +88,9 @@ class Project(models.Model):
action = super(Project, self).action_view_all_rating()
task_domain = action['domain']
domain = []
if self.use_tasks: # add task domain, if neeeded
if self.use_tasks: # add task domain, if needed
domain = task_domain
if self.use_issues: # add issue domain if needed
if self.use_issues: # add issue domain if needed
issue_domain = self.action_view_issue_rating()['domain']
domain = domain + issue_domain
if self.use_tasks and self.use_issues:
@@ -5,7 +5,7 @@
<record id="rating_rating_action_issue" model="ir.actions.act_window">
<field name="name">Customer Ratings</field>
<field name="res_model">rating.rating</field>
<field name="view_mode">kanban,pivot,graph</field>
<field name="view_mode">kanban,tree,pivot,graph,form</field>
<field name="domain">[('res_model','=','project.issue'),('res_id','=',active_id), ('consumed', '=', True)]</field>
<field name="help" type="html">
<p>
@@ -14,6 +14,17 @@
</field>
</record>
<record id="rating_rating_view_search" model="ir.ui.view">
<field name="name">rating.rating.search.inherit</field>
<field name="model">rating.rating</field>
<field name="inherit_id" ref="rating.rating_rating_view_search" />
<field name="arch" type="xml">
<xpath expr="//filter[@name='rating_tasks']" position="after">
<filter string="Rating for issues" domain="[('res_model', '=', 'project.issue')]" />
</xpath>
</field>
</record>
<record id="project_issue_view_form_inherit_rating" model="ir.ui.view">
<field name="name">project.issue.view.form.inherit.rating</field>
<field name="model">project.issue</field>
@@ -47,6 +58,18 @@
</field>
</record>
<record id="project_issue_view_search" model="ir.ui.view">
<field name="name">project.issue.view.search.inherit.rating.project.issue</field>
<field name="model">project.issue</field>
<field name="inherit_id" ref="project_issue.view_project_issue_filter" />
<field name="arch" type="xml">
<xpath expr="//group" position="before">
<separator/>
<filter string="Rated issues" domain="[('rating_last_value', '!=', 0.0)]" />
</xpath>
</field>
</record>
<!-- inherit get state button on project -->
<record id="project_issue_view_rating" model="ir.ui.view">
<field name="name">project.issue.view.rating</field>
@@ -16,9 +16,10 @@ class WebsiteMailController(WebsiteMail):
params.pop('rating', False)
message_data = super(WebsiteMailController, self).chatter_json(res_model=res_model, res_id=res_id, message=message, **params)
if message_data and kw.get('rating') and res_model == 'product.template': # restrict rating only for product template
res_model_id = request.env.ref('product.model_product_template').id
rating = request.env['rating.rating'].create({
'rating': float(kw.get('rating')),
'res_model': res_model,
'res_model_id': res_model_id,
'res_id': res_id,
'message_id': message_data['id'],
'consumed': True,
@@ -38,9 +39,10 @@ class WebsiteMailController(WebsiteMail):
try:
fragment = urlparse.urlparse(response.location).fragment
message_id = int(fragment.replace('message-', ''))
res_model_id = request.env.ref('product.model_product_template').id
request.env['rating.rating'].create({
'rating': float(kw.get('rating')),
'res_model': res_model,
'res_model_id': res_model_id,
'res_id': res_id,
'message_id': message_id,
'consumed': True,