diff --git a/backend/timed/tracking/serializers.py b/backend/timed/tracking/serializers.py index 56080bea6..b2603cf3a 100644 --- a/backend/timed/tracking/serializers.py +++ b/backend/timed/tracking/serializers.py @@ -2,7 +2,7 @@ from __future__ import annotations -from datetime import date, timedelta +from datetime import date, time, timedelta from typing import TYPE_CHECKING from django.contrib.auth import get_user_model @@ -108,8 +108,13 @@ def validate(self, data): from_time = data.get("from_time", instance and instance.from_time) to_time = data.get("to_time", instance and instance.to_time) - # validate that to is not before from - if to_time is not None and to_time < from_time: + if to_time == from_time: + raise ValidationError( + _("An attendance may not start and end at the same time.") + ) + + # allow attendances to end at midnight (00:00) + if to_time < from_time and to_time != time(0, 0): raise ValidationError(_("An attendance may not end before it starts.")) return data diff --git a/backend/timed/tracking/tests/test_attendance.py b/backend/timed/tracking/tests/test_attendance.py index 6636236b5..25fdc82fb 100644 --- a/backend/timed/tracking/tests/test_attendance.py +++ b/backend/timed/tracking/tests/test_attendance.py @@ -104,17 +104,47 @@ def test_attendance_delete(internal_employee_client): assert response.status_code == status.HTTP_204_NO_CONTENT -def test_attendance_to_before_from(internal_employee_client, attendance_factory): - """Test that to is not before from.""" - attendance = attendance_factory( - user=internal_employee_client.user, from_time=time(7, 30), to_time=time(8, 30) - ) +@pytest.mark.parametrize( + ( + "attendance__from_time", + "attendance__to_time", + "set_from_time", + "set_to_time", + "error", + ), + [ + (time(7, 30), time(8, 30), "07:30", "08:30", None), + (time(7, 30), time(8, 30), "07:30", "00:00", None), + ( + time(7, 30), + time(8, 30), + "07:30", + "07:00", + "An attendance may not end before it starts.", + ), + ( + time(7, 30), + time(8, 30), + "07:30", + "07:30", + "An attendance may not start and end at the same time.", + ), + ], +) +def test_attendance_validation( + internal_employee_client, attendance, set_from_time, set_to_time, error +): + attendance.user = internal_employee_client.user + attendance.save() data = { "data": { "type": "attendances", "id": attendance.id, - "attributes": {"to-time": "07:00"}, + "attributes": { + "to-time": set_to_time, + "from-time": set_from_time, + }, } } @@ -122,8 +152,9 @@ def test_attendance_to_before_from(internal_employee_client, attendance_factory) res = internal_employee_client.patch(url, data) - assert res.status_code == status.HTTP_400_BAD_REQUEST - json = res.json() - assert json["errors"][0]["detail"] == ( - "An attendance may not end before it starts." - ) + status_code = status.HTTP_400_BAD_REQUEST if error else status.HTTP_200_OK + assert res.status_code == status_code + + if error: + json = res.json() + assert json["errors"][0]["detail"] == error