- 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>
70 lines
4.0 KiB
Markdown
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)
|