79 lines
3.2 KiB
Python
79 lines
3.2 KiB
Python
"""Player evaluation record."""
|
|
|
|
from app.extensions import db
|
|
from app.time_utils import utc_now_naive
|
|
|
|
|
|
class Evaluation(db.Model):
|
|
"""Player evaluation record."""
|
|
|
|
__tablename__ = 'evaluations'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
tryout_id = db.Column(db.Integer, db.ForeignKey('tryouts.id'), nullable=False)
|
|
player_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
|
evaluator_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
|
mecanics_score = db.Column(db.Integer, nullable=True)
|
|
cohesion_score = db.Column(db.Integer, nullable=True)
|
|
communication_score = db.Column(db.Integer, nullable=True)
|
|
gamesense_score = db.Column(db.Integer, nullable=True)
|
|
versatility_score = db.Column(db.Integer, nullable=True)
|
|
discipline_score = db.Column(db.Integer, nullable=True)
|
|
analysis_score = db.Column(db.Integer, nullable=True)
|
|
sport_ethics_score = db.Column(db.Integer, nullable=True)
|
|
mental_score = db.Column(db.Integer, nullable=True)
|
|
overall_score = db.Column(db.Float, nullable=True)
|
|
comments = db.Column(db.Text, nullable=True)
|
|
position_recommendation = db.Column(db.String(50), nullable=True)
|
|
created_at = db.Column(db.DateTime, default=utc_now_naive)
|
|
updated_at = db.Column(db.DateTime, default=utc_now_naive, onupdate=utc_now_naive)
|
|
|
|
__table_args__ = (
|
|
db.UniqueConstraint('tryout_id', 'player_id', 'evaluator_id', name='unique_evaluation'),
|
|
)
|
|
|
|
#: The nine criteria, in the order the form shows them. The overall score
|
|
#: is their mean; a criterion left blank is left out of the mean rather
|
|
#: than counted as a zero, which is why this list exists rather than the
|
|
#: route summing nine named variables (ARCH-005, QUA-003).
|
|
CRITERIA = (
|
|
'mecanics_score',
|
|
'cohesion_score',
|
|
'communication_score',
|
|
'gamesense_score',
|
|
'versatility_score',
|
|
'discipline_score',
|
|
'analysis_score',
|
|
'sport_ethics_score',
|
|
'mental_score',
|
|
)
|
|
|
|
@classmethod
|
|
def overall_from(cls, scores):
|
|
"""Mean of the criteria that were actually filled in.
|
|
|
|
Args:
|
|
scores: Mapping of criterion name to score or None.
|
|
|
|
Returns:
|
|
float | None: None when nothing was scored — which is not the
|
|
same as zero, and must not become one. A player nobody could
|
|
assess has no overall score; a player who scored zero on
|
|
everything cannot exist, the scale starts at one.
|
|
"""
|
|
given = [scores.get(name) for name in cls.CRITERIA]
|
|
given = [score for score in given if score is not None]
|
|
if not given:
|
|
return None
|
|
return sum(given) / len(given)
|
|
|
|
def apply_scores(self, scores):
|
|
"""Write these criteria onto the record and recompute the overall.
|
|
|
|
Every criterion is assigned, including the ones left blank: an edit
|
|
that clears a score has to clear it, and the mean has to be the mean
|
|
of what is on the record afterwards.
|
|
"""
|
|
for name in self.CRITERIA:
|
|
setattr(self, name, scores.get(name))
|
|
self.overall_score = self.overall_from(scores)
|