# تسک ۱۳ — سیاست لغو، عدم حضور، لیست انتظار

**فاز:** ۳ (کسب‌وکار) · **وابستگی:** ۰۷ · **زمان:** ۱۰-۱۲ ساعت

---

## هدف

مستند بند ۱۱: «هر کلینیک تنظیم می‌کند: تا چند ساعت قبل لغو رایگان است، جریمه چقدر است،
بیعانه برمی‌گردد یا نه، بعد از چند بار عدم حضور بیمار پرریسک علامت بخورد.»
و بند ۱۷: «رقابت روی ساعت‌های پرتقاضا → پیشنهاد خودکار ساعت جایگزین» و
بند ۱۸ فاز ۳: «لیست انتظار».

## وضعیت فعلی

- لغو کار می‌کند (`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`
