survey_disc_test/models/survey_user_input.py

131 lines
5.8 KiB
Python

from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
class SurveyUserInput(models.Model):
_inherit = 'survey.user_input'
# MOST (Graph 1)
p_d = fields.Integer('P: D', compute='_compute_disc_scores', store=True)
p_i = fields.Integer('P: I', compute='_compute_disc_scores', store=True)
p_s = fields.Integer('P: S', compute='_compute_disc_scores', store=True)
p_c = fields.Integer('P: C', compute='_compute_disc_scores', store=True)
p_star = fields.Integer('P: *', compute='_compute_disc_scores', store=True)
# LEAST (Graph 2)
k_d = fields.Integer('K: D', compute='_compute_disc_scores', store=True)
k_i = fields.Integer('K: I', compute='_compute_disc_scores', store=True)
k_s = fields.Integer('K: S', compute='_compute_disc_scores', store=True)
k_c = fields.Integer('K: C', compute='_compute_disc_scores', store=True)
k_star = fields.Integer('K: *', compute='_compute_disc_scores', store=True)
# CHANGE (Graph 3)
c_d = fields.Integer('C: D', compute='_compute_disc_scores', store=True)
c_i = fields.Integer('C: I', compute='_compute_disc_scores', store=True)
c_s = fields.Integer('C: S', compute='_compute_disc_scores', store=True)
c_c = fields.Integer('C: C', compute='_compute_disc_scores', store=True)
disc_profile = fields.Char('DISC Profile', compute='_compute_disc_scores', store=True)
def _mark_done(self):
""" Strictly enforce DISC validation: Exactly 1 P and 1 K per set. """
for rec in self:
if not rec.survey_id.is_disc_test:
continue
# Group lines by question
lines_by_question = {}
for line in rec.user_input_line_ids:
if not line.matrix_row_id or not line.suggested_answer_id:
continue
q_id = line.question_id
if q_id not in lines_by_question:
lines_by_question[q_id] = []
lines_by_question[q_id].append(line)
# We expect 24 sets
if len(lines_by_question) < 24:
raise ValidationError(_("You must answer all 24 sets of the assessment."))
for q_id, lines in lines_by_question.items():
p_count = len([l for l in lines if l.suggested_answer_id.value == 'P'])
k_count = len([l for l in lines if l.suggested_answer_id.value == 'K'])
if p_count != 1 or k_count != 1:
raise ValidationError(
_("Invalid selection in '%s'. You must select exactly one 'P' (Most) and one 'K' (Least).") % q_id.title
)
return super(SurveyUserInput, self)._mark_done()
@api.depends('user_input_line_ids', 'user_input_line_ids.suggested_answer_id')
def _compute_disc_scores(self):
for rec in self:
if not rec.survey_id.is_disc_test:
rec.p_d = rec.p_i = rec.p_s = rec.p_c = rec.p_star = 0
rec.k_d = rec.k_i = rec.k_s = rec.k_c = rec.k_star = 0
rec.c_d = rec.c_i = rec.c_s = rec.c_c = 0
rec.disc_profile = False
continue
# Initialize counts
counts = {
'p': {'D': 0, 'I': 0, 'S': 0, 'C': 0, '*': 0},
'k': {'D': 0, 'I': 0, 'S': 0, 'C': 0, '*': 0}
}
# Group lines by question to check for multiple selections per set
lines_by_question = {}
for line in rec.user_input_line_ids:
if not line.matrix_row_id or not line.suggested_answer_id:
continue
q_id = line.question_id.id
if q_id not in lines_by_question:
lines_by_question[q_id] = []
lines_by_question[q_id].append(line)
# Process each question set
for q_id, lines in lines_by_question.items():
p_selections = [l for l in lines if l.suggested_answer_id.value == 'P']
k_selections = [l for l in lines if l.suggested_answer_id.value == 'K']
# Validation: We only count if exactly one P and one K are selected per set
# This enforces the "1 P and 1 K per set" rule
if len(p_selections) == 1:
line = p_selections[0]
cat = line.matrix_row_id.disc_category_p
if cat in counts['p']:
counts['p'][cat] += 1
if len(k_selections) == 1:
line = k_selections[0]
cat = line.matrix_row_id.disc_category_k
if cat in counts['k']:
counts['k'][cat] += 1
# Update fields
rec.p_d = counts['p']['D']
rec.p_i = counts['p']['I']
rec.p_s = counts['p']['S']
rec.p_c = counts['p']['C']
rec.p_star = counts['p']['*']
rec.k_d = counts['k']['D']
rec.k_i = counts['k']['I']
rec.k_s = counts['k']['S']
rec.k_c = counts['k']['C']
rec.k_star = counts['k']['*']
# Graph 3: Change (P - K)
rec.c_d = rec.p_d - rec.k_d
rec.c_i = rec.p_i - rec.k_i
rec.c_s = rec.p_s - rec.k_s
rec.c_c = rec.p_c - rec.k_c
# Determine Profile (based on highest score in Graph 3)
scores = {'D': rec.c_d, 'I': rec.c_i, 'S': rec.c_s, 'C': rec.c_c}
top_trait = max(scores, key=scores.get)
profile_map = {
'D': 'Director (Dominance)',
'I': 'Influencer (Influence)',
'S': 'Steady (Steadiness)',
'C': 'Compliant (Compliance)'
}
rec.disc_profile = profile_map.get(top_trait, 'Mixed')