131 lines
5.8 KiB
Python
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')
|