Files
clinicpro/tests/Resource/ResourceCalendarValidationTest.php
T
hamed 348e1cf517 feat: enhance resource calendar validation and UI
- Implement real-time validation for overlapping shifts in the ResourceWorkingHoursPanel.
- Remove the copy shift functionality to simplify the UI and prevent confusion.
- Introduce ResourceExceptionsCard to manage resource exceptions, including leave and maintenance.
- Update ClinicAppointmentSettingsPage to utilize new components and improve tab navigation for resource management.
- Add comprehensive validation tests for resource calendar to ensure overlapping shifts are correctly handled.
- Update API documentation to reflect new validation error messages and rules.
2026-08-03 09:37:22 +03:30

100 lines
4.4 KiB
PHP

<?php
namespace App\Tests\Resource;
/**
* قواعد اعتبارسنجی شیفت هفتگی منبع.
*
* پنل ادمین همین سه قاعده را حین تایپ هم اجرا می‌کند، ولی مرجع نهایی سرور است:
* کلاینت قدیمی، اسکریپت، و درخواست مستقیم به API نباید بتوانند شیفت متداخل بنشانند.
*/
class ResourceCalendarValidationTest extends ResourceTestCase
{
/** @param array<int|string, mixed> $days */
private function putCalendar(array $days): array
{
[$user, , $address] = $this->clinicWithAddress();
$resource = $this->createResource($user, $address, $this->resourceType($address));
return $this->authJson(
'PUT',
"/api/v1/resource/{$resource['data']['uuid']}/calendar",
$user,
['days' => $days],
);
}
/** ۰۹:۰۰–۱۳:۰۰ کنار ۱۲:۰۰–۱۷:۰۰ یعنی یک ساعت ظرفیتِ دوباره‌فروخته‌شده. */
public function testOverlappingShiftsInTheSameDayAreRejected(): void
{
$body = $this->putCalendar([
0 => [
['start_minute' => 540, 'end_minute' => 780], // ۰۹:۰۰–۱۳:۰۰
['start_minute' => 720, 'end_minute' => 1020], // ۱۲:۰۰–۱۷:۰۰
],
]);
self::assertSame(422, $this->responseCode(), json_encode($body, JSON_UNESCAPED_UNICODE));
self::assertSame('start_minute', $body['errors'][0]['field']);
self::assertStringContainsString('شنبه', $body['errors'][0]['message'], 'پیام باید نام روز را بگوید نه اندیس');
self::assertStringContainsString('تداخل', $body['errors'][0]['message']);
}
/** ترتیب ورودی نباید مهم باشد: تداخل بین شیفت اول و سوم هم باید دیده شود. */
public function testOverlapIsDetectedRegardlessOfInputOrder(): void
{
$body = $this->putCalendar([
2 => [
['start_minute' => 900, 'end_minute' => 1020], // ۱۵:۰۰–۱۷:۰۰
['start_minute' => 540, 'end_minute' => 600], // ۰۹:۰۰–۱۰:۰۰
['start_minute' => 960, 'end_minute' => 1080], // ۱۶:۰۰–۱۸:۰۰ ← با اولی تداخل دارد
],
]);
self::assertSame(422, $this->responseCode());
self::assertStringContainsString('دوشنبه', $body['errors'][0]['message']);
}
/** مرزِ چسبیده هم‌پوشانی نیست: ۱۳:۰۰ پایانِ یکی و شروعِ بعدی، شیفت صبح و عصر است. */
public function testBackToBackShiftsAreAccepted(): void
{
$body = $this->putCalendar([
0 => [
['start_minute' => 540, 'end_minute' => 780],
['start_minute' => 780, 'end_minute' => 1020],
],
]);
self::assertSame(200, $this->responseCode(), json_encode($body, JSON_UNESCAPED_UNICODE));
self::assertCount(2, $body['data']['days']['0']);
}
/** اعتبارسنجی کامل پیش از هر حذفی — روز نامعتبر نباید روزهای درست را پاک کند. */
public function testAnInvalidDayLeavesTheExistingCalendarUntouched(): void
{
[$user, , $address] = $this->clinicWithAddress();
$resource = $this->createResource($user, $address, $this->resourceType($address));
$uuid = $resource['data']['uuid'];
$this->authJson('PUT', "/api/v1/resource/$uuid/calendar", $user, [
'days' => [0 => [['start_minute' => 540, 'end_minute' => 1020]]],
]);
self::assertSame(200, $this->responseCode());
$this->authJson('PUT', "/api/v1/resource/$uuid/calendar", $user, [
'days' => [
0 => [['start_minute' => 540, 'end_minute' => 1020]],
1 => [
['start_minute' => 540, 'end_minute' => 780],
['start_minute' => 600, 'end_minute' => 900],
],
],
]);
self::assertSame(422, $this->responseCode());
$body = $this->authJson('GET', "/api/v1/resource/$uuid/calendar", $user);
self::assertCount(1, $body['data']['days']['0'], 'شنبهٔ قبلی سرِ جایش مانده');
self::assertSame([], $body['data']['days']['1']);
}
}