[REF] rating, various: cleanup rating from routes

PURPOSE

Cleanup code and flow of customer rating: routes, rating_apply, rating and
message creation and update.

SPECIFICATIONS

Cleanup code about rating controllers and rating_apply. Notably correctly
link a message to a rating once a feedback is posted, whatever the flow.

Update ``rating_apply`` to use either a token, either an existing rating to
udpate it and post a message. Always link the message and the rating to
be sure DB data are coherent.

This requires an update in several demo data to correctly set tokens on
ratings and use it in calls to ``rating_apply`` done in xml files.

Extract default subtype computation of rating_apply in a sub-method to allow
setting this parameter without having to deal with ``rating_apply`` details.

CODE CLEANUP

Split behavior that is generic but actually used only in project about stage
update based on rating. Move it directly in project. As it is used only once
and as generic approach is hardcoded based on fields names better keep it
localized.

Task-2812665 (Rating: Cleanup rating flow code)

Part-of: odoo/odoo#80707
This commit is contained in:
Thibault Delavallée
2022-04-04 17:48:23 +02:00
parent 084ed6920b
commit cce67a0a4d
14 changed files with 202 additions and 76 deletions
@@ -25,13 +25,15 @@
<field name="anonymous_name">Visitor #234, Mitchell Admin</field>
</record>
<record id="im_livechat_rating_1" model="rating.rating">
<field name="access_token">LIVECHAT_1</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_0"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field eval="False" name="partner_id"/>
<field eval="True" name="consumed"/>
</record>
<function eval="([ref('im_livechat.im_livechat_mail_channel_data_0')], 5)" model="mail.channel" name="rating_apply"/>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_0')], 5, 'LIVECHAT_1', None, 'Good Job')"/>
<record id="im_livechat_mail_message_5_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_0"/>
@@ -81,13 +83,15 @@
<field name="anonymous_name">Visitor #323, Marc Demo</field>
</record>
<record id="im_livechat_rating_2" model="rating.rating">
<field name="access_token">LIVECHAT_2</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_1"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="rated_partner_id" ref="base.partner_demo"/>
<field eval="False" name="partner_id"/>
<field eval="True" name="consumed"/>
</record>
<function eval="([ref('im_livechat.im_livechat_mail_channel_data_1')], 5)" model="mail.channel" name="rating_apply"/>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_1')], 5, 'LIVECHAT_2', None, 'Super Job')"/>
<record id="im_livechat_mail_message_10_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_1"/>
@@ -137,13 +141,16 @@
<field name="anonymous_name">Joel Willis, Mitchell Admin</field>
</record>
<record id="im_livechat_rating_3" model="rating.rating">
<field name="access_token">LIVECHAT_3</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_2"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field name="partner_id" ref="base.partner_demo_portal"/>
<field eval="True" name="consumed"/>
</record>
<function eval="([ref('im_livechat.im_livechat_mail_channel_data_2')], 5)" model="mail.channel" name="rating_apply"/>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_2')], 5, 'LIVECHAT_3', None, 'Mega Job')"/>
<record id="im_livechat_mail_message_14_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_2"/>
@@ -185,13 +192,16 @@
<field name="anonymous_name">Joel Willis, Marc Demo</field>
</record>
<record id="im_livechat_rating_4" model="rating.rating">
<field name="access_token">LIVECHAT_4</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_3"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="rated_partner_id" ref="base.partner_demo"/>
<field name="partner_id" ref="base.partner_demo_portal"/>
<field eval="True" name="consumed"/>
</record>
<function eval="([ref('im_livechat.im_livechat_mail_channel_data_3')], 5)" model="mail.channel" name="rating_apply"/>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_3')], 5, 'LIVECHAT_4', None, 'Good Job')"/>
<record id="im_livechat_mail_message_17_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_3"/>
@@ -225,13 +235,15 @@
<field name="anonymous_name">Visitor #532, Mitchell Admin</field>
</record>
<record id="im_livechat_rating_5" model="rating.rating">
<field name="access_token">LIVECHAT_5</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_4"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field eval="False" name="partner_id"/>
<field eval="True" name="consumed"/>
</record>
<function eval="([ref('im_livechat.im_livechat_mail_channel_data_4')], 1)" model="mail.channel" name="rating_apply"/>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_4')], 5, 'LIVECHAT_5', None, 'Super Job')"/>
<record id="im_livechat_mail_message_21_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_4"/>
@@ -273,13 +285,15 @@
<field name="anonymous_name">Visitor #649, Mitchell Admin</field>
</record>
<record id="im_livechat_rating_6" model="rating.rating">
<field name="access_token">LIVECHAT_6</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_5"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field eval="False" name="partner_id"/>
<field eval="True" name="consumed"/>
</record>
<function eval="([ref('im_livechat.im_livechat_mail_channel_data_5')], 5)" model="mail.channel" name="rating_apply"/>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_5')], 5, 'LIVECHAT_6', None, 'Good Job')"/>
<record id="im_livechat_mail_message_25_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_5"/>
@@ -321,13 +335,15 @@
<field name="anonymous_name">Joel Willis, Mitchell Admin</field>
</record>
<record id="im_livechat_rating_7" model="rating.rating">
<field name="access_token">LIVECHAT_7</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_6"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field name="partner_id" ref="base.partner_demo_portal"/>
<field eval="True" name="consumed"/>
</record>
<function eval="([ref('im_livechat.im_livechat_mail_channel_data_6')], 5)" model="mail.channel" name="rating_apply"/>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_6')], 5, 'LIVECHAT_7', None, 'Super Job')"/>
<record id="im_livechat_mail_message_29_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_6"/>
@@ -369,13 +385,15 @@
<field name="anonymous_name">Visitor #722, Marc Demo</field>
</record>
<record id="im_livechat_rating_8" model="rating.rating">
<field name="access_token">LIVECHAT_8</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_7"/>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="rated_partner_id" ref="base.partner_demo"/>
<field eval="False" name="partner_id"/>
<field eval="True" name="consumed"/>
</record>
<function eval="([ref('im_livechat.im_livechat_mail_channel_data_7')], 5)" model="mail.channel" name="rating_apply"/>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.im_livechat_mail_channel_data_7')], 5, 'LIVECHAT_8', None, 'Super Job')"/>
<record id="im_livechat_mail_message_33_data" model="mail.message">
<field name="model">mail.channel</field>
<field name="res_id" ref="im_livechat.im_livechat_mail_channel_data_7"/>
@@ -470,14 +488,15 @@
<field name="model">mail.channel</field>
</record>
<record id="rating_rating_livechat_1" model="rating.rating">
<field name="access_token">LIVECHAT_9</field>
<field name="res_model_id" ref="mail.model_mail_channel"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field name="partner_id" ref="base.partner_admin"/>
<field name="create_date" eval="datetime.now() - timedelta(days=1, seconds=-53)"/>
<field name="res_id" ref="im_livechat.mail_channel_livechat_1"/>
<field name="rating" eval="5"/>
<field name="consumed" eval="True"/>
</record>
<function model="mail.channel" name="rating_apply"
eval="([ref('im_livechat.mail_channel_livechat_1')], 5, 'LIVECHAT_9', None, 'Super Job')"/>
</data>
</odoo>
+4 -4
View File
@@ -2930,9 +2930,6 @@ class MailThread(models.AbstractModel):
# DISCORDUSS API
# ------------------------------------------------------
def _message_update_content_after_hook(self, message):
""" Hook to add custom behavior after having updated the message content. """
def _message_add_reaction_after_hook(self, message, content):
""" Hook to add custom behavior after having added a reaction to a message. """
@@ -2940,7 +2937,7 @@ class MailThread(models.AbstractModel):
""" Hook to add custom behavior after having removed a reaction from a message. """
# ------------------------------------------------------
# WRAPPERS AND TOOLS
# THREAD MESSAGE UPDATE
# ------------------------------------------------------
def message_change_thread(self, new_thread, new_parent_message=False):
@@ -2983,6 +2980,9 @@ class MailThread(models.AbstractModel):
msg_not_comment.write(msg_vals)
return True
def _message_update_content_after_hook(self, message):
""" Hook to add custom behavior after having updated the message content. """
# ------------------------------------------------------
# CONTROLLERS
# ------------------------------------------------------
+12 -4
View File
@@ -1227,36 +1227,44 @@ Send it ASAP, its urgent.</field>
<!-- Rating Demo Data -->
<record id="rating_task_1" model="rating.rating">
<field name="access_token">PROJECT_1</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_demo_portal"/>
<field name="res_id" ref="project.project_1_task_3"/>
</record>
<function model="project.task" name="rating_apply" eval="([ref('project.project_1_task_3')], 5, None, 'Good Job')"/>
<function model="project.task" name="rating_apply"
eval="([ref('project.project_1_task_3')], 5, 'PROJECT_1', None, 'Good Job')"/>
<record id="rating_task_2" model="rating.rating">
<field name="access_token">PROJECT_2</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_2_task_7"/>
</record>
<function model="project.task" name="rating_apply" eval="([ref('project.project_2_task_7')], 1, 'Not as good as expected')"/>
<function model="project.task" name="rating_apply"
eval="([ref('project.project_2_task_7')], 1, 'PROJECT_2', None, 'Not as good as expected')"/>
<record id="rating_task_3" model="rating.rating">
<field name="access_token">PROJECT_3</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_demo_portal"/>
<field name="res_id" ref="project.project_1_task_4"/>
</record>
<function model="project.task" name="rating_apply" eval="([ref('project.project_1_task_4')], 5, None, 'Exactly what I asked for, thank you!')"/>
<function model="project.task" name="rating_apply"
eval="([ref('project.project_1_task_4')], 5, 'PROJECT_3', None, 'Exactly what I asked for, thank you!')"/>
<record id="rating_task_4" model="rating.rating">
<field name="access_token">PROJECT_4</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_demo_portal"/>
<field name="res_id" ref="project.project_1_task_2"/>
</record>
<function model="project.task" name="rating_apply" eval="([ref('project.project_1_task_2')], 1, None, 'There must have been some miscomunication, because the result is not quite what I had in mind. I would like to request some modifications.')"/>
<function model="project.task" name="rating_apply"
eval="([ref('project.project_1_task_2')], 1, 'PROJECT_4', None, 'There must have been some miscomunication, because the result is not quite what I had in mind. I would like to request some modifications.')"/>
<!-- add the email template as value for the project stage 2 -->
+10 -2
View File
@@ -9,6 +9,7 @@ from datetime import timedelta, datetime, time
from random import randint
from odoo import api, Command, fields, models, tools, SUPERUSER_ID, _, _lt
from odoo.addons.rating.models.rating_data import RATING_LIMIT_OK
from odoo.exceptions import UserError, ValidationError, AccessError
from odoo.osv.expression import OR, AND
from odoo.tools.misc import get_lang
@@ -2278,8 +2279,15 @@ class Task(models.Model):
return self.project_id.partner_id
return res
def rating_apply(self, rate, token=None, feedback=None, subtype_xmlid=None):
return super(Task, self).rating_apply(rate, token=token, feedback=feedback, subtype_xmlid="project.mt_task_rating")
def rating_apply(self, rate, token=None, rating=None, feedback=None, subtype_xmlid=None):
rating = super(Task, self).rating_apply(rate, token=token, rating=rating, feedback=feedback, subtype_xmlid=subtype_xmlid)
if self.stage_id and self.stage_id.auto_validation_kanban_state:
kanban_state = 'done' if rating.rating >= RATING_LIMIT_OK else 'blocked'
self.write({'kanban_state': kanban_state})
return rating
def _rating_apply_get_default_subtype_id(self):
return self.env['ir.model.data']._xmlid_to_res_id("project.mt_task_rating")
def _rating_get_parent_field_name(self):
return 'project_id'
+1 -1
View File
@@ -3,7 +3,7 @@
{
'name': 'Customer Rating',
'version': '1.0',
'version': '1.1',
'category': 'Productivity',
'description': """
This module allows a customer to give rating.
+35 -14
View File
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
import werkzeug
from odoo import http
from odoo.http import request
@@ -20,31 +21,51 @@ class Rating(http.Controller):
@http.route('/rate/<string:token>/<int:rate>', type='http', auth="public", website=True)
def action_open_rating(self, token, rate, **kwargs):
assert rate in (1, 3, 5), "Incorrect rating"
if rate not in (1, 3, 5):
raise ValueError(_("Incorrect rating: should be 1, 3 or 5 (received %d)"), rate)
rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)])
if not rating:
return request.not_found()
rate_names = {
5: _("Satisfied"),
3: _("Okay"),
1: _("Dissatisfied")
}
return werkzeug.exceptions.Forbidden()
record_sudo = request.env[rating.res_model].sudo().browse(rating.res_id)
if not record_sudo.exists():
return werkzeug.exceptions.Forbidden()
rating.write({'rating': rate, 'consumed': True})
lang = rating.partner_id.lang or get_lang(request.env).code
return request.env['ir.ui.view'].with_context(lang=lang)._render_template('rating.rating_external_page_submit', {
'rating': rating, 'token': token,
'rate_names': rate_names, 'rate': rate
'rating': rating,
'token': token,
'rate_names': {
5: _("Satisfied"),
3: _("Okay"),
1: _("Dissatisfied"),
},
'rate': rate,
})
@http.route(['/rate/<string:token>/submit_feedback'], type="http", auth="public", methods=['post'], website=True)
def action_submit_rating(self, token, **kwargs):
rate = int(kwargs.get('rate'))
assert rate in (1, 3, 5), "Incorrect rating"
def action_submit_rating(self, token, rate, **kwargs):
rate = int(rate)
if rate not in (1, 3, 5):
raise ValueError(_("Incorrect rating: should be 1, 3 or 5 (received %d)"), rate)
rating = request.env['rating.rating'].sudo().search([('access_token', '=', token)])
if not rating:
return request.not_found()
return werkzeug.exceptions.Forbidden()
record_sudo = request.env[rating.res_model].sudo().browse(rating.res_id)
record_sudo.rating_apply(rate, token=token, feedback=kwargs.get('feedback'))
if not record_sudo.exists():
return werkzeug.exceptions.Forbidden()
record_sudo.rating_apply(rate,
rating=rating,
feedback=kwargs.get('feedback'),
subtype_xmlid=None, # force default subtype choice
)
lang = rating.partner_id.lang or get_lang(request.env).code
return request.env['ir.ui.view'].with_context(lang=lang)._render_template('rating.rating_external_page_view', {
'web_base_url': rating.get_base_url(),
+15 -1
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models
from odoo import api, models, _
class MailThread(models.AbstractModel):
@@ -9,6 +9,7 @@ class MailThread(models.AbstractModel):
@api.returns('mail.message', lambda value: value.id)
def message_post(self, **kwargs):
rating_id = kwargs.pop('rating_id', False)
rating_value = kwargs.pop('rating_value', False)
rating_feedback = kwargs.pop('rating_feedback', False)
message = super(MailThread, self).message_post(**kwargs)
@@ -25,4 +26,17 @@ class MailThread(models.AbstractModel):
'consumed': True,
'partner_id': self.env.user.partner_id.id,
})
elif rating_id:
self.env['rating.rating'].browse(rating_id).write({'message_id': message.id})
return message
def _message_create(self, values_list):
""" Force usage of rating-specific methods and API allowing to delegate
computation to records. Keep methods optimized and skip rating_ids
support to simplify MailThrad main API. """
if not isinstance(values_list, (list)):
values_list = [values_list]
if any(values.get('rating_ids') for values in values_list):
raise ValueError(_("Posting a rating should be done using message post API."))
return super()._message_create(values_list)
+6 -1
View File
@@ -42,6 +42,7 @@ class Rating(models.Model):
partner_id = fields.Many2one('res.partner', string='Customer', help="Author of the rating")
rating = fields.Float(string="Rating Value", group_operator="avg", default=0, help="Rating value: 0=Unhappy, 5=Happy")
rating_image = fields.Binary('Image', compute='_compute_rating_image')
rating_image_url = fields.Char('Image URL', compute='_compute_rating_image')
rating_text = fields.Selection(rating_data.RATING_TEXT, string='Rating', store=True, compute='_compute_rating_text', readonly=True)
feedback = fields.Text('Comment', help="Reason of the rating")
message_id = fields.Many2one(
@@ -91,13 +92,17 @@ class Rating(models.Model):
self.ensure_one()
return 'rating_%s.png' % rating_data._rating_to_threshold(self.rating)
@api.depends('rating')
def _compute_rating_image(self):
self.rating_image_url = False
self.rating_image = False
for rating in self:
try:
image_path = get_resource_path('rating', 'static/src/img', rating._get_rating_image_filename())
rating.rating_image_url = '/rating/static/src/img/%s' % rating._get_rating_image_filename()
rating.rating_image = base64.b64encode(open(image_path, 'rb').read()) if image_path else False
except (IOError, OSError):
rating.rating_image = False
pass
@api.depends('rating')
def _compute_rating_text(self):
+39 -29
View File
@@ -173,42 +173,52 @@ class RatingMixin(models.AbstractModel):
subtype_id=subtype_id
)
def rating_apply(self, rate, token=None, feedback=None, subtype_xmlid=None):
""" Apply a rating given a token. If the current model inherits from
mail.thread mixin, a message is posted on its chatter. User going through
this method should have at least employee rights because of rating
manipulation (either employee, either sudo-ed in public controllers after
security check granting access).
def rating_apply(self, rate, token=None, rating=None, feedback=None, subtype_xmlid=None):
""" Apply a rating to the record. This rating can either be linked to a
token (customer flow) or directly a rating record (code flow).
:param float rate : the rating value to apply
:param string token : access token
:param string feedback : additional feedback
:param string subtype_xmlid : xml id of a valid mail.message.subtype
If the current model inherits from mail.thread mixin a message is posted
on its chatter. User going through this method should have at least
employee rights as well as rights on the current record because of rating
manipulation and chatter post (either employee, either sudo-ed in public
controllers after security check granting access).
:returns rating.rating record
:param float rate: the rating value to apply (from 0 to 5);
:param string token: access token to fetch the rating to apply (optional);
:param record rating: rating.rating to apply (if no token);
:param string feedback: additional feedback (plaintext);
:param string subtype_xmlid: xml id of a valid mail.message.subtype used
to post the message (if it applies). If not given a classic comment is
posted;
:returns rating: rating.rating record
"""
rating = None
if rate < 0 or rate > 5:
raise ValueError('Wrong rating value. A rate should be between 0 and 5 (received %d).' % rate)
if token:
rating = self.env['rating.rating'].search([('access_token', '=', token)], limit=1)
else:
rating = self.env['rating.rating'].search([('res_model', '=', self._name), ('res_id', '=', self.ids[0])], limit=1)
if rating:
rating.write({'rating': rate, 'feedback': feedback, 'consumed': True})
if hasattr(self, 'message_post'):
feedback = tools.plaintext2html(feedback or '')
self.message_post(
body="<img src='/rating/static/src/img/rating_%s.png' alt=':%s/5' style='width:18px;height:18px;float:left;margin-right: 5px;'/>%s"
% (rate, rate, feedback),
subtype_xmlid=subtype_xmlid or "mail.mt_comment",
author_id=rating.partner_id and rating.partner_id.id or None # None will set the default author in mail_thread.py
)
if hasattr(self, 'stage_id') and self.stage_id and hasattr(self.stage_id, 'auto_validation_kanban_state') and self.stage_id.auto_validation_kanban_state:
if rating.rating > 2:
self.write({'kanban_state': 'done'})
else:
self.write({'kanban_state': 'blocked'})
if not rating:
raise ValueError('Invalid token or rating.')
rating.write({'rating': rate, 'feedback': feedback, 'consumed': True})
if hasattr(self, 'message_post'):
if subtype_xmlid is None:
subtype_id = self._rating_apply_get_default_subtype_id()
else:
subtype_id = self.env['ir.model.data']._xmlid_to_res_id(subtype_xmlid)
feedback = tools.plaintext2html(feedback or '')
self.message_post(
author_id=rating.partner_id.id or None, # None will set the default author in mail_thread.py
body="<img src='%s' alt=':%s/5' style='width:18px;height:18px;float:left;margin-right: 5px;'/>%s"
% (rating.rating_image_url, rate, feedback),
rating_id=rating.id,
subtype_id=subtype_id,
)
return rating
def _rating_apply_get_default_subtype_id(self):
return self.env['ir.model.data']._xmlid_to_res_id("mail.mt_comment")
def _rating_get_repartition(self, add_stats=False, domain=None):
""" get the repatition of rating grade for the given res_ids.
:param add_stats : flag to add stat to the result
@@ -1045,21 +1045,24 @@
<!-- Rating Demo Data -->
<record id="rating_task_1" model="rating.rating">
<field name="access_token">TS_0</field>
<field name="res_model_id" ref="project.model_project_task"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field name="partner_id" ref="base.res_partner_2"/>
<field name="res_id" ref="project_agr_task_1"/>
</record>
<function model="project.task" name="rating_apply" eval="([ref('project_agr_task_1')], 5, None, 'This is already looking very promising, thanks for the good work! 😃')"/>
<function model="project.task" name="rating_apply"
eval="([ref('project_agr_task_1')], 5, 'TS_0', None, 'This is already looking very promising, thanks for the good work! 😃')"/>
<record id="rating_task_2" model="rating.rating">
<field name="access_token">TS_1</field>
<field name="res_model_id" ref="project.model_project_task"/>
<field name="rated_partner_id" ref="base.partner_admin"/>
<field name="partner_id" ref="base.res_partner_4"/>
<field name="res_id" ref="project_dpc_task_5"/>
</record>
<function model="project.task" name="rating_apply" eval="([ref('project_dpc_task_5')], 3, None, 'Everything is working fine, but there are some loose cables')"/>
<function model="project.task" name="rating_apply"
eval="([ref('project_dpc_task_5')], 3, 'TS_1', None, 'Everything is working fine, but there are some loose cables')"/>
<!-- Timesheet for those tasks -->
<record id="project_agr_task_1_account_analytic_line_1" model="account.analytic.line">
+1
View File
@@ -24,6 +24,7 @@ real applications. """,
'sms',
],
'data': [
'data/mail_message_subtype_data.xml',
'security/ir.model.access.csv',
'security/ir_rule_data.xml',
],
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="mt_mail_test_rating_rating_done" model="mail.message.subtype">
<field name="name">Rating Done</field>
<field name="description">Rating Done</field>
<field name="res_model">mail.test.rating</field>
<field name="default" eval="True"/>
<field name="internal" eval="False"/>
</record>
</odoo>
@@ -51,5 +51,8 @@ class MailTestRating(models.Model):
elif not rating.phone_nbr:
rating.phone_nbr = False
def _rating_apply_get_default_subtype_id(self):
return self.env['ir.model.data']._xmlid_to_res_id("test_mail_full.mt_mail_test_rating_rating_done")
def rating_get_partner_id(self):
return self.customer_id
+31 -7
View File
@@ -48,27 +48,51 @@ class TestRatingFlow(TestMailFullCommon, TestMailFullRecipients):
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_rating_rating_apply(self):
record_rating = self.env['mail.test.rating'].browse(self.record_rating.ids)
record_messages = record_rating.message_ids
# prepare rating token
access_token = record_rating.rating_get_access_token()
record_rating.invalidate_cache(fnames=['rating_ids'])
# apply a rate
# apply a rate as note (first click)
with self.mock_mail_gateway(mail_unlink_sent=False), self.mock_mail_app():
record_rating.rating_apply(5, token=access_token, feedback='Top Feedback')
record_rating.rating_apply(5, token=access_token, feedback='Top Feedback', subtype_xmlid='mail.mt_note')
message = record_rating.message_ids[0]
rating = record_rating.rating_ids
# check posted message
self.assertEqual(record_rating.message_ids, record_messages + message)
self.assertIn('Top Feedback', message.body)
self.assertIn('rating/static/src/img/rating_5.png', message.body)
self.assertIn('/rating/static/src/img/rating_5.png', message.body)
self.assertEqual(message.author_id, self.partner_1)
self.assertFalse(message.rating_ids)
self.assertEqual(message.notified_partner_ids, self.partner_admin)
self.assertEqual(message.subtype_id, self.env.ref('mail.mt_comment'))
self.assertEqual(message.rating_ids, rating)
self.assertFalse(message.notified_partner_ids)
self.assertEqual(message.subtype_id, self.env.ref('mail.mt_note'))
# check rating update
self.assertTrue(rating.consumed)
self.assertEqual(rating.feedback, 'Top Feedback')
self.assertFalse(rating.message_id)
self.assertEqual(rating.message_id, message)
self.assertEqual(rating.rating, 5)
# apply a rate again (second click with feedback)
with self.mock_mail_gateway(mail_unlink_sent=False), self.mock_mail_app():
record_rating.rating_apply(1, token=access_token, feedback='Bad Feedback')
# check posted message: a new message is posted with default subtype
update_message = record_rating.message_ids[0]
self.assertNotEqual(update_message, message)
self.assertEqual(record_rating.message_ids, record_messages + message + update_message)
self.assertIn('Bad Feedback', update_message.body)
self.assertIn('/rating/static/src/img/rating_1.png', update_message.body)
self.assertEqual(update_message.author_id, self.partner_1)
self.assertEqual(update_message.rating_ids, rating)
self.assertEqual(update_message.notified_partner_ids, self.partner_admin)
self.assertEqual(update_message.subtype_id, self.env.ref("test_mail_full.mt_mail_test_rating_rating_done"))
# check rating update
rating = record_rating.rating_ids
self.assertTrue(rating.consumed)
self.assertEqual(rating.feedback, 'Bad Feedback')
self.assertEqual(rating.message_id, update_message)
self.assertEqual(rating.rating, 1)