Propagate "deducted" fields via API

This commit is contained in:
Daniel Egger 2024-05-21 16:56:04 +02:00
parent 7c4300f40c
commit f71e2e6ff3
7 changed files with 78 additions and 26 deletions

View File

@ -19,6 +19,7 @@ class AssignmentCompletionObjectType(DjangoObjectType):
# rounded to sensible representation
evaluation_points = graphene.Float()
evaluation_points_final = graphene.Float()
evaluation_max_points = graphene.Float()
class Meta:
@ -38,6 +39,9 @@ class AssignmentCompletionObjectType(DjangoObjectType):
"evaluation_user",
"additional_json_data",
"edoniq_extended_time_flag",
"evaluation_points_deducted",
"evaluation_points_deducted_reason",
"evaluation_points_deducted_user",
"evaluation_passed",
"task_completion_data",
)
@ -47,6 +51,11 @@ class AssignmentCompletionObjectType(DjangoObjectType):
return round(self.evaluation_points, 1) # noqa
return None
def resolve_evaluation_points_final(self, info):
if self.evaluation_points:
return round(self.evaluation_points_final, 1) # noqa
return None
def resolve_evaluation_max_points(self, info):
if self.evaluation_max_points:
return round(self.evaluation_max_points, 1) # noqa

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.20 on 2024-05-21 13:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assignment', '0013_assignment_competence_certificate_weight'),
]
operations = [
migrations.AddField(
model_name='assignmentcompletion',
name='evaluation_points_deducted',
field=models.FloatField(default=0.0, verbose_name='Punkteabzug'),
),
]

View File

@ -0,0 +1,31 @@
# Generated by Django 3.2.20 on 2024-05-21 14:52
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('assignment', '0013_assignment_competence_certificate_weight'),
]
operations = [
migrations.AddField(
model_name='assignmentcompletion',
name='evaluation_points_deducted',
field=models.FloatField(default=0.0, verbose_name='Punkteabzug'),
),
migrations.AddField(
model_name='assignmentcompletion',
name='evaluation_points_deducted_reason',
field=models.TextField(blank=True, default='', verbose_name='Punkteabzug Begründung'),
),
migrations.AddField(
model_name='assignmentcompletion',
name='evaluation_points_deducted_user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -343,14 +343,26 @@ class AssignmentCompletion(models.Model):
evaluation_points_deducted = models.FloatField(
default=0.0, verbose_name="Punkteabzug"
)
evaluation_points_deducted_reason = models.TextField(
default="", blank=True, verbose_name="Punkteabzug Begründung"
)
evaluation_points_deducted_user = models.ForeignKey(
User,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="+",
)
evaluation_max_points = models.FloatField(null=True, blank=True)
evaluation_passed = models.BooleanField(null=True, blank=True)
edoniq_extended_time_flag = models.BooleanField(default=False)
@property
def evaluation_points_final(self):
# with Django>=5 it can be replaced with a `GeneratedField`
return (self.evaluation_points or 0.0) - self.evaluation_points_deducted
if self.evaluation_points is None:
return None
return self.evaluation_points - self.evaluation_points_deducted
assignment_user = models.ForeignKey(User, on_delete=models.CASCADE)
assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE)
@ -399,6 +411,14 @@ class AssignmentCompletion(models.Model):
data[task.id] = get_task_data(task, self.completion_data)
return data
def save(
self,
**kwargs,
):
if self.evaluation_points_deducted > 0:
recalculate_assignment_passed(self)
super().save(**kwargs)
def get_file_info(file_id):
file_info = UploadFile.objects.filter(id=file_id).first()
@ -456,3 +476,13 @@ class AssignmentCompletionAuditLog(models.Model):
evaluation_points = models.FloatField(null=True, blank=True)
evaluation_max_points = models.FloatField(null=True, blank=True)
evaluation_passed = models.BooleanField(null=True, blank=True)
def recalculate_assignment_passed(ac: AssignmentCompletion):
if ac.evaluation_points_final is not None and ac.evaluation_max_points is not None:
# if more or equal than 55% of the points are reached, the assignment is passed
ac.evaluation_passed = (
ac.evaluation_points_final / ac.evaluation_max_points
) >= 0.55
return ac

View File

@ -21,6 +21,8 @@ class AssignmentCompletionSerializer(serializers.ModelSerializer):
"evaluation_user",
"additional_json_data",
"evaluation_points",
"evaluation_points_deducted",
"evaluation_points_deducted_reason",
"evaluation_max_points",
"evaluation_passed",
]

View File

@ -10,7 +10,7 @@ from vbv_lernwelt.assignment.models import (
AssignmentCompletionAuditLog,
AssignmentCompletionStatus,
AssignmentType,
is_valid_assignment_completion_status,
is_valid_assignment_completion_status, recalculate_assignment_passed,
)
from vbv_lernwelt.core.models import User
from vbv_lernwelt.core.utils import find_first
@ -146,11 +146,7 @@ def update_assignment_completion(
# if no evaluation_passed is provided, we calculate it from the points
if evaluation_passed is None and ac.evaluation_max_points > 0:
if evaluation_points is not None and ac.evaluation_max_points is not None:
# if more or equal than 60% of the points are reached, the assignment is passed
ac.evaluation_passed = (
evaluation_points / ac.evaluation_max_points
) >= 0.55
recalculate_assignment_passed(ac)
else:
ac.evaluation_passed = evaluation_passed

View File

@ -403,6 +403,7 @@ def create_test_assignment_evaluation_data(
# take the last input score as deduction if there is one left...
if points_deducted > 0:
ac.evaluation_points_deducted = points_deducted
ac.evaluation_points_deducted_reason = "Assignment Punkteabug Test"
ac.save()
@ -433,6 +434,7 @@ def create_edoniq_test_result_data(
if evaluation_points_deducted > 0:
ac.evaluation_points_deducted = evaluation_points_deducted
ac.evaluation_points_deducted_reason = "Edoniq Punkteabug Test"
ac.save()