feat(appointment): implement immutable booking mode after first save and update API documentation
This commit is contained in:
@@ -41,6 +41,18 @@ class AppointmentSettingsController extends BaseController
|
||||
* در حالت نوبتدهی سرویسی، پزشک باید حداقل یک سرویسِ «نمایش در نوبتدهی»
|
||||
* (bookable) داشته باشد؛ وگرنه هیچ نوبتی قابلمحاسبه نیست.
|
||||
*/
|
||||
/**
|
||||
* نوع نوبتدهی پس از اولین ثبت غیرقابلتغییر است. اگر قبلاً mode ذخیره شده بود
|
||||
* ($prevMode !== null) و meta جدید آن را تغییر دهد، خطای 422 برمیگرداند.
|
||||
*/
|
||||
private function assertModeImmutable(?string $prevMode, array $newMeta): ?JsonResponse
|
||||
{
|
||||
if ($prevMode !== null && ($newMeta['booking_mode'] ?? null) !== $prevMode) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'نوع نوبتدهی پس از ثبت قابل تغییر نیست', 422, 'booking_mode');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function serviceModeHasNoBookable(array $meta, \App\Doctor\Entity\Doctor $doctor): bool
|
||||
{
|
||||
return ($meta['booking_mode'] ?? WeeklySchedule::MODE_SLOT) === WeeklySchedule::MODE_SERVICE
|
||||
@@ -70,6 +82,7 @@ class AppointmentSettingsController extends BaseController
|
||||
|
||||
// Only one schedule per doctor — upsert
|
||||
$schedule = $this->scheduleRepo->findByDoctor($doctor);
|
||||
$prevMode = $schedule?->getStoredBookingMode();
|
||||
if ($schedule !== null) {
|
||||
$schedule->setSetting($data['schedule'] ?? []);
|
||||
} else {
|
||||
@@ -80,6 +93,10 @@ class AppointmentSettingsController extends BaseController
|
||||
$schedule->setMeta($data['meta']);
|
||||
}
|
||||
|
||||
if (($err = $this->assertModeImmutable($prevMode, $schedule->getMeta())) !== null) {
|
||||
return $err;
|
||||
}
|
||||
|
||||
if ($this->serviceModeHasNoBookable($schedule->getMeta(), $doctor)) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'برای نوبتدهی سرویسی حداقل یک سرویس با «نمایش در نوبتدهی» لازم است', 422, 'booking_mode');
|
||||
}
|
||||
@@ -107,6 +124,7 @@ class AppointmentSettingsController extends BaseController
|
||||
return $this->error(ErrorCodes::ERR_AUTH_006, 'دسترسی ممنوع', 403);
|
||||
}
|
||||
|
||||
$prevMode = $schedule->getStoredBookingMode();
|
||||
$data = json_decode($request->getContent(), true) ?? [];
|
||||
if (isset($data['schedule'])) {
|
||||
if (($err = $this->validateSessionsHaveLocation($data['schedule'])) !== null) {
|
||||
@@ -118,6 +136,10 @@ class AppointmentSettingsController extends BaseController
|
||||
$schedule->setMeta($data['meta']);
|
||||
}
|
||||
|
||||
if (($err = $this->assertModeImmutable($prevMode, $schedule->getMeta())) !== null) {
|
||||
return $err;
|
||||
}
|
||||
|
||||
if ($this->serviceModeHasNoBookable($schedule->getMeta(), $schedule->getDoctor())) {
|
||||
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'برای نوبتدهی سرویسی حداقل یک سرویس با «نمایش در نوبتدهی» لازم است', 422, 'booking_mode');
|
||||
}
|
||||
|
||||
@@ -79,6 +79,16 @@ class WeeklySchedule
|
||||
return array_merge(self::DEFAULT_META, $this->setting[self::META_KEY] ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* booking_mode ذخیرهشده بهصورت خام (بدون merge پیشفرض). null یعنی هنوز
|
||||
* صریحاً ثبت نشده — تا وقتی null است، انتخاب روش قابلتغییر است؛ پس از اولین
|
||||
* ثبت، قفل میشود.
|
||||
*/
|
||||
public function getStoredBookingMode(): ?string
|
||||
{
|
||||
return $this->setting[self::META_KEY]['booking_mode'] ?? null;
|
||||
}
|
||||
|
||||
public function setMeta(array $meta): self
|
||||
{
|
||||
$current = $this->getMeta();
|
||||
@@ -111,6 +121,8 @@ class WeeklySchedule
|
||||
'doctor_uuid' => $this->doctor->getUuid(),
|
||||
'schedule' => $this->getDaySchedule(),
|
||||
'meta' => $this->getMeta(),
|
||||
// نوع نوبتدهی پس از اولین ثبت قفل میشود (پنل توگل را غیرفعال میکند).
|
||||
'booking_mode_locked' => $this->getStoredBookingMode() !== null,
|
||||
'created_at' => $this->createdAt,
|
||||
'updated_at' => $this->updatedAt,
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user