144 lines
5.1 KiB
Python
144 lines
5.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from odoo import api, fields, models
|
|
from odoo.exceptions import ValidationError
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class Rating(models.Model):
|
|
_inherit = 'rating.rating'
|
|
_description = 'Rating with 5-star support'
|
|
|
|
# Enable audit logging for rating changes
|
|
_log_access = True
|
|
|
|
# Override rating field to support 0-5 range
|
|
rating = fields.Float(
|
|
string='Rating Value',
|
|
required=True,
|
|
help='Rating value: 0 (no rating), 1-5 (stars)',
|
|
aggregator="avg",
|
|
tracking=True # Track changes to rating value
|
|
)
|
|
|
|
# Computed fields for star display
|
|
rating_stars_filled = fields.Integer(
|
|
compute='_compute_rating_stars',
|
|
string='Filled Stars',
|
|
help='Number of filled stars to display'
|
|
)
|
|
|
|
rating_stars_empty = fields.Integer(
|
|
compute='_compute_rating_stars',
|
|
string='Empty Stars',
|
|
help='Number of empty stars to display'
|
|
)
|
|
|
|
# Audit fields - track who submitted/modified the rating
|
|
feedback = fields.Text(
|
|
string='Feedback',
|
|
tracking=True # Track changes to feedback
|
|
)
|
|
|
|
consumed = fields.Boolean(
|
|
string='Rating Submitted',
|
|
tracking=True # Track when rating is consumed
|
|
)
|
|
|
|
@api.constrains('rating')
|
|
def _check_rating_value(self):
|
|
"""Validate rating is between 0 and 5"""
|
|
for record in self:
|
|
if record.rating < 0 or record.rating > 5:
|
|
raise ValidationError(
|
|
'Rating must be between 0 and 5 stars. '
|
|
'Received value: %s' % record.rating
|
|
)
|
|
# Allow 0 (no rating) or values between 1-5
|
|
if record.rating > 0 and record.rating < 1:
|
|
raise ValidationError(
|
|
'Rating must be 0 (no rating) or between 1 and 5 stars. '
|
|
'Received value: %s' % record.rating
|
|
)
|
|
|
|
@api.depends('rating')
|
|
def _compute_rating_stars(self):
|
|
"""Compute the number of filled and empty stars"""
|
|
for record in self:
|
|
# Round rating to nearest integer for display
|
|
rating_int = round(record.rating)
|
|
record.rating_stars_filled = rating_int
|
|
record.rating_stars_empty = 5 - rating_int
|
|
|
|
def _get_rating_stars_html(self):
|
|
"""Generate HTML for star display"""
|
|
self.ensure_one()
|
|
filled_stars = self.rating_stars_filled
|
|
empty_stars = self.rating_stars_empty
|
|
|
|
# Unicode star characters
|
|
filled_star = '★' # U+2605 BLACK STAR
|
|
empty_star = '☆' # U+2606 WHITE STAR
|
|
|
|
# Generate HTML with stars
|
|
html = '<span class="o_rating_stars">'
|
|
html += '<span class="o_rating_stars_filled">' + (filled_star * filled_stars) + '</span>'
|
|
html += '<span class="o_rating_stars_empty">' + (empty_star * empty_stars) + '</span>'
|
|
html += '</span>'
|
|
|
|
return html
|
|
|
|
def write(self, vals):
|
|
"""Override write to add audit logging for rating changes"""
|
|
# Log rating changes for audit trail
|
|
for record in self:
|
|
if 'rating' in vals and vals['rating'] != record.rating:
|
|
old_value = record.rating
|
|
new_value = vals['rating']
|
|
_logger.info(
|
|
'Rating modified: ID=%s, Model=%s, ResID=%s, OldValue=%s, NewValue=%s, User=%s',
|
|
record.id,
|
|
record.res_model,
|
|
record.res_id,
|
|
old_value,
|
|
new_value,
|
|
self.env.user.login
|
|
)
|
|
|
|
# Post message to chatter if available
|
|
if record.res_model and record.res_id:
|
|
try:
|
|
resource = self.env[record.res_model].browse(record.res_id)
|
|
if resource.exists() and hasattr(resource, 'message_post'):
|
|
resource.message_post(
|
|
body=f'Rating updated from {int(old_value)} to {int(new_value)} stars',
|
|
subject='Rating Updated',
|
|
message_type='notification',
|
|
subtype_xmlid='mail.mt_note'
|
|
)
|
|
except Exception as e:
|
|
_logger.warning('Could not post rating change to chatter: %s', str(e))
|
|
|
|
return super(Rating, self).write(vals)
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
"""Override create to add audit logging for new ratings"""
|
|
records = super(Rating, self).create(vals_list)
|
|
|
|
# Log new ratings for audit trail
|
|
for record in records:
|
|
if record.rating > 0:
|
|
_logger.info(
|
|
'Rating created: ID=%s, Model=%s, ResID=%s, Value=%s, User=%s',
|
|
record.id,
|
|
record.res_model,
|
|
record.res_id,
|
|
record.rating,
|
|
self.env.user.login
|
|
)
|
|
|
|
return records
|