Files
tripz-llc/docs/18-driver-credit-commission.md
T
Hamza-AyedandClaude Opus 4.8 2edd8f6916 docs: نموذج الرصيد التشغيلي (18) والاستحقاقات (19) + تصحيحان على B
18 — الرصيد التشغيلي: السائق يشحن سلفاً، الراكب يدفع له الأجرة كاملة،
والعمولة تُخصم من الرصيد لا من الأجرة. مقارنة صريحة: هذا نموذج inDrive/
Yango/سيرو لا نموذج أوبر — وهو المعيار الفعلي في أسواق الكاش المستهدفة.
ثمنه ثلاثة التزامات: الحجب عند نفاد الرصيد (بدونه ينهار)، باقات لكل عملة،
ومعالجة حاجز دخول السائق الجديد.

19 — الاستحقاقات: علم الميزة في التطبيق قرار عرض لا حدّ أمني. الهندسة
العكسية تكشف شاشة تنادي نقطة ترجع 403. الحدّ الحقيقي FeatureGuard على
السيرفر + tenant_id من JWT موقَّع. الحقيقة التي تُقال صراحةً: ما يعمل كلياً
على الجهاز لا يُحمى، ووضع السيادة لا يُحمى تقنياً أصلاً (المستأجر يملك
السيرفر) — فليشمل سعره كل شيء بدل وهم حماية.

تصحيحان على المجموعة B (كلاهما بُني على افتراض خاطئ مني):
- B3: مشوار الوصول تعويضُ عدم حضور عند الإلغاء بعد 5 دقائق انتظار،
  لا بند في كل أجرة كما بنيته
- B6: price_for_driver = price_for_passenger — العمولة لا تُقتطع من الأجرة

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 13:32:32 +03:00

117 lines
9.7 KiB
Markdown

# 18 — الرصيد التشغيلي وعمولة السائق (نموذج الدفع المسبق)
> **طبقتان مختلفتان لا تُخلطان:**
> - **[05-pricing-billing](05-pricing-billing.md)** = كيف تقبض **Tripz** من المستأجر (اشتراك + نسبة GMV).
> - **هذا الملف** = كيف يقبض **المستأجر** (سيرو مثلاً) عمولته من **سائقيه**.
>
> مصدره: قرار المالك (2026-07-17) — «فلسفة التطبيق اللي بدنا إياه».
---
## 1. الفكرة في سطر واحد
السائق **يشتري رصيداً تشغيلياً مقدَّماً**. الراكب يدفع للسائق **الأجرة كاملة** (كاش أو محفظة). المنصة **لا تلمس أجرة الرحلة إطلاقاً** — بل تخصم عمولتها من الرصيد التشغيلي المدفوع سلفاً.
## 2. المثال المرجعي (كلام المالك حرفياً)
```
السائق يشحن رصيده التشغيلي → 4.000 دينار
الراكب يصل ويدفع للسائق (كاش/محفظة) → 4.000 دينار ← يأخذها السائق كاملة
عمولة التطبيق 10% من 4.000 → 0.400 دينار
تُخصم من الرصيد التشغيلي → 4.000 - 0.400 = 3.600 دينار
```
**الرصيد التشغيلي بعد الرحلة = 3.600 دينار.** أجرة الراكب لم تُمسّ.
> ملاحظة على الترقيم: الـ«4 دنانير» في المثال صدفة — رصيد الشحن وأجرة الرحلة رقمان مستقلان تماماً. لو شحن السائق 50 ديناراً وأنهى نفس الرحلة لصار رصيده 49.600.
## 3. هل هذا نموذج متعارف عليه عالمياً؟ — **نعم، لكنه ليس نموذج أوبر**
هناك نموذجان سائدان، وكلاهما شرعي:
| | **اقتطاع من الأرباح (take-rate)** | **الرصيد المدفوع مسبقاً (prepaid credit)** ← نموذجنا |
|---|---|---|
| **من يقبض المال؟** | المنصة تقبض الأجرة ثم تحوّل للسائق الصافي | السائق يقبض الأجرة كاملة مباشرة |
| **من يستعمله** | Uber · Bolt · Careem · Grab · Didi | **inDrive** · Yango/Yandex (شركاء) · Maxim · أغلب التطبيقات المحلية في الشرق الأوسط وأفريقيا وجنوب آسيا · **سيرو** |
| **يناسب** | أسواق الدفع الإلكتروني الغالب | **أسواق الكاش الغالب** |
| **مشكلة الكاش** | السائق يصير **مديناً** للمنصة → تحصيل ومطاردة وديون معدومة | **لا توجد** — العمولة مقبوضة سلفاً |
| **التدفق النقدي** | متأخر | **مقدَّم** |
| **حاجز الدخول للسائق** | صفر | يدفع قبل أن يكسب ← يحتاج معالجة |
**الحكم:** النموذج الذي تصفه هو **المعيار الفعلي في الأسواق التي تستهدفها** (سوريا · الأردن · مصر) حيث الكاش هو الغالب. أوبر نفسها في الأسواق كثيفة الكاش تضطر لتتبّع **رصيد سائق سالب** ثم مطاردة تحصيله — وهو بالضبط الوجع الذي يلغيه نموذجك من أصله. اختيارك سليم، وليس نسخاً أعمى عن سيرو.
**لكن ثمنه ثلاثة التزامات** (تفصيلها في §5): الحجب عند نفاد الرصيد، وباقات شحن لكل عملة، ومعالجة حاجز دخول السائق الجديد.
## 4. ما الذي يتغيّر في الكود (تصحيح لما نُفِّذ في B6)
الشريحة الأولى من المجموعة B (commit `f3fdc1b`) نُفِّذت على **نموذج الاقتطاع**:
```ts
price_for_driver = price_for_passenger - commission // ❌ ليس فلسفتنا
```
الصحيح حسب هذا المستند:
```ts
price_for_driver = price_for_passenger // السائق يأخذ الأجرة كاملة
commission_amount = split(price_for_passenger) // تُحسب وتُسجَّل على الرحلة
→ ثم تُخصم من driver_credit (رصيد منفصل تماماً)، لا من الأجرة
```
**`price_for_driver` و`price_for_passenger` يبقيان مفيدين** — لكن سبب اختلافهما ليس العمولة، بل: خصم على الراكب (كوبون/عرض) بينما السائق يقبض كاملاً، أو مكافأة تفاوض (`ai_negotiated_bonus` عند سيرو).
## 5. الآليات المطلوبة
### 5.1 الرصيد التشغيلي (`driver_credit`)
- محفظة **ثانية منفصلة** عن محفظة أرباح السائق. لا تُخلط: هذه للعمولة سلفاً، وتلك لأمواله.
- دفتر قيود append-only + خصم ذرّي — **نفس نمط I1 حرفياً** (`UPDATE … WHERE balance >= :amount`).
- الخصم يحدث عند `completed` (لا عند `paid`): الرحلة تمّت فالعمولة استُحقّت، بغضّ النظر عن وسيلة الدفع.
### 5.2 الحجب عند نفاد الرصيد — **الالتزام الأهم**
بلا حجب، النموذج **ينهار**: سائق برصيد صفر يعمل مجاناً إلى الأبد.
```
driver_credit < min_balance → لا يدخل فهرس geo:drivers:available
→ لا تُعرض عليه رحلات
→ إشعار: «اشحن رصيدك التشغيلي»
```
- الفحص عند: `setOnline` وقبل `accept` وبعد كل خصم.
- `min_balance` لكل مستأجر/عملة (قد يكون صفراً أو أعلى من أغلى عمولة متوقعة).
- **سباق حقيقي**: رحلة تُنهى ورصيده لا يكفي العمولة → نسمح بأرضية سالبة محدودة (`credit_floor`، مثلاً −1 عمولة) ثم نحجبه فوراً. البديل (رفض الخصم) يعني عمولة ضائعة.
### 5.3 باقات الشحن لكل عملة
كما في سيرو — لكل عملة باقاتها وأسعارها:
```
JOD: [5, 10, 25, 50]
SYP: [50k, 100k, 250k]
EGP: [100, 250, 500]
```
- الشحن عبر **[07-integrations](07-integrations.md)** وطرق الدفع لكل دولة (كليك · شام كاش · إي كاش · بيموب · فوري …).
- باقة قد تحمل **حافزاً**: «اشحن 50 واحصل على 55» — أداة تسويق مباشرة بيد المستأجر.
- الحافز يُسجَّل قيداً منفصلاً في الدفتر (`bonus`) لا يُخلط بالمدفوع فعلاً — وإلا فسدت المحاسبة.
### 5.4 حاجز دخول السائق الجديد
النموذج يطلب من السائق أن يدفع **قبل** أن يكسب — وهذا يقتل التجنيد.
المعالجات (قرار مالك، لا افتراض تقني):
- **رصيد ترحيبي** (مثلاً 5 دنانير مجاناً) — الأشيع.
- **فترة سماح** (أول 7 أيام أو أول 20 رحلة بلا خصم).
- **أرضية سالبة أوسع للسائق الجديد** ثم تُشدَّد.
### 5.5 وسيلة الدفع لا تغيّر شيئاً
| الدفع | من يقبض الأجرة | من أين العمولة |
|---|---|---|
| كاش | السائق مباشرة | الرصيد التشغيلي |
| محفظة الراكب | السائق (تُحوَّل لمحفظة أرباحه) | الرصيد التشغيلي |
**قاعدة واحدة لا استثناء لها** — وهذا أبسط بكثير من تفريع المنطق حسب وسيلة الدفع، وهو ما قاله المالك حرفياً: «إن كانت كاش أو محفظة».
> **مفارقة تستحق الانتباه:** في الدفع بالمحفظة، المنصة **تلمس المال فعلاً**، فتستطيع تقنياً اقتطاع العمولة منه. لكننا **لا نفعل** — عمداً. لأن قاعدتين مختلفتين حسب وسيلة الدفع تعني منطقاً مزدوجاً، ومحاسبةً مزدوجة، وسائقاً لا يفهم لماذا اختلف دخله. الاتساق أثمن من التحسين هنا.
## 6. لماذا تُحسب العمولة على الرحلة رغم أنها تُخصم من مكان آخر؟
لأن `commission_amount` على الرحلة هو **سبب** القيد في دفتر الرصيد التشغيلي. بدونه لا يستطيع السائق (ولا خدمة العملاء) الإجابة عن: «لماذا نقص رصيدي 400 فلس؟». كل خصم يشير إلى `trip_id`.
## 7. البنود المطلوبة (تُضاف للـ[17-backend-backlog](17-backend-backlog.md) كمجموعة J)
| # | البند |
|---|-------|
| J1 | جدول `driver_credit` + دفتر قيوده — خصم ذرّي داخل معاملة (نمط I1) |
| J2 | خصم العمولة من الرصيد التشغيلي عند `completed` (لا من الأجرة) |
| J3 | **تصحيح B6**: `price_for_driver = price_for_passenger` (السائق يقبض كاملاً) |
| J4 | الحجب عند نفاد الرصيد: `setOnline` + `accept` + بعد كل خصم |
| J5 | باقات الشحن لكل عملة + الحافز كقيد منفصل |
| J6 | رصيد ترحيبي / فترة سماح للسائق الجديد |
| J7 | أرضية سالبة محدودة (`credit_floor`) لسباق «أنهى الرحلة ورصيده لا يكفي» |
| J8 | شاشة/نقاط: رصيدي · تاريخ الخصومات · الشحن |
---
← ذو صلة: [05-pricing-billing](05-pricing-billing.md) · [17-backend-backlog](17-backend-backlog.md) · [19-entitlements-licensing](19-entitlements-licensing.md)