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:
@@ -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']);
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Resource;
|
||||
|
||||
use App\ClinicService\Entity\ServiceItem;
|
||||
use App\ClinicService\Entity\ServiceSection;
|
||||
use App\Doctor\Entity\Doctor;
|
||||
use App\Doctor\Entity\DoctorAddress;
|
||||
use App\Resource\Entity\ClinicResource;
|
||||
use App\Resource\Entity\ResourceCalendar;
|
||||
use App\Resource\Entity\ResourceServiceOffering;
|
||||
|
||||
/**
|
||||
* نوبتدهی منبعمحور از **سایت عمومی** — بدون هیچ توکنی.
|
||||
*
|
||||
* تا پیش از این، منابع و سرویسهایشان فقط از داخل پنل دیده میشدند، پس تیکِ «نمایش در
|
||||
* نوبتدهی آنلاین» روی سرویسِ یک دستگاه هیچ اثری در سایت نداشت.
|
||||
*/
|
||||
class PublicResourceBookingTest extends ResourceTestCase
|
||||
{
|
||||
/** @return array{0: Doctor, 1: DoctorAddress, 2: ClinicResource} */
|
||||
private function doctorWithResource(): array
|
||||
{
|
||||
[, $doctor, $address] = $this->doctorWithAddress();
|
||||
|
||||
$resource = new ClinicResource($address, $this->resourceType($address), 'لیزر CO2');
|
||||
$resource->setSupervisor($doctor);
|
||||
$this->em->persist($resource);
|
||||
$this->em->flush();
|
||||
|
||||
return [$doctor, $address, $resource];
|
||||
}
|
||||
|
||||
private function service(DoctorAddress $address, string $name, bool $bookable = true): ServiceItem
|
||||
{
|
||||
$section = new ServiceSection($address->tenantEntityType(), $address->tenantEntityId(), 'بخش ' . $name);
|
||||
$this->em->persist($section);
|
||||
|
||||
$item = new ServiceItem($section, $name, 5_000_000);
|
||||
$item->setDurationMinutes(30)->setBookable($bookable);
|
||||
$this->em->persist($item);
|
||||
$this->em->flush();
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
private function offer(ClinicResource $resource, ServiceItem $item, ?int $minutes = null, bool $active = true): ResourceServiceOffering
|
||||
{
|
||||
$offering = new ResourceServiceOffering($resource, $item);
|
||||
$offering->setDurationMinutes($minutes)->setActive($active);
|
||||
$this->em->persist($offering);
|
||||
$this->em->flush();
|
||||
|
||||
return $offering;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> درخواستِ ناشناس، دقیقاً مثل بازدیدکنندهٔ سایت */
|
||||
private function publicJson(string $uri): array
|
||||
{
|
||||
$this->client->request('GET', $uri);
|
||||
|
||||
return json_decode($this->client->getResponse()->getContent(), true) ?? [];
|
||||
}
|
||||
|
||||
private function resourcesUri(Doctor $doctor): string
|
||||
{
|
||||
return '/api/v1/appointment-booking-resources/' . $doctor->getUuid();
|
||||
}
|
||||
|
||||
/** شیفت ۰۹:۰۰ تا ۱۷:۰۰ روی همان روزِ هفتهای که تست رویش نوبت میگیرد. */
|
||||
private function shift(ClinicResource $resource): void
|
||||
{
|
||||
$this->em->persist(new ResourceCalendar($resource, $this->dayOfWeek($this->midnight()), 540, 1020));
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
/** فردا انتخاب میشود تا «زمانِ گذشته» نتیجه را کوتاه نکند. */
|
||||
private function midnight(): int
|
||||
{
|
||||
return (int) strtotime('tomorrow midnight');
|
||||
}
|
||||
|
||||
private function date(): string
|
||||
{
|
||||
return date('Y-m-d', $this->midnight());
|
||||
}
|
||||
|
||||
/** ۰ = شنبه، همان قرارداد تقویم منبع. */
|
||||
private function dayOfWeek(int $timestamp): int
|
||||
{
|
||||
return ((int) date('w', $timestamp) + 1) % 7;
|
||||
}
|
||||
|
||||
/** @param list<string> $serviceUuids */
|
||||
private function slotsUri(string $resourceUuid, string $date, array $serviceUuids): string
|
||||
{
|
||||
return '/api/v1/appointment-resource-slots?' . http_build_query([
|
||||
'resource_uuid' => $resourceUuid,
|
||||
'date' => $date,
|
||||
'service_item_uuids' => $serviceUuids,
|
||||
]);
|
||||
}
|
||||
|
||||
// ── ✅ موفق ──────────────────────────────────────────────────────────────
|
||||
|
||||
public function testAResourceWithAnOnlineEnabledServiceIsListedWithResolvedNumbers(): void
|
||||
{
|
||||
[$doctor, $address, $resource] = $this->doctorWithResource();
|
||||
$item = $this->service($address, 'لیزر پا');
|
||||
$this->offer($resource, $item, 45); // مدتِ اختصاصیِ همین دستگاه
|
||||
|
||||
$body = $this->publicJson($this->resourcesUri($doctor));
|
||||
|
||||
self::assertSame(200, $this->responseCode(), json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
self::assertCount(1, $body['data']['resources']);
|
||||
|
||||
$row = $body['data']['resources'][0];
|
||||
self::assertSame($resource->getUuid(), $row['uuid']);
|
||||
self::assertSame('لیزر CO2', $row['name']);
|
||||
self::assertSame($doctor->getUuid(), $row['supervisor']['uuid']);
|
||||
self::assertCount(1, $row['services']);
|
||||
// مدت از ردیف ارائه میآید، نه از پیشفرضِ ۳۰ دقیقهایِ خودِ سرویس.
|
||||
self::assertSame(45, $row['services'][0]['duration_minutes']);
|
||||
self::assertSame(5_000_000, $row['services'][0]['price_rials']);
|
||||
// ظرفیت عددِ عملیاتیِ داخل کلینیک است و نباید به سایت نشت کند.
|
||||
self::assertArrayNotHasKey('capacity', $row);
|
||||
}
|
||||
|
||||
// ── ❌ خطا ───────────────────────────────────────────────────────────────
|
||||
|
||||
public function testAServiceWithTheOnlineToggleOffHidesTheResource(): void
|
||||
{
|
||||
[$doctor, $address, $resource] = $this->doctorWithResource();
|
||||
$this->offer($resource, $this->service($address, 'سرویس خاموش', bookable: false));
|
||||
|
||||
$body = $this->publicJson($this->resourcesUri($doctor));
|
||||
|
||||
self::assertSame(200, $this->responseCode());
|
||||
self::assertSame([], $body['data']['resources']);
|
||||
}
|
||||
|
||||
public function testAnInactiveOfferingHidesTheResource(): void
|
||||
{
|
||||
[$doctor, $address, $resource] = $this->doctorWithResource();
|
||||
$this->offer($resource, $this->service($address, 'لیزر پا'), active: false);
|
||||
|
||||
$body = $this->publicJson($this->resourcesUri($doctor));
|
||||
|
||||
self::assertSame(200, $this->responseCode());
|
||||
self::assertSame([], $body['data']['resources']);
|
||||
}
|
||||
|
||||
public function testAnUnknownDoctorIsRejected(): void
|
||||
{
|
||||
$this->publicJson('/api/v1/appointment-booking-resources/00000000-0000-4000-8000-000000000000');
|
||||
|
||||
self::assertSame(404, $this->responseCode());
|
||||
}
|
||||
|
||||
// ── ⚠️ مرزی ──────────────────────────────────────────────────────────────
|
||||
|
||||
public function testADoctorWithoutAnyResourceGetsAnEmptyListNotAnError(): void
|
||||
{
|
||||
[, $doctor] = $this->doctorWithAddress();
|
||||
|
||||
$body = $this->publicJson($this->resourcesUri($doctor));
|
||||
|
||||
self::assertSame(200, $this->responseCode());
|
||||
self::assertSame([], $body['data']['resources']);
|
||||
}
|
||||
|
||||
/**
|
||||
* پزشکی که هیچ برنامهٔ هفتگی ندارد، هیچ «محل نوبتدهی» هم ندارد که سایت بتواند
|
||||
* `clinic_uuid` را از آن بردارد. منبع اما تقویم و شعبهٔ خودش را دارد و باید بدون
|
||||
* آن پارامتر هم پیدا شود، وگرنه دستگاهِ قابلِ رزرو هرگز در سایت دیده نمیشود.
|
||||
*/
|
||||
public function testWithoutAClinicParamTheResourcesOfEveryEnvironmentComeBack(): void
|
||||
{
|
||||
[$user, $clinic, $address] = $this->clinicWithAddress();
|
||||
|
||||
$doctor = $this->supervisorFor($address);
|
||||
|
||||
$resource = new ClinicResource($address, $this->resourceType($address), 'کندلا');
|
||||
$resource->setSupervisor($doctor);
|
||||
$this->em->persist($resource);
|
||||
$this->em->flush();
|
||||
|
||||
$this->offer($resource, $this->service($address, 'لیزر دست'), 20);
|
||||
|
||||
// بدون clinic_uuid — دقیقاً همان چیزی که سایت برای پزشکِ بیبرنامه میفرستد.
|
||||
$body = $this->publicJson($this->resourcesUri($doctor));
|
||||
|
||||
self::assertSame(200, $this->responseCode(), json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
self::assertCount(1, $body['data']['resources']);
|
||||
// محیطِ منبع همراهش میآید تا سایت بتواند نوبت را در همان کلینیک ثبت کند.
|
||||
self::assertSame($clinic->getUuid(), $body['data']['resources'][0]['clinic_uuid']);
|
||||
}
|
||||
|
||||
public function testAResourceSupervisedByAnotherDoctorIsNotListed(): void
|
||||
{
|
||||
[, $address, $resource] = $this->doctorWithResource();
|
||||
$this->offer($resource, $this->service($address, 'لیزر پا'));
|
||||
|
||||
$other = new Doctor($this->createUser(['ROLE_USER', 'ROLE_DOCTOR']), 'پزشک دیگر');
|
||||
$this->em->persist($other);
|
||||
$this->em->flush();
|
||||
|
||||
$body = $this->publicJson($this->resourcesUri($other));
|
||||
|
||||
self::assertSame(200, $this->responseCode());
|
||||
self::assertSame([], $body['data']['resources']);
|
||||
}
|
||||
|
||||
public function testAnInactiveResourceIsNotListed(): void
|
||||
{
|
||||
[$doctor, $address, $resource] = $this->doctorWithResource();
|
||||
$this->offer($resource, $this->service($address, 'لیزر پا'));
|
||||
|
||||
$resource->setActive(false);
|
||||
$this->em->flush();
|
||||
|
||||
$body = $this->publicJson($this->resourcesUri($doctor));
|
||||
|
||||
self::assertSame(200, $this->responseCode());
|
||||
self::assertSame([], $body['data']['resources']);
|
||||
}
|
||||
|
||||
// ── اسلاتهای عمومیِ منبع ────────────────────────────────────────────────
|
||||
|
||||
public function testTheFreeStartTimesOfAResourceComeBackWithoutAToken(): void
|
||||
{
|
||||
[, $address, $resource] = $this->doctorWithResource();
|
||||
$item = $this->service($address, 'لیزر پا');
|
||||
$this->offer($resource, $item, 45);
|
||||
$this->shift($resource);
|
||||
|
||||
$body = $this->publicJson($this->slotsUri($resource->getUuid(), $this->date(), [$item->getUuid()]));
|
||||
|
||||
self::assertSame(200, $this->responseCode(), json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
// مدت از ردیف ارائه میآید، نه از پیشفرضِ ۳۰ دقیقهایِ سرویس.
|
||||
self::assertSame(45, $body['data']['total_duration_minutes']);
|
||||
self::assertNotEmpty($body['data']['start_times']);
|
||||
self::assertSame('09:00', $body['data']['start_times'][0]['start_time']);
|
||||
self::assertSame('09:45', $body['data']['start_times'][0]['end_time']);
|
||||
}
|
||||
|
||||
public function testAServiceWithTheOnlineToggleOffIsRejectedEvenWhenTheResourceOffersIt(): void
|
||||
{
|
||||
[, $address, $resource] = $this->doctorWithResource();
|
||||
// یکی روشن تا خودِ منبع عمومی بماند، یکی خاموش تا گیتِ سرویس سنجیده شود.
|
||||
$this->offer($resource, $this->service($address, 'لیزر پا'), 45);
|
||||
$off = $this->service($address, 'سرویس خاموش', bookable: false);
|
||||
$this->offer($resource, $off, 20);
|
||||
$this->shift($resource);
|
||||
|
||||
$body = $this->publicJson($this->slotsUri($resource->getUuid(), $this->date(), [$off->getUuid()]));
|
||||
|
||||
self::assertSame(422, $this->responseCode());
|
||||
self::assertSame('این سرویس برای نوبتدهی آنلاین فعال نیست', $body['errors'][0]['message']);
|
||||
self::assertSame('service_item_uuids', $body['errors'][0]['field']);
|
||||
}
|
||||
|
||||
public function testAResourceWithoutAnyOnlineServiceIsNotReachable(): void
|
||||
{
|
||||
[, $address, $resource] = $this->doctorWithResource();
|
||||
$item = $this->service($address, 'سرویس خاموش', bookable: false);
|
||||
$this->offer($resource, $item, 20);
|
||||
$this->shift($resource);
|
||||
|
||||
$body = $this->publicJson($this->slotsUri($resource->getUuid(), $this->date(), [$item->getUuid()]));
|
||||
|
||||
self::assertSame(422, $this->responseCode());
|
||||
self::assertSame('resource_uuid', $body['errors'][0]['field']);
|
||||
}
|
||||
|
||||
public function testAMalformedDateIsRejected(): void
|
||||
{
|
||||
[, $address, $resource] = $this->doctorWithResource();
|
||||
$item = $this->service($address, 'لیزر پا');
|
||||
$this->offer($resource, $item, 45);
|
||||
|
||||
$body = $this->publicJson($this->slotsUri($resource->getUuid(), '2026-13-99', [$item->getUuid()]));
|
||||
|
||||
self::assertSame(422, $this->responseCode());
|
||||
self::assertSame('date', $body['errors'][0]['field']);
|
||||
}
|
||||
|
||||
public function testAnEmptyServiceSelectionIsRejected(): void
|
||||
{
|
||||
[, $address, $resource] = $this->doctorWithResource();
|
||||
$this->offer($resource, $this->service($address, 'لیزر پا'), 45);
|
||||
|
||||
$body = $this->publicJson($this->slotsUri($resource->getUuid(), $this->date(), []));
|
||||
|
||||
self::assertSame(422, $this->responseCode());
|
||||
self::assertSame('service_item_uuids', $body['errors'][0]['field']);
|
||||
}
|
||||
|
||||
// ── تقویم ماهِ منبع ──────────────────────────────────────────────────────
|
||||
|
||||
/** ماهِ آینده انتخاب میشود تا «زمانِ گذشته» همهٔ روزها را خالی نکند. */
|
||||
private function nextMonth(): array
|
||||
{
|
||||
$first = (int) strtotime('first day of next month midnight');
|
||||
|
||||
return [(int) date('Y', $first), (int) date('n', $first)];
|
||||
}
|
||||
|
||||
/** @param list<string> $serviceUuids */
|
||||
private function monthUri(string $resourceUuid, int $year, int $month, array $serviceUuids): string
|
||||
{
|
||||
return '/api/v1/appointment-resource-month-availability/' . $resourceUuid . '?' . http_build_query([
|
||||
'year' => $year,
|
||||
'month' => $month,
|
||||
'service_item_uuids' => $serviceUuids,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testOnlyTheWeekdaysWithAShiftAreEnabled(): void
|
||||
{
|
||||
[, $address, $resource] = $this->doctorWithResource();
|
||||
$item = $this->service($address, 'لیزر پا');
|
||||
$this->offer($resource, $item, 45);
|
||||
|
||||
// تنها شیفتِ منبع: شنبهها (۰ در قرارداد تقویم منبع).
|
||||
$this->em->persist(new ResourceCalendar($resource, 0, 540, 1020));
|
||||
$this->em->flush();
|
||||
|
||||
[$year, $month] = $this->nextMonth();
|
||||
$body = $this->publicJson($this->monthUri($resource->getUuid(), $year, $month, [$item->getUuid()]));
|
||||
|
||||
self::assertSame(200, $this->responseCode(), json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
self::assertNotEmpty($body['data']['enabled_dates']);
|
||||
|
||||
foreach ($body['data']['enabled_dates'] as $date) {
|
||||
self::assertSame('Saturday', date('l', (int) strtotime($date)), $date);
|
||||
}
|
||||
|
||||
// هیچ روزی از قلم نمیافتد — تقویم سایت روی همین دو فهرست تصمیم میگیرد.
|
||||
$daysInMonth = (int) date('t', (int) strtotime(sprintf('%04d-%02d-01', $year, $month)));
|
||||
self::assertCount(
|
||||
$daysInMonth,
|
||||
array_merge($body['data']['enabled_dates'], $body['data']['disabled_dates']),
|
||||
);
|
||||
}
|
||||
|
||||
public function testAnInvalidMonthIsRejected(): void
|
||||
{
|
||||
[, $address, $resource] = $this->doctorWithResource();
|
||||
$item = $this->service($address, 'لیزر پا');
|
||||
$this->offer($resource, $item, 45);
|
||||
|
||||
$body = $this->publicJson($this->monthUri($resource->getUuid(), 2026, 13, [$item->getUuid()]));
|
||||
|
||||
self::assertSame(422, $this->responseCode());
|
||||
self::assertSame('month', $body['errors'][0]['field']);
|
||||
}
|
||||
|
||||
public function testAPastMonthHasNoEnabledDay(): void
|
||||
{
|
||||
[, $address, $resource] = $this->doctorWithResource();
|
||||
$item = $this->service($address, 'لیزر پا');
|
||||
$this->offer($resource, $item, 45);
|
||||
$this->em->persist(new ResourceCalendar($resource, 0, 540, 1020));
|
||||
$this->em->flush();
|
||||
|
||||
$past = (int) strtotime('first day of last month midnight');
|
||||
$body = $this->publicJson(
|
||||
$this->monthUri($resource->getUuid(), (int) date('Y', $past), (int) date('n', $past), [$item->getUuid()]),
|
||||
);
|
||||
|
||||
self::assertSame(200, $this->responseCode());
|
||||
self::assertSame([], $body['data']['enabled_dates']);
|
||||
}
|
||||
|
||||
public function testADayWithoutAShiftReturnsAnEmptyListNotAnError(): void
|
||||
{
|
||||
[, $address, $resource] = $this->doctorWithResource();
|
||||
$item = $this->service($address, 'لیزر پا');
|
||||
$this->offer($resource, $item, 45);
|
||||
// بدون هیچ ResourceCalendar — منبع آن روز باز نیست.
|
||||
|
||||
$body = $this->publicJson($this->slotsUri($resource->getUuid(), $this->date(), [$item->getUuid()]));
|
||||
|
||||
self::assertSame(200, $this->responseCode(), json_encode($body, JSON_UNESCAPED_UNICODE));
|
||||
self::assertSame([], $body['data']['start_times']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user