feat(appointment): enforce booking window in slot calculation
buildAllSessions now rejects dates that are in the past, beyond the doctor's booking window (today + value week|month), or when online booking is disabled — gating overrides and weekly schedule alike. Add a public hasAnyAvailability() for the month-availability endpoint. Window config is read from the schedule meta, falling back to defaults. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ use App\Appointment\Repository\AppointmentRepository;
|
||||
use App\Appointment\Repository\DateOverrideRepository;
|
||||
use App\Appointment\Repository\HolidayRepository;
|
||||
use App\Appointment\Repository\WeeklyScheduleRepository;
|
||||
use App\Appointment\Entity\WeeklySchedule;
|
||||
use App\Doctor\Entity\Doctor;
|
||||
|
||||
|
||||
@@ -50,6 +51,44 @@ class SlotCalculatorService
|
||||
], $sessions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a doctor has at least one slot on the given date.
|
||||
* Lightweight check for the month-availability endpoint.
|
||||
*/
|
||||
public function hasAnyAvailability(Doctor $doctor, string $date): bool
|
||||
{
|
||||
return !empty($this->buildAllSessions($doctor, $date));
|
||||
}
|
||||
|
||||
/**
|
||||
* Booking is allowed only when online booking is enabled and the date is
|
||||
* today..(today + window). Past dates are always rejected.
|
||||
*/
|
||||
private function isWithinBookingWindow(Doctor $doctor, int $dayStart): bool
|
||||
{
|
||||
$todayStart = (int) strtotime('today 00:00:00');
|
||||
if ($dayStart < $todayStart) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$meta = $this->getBookingMeta($doctor);
|
||||
if (!($meta['online_booking_enabled'] ?? true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = max(1, (int)($meta['booking_window_value'] ?? 1));
|
||||
$unit = ($meta['booking_window_unit'] ?? 'month') === 'week' ? 'week' : 'month';
|
||||
$maxStart = (int) strtotime("today +{$value} {$unit} 00:00:00");
|
||||
|
||||
return $dayStart <= $maxStart;
|
||||
}
|
||||
|
||||
private function getBookingMeta(Doctor $doctor): array
|
||||
{
|
||||
$schedule = $this->scheduleRepo->findByDoctor($doctor);
|
||||
return $schedule ? $schedule->getMeta() : WeeklySchedule::DEFAULT_META;
|
||||
}
|
||||
|
||||
/**
|
||||
* Core: build all sessions with their slots, grouped by shift.
|
||||
*
|
||||
@@ -60,6 +99,11 @@ class SlotCalculatorService
|
||||
$dayStart = (int) strtotime($date . ' 00:00:00');
|
||||
$dayEnd = $dayStart + 86400;
|
||||
|
||||
// 0. Online booking disabled or date outside the booking window
|
||||
if (!$this->isWithinBookingWindow($doctor, $dayStart)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 1. Blocked by holiday
|
||||
if (!empty($this->holidayRepo->findActiveByDoctor($doctor, $dayStart, $dayEnd - 1))) {
|
||||
return [];
|
||||
|
||||
Reference in New Issue
Block a user