SS توثيق API
التوثيق مرجع واجهة API للواجهة الأمامية
واجهة الإدارة

مرجع واجهة API للواجهة الأمامية

مرجع شامل لمطوري الواجهات الأمامية — المصادقة، النقاط النهائية، النماذج، التعدادات، وأنماط التكامل.

REST + JWT استجابات JSON صلاحيات حسب الدور

نظام الشحن — مرجع واجهة برمجة التطبيقات للواجهة الأمامية

مرجع مفصّل لمطوّري الواجهة الأمامية الذين يتكاملون مع واجهة برمجة تطبيقات المسؤول (Admin API).

النطاق: تغطّي واجهة برمجة تطبيقات المسؤول (/api/admin/*) المصادقة، وإدارة المسؤولين/الأدوار/الصلاحيات، والسائقين، والمركبات، وفترات عدم التوفر، وتعيينات السائق–المركبة، والمستخدمين، والشحنات، ونقاط توقف الشحنات، وإثباتات التوصيل، وعمليات التوصيل الفاشلة، والمسارات ونقاط توقف المسار.


جدول المحتويات

  1. البدء السريع
  2. الاتفاقيات العامة
  3. المصادقة
  4. الملف الشخصي
  5. المسؤولون
  6. الأدوار والصلاحيات
  7. السائقون
  8. المركبات
  9. فترات عدم توفر السائقين
  10. تعيينات السائق–المركبة
  11. المستخدمون (العملاء)
  12. الشحنات
  13. نقاط توقف الشحنات
  14. إثباتات التوصيل
  15. عمليات التوصيل الفاشلة
  16. المسارات
  17. نقاط توقف المسار
  18. مرجع نماذج النطاق
  19. مرجع التعدادات (Enums)
  20. مرجع الصلاحيات
  21. معالجة الأخطاء
  22. قائمة التحقق لتكامل الواجهة الأمامية

البدء السريع

HTTP
POST /api/admin/login
Content-Type: application/json
Accept-Language: en

{
  "email": "mousa@example.com",
  "password": "password"
}

احفظ رمز JWT المُعاد وأرسله مع كل طلب لاحق:

HTTP
GET /api/admin/drivers
Authorization: Bearer {token}
Accept: application/json
Accept-Language: en

عنوان URL الأساسي: {APP_URL}/api — مثلًا http://localhost:8000/api عند تشغيل php artisan serve.


الاتفاقيات العامة

رؤوس الطلب (Request Headers)

الرأس مطلوب الوصف
Authorization نعم (ما عدا تسجيل الدخول) Bearer {jwt_token}
Accept موصى به application/json
Accept-Language اختياري ar (افتراضي) أو en — يتحكم في نص message المترجم
Content-Type يختلف application/json لأجسام JSON؛ multipart/form-data عند رفع الصور

غلاف الاستجابة (Response Envelope)

كل استجابة من واجهة برمجة التطبيقات تستخدم هذا الهيكل:

JSON
{
  "status": "Success",
  "message": "Data fetched successfully",
  "data": {},
  "statusCode": 200
}
الحقل النوع الوصف
status "Success" | "Error" مؤشر النتيجة
message string رسالة قابلة للقراءة ومترجمة
data object | array | null الحمولة (null عند الحذف/تسجيل الخروج)
statusCode integer رمز حالة HTTP مُعاد في الجسم

عند نجاح تسجيل الدخول، يُعاد رمز JWT أيضًا في رأس الاستجابة Authorization كـ Bearer {token}.

طرق HTTP

التحديثات تستخدم POST، وليس PUT أو PATCH.

جميع نقاط نهاية التحديث تتبع النمط POST /api/admin/{resource}/{id}.

أنواع المحتوى (Content Types)

السيناريو Content-Type
CRUD بـ JSON (بدون ملف) application/json
إنشاء/تحديث مع صورة (مسؤول، سائق، ملف شخصي) multipart/form-data
تعيين/إلغاء تعيين مركبة لا يتطلب جسمًا

عند استخدام multipart/form-data:

  • أرسل الحقول العددية كحقول نموذج.
  • أرسل working_days كحقول متكررة أو كسلسلة JSON (مصفوفة).
  • أرسل roles / permissions كحقول متكررة أو كسلسلة JSON للمصفوفة.
  • أرسل image كحقل ملف (حد أقصى 5 ميجابايت، يجب أن يكون صورة).

القوائم والتصفية والترتيب

معظم نقاط نهاية القوائم GET تقبل معاملات سلسلة الاستعلام (query string):

المعامل النوع الوصف
search string بحث نصي كامل عبر أعمدة خاصة بالنموذج
sort_by string اسم العمود (يجب أن يكون في قائمة الأعمدة القابلة للترتيب للنموذج)
sort_direction "asc" | "desc" اتجاه الترتيب (الافتراضي يختلف حسب النموذج)
page integer رقم الصفحة (نقاط النهاية المُقسّمة إلى صفحات فقط)

تُحوّل قيم سلسلة الاستعلام "null" و "" تلقائيًا إلى null بواسطة الوسيط (middleware).

التقسيم إلى صفحات (Pagination)

نقاط النهاية المُقسّمة (GET .../paginated) تُغلّف النتائج كالتالي:

JSON
{
  "drivers": [],
  "total": 50,
  "count": 10,
  "per_page": 10,
  "current_page": 1,
  "total_pages": 5,
  "links": {
    "first": "http://localhost:8000/api/admin/drivers/paginated?page=1",
    "last": "http://localhost:8000/api/admin/drivers/paginated?page=5",
    "prev": null,
    "next": "http://localhost:8000/api/admin/drivers/paginated?page=2"
  }
}

مفتاح المجموعة يطابق اسم المورد:

بادئة نقطة النهاية مفتاح المجموعة
/admins/paginated admins
/roles/paginated roles
/drivers/paginated drivers
/vehicles/paginated vehicles
/users/paginated users
/driver-unavailabilities/paginated driver_unavailabilities
/shipments/paginated shipments
/shipment-stops/paginated shipment_stops
/routes/paginated routes

حجم الصفحة ثابت عند 10 عناصر لكل صفحة.


المصادقة

جميع المسارات تحت /api/admin/* ما عدا POST /login تتطلب JWT صالحًا في رأس Authorization.

  • الحارس (Guard): admin
  • المكتبة: JWT Auth (tymon/jwt-auth)
  • مدة صلاحية الرمز (Token TTL): تُعاد كـ expires_in (بالثواني) في استجابة تسجيل الدخول. تُضبط عبر متغير البيئة JWT_TTL (بالدقائق)؛ إذا لم يُضبط، قد لا ينتهي الرمز.

POST /api/admin/login

مصادقة مسؤول واستلام JWT.

المصادقة مطلوبة: لا

جسم الطلب:

الحقل النوع مطلوب التحقق
email string نعم بريد إلكتروني صالح
password string نعم سلسلة غير فارغة
fcm_token string لا رمز جهاز الإشعارات الفورية؛ يُخزّن في سجل المسؤول

مثال على جسم الطلب:

JSON
{
  "email": "mousa@example.com",
  "password": "SecurePass123!",
  "fcm_token": "device-fcm-token-abc123"
}

استجابة النجاح 200:

JSON
{
  "status": "Success",
  "message": "User successfully signed in",
  "data": {
    "admin": {
      "id": 1,
      "name": "mousa",
      "email": "mousa@example.com",
      "roles": ["operations_manager"],
      "permission_groups": [
        {
          "group": "Driver",
          "group_label": "Drivers",
          "permissions": [
            {
              "id": 1,
              "name": "ViewAny:Driver",
              "display_name": "View Any",
              "group": "Driver"
            }
          ]
        }
      ]
    },
    "token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
    "token_type": "bearer",
    "expires_in": 3600
  },
  "statusCode": 200
}

استجابات الخطأ:

الحالة متى
401 بريد إلكتروني/كلمة مرور غير صحيحة (credentialsError)
422 فشل التحقق (بريد إلكتروني/كلمة مرور مفقودة)
500 فشل إنشاء الرمز (couldNotCreateToken)

POST /api/admin/logout

إبطال جلسة JWT الحالية.

المصادقة مطلوبة: نعم

جسم الطلب: لا يوجد

استجابة النجاح 200:

JSON
{
  "status": "Success",
  "message": "User successfully signed out",
  "data": null,
  "statusCode": 200
}

استجابات الخطأ:

الحالة متى
403 لم يُقدّم رمز (Unauthenticated)
500 فشل تسجيل الخروج (couldNotLogout)

الملف الشخصي

إدارة الملف الشخصي للمسؤول المصادق حاليًا. لا تتطلب صلاحيات إدارة المسؤولين.


GET /api/admin/profile

الصلاحية المطلوبة: لا شيء (المصادقة فقط)

استجابة النجاح 200: تُعيد AdminResource (انظر المسؤولون) مع:

  • is_current_admin: true
  • permission_groups مُضمّنة
  • roles مُضمّنة

POST /api/admin/profile

تحديث ملف المسؤول المصادق.

الصلاحية المطلوبة: لا شيء (المصادقة فقط)

جسم الطلب (JSON أو multipart):

الحقل النوع مطلوب التحقق
name string لا حد أقصى 255 حرفًا
email string لا بريد إلكتروني صالح، فريد بين المسؤولين
password string لا قواعد كلمة مرور Laravel الافتراضية
image file لا صورة، حد أقصى 5 ميجابايت

مثال على جسم الطلب:

JSON
{
  "name": "mousa",
  "email": "mousa.updated@example.com",
  "password": "NewSecurePass123!"
}

استجابة النجاح 200: AdminResource محدّث مع رسالة profileUpdatedSuccessfully.


إحصائيات لوحة التحكم

إحصائيات KPI مجمّعة للوحة تحكم العمليات. تتطلب كلا النقطتين صلاحية View:Dashboard (أو مسؤول عام).


GET /api/admin/dashboard/overview

بطاقات KPI العليا لليوم والأسبوع والشهر. لا توجد معاملات استعلام.

الصلاحية المطلوبة: View:Dashboard

استجابة النجاح 200:

JSON
{
  "data": {
    "shipments_created_today": 12,
    "shipments_created_this_week": 48,
    "shipments_created_this_month": 190,
    "active_routes": 5,
    "active_drivers": 18,
    "pending_pickups": 9,
    "out_for_delivery": 14,
    "delivered_today": 22
  }
}

GET /api/admin/dashboard/trends

سلسلة زمنية يومية للرسوم البيانية، تمتد 7 أو 30 يومًا.

الصلاحية المطلوبة: View:Dashboard

معاملات الاستعلام:

المعامل النوع مطلوب الوصف
days عدد صحيح 7 أو 30 لا عدد الأيام (الافتراضي: 30)

استجابة النجاح 200:

JSON
{
  "data": {
    "days": 30,
    "from": "2026-06-20",
    "to": "2026-07-19",
    "series": [
      {
        "date": "2026-06-20",
        "shipments_created": 8,
        "shipments_delivered": 6,
        "failed_deliveries": 1,
        "failure_rate": 0.1429
      }
    ]
  }
}

خطأ التحقق 422: يُعاد عند إرسال قيمة days غير 7 أو 30.


المسؤولون

إدارة مستخدمي المكتب الخلفي.

بادئة الصلاحية: Admin (مثل ViewAny:Admin, Create:Admin)

حسابات المسؤولين المخفية (المُضبطة عبر متغير البيئة HIDDEN_ADMIN) مستبعدة من القوائم.

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/admins قائمة جميع المسؤولين ViewAny:Admin
GET /api/admin/admins/paginated قائمة مُقسّمة إلى صفحات ViewAny:Admin
GET /api/admin/admins/{id} جلب مسؤول واحد View:Admin
POST /api/admin/admins إنشاء مسؤول Create:Admin
POST /api/admin/admins/{id} تحديث مسؤول Update:Admin
DELETE /api/admin/admins/{id} حذف مسؤول Delete:Admin

معاملات استعلام القائمة

المعامل الوصف
search يبحث في name, email
role تصفية حسب اسم الدور (تطابق تام)
sort_by name, email, created_at
sort_direction asc أو desc (افتراضي: asc حسب name)

جسم طلب الإنشاء

الحقل النوع مطلوب التحقق
name string نعم حد أقصى 255
email string نعم بريد إلكتروني صالح، فريد
password string نعم قواعد كلمة مرور Laravel الافتراضية
image file لا صورة، حد أقصى 5 ميجابايت
roles string[] لا مصفوفة من أسماء الأدوار الموجودة

مثال على جسم الطلب:

JSON
{
  "name": "mousa",
  "email": "mousa@example.com",
  "password": "SecurePass123!",
  "roles": ["operations_manager"]
}

جسم طلب التحديث

نفس حقول الإنشاء، جميعها اختيارية (تُطبّق قواعد sometimes). احذف password للإبقاء على كلمة المرور الحالية. أرسل roles: [] لإزالة جميع الأدوار.

مثال على جسم الطلب:

JSON
{
  "name": "mousa",
  "email": "mousa.admin@example.com",
  "roles": ["super_admin"]
}

شكل مورد المسؤول (Admin Resource Shape)

JSON
{
  "id": 1,
  "name": "mousa",
  "email": "mousa@example.com",
  "image": "http://localhost:8000/storage/1/admin_image.jpg",
  "roles": ["super_admin"],
  "permission_groups": [],
  "is_current_admin": false,
  "created_at": "2026-01-15T10:00:00.000000Z",
  "updated_at": "2026-01-15T10:00:00.000000Z"
}
الحقل ملاحظات
image عنوان URL كامل لصورة الملف الشخصي، أو سلسلة فارغة إن لم توجد
roles مصفوفة من سلاسل أسماء الأدوار
permission_groups تُضمّن فقط في GET /profile و GET /admins/{id}
is_current_admin true إذا كان هذا المسؤول هو مُقدّم الطلب

قيود الحذف

  • لا يمكن حذف حسابك الخاص → 403 مع رسالة cannotDeleteCurrentAdmin

الأدوار والصلاحيات

التحكم في الوصول المبني على الأدوار باستخدام Spatie Permission (الحارس: admin).

بادئات الصلاحيات: Role, Permission

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/permissions جميع الصلاحيات مجمّعة ViewAny:Permission
GET /api/admin/roles قائمة جميع الأدوار ViewAny:Role
GET /api/admin/roles/paginated قائمة مُقسّمة إلى صفحات ViewAny:Role
GET /api/admin/roles/{id} جلب دور واحد View:Role
POST /api/admin/roles إنشاء دور Create:Role
POST /api/admin/roles/{id} تحديث دور Update:Role
POST /api/admin/roles/{id}/permissions مزامنة الصلاحيات فقط Update:Role
DELETE /api/admin/roles/{id} حذف دور Delete:Role

معاملات استعلام القائمة (الأدوار)

المعامل الوصف
search يبحث في name للدور
sort_by name, created_at
sort_direction asc أو desc (افتراضي: asc حسب name)

جسم طلب إنشاء الدور

الحقل النوع مطلوب التحقق
name string نعم فريد لكل حارس، حد أقصى 255
permissions string[] لا مصفوفة من سلاسل أسماء الصلاحيات

مثال على جسم الطلب:

JSON
{
  "name": "warehouse_manager",
  "permissions": ["ViewAny:Driver", "Create:Driver", "ViewAny:Vehicle"]
}

جسم طلب تحديث الدور

الحقل النوع مطلوب التحقق
name string لا فريد لكل حارس، حد أقصى 255
permissions string[] لا يستبدل جميع الصلاحيات عند التقديم

مثال على جسم الطلب:

JSON
{
  "name": "warehouse_manager",
  "permissions": ["ViewAny:Driver", "Update:Driver"]
}

جسم طلب مزامنة الصلاحيات

POST /api/admin/roles/{id}/permissions

الحقل النوع مطلوب التحقق
permissions string[] نعم مصفوفة من سلاسل أسماء الصلاحيات

مثال على جسم الطلب:

JSON
{
  "permissions": ["ViewAny:Driver", "Create:Driver", "ViewAny:Vehicle", "Create:Vehicle"]
}

رسالة النجاح: permissionsAssignedSuccessfully

شكل مورد الدور (Role Resource Shape)

JSON
{
  "id": 2,
  "name": "warehouse_manager",
  "guard_name": "admin",
  "permission_groups": [
    {
      "group": "Driver",
      "group_label": "Drivers",
      "permissions": [
        {
          "id": 1,
          "name": "ViewAny:Driver",
          "display_name": "View Any",
          "group": "Driver"
        }
      ]
    }
  ],
  "created_at": "2026-01-15T10:00:00.000000Z",
  "updated_at": "2026-01-15T10:00:00.000000Z"
}

شكل مجموعة الصلاحيات (Permission Group Shape)

يُستخدم في تسجيل الدخول والملف الشخصي والأدوار وقائمة الصلاحيات:

JSON
{
  "group": "Driver",
  "group_label": "Drivers",
  "permissions": [
    {
      "id": 1,
      "name": "ViewAny:Driver",
      "display_name": "View Any",
      "group": "Driver"
    }
  ]
}

القيود

  • دور المسؤول الأعلى (super admin) لا يمكن تعديله أو حذفه → 403 (cannotModifySuperAdmin)

السائقون

إدارة سائقي التوصيل.

بادئة الصلاحية: Driver

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/drivers قائمة جميع السائقين ViewAny:Driver
GET /api/admin/drivers/paginated قائمة مُقسّمة إلى صفحات ViewAny:Driver
GET /api/admin/drivers/{id} جلب سائق واحد View:Driver
POST /api/admin/drivers إنشاء سائق Create:Driver
POST /api/admin/drivers/{id} تحديث سائق Update:Driver
DELETE /api/admin/drivers/{id} حذف سائق Delete:Driver
GET /api/admin/drivers/{id}/vehicle-assignments تعيينات المركبات ViewAny:DriverVehicleAssignment
GET /api/admin/drivers/{id}/unavailabilities فترات عدم التوفر ViewAny:DriverUnavailability
POST /api/admin/drivers/{driverId}/vehicles/{vehicleId}/assign تعيين مركبة Create:DriverVehicleAssignment
POST /api/admin/drivers/{driverId}/vehicles/{vehicleId}/unassign إلغاء تعيين مركبة Update:DriverVehicleAssignment

معاملات استعلام القائمة

المعامل النوع الوصف
search string يبحث في name, phone, email, driver_number, license_number
is_active boolean تصفية حسب حالة النشاط
lat float خط العرض للبحث القريب (يتطلب lng)
lng float خط الطول للبحث القريب (يتطلب lat)
radius float نصف قطر البحث بالكيلومتر (افتراضي: 10)
work_start_time time تصفية السائقين الذين يتداخل ورديتهم مع وقت البداية هذا
work_end_time time تصفية السائقين الذين يتداخل ورديتهم مع وقت النهاية هذا
work_start_time_from time الحد الأدنى لوقت بداية الوردية
work_start_time_to time الحد الأقصى لوقت بداية الوردية
work_end_time_from time الحد الأدنى لوقت نهاية الوردية
work_end_time_to time الحد الأقصى لوقت نهاية الوردية
sort_by string انظر الأعمدة القابلة للترتيب أدناه
sort_direction string asc أو desc

الأعمدة القابلة للترتيب: name, phone, driver_number, work_start_time, work_end_time, created_at, distance

عند تقديم lat/lng، تتضمن النتائج حقل distance (كم) ويُرتّب افتراضيًا حسب الأقرب أولًا ما لم يُضبط sort_by صراحةً.

صيغة الوقت: HH:MM:SS أو HH:MM (تُطبّع تلقائيًا إلى HH:MM:SS).

جسم طلب الإنشاء

الحقل النوع مطلوب التحقق
name string نعم حد أقصى 255
phone string نعم حد أقصى 50
phone_country string نعم حد أقصى 10 (مثل +963)
email string لا بريد إلكتروني صالح، فريد
password string نعم قواعد كلمة مرور Laravel الافتراضية
address string نعم
license_number string لا حد أقصى 255
working_days string[] نعم عنصر واحد على الأقل؛ انظر أيام العمل
work_start_time time نعم يجب أن يختلف عن work_end_time
work_end_time time نعم يجب أن يختلف عن work_start_time
lat float لا -90 إلى 90
lng float لا -180 إلى 180
fcm_token string لا رمز الإشعارات الفورية
is_active boolean لا افتراضي: true
image file لا صورة، حد أقصى 5 ميجابايت
vehicle_id integer لا يجب أن يكون موجودًا في vehicles؛ يُعيَّن عند الإنشاء عند التوفير
driver_number string لا فريد؛ يُولّد تلقائيًا رقم من 6 أرقام إذا لم يُذكر

مثال على جسم الطلب:

JSON
{
  "name": "mousa",
  "phone": "944123456",
  "phone_country": "+963",
  "email": "mousa.driver@example.com",
  "password": "SecurePass123!",
  "address": "Damascus, Syria",
  "license_number": "SY-12345",
  "working_days": ["sun", "mon", "tue", "wed", "thu"],
  "work_start_time": "08:00:00",
  "work_end_time": "17:00:00",
  "lat": 33.5138,
  "lng": 36.2765,
  "is_active": true,
  "vehicle_id": 7
}

تعيين المركبة عند التحديث: أرسل vehicle_id لتعيين أو تبديل المركبة؛ أرسل vehicle_id: null لإلغاء التعيين الحالي. احذف الحقل لإبقاء التعيين دون تغيير.

جسم طلب التحديث

نفس حقول الإنشاء. جميع الحقول اختيارية ما عدا حيث تُطبّق sometimes + required. كلمة المرور اختيارية (احذفها للإبقاء على الحالية).

مثال على جسم الطلب:

JSON
{
  "name": "mousa",
  "phone": "944654321",
  "phone_country": "+963",
  "work_start_time": "09:00:00",
  "work_end_time": "18:00:00",
  "is_active": true
}

شكل مورد السائق (Driver Resource Shape)

JSON
{
  "id": 1,
  "driver_number": "482910",
  "name": "mousa",
  "phone": "944123456",
  "phone_country": "+963",
  "email": "mousa.driver@example.com",
  "image": "http://localhost:8000/storage/2/driver_image.jpg",
  "address": "Damascus, Syria",
  "license_number": "DL-12345",
  "working_days": ["sun", "mon", "tue", "wed", "thu"],
  "work_start_time": "08:00:00",
  "work_end_time": "17:00:00",
  "lat": 24.7136,
  "lng": 46.6753,
  "is_active": true,
  "created_at": "2026-01-15T10:00:00.000000Z",
  "updated_at": "2026-01-15T10:00:00.000000Z",
  "distance": 3.2,
  "vehicle": {
    "id": 7,
    "plate_number": "ABC-1234",
    "owner_type": "driver",
    "owner_type_label": "سائق",
    "owner_id": 1,
    "max_weight": 500,
    "max_volume": 10,
    "is_active": true,
    "created_at": "2026-01-15T10:00:00.000000Z",
    "updated_at": "2026-01-15T10:00:00.000000Z"
  }
}
الحقل ملاحظات
distance موجود فقط عند استخدام تصفية القرب (lat/lng)
working_days مصفوفة JSON من رموز الأيام
image عنوان URL كامل أو سلسلة فارغة
vehicle VehicleResource متداخل للمركبة المُعيَّنة حاليًا للسائق (released_at = nullnull عندما لا توجد مركبة مُعيَّنة

المركبات

إدارة مركبات الأسطول.

بادئة الصلاحية: Vehicle

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/vehicles قائمة جميع المركبات ViewAny:Vehicle
GET /api/admin/vehicles/paginated قائمة مُقسّمة إلى صفحات ViewAny:Vehicle
GET /api/admin/vehicles/{id} جلب مركبة واحدة View:Vehicle
POST /api/admin/vehicles إنشاء مركبة Create:Vehicle
POST /api/admin/vehicles/{id} تحديث مركبة Update:Vehicle
DELETE /api/admin/vehicles/{id} حذف مركبة Delete:Vehicle

معاملات استعلام القائمة

المعامل الوصف
search يبحث في plate_number
owner_type تطابق تام: company أو driver
is_active تصفية منطقية
sort_by plate_number, owner_type, max_weight, max_volume, created_at
sort_direction asc أو desc (افتراضي: asc حسب plate_number)

جسم طلب الإنشاء

الحقل النوع مطلوب التحقق
plate_number string نعم فريد، حد أقصى 255
owner_type string نعم company أو driver — انظر OwnerTypes
owner_id integer مشروط مطلوب عندما يكون owner_type هو driver؛ يجب أن يكون معرّف سائق صالحًا. يجب ألا يُرسل عندما يكون owner_type هو company
max_weight number نعم حد أدنى 0 (كجم)
max_volume number نعم حد أدنى 0 (م³)

مثال على جسم الطلب:

JSON
{
  "plate_number": "DMS-1234",
  "owner_type": "company",
  "max_weight": 1500,
  "max_volume": 12.5
}

مثال على جسم الطلب (مملوكة للسائق):

JSON
{
  "plate_number": "DMS-5678",
  "owner_type": "driver",
  "owner_id": 1,
  "max_weight": 2000,
  "max_volume": 15
}

جسم طلب التحديث

الحقل النوع مطلوب التحقق
plate_number string لا فريد، حد أقصى 255
owner_type string لا company أو driver
owner_id integer مشروط نفس قواعد الإنشاء
max_weight number لا حد أدنى 0
max_volume number لا حد أدنى 0
is_active boolean لا

مثال على جسم الطلب:

JSON
{
  "plate_number": "DMS-9999",
  "max_weight": 1800,
  "max_volume": 14,
  "is_active": false
}

شكل مورد المركبة (Vehicle Resource Shape)

JSON
{
  "id": 1,
  "plate_number": "ABC-1234",
  "owner_type": "company",
  "owner_type_label": "الشركة",
  "owner_id": null,
  "max_weight": 1500,
  "max_volume": 12.5,
  "is_active": true,
  "created_at": "2026-01-15T10:00:00.000000Z",
  "updated_at": "2026-01-15T10:00:00.000000Z"
}
الحقل ملاحظات
owner_type_label تسمية عربية مترجمة (تُعيد واجهة برمجة التطبيقات التسمية العربية دائمًا بغض النظر عن Accept-Language)
owner_id null للمركبات المملوكة للشركة؛ معرّف السائق للمركبات المملوكة للسائق

فترات عدم توفر السائقين

فترات الإجازة / عدم التوفر للسائقين.

بادئة الصلاحية: DriverUnavailability

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/driver-unavailabilities قائمة الكل ViewAny:DriverUnavailability
GET /api/admin/driver-unavailabilities/paginated قائمة مُقسّمة إلى صفحات ViewAny:DriverUnavailability
GET /api/admin/driver-unavailabilities/{id} جلب واحدة View:DriverUnavailability
POST /api/admin/driver-unavailabilities إنشاء Create:DriverUnavailability
POST /api/admin/driver-unavailabilities/{id} تحديث Update:DriverUnavailability
DELETE /api/admin/driver-unavailabilities/{id} حذف Delete:DriverUnavailability

يمكن الوصول إليها أيضًا عبر GET /api/admin/drivers/{id}/unavailabilities.

معاملات استعلام القائمة

المعامل الوصف
driver_id تصفية حسب معرّف السائق (تطابق تام)
sort_by start_date, end_date, created_at
sort_direction افتراضي: desc حسب start_date

جسم طلب الإنشاء

الحقل النوع مطلوب التحقق
driver_id integer نعم يجب أن يكون موجودًا في جدول drivers
start_date date نعم تاريخ ISO أو تاريخ ووقت
end_date date نعم يجب أن يكون بعد start_date
reason string لا نص حر

مثال على جسم الطلب:

JSON
{
  "driver_id": 1,
  "start_date": "2026-06-01",
  "end_date": "2026-06-05",
  "reason": "Annual leave"
}

جسم طلب التحديث

نفس الحقول، جميعها اختيارية. إذا قُدّمت كلا التاريخين في التحديث، يجب أن يظل end_date بعد start_date.

مثال على جسم الطلب:

JSON
{
  "start_date": "2026-06-01",
  "end_date": "2026-06-10",
  "reason": "Extended leave"
}

شكل مورد عدم توفر السائق (Driver Unavailability Resource Shape)

JSON
{
  "id": 1,
  "driver_id": 5,
  "start_date": "2026-06-01T00:00:00.000000Z",
  "end_date": "2026-06-05T00:00:00.000000Z",
  "reason": "Annual leave",
  "created_at": "2026-05-20T10:00:00.000000Z",
  "updated_at": "2026-05-20T10:00:00.000000Z"
}

تعيينات السائق–المركبة

يربط السائقين بالمركبات للاستخدام التشغيلي. يمكن للمركبة أن يكون لها تعيين نشط واحد فقط في كل مرة (released_at === null).

بادئة الصلاحية: DriverVehicleAssignment

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/drivers/{id}/vehicle-assignments قائمة التعيينات للسائق ViewAny:DriverVehicleAssignment
POST /api/admin/drivers/{driverId}/vehicles/{vehicleId}/assign تعيين مركبة للسائق Create:DriverVehicleAssignment
POST /api/admin/drivers/{driverId}/vehicles/{vehicleId}/unassign إنهاء التعيين Update:DriverVehicleAssignment

التعيين (Assign)

لا يوجد جسم طلب. ينشئ سجلًا مع:

  • assigned_at = الطابع الزمني الحالي
  • released_at = null

خطأ: 422 إذا كانت المركبة لديها تعيين نشط بالفعل (vehicleAlreadyAssigned)

إلغاء التعيين (Unassign)

لا يوجد جسم طلب. يضبط released_at على الطابع الزمني الحالي للتعيين النشط.

خطأ: 404 إذا لم يوجد تعيين نشط (vehicleAssignmentNotFound)

شكل مورد تعيين السائق–المركبة (Driver Vehicle Assignment Resource Shape)

JSON
{
  "id": 1,
  "driver_id": 3,
  "vehicle_id": 7,
  "assigned_at": "2026-06-01T08:00:00.000000Z",
  "released_at": null,
  "vehicle": {
    "id": 7,
    "plate_number": "XYZ-5678",
    "owner_type": "company",
    "owner_type_label": "الشركة",
    "owner_id": null,
    "max_weight": 2000,
    "max_volume": 15,
    "is_active": true,
    "created_at": "...",
    "updated_at": "..."
  },
  "driver": {
    "id": 3,
    "driver_number": "482910",
    "name": "mousa"
  },
  "created_at": "2026-06-01T08:00:00.000000Z",
  "updated_at": "2026-06-01T08:00:00.000000Z"
}
الحقل ملاحظات
vehicle VehicleResource متداخل عند تحميل العلاقة
driver DriverResource متداخل عند تحميل العلاقة
released_at null = مُعيّنة حاليًا

المستخدمون (العملاء)

العملاء النهائيون الذين يقدّمون الشحنات. هؤلاء ليسوا حسابات مسؤولين.

بادئة الصلاحية: User

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/users قائمة جميع المستخدمين ViewAny:User
GET /api/admin/users/paginated قائمة مُقسّمة إلى صفحات ViewAny:User
GET /api/admin/users/{id} جلب مستخدم واحد View:User
POST /api/admin/users إنشاء مستخدم Create:User
POST /api/admin/users/{id} تحديث مستخدم Update:User
DELETE /api/admin/users/{id} حذف مستخدم Delete:User

معاملات استعلام القائمة

المعامل الوصف
search يبحث في name, phone, email, company_name
sort_by name, phone, email, company_name, created_at
sort_direction asc أو desc (افتراضي: asc حسب name)

جسم طلب الإنشاء

الحقل النوع مطلوب التحقق
name string نعم حد أقصى 255
phone string نعم حد أقصى 50؛ فريد لكل phone_country
phone_country string نعم حد أقصى 10
email string لا بريد إلكتروني صالح، فريد
company_name string لا

مثال على جسم الطلب:

JSON
{
  "name": "mousa",
  "phone": "944123456",
  "phone_country": "+963",
  "email": "mousa@example.com",
  "company_name": "Mousa Trading Co."
}

جسم طلب التحديث

نفس الحقول، جميعها اختيارية. تُعاد التحقق من تفرد رقم الهاتف عند تغيير phone أو phone_country.

مثال على جسم الطلب:

JSON
{
  "name": "mousa",
  "phone": "944654321",
  "phone_country": "+963",
  "company_name": "Mousa Logistics"
}

شكل مورد المستخدم (User Resource Shape)

JSON
{
  "id": 1,
  "name": "mousa",
  "phone": "944123456",
  "phone_country": "+963",
  "email": "mousa@example.com",
  "company_name": "Mousa Trading Co.",
  "created_at": "2026-01-15T10:00:00.000000Z",
  "updated_at": "2026-01-15T10:00:00.000000Z"
}

الشحنات

إدارة دورة حياة الشحنات بالكامل — الإنشاء والتعديل والتأكيد والإلغاء والتعيين للمسارات والعمليات الجماعية.

بادئة الصلاحية: Shipment

نقاط النهاية (Endpoints)

الطريقة المسار الوصف الصلاحية
GET /api/admin/shipments قائمة جميع الشحنات ViewAny:Shipment
GET /api/admin/shipments/paginated قائمة مع ترقيم الصفحات ViewAny:Shipment
GET /api/admin/shipments/{id} جلب شحنة واحدة (بالمعرّف أو رقم الشحنة) View:Shipment
POST /api/admin/shipments إنشاء شحنة Create:Shipment
POST /api/admin/shipments/create-with-user إنشاء/تحديث عميل ثم إنشاء شحنة Create:Shipment
POST /api/admin/shipments/{id} تعديل شحنة Update:Shipment
DELETE /api/admin/shipments/{id} حذف شحنة مسودة Delete:Shipment
POST /api/admin/shipments/{id}/confirm تأكيد مسودة → قيد الانتظار Update:Shipment
POST /api/admin/shipments/{id}/cancel إلغاء الشحنة Update:Shipment
POST /api/admin/shipments/{id}/status تغيير حالة يدوي (مسؤول) Update:Shipment
POST /api/admin/shipments/{id}/assign-route تعيين لمسار Update:Shipment
POST /api/admin/shipments/{id}/unassign-route إلغاء التعيين من المسار Update:Shipment
GET /api/admin/shipments/{id}/events قائمة أحداث الشحنة View:Shipment
POST /api/admin/shipments/bulk/cancel إلغاء جماعي Create:Shipment
POST /api/admin/shipments/bulk/confirm تأكيد جماعي Create:Shipment
POST /api/admin/shipments/bulk/assign-route تعيين جماعي لمسار Create:Shipment

معاملات البحث والتصفية

المعامل النوع الوصف
search string البحث في shipment_number وuser_name وnotes
status string تطابق تام — انظر ShipmentStatuses
type string تطابق تام — انظر ShipmentTypes
user_id integer تصفية حسب العميل
payment_type string تطابق تام — انظر PaymentTypes
priority string تطابق تام — انظر ShipmentPriorities
delivery_date_from date بداية نطاق تاريخ التسليم
delivery_date_to date نهاية نطاق تاريخ التسليم
sort_by string shipment_number، delivery_date، status، created_at
sort_direction string asc أو desc (افتراضي: desc حسب created_at)

جلب شحنة واحدة

GET /api/admin/shipments/{id}

{id} يقبل المعرّف الرقمي أو shipment_number (مثل SH-AB12CD34).

نموذج طلب الإنشاء

الحقل النوع مطلوب التحقق
user_id integer نعم يجب أن يكون موجودًا في users
delivery_date date نعم يجب أن يكون بعد اليوم
payment_type string نعم prepaid أو cod
cod_amount number شرطي مطلوب عند payment_type = cod
notes string لا
priority string لا low أو normal أو high أو urgent — انظر ShipmentPriorities؛ الافتراضي normal
stops array نعم 2 عناصر على الأقل؛ يجب أن يحتوي على pickup واحد بالضبط وdelivery واحد بالضبط
stops.*.type string نعم pickup أو delivery أو stop
stops.*.country string نعم
stops.*.city string نعم
stops.*.lat number نعم -90 إلى 90
stops.*.lng number نعم -180 إلى 180
stops.*.sequence integer نعم الحد الأدنى 1
items array نعم عنصر واحد على الأقل
items.*.name string نعم
items.*.quantity integer نعم الحد الأدنى 1
items.*.weight number لا كغ

إنشاء مع مستخدم (Upsert)

POST /api/admin/shipments/create-with-user

نفس حقول إنشاء الشحنة، مع استبدال user_id بكائن user. يطابق العميل عبر phone + phone_country ويحدّث الاسم/البريد/الشركة إن وُجد، أو ينشئ مستخدمًا جديدًا ثم ينشئ شحنة مسودة.

الحقل النوع مطلوب التحقق
user object نعم بيانات العميل
user.name string نعم بحد أقصى 255
user.phone string نعم رقم صالح لـ user.phone_country
user.phone_country string نعم بحد أقصى 10 (مثل SA)
user.email string لا فريد (يُتجاهل للمستخدم المطابق عند التحديث)
user.company_name string لا
(حقول الشحنة) نفس نموذج الإنشاء باستثناء user_id

مثال:

JSON
{
  "user": {
    "name": "أحمد الفارسي",
    "phone": "0501234567",
    "phone_country": "SA",
    "email": "ahmed@example.com",
    "company_name": "Acme"
  },
  "delivery_date": "2026-07-15",
  "payment_type": "cod",
  "cod_amount": 150,
  "total_weight": 2.5,
  "total_volume": 0.0005,
  "stops": [
    { "type": "pickup", "country": "SA", "city": "Riyadh", "lat": 24.7136, "lng": 46.6753 },
    { "type": "delivery", "country": "SA", "city": "Jeddah", "lat": 21.4858, "lng": 39.1925 }
  ],
  "items": [{ "name": "صندوق إلكترونيات", "quantity": 1, "weight": 2.5 }]
}

شكل مورد الشحنة (Shipment Resource)

JSON
{
  "id": 1,
  "shipment_number": "AB3XZ7QR",
  "user_id": 5,
  "user_name": "أحمد الفارسي",
  "user": { "id": 5, "name": "أحمد الفارسي" },
  "delivery_date": "2026-07-15T00:00:00.000000Z",
  "status": "pending",
  "status_label": "في الانتظار",
  "type": "domestic",
  "type_label": "محلي",
  "payment_type": "cod",
  "payment_type_label": "عند الاستلام",
  "cod_amount": 150,
  "total_weight": 2.5,
  "total_volume": 0.0005,
  "priority": "normal",
  "priority_label": "عادية",
  "priority_color": "primary",
  "notes": "التعامل بحذر",
  "stops": [...],
  "items": [...],
  "events": [...],
  "created_at": "2026-06-21T10:00:00.000000Z",
  "updated_at": "2026-06-21T10:00:00.000000Z"
}

stops وitems وevents موجودة فقط عند جلب الشحنة عبر GET /shipments/{id}.


نقاط توقف الشحنات

قائمة نقاط توقف الشحنات مع فلاتر متعددة — مفيدة لتخطيط المسارات والعمليات اليومية. تتضمن كل نقطة ملخص الشحنة الأم.

بادئة الصلاحية: ShipmentStop

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/shipment-stops قائمة جميع نقاط التوقف ViewAny:ShipmentStop
GET /api/admin/shipment-stops/paginated قائمة مع ترقيم ViewAny:ShipmentStop
GET /api/admin/shipment-stops/{id} جلب نقطة توقف واحدة View:ShipmentStop

معاملات الاستعلام للقائمة

المعامل النوع الوصف
search string يبحث في contact_name, phone, city, area, street, full_address
type string نوع النقطة — pickup, delivery, أو stop
shipment_id integer تصفية حسب الشحنة
shipment_number string تطابق جزئي على shipment_number للشحنة الأم
shipment_status string تطابق تام على status للشحنة الأم — انظر ShipmentStatuses
shipment_type string تطابق تام على type للشحنة الأم — انظر ShipmentTypes
user_id integer تصفية حسب العميل في الشحنة الأم
payment_type string تطابق تام على payment_type للشحنة الأم
priority string تطابق تام على priority للشحنة الأم
delivery_date date تاريخ التسليم للشحنة الأم (يوم محدد)
delivery_date_from date بداية نطاق تاريخ التسليم
delivery_date_to date نهاية نطاق تاريخ التسليم
country string تطابق تام على country للنقطة
city string تطابق تام على city للنقطة
unassigned boolean true = غير مُعيَّنة لمسار assigned أو active
on_route boolean true = مُعيَّنة بالفعل لمسار assigned أو active
sort_by string sequence, type, city, created_at, delivery_date
sort_direction string asc أو desc (افتراضي: desc حسب created_at)

شكل مورد نقطة التوقف

JSON
{
  "id": 12,
  "shipment_id": 4,
  "type": "pickup",
  "type_label": "تحصيل",
  "contact_name": "Warehouse",
  "phone": "0501234567",
  "phone_country": "SA",
  "country": "SA",
  "city": "Riyadh",
  "area": "Al Olaya",
  "street": "King Fahd Rd",
  "building": null,
  "floor": null,
  "apartment": null,
  "lat": 24.7136,
  "lng": 46.6753,
  "full_address": "King Fahd Rd, Al Olaya, Riyadh, SA",
  "sequence": 1,
  "created_at": "2026-06-21T10:00:00.000000Z",
  "updated_at": "2026-06-21T10:00:00.000000Z",
  "shipment": {
    "id": 4,
    "shipment_number": "SH-AB12CD34",
    "delivery_date": "2026-07-15T00:00:00.000000Z",
    "status": "pending",
    "type": "domestic",
    "priority": "normal",
    "user_id": 5,
    "user_name": "Ahmed Al-Farsi",
    "payment_type": "prepaid"
  }
}

إثباتات التوصيل

سجلات تأكيد التوصيل للشحنات.

بادئة الصلاحية: ProofOfDelivery

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/shipments/{shipmentId}/proof-of-deliveries قائمة إثباتات التوصيل للشحنة ViewAny:ProofOfDelivery
POST /api/admin/shipments/{shipmentId}/proof-of-deliveries إنشاء إثبات توصيل Create:ProofOfDelivery
GET /api/admin/proof-of-deliveries/{id} جلب إثبات توصيل واحد View:ProofOfDelivery

نموذج الطلب

الحقل النوع مطلوب التحقق
receiver_name string لا
receiver_phone string لا
receiver_phone_country string لا
delivered_at datetime نعم تاريخ صالح
notes string لا

التأثيرات الجانبية: يُعيّن حالة الشحنة إلى delivered ويُسجّل حدث pod_uploaded.

شكل مورد إثبات التوصيل

JSON
{
  "id": 1,
  "shipment_id": 1,
  "receiver_name": "عمر أحمد",
  "receiver_phone": "0559876543",
  "receiver_phone_country": null,
  "delivered_at": "2026-07-15T14:30:00.000000Z",
  "notes": null,
  "created_by_type": "App\\Models\\Admin",
  "created_by_id": 1,
  "created_by_name": "Admin",
  "shipment": null,
  "created_at": "2026-07-15T14:31:00.000000Z",
  "updated_at": "2026-07-15T14:31:00.000000Z"
}

عمليات التوصيل الفاشلة

سجلات محاولات التوصيل الفاشلة. تُنشأ تلقائيًا عند فشل RouteStop من نوع delivery، أو يدويًا عبر هذه الواجهة.

بادئة الصلاحية: FailedDelivery

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/shipments/{shipmentId}/failed-deliveries قائمة التوصيلات الفاشلة للشحنة ViewAny:FailedDelivery
POST /api/admin/shipments/{shipmentId}/failed-deliveries إنشاء يدوي Create:FailedDelivery
GET /api/admin/failed-deliveries/{id} جلب سجل واحد View:FailedDelivery

نموذج الطلب

الحقل النوع مطلوب التحقق
reason_code string نعم انظر FailedDeliveryReasons
notes string لا

التأثيرات الجانبية: يُعيّن حالة الشحنة إلى delivery_failed ويُسجّل حدث delivery_failed.

شكل مورد التوصيل الفاشل

JSON
{
  "id": 1,
  "shipment_id": 1,
  "reason_code": "customer_refused",
  "reason_code_label": "العميل رفض الاستلام",
  "notes": null,
  "created_by_type": "App\\Models\\Admin",
  "created_by_id": 1,
  "created_by_name": "Admin",
  "shipment": null,
  "created_at": "2026-07-15T14:35:00.000000Z",
  "updated_at": "2026-07-15T14:35:00.000000Z"
}

المسارات

مسارات السائق اليومية مع نقاط توقف مرتبة ومقاييس المسافة وإجراءات دورة الحياة (بدء، إكمال، إلغاء). يمكن إنشاء المسارات يدويًا أو توليدها عبر مهمة التخطيط.

بادئة الصلاحية: Route

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/routes قائمة جميع المسارات ViewAny:Route
GET /api/admin/routes/paginated قائمة مع ترقيم ViewAny:Route
GET /api/admin/routes/{id} مسار واحد مع نقاط التوقف والسائق والمركبة View:Route
POST /api/admin/routes إنشاء مسار مع نقاط توقف Create:Route
POST /api/admin/routes/{id} تحديث مسار Update:Route
DELETE /api/admin/routes/{id} حذف مسار مسودة أو مُعيَّن Delete:Route
POST /api/admin/routes/{id}/start بدء المسار (assigned → active) Update:Route
POST /api/admin/routes/{id}/complete إكمال المسار (active → completed) Update:Route
POST /api/admin/routes/{id}/cancel إلغاء المسار Update:Route
GET /api/admin/routes/{id}/stops قائمة نقاط التوقف مرتبة View:Route
GET /api/admin/routes/{id}/assignments قائمة سجل تعيينات السائق للمسار ViewAny:RouteAssignment
POST /api/admin/routes/plan إرسال مهمة تخطيط المسارات Create:Route
GET /api/admin/routes/plan/result جلب ملخص التخطيط المخزّن ViewAny:Route

معاملات الاستعلام للقائمة

المعامل النوع الوصف
status string تطابق تام — انظر RouteStatuses
driver_id integer تصفية حسب السائق
vehicle_id integer تصفية حسب المركبة
route_date date تصفية حسب تاريخ المسار
sort_by string route_number, route_date, status, created_at
sort_direction string asc أو desc (افتراضي: desc حسب route_date)

نموذج طلب الإنشاء

الحقل النوع مطلوب التحقق
driver_id integer نعم يجب أن يكون موجودًا في drivers؛ يجب أن يكون للسائق تعيين مركبة نشط
route_date date نعم
stops array نعم عنصر واحد على الأقل؛ قائمة مرتبة من معرفات shipment_stop — يُعيَّن الترتيب تلقائيًا
stops.* integer نعم يجب أن يكون موجودًا في shipment_stops؛ فريد؛ غير مُعيَّن لمسار نشط؛ لنفس الشحنة يجب أن يأتي الاستلام قبل التسليم

غير مقبول عند الإنشاء: vehicle_id, status, total_stops, optimized_distance, duration — يتم حلها أو حسابها من الخادم.

سلوك الخادم:

  • يحل vehicle_id من أحدث DriverVehicleAssignment نشط للسائق
  • يُعيّن status إلى assigned (السائق مُعيَّن ولم يبدأ بعد)
  • يحسب total_stops, optimized_distance (كم), وduration (دقيقة) من إحداثيات نقاط التوقف
  • ينشئ سجلات RouteStop مع أوقات الوصول/المغادرة المتوقعة
  • يُعيّن الشحنات المرتبطة (pending أو delivery_failed) إلى assigned

أخطاء:

  • 422 vehicleAssignmentNotFound — لا يوجد تعيين مركبة نشط للسائق
  • 422 shipmentStopAlreadyOnRoute — إحدى النقاط مُعيَّنة بالفعل لمسار نشط/مُعيَّن
  • 422 deliveryStopBeforePickupStop — نقطة التسليم تظهر قبل نقطة الاستلام لنفس الشحنة

مثال على نموذج الطلب:

JSON
{
  "driver_id": 1,
  "route_date": "2026-06-25",
  "stops": [10, 11, 15]
}

نموذج طلب التحديث

الحقل النوع مطلوب التحقق
driver_id integer لا يُعيد حل vehicle_id من تعيين السائق الجديد
route_date date لا يُعيد حساب مقاييس نقاط التوقف عند التغيير
status string لا انظر RouteStatuses
stops array لا يستبدل جميع نقاط التوقف ويُعيد حساب المقاييس

غير مقبول عند التحديث: vehicle_id, total_stops, optimized_distance, duration.

مسموح فقط عندما لا يكون المسار في حالة نهائية (completed, cancelled).

طلب تخطيط المسارات

POST /api/admin/routes/plan

الحقل النوع مطلوب التحقق
date date نعم تاريخ التخطيط
driver_ids array لا تصفية اختيارية؛ كل عنصر يجب أن يكون موجودًا في drivers

يُرسل مهمة غير متزامنة. استعلم عبر GET /api/admin/routes/plan/result?date=YYYY-MM-DD للحصول على الملخص.

شكل مورد المسار (Route Resource)

JSON
{
  "id": 1,
  "route_number": "AB12CD34",
  "route_date": "2026-06-25T00:00:00.000000Z",
  "status": "assigned",
  "status_label": "تم تخصيص السائق",
  "total_stops": 3,
  "optimized_distance": 42.5,
  "duration": 95.0,
  "driver": { "...": "DriverResource عند التحميل" },
  "vehicle": { "...": "VehicleResource عند التحميل" },
  "stops": [ { "...": "RouteStopResource عند التحميل" } ],
  "created_at": "2026-06-24T20:00:00.000000Z",
  "updated_at": "2026-06-24T20:00:00.000000Z"
}

driver وvehicle وstops تظهر فقط عند تحميل العلاقات عبر GET /routes/{id} أو قوائم تحمّل العلاقات.

تعيينات المسار

يتتبّع سجل تعيين السائق للمسار. يمكن تعيين سائق ثم إلغاء تعيينه عند إعادة تعيين المسار.

بادئة الصلاحية: RouteAssignment

الطريقة المسار الوصف الصلاحية
GET /api/admin/routes/{id}/assignments قائمة التعيينات للمسار ViewAny:RouteAssignment

شكل مورد تعيين المسار

JSON
{
  "id": 1,
  "assigned_at": "2026-06-01T08:00:00.000000Z",
  "unassigned_at": null,
  "driver": {
    "id": 3,
    "driver_number": "482910",
    "name": "mousa"
  },
  "created_at": "2026-06-01T08:00:00.000000Z",
  "updated_at": "2026-06-01T08:00:00.000000Z"
}
الحقل ملاحظات
driver DriverResource متداخل عند تحميل العلاقة
unassigned_at null = مُعيَّن حاليًا لهذا المسار

نقاط توقف المسار

نقاط توقف مرتبة على مسار السائق، مرتبطة بنقاط توقف الشحنة.

بادئة الصلاحية: Route

نقاط النهاية

الطريقة المسار الوصف الصلاحية
GET /api/admin/route-stops/{id} جلب نقطة توقف واحدة ViewAny:Route
POST /api/admin/route-stops/{id} تحديث حالة/أوقات نقطة التوقف Update:Route
DELETE /api/admin/route-stops/{id} حذف نقطة توقف Delete:Route

تُنشأ نقاط التوقف تلقائيًا عند إنشاء أو تحديث مسار عبر POST /api/admin/routes.

نموذج طلب التحديث

الحقل النوع مطلوب التحقق
status string لا انظر RouteStopStatuses
arrived_at datetime لا
completed_at datetime لا

شكل مورد نقطة توقف المسار (RouteStop Resource)

JSON
{
  "id": 1,
  "route_id": 1,
  "shipment_stop_id": 10,
  "sequence": 1,
  "status": "pending",
  "status_label": "قيد الانتظار",
  "stop_type": "pickup",
  "stop_type_label": "تحصيل",
  "lat": 24.7136,
  "lng": 46.6753,
  "full_address": "Riyadh, SA",
  "contact_name": "Ali Hassan",
  "phone": "0501234567",
  "shipment": { "...": "ShipmentResource عند التحميل" },
  "distance_from_previous_km": 5.2,
  "estimated_minutes_from_previous": 12.5,
  "estimated_arrival_at": "2026-06-25T08:12:00.000000Z",
  "estimated_departure_at": "2026-06-25T08:27:00.000000Z",
  "arrived_at": null,
  "completed_at": null,
  "created_at": "2026-06-24T20:00:00.000000Z",
  "updated_at": "2026-06-24T20:00:00.000000Z"
}

مرجع نماذج النطاق

المعرّض حاليًا عبر واجهة برمجة التطبيقات

النموذج الجدول الوصف الحقول الرئيسية
Admin admins مستخدمو المكتب الخلفي name, email, password, fcm_token
Role roles أدوار Spatie (الحارس: admin) name, guard_name
Permission permissions صلاحيات Spatie name, guard_name
Driver drivers سائقو التوصيل driver_number, name, phone, working_days, work_start_time, work_end_time, lat, lng, is_active
Vehicle vehicles مركبات الأسطول plate_number, owner_type, owner_id, max_weight, max_volume, is_active
DriverVehicleAssignment driver_vehicle_assignments رابط السائق ↔ المركبة driver_id, vehicle_id, assigned_at, released_at
DriverUnavailability driver_unavailabilities إجازة السائق driver_id, start_date, end_date, reason
User users العملاء / الشاحنون name, phone, phone_country, email, company_name
Shipment shipments طلبات التوصيل shipment_number, user_id, status, type, payment_type, delivery_date
ShipmentItem shipment_items محتويات الشحنة name, quantity, weight, declared_value
ShipmentStop shipment_stops نقاط التحصيل/التسليم type, lat, lng, sequence
ShipmentEvent shipment_events سجل أحداث الشحنة event_type, data, causer_type, causer_id
ProofOfDelivery proof_of_deliveries تأكيد التوصيل receiver_name, delivered_at
FailedDelivery failed_deliveries محاولات التوصيل الفاشلة reason_code, notes
Route routes مسارات السائق اليومية route_number, driver_id, vehicle_id, route_date, status, total_stops, optimized_distance, duration
RouteStop route_stops نقاط توقف مرتبة على المسار shipment_stop_id, sequence, status, estimated_arrival_at, estimated_departure_at
RouteAssignment route_assignments سجل تعيين السائق على المسار route_id, driver_id, assigned_at, unassigned_at

النطاق المخطّط (غير موجود بعد في واجهة برمجة التطبيقات)

هذه النماذج موجودة في قاعدة البيانات ولكن ليس لها نقاط نهاية HTTP مخصصة بعد.

StaticContent (static_contents)

مخزن إعدادات CMS / التطبيق بصيغة مفتاح–قيمة (غير موجود بعد في واجهة برمجة التطبيقات).

الحقل النوع ملاحظات
key string المفتاح الأساسي؛ انظر StaticContentTypes
value string نص عادي أو قيمة مُرمّزة JSON

مخطط علاقات الكيانات (نظرة عامة)

TEXT
User ──< Shipment ──< ShipmentItem
                  ──< ShipmentStop ──< RouteStop >── Route >── Driver
                  ──< ShipmentEvent                  └── Vehicle
                  ──< ProofOfDelivery
                  ──< FailedDelivery

Driver ──< DriverVehicleAssignment >── Vehicle
       ──< DriverUnavailability
       ──< RouteAssignment >── Route

Admin ──< Role ──< Permission

مرجع التعدادات (Enums)

جميع قيم التعدادات هي سلاسل snake_case. خزّنها كثوابت سلسلة في الواجهة الأمامية.

OwnerTypes

مُستخدم في واجهة برمجة التطبيقات اليوم — ملكية المركبة.

القيمة التسمية العربية القواعد
company الشركة يجب أن يكون owner_id هو null
driver سائق يجب أن يكون owner_id معرّف سائق صالحًا

تُعيد واجهة برمجة التطبيقات كلًا من owner_type (القيمة) و owner_type_label (التسمية العربية).

TypeScript مقترح:

TYPESCRIPT
type OwnerType = 'company' | 'driver';

ShipmentStatuses

مخطّط — حالة دورة حياة الشحنة.

القيمة التسمية العربية لون واجهة المستخدم المقترح
draft مسودة secondary
pending في الانتظار warning
assigned تم التخصيص لسائق primary
pickup_in_progress قيد التحصيل warning
picked_up تم التحصيل success
at_hub في المخزن info
out_for_delivery قيد التسليم primary
delivered تم التسليم success
delivery_failed فشل التسليم danger
returned مرتجع warning
cancelled تم الإلغاء danger

التدفق النموذجي:

TEXT
draft → pending → assigned → pickup_in_progress → picked_up → at_hub
  → out_for_delivery → delivered
                                    ↘ delivery_failed → returned
Any state → cancelled

ShipmentTypes

القيمة التسمية العربية
domestic محلي
international دولية

ShipmentPriorities

مستخدم في واجهة برمجة التطبيقات اليوم — أولوية الشحنة للتخطيط والتصفية.

القيمة التسمية العربية لون واجهة مقترح
low منخفضة secondary
normal عادية primary
high عالية warning
urgent عاجلة danger

الافتراضي normal عند الإنشاء إذا لم يُرسل الحقل. تُخطَّط الشحنات ذات الأولوية الأعلى أولًا أثناء تخطيط المسارات.


ShipmentStopTypes

القيمة التسمية العربية الوصف
pickup تحصيل جمع البضائع من المرسل
delivery تسليم التسليم للمستلم
stop موقف محطة وسيطة

PaymentTypes

القيمة التسمية العربية ملاحظات
cod عند الاستلام الدفع عند الاستلام؛ يتطلب cod_amount
prepaid مقدما مدفوع مسبقًا

RouteStatuses

القيمة التسمية العربية
draft مسودة
assigned تم تخصيص السائق
active فعال
completed مكتمل
cancelled ملغي

RouteStopStatuses

القيمة التسمية العربية
pending قيد الانتظار
arrived تم الوصول
completed مكتمل
failed فشل
skipped تخطي

ShipmentEvents

أنواع أحداث الجدول الزمني المُسجّلة على الشحنات. يحتوي كل حدث على حمولة JSON في حقل data.

القيمة التسمية العربية مفاتيح data
shipment_created تم إنشاء الشحنة shipment_number, type, payment_type, delivery_date
status_changed تم تغيير الحالة from_status, to_status
route_assigned تم تعيين المسار route_id, driver_id, driver_name
route_unassigned تم إلغاء تعيين المسار route_id, reason
driver_assigned تم تخصيص السائق driver_id, driver_name
route_created تم إنشاء الرحلة route_id
pickup_started تم بدء التحصيل stop_id, driver_id, driver_name
pickup_completed تم إنهاء التحصيل stop_id, arrived_at, completed_at
out_for_delivery خرجت للتسليم route_id, driver_id, driver_name
delivery_failed فشل التسليم stop_id, reason_code, notes
delivered تم التسليم stop_id, receiver_name, delivered_at
pod_uploaded تم تحميل إثبات التوصيل receiver_name, delivered_at, notes
cancelled تم الإلغاء reason, cancelled_by_type, cancelled_by_id
returned تم الإرجاع reason, returned_at

FailedDeliveryReasons

القيمة التسمية العربية
customer_unavailable العميل غير متاح
wrong_address عنوان خاطئ
customer_refused العميل رفض الاستلام
unable_to_contact تعذر التواصل مع العميل
damaged_package الطرد تالف
other أخرى

MediaTypes

أسماء مجموعات الوسائط الداخلية (تُستخدم لرفع الصور).

القيمة يُستخدم لـ
admin_image صور ملف المسؤول الشخصي
driver_image صور ملف السائق الشخصي
user_image صور ملف المستخدم الشخصي (مستقبلًا)

StaticContentTypes

مفاتيح إعدادات CMS / التطبيق (غير موجودة بعد في واجهة برمجة التطبيقات).

القيمة التسمية العربية
privacy_policy سياسة الخصوصية
commission عمولة الإدارة
social_media المواقع الاجتماعية
android_app_version نسخة التطبيق للاندرويد
ios_app_version نسخة التطبيق لل IOS
android_provider_app_version نسخة التطبيق للاندرويد للمزود
ios_provider_app_version نسخة التطبيق لل IOS للمزود

NotificationTypes

فئات الإشعارات الفورية (تعداد مدعوم بـ PHP).

القيمة
general
wallet_deposit
wallet_withdraw
new_offer
offer_accepted
offer_rejected
order_status_changed
new_order

أيام العمل (ليست تعداد PHP)

أيام جدول السائق. تُقبل كقيم مصفوفة في طلبات الإنشاء/التحديث.

القيمة اليوم
sun الأحد
mon الاثنين
tue الثلاثاء
wed الأربعاء
thu الخميس
fri الجمعة
sat السبت

TypeScript مقترح:

TYPESCRIPT
type WorkingDay = 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat';

مرجع الصلاحيات

تتحكم الصلاحيات فيما يمكن لكل مسؤول فعله. تحقّق منها في جانب العميل لإظهار/إخفاء عناصر الواجهة.

اتفاقية التسمية

TEXT
{Action}:{Model}
الإجراء الوصف
ViewAny الوصول إلى القائمة/الفهرس
View عرض سجل واحد
Create إنشاء سجل جديد
Update تعديل سجل موجود
Delete حذف سجل
Reorder إعادة ترتيب السجلات (إن وُجد)

أمثلة:

  • ViewAny:Driver — يمكنه عرض قائمة السائقين
  • Create:Vehicle — يمكنه إنشاء مركبات
  • Update:Admin — يمكنه تعديل المسؤولين
  • Delete:Role — يمكنه حذف الأدوار

الصلاحيات المخصّصة

هذه لا ترتبط بنموذج CRUD:

الصلاحية الوصف
Export:Reports تصدير التقارير
Send:Notifications إرسال الإشعارات الفورية
Manage:AppSettings إدارة إعدادات التطبيق
Assign:Routes تعيين المسارات للسائقين
Track:Deliveries تتبّع التسليمات المباشرة

كيفية التحقق من الصلاحيات في الواجهة الأمامية

بعد تسجيل الدخول، افحص data.admin.permission_groups:

TYPESCRIPT
function hasPermission(
  permissionGroups: PermissionGroup[],
  permissionName: string
): boolean {
  return permissionGroups.some(group =>
    group.permissions.some(p => p.name === permissionName)
  );
}

// Usage
if (hasPermission(admin.permission_groups, 'Create:Driver')) {
  // Show "Add Driver" button
}

دور المسؤول الأعلى (super admin) لديه جميع الصلاحيات ضمنيًا.


معالجة الأخطاء

رموز حالة HTTP

الرمز المعنى متى
200 نجاح عملية عادية
401 غير مصرّح صلاحية مفقودة/غير صالحة، بيانات اعتماد خاطئة
403 ممنوع غير مصادق (لا يوجد رمز/رمز غير صالح)
404 غير موجود المسار أو المورد غير موجود
422 خطأ تحقق جسم/استعلام طلب غير صالح
500 خطأ خادم فشل غير متوقع

رسائل الخطأ الشائعة

مفتاح الرسالة النص الإنجليزي الحالة
credentialsError Wrong Credentials 401
Unauthenticated Please login first 403
Unauthorized You do not have permissions to perform this action 401
cannotDeleteCurrentAdmin You cannot delete your own admin account 403
cannotModifySuperAdmin Super admin role cannot be modified 403
vehicleAlreadyAssigned This vehicle is already assigned to a driver 422
vehicleAssignmentNotFound No active vehicle assignment found for this driver 404
couldNotCreateToken Could not create authentication token 500
couldNotLogout Could not log out 500
cannotUpdateShipment لا يمكن تعديل الشحنة في حالتها الحالية 422
cannotConfirmShipment يمكن تأكيد الشحنات المسودة فقط 422
shipmentAlreadyCancelled الشحنة في حالة نهائية ولا يمكن إلغاؤها 422
cannotDeleteShipment يمكن حذف الشحنات المسودة فقط 422
shipmentNotPending يجب أن تكون الشحنة في حالة انتظار لتعيين مسار 422
shipmentNotAssigned يجب أن تكون الشحنة في حالة مُعيَّنة لإلغاء تعيين المسار 422
invalidShipmentStatus حالة الشحنة المُدخلة غير صالحة 422

أخطاء التحقق تُعيد أول رسالة تحقق كـ message.

شكل استجابة الخطأ

JSON
{
  "status": "Error",
  "message": "Wrong Credentials",
  "data": null,
  "statusCode": 401
}

قائمة التحقق لتكامل الواجهة الأمامية

  • تخزين JWT من استجابة تسجيل الدخول (data.token)
  • إرسال Authorization: Bearer {token} مع كل طلب مصادق
  • ضبط Accept-Language: en أو ar للرسائل المترجمة
  • استخدام POST لجميع التحديثات (وليس PUT/PATCH)
  • استخدام multipart/form-data عند رفع حقول image
  • التحكم في الواجهة بالتحقق من permission_groups من استجابة تسجيل الدخول/الملف الشخصي
  • معالجة الغلاف القياسي { status, message, data, statusCode }
  • استخدام نقاط النهاية المُقسّمة مع معامل page للجداول
  • تمرير search, sort_by, sort_direction للقوائم القابلة للتصفية
  • للمركبات: فرض قواعد owner_id بناءً على owner_type
  • للسائقين: إرسال working_days كمصفوفة؛ الأوقات كـ HH:MM أو HH:MM:SS
  • للشحنات: يجب أن يحتوي مصفوف stops على نقطة pickup واحدة بالضبط ونقطة delivery واحدة بالضبط
  • للشحنات: cod_amount مطلوب عند payment_type = cod
  • معالجة أحداث status_changed من GET /shipments/{id}/events لعرض الجدول الزمني
  • تعيين المسار: يجب أن تكون الشحنة pending قبل assign-route؛ وassigned قبل unassign-route
  • إنشاء المسار: أرسل driver_id + stops[]؛ لا ترسل vehicle_id أو status أو المقاييس — الخادم يحسبها
  • إنشاء المسار يتطلب أن يكون للسائق تعيين مركبة نشط
  • تخطيط المسارات: أرسل عبر POST /routes/plan، واستعلم عبر GET /routes/plan/result?date=

فهرس المسارات (مرجع سريع)

الطريقة المسار
POST /api/admin/login
POST /api/admin/logout
GET /api/admin/profile
POST /api/admin/profile
GET /api/admin/dashboard/overview
GET /api/admin/dashboard/trends
GET /api/admin/permissions
GET/POST/DELETE /api/admin/roles, /api/admin/roles/paginated, /api/admin/roles/{id}, /api/admin/roles/{id}/permissions
GET/POST/DELETE /api/admin/admins, /api/admin/admins/paginated, /api/admin/admins/{id}
GET/POST/DELETE /api/admin/drivers, /api/admin/drivers/paginated, /api/admin/drivers/{id}
GET/POST /api/admin/drivers/{id}/vehicle-assignments, .../assign, .../unassign
GET /api/admin/drivers/{id}/unavailabilities
GET/POST/DELETE /api/admin/vehicles, /api/admin/vehicles/paginated, /api/admin/vehicles/{id}
GET/POST/DELETE /api/admin/driver-unavailabilities, .../paginated, .../{id}
GET/POST/DELETE /api/admin/users, /api/admin/users/paginated, /api/admin/users/{id}
GET/POST/DELETE /api/admin/shipments, /api/admin/shipments/paginated, /api/admin/shipments/{id}
POST /api/admin/shipments/{id}/confirm, /api/admin/shipments/{id}/cancel, /api/admin/shipments/{id}/status
POST /api/admin/shipments/{id}/assign-route, /api/admin/shipments/{id}/unassign-route
GET /api/admin/shipments/{id}/events
POST /api/admin/shipments/bulk/cancel, /api/admin/shipments/bulk/confirm, /api/admin/shipments/bulk/assign-route
GET /api/admin/shipment-stops, /api/admin/shipment-stops/paginated, /api/admin/shipment-stops/{id}
GET/POST /api/admin/shipments/{id}/proof-of-deliveries
GET /api/admin/proof-of-deliveries/{id}
GET/POST /api/admin/shipments/{id}/failed-deliveries
GET /api/admin/failed-deliveries/{id}
GET/POST/DELETE /api/admin/routes, /api/admin/routes/paginated, /api/admin/routes/{id}
POST /api/admin/routes/{id}/start, /api/admin/routes/{id}/complete, /api/admin/routes/{id}/cancel
GET /api/admin/routes/{id}/stops, /api/admin/routes/{id}/assignments
POST/GET /api/admin/routes/plan, /api/admin/routes/plan/result
GET/POST/DELETE /api/admin/route-stops/{id}

واجهة برمجة تطبيق السائق (Driver App API)

واجهة تطبيق السائق (/api/driver/*) مخصصة للتطبيق الجوال للسائقين. تستخدم نفس آلية JWT مع حارس driver. الرموز لا تنتهي صلاحيتها (expires_in: null).

مصادقة السائق

الطريقة المسار المصادقة الوصف
POST /api/driver/login عام تسجيل الدخول بـ phone, phone_country, password. يمكن إرسال fcm_token. يعيد JWT + ملف السائق.
POST /api/driver/logout مطلوبة إلغاء صلاحية الرمز الحالي.

ملف السائق

الطريقة المسار الوصف
GET /api/driver/profile جلب ملف السائق الكامل مع المركبة المُعيَّنة.
POST /api/driver/profile تعديل name, email, password (اختياري، الحد الأدنى 6 أحرف).
POST /api/driver/fcm-token تحديث رمز الإشعارات. الجسم: { "fcm_token": "..." }
POST /api/driver/location تحديث إحداثيات GPS. الجسم: { "lat": 24.71, "lng": 46.67 }

مسارات السائق

جميع مسارات الطلبات مقيّدة تلقائيًا بالسائق المصادَق عليه. للسائق مسار واحد في اليوم.

الطريقة المسار الوصف
GET /api/driver/routes قائمة مقسّمة (15/صفحة). فلاتر: ?status=assigned&date=2026-07-02
GET /api/driver/routes/today مسار اليوم. يعيد 404 إذا لم يُعيَّن مسار لليوم.
GET /api/driver/routes/{id} المسار الكامل مع نقاط التوقف. كل shipment داخل نقطة التوقف يتضمن items ليعرف السائق ما يجب استلامه أو تسليمه.
POST /api/driver/routes/{id}/start بدء المسار: assigned → active.
POST /api/driver/routes/{id}/complete إنهاء المسار: active → completed.

نقاط توقف المسار

الطريقة المسار الوصف
GET /api/driver/routes/{routeId}/stops جميع نقاط التوقف مرتبة حسب sequence.
GET /api/driver/routes/{routeId}/stops/{stopId} تفاصيل نقطة التوقف الكاملة. shipment.items يعرض ما يجب استلامه أو تسليمه.
POST /api/driver/routes/{routeId}/stops/{stopId}/arrive تسجيل الوصول: pending → arrived. يجب أن يكون المسار active (مُبدَأ) أولاً.
POST /api/driver/routes/{routeId}/stops/{stopId}/complete إكمال نقطة التوقف. انظر المنطق أدناه.
POST /api/driver/routes/{routeId}/stops/{stopId}/fail تسجيل فشل التسليم. الجسم: reason_code, notes?.
POST /api/driver/routes/{routeId}/stops/{stopId}/skip تخطي نقطة التوقف.

منطق إكمال نقطة التوقف حسب النوع:

نوع النقطة ما يحدث
delivery إنشاء ProofOfDelivery، تحديث الشحنة إلى delivered، حدث delivered. الجسم: receiver_name, receiver_phone, notes?
pickup تحديث الشحنة إلى picked_up، حدث pickup_completed. لا يحتاج جسمًا.

قيم reason_code لنقطة الفشل: customer_unavailable, wrong_address, customer_refused, unable_to_contact, damaged_package, other.


مُولّد من قاعدة شفرة shipping_system. آخر تحديث: يوليو 2026.