diff --git a/addons/rating/models/__init__.py b/addons/rating/models/__init__.py
index 27f56b84f11..8ef312cfec8 100644
--- a/addons/rating/models/__init__.py
+++ b/addons/rating/models/__init__.py
@@ -1,2 +1,5 @@
# -*- coding: utf-8 -*-
+
from . import rating
+from . import mail_thread
+from . import mail_message
diff --git a/addons/rating/models/mail_message.py b/addons/rating/models/mail_message.py
new file mode 100644
index 00000000000..b0190933d15
--- /dev/null
+++ b/addons/rating/models/mail_message.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models
+
+
+class MailMessage(models.Model):
+ _inherit = 'mail.message'
+
+ rating_ids = fields.One2many('rating.rating', 'message_id', string='Related ratings')
+ rating_value = fields.Float("Rating Value", compute='_compute_rating_value', store=True)
+
+ @api.multi
+ @api.depends('rating_ids', 'rating_ids.rating')
+ def _compute_rating_value(self):
+ ratings = self.env['rating.rating'].search([('message_id', 'in', self.ids), ('consumed', '=', True)], order='create_date DESC')
+ mapping = dict((r.message_id.id, r.rating) for r in ratings)
+ for message in self:
+ message.rating_value = mapping.get(message.id, 0.0)
diff --git a/addons/rating/models/mail_thread.py b/addons/rating/models/mail_thread.py
new file mode 100644
index 00000000000..89ba8badf89
--- /dev/null
+++ b/addons/rating/models/mail_thread.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, models
+
+
+class MailThread(models.AbstractModel):
+ _inherit = 'mail.thread'
+
+ @api.multi
+ @api.returns('self', lambda value: value.id)
+ def message_post(self, body='', subject=None, message_type='notification', subtype=None, parent_id=False, attachments=None, content_subtype='html', **kwargs):
+ rating_value = kwargs.get('rating_value')
+ message = super(MailThread, self).message_post(body=body, subject=subject, message_type=message_type, subtype=subtype, parent_id=parent_id, attachments=attachments, content_subtype=content_subtype, **kwargs)
+ if rating_value:
+ ir_model = self.env['ir.model'].sudo().search([('model', '=', self._name)])
+ self.env['rating.rating'].create({
+ 'rating': float(rating_value) if rating_value is not None else False,
+ 'res_model_id': ir_model.id,
+ 'res_id': self.id,
+ 'message_id': message.id,
+ 'consumed': True,
+ 'partner_id': self.env.user.partner_id.id,
+ })
+ return message
diff --git a/addons/rating/static/src/css/rating_common.css b/addons/rating/static/src/css/rating_common.css
deleted file mode 100644
index ff84353a8eb..00000000000
--- a/addons/rating/static/src/css/rating_common.css
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Star Widget */
-.o_rating_star_card{
- margin-bottom: 5px;
-}
-
-.o_rating_star_card .stars {
- display: inline-block;
- color: #FACC2E;
- margin-right: 15px;
-}
-
-.o_rating_star_card .stars i {
- margin-right: -3px;
- text-align: center;
-}
-
-.o_rating_star_card .stars.enabled{
- cursor: pointer;
-}
-
-.o_rating_star_card .rate_text{
- display: inline-block;
-}
-
-
-/* Rating Card */
-.o_rating_card .progress {
- position: relative;
- height: 25px;
- margin-bottom: 3px;
-}
-.o_rating_card .progress-bar {
- background-color: #FACC2E;
-}
-.o_rating_card .progress > .progress_type {
- position: absolute;
- left: 0px;
- font-weight: 800;
- padding: 3px 10px 2px 10px;
- color: rgb(120, 100, 100);
- width: 100%;
-}
-.o_rating_card .progress > .progress_completed {
- position: absolute;
- right: 0px;
- font-weight: 800;
- padding: 3px 10px 2px;
-}
\ No newline at end of file
diff --git a/addons/rating/static/src/js/rating_common.js b/addons/rating/static/src/js/rating_common.js
deleted file mode 100644
index 623f6466c1b..00000000000
--- a/addons/rating/static/src/js/rating_common.js
+++ /dev/null
@@ -1,127 +0,0 @@
-odoo.define('rating.rating', function (require) {
- "use strict";
-
- var Widget = require('web.Widget');
- var translation = require('web.translation');
- var _t = translation._t;
-
- // Star Widget
- var RatingStarWidget = Widget.extend({
- template: 'rating.rating_star_card',
- events: {
- "mousemove .stars i" : "moveOnStars",
- "mouseleave .stars i" : "moveOut",
- "click .stars" : "clickOnStar",
- "mouseleave .stars" : "moveOutStars",
- },
- init: function(parent, options){
- this._super.apply(this, arguments);
- this.options = _.defaults(options || {}, {
- 'rating_default_value': 0,
- 'rating_disabled': 0,
- });
- this.labels = {
- '0': "",
- '1': _t("I hate it"),
- '2': _t("I don't like it"),
- '3': _t("It's okay"),
- '4': _t("I like it"),
- '5': _t("I love it"),
- };
- this.user_click = false; // user has click or not
- this.set("star_value", 0);
- this.on("change:star_value", this, this.changeStars);
- },
- start: function(){
- this.$input = this.$('input');
- this.star_list = this.$('.stars').find('i');
- // set the default value
- this.set("star_value", this.options.rating_default_value);
- this.is_editable = !this.options.rating_disabled;
- },
- attachTo: function(el){
- this._super.apply(this, arguments);
- // set the default value and bind event
- var default_value = this.$('input').data('default') || this.options['rating_default_value'];
- default_value = this.roundToHalf(default_value);
- this.set('star_value', default_value);
- // is_editable value from DOM
- this.is_editable = !this.$input.data('is_disabled') || this.options['rating_disabled'];
- },
- changeStars: function(){
- var val = this.get("star_value");
- var index = Math.floor(val);
- var decimal = val - index;
- // reset the stars
- this.star_list.removeClass('fa-star fa-star-half-o').addClass('fa-star-o');
-
- this.$('.stars').find("i:lt("+index+")").removeClass('fa-star-o fa-star-half-o').addClass('fa-star');
- if(decimal){
- this.$('.stars').find("i:eq("+(index)+")").removeClass('fa-star-o fa-star fa-star-half-o').addClass('fa-star-half-o');
- }
-
- this.$input.val(val);
- this.$('.rate_text .label').text(this.labels[index]);
- },
- moveOut: function(){
- if(!this.user_click && this.is_editable){
- this.set("star_value", 0);
- }
- this.user_click = false;
- },
- moveOnStars: function(e){
- if(this.is_editable){
- this.$('.rate_text').show();
- var index = this.$('.stars i').index(e.currentTarget);
- this.set("star_value", index+1);
- }
- },
- clickOnStar: function(e){
- if(this.is_editable){
- this.user_click = true;
- }
- },
- moveOutStars: function(e){
- this.$('.rate_text').hide();
- },
- roundToHalf: function(value) {
- var converted = parseFloat(value); // Make sure we have a number
- var decimal = (converted - parseInt(converted, 10));
- decimal = Math.round(decimal * 10);
- if(decimal == 5){
- return (parseInt(converted, 10)+0.5);
- }
- if((decimal < 3) || (decimal > 7)){
- return Math.round(converted);
- }else{
- return (parseInt(converted, 10)+0.5);
- }
- },
- });
-
- var page_widgets = {};
-
- $(document).ready(function(){
- // Rating Card
- $('[data-toggle="rating-popover"]').popover({
- html : true,
- trigger: 'hover',
- title: function() {
- return $(this).parent().find('.rating_popover').find('.popover-title').html();
- },
- content: function() {
- return $(this).parent().find('.rating_popover').find('.popover-content').html();
- }
- });
- // Rating Star Widget instances
- $('.o_rating_star_card').each(function(index, elem){
- page_widgets[index] = new RatingStarWidget();
- page_widgets[index].attachTo(elem);
- })
- });
-
- return {
- RatingStarWidget: RatingStarWidget,
- rating_star_widgets: page_widgets,
- };
-});
\ No newline at end of file
diff --git a/addons/rating/static/src/xml/rating_common.xml b/addons/rating/static/src/xml/rating_common.xml
deleted file mode 100644
index fb703785ae7..00000000000
--- a/addons/rating/static/src/xml/rating_common.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
diff --git a/addons/rating/views/rating_template.xml b/addons/rating/views/rating_template.xml
index 79b86bfa9de..b6fa5304b54 100644
--- a/addons/rating/views/rating_template.xml
+++ b/addons/rating/views/rating_template.xml
@@ -1,91 +1,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- %
-
-
-
-
-
-
- %
-
-
-
-
-
-
-
-
-
-
diff --git a/addons/website_blog/models/website_blog.py b/addons/website_blog/models/website_blog.py
index cf202dea0ff..f10f3fe0745 100644
--- a/addons/website_blog/models/website_blog.py
+++ b/addons/website_blog/models/website_blog.py
@@ -140,14 +140,8 @@ class BlogPost(models.Model):
teaser = fields.Text('Teaser', compute='_compute_teaser', inverse='_set_teaser')
teaser_manual = fields.Text(string='Teaser Content')
- website_message_ids = fields.One2many(
- 'mail.message', 'res_id',
- domain=lambda self: [
- '&', '&', ('model', '=', self._name), ('message_type', '=', 'comment'), ('path', '=', False)
- ],
- string='Website Messages',
- help="Website communication history",
- )
+ website_message_ids = fields.One2many(domain=lambda self: [('model', '=', self._name), ('message_type', '=', 'comment'), ('path', '=', False)])
+
# creation / update stuff
create_date = fields.Datetime('Created on', index=True, readonly=True)
published_date = fields.Datetime('Published Date')
diff --git a/addons/website_blog/views/website_blog_templates.xml b/addons/website_blog/views/website_blog_templates.xml
index f6f35135484..c2ecb61d5aa 100644
--- a/addons/website_blog/views/website_blog_templates.xml
+++ b/addons/website_blog/views/website_blog_templates.xml
@@ -299,13 +299,11 @@
-
diff --git a/addons/website_project/views/project_templates.xml b/addons/website_project/views/project_templates.xml
index 412fca0cb8f..0a4f7622795 100644
--- a/addons/website_project/views/project_templates.xml
+++ b/addons/website_project/views/project_templates.xml
@@ -134,7 +134,6 @@
-
@@ -254,7 +253,6 @@
-
diff --git a/addons/website_project_issue/views/project_issue_templates.xml b/addons/website_project_issue/views/project_issue_templates.xml
index e83e24fa2bc..686d7f5f428 100644
--- a/addons/website_project_issue/views/project_issue_templates.xml
+++ b/addons/website_project_issue/views/project_issue_templates.xml
@@ -136,7 +136,6 @@
-
diff --git a/addons/website_quote/views/website_quote_templates.xml b/addons/website_quote/views/website_quote_templates.xml
index 39b7924cc93..d9ffd6a5da4 100644
--- a/addons/website_quote/views/website_quote_templates.xml
+++ b/addons/website_quote/views/website_quote_templates.xml
@@ -438,15 +438,12 @@
-
+
+
+
+
+
+
diff --git a/addons/website_rating/__init__.py b/addons/website_rating/__init__.py
new file mode 100644
index 00000000000..7d34c7c054a
--- /dev/null
+++ b/addons/website_rating/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import controllers
+from . import models
diff --git a/addons/website_rating/__manifest__.py b/addons/website_rating/__manifest__.py
new file mode 100644
index 00000000000..c77566341dd
--- /dev/null
+++ b/addons/website_rating/__manifest__.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+{
+ 'name': 'Website Rating',
+ 'category': 'Hidden',
+ 'version': '1.0',
+ 'description': """
+Bridge module for rating on website stuff.
+ """,
+ 'depends': ['rating', 'website_mail'],
+ 'data': [
+ 'views/website_rating_templates.xml',
+ ],
+ 'qweb': ['static/src/xml/*.xml'],
+ 'auto_installable': True,
+}
diff --git a/addons/website_rating/controllers/__init__.py b/addons/website_rating/controllers/__init__.py
new file mode 100644
index 00000000000..a8136630fc9
--- /dev/null
+++ b/addons/website_rating/controllers/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import website_mail
diff --git a/addons/website_rating/controllers/website_mail.py b/addons/website_rating/controllers/website_mail.py
new file mode 100644
index 00000000000..4487307effd
--- /dev/null
+++ b/addons/website_rating/controllers/website_mail.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from werkzeug.exceptions import NotFound
+
+from odoo import http
+from odoo.http import request
+
+from odoo.addons.website_mail.controllers.main import WebsiteMail
+
+
+class WebsiteRating(WebsiteMail):
+
+ @http.route()
+ def website_chatter_init(self, res_model, res_id, domain=False, limit=False, **kwargs):
+ result = super(WebsiteRating, self).website_chatter_init(res_model, res_id, domain=domain, limit=limit, **kwargs)
+ # get the rating statistics about the record
+ if kwargs.get('rating_include'):
+ record = request.env[res_model].browse(res_id)
+ if hasattr(record, 'rating_get_stats'):
+ result['rating_stats'] = record.rating_get_stats([('website_published', '=', True)])
+ return result
+
+ @http.route()
+ def website_message_fetch(self, res_model, res_id, domain=False, limit=False, offset=False, **kw):
+ # add 'rating_include' in context, to fetch them in website_message_format
+ if kw.get('rating_include'):
+ context = dict(request.context)
+ context['rating_include'] = True
+ request.context = context
+ return super(WebsiteRating, self).website_message_fetch(res_model, res_id, domain=domain, limit=limit, offset=offset, **kw)
diff --git a/addons/website_rating/models/__init__.py b/addons/website_rating/models/__init__.py
new file mode 100644
index 00000000000..3404de196ed
--- /dev/null
+++ b/addons/website_rating/models/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import mail_message
+from . import rating
diff --git a/addons/website_rating/models/mail_message.py b/addons/website_rating/models/mail_message.py
new file mode 100644
index 00000000000..8e6c67fc601
--- /dev/null
+++ b/addons/website_rating/models/mail_message.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models
+
+
+class MailMessage(models.Model):
+ _inherit = 'mail.message'
+
+ @api.multi
+ def website_message_format(self):
+ result = super(MailMessage, self).website_message_format()
+ # inlude rating value in data if requested
+ if self._context.get('rating_include'):
+ message_data = self.read(['rating_value'])
+ message_tree = dict((m['id'], m['rating_value']) for m in message_data)
+ for message_vals in result:
+ message_vals['rating_value'] = message_tree.get(message_vals['id'], False) # False for no rating
+ return result
diff --git a/addons/website_sale/models/rating.py b/addons/website_rating/models/rating.py
similarity index 100%
rename from addons/website_sale/models/rating.py
rename to addons/website_rating/models/rating.py
diff --git a/addons/website_rating/static/src/js/website_mail.js b/addons/website_rating/static/src/js/website_mail.js
new file mode 100644
index 00000000000..d9d114de502
--- /dev/null
+++ b/addons/website_rating/static/src/js/website_mail.js
@@ -0,0 +1,234 @@
+odoo.define('website_rating.thread', function(require) {
+ 'use strict';
+
+ var ajax = require('web.ajax');
+ var core = require('web.core');
+ var Widget = require('web.Widget');
+
+ var qweb = core.qweb;
+ var _t = core._t;
+
+ var WebsiteMailThread = require('website_mail.thread').WebsiteMailThread;
+
+ /**
+ * Extends Frontend Chatter to handle rating
+ */
+ WebsiteMailThread.include({
+ events: _.extend({}, WebsiteMailThread.prototype.events, {
+ "mousemove .stars i" : "_onMoveStar",
+ "mouseleave .stars i" : "_onMoveOutStar",
+ "click .stars" : "_onClickStar",
+ "mouseleave .stars" : "_onMouseleaveStar",
+ "click .o_website_rating_select": "_onClickStarDomain",
+ "click .o_website_rating_select_text": "_onClickStarDomainReset",
+ }),
+
+ init: function(parent, options){
+ this._super.apply(this, arguments);
+ // options
+ if(!_.contains(this.options, 'display_rating')){
+ this.options = _.defaults(this.options, {
+ 'display_rating': false,
+ 'rating_default_value': 0.0,
+ });
+ }
+ // rating card
+ this.set('rating_card_values', {});
+ this.set('rating_value', false);
+ this.on("change:rating_value", this, this._onChangeRatingDomain);
+ // rating star
+ this.labels = {
+ '0': "",
+ '1': _t("I hate it"),
+ '2': _t("I don't like it"),
+ '3': _t("It's okay"),
+ '4': _t("I like it"),
+ '5': _t("I love it"),
+ };
+ this.user_click = false; // user has click or not
+ this.set("star_value", this.options.rating_default_value);
+ this.on("change:star_value", this, this._onChangeStarValue);
+ },
+ willStart: function(){
+ var self = this;
+ return this._super.apply(this, arguments).then(function(result){
+ // rating card
+ if(result['rating_stats']){
+ var rating_data = {
+ 'avg': self.round_to_half(result['rating_stats']['avg']),
+ 'percent': [],
+ };
+ _.each(_.keys(result['rating_stats']['percent']), function(rating){
+ if(0 < rating && rating <= 5){
+ rating_data['percent'].push({
+ 'num': rating,
+ 'percent': result['rating_stats']['percent'][rating],
+ });
+ }
+ });
+ self.set('rating_card_values', rating_data);
+ }
+ });
+ },
+ start: function(){
+ var self = this;
+ return this._super.apply(this, arguments).then(function(){
+ // rating stars
+ self.$input = self.$('input[name="rating_value"]');
+ self.$star_list = self.$('.stars').find('i');
+ self.set("star_value", self.options.rating_default_value); // set the default value to trigger the display of star widget
+ });
+ },
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * Update the messages format
+ *
+ * @param {Array}
+ * @returns {Array}
+ */
+ preprocessMessages: function(messages){
+ var self = this;
+ var messages = this._super.apply(this, arguments);
+ if(this.options['display_rating']){
+ _.each(messages, function(m){
+ m['rating_value'] = self.round_to_half(m['rating_value']);
+ });
+ }
+ return messages;
+ },
+ /**
+ * Round the given value with a precision of 0.5.
+ * Example : 1.2 --> 1.0
+ * 1.7 --> 1.5
+ * 1.9 --> 2.0
+ * @param Float
+ * @returns Float
+ **/
+ round_to_half: function(value) {
+ var converted = parseFloat(value); // Make sure we have a number
+ var decimal = (converted - parseInt(converted, 10));
+ decimal = Math.round(decimal * 10);
+ if(decimal == 5){
+ return (parseInt(converted, 10)+0.5);
+ }
+ if((decimal < 3) || (decimal > 7)){
+ return Math.round(converted);
+ }else{
+ return (parseInt(converted, 10)+0.5);
+ }
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ _loadTemplates: function(){
+ return $.when(this._super(), ajax.loadXML('/website_rating/static/src/xml/website_mail.xml', qweb));
+ },
+ _messageFetchPrepareParams: function(){
+ var params = this._super.apply(this, arguments);
+ if(this.options['display_rating']){
+ params['rating_include'] = true;
+ }
+ return params;
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {MouseEvent} event
+ */
+ _onClickStar: function(e){
+ this.user_click = true;
+ this.$input.val(this.get("star_value"));
+ },
+ /**
+ * @private
+ * @param {MouseEvent} event
+ */
+ _onClickStarDomain: function(e){
+ var $tr = this.$(e.currentTarget);
+ var num = $tr.data('star');
+ if($tr.css('opacity') == 1){
+ this.set('rating_value', num);
+ this.$('.o_website_rating_select').css({
+ 'opacity': 0.5,
+ });
+ this.$('.o_website_rating_select_text[data-star="'+num+'"]').css({
+ 'visibility': 'visible',
+ 'opacity': 1,
+ });
+ this.$('.o_website_rating_select[data-star="'+num+'"]').css({
+ 'opacity': 1,
+ });
+ }
+ },
+ /**
+ * @private
+ * @param {MouseEvent} event
+ */
+ _onClickStarDomainReset: function(e){
+ e.stopPropagation();
+ this.set('rating_value', false);
+ this.$('.o_website_rating_select_text').css('visibility', 'hidden');
+ this.$('.o_website_rating_select').css({
+ 'opacity': 1,
+ });
+ },
+ /**
+ * @private
+ */
+ _onChangeRatingDomain: function(){
+ var domain = [];
+ if(this.get('rating_value')){
+ domain = [['rating_value', '=', this.get('rating_value')]];
+ }
+ this._changeCurrentPage(1, domain);
+ },
+ /**
+ * @private
+ */
+ _onChangeStarValue: function(){
+ var val = this.get("star_value");
+ var index = Math.floor(val);
+ var decimal = val - index;
+ // reset the stars
+ this.$star_list.removeClass('fa-star fa-star-half-o').addClass('fa-star-o');
+
+ this.$('.stars').find("i:lt("+index+")").removeClass('fa-star-o fa-star-half-o').addClass('fa-star');
+ if(decimal){
+ this.$('.stars').find("i:eq("+(index)+")").removeClass('fa-star-o fa-star fa-star-half-o').addClass('fa-star-half-o');
+ }
+
+ this.$('.rate_text .label').text(this.labels[index]);
+ },
+ _onMouseleaveStar: function(e){
+ this.$('.rate_text').hide();
+ },
+ /**
+ * @private
+ * @param {MouseEvent} event
+ */
+ _onMoveStar: function(e){
+ var index = this.$('.stars i').index(e.currentTarget);
+ this.$('.rate_text').show();
+ this.set("star_value", index+1);
+ },
+ /**
+ * @private
+ */
+ _onMoveOutStar: function(){
+ if(!this.user_click){
+ this.set("star_value", parseInt(this.$input.val()));
+ }
+ this.user_click = false;
+ },
+ });
+});
diff --git a/addons/website_rating/static/src/less/website_rating.less b/addons/website_rating/static/src/less/website_rating.less
new file mode 100644
index 00000000000..3d7b6465515
--- /dev/null
+++ b/addons/website_rating/static/src/less/website_rating.less
@@ -0,0 +1,70 @@
+/* static stars */
+@rating-star-color: #FACC2E;
+.o_website_rating_static{
+ color: @rating-star-color;
+}
+
+.o_website_rating_card_container {
+
+ .o_message_counter {
+ color: @gray;
+ }
+
+ /* progress bars */
+ table.o_website_rating_progress_table {
+ width: 100%;
+ overflow: visible;
+
+ .o_website_rating_table_star_num{
+ min-width: 30px;
+ }
+ .o_website_rating_select[style*="opacity: 1"] {
+ cursor: pointer;
+ }
+ .o_website_rating_table_progress{
+ min-width: 120px;
+ > .progress {
+ margin-bottom: 5px;
+ margin-left: 5px;
+ margin-right: 5px;
+ }
+ .o_rating_progressbar{
+ background-color: @rating-star-color;
+ }
+ }
+ .o_website_rating_table_percent {
+ text-align: right;
+ padding-left: 5px;
+ font-size: @font-size-small;
+ }
+ .o_website_rating_table_reset {
+ .o_website_rating_select_text {
+ visibility: hidden;
+ }
+ }
+ }
+
+}
+
+/* Star Widget */
+.o_rating_star_card{
+ margin-bottom: 5px;
+ .stars {
+ display: inline-block;
+ color: #FACC2E;
+ margin-right: 15px;
+ }
+
+ .stars i {
+ margin-right: -3px;
+ text-align: center;
+ }
+
+ .stars.enabled{
+ cursor: pointer;
+ }
+
+ .rate_text{
+ display: inline-block;
+ }
+}
diff --git a/addons/website_rating/static/src/xml/website_mail.xml b/addons/website_rating/static/src/xml/website_mail.xml
new file mode 100644
index 00000000000..ffe0df540c4
--- /dev/null
+++ b/addons/website_rating/static/src/xml/website_mail.xml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Average
+
+
+
+
+
+
+
+
+
+
Details
+
+
+
+
+
+ stars
+
+
+
+
+
+ %
+
+
+ Remove selection
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/website_rating/views/website_rating_templates.xml b/addons/website_rating/views/website_rating_templates.xml
new file mode 100644
index 00000000000..c5c6684e371
--- /dev/null
+++ b/addons/website_rating/views/website_rating_templates.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ display_rating or False
+
+
+
+
diff --git a/addons/website_sale/__manifest__.py b/addons/website_sale/__manifest__.py
index 102ed5b4160..abad5ffc189 100644
--- a/addons/website_sale/__manifest__.py
+++ b/addons/website_sale/__manifest__.py
@@ -10,7 +10,7 @@ Odoo E-Commerce
==================
""",
- 'depends': ['website', 'sale', 'payment', 'website_payment', 'website_portal_sale', 'website_account', 'website_mail', 'website_form', 'rating'],
+ 'depends': ['website', 'sale', 'payment', 'website_payment', 'website_portal_sale', 'website_account', 'website_mail', 'website_form', 'website_rating'],
'data': [
'security/ir.model.access.csv',
'security/website_sale.xml',
diff --git a/addons/website_sale/controllers/__init__.py b/addons/website_sale/controllers/__init__.py
index 720ed5bf928..5ee7aaab8f2 100644
--- a/addons/website_sale/controllers/__init__.py
+++ b/addons/website_sale/controllers/__init__.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
from . import backend
from . import main
-from . import website_mail
diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py
index 7162db54804..dbedb81ab88 100644
--- a/addons/website_sale/controllers/main.py
+++ b/addons/website_sale/controllers/main.py
@@ -277,7 +277,6 @@ class WebsiteSale(http.Controller):
def product(self, product, category='', search='', **kwargs):
product_context = dict(request.env.context, active_id=product.id)
ProductCategory = request.env['product.public.category']
- Rating = request.env['rating.rating']
if category:
category = ProductCategory.browse(int(category)).exists()
@@ -296,11 +295,6 @@ class WebsiteSale(http.Controller):
to_currency = pricelist.currency_id
compute_currency = lambda price: from_currency.compute(price, to_currency)
- # get the rating attached to a mail.message, and the rating stats of the product
- ratings = Rating.search([('message_id', 'in', product.website_message_ids.ids)])
- rating_message_values = dict([(record.message_id.id, record.rating) for record in ratings])
- rating_product = product.rating_get_stats([('website_published', '=', True)])
-
if not product_context.get('pricelist'):
product_context['pricelist'] = pricelist.id
product = product.with_context(product_context)
@@ -317,8 +311,6 @@ class WebsiteSale(http.Controller):
'main_object': product,
'product': product,
'get_attribute_value_ids': self.get_attribute_value_ids,
- 'rating_message_values': rating_message_values,
- 'rating_product': rating_product
}
return request.render("website_sale.product", values)
diff --git a/addons/website_sale/controllers/website_mail.py b/addons/website_sale/controllers/website_mail.py
deleted file mode 100644
index 5931098d3a1..00000000000
--- a/addons/website_sale/controllers/website_mail.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# -*- coding: utf-8 -*-
-# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from werkzeug import urls
-
-from odoo import http
-from odoo.http import request
-
-from odoo.addons.website_mail.controllers.main import WebsiteMail
-
-
-class WebsiteMailController(WebsiteMail):
-
- @http.route(['/website_mail/post/json'], type='json', auth='public', website=True)
- def chatter_json(self, res_model='', res_id=None, message='', **kw):
- params = kw.copy()
- 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_id': res_model_id,
- 'res_id': res_id,
- 'message_id': message_data['id'],
- 'consumed': True,
- })
- message_data.update({
- 'rating_default_value': rating.rating,
- 'rating_disabled': True,
- })
- return message_data
-
- @http.route(['/website_mail/post/post'], type='http', methods=['POST'], auth='public', website=True)
- def chatter_post(self, res_model='', res_id=None, message='', redirect=None, **kw):
- params = kw.copy()
- params.pop('rating')
- response = super(WebsiteMailController, self).chatter_post(res_model=res_model, res_id=res_id, message=message, redirect=redirect, **params)
- if kw.get('rating') and res_model == 'product.template': # restrict rating only for product template
- try:
- fragment = urls.url_parse(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_id': res_model_id,
- 'res_id': res_id,
- 'message_id': message_id,
- 'consumed': True,
- })
- except Exception:
- pass
- return response
diff --git a/addons/website_sale/models/__init__.py b/addons/website_sale/models/__init__.py
index 7eca4d5c21a..94adf33f350 100644
--- a/addons/website_sale/models/__init__.py
+++ b/addons/website_sale/models/__init__.py
@@ -4,7 +4,6 @@
from . import crm_team
from . import ir_http
from . import product
-from . import rating
from . import sale_order
from . import website
from . import website_config_settings
diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py
index fe22160267f..c697973cd5d 100644
--- a/addons/website_sale/models/product.py
+++ b/addons/website_sale/models/product.py
@@ -109,11 +109,6 @@ class ProductTemplate(models.Model):
_name = 'product.template'
_mail_post_access = 'read'
- website_message_ids = fields.One2many(
- 'mail.message', 'res_id',
- domain=lambda self: ['&', ('model', '=', self._name), ('message_type', '=', 'comment')],
- string='Website Comments',
- )
website_description = fields.Html('Description for the website', sanitize_attributes=False, translate=html_translate)
alternative_product_ids = fields.Many2many('product.template', 'product_alternative_rel', 'src_id', 'dest_id',
string='Alternative Products', help='Suggest more expensive alternatives to '
diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml
index 83270ed6682..cba93b108d6 100644
--- a/addons/website_sale/views/templates.xml
+++ b/addons/website_sale/views/templates.xml
@@ -17,7 +17,6 @@
-
@@ -552,32 +551,20 @@