# 09 — محرك التسعير

## نظرة عامة

**لا توجد أسعار ثابتة.** كل سعر يُحسب لحظياً عند البيع/التسجيل بناءً على:
1. السعر الأساسي
2. قواعد الخصم (13 نوع)
3. العروض والكوبونات
4. حدود الخصم

بعد الحساب، يُجمّد السعر على الفاتورة ولا يتغير أبداً.

---

## الشاشات المنفذة

### 1. الأسعار الأساسية (`/pricing/base-prices`)

**من يراها:** من لديه صلاحية `pricing.list`

**القائمة:**
| العمود | الوصف |
|--------|-------|
| العنصر | البرنامج أو المنتج |
| الفرع | branch (أو الكل) |
| السعر (أعضاء) | member_price ج.م |
| السعر (غير أعضاء) | non_member_price ج.م |
| من تاريخ | effective_from |
| إلى تاريخ | effective_to |
| مفعّل | is_active |

**إنشاء/تعديل (`/pricing/base-prices/create`, `/pricing/base-prices/{id}/edit`):**
| الحقل | النوع | مطلوب |
|--------|------|-------|
| النوع المسعّر | select | ✓ | program / product |
| العنصر | select | ✓ | |
| الفرع | select | ✗ | كل الفروع إذا فارغ |
| سعر الأعضاء | money | ✓ | |
| سعر غير الأعضاء | money | ✗ | |
| من تاريخ | date | ✓ | |
| إلى تاريخ | date | ✗ | |
| مفعّل | toggle | — | |

**قاعدة:** إذا لم يُوجد سعر أساسي نشط → البيع/التسجيل يُرفض مع رسالة "لا يوجد سعر محدد".

---

### 2. قواعد التسعير (`/pricing/rules`)

**من يراها:** من لديه صلاحية `pricing.list`

**القائمة:**
| العمود | الوصف |
|--------|-------|
| الاسم | name_ar |
| النوع | rule_type |
| التعديل | adjustment_type + قيمة |
| الأولوية | priority |
| قابل للتراكم | stackable ✓/✗ |
| مفعّل | is_active |

---

### 3. إنشاء قاعدة — ويزارد (`/pricing/rules/wizard`)

**خطوات:**
1. اختيار نوع القاعدة (من 13 نوع)
2. إعداد الشروط
3. تحديد التعديل (نسبة أو مبلغ ثابت)
4. إعدادات متقدمة (أولوية، تراكم، حدود)

---

### 4. إنشاء/تعديل قاعدة — نموذج (`/pricing/rules/create`, `/pricing/rules/{id}/edit`)

**الحقول:**
| الحقل | النوع | مطلوب | ملاحظات |
|--------|------|-------|---------|
| الاسم بالعربية | text | ✓ | |
| الاسم بالإنجليزية | text | ✗ | |
| نوع القاعدة | select | ✓ | 13 نوع |
| نوع التعديل | select | ✓ | percentage_discount, fixed_discount, fixed_price, percentage_increase |
| قيمة التعديل | number | ✓ | |
| الشروط | JSON/dynamic | ✓ | حسب نوع القاعدة |
| الأولوية | number | ✓ | رقم أقل = يُطبّق أولاً |
| قابل للتراكم | toggle | — | |
| الحد الأقصى للخصم | number | ✗ | نسبة % |
| من تاريخ | date | ✗ | |
| إلى تاريخ | date | ✗ | |
| الفرع | select | ✗ | |
| مفعّل | toggle | — | |

---

### 5. العروض والكوبونات (`/pricing/promotions`)

**القائمة:**
| العمود | الوصف |
|--------|-------|
| الكود | coupon_code |
| الاسم | name_ar |
| نوع الخصم | percentage / fixed |
| القيمة | discount_value |
| الاستخدام | used_count / max_uses |
| من - إلى | valid_from — valid_to |
| مفعّل | is_active |

**إنشاء عرض (`/pricing/promotions/create`):**
| الحقل | النوع | مطلوب |
|--------|------|-------|
| كود الكوبون | text | ✓ | فريد |
| الاسم بالعربية | text | ✓ | |
| نوع الخصم | select | ✓ | percentage / fixed_amount |
| قيمة الخصم | number | ✓ | |
| تاريخ البداية | date | ✗ | |
| تاريخ النهاية | date | ✗ | |
| الحد الأقصى للاستخدام | number | ✗ | |
| استخدام لكل مشترك | number | ✗ | |
| الحد الأدنى للمبلغ | money | ✗ | |
| مفعّل | toggle | — | |

---

### 6. فاحص الكوبون (Coupon Validator)

**المكوّن:** `CouponValidator` — يُستخدم داخل نقطة البيع والفواتير

**8 تحققات:**
1. هل الكود موجود؟
2. هل مفعّل؟
3. هل في فترة الصلاحية؟
4. هل تجاوز الحد الأقصى للاستخدام الكلي؟
5. هل هذا المشترك استخدمه أكثر من المسموح؟
6. هل المبلغ يتجاوز الحد الأدنى المطلوب؟
7. هل ينطبق على هذا الفرع؟
8. هل ينطبق على هذا البرنامج/المنتج؟

---

## أنواع قواعد التسعير (13 نوع)

| النوع | الشرح | مثال |
|-------|-------|------|
| age | حسب عمر المشترك | أقل من 6 سنوات: خصم 20% |
| membership_duration | حسب مدة العضوية | عضو لأكثر من سنة: خصم 10% |
| family_size | حسب عدد الأبناء | 3 أبناء فأكثر: خصم 15% |
| sibling_order | حسب ترتيب الأخ | الأخ الثاني: 10%، الثالث: 20% |
| classification | حسب تصنيف المشترك | VIP: خصم 25% |
| enrollment_timing | حسب توقيت التسجيل | تسجيل مبكر (قبل بدء الموسم): 10% |
| enrollment_volume | حسب عدد البرامج | مسجّل في 3 برامج+: خصم 15% |
| seasonal | موسمي | صيف: خصم 30% |
| gender | حسب الجنس | إناث: خصم 10% (تحفيز) |
| branch | حسب الفرع | فرع التجمع: خصم افتتاح 20% |
| day_time | حسب الوقت | حصص صباحية: أرخص بـ 200 ج.م |
| loyalty | ولاء | مشترك 3 سنوات: 25% |
| custom | مخصص | أي شرط آخر |

---

## أنواع التعديل

| النوع | المعنى | مثال |
|-------|--------|------|
| percentage_discount | خصم نسبي | 15% من السعر الحالي |
| fixed_discount | خصم ثابت | 200 ج.م |
| fixed_price | سعر ثابت (يحل محل الأصلي) | 800 ج.م بغض النظر |
| percentage_increase | زيادة نسبية | +10% (حصة خاصة) |

---

## خوارزمية حساب السعر (10 خطوات)

```mermaid
flowchart TD
    A[1. إيجاد السعر الأساسي] --> B{وُجد؟}
    B -->|لا| C[✗ رفض: لا يوجد سعر]
    B -->|نعم| D[2. جمع القواعد المطبقة]
    D --> E[3. تقييم الشروط ضد بيانات المشترك]
    E --> F[4. تصفية غير المتراكمة — الأعلى أولوية يفوز]
    F --> G[5. تطبيق القواعد بترتيب الأولوية]
    G --> H[6. تطبيق حد أقصى لكل قاعدة]
    H --> I[7. تطبيق عرض/كوبون]
    I --> J[8. تطبيق حد أقصى عام - افتراضي 50%]
    J --> K[9. فحص: لا يكون سالب]
    K --> L[10. إرجاع النتيجة النهائية]
```

---

## التراكم vs عدم التراكم

**قابل للتراكم (stackable=true):**
- يُطبّق مع قواعد أخرى (تراكمي)
- مثال: خصم العمر 10% + خصم الأخ الثاني 10% = 20%

**غير قابل للتراكم (stackable=false):**
- إذا تعارض مع قاعدة غير قابلة للتراكم أخرى → الأعلى أولوية فقط
- مثال: خصم VIP 25% (غير متراكم) vs خصم موسمي 30% (غير متراكم) → 30% فقط (الأعلى)
- يمكن أن يتراكم مع قواعد متراكمة أخرى

---

## أمثلة عملية

### مثال 1: حساب سعر بسيط
> - السعر الأساسي: 1500 ج.م
> - لا توجد قواعد مطبقة
> - **النتيجة: 1500 ج.م**

### مثال 2: خصم عمر
> - السعر الأساسي: 1500 ج.م
> - قاعدة: عمر < 6 سنوات → خصم 20%
> - المشترك عمره 5 سنوات → ينطبق
> - **1500 - 300 = 1200 ج.م**

### مثال 3: خصم أخوة تراكمي
> - السعر الأساسي: 1500 ج.م
> - قاعدة 1: الأخ الثاني → خصم 10% (stackable)
> - قاعدة 2: عائلة 3 أبناء+ → خصم 5% (stackable)
> - المشترك: الأخ الثاني من 3 أبناء
> - **1500 - 150 (10%) - 75 (5% من 1500) = 1275 ج.م**

### مثال 4: تطبيق كوبون بعد القواعد
> - السعر بعد القواعد: 1200 ج.م
> - كوبون "SUMMER2024": خصم 100 ج.م ثابت
> - **1200 - 100 = 1100 ج.م**
> - فحص الحد الأقصى (50%): 1100 > 750 (50% من 1500) → ✓ مقبول

### مثال 5: وصول للحد الأقصى
> - السعر الأساسي: 1000 ج.م
> - قاعدة VIP: خصم 40%
> - كوبون: خصم 20%
> - المجموع: 60% خصم → لكن الحد الأقصى 50%
> - **النتيجة: 500 ج.م** (أقل خصم ممكن = 50%)

### مثال 6: سعر ثابت (override)
> - السعر الأساسي: 1500 ج.م
> - قاعدة "تصنيف منحة": fixed_price = 0
> - **النتيجة: 0 ج.م** (مجاني — طالب منحة)

---

## لماذا يحتاج عملك هذا

| الميزة | الفائدة |
|--------|---------|
| لا أسعار ثابتة | مرونة كاملة بدون تغيير كود |
| 13 نوع قاعدة | تغطي كل سيناريو تسعير ممكن |
| التراكم | خصومات متعددة تعمل معاً بشكل عادل |
| الحد الأقصى | حماية من خصومات مبالغ فيها بالخطأ |
| التجميد | تغيير الأسعار لا يؤثر على الفواتير القديمة |
| الكوبونات | أداة تسويقية قوية مع 8 تحققات |
| الأولويات | تحكم دقيق في ترتيب التطبيق |

---

## التكاملات

| الوحدة | العلاقة |
|--------|---------|
| التسجيل | حساب السعر عند التسجيل في مجموعة |
| نقطة البيع | حساب السعر عند البيع |
| المالية | النتيجة تذهب لبند الفاتورة |
| المشتركين | بيانات المشترك تُقيّم ضد شروط القواعد |
