rating/models/rating_parent_mixin.py

72 lines
4.1 KiB
Python
Raw Permalink Normal View History

2024-05-03 15:15:12 +03:00
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from collections import defaultdict
from datetime import timedelta
from odoo import api, fields, models
from odoo.addons.rating.models import rating_data
from odoo.osv import expression
from odoo.tools.float_utils import float_compare
class RatingParentMixin(models.AbstractModel):
_name = 'rating.parent.mixin'
_description = "Rating Parent Mixin"
_rating_satisfaction_days = False # Number of last days used to compute parent satisfaction. Set to False to include all existing rating.
rating_ids = fields.One2many(
'rating.rating', 'parent_res_id', string='Ratings',
auto_join=True, groups='base.group_user',
domain=lambda self: [('parent_res_model', '=', self._name)])
rating_percentage_satisfaction = fields.Integer(
"Rating Satisfaction",
compute="_compute_rating_percentage_satisfaction", compute_sudo=True,
store=False, help="Percentage of happy ratings")
rating_count = fields.Integer(string='# Ratings', compute="_compute_rating_percentage_satisfaction", compute_sudo=True)
rating_avg = fields.Float('Average Rating', groups='base.group_user',
compute='_compute_rating_percentage_satisfaction', compute_sudo=True, search='_search_rating_avg')
rating_avg_percentage = fields.Float('Average Rating (%)', groups='base.group_user',
compute='_compute_rating_percentage_satisfaction', compute_sudo=True)
@api.depends('rating_ids.rating', 'rating_ids.consumed')
def _compute_rating_percentage_satisfaction(self):
# build domain and fetch data
domain = [('parent_res_model', '=', self._name), ('parent_res_id', 'in', self.ids), ('rating', '>=', rating_data.RATING_LIMIT_MIN), ('consumed', '=', True)]
if self._rating_satisfaction_days:
domain += [('write_date', '>=', fields.Datetime.to_string(fields.datetime.now() - timedelta(days=self._rating_satisfaction_days)))]
data = self.env['rating.rating']._read_group(domain, ['parent_res_id', 'rating'], ['__count'])
# get repartition of grades per parent id
default_grades = {'great': 0, 'okay': 0, 'bad': 0}
grades_per_parent = dict((parent_id, dict(default_grades)) for parent_id in self.ids) # map: {parent_id: {'great': 0, 'bad': 0, 'ok': 0}}
rating_scores_per_parent = defaultdict(int) # contains the total of the rating values per record
for parent_id, rating, count in data:
grade = rating_data._rating_to_grade(rating)
grades_per_parent[parent_id][grade] += count
rating_scores_per_parent[parent_id] += rating * count
# compute percentage per parent
for record in self:
repartition = grades_per_parent.get(record.id, default_grades)
rating_count = sum(repartition.values())
record.rating_count = rating_count
record.rating_percentage_satisfaction = repartition['great'] * 100 / rating_count if rating_count else -1
record.rating_avg = rating_scores_per_parent[record.id] / rating_count if rating_count else 0
record.rating_avg_percentage = record.rating_avg / 5
def _search_rating_avg(self, operator, value):
if operator not in rating_data.OPERATOR_MAPPING:
raise NotImplementedError('This operator %s is not supported in this search method.' % operator)
domain = [('parent_res_model', '=', self._name), ('consumed', '=', True), ('rating', '>=', rating_data.RATING_LIMIT_MIN)]
if self._rating_satisfaction_days:
min_date = fields.datetime.now() - timedelta(days=self._rating_satisfaction_days)
domain = expression.AND([domain, [('write_date', '>=', fields.Datetime.to_string(min_date))]])
rating_read_group = self.env['rating.rating'].sudo()._read_group(domain, ['parent_res_id'], ['rating:avg'])
parent_res_ids = [
parent_res_id
for parent_res_id, rating_avg in rating_read_group
if rating_data.OPERATOR_MAPPING[operator](float_compare(rating_avg, value, 2), 0)
]
return [('id', 'in', parent_res_ids)]