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:
hamed
2026-08-09 10:45:51 +03:30
parent cd793489ef
commit cfeb447645
10 changed files with 1645 additions and 13 deletions
+108
View File
@@ -174,6 +174,114 @@ class BookForResourceTest extends ApiTestCase
self::assertSame('این منبع این سرویس را ارائه نمی‌دهد', $res['errors'][0]['message']);
}
/**
* مدتِ نوبت باید همان عددی باشد که `appointment-resource-slots` با آن زمان‌ها را
* ساخته — وگرنه بیمار وقتی را می‌گیرد که سرور جای دیگری آزاد حساب کرده بود.
*/
public function testTheLengthComesFromTheResourceOfferingNotTheServiceDefault(): void
{
[$clinic, $doctor, $address, $section] = $this->clinic();
$resource = $this->resource($clinic, $address, 'دستگاه لیزر', $doctor);
$service = $this->service($section, 'لیزر پا', 30); // پیش‌فرضِ سرویس
$offering = new ResourceServiceOffering($resource, $service);
$offering->setDurationMinutes(45); // مدتِ همین دستگاه
$this->em->persist($offering);
$this->em->flush();
[$res] = $this->book([
'doctor_uuid' => $doctor->getUuid(),
'clinic_uuid' => $clinic->getUuid(),
'resource_uuid' => $resource->getUuid(),
'service_item_uuids' => [$service->getUuid()],
]);
self::assertSame(201, $this->responseCode(), json_encode($res, JSON_UNESCAPED_UNICODE));
$row = $res['data']['data'];
self::assertSame(45 * 60, $row['slot_end'] - $row['slot_start']);
}
/**
* سازگاری عقب‌رو: محیطی که هنوز هیچ ردیفِ منبع↔سرویس نساخته باید مثل قبل کار کند —
* مدت از پیش‌فرضِ خودِ سرویس می‌آید و نوبت‌دهی‌اش قطع نمی‌شود.
*/
public function testWithoutAnyOfferingRowTheLengthStaysTheServiceDefault(): void
{
[$clinic, $doctor, $address, $section] = $this->clinic();
$resource = $this->resource($clinic, $address, 'دستگاه بدون رابطه', $doctor);
$service = $this->service($section, 'سرویس بدون رابطه', 30);
[$res] = $this->book([
'doctor_uuid' => $doctor->getUuid(),
'clinic_uuid' => $clinic->getUuid(),
'resource_uuid' => $resource->getUuid(),
'service_item_uuids' => [$service->getUuid()],
]);
self::assertSame(201, $this->responseCode(), json_encode($res, JSON_UNESCAPED_UNICODE));
$row = $res['data']['data'];
self::assertSame(30 * 60, $row['slot_end'] - $row['slot_start']);
}
/**
* ردیفِ **غیرفعال** فرق دارد و همان ۴۲۲ قبلی را می‌گیرد: «فعلاً این را نمی‌دهم»
* حرفِ صریحِ مالک است، نه سکوتِ محیطی که هنوز رابطه‌ها را پر نکرده.
*/
public function testAnInactiveOfferingStillRejectsTheBooking(): void
{
[$clinic, $doctor, $address, $section] = $this->clinic();
$resource = $this->resource($clinic, $address, 'دستگاه لیزر', $doctor);
$service = $this->service($section, 'لیزر پا', 30);
$offering = new ResourceServiceOffering($resource, $service);
$offering->setDurationMinutes(45)->setActive(false);
$this->em->persist($offering);
$this->em->flush();
[$res] = $this->book([
'doctor_uuid' => $doctor->getUuid(),
'clinic_uuid' => $clinic->getUuid(),
'resource_uuid' => $resource->getUuid(),
'service_item_uuids' => [$service->getUuid()],
]);
self::assertSame(422, $this->responseCode(), json_encode($res, JSON_UNESCAPED_UNICODE));
self::assertSame('این منبع این سرویس را ارائه نمی‌دهد', $res['errors'][0]['message']);
}
/**
* گیتِ «نمایش در نوبت‌دهی آنلاین» با منبع هم دور زده نمی‌شود: شاخهٔ منبع فقط وقتی
* فعال است که سرویس عمومی باشد، و در غیر این‌صورت همان ۴۲۲ مسیر پزشک‌محور می‌آید.
*/
public function testAServiceWithTheOnlineToggleOffIsStillRejectedOnAResource(): void
{
[$clinic, $doctor, $address, $section] = $this->clinic();
$resource = $this->resource($clinic, $address, 'دستگاه لیزر', $doctor);
$service = $this->service($section, 'لیزر پا', 30);
$service->setBookable(false);
$offering = new ResourceServiceOffering($resource, $service);
$offering->setDurationMinutes(45);
$this->em->persist($offering);
$this->em->flush();
[$res] = $this->book([
'doctor_uuid' => $doctor->getUuid(),
'clinic_uuid' => $clinic->getUuid(),
'resource_uuid' => $resource->getUuid(),
'service_item_uuids' => [$service->getUuid()],
]);
self::assertSame(422, $this->responseCode(), json_encode($res, JSON_UNESCAPED_UNICODE));
self::assertSame('این سرویس برای نوبت‌دهی فعال نیست', $res['errors'][0]['message']);
}
public function testAnUnknownResourceIsRejected(): void
{
$this->book(['resource_uuid' => '00000000-0000-4000-8000-000000000000']);