# دليل عمليات النشاط الرياضي — Sports Activity Workflows

---

## 1. مكتب الاشتراكات — تسجيل لاعب جديد

### الهدف

تسجيل لاعب (عضو أو غير عضو) في النشاط الرياضي، دفع رسوم التسجيل، التقاط صورة، واختيار الأنشطة المطلوبة.

### المسار

`/sa/registration`

### الخطوات

#### خطوة 1: إدخال البيانات

1. ادخل على **مكتب الخدمة** ← **التسجيل الرياضي** من الشريط الجانبي
2. أدخل **رقم العضوية** (للأعضاء — يملأ الاسم والهاتف والرقم القومي تلقائياً)
3. أو أدخل **الرقم القومي** (14 رقم — يستخرج تاريخ الميلاد والنوع تلقائياً)
4. أكمل الاسم بالعربي + هاتف ولي الأمر (إن وُجد)
5. اضغط **بدء التسجيل**

> **ملاحظة**: إذا كان الشخص عضو في النادي (موجود في قاعدة البيانات)، يدفع **50 ج.م**. غير الأعضاء يدفعون **100 ج.م**.

#### خطوة 2: الدفع (Step 1 في الويزارد)

- تظهر شاشة الدفع بالمبلغ المطلوب
- اضغط **إرسال للخزينة**
- يتم إنشاء طلب دفع يظهر عند الخزينة في طابور الدفع
- بعد ما الخزينة تحصّل المبلغ → الويزارد يتقدم تلقائياً

> **لاعب عائد** (سبق ودفع رسوم التسجيل قبل كده): يتخطى هذه الخطوة مباشرة.

#### خطوة 3: التقاط الصورة (Step 2)

- افتح الكاميرا أو ارفع ملف صورة
- اضغط **التالي**

#### خطوة 4: اختيار الأنشطة (Step 3)

- اختر النشاط/الأنشطة المطلوبة (كرة قدم، سباحة، كاراتيه، إلخ)
- هذا لا يعيّن مجموعة — فقط يسجل رغبة اللاعب
- اضغط **حفظ الأنشطة المختارة**

#### خطوة 5: الاستلام (Step 4)

- **طباعة الاستمارة** — استمارة ورقية بالبيانات + QR
- **إنشاء الكارت** — كارت النشاط الرياضي (يعمل فقط بعد اكتمال الدفع)
- **طباعة الكارت** — بعد إنشائه

### النتيجة

اللاعب مسجل بحالة `completed` وينتظر **التقييم الفني من المدرب**.

---

## 2. تقييم المدرب — تعيين لاعب في مجموعة

### الهدف

المدرب يقيّم اللاعب فنياً ويعيّنه في المجموعة المناسبة.

### المسار

`/sa/coach-assessment`

### من يستخدمه

المدرب أو الإدارة (صلاحية `sa.coach_assessment.view` + `sa.coach_assessment.manage`)

### الخطوات

#### خطوة 1: فتح شاشة التقييم

1. من الشريط الجانبي ← **تقييم اللاعبين** (تحت قسم "── تقييم المدربين ──")
2. تظهر قائمة اللاعبين المنتظرين للتقييم
3. إذا المدرب مرتبط بنشاط معين (مثلاً كاراتيه)، يرى فقط اللاعبين اللي اختاروا الكاراتيه
4. يمكن فلترة بنشاط معين من القائمة المنسدلة

#### خطوة 2: تقييم لاعب

1. اضغط **تقييم** بجانب اسم اللاعب
2. تفتح صفحة التقييم:
   - بيانات اللاعب + الأنشطة المطلوبة ظاهرة
   - اختر **المستوى**: مبتدئ / متوسط / متقدم
   - اكتب **ملاحظات** (اختياري)
   - اختر **المجموعة** من القائمة (مفلترة حسب أنشطة اللاعب المختارة)
3. اضغط **تأكيد التقييم والتعيين**

### ماذا يحدث بعد التأكيد

- اللاعب يُضاف للمجموعة بحالة `active`
- يُنشأ اشتراك شهري بمبلغ المجموعة (عضو/غير عضو)
- **يُرسل طلب دفع للخزينة** (اشتراك شهري) — يظهر في طابور الدفع
- حالة التسجيل تتحول إلى `assessed`

### الدورة الكاملة: تقييم ← خزينة

1. المدرب يقيّم ويعيّن ← تسجيل "assessed"
2. طلب دفع اشتراك يظهر في الخزينة
3. اللاعب يروح يدفع
4. الخزينة تحصّل ← الاشتراك يُعلّم "paid" تلقائياً

---

## 3. تعيين مدربين على المجموعات

### الهدف

إضافة مدرب أساسي + مدربين مساعدين على مجموعة واحدة.

### المسار

`/sa/groups` ← إنشاء أو تعديل مجموعة

### الخطوات

#### عند إنشاء مجموعة جديدة

1. اذهب إلى **المجموعات** ← **إنشاء مجموعة**
2. اختر البرنامج + الاسم + السعة
3. **المدرب الأساسي** — اختره من القائمة (مطلوب)
4. **مدربين مساعدين** — اختر واحد أو أكثر (اختياري)
5. احفظ

#### تعديل مدربين مجموعة قائمة

1. اذهب إلى **المجموعات** ← اختر المجموعة ← **تعديل**
2. غيّر المدرب الأساسي أو أضف/أزل مساعدين
3. احفظ

### الأدوار

- `primary` — المدرب الأساسي (واحد فقط)
- `assistant` — مدرب مساعد (عدد غير محدود)

---

## 4. حضور التدريب

### الهدف

تسجيل حضور/غياب اللاعبين في التدريبات اليومية.

### المسار

`/sa/training-attendance`

### من يستخدمه

المدرب أو الإدارة (صلاحية `sa.attendance.manage`)

### الخطوات

#### خطوة 1: اختيار اليوم والمجموعة

1. من الشريط الجانبي ← **حضور التدريب**
2. اختر التاريخ (افتراضي: اليوم)
3. تظهر المجموعات المجدولة لهذا اليوم (حسب `sa_group_schedule`)
4. اضغط **تسجيل حضور** بجانب المجموعة

#### خطوة 2: تسجيل الحضور

1. تظهر قائمة لاعبي المجموعة النشطين
2. لكل لاعب اختر: **حاضر** / **غائب** / **معذور** / **متأخر** / **تعويضي**
3. اضغط **حفظ**

### التنبيهات الآلية

- إذا تجاوز لاعب حد الغياب (افتراضي 5 مرات/شهر) ← SMS لولي الأمر تلقائياً
- يمكن رؤية التقرير من `/sa/training-attendance/report`

### معلومات المجموعة

- كل مجموعة تظهر: اسمها + المدرب + عدد اللاعبين
- من صفحة المجموعة (`/sa/groups/{id}`) يمكن رؤية:
  - المدرب الأساسي + المساعدين
  - قائمة اللاعبين + حالة كل واحد
  - جدول التدريب الأسبوعي

---

## 5. مدربين السباحة (Freelance) — حجز حارات

### الهدف

إدارة مدربين السباحة المستقلين وحجز حارات لهم.

### المسار

`/sa/swimming/coaches` — إدارة المدربين
`/sa/mirror/pool/{facility_id}` — مراية حمام السباحة (حجز الحارات)

### إضافة مدرب سباحة

1. من الشريط الجانبي ← **مدربين السباحة** (تحت قسم "── السباحة ──")
2. اضغط **إضافة مدرب**
3. أدخل: الاسم + الرقم القومي + الهاتف + نوع التعاقد (freelance/staff/contract)
4. يُربط تلقائياً بنشاط "السباحة"

### حجز حارة لمدرب Freelance

1. اذهب إلى **المراية** ← **مراية حمام السباحة** (أو `/sa/mirror/pool/{id}`)
2. تظهر شبكة الحارات × المواعيد (grid)
3. حدد الخانات (حارة + وقت) المطلوبة
4. اختر نوع الحجز: **hourly**
5. اختر المجموعة/المدرب
6. احفظ

### التحقق من التوفر

- الشبكة تظهر الخانات المحجوزة بألوان مختلفة:
  - أخضر = تدريب (training)
  - أزرق = حجز ساعي (hourly) — freelance
  - رمادي = مقفول (blocked)
  - أحمر = صيانة (maintenance)
- لا يمكن حجز خانة محجوزة بالفعل (unique constraint)
- المراية في real-time — كل حجز يظهر فوراً

### عدد أفراد الحارة

- نظام Open Access (`open_access`) فيه `max_occupancy` لكل منطقة
- إذا المنطقة وصلت الحد الأقصى → لا يمكن إصدار تذاكر إضافية
- تذاكر السباحة (`/sa/pool-tickets`) تتحكم في الإشغال

### تذاكر الدخول (Booking Passes)

- عند حجز ساعي بنمط "passes" ← تُنشأ تذاكر دخول لكل فرد
- رقم التذكرة: `{رقم_الحجز}-P01`, `P02`, ...
- عند البوابة: يُمسح رقم التذكرة ← تُعلّم "مستخدمة"
- تذاكر غير مستخدمة تنتهي صلاحيتها بعد الحجز

---

## 6. الشهادات الطبية

### الهدف

كل لاعب يحتاج شهادة طبية سارية للتدريب. بدونها يُوقف الاشتراك.

### المسار

`/medical-board` — لجنة الفحص الطبي

### أنواع الشهادات

| النوع                 | المدة  |
| --------------------- | ------ |
| ترفيهي (recreational) | 12 شهر |
| أكاديمي (academy)     | 6 شهور |
| دولي (international)  | 3 شهور |

### الدورة الكاملة

#### خطوة 1: تقديم الشهادة

- من صفحة اللاعب ← رفع شهادة طبية (صورة/PDF)
- أو من تطبيق الموبايل (Player API)
- الحالة: `pending`

#### خطوة 2: المراجعة والاعتماد

1. اذهب إلى **لجنة الفحص الطبي** (`/medical-board`)
2. تظهر الشهادات المنتظرة من كلا المصدرين (عضوية + نشاط رياضي)
3. لكل شهادة:
   - **اعتماد** — يحدد تاريخ الانتهاء ← `medical_status = fit`
   - **رفض** — `medical_status = unfit` ← اللاعب لا يمكنه التدريب

#### خطوة 3: التأثير على الاشتراكات

- عند توليد اشتراكات شهرية ← يتم التحقق من الشهادة الطبية
- إذا منتهية: الاشتراك يُنشأ لكن `medical_verified = 0`

#### خطوة 4: التذكيرات والإيقاف (Cron — يومياً)

- **قبل 30 يوم من الانتهاء** ← تذكير SMS
- **بعد الانتهاء** ← `medical_status = expired`
- **بعد انتهاء فترة السماح** ← إيقاف التسجيل في المجموعة + إنقاص عداد المجموعة

---

## 7. تجديد الاشتراك الشهري

### الهدف

كل أول شهر يُنشأ اشتراك جديد لكل لاعب نشط في مجموعاته.

### المسار

`/sa/subscriptions` → زر **توليد اشتراكات**

### من يستخدمه

الإدارة (صلاحية `sa.subscription.generate`)

### الخطوات

#### خطوة 1: توليد الاشتراكات

1. اذهب إلى **الاشتراكات** (`/sa/subscriptions`)
2. اضغط **توليد اشتراكات**
3. اختر الشهر (مثلاً `2026-08`)
4. اضغط **توليد**

#### ماذا يحدث

- يتم جلب كل لاعب نشط (`sa_group_players.status = active`) في مجموعة نشطة
- يُتحقق من عدم وجود اشتراك مسبق لنفس الشهر
- يُتحقق من حالة الشهادة الطبية
- يُنشأ سجل `sa_subscriptions` بحالة `unpaid`
- المبلغ حسب نوع اللاعب:
  - عضو ← `monthly_fee_member` (من البرنامج)
  - غير عضو ← `monthly_fee_nonmember`
- لو أول شهر للاعب ودخل بعد يوم 15 ← المبلغ ينخفض للنصف

#### خطوة 2: التحصيل

- من شاشة الاشتراكات ← فلتر حسب الشهر/المجموعة/حالة الدفع
- اضغط على الاشتراك ← **تحصيل**
- اختر طريقة الدفع (كاش/فيزا/شيك/تحويل)
- أو **إعفاء** مع سبب

### الاشتراك المتأخر

- Cron يومي يعلّم الاشتراكات المنتهية (`period_end < today`) بحالة `overdue`
- يرسل SMS لولي الأمر

---

## 8. دورة الدفع بعد تعيين المدرب — من التقييم للخزينة

### الهدف

بعد ما المدرب يعيّن لاعب في مجموعة ← اللاعب يروح الخزينة يدفع اشتراك الشهر.

### الدورة

```
┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  المدرب يقيّم   │────▶│  طلب دفع يُنشأ  │────▶│  يظهر في الخزينة│
│  ويعيّن مجموعة  │     │  (sports_subscription) │  │  (طابور الدفع)  │
└─────────────────┘     └──────────────────┘     └─────────────────┘
                                                          │
                                                          ▼
┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  الاشتراك paid  │◀────│  Event يُطلق     │◀────│  الخزينة تحصّل  │
│  تلقائياً       │     │  payment_request  │     │  المبلغ         │
└─────────────────┘     │  .completed       │     └─────────────────┘
                        └──────────────────┘
```

### الخطوات التفصيلية

1. **المدرب** يفتح `/sa/coach-assessment` ← يقيّم لاعب ← يختار مجموعة ← يأكد
2. **النظام** ينشئ:
   - تسجيل في المجموعة (`sa_group_players`)
   - اشتراك شهري (`sa_subscriptions`) بحالة `unpaid`
   - طلب دفع (`payment_requests`) بنوع `sports_subscription`
3. **طابور الخزينة** — الطلب يظهر في خزينة النشاط الرياضي (SUB_SA)
4. **اللاعب/ولي الأمر** يذهب للخزينة ← يدفع المبلغ
5. **الخزينة** تحصّل ← event `payment_request.completed` يُطلق
6. **Event Listener** (`SaEventListenerService::handleSubscriptionPaid`) يعلّم الاشتراك `paid`

### ملاحظة مهمة

اللاعب يكون نشط في المجموعة فوراً بعد التقييم (لا ينتظر الدفع). الدفع يحصل بالتوازي ولا يمنع الحضور.

---

## ملخص المسارات

| الخطوة                   | من يفعلها       | أين                         |
| ------------------------ | --------------- | --------------------------- |
| تسجيل لاعب جديد          | مكتب الاشتراكات | `/sa/registration`          |
| دفع رسوم التسجيل         | الخزينة         | طابور الدفع                 |
| تقييم فني + تعيين مجموعة | المدرب          | `/sa/coach-assessment`      |
| دفع اشتراك شهري          | الخزينة         | طابور الدفع                 |
| تسجيل حضور يومي          | المدرب          | `/sa/training-attendance`   |
| توليد اشتراكات شهرية     | الإدارة         | `/sa/subscriptions` → توليد |
| اعتماد شهادة طبية        | لجنة الفحص      | `/medical-board`            |
| حجز حارة سباحة           | الإدارة         | `/sa/mirror/pool/{id}`      |
| إدارة مدربين سباحة       | الإدارة         | `/sa/swimming/coaches`      |
| تذكرة نشاط (مكتب الخدمة) | مكتب الخدمة     | `/sa/service-desk#ticket`   |
| تذكرة لعبة ترفيهية       | مكتب الخدمة     | `/sa/games/{id}/sessions/{sid}` |
| حجز ملعب (معالج الحجز)   | مكتب الخدمة     | `/sa/booking-wizard`        |

---

## 9. تذكرة نشاط — مكتب الخدمة (دخول سريع)

### الهدف

إصدار تذكرة دخول سريعة لشخص (عضو أو ضيف) لأي نشاط ترفيهي بدون حجز مسبق. مناسب للأنشطة اللحظية مثل: سباحة حرة، بنج بونج، بلاي ستيشن، إلخ.

### المسار

`/sa/service-desk` ← تبويب **تذكرة نشاط**

### من يستخدمه

موظف مكتب الخدمة (صلاحية `sa.registration.manage`)

### الخطوات

#### خطوة 1: البحث (اختياري)

1. أدخل **الرقم القومي** في شريط البحث أعلى الصفحة
2. اضغط **بحث**
3. إذا كان عضو ← تظهر بيانات العضوية + اسمه + كارنيه (إن وُجد)
4. يتم ملء اسم الضيف تلقائياً من بيانات العضو

#### خطوة 2: ملء البيانات

1. اختر **نوع النشاط** من القائمة:
   - سباحة حرة (`free_swim`)
   - حجز ملعب (`court_booking`)
   - ترفيه (`recreation`)
   - بنج بونج (`ping_pong`)
   - بولينج (`bowling`)
   - بلاي ستيشن (`playstation`)
   - تنس (`tennis`)
   - بادل (`paddle`)
   - جيم (`gym`)
2. أدخل **اسم الضيف** (يُملأ تلقائياً لو عملت بحث)
3. حدد **عدد الأشخاص** (افتراضي: 1)
4. أدخل **المبلغ** المطلوب (يدوي — مثلاً 50 أو 100 ج.م)
5. اختر **المرفق** (اختياري — حمام سباحة، ملعب تنس، إلخ)
6. ملاحظات (اختياري)

#### خطوة 3: الإصدار

1. اضغط **إصدار التذكرة**
2. يظهر تأكيد "تم إصدار التذكرة بنجاح" ✓

### ماذا يحدث داخلياً

- يُنشأ سجل في `carnet_guest_entries` بالبيانات المُدخلة
- إذا العضو عنده **كارنيه ضيافة** ← يُخصم من رصيد دعواته تلقائياً
- إذا ما عندوش كارنيه ← التذكرة تُسجّل بدون خصم (الدفع مباشر)
- المبلغ يُسجّل كـ `amount_paid` مباشرة (لا يذهب لطابور الدفع)

### الحالات الخاصة

| الحالة | السلوك |
|--------|--------|
| عضو بكارنيه + رصيد متاح | يُخصم من رصيد الكارنيه |
| عضو بكارنيه + رصيد منتهي | خطأ: "تم استنفاذ جميع الدعوات" |
| عضو بدون كارنيه | يمر عادي — المبلغ يُدفع مباشر |
| ضيف (غير عضو) | لا بحث مسبق — أدخل الاسم يدوي |
| عضو + رصيد كارنيه = 2 أو أقل | تنبيه "رصيد منخفض" يُطلق |

### متى تستخدم هذه الطريقة

- دخول سريع لنشاط واحد (لا حاجة لجلسة أو حجز)
- ضيوف عابرين (مرة واحدة)
- تسجيل دخول سريع لأنشطة بسيطة (جيم، بنج بونج)

### متى لا تستخدمها

- حجز ملعب بوقت محدد ← استخدم **معالج الحجز** (القسم 11)
- بولينج/بلاي ستيشن مع تتبع جلسة وسعة ← استخدم **تذكرة لعبة ترفيهية** (القسم 10)

---

## 10. تذكرة لعبة ترفيهية — بولينج / بلاي ستيشن / إلخ

### الهدف

إدارة الألعاب الترفيهية بنظام الجلسات: فتح جلسة ← إصدار تذاكر للاعبين ← تتبع السعة ← إغلاق الجلسة. كل تذكرة تُرسل للخزنة الفرعية في طابور الدفع.

### المسار

`/sa/games` — قائمة الألعاب
`/sa/games/{id}` — تفاصيل لعبة + جلساتها
`/sa/games/{id}/sessions/{sid}` — جلسة محددة + إصدار تذاكر

### من يستخدمه

مشرف الألعاب (صلاحية `sa.game.view` + `sa.game.manage`)

### التسلسل الكامل

```
┌──────────────┐    ┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│  إنشاء لعبة  │───▶│  فتح جلسة   │───▶│ إصدار تذاكر │───▶│ إنهاء الجلسة │
│  (مرة واحدة) │    │  (يومياً)    │    │  (لكل لاعب)  │    │  (بعد اللعب) │
└──────────────┘    └──────────────┘    └──────────────┘    └──────────────┘
                                               │
                                               ▼
                                    ┌──────────────────────┐
                                    │ طلب دفع → الخزنة    │
                                    │ الفرعية (طابور الدفع)│
                                    └──────────────────────┘
```

### خطوة 1: إنشاء لعبة (مرة واحدة)

1. اذهب إلى `/sa/games` ← **إنشاء لعبة**
2. أدخل:
   - **اسم اللعبة** (عربي) — مثلاً "بولينج" أو "بلاي ستيشن"
   - **اسم إنجليزي** (اختياري)
   - **نوع التسعير**: `per_game` (سعر ثابت للمباراة) أو `per_hour` (سعر × ساعات الجلسة)
   - **سعر الأعضاء** (fee_member)
   - **سعر غير الأعضاء** (fee_nonmember)
   - **أقصى عدد لاعبين** في الجلسة
   - **مدة الجلسة** بالدقائق (افتراضي 60)
   - **المرفق** المرتبط (اختياري — مثلاً "صالة البولينج")
3. احفظ

> **مثال**: بولينج → per_game, fee_member=650, fee_nonmember=900, max_players=6

### خطوة 2: فتح جلسة جديدة (يومياً)

1. من صفحة اللعبة (`/sa/games/{id}`)
2. أدخل: **التاريخ** + **وقت البدء** + **وقت الانتهاء**
3. اضغط **إنشاء جلسة**
4. الجلسة تُنشأ بحالة `open`

### خطوة 3: إصدار تذاكر (لكل لاعب)

1. ادخل على الجلسة (`/sa/games/{id}/sessions/{sid}`)
2. في نموذج "إصدار تذكرة":
   - أدخل **اسم اللاعب/الضيف**
   - اختر **النوع**: ضيف / عضو / غير عضو
3. اضغط **إصدار تذكرة**
4. النظام:
   - يحسب الرسوم تلقائياً حسب نوع التسعير ونوع اللاعب
   - يُنشئ تذكرة برقم فريد (GT-XXXXXXXX)
   - **يُنشئ طلب دفع** يظهر في طابور الخزنة الفرعية
   - يزيد عداد اللاعبين في الجلسة
   - إذا الجلسة امتلأت ← تتحول لحالة `full` تلقائياً
5. تظهر رسالة: "تم إصدار تذكرة GT-XXXXXXXX بنجاح — في انتظار التحصيل من الخزنة"

### خطوة 4: إدارة حالة الجلسة

من صفحة الجلسة تتوفر أزرار:

| الزر | الشرط | الأثر |
|------|-------|-------|
| **بدء الجلسة** | حالة = `open` | تتحول إلى `in_progress` |
| **إنهاء الجلسة** | حالة = `open`/`in_progress`/`full` | تتحول إلى `completed` |
| **إلغاء** | حالة ≠ `completed` | تتحول إلى `cancelled` |

> **ملاحظة**: يمكن إصدار تذاكر أثناء حالة `open` أو `in_progress`.

### حساب الرسوم

| نوع التسعير | الحساب |
|-------------|--------|
| `per_game` | fee_member أو fee_nonmember (مبلغ ثابت) |
| `per_hour` | fee × عدد ساعات الجلسة (مقرّب لأعلى) |

**مثال**: بولينج per_game, fee_nonmember=900 ← كل تذكرة لغير عضو = 900 ج.م

**مثال**: بلاي ستيشن per_hour, fee_member=50, جلسة من 14:00-16:00 (ساعتين) ← 50×2 = 100 ج.م

### دورة الدفع

```
إصدار تذكرة ← طلب دفع (payment_requests) بنوع sa_game_ticket
                                    │
                                    ▼
                    يظهر في الخزنة الفرعية (طابور الدفع)
                                    │
                                    ▼
                    الخزينة تحصّل ← event: payment_request.completed
                                    │
                                    ▼
                    التذكرة تتحول payment_status = 'paid' تلقائياً
```

### الحالات الخاصة

| الحالة | السلوك |
|--------|--------|
| الجلسة ممتلئة | لا يمكن إصدار تذاكر إضافية |
| الجلسة مكتملة أو ملغية | لا يمكن إصدار تذاكر |
| رسوم = 0 | التذكرة تُنشأ بحالة `paid` مباشرة (بدون طلب دفع) |
| تذكرة لعضو | يستخدم `fee_member` |
| تذكرة لضيف أو غير عضو | يستخدم `fee_nonmember` |

---

## 11. حجز ملعب/مرفق — معالج الحجز

### الهدف

حجز مرفق (ملعب تنس، كورت بادل، ملعب كرة، جيم، إلخ) لوقت محدد مع حساب السعر التلقائي وإرسال طلب الدفع للخزنة الفرعية.

### المسار

`/sa/booking-wizard` — معالج حجز تفاعلي (4 خطوات)

### من يستخدمه

موظف مكتب الخدمة أو أي مستخدم بصلاحية `sa.booking_wizard.use`

### التسلسل الكامل

```
┌──────────────┐    ┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│  1. الشخص    │───▶│  2. المرفق   │───▶│  3. الموعد   │───▶│  4. التأكيد  │
│  (بحث/يدوي) │    │  (اختيار)    │    │  (التوقيت)   │    │  → الخزنة    │
└──────────────┘    └──────────────┘    └──────────────┘    └──────────────┘
```

### خطوة 1: تحديد الشخص

1. ابحث بـ **رقم العضوية** أو **الرقم القومي** أو **الاسم**
2. إذا وُجد عضو ← يُملأ الاسم والنوع تلقائياً (`booker_type = member`)
3. إذا لم يُوجد ← أدخل الاسم يدوياً (`booker_type = guest`)
4. يمكن أيضاً إدخال اسم مؤسسة (`organization`)

### خطوة 2: اختيار المرفق

1. تظهر جميع الوحدات المتاحة مجمّعة حسب المرفق
2. كل وحدة تظهر:
   - اسمها (مثلاً "كورت 1")
   - نمط الحجز: `exclusive` (حجز كامل) أو `shared` (سعة مشتركة)
   - السعة القصوى
3. اضغط على الوحدة المطلوبة

### خطوة 3: اختيار التاريخ والوقت

1. اختر **التاريخ** من التقويم
2. تظهر **شبكة المواعيد** (time grid) مقسمة بالساعة:
   - 🟢 أخضر = متاح
   - 🟡 أصفر = جزئي (shared فيه أماكن)
   - 🔴 أحمر = محجوز بالكامل
   - ⚫ أسود = مغلق (blackout)
3. اضغط على الخانة الزمنية المطلوبة
4. يظهر **معاينة السعر** مباشرة:
   - سعر الشخص × عدد المشاركين × عدد الساعات = الإجمالي
   - نوع الفترة (peak/off-peak)

### خطوة 4: التأكيد والإرسال للخزنة

1. تظهر ملخص الحجز:
   - الشخص + المرفق + الوحدة + التاريخ + الوقت + عدد المشاركين + المبلغ
2. اضغط **تأكيد وإرسال للخزينة**
3. النظام:
   - يُنشئ حجز في `sa_bookings` بحالة `payment_status = pending`
   - يُنشئ طلب دفع (`payment_requests`) بنوع `hourly_booking`
   - يظهر طلب الدفع في **طابور الخزنة الفرعية**
4. تظهر شاشة النجاح: "تم الحجز — في انتظار التحصيل من الخزينة"

### نظام التسعير

السعر يُحسب تلقائياً بناءً على:

1. **فترة زمنية** (Time Bracket) — يحدد هل الوقت peak أو عادي
2. **قاعدة التسعير** (Pricing Rule) — السعر لكل شخص حسب الوحدة + الفترة + نوع الحاجز

| العامل | كيف يؤثر |
|--------|----------|
| نوع الحاجز (عضو/ضيف/مؤسسة) | سعر مختلف لكل فئة |
| الفترة (peak/off-peak) | Peak أغلى |
| عدد المشاركين | المبلغ × العدد |
| مدة الحجز (ساعات) | المبلغ × الساعات |

**المعادلة**: `الإجمالي = سعر_الشخص × عدد_المشاركين × عدد_الساعات`

### فحص التوفر (Availability Check)

النظام يتحقق تلقائياً قبل أي حجز من:

1. **الوحدة نشطة** — غير مؤرشفة
2. **لا يوجد إغلاق** (blackout) — على مستوى المرفق أو الوحدة
3. **نمط exclusive**: لا يوجد حجز آخر يتداخل مع نفس الوقت
4. **نمط shared**: مجموع الأماكن المحجوزة + المطلوبة ≤ السعة القصوى
5. **تذاكر السباحة**: إذا المرفق حمام سباحة ← يتحقق من شبكة الحارات

### دورة الدفع

```
حجز جديد ← طلب دفع بنوع hourly_booking
                    │
                    ▼
    يظهر في الخزنة الفرعية (طابور الدفع)
                    │
                    ▼
    الخزينة تحصّل ← event: payment_request.completed
                    │
                    ▼
    الحجز يتحول payment_status = 'paid' تلقائياً
```

### بعد الحجز

| الإجراء | المسار | الشرط |
|---------|--------|-------|
| إلغاء | `/sa/bookings/{id}/cancel` | قبل وقت البدء |
| تأجيل | `/sa/bookings/{id}/postpone` | تغيير التاريخ/الوقت |
| تسجيل دخول | `/sa/bookings/{id}/checkin` | عند الحضور |
| تسجيل خروج | `/sa/bookings/{id}/checkout` | عند المغادرة |

### الحالات الخاصة

| الحالة | السلوك |
|--------|--------|
| حجز exclusive + يوجد حجز آخر | خطأ: "الوقت غير متاح" |
| حجز shared + سعة ممتلئة | خطأ: "متبقي X أماكن فقط" |
| تاريخ مغلق (blackout) | الخانة تظهر مقفلة ولا يمكن الضغط عليها |
| مبلغ = 0 | الحجز يُنشأ بحالة `paid` مباشرة |
| إلغاء حجز مدفوع (خلال 24 ساعة) | يُلغى طلب الدفع تلقائياً |

---

## 12. متى تستخدم كل نظام — دليل الاختيار

### للدخول السريع (بدون وقت محدد):

→ **مكتب الخدمة — تذكرة نشاط** (القسم 9)

مناسب لـ: جيم، بنج بونج، سباحة حرة، أي نشاط "ادخل الآن"

### للألعاب الترفيهية (بولينج، بلاي ستيشن):

→ **تذاكر الألعاب** (القسم 10)

مناسب لـ: أي نشاط بسعة محدودة + جلسة بوقت + تسعير تلقائي + تحصيل عبر الخزنة

### لحجز ملعب/مرفق بوقت محدد:

→ **معالج الحجز** (القسم 11)

مناسب لـ: ملاعب تنس، بادل، سكواش، كرة قدم، أي شيء محجوز بالساعة

### جدول المقارنة

| المعيار | تذكرة نشاط (§9) | تذكرة لعبة (§10) | حجز ملعب (§11) |
|---------|-----------------|------------------|----------------|
| يحتاج وقت محدد؟ | لا | نعم (جلسة) | نعم (slot) |
| يتتبع السعة؟ | لا | نعم (max_players) | نعم (availability) |
| يذهب للخزنة؟ | لا (مباشر) | نعم ✓ | نعم ✓ |
| يُحسب السعر تلقائياً؟ | لا (يدوي) | نعم ✓ | نعم ✓ |
| يدعم الأعضاء + الضيوف؟ | نعم | نعم | نعم |
| يحتاج كارنيه؟ | اختياري | لا | لا |
| جدول بصري (grid)؟ | لا | لا | نعم ✓ |

---

## 13. إعداد الألعاب الترفيهية — دليل المشرف

### لإضافة لعبة جديدة (مثلاً: بلاي ستيشن)

1. اذهب إلى `/sa/games/create`
2. أدخل:
   - اسم: "بلاي ستيشن"
   - نوع التسعير: `per_hour` (أو `per_game` حسب السياسة)
   - سعر أعضاء: 50 ج.م
   - سعر غير أعضاء: 75 ج.م
   - أقصى عدد: 4 لاعبين
   - مدة: 60 دقيقة
3. احفظ

### العمليات اليومية

1. **الصباح**: فتح جلسات جديدة للألعاب المطلوبة
2. **عند الطلب**: إصدار تذاكر لكل لاعب يأتي
3. **نهاية اليوم**: إنهاء/إلغاء الجلسات المفتوحة

### نصائح

- يمكن فتح عدة جلسات لنفس اللعبة في نفس اليوم (مثلاً جلسة صباحية + مسائية)
- الجلسة المكتملة لا يمكن إلغاؤها
- إذا لاعب لم يدفع ← التذكرة تبقى `unpaid` والخزنة تتابع التحصيل

---

## 14. إعداد المرافق والتسعير — دليل المشرف

### لإضافة مرفق جديد

1. `/sa/facilities/create` ← أدخل الاسم + النوع (pool/court/pitch/gym/track/multipurpose)
2. أضف وحدات: `/sa/facilities/{id}/units/create`
   - مثلاً: "كورت بادل 1", booking_mode=exclusive, max_capacity=4
3. أضف فترات زمنية: `/sa/facilities/{id}/brackets`
   - مثلاً: فترة صباحية 06:00-12:00 (off-peak), فترة مسائية 16:00-22:00 (peak)
4. أضف قواعد تسعير: `/sa/pricing/rules`
   - مثلاً: كورت بادل + peak + member = 200 ج.م/شخص/ساعة

### إغلاق مرفق مؤقتاً (Blackout)

1. من صفحة المرفق ← **إضافة فترة إغلاق**
2. حدد: التاريخ من/إلى + السبب
3. خلال هذه الفترة لن يظهر المرفق كمتاح في المعالج
