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:
hamed
2026-07-30 11:43:58 +03:30
parent 1d338503c8
commit 021d0eb6b2
62 changed files with 8098 additions and 0 deletions
@@ -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`