feat: implement cancellation policy, no-show tracking, and waitlist management
- 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.
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
# تسک ۱۳ — سیاست لغو، عدم حضور، لیست انتظار
|
||||
|
||||
**فاز:** ۳ (کسبوکار) · **وابستگی:** ۰۷ · **زمان:** ۱۰-۱۲ ساعت
|
||||
|
||||
---
|
||||
|
||||
## هدف
|
||||
|
||||
مستند بند ۱۱: «هر کلینیک تنظیم میکند: تا چند ساعت قبل لغو رایگان است، جریمه چقدر است،
|
||||
بیعانه برمیگردد یا نه، بعد از چند بار عدم حضور بیمار پرریسک علامت بخورد.»
|
||||
و بند ۱۷: «رقابت روی ساعتهای پرتقاضا → پیشنهاد خودکار ساعت جایگزین» و
|
||||
بند ۱۸ فاز ۳: «لیست انتظار».
|
||||
|
||||
## وضعیت فعلی
|
||||
|
||||
- لغو کار میکند (`cancelled_by_user` / `cancelled_by_doctor`) ولی **بدون سیاست**:
|
||||
هیچ جریمهای، هیچ محدودیت زمانی، هیچ رفتاری با بیعانه
|
||||
- `no_show` وضعیت هست ولی هیچ اثری ندارد
|
||||
- `Appointment.is_reserve` وجود دارد: «نوبت رزرو» روزی (بدون ساعت) — یک لیست انتظار
|
||||
ابتدایی که `ReserveAppointmentsPage.tsx` نمایشش میدهد
|
||||
- بیعانه ثبت میشود (`deposit_required`, `deposit_amount_rials`) ولی بازگشتش دستی است
|
||||
|
||||
## دامنه
|
||||
|
||||
**هست:**
|
||||
- `CancellationPolicy` per محیط/سرویس: پنجرهٔ لغو رایگان، درصد/مبلغ جریمه، رفتار بیعانه
|
||||
- `NoShowPolicy`: بعد از N بار، برچسب پرریسک روی بیمار (استفاده از `TenantTag` موجود)
|
||||
- محاسبهٔ جریمه در لحظهٔ لغو + ثبت در دفتر مالی موجود
|
||||
- `Waitlist` — لیست انتظار برای بازهٔ زمانی مشخص (توسعهٔ `is_reserve` موجود)
|
||||
- اطلاعرسانی خودکار به لیست انتظار وقتی ظرفیت آزاد میشود
|
||||
|
||||
**نیست:** پیشبینی عدم حضور (فاز ۴ مستند — خارج از دامنه).
|
||||
|
||||
## Endpoint ها
|
||||
|
||||
| متد | مسیر | توضیح |
|
||||
|---|---|---|
|
||||
| GET/PUT | `/api/v1/cancellation-policy` | سیاست محیط |
|
||||
| PUT | `/api/v1/service-item/{uuid}/cancellation-policy` | override سرویس |
|
||||
| GET | `/api/v1/appointment/{uuid}/cancellation-preview` | جریمه و بازگشت **پیش از** لغو |
|
||||
| POST | `/api/v1/appointment/{uuid}/cancel` | لغو با اعمال سیاست |
|
||||
| GET/POST | `/api/v1/waitlist` | ثبت در لیست انتظار |
|
||||
| DELETE | `/api/v1/waitlist/{uuid}` | |
|
||||
| GET | `/api/v1/waitlist/matches` | (پنل) درخواستهای قابل تطبیق با ظرفیت آزاد |
|
||||
|
||||
## معیار پذیرش
|
||||
|
||||
- ✅ موفق: سیاست «لغو رایگان تا ۲۴ ساعت قبل، پس از آن ۵۰٪ جریمه، بیعانه برنمیگردد» →
|
||||
`GET /cancellation-preview` برای نوبت ۴۸ ساعت بعد: `penalty_rials: 0, deposit_refundable: true`؛
|
||||
برای نوبت ۶ ساعت بعد: `penalty_rials: <۵۰٪>, deposit_refundable: false`.
|
||||
- ✅ موفق: `POST /cancel` جریمه را در `wallet_transactions` (الگوی موجود) ثبت میکند و
|
||||
اشغال منابع را آزاد میکند.
|
||||
- ✅ موفق: سومین `no_show` بیمار → برچسب «پرریسک» (`TenantTag`) خودکار اضافه میشود و
|
||||
در `PatientDetailPage` دیده میشود.
|
||||
- ✅ موفق: بیمار در لیست انتظار برای «۵ مرداد، بعدازظهر» است؛ نوبتی در آن بازه لغو
|
||||
میشود → یک پیامک به او میرود و رکورد `notified_at` پر میشود.
|
||||
- ✅ موفق: لغو دورهٔ درمان (تسک ۱۲) → اعتبار پکیج **طبق سیاست** برمیگردد، نه همیشه.
|
||||
- ❌ خطا: `cancel` نوبتی که قبلاً لغو شده → `409` idempotent (همان وضعیت برگردد).
|
||||
- ❌ خطا: `cancel` نوبت گذشته → `422`؛ برای گذشته `no_show` یا `completed` معنی دارد.
|
||||
- ❌ خطا: ثبت در لیست انتظار برای بازهٔ گذشته → `422`.
|
||||
- ⚠️ مرزی: جریمه بیشتر از مبلغ پرداختی → سقف = مبلغ پرداختی.
|
||||
- ⚠️ مرزی: لغو توسط **کلینیک** (`cancelled_by_doctor`) → هرگز جریمه ندارد و بیعانه
|
||||
کامل برمیگردد.
|
||||
- ⚠️ مرزی: نوبت بدون پرداخت (نقدی سر جلسه) → جریمه ثبت میشود بهعنوان بدهی، نه کسر.
|
||||
- ⚠️ مرزی: لیست انتظار با ده نفر برای یک بازه → **همه** مطلع میشوند (اولین رزروکننده
|
||||
میبرد) — نه صف انحصاری. تصمیم و دلیلش در implementation_notes.
|
||||
- ⚠️ مرزی: بیمار پرریسک → **مسدود نمیشود**؛ فقط برچسب. مسدودسازی یک قانون
|
||||
`eligibility` (تسک ۰۹) روی همان برچسب است.
|
||||
|
||||
## خروجی
|
||||
|
||||
- `src/Cancellation/` + `src/Waitlist/`
|
||||
- `assets/admin/pages/CancellationPolicyPage.tsx` + `WaitlistPage.tsx`
|
||||
- توسعهٔ `AppointmentDetailPage.tsx` با پیشنمایش لغو
|
||||
- `docs/api/cancellation.md` + `docs/api/waitlist.md`
|
||||
Reference in New Issue
Block a user