50 lines
1.9 KiB
Python
50 lines
1.9 KiB
Python
from datetime import timedelta
|
|
|
|
from django.utils import timezone
|
|
from django.utils.translation import gettext_lazy as _
|
|
from rest_framework import serializers
|
|
|
|
from apps.bookings.models import Booking, BookingStatus
|
|
from apps.salons.models import StaffAvailability, StaffProfile
|
|
|
|
|
|
def validate_booking_request(service, staff, start_time, end_time):
|
|
if staff is None:
|
|
raise serializers.ValidationError({"staff": _("Staff is required for booking")})
|
|
|
|
if isinstance(staff, StaffProfile) and staff.salon_id != service.salon_id:
|
|
raise serializers.ValidationError({"staff": _("Selected staff does not belong to this salon")})
|
|
|
|
if start_time >= end_time:
|
|
raise serializers.ValidationError({"end_time": _("End time must be after start time")})
|
|
|
|
expected_end = start_time + timedelta(minutes=service.duration_minutes)
|
|
if expected_end != end_time:
|
|
raise serializers.ValidationError({"end_time": _("End time must match service duration")})
|
|
|
|
start_local = timezone.localtime(start_time)
|
|
end_local = timezone.localtime(end_time)
|
|
|
|
availability_qs = StaffAvailability.objects.filter(
|
|
staff=staff,
|
|
day_of_week=start_local.weekday(),
|
|
is_active=True,
|
|
)
|
|
|
|
if availability_qs.exists():
|
|
within_window = availability_qs.filter(
|
|
start_time__lte=start_local.time(),
|
|
end_time__gte=end_local.time(),
|
|
).exists()
|
|
if not within_window:
|
|
raise serializers.ValidationError({"start_time": _("Booking is outside staff availability")})
|
|
|
|
overlap_exists = Booking.objects.filter(
|
|
staff=staff,
|
|
status__in=[BookingStatus.PENDING, BookingStatus.CONFIRMED],
|
|
start_time__lt=end_time,
|
|
end_time__gt=start_time,
|
|
).exists()
|
|
if overlap_exists:
|
|
raise serializers.ValidationError({"start_time": _("Booking overlaps an existing appointment")})
|