Files
tripz-llc/docs/04-tariff-engine.md
T
HamzaandClaude Opus 4.8 95fea546f5 first commit: منصة Tripz — خطط كاملة + سكافولد باك إند NestJS/Docker
- docs/00-15: دراسة، بنية، محرك تعرفة، تسعير، نموذج استئجار، تكاملات، بيانات، realtime، خطة، devops، لاندنج، مخاطر، اصطلاحات سيرفر، تدفق نشر
- backend/: NestJS 11 على Docker (health + tenants + عزل tenant_id + بادئة tripz_ + Redis DB 3)
- apps/rider, apps/driver, dashboards/admin-web, dashboards/superadmin-web (هياكل)
- sync-to-server.sh + .gitignore

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 15:22:06 +03:00

70 lines
4.0 KiB
Markdown

# 04 — محرك التعرفة
## المبدأ
محرك قواعد يقرأ تعريف التعرفة كـ **وثيقة JSON** لكل مجموعة `(مستأجر × مدينة × فئة خدمة)`. يغطي كل قدرات Onde الموثقة ويضيف ما يحتاجه سوقنا (العداد المنظّم الأردني، تقريب العملة).
## الأوضاع المدعومة
| الوضع | الوصف | مثال سوق |
|-------|-------|---------|
| `time_and_distance` | زمن + مسافة معاً | عام |
| `time_or_distance` | يبدّل حسب عتبة سرعة (تحت العتبة = دقيقة/زحمة، فوقها = كم) | العداد المنظّم — عمّان |
| `fixed_quote` | سعر مقفول لحظة تحديد الوجهة | يلا غو / كريم |
| `zone_matrix` | مصفوفة منطقة ← منطقة (PostGIS) | مطار ← وسط البلد |
## المكوّنات
- **فتحة عداد** (flag down) + **سعر/كم** + **سعر/دقيقة** + **رسوم خدمة/حجز**.
- **نوافذ زمنية:** نهار/ليل/جمعة/أعياد بجدولة صريحة.
- **Surge** بسقف معلن (مضاعف حسب العرض/الطلب في خلايا H3، قابل للتعطيل حيث يمنعه المنظّم).
- **رسوم إضافية مسماة:** بدل تطبيق، مطار، أمتعة.
- **بدل انتظار:** بالدقيقة أو بزيادات ثوانٍ.
- **رسوم إلغاء متدرجة** بمرحلة الرحلة + **حد أدنى للأجرة**.
- **قواعد تقريب لكل عملة** (أقرب 0.05 دينار؛ أقرب 500 ل.س...).
- **سياسة إعادة الاحتساب:** متى يُكسر السعر المقفول (انحراف مسار > نسبة محددة).
## واجهة المحرك (الباك إند)
```
tariff.quote(input) → يحسب سعراً تقديرياً/مقفولاً قبل الطلب
tariff.finalize(trip) → يحسب السعر النهائي عند الإنهاء
tariff.cancelFee(trip) → رسم الإلغاء حسب المرحلة
```
كلها نقية، مختبَرة بوحدات (نفس المدخل = نفس المخرج).
## مثال — عمّان على العداد المنظّم (أرقام رسمية)
```json
{
"tenant": "amman-operator-x",
"service_class": "taxi-yellow",
"currency": "JOD",
"rounding": { "increment": 0.05, "mode": "nearest" },
"mode": "time_or_distance",
"speed_threshold_kmh": 18,
"windows": [
{ "name": "day", "from": "06:00", "to": "22:00",
"flag": 0.39, "per_km": 0.28, "per_min_waiting": 0.48 },
{ "name": "night", "from": "22:00", "to": "06:00",
"flag": 0.40, "per_km": 0.33, "per_min_waiting": 0.55 }
],
"booking_fee": 0.25,
"min_fare": 1.00,
"surge": { "enabled": false },
"cancellation": [
{ "stage": "after_assign", "after_sec": 120, "fee": 0.50 },
{ "stage": "driver_arrived", "fee": 1.00 }
],
"recalc_policy": { "fixed_quote": false }
}
```
> قيم الانتظار بالدقيقة تقديرية للتوضيح وتُضبط من الزيادات الرسمية (كل 35 ثانية) عند التفعيل؛ فتحة العداد وسعر الكيلومتر هما الرقمان الرسميان المعتمدان.
## مخطط التخزين
- الجدول `tariffs`: `id, tenant_id, city, service_class, definition (jsonb), version, active_from`.
- إصدارات (versioning) — التعرفة النافذة وقت الرحلة تُثبَّت في `trip.tariff_version` للمراجعة.
- مناطق `zone_matrix` تُخزَّن كـ PostGIS polygons في [pricing-zones](02-backend-plan.md).
## قواعد
- **لا سعر بلا تعرفة نافذة مطابقة** — خطأ صريح لا افتراض صامت.
- **كل رحلة تحفظ نسخة من التعرفة المستخدمة** (audit trail + مطلب المنظّم).
- **التقريب آخر خطوة دائماً** بعد جمع كل المكوّنات.
← السابق: [03-mobile-plan](03-mobile-plan.md) · التالي: [05-pricing-billing](05-pricing-billing.md)