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.
This commit is contained in:
hamed
2026-08-03 09:37:22 +03:30
parent c42679d98c
commit 348e1cf517
9 changed files with 535 additions and 289 deletions
@@ -14,6 +14,9 @@ final class ResourceCalendarService
{
public const DAYS = [0, 1, 2, 3, 4, 5, 6];
/** ۰ = شنبه. پیام خطا باید نام روز را بگوید، نه اندیس خام را. */
private const DAY_LABELS = ['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه'];
public function __construct(
private readonly ResourceCalendarRepository $calendars,
private readonly EntityManagerInterface $em,
@@ -115,7 +118,7 @@ final class ResourceCalendarService
if ($end <= $start) {
throw new AppException(
ErrorCodes::ERR_VALIDATION_001,
sprintf('در روز %d، پایان شیفت باید بعد از شروع آن باشد', $day),
sprintf('در روز %s، پایان شیفت باید بعد از شروع آن باشد', self::DAY_LABELS[$day]),
422,
'end_minute',
);
@@ -130,7 +133,7 @@ final class ResourceCalendarService
if ($i > 0 && $range['start_minute'] < $parsed[$i - 1]['end_minute']) {
throw new AppException(
ErrorCodes::ERR_VALIDATION_001,
sprintf('شیفت‌های روز %d با هم هم‌پوشانی دارند', $day),
sprintf('شیفت‌های روز %s با هم تداخل دارند — بازه‌ها نباید هم‌پوشانی داشته باشند', self::DAY_LABELS[$day]),
422,
'start_minute',
);
@@ -145,7 +148,7 @@ final class ResourceCalendarService
if (!is_numeric($value)) {
throw new AppException(
ErrorCodes::ERR_VALIDATION_002,
sprintf('در روز %d مقدار %s الزامی است', $day, $field),
sprintf('در روز %s مقدار %s الزامی است', self::DAY_LABELS[$day], $field),
422,
$field,
);
@@ -156,7 +159,7 @@ final class ResourceCalendarService
if ($minute < 0 || $minute > ResourceCalendar::MINUTES_IN_DAY) {
throw new AppException(
ErrorCodes::ERR_VALIDATION_001,
sprintf('در روز %d مقدار %s باید بین ۰ و ۱۴۴۰ باشد', $day, $field),
sprintf('در روز %s مقدار %s باید بین ۰ و ۱۴۴۰ باشد', self::DAY_LABELS[$day], $field),
422,
$field,
);