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

4.0 KiB

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) → رسم الإلغاء حسب المرحلة

كلها نقية، مختبَرة بوحدات (نفس المدخل = نفس المخرج).

مثال — عمّان على العداد المنظّم (أرقام رسمية)

{
  "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.

قواعد

  • لا سعر بلا تعرفة نافذة مطابقة — خطأ صريح لا افتراض صامت.
  • كل رحلة تحفظ نسخة من التعرفة المستخدمة (audit trail + مطلب المنظّم).
  • التقريب آخر خطوة دائماً بعد جمع كل المكوّنات.

← السابق: 03-mobile-plan · التالي: 05-pricing-billing