Propagate "deducted" fields via API
This commit is contained in:
parent
7c4300f40c
commit
f71e2e6ff3
|
|
@ -19,6 +19,7 @@ class AssignmentCompletionObjectType(DjangoObjectType):
|
||||||
|
|
||||||
# rounded to sensible representation
|
# rounded to sensible representation
|
||||||
evaluation_points = graphene.Float()
|
evaluation_points = graphene.Float()
|
||||||
|
evaluation_points_final = graphene.Float()
|
||||||
evaluation_max_points = graphene.Float()
|
evaluation_max_points = graphene.Float()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -38,6 +39,9 @@ class AssignmentCompletionObjectType(DjangoObjectType):
|
||||||
"evaluation_user",
|
"evaluation_user",
|
||||||
"additional_json_data",
|
"additional_json_data",
|
||||||
"edoniq_extended_time_flag",
|
"edoniq_extended_time_flag",
|
||||||
|
"evaluation_points_deducted",
|
||||||
|
"evaluation_points_deducted_reason",
|
||||||
|
"evaluation_points_deducted_user",
|
||||||
"evaluation_passed",
|
"evaluation_passed",
|
||||||
"task_completion_data",
|
"task_completion_data",
|
||||||
)
|
)
|
||||||
|
|
@ -47,6 +51,11 @@ class AssignmentCompletionObjectType(DjangoObjectType):
|
||||||
return round(self.evaluation_points, 1) # noqa
|
return round(self.evaluation_points, 1) # noqa
|
||||||
return None
|
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):
|
def resolve_evaluation_max_points(self, info):
|
||||||
if self.evaluation_max_points:
|
if self.evaluation_max_points:
|
||||||
return round(self.evaluation_max_points, 1) # noqa
|
return round(self.evaluation_max_points, 1) # noqa
|
||||||
|
|
|
||||||
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -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),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -343,14 +343,26 @@ class AssignmentCompletion(models.Model):
|
||||||
evaluation_points_deducted = models.FloatField(
|
evaluation_points_deducted = models.FloatField(
|
||||||
default=0.0, verbose_name="Punkteabzug"
|
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_max_points = models.FloatField(null=True, blank=True)
|
||||||
evaluation_passed = models.BooleanField(null=True, blank=True)
|
evaluation_passed = models.BooleanField(null=True, blank=True)
|
||||||
edoniq_extended_time_flag = models.BooleanField(default=False)
|
edoniq_extended_time_flag = models.BooleanField(default=False)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def evaluation_points_final(self):
|
def evaluation_points_final(self):
|
||||||
# with Django>=5 it can be replaced with a `GeneratedField`
|
if self.evaluation_points is None:
|
||||||
return (self.evaluation_points or 0.0) - self.evaluation_points_deducted
|
return None
|
||||||
|
return self.evaluation_points - self.evaluation_points_deducted
|
||||||
|
|
||||||
assignment_user = models.ForeignKey(User, on_delete=models.CASCADE)
|
assignment_user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
assignment = models.ForeignKey(Assignment, 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)
|
data[task.id] = get_task_data(task, self.completion_data)
|
||||||
return 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):
|
def get_file_info(file_id):
|
||||||
file_info = UploadFile.objects.filter(id=file_id).first()
|
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_points = models.FloatField(null=True, blank=True)
|
||||||
evaluation_max_points = models.FloatField(null=True, blank=True)
|
evaluation_max_points = models.FloatField(null=True, blank=True)
|
||||||
evaluation_passed = models.BooleanField(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
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ class AssignmentCompletionSerializer(serializers.ModelSerializer):
|
||||||
"evaluation_user",
|
"evaluation_user",
|
||||||
"additional_json_data",
|
"additional_json_data",
|
||||||
"evaluation_points",
|
"evaluation_points",
|
||||||
|
"evaluation_points_deducted",
|
||||||
|
"evaluation_points_deducted_reason",
|
||||||
"evaluation_max_points",
|
"evaluation_max_points",
|
||||||
"evaluation_passed",
|
"evaluation_passed",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ from vbv_lernwelt.assignment.models import (
|
||||||
AssignmentCompletionAuditLog,
|
AssignmentCompletionAuditLog,
|
||||||
AssignmentCompletionStatus,
|
AssignmentCompletionStatus,
|
||||||
AssignmentType,
|
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.models import User
|
||||||
from vbv_lernwelt.core.utils import find_first
|
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 no evaluation_passed is provided, we calculate it from the points
|
||||||
if evaluation_passed is None and ac.evaluation_max_points > 0:
|
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:
|
recalculate_assignment_passed(ac)
|
||||||
# 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
|
|
||||||
else:
|
else:
|
||||||
ac.evaluation_passed = evaluation_passed
|
ac.evaluation_passed = evaluation_passed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -403,6 +403,7 @@ def create_test_assignment_evaluation_data(
|
||||||
# take the last input score as deduction if there is one left...
|
# take the last input score as deduction if there is one left...
|
||||||
if points_deducted > 0:
|
if points_deducted > 0:
|
||||||
ac.evaluation_points_deducted = points_deducted
|
ac.evaluation_points_deducted = points_deducted
|
||||||
|
ac.evaluation_points_deducted_reason = "Assignment Punkteabug Test"
|
||||||
ac.save()
|
ac.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -433,6 +434,7 @@ def create_edoniq_test_result_data(
|
||||||
|
|
||||||
if evaluation_points_deducted > 0:
|
if evaluation_points_deducted > 0:
|
||||||
ac.evaluation_points_deducted = evaluation_points_deducted
|
ac.evaluation_points_deducted = evaluation_points_deducted
|
||||||
|
ac.evaluation_points_deducted_reason = "Edoniq Punkteabug Test"
|
||||||
ac.save()
|
ac.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue