- Add implementation notes for cancellation and waitlist features. - Create task documentation outlining goals, current status, and acceptance criteria for cancellation policy and resource utilization reporting. - Establish architecture for domain events and outbox pattern to ensure reliable event publishing. - Define database schema for domain events and necessary queries for resource utilization and plan accuracy reports. - Implement detailed implementation notes covering edge cases, testing strategies, and documentation requirements.
124 lines
5.9 KiB
Markdown
124 lines
5.9 KiB
Markdown
# جریان کاربری — تسک ۰۵
|
||
|
||
## الف) کلینیک الگوی بخشهای یک سرویس را تعریف میکند
|
||
|
||
```
|
||
پنل › خدمات › لیزر کندلا › تب «بخشهای نوبت»
|
||
│
|
||
├─ «افزودن بخش»
|
||
│ نام: مالیدن کرم بیحسی
|
||
│ نوع (کلید ادغام): آمادهسازی
|
||
│ مدت: ثابت — ۵ دقیقه
|
||
│ بیمار حاضر است: بله
|
||
│ با بخشهای همنوع ادغام شود: بله
|
||
│ └─ نیازمندیها:
|
||
│ [اتاق] × ۱ — انحصاری
|
||
│ [اپراتور] × ۱ — انحصاری — مهارت: لیزر آلکساندرایت — قید: همجنس با بیمار
|
||
│
|
||
├─ بخش ۲: انتظار اثر بیحسی — ثابت ۳۰ — ادغامپذیر
|
||
│ نیازمندی: فقط [اتاق] × ۱ انحصاری ← اپراتور اینجا آزاد است
|
||
│
|
||
├─ بخش ۳: خود لیزر — سهمی ۱۰۰٪
|
||
│ نیازمندی: [اتاق] × ۱ · [اپراتور] × ۱ · [دستگاه] × ۱ از استخر «لیزرهای آلکساندرایت»
|
||
│
|
||
└─ بخش ۴: مراقبت بعد — ثابت ۵
|
||
نیازمندی: [اتاق] × ۱ · [اپراتور] × ۱
|
||
│
|
||
▼
|
||
نوار پیشنمایش زمانی (زیر فرم، زنده):
|
||
|
||
┌─────┬───────────────────┬─────────────┬─────┐
|
||
│ ۵' │ ۳۰' │ ۲۰' │ ۵' │
|
||
│🏠👤 │ 🏠 │ 🏠 👤 🔧 │🏠👤 │
|
||
└─────┴───────────────────┴─────────────┴─────┘
|
||
کل: ۶۰ دقیقه · اپراتور واقعاً درگیر: ۳۰ دقیقه
|
||
|
||
│
|
||
▼
|
||
«ذخیره» → PUT /api/v1/service-item/{uuid}/segments
|
||
```
|
||
|
||
خط «اپراتور واقعاً درگیر: ۳۰ دقیقه» مهمترین بازخورد این صفحه است: کلینیک آنجا میفهمد
|
||
چرا این کار ارزشش را دارد.
|
||
|
||
---
|
||
|
||
## ب) بیمار سرویس و آیتم انتخاب میکند (سایت عمومی)
|
||
|
||
```
|
||
انتخاب پزشک/کلینیک
|
||
│
|
||
▼
|
||
GET /api/v1/appointment-booking-services/{doctorUuid}
|
||
→ booking_mode = "resource" ← حالت جدید
|
||
→ services[] با گروههای آیتم
|
||
│
|
||
▼
|
||
بیمار انتخاب میکند: ناحیه = صورت + بیکینی · سطح انرژی = ۱۶
|
||
│
|
||
▼
|
||
POST /api/v1/service-selection/validate (تسک ۰۴، debounce)
|
||
→ valid: true · total_duration_minutes: 23 · total_price_rials: …
|
||
│
|
||
│ اگر valid=false:
|
||
│ خطاها زیر همان گروه نمایش داده میشوند
|
||
│ «انتخاب حداقل یک مورد از نواحی الزامی است»
|
||
│ «صورت و فولبادی با هم قابل انتخاب نیستند»
|
||
│ و دکمهٔ «ادامه» غیرفعال میماند
|
||
▼
|
||
POST /api/v1/appointment-plan/preview
|
||
→ total_minutes: 68
|
||
segments: [آمادهسازی ۵ · انتظار ۳۰ · لیزر ۲۳ · مراقبت ۵ · تمیزکاری ۵]
|
||
│
|
||
│ اگر NoEligibleResourceException:
|
||
│ «هیچ اپراتور خانمی با مهارت لیزر آلکساندرایت در شعبهٔ مرکزی موجود نیست»
|
||
│ + پیشنهاد شعبهٔ دیگر (اگر داشته باشد)
|
||
▼
|
||
مرحلهٔ انتخاب زمان → تسک ۰۶
|
||
```
|
||
|
||
**نکته UX:** برنامهٔ نوبت به بیمار **نمایش داده نمیشود**. بیمار فقط «۶۸ دقیقه» و
|
||
«توضیحات آمادهسازی» را میبیند. بخشها جزئیات عملیاتی کلینیکاند؛ نشان دادنشان به بیمار
|
||
فقط سؤال میسازد.
|
||
|
||
استثنا: بخشهایی با `patient_present = false` نباید در مدت اعلامی به بیمار بیایند
|
||
(«تمیزکاری یونیت» ۵ دقیقهٔ بعد از رفتن بیمار است). پس دو عدد وجود دارد:
|
||
|
||
- `total_minutes` = ۶۸ (اشغال کلینیک) — برای موتور
|
||
- `patient_facing_minutes` = ۶۳ — برای نمایش
|
||
|
||
هر دو در پاسخ `preview` برگردند.
|
||
|
||
---
|
||
|
||
## ج) منشی از پنل نوبت میسازد
|
||
|
||
همان جریان ب، با دو تفاوت:
|
||
|
||
1. `forManagement = true` — بازهٔ رزرو و خاموش بودن نوبتدهی آنلاین اعمال نمیشود
|
||
(همان رفتاری که `SlotCalculatorService::isWithinBookingWindow()` امروز دارد)
|
||
2. منشی میتواند **منبع را دستی انتخاب کند**: پاسخ `preview` برای هر نیازمندی
|
||
`candidates` را با نام برمیگرداند و پنل یک `SearchableSelect` اختیاری نشان میدهد.
|
||
خالی گذاشتن یعنی «تو انتخاب کن» (استراتژی تسک ۰۶).
|
||
|
||
---
|
||
|
||
## د) حالت خطا — هیچ منبعی موجود نیست
|
||
|
||
```
|
||
POST /appointment-plan/preview
|
||
▼
|
||
422 {
|
||
"success": false,
|
||
"errors": [{
|
||
"code": "ERR_NO_ELIGIBLE_RESOURCE",
|
||
"message": "هیچ اپراتور خانمی با مهارت لیزر آلکساندرایت در شعبهٔ مرکزی موجود نیست",
|
||
"meta": { "segment": "خود لیزر", "role": "اپراتور", "branch_uuid": "…" }
|
||
}]
|
||
}
|
||
```
|
||
|
||
`meta` اجباری است: پنل با آن میتواند مستقیم به صفحهٔ منابع همان شعبه لینک بدهد
|
||
(«افزودن اپراتور») و کلینیک در سه کلیک مشکل را حل کند، بهجای اینکه با یک پیام
|
||
بنبست بماند.
|