add survey_score_ranges: displays different messages depending on the score obtained, allowing different score ranges

This commit is contained in:
Luis 2025-09-22 12:47:58 +02:00
parent 9cabf044c8
commit 4d1eaebc06
11 changed files with 269 additions and 1 deletions

View file

@ -0,0 +1,3 @@
from . import survey_score_range
from . import survey_survey
from . import survey_user_input

View file

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
class SurveyScoreRange(models.Model):
_name = "survey.score.range"
_description = "Survey Score Range"
_order = "survey_id, min_score, max_score, id"
name = fields.Char("Name", required=True, translate=True)
survey_id = fields.Many2one(
"survey.survey", string="Survey", required=True, ondelete="cascade", index=True
)
min_score = fields.Float("Min Score", required=True, help="Inclusive lower bound")
max_score = fields.Float(
"Max Score",
required=True,
help="Inclusive upper bound (use same value as min for exact match). Deje vacío para indicar sin límite superior.",
default=0.0,
)
no_upper_limit = fields.Boolean(
"No upper limit",
help="If checked, max_score is ignored and the range is open-ended ( >= min_score ).",
)
result_html = fields.Html(
"Result Content", translate=True, sanitize=True, sanitize_overridable=True
)
active = fields.Boolean(default=True)
_sql_constraints = [
(
"min_le_max",
"CHECK( min_score <= max_score )",
"El mínimo debe ser menor o igual que el máximo.",
)
]
@api.constrains("min_score", "max_score", "no_upper_limit", "survey_id", "active")
def _check_overlapping(self):
for rec in self:
if rec.no_upper_limit:
domain = [
("id", "!=", rec.id),
("survey_id", "=", rec.survey_id.id),
("active", "=", True),
"|",
("no_upper_limit", "=", True),
("max_score", ">=", rec.min_score),
]
else:
domain = [
("id", "!=", rec.id),
("survey_id", "=", rec.survey_id.id),
("active", "=", True),
("min_score", "<=", rec.max_score),
"|",
("no_upper_limit", "=", True),
("max_score", ">=", rec.min_score),
]
overlaps = self.search_count(domain)
if overlaps:
raise ValidationError(
_("Los rangos de puntuación no pueden solaparse.")
)
def name_get(self):
res = []
for r in self:
if r.no_upper_limit:
label = _("%s (%s+ pts)") % (r.name, r.min_score)
else:
label = _("%s (%s-%s pts)") % (r.name, r.min_score, r.max_score)
res.append((r.id, label))
return res

View file

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class SurveySurvey(models.Model):
_inherit = "survey.survey"
enable_score_ranges = fields.Boolean(
"Enable Score Ranges", help="Show a result page based on score ranges."
)
score_range_ids = fields.One2many(
"survey.score.range", "survey_id", string="Score Ranges"
)

View file

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
class SurveyUserInput(models.Model):
_inherit = "survey.user_input"
result_range_id = fields.Many2one(
"survey.score.range",
string="Score Range",
compute="_compute_result_range_id",
store=True,
compute_sudo=True,
)
result_range_html = fields.Html(
string="Result Range Content",
compute="_compute_result_range_html",
sanitize=False,
)
@api.depends(
"scoring_total", "survey_id.enable_score_ranges", "survey_id.score_range_ids"
)
def _compute_result_range_id(self):
for user_input in self:
selected = False
if user_input.survey_id.enable_score_ranges and user_input.state == "done":
total = user_input.scoring_total
ranges = user_input.survey_id.score_range_ids.filtered("active").sorted(
lambda r: r.min_score
)
for r in ranges:
if r.no_upper_limit:
if total >= r.min_score:
selected = r
else:
if total >= r.min_score and total <= r.max_score:
selected = r
if selected:
break
user_input.result_range_id = selected
@api.depends("result_range_id")
def _compute_result_range_html(self):
for user_input in self:
user_input.result_range_html = (
user_input.result_range_id.result_html
if user_input.result_range_id
else False
)