feat: add PublicResourceBookingController and PublicResourceBookingService for public booking functionality
- Implemented PublicResourceBookingController to handle public resource booking requests. - Added methods for retrieving bookable resources, available slots, and month availability. - Created PublicResourceBookingService to manage public resource offerings and service visibility. - Developed tests for public resource booking to ensure correct functionality and error handling.
This commit is contained in:
@@ -52,6 +52,8 @@ class AppointmentController extends BaseController
|
||||
private readonly \App\Appointment\Service\ServiceBookingCalculator $serviceCalculator,
|
||||
private readonly \App\Appointment\Service\ServiceRescheduleService $rescheduleService,
|
||||
private readonly \App\Appointment\Availability\Service\ResourceOccupier $occupier,
|
||||
private readonly \App\Resource\Service\ResourceBookingSlotService $resourceSlots,
|
||||
private readonly \App\Resource\Service\PublicResourceBookingService $publicResources,
|
||||
private readonly \App\Treatment\Service\SessionBookingLink $sessionLink,
|
||||
private readonly \Psr\Log\LoggerInterface $logger,
|
||||
) {}
|
||||
@@ -523,6 +525,22 @@ class AppointmentController extends BaseController
|
||||
|
||||
$bookingClinic = $this->bookingClinic($doctor, $clinicUuid);
|
||||
|
||||
if ($resource !== null) {
|
||||
/**
|
||||
* منبع با uuid از بدنهٔ درخواست میآید و `TenantFilter` پوششش نمیدهد، پس
|
||||
* بدون این بررسی بیمار میتوانست دستگاه کلینیک دیگری را روی نوبت این کلینیک
|
||||
* بنشاند.
|
||||
*
|
||||
* پیش از محاسبهٔ مدت میآید تا منبعِ بیگانه همان «منبع یافت نشد» را بگیرد، نه
|
||||
* خطای ریزترِ سرویس را.
|
||||
*/
|
||||
[$bookingType, $bookingId] = EntityContext::forBooking($doctor, $bookingClinic)->toEntityPair();
|
||||
|
||||
if ($resource->getEntityType() !== $bookingType || $resource->getEntityId() !== $bookingId) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_002, 'منبع یافت نشد', 422, 'resource_uuid');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* مدت از {@see ServiceBookingCalculator} میآید، نه از جمعِ دستیِ `duration_minutes`.
|
||||
*
|
||||
@@ -531,25 +549,25 @@ class AppointmentController extends BaseController
|
||||
* میکرد که سرور جای دیگری آزاد حساب کرده بود. calculator خودش هم مالکیت محیط را
|
||||
* میسنجد (همان بررسیای که قبلاً جداگانه صدا زده میشد) و خطاهایش همان کد و پیام
|
||||
* قبلی را دارند.
|
||||
*
|
||||
* **استثنای منبع:** وقتی منبع همهٔ این سرویسها را عمومی ارائه میدهد، مدت از
|
||||
* زنجیرهٔ حلِ خودِ منبع میآید ({@see ResourceServiceResolver}) — همان عددی که
|
||||
* `appointment-resource-slots` با آن زمانها را ساخته. وگرنه `slot_end` با اسلاتی
|
||||
* که به بیمار نشان داده شد یکی نمیشد.
|
||||
*
|
||||
* شرطی است و نه همیشگی: محیطی که هنوز رابطههای منبع↔سرویس را پر نکرده باید مثل
|
||||
* قبل کار کند.
|
||||
*/
|
||||
$duration = null;
|
||||
if ($hasServices) {
|
||||
$duration = $this->serviceCalculator->calculate($doctor, $bookingClinic, $serviceUuids);
|
||||
$slotEnd = $duration->endFor($slotStart);
|
||||
$duration = $resource !== null && $this->publicResources->offersAllPublicly($resource, $serviceUuids)
|
||||
? $this->resourceDuration($resource, $serviceUuids)
|
||||
: $this->serviceCalculator->calculate($doctor, $bookingClinic, $serviceUuids);
|
||||
|
||||
$slotEnd = $duration->endFor($slotStart);
|
||||
}
|
||||
|
||||
if ($resource !== null) {
|
||||
/**
|
||||
* منبع با uuid از بدنهٔ درخواست میآید و `TenantFilter` پوششش نمیدهد، پس
|
||||
* بدون این بررسی بیمار میتوانست دستگاه کلینیک دیگری را روی نوبت این کلینیک
|
||||
* بنشاند.
|
||||
*/
|
||||
[$bookingType, $bookingId] = EntityContext::forBooking($doctor, $bookingClinic)->toEntityPair();
|
||||
|
||||
if ($resource->getEntityType() !== $bookingType || $resource->getEntityId() !== $bookingId) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_002, 'منبع یافت نشد', 422, 'resource_uuid');
|
||||
}
|
||||
|
||||
/**
|
||||
* منبعی که این سرویس را نمیدهد، همینجا رد میشود نه وقتی بیمار سرِ قرار
|
||||
* حاضر شده. روی `serviceItems`ِ خروجی calculator کار میکند نه uuidهای خام:
|
||||
@@ -898,6 +916,27 @@ class AppointmentController extends BaseController
|
||||
return $this->bookingContext->resolve($doctor, $clinicUuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* مدتِ نوبت روی یک منبع، در قالبِ همان VOیی که مسیر پزشکمحور تولید میکند.
|
||||
*
|
||||
* همشکلکردنشان عمدی است: پاییندستِ این نقطه (`replaceServiceItems`،
|
||||
* `setServiceDuration`، `endFor`) دیگر نمیداند نوبت منبعدار است یا نه، و شاخهٔ
|
||||
* دومی برای نگهداری ندارد.
|
||||
*
|
||||
* بافر صفر است چون `ResourceBookingSlotService::startTimes()` زمانها را پشتسرهم و
|
||||
* بدون بافر میچیند؛ عددِ دیگری اینجا یعنی واگرایی با همان اسلاتها.
|
||||
*
|
||||
* @param list<string> $serviceUuids
|
||||
*/
|
||||
private function resourceDuration(
|
||||
\App\Resource\Entity\ClinicResource $resource,
|
||||
array $serviceUuids,
|
||||
): \App\Appointment\ValueObject\ServiceBookingDuration {
|
||||
['minutes' => $minutes, 'items' => $items] = $this->resourceSlots->resolveDuration($resource, $serviceUuids);
|
||||
|
||||
return new \App\Appointment\ValueObject\ServiceBookingDuration($minutes, 0, $items);
|
||||
}
|
||||
|
||||
/**
|
||||
* آیا این درخواستِ اسلات از پنل مدیریت است (پزشک/منشی/ادمینِ دارای دسترسی)؟
|
||||
* اندپوینتهای اسلات عمومیاند؛ فقط با management=1 + کاربرِ احرازشده و مجاز،
|
||||
|
||||
Reference in New Issue
Block a user