Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IMP] rating_*: Improvement #13692

Merged
merged 4 commits into from Jan 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 2 additions & 5 deletions addons/im_livechat/controllers/main.py
Expand Up @@ -86,23 +86,20 @@ def feedback(self, uuid, rate, reason=None, **kwargs):
# 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:
values['rated_partner_id'] = channel.channel_partner_ids[0] and channel.channel_partner_ids[0].id or False
# 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
Expand Down
31 changes: 10 additions & 21 deletions addons/im_livechat/views/mail_channel_views.xml
Expand Up @@ -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>
Expand All @@ -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>
Expand All @@ -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">
Expand Down
72 changes: 62 additions & 10 deletions addons/rating/models/rating.py
Expand Up @@ -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):
Expand All @@ -26,17 +28,37 @@ def _compute_res_name(self):
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:
Expand All @@ -47,13 +69,24 @@ def reset(self):
'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
Expand All @@ -67,6 +100,20 @@ def _compute_rating_count(self):
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
Expand All @@ -83,18 +130,23 @@ def rating_get_access_token(self, partner=None):
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
Expand Down
16 changes: 0 additions & 16 deletions addons/rating/static/src/js/rating.js

This file was deleted.

89 changes: 42 additions & 47 deletions addons/rating/views/rating_template.xml
@@ -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">
Expand All @@ -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
Expand Down Expand Up @@ -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" />
</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>
<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>
</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'/>
</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>
<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 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>