feat: Enhance appointment management by decoupling online booking toggle for admin context
- Introduced management mode for appointment slots, allowing doctors, admins, and clinic managers to view and book slots regardless of the online booking status. - Updated SlotCalculatorService to accept a management context parameter, bypassing online booking restrictions. - Modified appointment-related endpoints to handle management context and ensure proper authorization checks. - Added tests to verify that management users can access slots even when online booking is disabled, while public users are still restricted. - Improved documentation for API endpoints to reflect new management parameters and behaviors.
This commit is contained in:
@@ -158,8 +158,9 @@ class AppointmentController extends BaseController
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'فرمت تاریخ نادرست است (Y-m-d)', 422, 'date');
|
||||
}
|
||||
|
||||
$clinic = $this->bookingClinic($doctor, $request->query->get('clinic_uuid'));
|
||||
$sessions = $this->slotCalculator->getAllSlotsWithAvailability($doctor, $date, $clinic);
|
||||
$clinic = $this->bookingClinic($doctor, $request->query->get('clinic_uuid'));
|
||||
$forManagement = $this->isManagementContext($request, $doctor, $clinic);
|
||||
$sessions = $this->slotCalculator->getAllSlotsWithAvailability($doctor, $date, $clinic, $forManagement);
|
||||
|
||||
return $this->success([
|
||||
'doctor_uuid' => $doctorUuid,
|
||||
@@ -168,7 +169,7 @@ class AppointmentController extends BaseController
|
||||
'sessions' => $sessions,
|
||||
// خالیبودن دلایل مختلفی دارد؛ کلاینت نباید همه را «تعطیل» بنامد.
|
||||
'empty_reason' => $sessions === []
|
||||
? $this->slotCalculator->explainEmptyDay($doctor, $date, $clinic)
|
||||
? $this->slotCalculator->explainEmptyDay($doctor, $date, $clinic, $forManagement)
|
||||
: null,
|
||||
]);
|
||||
}
|
||||
@@ -234,7 +235,13 @@ class AppointmentController extends BaseController
|
||||
'total_duration_minutes' => $totalMinutes,
|
||||
'buffer_minutes' => (int) $meta['buffer_minutes'],
|
||||
'clinic_uuid' => $clinic?->getUuid(),
|
||||
'start_times' => $this->slotCalculator->getServiceStartTimes($doctor, $date, $totalMinutes, $clinic),
|
||||
'start_times' => $this->slotCalculator->getServiceStartTimes(
|
||||
$doctor,
|
||||
$date,
|
||||
$totalMinutes,
|
||||
$clinic,
|
||||
$this->isManagementContext($request, $doctor, $clinic),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -306,8 +313,9 @@ class AppointmentController extends BaseController
|
||||
continue;
|
||||
}
|
||||
|
||||
$meta = $schedule->getMeta();
|
||||
$address = $byId[$hours[0]['location_id']] ?? $addresses[0];
|
||||
$meta = $schedule->getMeta();
|
||||
$address = $byId[$hours[0]['location_id']] ?? $addresses[0];
|
||||
$forManagement = $this->isManagementContext($request, $doctor, $clinic);
|
||||
|
||||
$locations[] = [
|
||||
'location_uuid' => $address->getUuid(),
|
||||
@@ -321,10 +329,10 @@ class AppointmentController extends BaseController
|
||||
'services' => $meta['booking_mode'] === WeeklySchedule::MODE_SERVICE
|
||||
? $this->bookableServices($doctor, $clinic)
|
||||
: [],
|
||||
'next_available_at' => $this->slotCalculator->findNextAvailableStart($doctor, $clinic),
|
||||
'next_available_at' => $this->slotCalculator->findNextAvailableStart($doctor, $clinic, 30, $forManagement),
|
||||
'available_on_date' => $date === ''
|
||||
? null
|
||||
: $this->slotCalculator->getAvailableSlots($doctor, $date, $clinic) !== [],
|
||||
: $this->slotCalculator->getAvailableSlots($doctor, $date, $clinic, $forManagement) !== [],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -352,14 +360,15 @@ class AppointmentController extends BaseController
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'سال یا ماه نامعتبر است', 422, 'month');
|
||||
}
|
||||
|
||||
$clinic = $this->bookingClinic($doctor, $request->query->get('clinic_uuid'));
|
||||
$daysInMonth = (int) date('t', (int) strtotime(sprintf('%04d-%02d-01', $year, $month)));
|
||||
$clinic = $this->bookingClinic($doctor, $request->query->get('clinic_uuid'));
|
||||
$forManagement = $this->isManagementContext($request, $doctor, $clinic);
|
||||
$daysInMonth = (int) date('t', (int) strtotime(sprintf('%04d-%02d-01', $year, $month)));
|
||||
|
||||
$disabled = [];
|
||||
$enabled = [];
|
||||
for ($day = 1; $day <= $daysInMonth; $day++) {
|
||||
$date = sprintf('%04d-%02d-%02d', $year, $month, $day);
|
||||
if ($this->slotCalculator->hasAnyAvailability($doctor, $date, $clinic)) {
|
||||
if ($this->slotCalculator->hasAnyAvailability($doctor, $date, $clinic, $forManagement)) {
|
||||
$enabled[] = $date;
|
||||
} else {
|
||||
$disabled[] = $date;
|
||||
@@ -747,6 +756,25 @@ class AppointmentController extends BaseController
|
||||
return $this->bookingContext->resolve($doctor, $clinicUuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* آیا این درخواستِ اسلات از پنل مدیریت است (پزشک/منشی/ادمینِ دارای دسترسی)؟
|
||||
* اندپوینتهای اسلات عمومیاند؛ فقط با management=1 + کاربرِ احرازشده و مجاز،
|
||||
* توگلِ نوبتدهی آنلاین دور زده میشود. در غیر اینصورت مثل رزرو عمومی رفتار میشود
|
||||
* (fail-safe عمومی) تا اسلاتِ خاموش به بازدیدکنندهٔ سایت نشت نکند.
|
||||
*/
|
||||
private function isManagementContext(Request $request, Doctor $doctor, ?Clinic $clinic): bool
|
||||
{
|
||||
if ($request->query->get('management') !== '1') {
|
||||
return false;
|
||||
}
|
||||
$user = $this->getUser();
|
||||
if (!$user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->accessChecker->canManageContext($user, $doctor, $clinic);
|
||||
}
|
||||
|
||||
private function assertServicesMatchContext(array $serviceUuids, Doctor $doctor, ?Clinic $clinic): ?JsonResponse
|
||||
{
|
||||
[$type, $id] = $clinic !== null
|
||||
|
||||
Reference in New Issue
Block a user