Exemplo n.º 1
0
def mark_attendance(request, **kwargs):
    serializer = AttendanceMarkSerializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    trainer = request.user  # trainer.pk == trainer.user.pk
    try:
        training = Training.objects.select_related("group").only(
            "group__trainer", "start",
            "end").get(pk=serializer.validated_data["training_id"])
    except Training.DoesNotExist:
        raise NotFound()

    is_training_group(training.group, trainer)

    now = timezone.now()
    if not training.start <= now <= training.start + \
           settings.TRAINING_EDITABLE_INTERVAL:
        return Response(
            status=status.HTTP_400_BAD_REQUEST,
            data=error_detail(*AttendanceErrors.TRAINING_NOT_EDITABLE))

    id_to_hours = dict([(item["student_id"], item["hours"])
                        for item in serializer.validated_data["students_hours"]
                        ])

    max_hours = training.academic_duration
    students = User.objects.filter(pk__in=id_to_hours.keys()).only("email")

    hours_to_mark = []
    negative_mark = []
    overflow_mark = []

    for student in students:
        hours_put = id_to_hours[student.pk]
        if hours_put < 0:
            negative_mark.append(
                compose_bad_grade_report(student.email, hours_put))
        elif hours_put > max_hours:
            overflow_mark.append(
                compose_bad_grade_report(student.email, hours_put))
        else:
            hours_to_mark.append((student, hours_put))

    if negative_mark or overflow_mark:
        return Response(status=status.HTTP_400_BAD_REQUEST,
                        data={
                            **error_detail(*AttendanceErrors.OUTBOUND_GRADES),
                            "negative_marks":
                            negative_mark,
                            "overflow_marks":
                            overflow_mark,
                        })
    else:
        mark_data = [(x[0].pk, x[1]) for x in hours_to_mark]
        mark_hours(training, mark_data)
        return Response(
            list(
                map(lambda x: compose_bad_grade_report(x[0].email, x[1]),
                    hours_to_mark)))
def mark_attendance(
        training: Training,
        student_hours: Iterable[Tuple[User, float]],
):
    mark_hours(
        training,
        [
            (data[0].pk, data[1])
            for data in student_hours
        ]
    )
Exemplo n.º 3
0
 def save_related(self, request, form, formsets, change):
     """
     There are three ways of creating/changing attendance records (from highest priority to lowest):
     1) Upload CSV file
     2) Use ModelMultipleChoiceField in ModelAdmin for training
     3) Change/add attendance records using inline
     """
     super().save_related(request, form, formsets, change)
     training = form.instance
     similar_student_hours = [
         (student.pk, form.cleaned_data['hours'])
         for student in form.cleaned_data['attended_students']
     ]
     xlsx_student_hours = [
         (student.pk, hours)
         for (student, hours) in form.cleaned_data['attendances']
     ]
     mark_hours(training, OrderedDict(similar_student_hours + xlsx_student_hours).items())
     return training
Exemplo n.º 4
0
 def save_related(self, request, form, formsets, change):
     """
     There are three ways of creating/changing attendance records (from highest priority to lowest):
     1) Upload CSV file
     2) Use ModelMultipleChoiceField in ModelAdmin for training
     3) Change/add attendance records using inline
     """
     if 'add-extra-multi' in request.path:
         for attendance_form in formsets[0].forms:
             attendance_form.instance.student = form.cleaned_data['student']
             start = datetime.datetime.combine(
                 datetime.date.fromisoformat(
                     attendance_form['date'].value()),
                 datetime.time(0, 0, 0),
                 tzinfo=timezone.localtime().tzinfo)
             end = datetime.datetime.combine(
                 datetime.date.fromisoformat(
                     attendance_form['date'].value()),
                 datetime.time(23, 59, 59),
                 tzinfo=timezone.localtime().tzinfo)
             training = Training.objects.create(group=form.instance.group,
                                                start=start,
                                                end=end)
             attendance_form.instance.training = training
             training.save(False)
             attendance_form.instance.save(False)
         return None
     super().save_related(request, form, formsets, change)
     training = form.instance
     similar_student_hours = [
         (student.pk, form.cleaned_data['hours'])
         for student in form.cleaned_data['attended_students']
     ]
     xlsx_student_hours = [(student.pk, hours)
                           for (student,
                                hours) in form.cleaned_data['attendances']]
     mark_hours(
         training,
         OrderedDict(similar_student_hours + xlsx_student_hours).items())
     return training
def test_mark_hours(student_factory, sport_factory, semester_factory, group_factory, training_factory):
    student1 = student_factory("A").student
    student2 = student_factory("B").student
    sport = sport_factory(name="Sport")
    semester = semester_factory(name="S19", start=dummy_date, end=dummy_date)
    group = group_factory(name="G1", sport=sport, semester=semester, capacity=20)
    training = training_factory(group=group, start=timezone.now(), end=timezone.now())
    mark_hours(training, [
        (student1.pk, 1.5),
        (student2.pk, 2.5)
    ])
    attendance1 = Attendance.objects.get(student=student1)
    attendance2 = Attendance.objects.get(student=student2)
    assert attendance1.hours == 1.5
    assert attendance2.hours == 2.5
    mark_hours(training, [
        (student1.pk, 3.5),
        (student2.pk, 0)
    ])
    attendance1 = Attendance.objects.get(student=student1)
    assert attendance1.hours == 3.5
    assert Attendance.objects.count() == 1