feat(practice-domain): add practice domains and let a clinic select one
A practice domain is the field a clinic operates in — beauty, dentistry —
and unlike Specialty it is configuration, not a label: treatment workflows
will bind to its code, so the code is immutable once created and only a
platform admin can mint one. A clinic that has not chosen a domain keeps
behaving exactly as it does today.
Assignment reuses PATCH /api/v1/clinic/{uuid} rather than adding a second
endpoint. An unknown domain uuid is rejected instead of silently dropped,
because a lost selection would only surface at the first protocol-driven
booking.
Also corrects ADR-0003: resource occupancy does not in fact guard the panel
booking path, which writes appointments.resource_id and no occupancy row at
all, so the doctor slot key cannot simply be dropped.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -224,26 +224,49 @@ if ($doctorUuid === '' && $resource->getSupervisor() !== null) {
|
||||
«این منبع پزشک ناظر ندارد؛ ابتدا در تنظیمات منابع پزشک ناظر را مشخص کنید».
|
||||
پیام فعلی (`doctor_uuid یا resource_uuid ...`) گمراهکننده است.
|
||||
|
||||
### ۵. آزادسازی کلید اسلات برای نوبتهای منبعدار
|
||||
### ۵. رزرو منبع مستقل از پزشک
|
||||
|
||||
در `Appointment::refreshActiveSlotKey()`:
|
||||
**این وظیفه بعد از بررسی داده واقعی بازنویسی شد. ADR-0003 را بخوان.**
|
||||
|
||||
آنچه با داده تأیید شد:
|
||||
|
||||
- دو مسیر رزرو داریم و هیچکدام ردیف دیگری نمیسازد.
|
||||
مسیر پنل روی `appointments.resource_id` مینشیند، مسیر hold روی `resource_occupancy`.
|
||||
- `bookAtomically` روی **پزشک** قفل میگیرد و `isSlotTaken` تداخل بازهای را فقط روی پزشک
|
||||
میسنجد. منبع در آن کوئری نیست.
|
||||
- در دیتابیس فعلی هر محیط چند منبع با یک پزشک ناظر مشترک دارد. کلینیک ۲ شش منبع با پزشک ۶،
|
||||
کلینیک ۳ سه منبع با پزشک ۹. پس این باگ همین حالا فعال است.
|
||||
- برنامه هفتگی پزشک مانع نیست؛ `resolveSlotLocationId` فقط `null` برمیگرداند.
|
||||
|
||||
پنج تغییر:
|
||||
|
||||
۱. مسیر پنل هنگام رزرو `ResourceOccupancy` بسازد، همانطور که `HoldService` میسازد.
|
||||
منطق مشترک در یک سرویس باشد، در دو جا کپی نشود.
|
||||
|
||||
۲. لغو یا انقضای نوبت، ردیف اشغال را `released` کند.
|
||||
|
||||
۳. در `Appointment::refreshActiveSlotKey()` وقتی منبع هست کلید `null` بماند:
|
||||
|
||||
```php
|
||||
$this->activeSlotKey = (!$this->isReserve
|
||||
&& $this->resource === null // ← شرط جدید
|
||||
&& $this->resource === null
|
||||
&& in_array($this->status, self::SLOT_OCCUPYING_STATUSES, true))
|
||||
? sprintf('%d:%d', $this->doctor->getId(), $this->slotStart)
|
||||
: null;
|
||||
```
|
||||
|
||||
`setResource()` باید `refreshActiveSlotKey()` را صدا بزند، وگرنه نوبتی که اول ساخته
|
||||
و بعد منبعش ست میشود کلیدش باقی میماند.
|
||||
`setResource()` باید `refreshActiveSlotKey()` را صدا بزند.
|
||||
|
||||
**قبل از این تغییر:** همه مسیرهای ساخت نوبت را فهرست کن و مشخص کن کدامها `resource`
|
||||
ست نمیکنند. آنها بعد از این تغییر همچنان با کلید پزشک محافظت میشوند — این درست است،
|
||||
ولی باید مستند شود که کدامها هستند. ADR-0003 روی همین هشدار داده.
|
||||
۴. `bookAtomically` وقتی نوبت منبع دارد روی پزشک قفل نگیرد و `isSlotTaken` را صدا نزند.
|
||||
تضمین یکتایی از `uniq_bucket_resource_seat` میآید که ظرفیت و `seat` را میفهمد.
|
||||
|
||||
migration لازم نیست؛ ستون بدون تغییر میماند و فقط منطق پرشدنش عوض میشود.
|
||||
۵. شعبه نوبتِ منبعدار از `ClinicResource.getAddress()` بیاید، نه از برنامه پزشک.
|
||||
|
||||
**قبل از شروع:** همه مسیرهای ساخت نوبت را فهرست کن و بنویس کدامها منبع ست نمیکنند.
|
||||
آنها کلید پزشک و قفل پزشک را نگه میدارند. این فهرست باید در گزارش بیاید.
|
||||
|
||||
migration برای `active_slot_key` لازم نیست. برای ردیفهای اشغالِ گذشتهٔ مسیر پنل یک
|
||||
migration دادهای لازم است تا نوبتهای فعالِ منبعدار موجود ردیف اشغال بگیرند.
|
||||
|
||||
### ۶. تعریف فیلد روی نوع منبع
|
||||
|
||||
|
||||
Reference in New Issue
Block a user