feat: المجموعة J — الرصيد التشغيلي + تصحيح نموذج العمولة (B3/B6)
فلسفة العمولة الصحيحة (docs/18): السائق يقبض أجرة الراكب **كاملة**،
والعمولة تُخصم من رصيد تشغيلي مدفوع سلفاً. ما بُني في f3fdc1b كان نموذج
أوبر (اقتطاع من الأرباح) — عكس المطلوب.
- J1: driver_credits + credit_txns. خصم ذرّي كنمط I1 لكن **بلا شرط رصيد**
ولا قيد >= 0: الدين مسموح عمداً (قرار المالك: الرحلة لا تُقطع أبداً)
- J2: خصم العمولة عند completed لا paid — الرحلة تمّت فالعمولة استُحقّت.
قاعدة واحدة للكاش والمحفظة (§5.5): لا تفريع حسب وسيلة الدفع
- J3: price_for_driver = price_for_passenger. TariffEngine.split →
commission، وبلا سقف بالأجرة لأن الخصم على رصيد منفصل يجوز أن يسلب
- J4: الحجب عند تجاوز credit_floor فقط، عند setOnline و accept — لا أثناء
رحلة. الحجب يمنع الاتصال أصلاً وإلا عُرضت رحلات يُرفض قبولها
- J6: مكافأة التسجيل عند الاعتماد (3 JOD / 300 SYP جديدة / 300 EGP).
حارسان: فحص تطبيقي للحالة الشائعة + فهرس فريد جزئي للسباق
- J7: credit_floor لكل عملة
- J8: GET /credit + /credit/transactions
تصحيح B3: مشوار الوصول تعويضُ إلغاء بعد انقضاء الانتظار المجاني — لا بند
في كل أجرة. أُزيل مفتاح pickup_leg.charge.
هجرة: DriverCredit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2edd8f6916
commit
d9b0faab2d
+14
-11
@@ -191,21 +191,24 @@
|
||||
|
||||
---
|
||||
|
||||
## المجموعة J — الرصيد التشغيلي وعمولة السائق 🔴 يسبق I2
|
||||
## المجموعة J — الرصيد التشغيلي وعمولة السائق — ✅ منفَّذة (عدا J5)
|
||||
> **المستند الكامل: [18-driver-credit-commission](18-driver-credit-commission.md).**
|
||||
> السائق يشحن رصيداً تشغيلياً سلفاً · الراكب يدفع له الأجرة كاملة · العمولة تُخصم من الرصيد لا من الأجرة.
|
||||
> نموذج معتمد عالمياً في أسواق الكاش (inDrive · Yango · سيرو) — وليس نموذج أوبر.
|
||||
|
||||
| # | البند |
|
||||
|---|-------|
|
||||
| J1 | جدول `driver_credit` + دفتر قيود — خصم ذرّي داخل معاملة (نمط I1 حرفياً) |
|
||||
| J2 | خصم العمولة عند `completed` من الرصيد التشغيلي (لا من الأجرة) |
|
||||
| J3 | **تصحيح B6**: `price_for_driver = price_for_passenger` |
|
||||
| J4 | **الحجب عند نفاد الرصيد** — بدونه ينهار النموذج (سائق برصيد صفر يعمل مجاناً للأبد) |
|
||||
| J5 | باقات شحن لكل عملة + الحافز كقيد منفصل |
|
||||
| J6 | رصيد ترحيبي / فترة سماح للسائق الجديد (حاجز الدخول) |
|
||||
| J7 | أرضية سالبة محدودة لسباق «أنهى ورصيده لا يكفي» |
|
||||
| J8 | نقاط: رصيدي · تاريخ الخصومات · الشحن |
|
||||
| # | البند | الحالة |
|
||||
|---|-------|--------|
|
||||
| J1 | `driver_credits` + `credit_txns` — خصم ذرّي (نمط I1) لكن **بلا شرط رصيد**: الدين مسموح عمداً، ولا قيد `>= 0` على الجدول | ✅ |
|
||||
| J2 | خصم العمولة عند `completed` من الرصيد التشغيلي — كاشاً كانت أو محفظة (قاعدة واحدة) | ✅ |
|
||||
| J3 | **تصحيح B6**: `price_for_driver = price_for_passenger`؛ `TariffEngine.split` → `commission` (بلا سقف بالأجرة) | ✅ |
|
||||
| J4 | الحجب عند تجاوز `credit_floor` فقط — عند `setOnline` و`accept`، **لا** أثناء رحلة جارية | ✅ |
|
||||
| J6 | مكافأة التسجيل عند **الاعتماد** لا التقديم: 3 JOD · 300 SYP · 300 EGP. حارسان: فحص تطبيقي + فهرس فريد جزئي | ✅ |
|
||||
| J7 | `credit_floor` لكل عملة: −5 JOD · −500 SYP · −500 EGP | ✅ |
|
||||
| J8 | `GET /credit` (الرصيد · الأرضية · مَدين؟ · محجوب؟) و`GET /credit/transactions` | ✅ |
|
||||
| — | **تصحيح B3**: مشوار الوصول = تعويض إلغاء بعد انقضاء الانتظار المجاني — لا بند في كل أجرة | ✅ |
|
||||
| J5 | باقات شحن لكل عملة (`promo_bonus` جاهز كنوع قيد؛ الباقات نفسها لم تُبنَ) | ⏳ |
|
||||
|
||||
**الأرقام ثوابت في `driver-credit.service.ts` مؤقتاً** (المكافأة والأرضية) — تُنقل لإعداد المستأجر عند بناء J5.
|
||||
|
||||
> **أثره على I2**: محفظة المنصة لم تعد تستقبل عمولة من كل رحلة — بل تستقبل **مدفوعات الشحن**. هذا يبسّط I2 كثيراً.
|
||||
|
||||
|
||||
@@ -58,34 +58,43 @@ commission_amount = split(price_for_passenger) // تُحسب وتُسجَ
|
||||
- دفتر قيود append-only + خصم ذرّي — **نفس نمط I1 حرفياً** (`UPDATE … WHERE balance >= :amount`).
|
||||
- الخصم يحدث عند `completed` (لا عند `paid`): الرحلة تمّت فالعمولة استُحقّت، بغضّ النظر عن وسيلة الدفع.
|
||||
|
||||
### 5.2 الحجب عند نفاد الرصيد — **الالتزام الأهم**
|
||||
بلا حجب، النموذج **ينهار**: سائق برصيد صفر يعمل مجاناً إلى الأبد.
|
||||
### 5.2 الرصيد السالب مسموح — والرحلة لا تُقطع أبداً (قرار المالك 2026-07-17)
|
||||
> «نعطي رصيداً سالباً مثل أوبر… ولا تتوقف العملية عند الرصيد. لو بدأ رحلة وعمولتها أكبر من رصيده، يكمل عادي وتُضاف إلى الدين — حتى نُسهّل التجنيد.»
|
||||
|
||||
فالتصميم **ليس** حجباً عند الصفر:
|
||||
```
|
||||
driver_credit < min_balance → لا يدخل فهرس geo:drivers:available
|
||||
→ لا تُعرض عليه رحلات
|
||||
→ إشعار: «اشحن رصيدك التشغيلي»
|
||||
الرحلة الجارية → لا تُقطع أبداً مهما كان الرصيد. العمولة تُخصم ولو صار سالباً.
|
||||
الدين ضمن الأرضية → يبقى متاحاً ويعمل طبيعياً (إشعار تذكير فقط).
|
||||
الدين تجاوز الأرضية → يخرج من فهرس المتاحين: «اشحن رصيدك التشغيلي».
|
||||
```
|
||||
- الفحص عند: `setOnline` وقبل `accept` وبعد كل خصم.
|
||||
- `min_balance` لكل مستأجر/عملة (قد يكون صفراً أو أعلى من أغلى عمولة متوقعة).
|
||||
- **سباق حقيقي**: رحلة تُنهى ورصيده لا يكفي العمولة → نسمح بأرضية سالبة محدودة (`credit_floor`، مثلاً −1 عمولة) ثم نحجبه فوراً. البديل (رفض الخصم) يعني عمولة ضائعة.
|
||||
- **الخصم لا يفشل أبداً** — بخلاف محفظة الأرباح (I1) حيث الخصم مشروط بالرصيد. هنا الشرط الوحيد هو الأرضية، ويُفحص **بعد** الخصم لا قبله.
|
||||
- `credit_floor` (أقصى دين) لكل مستأجر/عملة. الفحص عند `setOnline` و`accept` وبعد كل خصم — **لا** أثناء رحلة جارية.
|
||||
- **لماذا لا نحجب عند الصفر:** حجبٌ عند الصفر يعني سائقاً يُترك في منتصف يومه، وراكباً بلا سائق، وتجنيداً يموت. الدين المحدود أرخص من ذلك بكثير. لكنه يظلّ **محدوداً** — أرضية بلا سقف تعني عمولة غير قابلة للتحصيل إلى الأبد.
|
||||
|
||||
### 5.3 باقات الشحن لكل عملة
|
||||
كما في سيرو — لكل عملة باقاتها وأسعارها:
|
||||
> ⚠️ **الليرة السورية الجديدة حذفت صفرين** — كل الأرقام السورية تُكتب بالعملة الجديدة.
|
||||
|
||||
لكل عملة باقاتها (أرقام مبدئية تُضبط من لوحة الأدمن):
|
||||
```
|
||||
JOD: [5, 10, 25, 50]
|
||||
SYP: [50k, 100k, 250k]
|
||||
JOD: [3, 5, 10, 25]
|
||||
SYP: [500, 1000, 2500] ← بالعملة الجديدة
|
||||
EGP: [100, 250, 500]
|
||||
```
|
||||
- الشحن عبر **[07-integrations](07-integrations.md)** وطرق الدفع لكل دولة (كليك · شام كاش · إي كاش · بيموب · فوري …).
|
||||
- باقة قد تحمل **حافزاً**: «اشحن 50 واحصل على 55» — أداة تسويق مباشرة بيد المستأجر.
|
||||
- الحافز يُسجَّل قيداً منفصلاً في الدفتر (`bonus`) لا يُخلط بالمدفوع فعلاً — وإلا فسدت المحاسبة.
|
||||
|
||||
### 5.4 حاجز دخول السائق الجديد
|
||||
النموذج يطلب من السائق أن يدفع **قبل** أن يكسب — وهذا يقتل التجنيد.
|
||||
المعالجات (قرار مالك، لا افتراض تقني):
|
||||
- **رصيد ترحيبي** (مثلاً 5 دنانير مجاناً) — الأشيع.
|
||||
- **فترة سماح** (أول 7 أيام أو أول 20 رحلة بلا خصم).
|
||||
- **أرضية سالبة أوسع للسائق الجديد** ثم تُشدَّد.
|
||||
### 5.4 مكافأة التسجيل (محسومة — قرار المالك)
|
||||
السائق الجديد يبدأ **برصيد هدية** يُقيَّد في دفتره فور اعتماده، فيعمل من أول دقيقة بلا دفع:
|
||||
|
||||
| العملة | المكافأة |
|
||||
|--------|----------|
|
||||
| SYP (الجديدة) | **300** |
|
||||
| EGP | **300** |
|
||||
| JOD | **3–4** (يُحسم رقم واحد عند التنفيذ) |
|
||||
|
||||
- تُقيَّد كنوع `signup_bonus` **منفصلاً عن المدفوع فعلاً** — وإلا اختلطت الهدايا بالإيرادات في المحاسبة.
|
||||
- تُمنح **مرة واحدة لكل سائق** — الحارس: قيد واحد بهذا النوع لكل `driver_id` (فريد على مستوى القاعدة، لا فحص تطبيقي).
|
||||
|
||||
### 5.5 وسيلة الدفع لا تغيّر شيئاً
|
||||
| الدفع | من يقبض الأجرة | من أين العمولة |
|
||||
@@ -106,11 +115,13 @@ EGP: [100, 250, 500]
|
||||
| J1 | جدول `driver_credit` + دفتر قيوده — خصم ذرّي داخل معاملة (نمط I1) |
|
||||
| J2 | خصم العمولة من الرصيد التشغيلي عند `completed` (لا من الأجرة) |
|
||||
| J3 | **تصحيح B6**: `price_for_driver = price_for_passenger` (السائق يقبض كاملاً) |
|
||||
| J4 | الحجب عند نفاد الرصيد: `setOnline` + `accept` + بعد كل خصم |
|
||||
| J5 | باقات الشحن لكل عملة + الحافز كقيد منفصل |
|
||||
| J6 | رصيد ترحيبي / فترة سماح للسائق الجديد |
|
||||
| J7 | أرضية سالبة محدودة (`credit_floor`) لسباق «أنهى الرحلة ورصيده لا يكفي» |
|
||||
| J4 | الرصيد السالب مسموح: الخصم لا يفشل أبداً؛ الحجب فقط عند تجاوز `credit_floor` — عند `setOnline`/`accept`، **لا** أثناء رحلة جارية |
|
||||
| J5 | باقات الشحن لكل عملة (SYP بالعملة الجديدة) + الحافز كقيد منفصل |
|
||||
| J6 | مكافأة التسجيل: 300 SYP · 300 EGP · 3–4 JOD — مرة واحدة لكل سائق (قيد فريد على القاعدة) |
|
||||
| J7 | `credit_floor` لكل مستأجر/عملة |
|
||||
| J8 | شاشة/نقاط: رصيدي · تاريخ الخصومات · الشحن |
|
||||
|
||||
> **لا مستخدمين في Tripz بعد** (2026-07-17) — فلا حاجة لهجرة بيانات ولا توافق خلفي. مستخدمو سيرو يُهاجَرون لاحقاً في عملية منفصلة وبسيطة.
|
||||
|
||||
---
|
||||
← ذو صلة: [05-pricing-billing](05-pricing-billing.md) · [17-backend-backlog](17-backend-backlog.md) · [19-entitlements-licensing](19-entitlements-licensing.md)
|
||||
|
||||
Reference in New Issue
Block a user