[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:
@@ -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,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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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>
|
||||
|
||||
@@ -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', '>=', 7)]"/>
|
||||
<filter string="Okay" domain="[('rating', '>', 3), ('rating', '<', 7)]"/>
|
||||
<filter string="Unhappy" domain="[('rating', '>=', 1), ('rating', '<=',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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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>
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user