From 798c1da4400a51fa3af7c4a3954668f3182a3384 Mon Sep 17 00:00:00 2001 From: dbh Date: Wed, 22 Mar 2017 11:19:14 +0100 Subject: [PATCH] [IMP] rating: parenting model mecanism This commit provide a parenting system for rated record, such as mail alias. For instance, 'project.project' is the parent of task and issue objects. This will allow to have a global view of customer statisfaction on 'parent' objects (project and livechat channel for now). To do so, the rating mixin provides 2 methods that need to be overriden: `rating_get_parent_model_name` and `rating_get_parent_id`. --- .../im_livechat/models/im_livechat_channel.py | 4 +- addons/im_livechat/models/mail_channel.py | 8 +++ addons/rating/models/rating.py | 57 ++++++++++++++++++- addons/rating/views/rating_view.xml | 5 +- addons/rating_project/models/project.py | 6 ++ addons/rating_project/views/project_view.xml | 2 +- .../models/project_issue.py | 8 ++- 7 files changed, 82 insertions(+), 8 deletions(-) diff --git a/addons/im_livechat/models/im_livechat_channel.py b/addons/im_livechat/models/im_livechat_channel.py index 51ebc87a908..1c72ba8725d 100644 --- a/addons/im_livechat/models/im_livechat_channel.py +++ b/addons/im_livechat/models/im_livechat_channel.py @@ -133,8 +133,8 @@ class ImLivechatChannel(models.Model): :returns : the ir.action 'action_view_rating' with the correct domain """ self.ensure_one() - action = self.env['ir.actions.act_window'].for_xml_id('rating', 'action_view_rating') - action['domain'] = [('res_id', 'in', [s.id for s in self.channel_ids]), ('res_model', '=', 'mail.channel')] + action = self.env['ir.actions.act_window'].for_xml_id('im_livechat', 'rating_rating_action_view_livechat_rating') + action['domain'] = [('parent_res_id', '=', self.id), ('parent_res_model', '=', 'im_livechat.channel')] return action # -------------------------- diff --git a/addons/im_livechat/models/mail_channel.py b/addons/im_livechat/models/mail_channel.py index 5333b7ed4cb..32d66a0154c 100644 --- a/addons/im_livechat/models/mail_channel.py +++ b/addons/im_livechat/models/mail_channel.py @@ -133,3 +133,11 @@ class MailChannel(models.Model): 'channel_ids': self.ids, 'info': 'transient_message', }) + + # Rating Mixin + + def rating_get_parent_model_name(self, values): + return 'im_livechat.channel' + + def rating_get_parent_id(self): + return self.livechat_channel_id.id diff --git a/addons/rating/models/rating.py b/addons/rating/models/rating.py index 8126cc5bb23..317329c5779 100644 --- a/addons/rating/models/rating.py +++ b/addons/rating/models/rating.py @@ -8,6 +8,10 @@ from odoo import api, fields, models, tools, _ from odoo.modules.module import get_resource_path from odoo.tools import pycompat +RATING_LIMIT_SATISFIED = 7 +RATING_LIMIT_OK = 3 +RATING_LIMIT_MIN = 1 + class Rating(models.Model): @@ -32,7 +36,11 @@ class Rating(models.Model): 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) + res_id = fields.Integer(string='Document', required=True, help="Identifier of the rated object", index=True) + parent_res_name = fields.Char('Parent Document Name', compute='_compute_parent_res_name', store=True) + parent_res_model_id = fields.Many2one('ir.model', 'Parent Related Document Model', index=True) + parent_res_model = fields.Char('Parent Document Model', store=True, related='parent_res_model_id.model', index=True) + parent_res_id = fields.Integer('Parent Document', index=True) 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") @@ -43,6 +51,15 @@ class Rating(models.Model): 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.depends('parent_res_model', 'parent_res_id') + def _compute_parent_res_name(self): + for rating in self: + name = False + if rating.parent_res_model and rating.parent_res_id: + name = self.env[rating.parent_res_model].sudo().browse(rating.parent_res_id).name_get() + name = name and name[0][1] or ('%s/%s') % (rating.parent_res_model, rating.parent_res_id) + rating.parent_res_name = name + @api.multi @api.depends('rating') def _compute_rating_image(self): @@ -60,6 +77,32 @@ class Rating(models.Model): for rating in self: rating.rating_text = text[rating.rating] or _('No rating yet') + @api.model + def create(self, values): + if values.get('res_model_id') and values.get('res_id'): + values.update(self._find_parent_data(values)) + return super(Rating, self).create(values) + + @api.multi + def write(self, values): + if values.get('res_model_id') and values.get('res_id'): + values.update(self._find_parent_data(values)) + return super(Rating, self).write(values) + + def _find_parent_data(self, values): + """ Determine the parent res_model/res_id, based on the values to create or write """ + current_model_name = self.env['ir.model'].sudo().browse(values['res_model_id']).model + current_record = self.env[current_model_name].browse(values['res_id']) + data = { + 'parent_res_model_id': False, + 'parent_res_id': False, + } + if hasattr(current_record, 'rating_get_parent_model_name'): + parent_res_model = current_record.rating_get_parent_model_name(values) + data['parent_res_model_id'] = self.env['ir.model']._get(parent_res_model).id + data['parent_res_id'] = current_record.rating_get_parent_id() + return data + @api.multi def reset(self): for record in self: @@ -123,6 +166,14 @@ class RatingMixin(models.AbstractModel): self.env['rating.rating'].sudo().search([('res_model', '=', self._name), ('res_id', 'in', record_ids)]).unlink() return result + def rating_get_parent_model_name(self, vals): + """ Return the parent model name """ + return None + + def rating_get_parent_id(self): + """ Return the parent record id """ + return None + def rating_get_partner_id(self): if hasattr(self, 'partner_id') and self.partner_id: return self.partner_id @@ -236,9 +287,9 @@ class RatingMixin(models.AbstractModel): data = self.rating_get_repartition(domain=domain) res = dict.fromkeys(['great', 'okay', 'bad'], 0) for key in data: - if key >= 7: + if key >= RATING_LIMIT_SATISFIED: res['great'] += data[key] - elif key > 3: + elif key > RATING_LIMIT_OK: res['okay'] += data[key] else: res['bad'] += data[key] diff --git a/addons/rating/views/rating_view.xml b/addons/rating/views/rating_view.xml index b5d63046141..d638eb61fde 100644 --- a/addons/rating/views/rating_view.xml +++ b/addons/rating/views/rating_view.xml @@ -7,6 +7,7 @@ + @@ -25,6 +26,7 @@ + @@ -127,13 +129,14 @@ + - + diff --git a/addons/rating_project/models/project.py b/addons/rating_project/models/project.py index 7fd98913b8d..fda4cc15220 100644 --- a/addons/rating_project/models/project.py +++ b/addons/rating_project/models/project.py @@ -53,6 +53,12 @@ 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") + def rating_get_parent_model_name(self, vals): + return 'project.project' + + def rating_get_parent_id(self): + return self.project_id.id + class Project(models.Model): diff --git a/addons/rating_project/views/project_view.xml b/addons/rating_project/views/project_view.xml index fbbd9bb8efc..4104f2d94d7 100644 --- a/addons/rating_project/views/project_view.xml +++ b/addons/rating_project/views/project_view.xml @@ -153,7 +153,7 @@ Customer Ratings rating.rating kanban,tree,pivot,graph,form - [('res_model','in',['project.task', 'project.issue']), ('consumed', '=', True)] + [('parent_res_model','=','project.project'), ('consumed', '=', True)]

Customer ratings on tasks/issues. If you have no rating, change your project Settings to activate it. diff --git a/addons/rating_project_issue/models/project_issue.py b/addons/rating_project_issue/models/project_issue.py index 47704a347fd..00b5143b84b 100644 --- a/addons/rating_project_issue/models/project_issue.py +++ b/addons/rating_project_issue/models/project_issue.py @@ -29,10 +29,16 @@ class ProjectIssue(models.Model): def rating_apply(self, rate, token=None, feedback=None, subtype=None): return super(ProjectIssue, self).rating_apply(rate, token=token, feedback=feedback, subtype="rating_project_issue.mt_issue_rating") + def rating_get_parent_model_name(self, vals): + return 'project.project' + + def rating_get_parent_id(self): + return self.project_id.id + class Stage(models.Model): - _inherit = ['project.task.type'] + _inherit = 'project.task.type' def _default_domain_rating_template_id(self): domain = super(Stage, self)._default_domain_rating_template_id()