diff --git a/backend/Admin/rides/admin_get_rides_by_phone.php b/backend/Admin/rides/admin_get_rides_by_phone.php index af1bee8..df4af02 100644 --- a/backend/Admin/rides/admin_get_rides_by_phone.php +++ b/backend/Admin/rides/admin_get_rides_by_phone.php @@ -1,6 +1,25 @@ encryptData($raw); try { - error_log("[get_last_ride] Searching passenger with phone=$raw"); + error_log("[get_last_ride] Searching phone normalized=$raw"); // 1) ابحث عن الراكب بالهاتف المشفّر $selP = $con->prepare(" SELECT id, first_name, last_name, phone FROM passengers - WHERE phone =:enc_raw + WHERE phone = :enc_raw LIMIT 1 "); $selP->execute(['enc_raw' => $enc_raw]); $passenger = $selP->fetch(PDO::FETCH_ASSOC); - if (!$passenger) { - error_log("[get_last_ride] Passenger not found (phone=$raw)"); - jsonError('Passenger not found for provided phone'); + // 2) ابحث عن السائق بالهاتف المشفّر + $selD = $con->prepare(" + SELECT id AS driverID, first_name, last_name, phone + FROM driver + WHERE phone = :enc_raw + LIMIT 1 + "); + $selD->execute(['enc_raw' => $enc_raw]); + $driver = $selD->fetch(PDO::FETCH_ASSOC); + + $userId = null; + $userType = null; + + if ($passenger) { + $userId = $passenger['id']; + $userType = 'passenger'; + error_log("[get_last_ride] Passenger found id=" . $userId); + } + if ($driver) { + $userId = $driver['driverID']; + $userType = 'driver'; + error_log("[get_last_ride] Driver found id=" . $userId); + } + + if (!$userId) { + error_log("[get_last_ride] User not found (phone=$raw)"); + jsonError('Phone number not found in system'); exit; } - error_log("[get_last_ride] Passenger found id=" . $passenger['id']); + // 3) تحديد حقل البحث في الرحلة + $userField = ($userType === 'driver') ? 'r.driver_id' : 'r.passenger_id'; - // 2) آخر رحلة لهذا الراكب + // فلترة حسب الحالة إذا أُرسلت + $filterStatus = filterRequest('status'); + $whereExtra = ''; + $params = [':uid' => $userId]; + + if (!empty($filterStatus) && $filterStatus !== 'all') { + $whereExtra = "AND r.status = :filter_status"; + $params[':filter_status'] = $filterStatus; + } + + // 4) آخر 20 رحلة لهذا المستخدم $rideStmt = $con->prepare(" SELECT r.id, @@ -58,43 +113,63 @@ try { r.rideTimeStart, r.rideTimeFinish, d.first_name AS driver_first_name, - d.last_name AS driver_last_name + d.last_name AS driver_last_name, + d.phone AS d_phone, + p.first_name AS p_fname, + p.last_name AS p_lname, + p.phone AS p_phone FROM ride r LEFT JOIN driver d ON d.id = r.driver_id - WHERE r.passenger_id = :pid + LEFT JOIN passengers p ON p.id = r.passenger_id + WHERE $userField = :uid $whereExtra ORDER BY r.created_at DESC, r.id DESC - LIMIT 1 + LIMIT 20 "); - $rideStmt->execute(['pid' => $passenger['id']]); - $ride = $rideStmt->fetch(PDO::FETCH_ASSOC); + $rideStmt->execute($params); + $rides = $rideStmt->fetchAll(PDO::FETCH_ASSOC); - if (!$ride) { - error_log("[get_last_ride] No rides found for passenger_id=" . $passenger['id']); - jsonError('No rides found for this passenger'); - exit; + // 5) فك تشفير الأسماء + if ($passenger) { + $passenger['first_name'] = $encryptionHelper->decryptData($passenger['first_name']); + $passenger['last_name'] = $encryptionHelper->decryptData($passenger['last_name']); + $passenger['phone'] = $encryptionHelper->decryptData($passenger['phone']); + } + if ($driver) { + $driver['first_name'] = $encryptionHelper->decryptData($driver['first_name']); + $driver['last_name'] = $encryptionHelper->decryptData($driver['last_name']); + $driver['phone'] = $encryptionHelper->decryptData($driver['phone']); } - error_log("[get_last_ride] Found ride id=" . $ride['id'] . " for passenger_id=" . $passenger['id']); + foreach ($rides as &$ride) { + if (!empty($ride['driver_first_name'])) { + $ride['driver_first_name'] = $encryptionHelper->decryptData($ride['driver_first_name']); + } + if (!empty($ride['driver_last_name'])) { + $ride['driver_last_name'] = $encryptionHelper->decryptData($ride['driver_last_name']); + } + if (!empty($ride['d_phone'])) { + $ride['d_phone'] = $encryptionHelper->decryptData($ride['d_phone']); + } + if (!empty($ride['p_fname'])) { + $ride['p_fname'] = $encryptionHelper->decryptData($ride['p_fname']); + } + if (!empty($ride['p_lname'])) { + $ride['p_lname'] = $encryptionHelper->decryptData($ride['p_lname']); + } + if (!empty($ride['p_phone'])) { + $ride['p_phone'] = $encryptionHelper->decryptData($ride['p_phone']); + } + } + unset($ride); - // فك التشفير - $passenger['first_name'] = $encryptionHelper->decryptData($passenger['first_name']); - $passenger['last_name'] = $encryptionHelper->decryptData($passenger['last_name']); - $passenger['phone'] = $encryptionHelper->decryptData($passenger['phone']); - $ride['driver_first_name'] = $encryptionHelper->decryptData($ride['driver_first_name']); - $ride['driver_last_name'] = $encryptionHelper->decryptData($ride['driver_last_name']); - - // 3) اطبع النتيجة + // 6) الرد $response = [ - 'passenger' => [ - 'id' => $passenger['id'], - 'first_name' => $passenger['first_name'], - 'last_name' => $passenger['last_name'], - 'phone' => $passenger['phone'], - ], - 'ride' => $ride + 'user_type' => $userType, + 'user' => $userType === 'driver' ? $driver : $passenger, + 'rides' => $rides ]; - error_log("[get_last_ride] Success response for passenger_id=" . $passenger['id']); + error_log("[get_last_ride] Success response for " . $userType . " id=" . $userId); jsonSuccess($response); } catch (Throwable $e) { diff --git a/backend/Admin/rides/admin_update_ride_status.php b/backend/Admin/rides/admin_update_ride_status.php index b49b98c..5f859f0 100644 --- a/backend/Admin/rides/admin_update_ride_status.php +++ b/backend/Admin/rides/admin_update_ride_status.php @@ -12,10 +12,11 @@ if (empty($rideId) || empty($status)) { exit; } -/* whitelist للحالات المسموحة – عدّل حسب نظامك */ +/* whitelist للحالات المسموحة – تطابق حالات DB الفعلية */ $allowed = [ - 'Pending', 'Accepted', 'EnRoute', 'Arrived', - 'Started', 'Completed', 'Canceled' + 'New', 'waiting', 'wait', 'Apply', 'Applied', + 'Arrived', 'arrived', 'Begin', 'Finished', + 'Cancel', 'CancelFromDriver', 'CancelFromPassenger', 'TimeOut' ]; if (!in_array($status, $allowed, true)) { diff --git a/backend/Admin/rides/get_rides_by_status.php b/backend/Admin/rides/get_rides_by_status.php index bd6ba25..01c4f64 100644 --- a/backend/Admin/rides/get_rides_by_status.php +++ b/backend/Admin/rides/get_rides_by_status.php @@ -12,31 +12,32 @@ try { $params = []; $whereClause = ""; - // --- منطق ترجمة الحالات (Mapping Logic) --- + // --- منطق ترجمة الحالات (Mapping Logic) - مصحح ليطابق حالات DB الفعلية --- switch ($statusFilter) { case 'All': $whereClause = ""; // لا يوجد شرط، اجلب الكل break; - - case 'Begin': - // قد تكون الرحلة بدأت أو وصل السائق - $whereClause = "WHERE r.status IN ('Begin','Apply','Applied')"; + + case 'Pending': + // الرحلات المعلقة/الجديدة: بانتظار سائق + $whereClause = "WHERE r.status IN ('New','nothing','waiting','wait')"; break; - case 'New': - $whereClause = "WHERE r.status = 'New'"; + case 'Begin': + // الرحلات الجارية: من قبول السائق إلى بدء التشغيل + $whereClause = "WHERE r.status IN ('Apply','Applied','Arrived','arrived','Begin')"; break; case 'Completed': - // في قاعدة البيانات الحالة اسمها Finished + // الرحلات المكتملة $whereClause = "WHERE r.status = 'Finished'"; break; case 'Canceled': - // نجمع كل حالات الإلغاء الممكنة - $whereClause = "WHERE r.status IN ('Cancel', 'CancelFromDriverAfterApply', 'TimeOut')"; + // جميع أنواع الإلغاء + $whereClause = "WHERE r.status IN ('Cancel','CancelFromDriver','CancelFromDriverAfterApply','CancelFromPassenger','TimeOut')"; break; - + default: // في حال تم إرسال حالة محددة غير المذكورين $whereClause = "WHERE r.status = ?"; diff --git a/backend/Admin/rides/monitorRide.php b/backend/Admin/rides/monitorRide.php index b6900a9..b3adf4c 100644 --- a/backend/Admin/rides/monitorRide.php +++ b/backend/Admin/rides/monitorRide.php @@ -1,11 +1,34 @@ prepare("SELECT id AS customerID FROM passengers WHERE ph $customerQuery->execute([':phone' => $encPhone]); $customer = $customerQuery->fetch(PDO::FETCH_ASSOC); - // حدد نوع المستخدم $userType = ''; $driverID = null; @@ -44,14 +66,16 @@ if ($driver) { } //------------------------------------------------------------------------ -// 2) جلب آخر رحلة حالتها "بدأت" بناءً على نوع المستخدم +// 2) جلب آخر رحلة حالتها نشطة (Apply, Applied, Arrived, Begin) //------------------------------------------------------------------------ +$activeStatuses = "'Apply','Applied','Arrived','arrived','Begin'"; + if ($userType == 'driver') { error_log("[MONITOR_RIDE] 4. Searching for active ride for Driver ID: " . $driverID); $rideQuery = $con->prepare(" SELECT * FROM ride - WHERE driver_id = :driverID AND status = 'Begin' + WHERE driver_id = :driverID AND status IN ($activeStatuses) ORDER BY id DESC LIMIT 1 "); $rideQuery->execute([':driverID' => $driverID]); @@ -59,7 +83,7 @@ if ($userType == 'driver') { error_log("[MONITOR_RIDE] 4. Searching for active ride for Customer ID: " . $customerID); $rideQuery = $con->prepare(" SELECT * FROM ride - WHERE passenger_id = :customerID AND status = 'Begin' + WHERE passenger_id = :customerID AND status IN ($activeStatuses) ORDER BY id DESC LIMIT 1 "); $rideQuery->execute([':customerID' => $customerID]); @@ -68,23 +92,20 @@ if ($userType == 'driver') { $ride = $rideQuery->fetch(PDO::FETCH_ASSOC); if (!$ride) { - error_log("[MONITOR_RIDE] 4. FAILURE: No ride with status 'Begin' found."); - jsonError("لا توجد رحلة بدأت لهذا المستخدم."); + error_log("[MONITOR_RIDE] 4. FAILURE: No active ride found."); + jsonError("لا توجد رحلة نشطة لهذا المستخدم."); exit; } else { - error_log("[MONITOR_RIDE] 4. SUCCESS: Active Ride Found. Ride ID: " . $ride['id']); + error_log("[MONITOR_RIDE] 4. SUCCESS: Active Ride Found. Ride ID: " . $ride['id'] . " Status: " . $ride['status']); } //------------------------------------------------------------------------ // 3) جلب معلومات السائق من الرحلة //------------------------------------------------------------------------ -// FIX 1: Safe assignment of driver ID (checking driverID vs driver_id) $rideDriverID = $ride['driverID'] ?? $ride['driver_id']; - error_log("[MONITOR_RIDE] 5. Fetching info for Driver ID from Ride: " . $rideDriverID); -// FIX 2: Select first_name and last_name instead of fullname $driverInfoQuery = $con->prepare(" SELECT id, first_name, last_name, phone FROM driver @@ -96,29 +117,22 @@ $driverInfoQuery->execute([':driverID' => $rideDriverID]); $driverInfo = $driverInfoQuery->fetch(PDO::FETCH_ASSOC); if ($driverInfo) { - // فك التشفير للهاتف $driverInfo['phone'] = $encryptionHelper->decryptData($driverInfo['phone']); - - // FIX 4: Decrypt First Name and Last Name $driverInfo['first_name'] = $encryptionHelper->decryptData($driverInfo['first_name']); $driverInfo['last_name'] = $encryptionHelper->decryptData($driverInfo['last_name']); - - // Construct fullname for the response $fullName = $driverInfo['first_name'] . " " . $driverInfo['last_name']; $driverInfo['fullname'] = $fullName; - error_log("[MONITOR_RIDE] 5. Driver Info Found: " . $fullName); } else { error_log("[MONITOR_RIDE] 5. WARNING: Driver info not found for ID " . $rideDriverID); } //------------------------------------------------------------------------ -// 4) جلب آخر موقع للسائق من جدول driver_location بشرط الحالة ON +// 4) جلب آخر موقع للسائق من جدول car_locations بشرط الحالة ON //------------------------------------------------------------------------ error_log("[MONITOR_RIDE] 6. Querying Tracking DB for Driver ID: " . $rideDriverID); -// FIX 3: Changed ORDER BY id DESC to ORDER BY updated_at DESC $locationQuery = $con_tracking->prepare(" SELECT latitude, longitude, speed, heading, updated_at FROM car_locations @@ -129,9 +143,9 @@ $locationQuery->execute([':driverID' => $rideDriverID]); $location = $locationQuery->fetch(PDO::FETCH_ASSOC); if ($location) { - error_log("[MONITOR_RIDE] 6. Location Found: Lat=" . $location['latitude'] . " Lng=" . $location['longitude'] . " Updated=" . $location['updated_at']); + error_log("[MONITOR_RIDE] 6. Location Found: Lat=" . $location['latitude'] . " Lng=" . $location['longitude']); } else { - error_log("[MONITOR_RIDE] 6. WARNING: No live location found (status=ON) or list empty."); + error_log("[MONITOR_RIDE] 6. WARNING: No live location found."); } //------------------------------------------------------------------------ @@ -145,6 +159,4 @@ $response = [ ]; error_log("[MONITOR_RIDE] 7. Sending Success Response."); -jsonSuccess($response); - -?> \ No newline at end of file +jsonSuccess($response); \ No newline at end of file diff --git a/backend/ride/rides/cancel_ride_by_passenger.php b/backend/ride/rides/cancel_ride_by_passenger.php index 77370b1..2b28644 100644 --- a/backend/ride/rides/cancel_ride_by_passenger.php +++ b/backend/ride/rides/cancel_ride_by_passenger.php @@ -18,8 +18,8 @@ if (!$rideId) { } try { - // جلب بيانات الرحلة للتحقق - $stmt = $con->prepare("SELECT driver_id, status FROM ride WHERE id = ?"); + // جلب بيانات الرحلة للتحقق (مع passenger_id للإدراج في canecl) + $stmt = $con->prepare("SELECT driver_id, passenger_id, status FROM ride WHERE id = ?"); $stmt->execute([$rideId]); $ride = $stmt->fetch(PDO::FETCH_ASSOC); @@ -55,6 +55,15 @@ try { $updateOrder->execute([$reason, $rideId, $driverId]); } + // إدراج سبب الإلغاء في جدول canecl المخصص + if ($driverId > 0 && !empty($reason)) { + $passengerId = $ride['passenger_id'] ?? '0'; + $insertCanecl = $con->prepare( + "INSERT INTO canecl (driverID, passengerID, rideID, note) VALUES (?, ?, ?, ?)" + ); + $insertCanecl->execute([$driverId, $passengerId, $rideId, $reason]); + } + $con->commit(); // تحديث السيرفر البعيد (Remote DB) diff --git a/backend/ride/rides/finish_ride_updates.php b/backend/ride/rides/finish_ride_updates.php index e6b9a34..fe4577a 100644 --- a/backend/ride/rides/finish_ride_updates.php +++ b/backend/ride/rides/finish_ride_updates.php @@ -15,14 +15,15 @@ try { // and atomically updates all databases within a transaction. // // Flow: -// 1. Receive raw params from driver app -// 2. Calculate price server-side (from DB + actual distance) -// 3. BEGIN TRANSACTION (local DB) -// 4. Update ride on local DB + remote DB (con_ride) -// 5. Update driver_orders -// 6. S2S cURL → Wallet Payment Server (process_ride_payments.php) -// 7. If payment OK → COMMIT, notify passenger (Socket + FCM) -// 8. If payment FAIL → ROLLBACK, ride stays 'Begin', safe retry +// 1. Receive raw params from driver app (including country_code) +// 2. Load country pricing from `kazan` table +// 3. Calculate price server-side (from DB + actual distance) +// 4. BEGIN TRANSACTION (local DB) +// 5. Update ride on local DB + remote DB (con_ride) +// 6. Update driver_orders +// 7. S2S cURL → Wallet Payment Server (process_ride_payments.php) +// 8. If payment OK → COMMIT, notify passenger (Socket + FCM) +// 9. If payment FAIL → ROLLBACK, ride stays 'Begin', safe retry // ============================================================ // --- Secure S2S Configuration --- @@ -42,6 +43,7 @@ $passengerToken = filterRequest("passengerToken"); $driver_token = filterRequest("driver_token"); $walletChecked = filterRequest("walletChecked"); $passengerWalletBurc = filterRequest("passengerWalletBurc"); +$countryCode = filterRequest("country_code"); // 🆕 الدولة: Syria, Egypt, ... if (empty($rideId) || empty($newStatus) || empty($driver_id) || empty($passengerId)) { jsonError("Missing required parameters: rideId, driver_id, passengerId, status"); @@ -53,8 +55,44 @@ if ($newStatus !== 'Finished') { exit; } +// 🆕 إذا لم يتم إرسال country_code، نأخذه من قاعدة بيانات الرحلة +if (empty($countryCode)) { + try { + $stmtCountry = $con->prepare("SELECT r.id, d.site AS country_code + FROM ride r + LEFT JOIN driver d ON r.driver_id = d.id + WHERE r.id = ? LIMIT 1"); + $stmtCountry->execute([$rideId]); + $rowCountry = $stmtCountry->fetch(PDO::FETCH_ASSOC); + $countryCode = $rowCountry['country_code'] ?? 'Syria'; + } catch (Exception $e) { + $countryCode = 'Syria'; // fallback + } +} + // ============================================================ -// 2. Server-Side Price Calculation (Secure — NOT from client) +// 2. Load Country Pricing from `kazan` Table +// ============================================================ +try { + $stmtKazan = $con->prepare("SELECT * FROM kazan WHERE country = ? LIMIT 1"); + $stmtKazan->execute([$countryCode]); + $countryPricing = $stmtKazan->fetch(PDO::FETCH_ASSOC); + + if (!$countryPricing) { + // Fallback: إذا لم نجد سعر للدولة، نستخدم Syria كافتراضي + error_log("[finish_ride_updates] No pricing found for country: $countryCode. Falling back to Syria."); + $stmtKazan->execute(['Syria']); + $countryPricing = $stmtKazan->fetch(PDO::FETCH_ASSOC); + $countryCode = 'Syria'; + } +} catch (PDOException $e) { + error_log("[finish_ride_updates] Failed to load country pricing: " . $e->getMessage()); + jsonError("Failed to load pricing configuration."); + exit; +} + +// ============================================================ +// 3. Server-Side Price Calculation (Secure — NOT from client) // ============================================================ try { // Fetch ride data from remote/local DB for server-side calculation @@ -73,10 +111,10 @@ try { } $quotedPrice = floatval($rideData['quoted_price'] ?? 0); - $kazanPercent = 10; + $kazanPercent = floatval($countryPricing['kazanPercent'] ?? $countryPricing['kazan'] ?? 10); // 🆕 من جدول kazan (kazanPercent هو الاسم الجديد) $carType = $rideData['car_type'] ?? 'Fixed Price'; - // Fixed-price types: use quoted price as-is + // Fixed-price types, Speed & Awfar: use quoted price as-is $fixedPriceTypes = ['Speed', 'Fixed Price', 'Awfar Car']; if (in_array($carType, $fixedPriceTypes)) { $finalPrice = $quotedPrice; @@ -88,8 +126,9 @@ try { if ($distanceKm <= 0) { $finalPrice = $quotedPrice; // fallback } else { - $perKmRate = getPerKmRate($carType); - $perMinRate = getPerMinRate(); + // 🆕 استخدام الأسعار من جدول kazan حسب الدولة (كل نوع سيارة له عمود سعره الخاص) + $perKmRate = getPerKmRate($carType, $countryPricing); + $perMinRate = getPerMinRate($countryPricing); $durationMin = intval(preg_replace('/[^0-9]/', '', $actualDuration)); $calculated = ($distanceKm * $perKmRate) + ($durationMin * $perMinRate); @@ -98,18 +137,20 @@ try { $finalPrice = max($quotedPrice, round($calculated, 2)); } } + + // 🆕 تحديد رمز العملة حسب الدولة + $currency = getCurrencyByCountry($countryCode); + } catch (PDOException $e) { jsonError("Error calculating price: " . $e->getMessage()); exit; } // ============================================================ -// 3. Atomic Transaction: Update DBs + Process Payment +// 4. Atomic Transaction: Update DBs + Process Payment // ============================================================ try { // --- Update Remote DB (con_ride) FIRST --- - // (Not in transaction — remote DB doesn't support cross-DB rollback, - // but we keep it minimal as a "best-effort" update) if (isset($con_ride)) { $stmtRemote = $con_ride->prepare( "UPDATE ride SET status = ?, rideTimeFinish = NOW(), price = ? WHERE id = ? AND status = 'Begin'" @@ -120,7 +161,7 @@ try { // --- BEGIN Local DB Transaction --- $con->beginTransaction(); - // 3a. Update ride (local DB) + // 4a. Update ride (local DB) $stmtLocal = $con->prepare( "UPDATE ride SET status = ?, rideTimeFinish = NOW(), price = ? WHERE id = ? AND status = 'Begin'" ); @@ -130,7 +171,7 @@ try { throw new Exception("Ride already finished or not found in local DB."); } - // 3b. Update driver_orders + // 4b. Update driver_orders $checkStmt = $con->prepare("SELECT order_id FROM driver_orders WHERE order_id = ?"); $checkStmt->execute([$rideId]); @@ -143,7 +184,7 @@ try { } // ============================================================ - // 3c. Server-to-Server Payment Processing (S2S) + // 4c. Server-to-Server Payment Processing (S2S) // ============================================================ $paymentPayload = [ 'rideId' => $rideId, @@ -154,6 +195,8 @@ try { 'walletChecked' => $walletChecked, 'passengerWalletBurc' => $passengerWalletBurc, 'authToken' => $driver_token, + 'currency' => $currency, // 🆕 إرسال العملة لمخدم الدفع + 'country_code' => $countryCode, // 🆕 إرسال الدولة لمخدم الدفع ]; $ch = curl_init(WALLET_PAYMENT_URL); @@ -202,7 +245,7 @@ try { $con->commit(); // ============================================================ - // 4. Notifications (After successful commit) + // 5. Notifications (After successful commit) // ============================================================ $passenger_id = $passengerId; // alias for legacy code @@ -220,6 +263,7 @@ try { 'ride_id' => $rideId, 'status' => 'finished', 'price' => $finalPrice, + 'currency' => $currency, // 🆕 'DriverList' => $legacyList ]; @@ -232,13 +276,14 @@ try { $fcmData = [ 'ride_id' => (string)$rideId, 'price' => (string)$finalPrice, + 'currency' => $currency, // 🆕 'DriverList' => $legacyList ]; sendFCM_Internal( $passengerToken, "تم إنهاء الرحلة 🏁", - "المبلغ المطلوب: " . $finalPrice . " ل.س", + "المبلغ المطلوب: " . $finalPrice . " " . $currency, $fcmData, 'Driver Finish Trip', false @@ -247,11 +292,12 @@ try { } // ============================================================ - // 5. Return Success with server-calculated price + // 6. Return Success with server-calculated price + currency // ============================================================ jsonSuccess([ - 'price' => $finalPrice, - 'rideId' => $rideId + 'price' => $finalPrice, + 'currency' => $currency, // 🆕 إرجاع العملة للتطبيق + 'rideId' => $rideId ], "Ride finished and payment processed successfully."); } catch (Exception $e) { @@ -263,28 +309,131 @@ try { } // ============================================================ -// Helper Functions +// Helper Functions — الآن تقرأ الأسعار من جدول kazan حسب الدولة // ============================================================ -function getPerKmRate(string $carType): float { - $rates = [ - 'Comfort' => 44, - 'Lady' => 44, - 'Mishwar Vip' => 50, - 'Electric' => 45, - 'Van' => 63, - 'Delivery' => 25, - 'Speed' => 36, - 'Fixed Price' => 36, - 'Awfar Car' => 36, +/** + * الحصول على سعر الكيلومتر حسب نوع السيارة من جدول أسعار الدولة + * + * 🆕 كل نوع سيارة له عمود مستقل في جدول kazan: + * Speed → speedPrice | Comfort → comfortPrice | Lady → ladyPrice + * Electric → electricPrice | Van → vanPrice | Delivery → deliveryPrice + * Mishwar Vip → mishwarVipPrice | Fixed Price → fixedPrice | Awfar → awfarPrice + * + * @param string $carType نوع السيارة + * @param array $countryPricing صف من جدول kazan + * @return float + */ +function getPerKmRate(string $carType, array $countryPricing): float { + // 🆕 الخريطة المباشرة: كل نوع سيارة يقابله عمود بنفس الاسم + "Price" + $rateColumns = [ + 'Comfort' => 'comfortPrice', + 'Speed' => 'speedPrice', + 'Lady' => 'ladyPrice', + 'Electric' => 'electricPrice', + 'Van' => 'vanPrice', + 'Delivery' => 'deliveryPrice', + 'Mishwar Vip' => 'mishwarVipPrice', + 'Fixed Price' => 'fixedPrice', + 'Awfar Car' => 'awfarPrice', ]; - return $rates[$carType] ?? 36; + + $column = $rateColumns[$carType] ?? 'speedPrice'; + + // دعم التوافق مع الإصدارات القديمة (backward compatibility) + $rate = floatval($countryPricing[$column] ?? 0); + + // إذا كان السعر صفر أو غير موجود، نبحث في الأسماء القديمة + if ($rate <= 0) { + $oldColumnMap = [ + 'Lady' => 'familyPrice', + 'Mishwar Vip' => 'freePrice', + 'Electric' => 'naturePrice', + 'Van' => 'heavyPrice', + ]; + $oldColumn = $oldColumnMap[$carType] ?? null; + if ($oldColumn && isset($countryPricing[$oldColumn])) { + $rate = floatval($countryPricing[$oldColumn]); + } + } + + // Fallback أخير + if ($rate <= 0) { + $rate = floatval($countryPricing['speedPrice'] ?? 36); + } + + return $rate; } -function getPerMinRate(): float { +/** + * الحصول على سعر الدقيقة حسب وقت اليوم من جدول kazan + * + * 🆕 الآن يقرأ من أعمدة الدقيقة المنفصلة: + * normalMinPrice → Normal (9 ص - 2 م / 6 م - 9 م) + * peakMinPrice → Peak (2 م - 5 م) + * lateMinPrice → Late (9 م - 1 ص) + * + * @param array $countryPricing صف من جدول kazan + * @return float + */ +function getPerMinRate(array $countryPricing): float { $hour = (int)date('H'); - if ($hour >= 21 || $hour < 1) return 11; // Late - if ($hour >= 14 && $hour <= 17) return 10; // Peak - return 9; // Normal + + // 🆕 قراءة الأسعار من الأعمدة الجديدة للدقيقة + $normalMinPrice = floatval($countryPricing['normalMinPrice'] ?? 0); + $peakMinPrice = floatval($countryPricing['peakMinPrice'] ?? 0); + $lateMinPrice = floatval($countryPricing['lateMinPrice'] ?? 0); + + // 🆕 دعم التوافق مع الإصدارات القديمة (latePrice, naturePrice) + if ($lateMinPrice <= 0) $lateMinPrice = floatval($countryPricing['latePrice'] ?? 0); + if ($normalMinPrice <= 0) $normalMinPrice = floatval($countryPricing['naturePrice'] ?? 0); + + // Fallback: حساب سعر الدقيقة من speedPrice إذا كانت الأعمدة الجديدة فارغة + if ($normalMinPrice <= 0) { + $speedPrice = floatval($countryPricing['speedPrice'] ?? 36); + $normalMinPrice = $speedPrice / 4; + } + if ($peakMinPrice <= 0) $peakMinPrice = $normalMinPrice * 1.15; // 15% زيادة + if ($lateMinPrice <= 0) $lateMinPrice = $normalMinPrice * 1.25; // 25% زيادة + + if ($hour >= 21 || $hour < 1) { + return round($lateMinPrice, 2); // Late Night + } + if ($hour >= 14 && $hour <= 17) { + return round($peakMinPrice, 2); // Peak + } + return round($normalMinPrice, 2); // Normal } -?> + +/** + * تحديد رمز العملة حسب الدولة + * + * @param string $countryCode رمز الدولة (Syria, Egypt, Jordan, ...) + * @return string رمز العملة (SYP, EGP, JOD, ...) + */ +function getCurrencyByCountry(string $countryCode): string { + $currencies = [ + 'Syria' => 'SYP', + 'Egypt' => 'EGP', + 'Jordan' => 'JOD', + 'Iraq' => 'IQD', + 'UAE' => 'AED', + 'Saudi Arabia' => 'SAR', + 'Qatar' => 'QAR', + 'Kuwait' => 'KWD', + 'Bahrain' => 'BHD', + 'Oman' => 'OMR', + 'Turkey' => 'TRY', + 'Lebanon' => 'LBP', + 'Palestine' => 'ILS', + 'Yemen' => 'YER', + 'Libya' => 'LYD', + 'Tunisia' => 'TND', + 'Algeria' => 'DZD', + 'Morocco' => 'MAD', + 'Sudan' => 'SDG', + ]; + + return $currencies[$countryCode] ?? 'SYP'; // افتراضي: ليرة سورية +} +?> \ No newline at end of file diff --git a/backend/schema_primary.sql b/backend/schema_primary.sql index 7767f28..d78ccfe 100644 --- a/backend/schema_primary.sql +++ b/backend/schema_primary.sql @@ -802,29 +802,64 @@ CREATE TABLE `invoicesAdmin` ( /*!40101 SET character_set_client = @saved_cs_client */; -- --- Table structure for table `kazan` +-- ============================================================ +-- 🆕 جدول الأسعار لكل دولة (kazan) - النسخة المطورة 🆕 +-- ============================================================ +-- قائمة أنواع السيارات المعتمدة (كل نوع له عمود سعر مستقل): +-- 1. Speed - السيارات الاقتصادية السريعة +-- 2. Comfort - السيارات المكيفة والمريحة +-- 3. Lady - سائقات للسيدات +-- 4. Electric - السيارات الكهربائية +-- 5. Van - فانات نقل الركاب +-- 6. Delivery - توصيل الطلبات +-- 7. Mishwar Vip - مشوار VIP +-- 8. Fixed Price - سعر ثابت +-- 9. Awfar Car - أوفر كار (السيارات الأقدم) +-- ============================================================ +-- أعمدة أسعار الدقيقة (منفصلة عن أسعار الكيلومتر): +-- - normalMinPrice: سعر الدقيقة في الوقت العادي (9 ص - 2 م / 6 م - 9 م) +-- - peakMinPrice: سعر الدقيقة في وقت الذروة (2 م - 5 م) +-- - lateMinPrice: سعر الدقيقة في الليل المتأخر (9 م - 1 ص) +-- ============================================================ +-- عند إضافة دولة جديدة، فقط أضف صفاً جديداً في هذا الجدول. +-- عند إضافة نوع سيارة جديد، أضف عموداً جديداً هنا وفي finish_ride_updates.php. +-- ============================================================ -- - DROP TABLE IF EXISTS `kazan`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `kazan` ( `id` int NOT NULL AUTO_INCREMENT, - `country` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, - `kazan` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, - `comfortPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, - `speedPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, - `familyPrice` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, - `deliveryPrice` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, - `freePrice` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, - `latePrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, - `heavyPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, - `adminId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `country` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'اسم الدولة: Syria, Egypt, Jordan, Iraq, ...', + + -- ========== ⚙️ الإعدادات العامة ========== + `kazanPercent` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '10' COMMENT 'نسبة الكازان (عمولة المنصة) %', + `fuelPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الوقود المرجعي', + `currency` varchar(5) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'SYP' COMMENT 'رمز العملة: SYP, EGP, JOD, IQD, ...', + + -- ========== 🚗 أسعار الكيلومتر لكل نوع سيارة ========== + `speedPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الكيلومتر - Speed', + `comfortPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الكيلومتر - Comfort', + `ladyPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الكيلومتر - Lady (سائقة للسيدات)', + `electricPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الكيلومتر - Electric', + `vanPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الكيلومتر - Van', + `deliveryPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الكيلومتر - Delivery', + `mishwarVipPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الكيلومتر - Mishwar Vip', + `fixedPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الكيلومتر - Fixed Price', + `awfarPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الكيلومتر - Awfar Car', + + -- ========== ⏱️ أسعار الدقيقة (زمن الرحلة) ========== + `normalMinPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الدقيقة - الوقت العادي (9ص-2م / 6م-9م)', + `peakMinPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الدقيقة - وقت الذروة (2م-5م)', + `lateMinPrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'سعر الدقيقة - الليل المتأخر (9م-1ص)', + + -- ========== إداري ========== + `adminId` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `naturePrice` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, - `fuelPrice` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + PRIMARY KEY (`id`), + UNIQUE KEY `idx_country` (`country`) COMMENT 'ضمان عدم وجود صفين لنفس الدولة' +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='أسعار الرحلات حسب الدولة - كل نوع سيارة له عمود مستقل'; /*!40101 SET character_set_client = @saved_cs_client */; -- diff --git a/contract.html b/contract.html index 6f3d79a..f5b5349 100644 --- a/contract.html +++ b/contract.html @@ -3,24 +3,24 @@ - مولد ومطبع عقد شراكة Siro القانوني - - - + مولد ومطبع عقد شراكة Siro القانوني المطور + + + + + + + +
+
+
+

مشروع النقل الذكي (تطبيق سيرو) — سوريا 🇸🇾

+

خطة تمويل 14 شهراً — النسخة النهائية للمستثمرين

+
+
+ Siro Logo +
+
+ + +
+
+ + + + + +
+
+
+ + +
+ + +
+ +
+

المحتويات

+
+
1. الملخص التنفيذي وأطروحة الاستثمار
+
2. إثبات السوق (Pilot Validation)
+
3. الإطار القانوني والتراخيص
+
4. المصاريف التأسيسية (CAPEX)
+
5. المصاريف التشغيلية الشهرية (OPEX)
+
6. استراتيجية بناء الأسطول
+
استراتيجيات النمو والتسويق (في تبويب مستقل)
+
7. استراتيجية التوسع الجغرافي
+
8. التحليل المالي ونقطة التعادل
+
9. ملخص رأس المال المطلوب
+
10. مؤشرات الأداء الرئيسية (KPIs)
+
11. المخاطر والتخفيف
+
12. الخلاصة للمستثمر
+
+
+ +

1. الملخص التنفيذي وأطروحة الاستثمار

+ +

المشروع

+

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

+ +

لماذا هذا الاستثمار مختلف ومربح؟

+
+ "هذا التمويل للنمو والسيطرة على السوق، وليس لبناء المنتج." +
+

على عكس الشركات الناشئة التي تطلب المال لبناء التطبيق وتوظيف فريق البرمجة:

+ + +

الفرضيات المالية الأساسية والميزة التنافسية

+ +
+
+

مؤشرات التطبيق:

+
+ + + + + + + + +
متوسط سعر الرحلة2.70$ (حوالي 280 ل.س)
نسبة عمولة التطبيق11% ثابتة
صافي عمولة الرحلة للتطبيق~0.30$
معدل رحلات السائق اليومي3 رحلات (فرضية متحفظة)
خطة التمويل (Runway)14 شهراً
+
+
+
+

مقارنة عمولات السوق (السوق السوري):

+
+ + + + + + + + + + +
التطبيق المنافسنسبة العمولة
تطبيق يلا جو (YallaGo)~ 20%
تطبيق زاكن (Zakinn)~ 17%
تطبيق تفضل15%
تطبيق سيرو (Siro)11% (جذب هائل للسائقين)
+
+
+
+ +

2. إثبات السوق — نتائج التشغيل التجريبي (Pilot)

+

خلال تجربة تشغيلية سابقة مدتها 45 يوماً فقط وبميزانية تسويقية لم تتجاوز 1,400$، تم تحقيق النتائج التالية:

+ +
+ + + + + + + + + + + +
المؤشرالنتيجة
السائقون الموثّقون (Onboarded)1,447 سائق (انظر الملاحظة أدناه)
الركاب المسجلون2,891 راكب
طلبات الرحلات697 طلب رحلة
تكلفة اكتساب الراكب (CAC Signal)~0.48$ فقط
سبب التوقفنفاد ميزانية النمو (وليس فشل المنتج أو رفض السوق)
+
+ +

الدرس المستفاد من التجربة (التغيير الاستراتيجي)

+

السائقون البالغ عددهم 1,447 كانوا موزعين ومشتتين على كافة المحافظات السورية وليس في نطاق جغرافي واحد. التحدي الوحيد كان تشتت الكثافة الجغرافية. هذا الدرس أصبح حجر الأساس لاستراتيجية "الكثافة أولاً (Density-First)" المعتمدة في هذه الخطة، حيث سيتم استهداف الرقعة الجغرافية المحددة والتركيز على السائقين المتواجدين في مناطق الاهتمام فقط.

+
+ 📍 لمشاهدة خارطة توزع السائقين من التجربة السابقة، انتقل إلى تبويب: توزع السائقين +
+ +

3. الإطار القانوني والتراخيص

+ +

الأساس القانوني

+

يعمل المشروع وفق القانون رقم 16 لعام 2021 الذي ينظم نقل الركاب عبر التطبيقات الإلكترونية في سوريا.

+ +

مراحل الترخيص والمدة المتوقعة

+
+ + + + + + + + + + + + +
المرحلةالمدةالتكلفة
تأسيس الشركة + السجل التجاري1-2 أسبوعضمن رسوم المحامي
تقديم طلب الترخيص + الملف الفني1-2 أسبوع
المراجعة الفنية + الموافقة المبدئية (الهيئة الناظمة)2-4 أسابيع
التنسيق مع وزارة النقل2-3 أسابيع
إصدار شهادة الاعتمادية + الترخيص النهائي1-2 أسبوع600$
الإجمالي8-14 أسبوعاً
+
+ +
+ 📄 للتفاصيل الكاملة حول الوثائق المطلوبة، شروط المركبات، والمراحل الزمنية الدقيقة، يرجى الرجوع إلى تبويب: دليل التراخيص والتسجيل. +
+ +

4. المصاريف التأسيسية الثابتة (CAPEX)

+

تُدفع لمرة واحدة قبل بدء التشغيل:

+
+ + + + + + + + + + + + + + +
البندالتكلفة
شهادة الاعتمادية (الهيئة الناظمة)600$
أتعاب المحامي والتخليص القانوني1,500$
رسوم حكومية (وزارة النقل، سجل تجاري)200$
هواتف خدمة العملاء (3 أجهزة أندرويد)450$
أجهزة ومحطات التطوير (آيفون + أندرويد + أجهزة برمجة عالية الأداء)5,000$
تجهيز المكتب (3 مكاتب + 4 كنبايات ضيافة + أدوات مطبخ)850$
لابتوب للسيرفرات والإعلانات (بخصوص سوريا)350$
إجمالي التأسيس8,950$
+
+ +

5. المصاريف التشغيلية الشهرية (OPEX) — خطة 14 شهراً

+
+ + + + + + + + + + + + + + + + +
البندالتكلفة الشهريةملاحظات
راتب المطور والمشغل الرئيسي3,500$يغطي 5 أدوار (انظر التفصيل أدناه)
فريق خدمة العملاء (3 موظفين)350$رواتب تتراوح بين 100$ - 130$ للموظف الواحد
أجور السيرفرات والبنية التحتية السحابية200$لاستضافة التطبيق وقواعد البيانات والنسخ الاحتياطي
إيجار المكتب (مقر فعلي بدمشق)600$ضروري لتراخيص وزارة النقل
إيجار سكن300$
إدارة السوشيال ميديا (فريلانسر)200$
مرافق (إنترنت + كهرباء ومياه)110$40$ + 70$
راتب سكرتير (سكرتيرة)100$
الإجمالي الشهري5,360$
الإجمالي لـ 14 شهراً75,040$
+
+ +

🔍 المهام والمسؤوليات المطلوبة من المطور والمشغل الرئيسي (3,500$)

+

هذا المبلغ يغطي مهاماً كانت لتتطلب فريقاً كاملاً أو شركات خارجية بتكاليف مضاعفة:

+
    +
  1. الإدارة التشغيلية: الإشراف اليومي على العمليات، وتوجيه فريق خدمة العملاء، وإدارة التسعير الديناميكي.
  2. +
  3. التطوير التقني المستمر: تحديث الأكواد، برمجة الميزات الجديدة لضمان الاستقلالية التقنية الكاملة.
  4. +
  5. إدارة السيرفرات (DevOps): مراقبة استقرار السيرفرات السحابية واستيعابها للضغط المتزايد دون توقف.
  6. +
  7. الأمن السيبراني: حماية قواعد بيانات العملاء وتأمين المحافظ الرقمية والأرصدة.
  8. +
  9. إدارة خوارزميات المطابقة: تحسين ربط السائق بالراكب جغرافياً لتقليل أوقات الانتظار.
  10. +
+ +

6. استراتيجية بناء الأسطول (النواة الصلبة + الانتشار العضوي)

+ +

الفلسفة: لماذا لا ندفع لكل السائقين؟

+

تعتمد الخطة على تمويل "النواة الصلبة" من السائقين فقط (السائقون المحفزون)، بينما يتضاعف عدد السائقين النشطين العضويين بشكل طبيعي بفضل العامل النفسي وعدوى النجاح، دون أن يكلفوا الشركة أي حوافز إضافية.

+ +
+ + + + + + + + +
النوعالتعريفالتكلفة على الشركة
السائق المحفزيحقق 7 ساعات عمل يومياً + 80% نسبة قبول = يستحق 15$/شهرمدفوع (كاش + رصيد)
السائق النشط العضوييعمل بدوام جزئي أو لم يحقق شروط الحافز لكنه متواجد وينجز رحلاتصفر تكلفة (يدرّ أرباحاً صافية)
+
+ +

خطة حوافز النواة الصلبة (أول 6 أشهر فقط)

+
+ + + + + + + + + + + + + +
الشهرعدد السائقين المحفزينالتكلفة الشهرية
الأول1001,500$
الثاني1201,800$
الثالث1301,950$
الرابع1802,700$
الخامس2403,600$
السادس3004,500$
الإجمالي16,050$
+
+ + + +

7. استراتيجية التوسع الجغرافي — خارطة دمشق

+ +

التقسيم الجغرافي الاستراتيجي

+
+ + + + + + + + + + +
المنطقةالأحياءالأولويةمستوى الدخل
🟢 منطقة أالمزة، كفرسوسة، المالكيةالشهر 1مرتفع جداً (سفارات، شركات)
🔵 منطقة بأبو رمانة، المهاجرين، الروضة، الجسر الأبيضالأشهر 2-3مرتفع (وزاري، حكومي)
🟡 منطقة جدمر، ركن الدين، القصاع، المزة فيلات غربيةالأشهر 4-6متوسط-مرتفع (كثافة سكانية عالية)
🔴 منطقة دبرزة، جرمانا، قدسيا، دارياالشهر 7+متوسط (ضواحي — يُضاف بعد التعادل)
+
+ +
+ 🗺️ لمشاهدة التوزيع الجغرافي التفصيلي، انتقل إلى تبويب: خارطة التوسع الجغرافي +
+ +

8. التحليل المالي ونقطة التعادل (Break-Even)

+ +

المصاريف الشهرية الثابتة (بعد انتهاء خطة الحوافز في الشهر السابع):

+
+ + + + + + + + + +
البندالمبلغ
التشغيل (OPEX) شاملاً السيرفرات5,360$
الإعلانات الرقمية2,500$
الإجمالي7,860$
+
+ +

حساب نقطة التعادل:

+

+ المطلوب: 7,860$ ÷ 0.30$ (عمولة/رحلة) = ~26,200 رحلة شهرياً = ~873 رحلة يومياً +

+ +

الواقع التشغيلي المتوقع في الشهر السادس:

+

التطبيق سيمتلك أسطولاً مزدوجاً:

+ + +

جدول التدفق النقدي الشهري (الستة أشهر الأولى):

+

يوضح هذا الجدول مسار الصرف المتوقع حتى الوصول لنقطة التعادل التدريجية في الشهر السادس.

+
+ + + + + + + + + + + + + +
الشهرالتشغيل (OPEX)التسويقحوافز السائقينإجمالي الصرف الشهريإجمالي تراكمي
التأسيس (CAPEX)---8,950$8,950$
الشهر 15,360$2,500$1,500$9,360$18,310$
الشهر 25,360$2,500$1,800$9,660$27,970$
الشهر 35,360$2,500$1,950$9,810$37,780$
الشهر 45,360$2,500$2,700$10,560$48,340$
الشهر 55,360$2,500$3,600$11,460$59,800$
الشهر 6 (التعادل)5,360$2,500$4,500$12,360$72,160$
+
+ +

9. ملخص رأس المال المطلوب من المستثمر

+
+ + + + + + + + + + + + +
البندالمبلغ ($)النسبة
التأسيس والتراخيص وأجهزة التطوير (CAPEX)8,9505%
التشغيل والرواتب والسيرفرات - 14 شهراً (OPEX)75,04042%
التسويق والإعلانات60,00033%
حوافز السائقين (6 أشهر)16,0509%
الاحتياطي والطوارئ المتبقي19,96011%
الإجمالي180,000100%
+
+ +
+ المبلغ المطلوب من المستثمر: 180,000$ دولار أمريكي
+ (مائة وثمانون ألف دولار أمريكي) +
+ +

10. مؤشرات الأداء الرئيسية (KPIs) للمستثمر

+

لضمان الشفافية ومتابعة نمو الاستثمار، سيتم الاعتماد على المؤشرات التالية كمعايير نجاح (Milestones):

+
+ + + + + + + + + + +
المؤشرالشهر 3الشهر 6 (نقطة التعادل)الشهر 12
عدد الرحلات اليومية1508621,500+
سائقون نشطون220500+800+
تقييم متوسط للتطبيق4.3+4.5+4.6+
تكلفة اكتساب الراكب (CAC)<1$<0.6$<0.4$
+
+ +

11. المخاطر والتخفيف

+
+ + + + + + + + + +
المخاطر المحتملةاحتمالية الحدوثاستراتيجية التخفيف
تأخر إصدار التراخيصمتوسطةمحامٍ متخصص + خبرة سابقة في الإجراءات
تقلب سعر صرف الليرةمرتفعةالاحتياطي المالي المتبقي (16,500$) + التسعير الديناميكي
منافسة شديدةمتوسطةعمولة تنافسية للسائق (11%) + استهداف مناطق غنية
+
+ +

12. الخلاصة للمستثمر

+

هذا المشروع يتميز بميزة نادرة: المنتج التقني جاهز والسوق مُثبت ميدانياً. نحن لسنا في مرحلة بناء المنتج، نحن في مرحلة السيطرة على السوق.

+ +

بمبلغ 175,000$ فقط:

+ + +
+

الفرصة أمامك. السوق ينتظر. والبنية التحتية جاهزة.

+

كل ما ينقص هو الوقود.

+
+
+ + +
+

خارطة توزع السائقين — نتائج التشغيل التجريبي

+

توضح الخارطة أدناه الكثافة الجغرافية والتجمعات الفعلية للسائقين الذين تم استقطابهم وتسجيلهم بنجاح (1,447 سائق).
المشكلة واضحة: السائقون مشتتون على امتداد المحافظات السورية، مما يثبت صحة استراتيجية "التركيز وبناء الكثافة" بدمشق أولاً.

+ +
+
+ + +
+

إحصائيات الكثافة

+
إجمالي المجموعات: 0
+
إجمالي السائقين: 0
+
أكبر تجمع: 0
+
+
+
+ + +
+

خارطة التوسع الجغرافي - دمشق

+
+
+ + +
+ +
+

دليل التراخيص والتسجيل: تطبيق نقل ذكي في سوريا

+

(الإجراءات القانونية والفنية الكاملة - محدّث 2026)

+
+ +

1. الإطار القانوني الحاكم

+ +

القانون رقم 16 لعام 2021 (قانون النقل بالتطبيقات الإلكترونية)

+

هذا القانون هو الأساس القانوني الذي يسمح لأصحاب السيارات الخاصة والصغيرة بنقل الركاب عبر تطبيقات الهاتف، بشرط أن تكون الشركة المشغلة مرخصة رسمياً من وزارة النقل وتعمل تحت إشراف الهيئة الناظمة للاتصالات والبريد.

+ +

الجهات المعنية بالترخيص

+
+ + + + + + + + + +
الجهةالدور
الهيئة الناظمة للاتصالات والبريد (NANS)منح الترخيص التقني للتطبيق (شهادة الاعتمادية)، والإشراف على البنية التقنية.
وزارة النقلترخيص الشركة كناقل رسمي، فحص المركبات، والإشراف التشغيلي.
الهيئة الوطنية لخدمات تقانة المعلوماتالإبلاغ عن التطبيق (مبدأ "الإعلام" بدلاً من "الترخيص").
+
+ +

2. شروط الشركة المتقدمة (طالب الترخيص)

+
    +
  1. الشكل القانوني: شركة محدودة المسؤولية مؤسسة في سوريا.
  2. +
  3. غاية الشركة: تقديم خدمة نقل الركاب باستخدام التطبيق الإلكتروني في السجل التجاري.
  4. +
  5. المقر الفعلي: يُفضل بشدة أن يكون للشركة مقر فعلي (مكتب) لتسهيل إجراءات وزارة النقل.
  6. +
+ +

3. الوثائق المطلوبة لتقديم طلب الترخيص

+
+ + + + + + + + + + +
#الوثيقةملاحظات
1استمارة طلب الترخيصنموذج رسمي معتمد
2صورة مصدقة عن السجل التجاريأو نظام التأسيس
3وثائق "لا حكم عليه"للمؤسسين
4ملف فني تقنييوضح آلية عمل التطبيق
+
+ +

4. شروط المركبات والسائقين

+ + +

5. مراحل الترخيص وتسلسلها الزمني المتوقع

+ +
+ +
+
+ الأسبوع 1 - 2 +

تأسيس الشركة والسجل التجاري

+

تسجيل الشركة (م.م.ذ) وإضافة غاية "نقل الركاب بالتطبيق الإلكتروني" بشكل رسمي.

+
+
+ +
+
+ الأسبوع 3 - 4 +

تقديم الطلب والملف الفني

+

تجميع كافة الوثائق وتقديمها للهيئة الناظمة للاتصالات والبريد لدراسة الطلب.

+
+
+ +
+
+ الأسبوع 5 - 8 +

المراجعة الفنية والموافقة المبدئية

+

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

+
+
+ +
+
+ الأسبوع 8 - 12 +

التنسيق مع وزارة النقل

+

فحص المركبات، التأكد من السلامة التشغيلية وشروط السائقين بحسب القانون.

+
+
+ +
+
+ الأسبوع 12 - 14 +

الترخيص النهائي والإطلاق

+

إصدار شهادة الاعتمادية النهائية وبدء العمليات التشغيلية للتطبيق في الشارع السوري.

+
+
+ +
+ +

6. التكاليف التقديرية للتراخيص

+
+ + + + + + + + + + +
البندالتكلفة التقديرية
رسوم شهادة الاعتمادية (NANS)600$
أتعاب المحامي (لتخليص جميع الإجراءات)1,200$ - 1,500$
رسوم متفرقة (وزارة النقل، سجل تجاري)~200$
الإجمالي التقديري2,000$ - 2,300$
+
+ +

7. نصائح عملية لتسريع الإجراءات

+
    +
  1. وكّل محامياً متخصصاً: محامٍ لديه علاقات في وزارة النقل والهيئة الناظمة سيختصر عليك أسابيع.
  2. +
  3. جهّز الملف الفني مسبقاً: لا تنتظر حتى تقدم الطلب. جهّز وثيقة تقنية احترافية توضح بنية التطبيق.
  4. +
  5. ابدأ بتأسيس الشركة فوراً: السجل التجاري يستغرق وقتاً ويمكن أن يسير بالتوازي مع التطوير.
  6. +
  7. المقر الفعلي ضروري: لا تعتمد على "المكتب المرن (عقد مرن)" لأنه قد لا يكفي لإجراءات فحص وزارة النقل. استأجر مكتباً فعلياً مستقلاً في دمشق.
  8. +
+ +
+ + +
+

دراسات تسويقية واستراتيجيات النمو

+ +

1. استراتيجيات النمو: تحفيز الركاب ونظام الإحالة المتكامل

+

لضمان سرعة الانتشار وتقليل تكلفة الاستحواذ على العملاء (CAC)، يعتمد التطبيق على محرك نمو داخلي (Growth Engine) يحفز التكرار والمشاركة الفيروسية.

+ +

القسم أ: تحفيز الركاب وتعزيز الطلب اليومي

+
    +
  1. التوزيع الذكي وإبراز جودة السائق: عند قبول الطلب، يتلقى الراكب "بطاقة السائق" متضمنة تقييمه وشارته (مثلاً: سائق نخبة، موثوق). يعتمد التوزيع على الأولوية: يُرسل الطلب حصرياً لأعلى السائقين تقييماً في النطاق لمدة 7 ثوانٍ، ثم يُوسع. (معيار الأفضلية = 40% تقييم + 30% نسبة قبول + 30% نشاط الأسبوع).
  2. +
  3. أكواد الترحيب والخصم التدريجية: أول رحلة مخفضة أو مجانية عبر كود التسجيل. تليها أكواد ترويجية ذات صلاحية محدودة (48 ساعة) تُوزع عبر قنوات تيليغرام وواتساب الرسمية لخلق دافع للاستخدام الفوري (Urgency).
  4. +
  5. الرحلات المتسلسلة (Ride Streaks): أهداف أسبوعية بسيطة للراكب تظهر داخل التطبيق (مثال: أتمم 3 رحلات هذا الأسبوع واحصل على الرابعة بخصم 50%). يتجدد النظام تلقائياً كل أسبوع.
  6. +
  7. ساعة السعادة (Happy Hour): خصومات محددة في أوقات هدوء الطلب (مثال: 2 - 4 عصراً) على مناطق محددة، تُعلن عبر إشعارات الـ Push Notification لضمان استمرار دوران الأسطول.
  8. +
  9. محفظة النقاط (Siro Points): كل رحلة تُولد نقاطاً تُضاف لمحفظة الراكب كخصم للرحلات القادمة. هذا يخلق "رصيداً محجوزاً" يدفع المستخدم العشوائي للتحول إلى مستخدم وفيّ.
  10. +
  11. باقة الاشتراك الشهري (Siro Pass): خيار اشتراك مسبق الدفع يمنح الراكب عدداً معيناً من الرحلات بخصم ثابت، مما يضمن طلباً منتظماً ويحسن التدفق النقدي للشركة.
  12. +
+ +

القسم ب: نظام الإحالة والمشاركة الفيروسي (Referral System)

+

الاعتماد على كود موحد من 6 خانات لكل مستخدم. يعمل الكود لجميع أنواع الإحالات، ويقوم السيرفر بتحديد نوع العلاقة تلقائياً لتطبيق المكافأة المناسبة فوراً.

+ +
+ + + + + + + + + + +
نوع الإحالةمكافأة الداعي (Inviter)مكافأة المدعو (Invitee)
راكب ⟵ يدعو ⟵ راكبرصيد 1.5$أول رحلة بنصف السعر
راكب ⟵ يدعو ⟵ سائق0.50$ / رحلة (لأول 30 رحلة)مكافأة تسجيل (بونص)
سائق ⟵ يدعو ⟵ راكب0.30$ / رحلة (لأول 10 رحلات)خصم ترحيبي للراكب
سائق ⟵ يدعو ⟵ سائق5$ بعد 50 رحلة مكتملةمكافأة انضمام
+
+ +
+ استراتيجية الدعوة الفورية داخل السيارة (Quick Invite): +

زر مخصص في واجهة السائق يولد (QR Code) ورابط (Deep Link) فوري. عندما يقلّ السائق راكباً من الشارع (توصيلة خاصة)، يمكن للراكب مسح الكود ليتم توجيهه للمتجر وتنزيل التطبيق. بمجرد التسجيل، يُحسب الكود تلقائياً للسائق كإحالة ناجحة، مما يحول الركاب العشوائيين إلى مستخدمين دائمين لمنصتنا بدون أي إدخال يدوي.

+
+ +

القسم ج: استراتيجية الثقة والالتزام المجتمعي

+

الخطر الحقيقي: أن يجرّب الراكب مرة واحدة وما يعود، أو أن يلتحق السائق ثم يترك بعد شهر. المشكلة في الأسواق المشابهة لم تكن المنتج، بل كانت التوزيع المتشتت وضعف التمويل. مع توفر الكثافة الجغرافية والتمويل، نعالج هذا الخطر عبر التزام متبادل وانتماء للمشروع.

+ +

أولاً — للسائق: الالتزام المتبادل لا الحافز فقط

+
+ مشكلة الحوافز المالية وحدها: السائق يأتي للمال ويرحل مع أول عرض أفضل من المنافس. الحل هو جعله يشعر بالانتماء قبل المال. +
+
    +
  1. ميثاق السائق المؤسس: أول 300 سائق يوقّعون على "ميثاق المؤسسين" — وثيقة رمزية تتضمن: ضمان حد أدنى للدخل خلال الأشهر الثلاثة الأولى من الشركة، مقابل ساعات عمل محددة والحفاظ على تقييم 4.5+ من السائق. (يخلق ولاء نفسي).
  2. +
  3. مجتمع السائقين الرسمي: مجموعة واتساب رسمية مُدارة، لقاء شهري، إشراك السائق في قرارات التطبيق، وإعلان أفضل سائق شهرياً على صفحات سيرو.
  4. +
  5. مسار النمو المرئي للسائق: +
      +
    • 🥉 سائق جديد: 0-50 رحلة ← أولوية في الطلبات العادية
    • +
    • 🥈 سائق فضي: 51-200 رحلة ← طلبات حصرية + شارة مرئية
    • +
    • 🥇 سائق ذهبي: 201-500 رحلة ← أولوية قصوى + مكافأة شهرية
    • +
    • 💎 سائق نخبة: 500+ رحلة ← عمولة مخفضة 9% بدل 11%
    • +
    +
  6. +
+ +

ثانياً — للراكب: الانتماء قبل الخصم

+
+ مشكلة الخصومات وحدها: الراكب الذي جاء بخصم يرحل مع خصم أفضل. الحل هو جعله يشعر أنه جزء من المشروع. +
+
    +
  1. برنامج المؤسسين (أول 500 راكب): شارة "مؤسس سيرو" دائمة، خصم ثابت 10% إلى الأبد، واسمهم في صفحة "من بنى سيرو معنا". تكلفة ضئيلة بأثر نفسي وتسويق عضوي ضخم.
  2. +
  3. الشفافية كسلاح تسويقي: شعار الحملة "سائقك يأخذ ما يصل إلى 89% من كل رحلة". في سوق يأخذ فيه المنافسون 17-20%، هذه الشفافية تكسب ثقة الراكب وتجذب السائق فوراً.
  4. +
  5. ضمان التوفر في المناطق المستهدفة: تعهّد رسمي في التطبيق (في المزة وكفرسوسة وأبو رمانة — سيارتك خلال 8 دقائق أو الرحلة مجانية). يبني توقعاً واضحاً ويميزنا عن المنافسين.
  6. +
+ +

ثالثاً — كسر معادلة الدجاجة والبيضة

+

الراكب لا يفتح التطبيق لعدم وجود سائق، والسائق لا يعمل لعدم وجود راكب. الحل: عملاء B2B كـ Anchor قبل الإطلاق. بدلاً من الاعتماد فقط على الركاب الأفراد في الأيام الأولى، سنقوم بتأمين رحلات يومية مضمونة للسائقين عبر عقود الشركات.

+ +
+

خطة تنفيذ المبيعات للشركات (B2B Execution Plan)

+
    +
  • الشركات المستهدفة (Target): الفنادق المتوسطة والفخمة (مثل فندق الشام، الداما روز)، المطاعم الكبرى لتوصيل موظفيها ليلاً، وشركات الاتصالات والبنوك لنقل مدرائهم.
  • +
  • المسؤول عن التنفيذ والإطار الزمني: يتولى "المشغل الرئيسي" مهام الـ B2B Sales. يبدأ التواصل قبل الإطلاق الفعلي بـ 45 يوماً (أثناء فترة التراخيص).
  • +
  • الشكل القانوني: توقيع "مذكرة تفاهم (MoU)" للتعاون المشترك لا تلزم الشركة بأي مبالغ مقدمة، بل تقدم لهم نظام "لوحة تحكم الشركات (Corporate Dashboard)" لطلب سيارات لموظفيهم ودفع الفواتير نهاية الشهر بخصم خاص.
  • +
  • الفائدة للسائق: السائق المحفز يعرف أن هناك رحلات يومية مضمونة، مما يكسر حاجز الخوف من عدم وجود طلبات في الأيام الأولى.
  • +
+
+

إبرام اتفاقيات مسبقة مع (3 شركات في منطقة أ، فندق أو فندقان، مركز طبي) لتوفير طلبات حقيقية ودخل ثابت للسائق من اليوم الأول قبل دخول الراكب العادي.

+ +
+ + + + + + + + + + + + +
الأداةيخدمالأثر
ميثاق السائق المؤسسسائقولاء نفسي لا مالي فقط
مسار النمو المرئيسائق + راكبحافز مستمر + ثقة
برنامج المؤسسين 500راكبانتماء وتسويق عضوي
شعار الشفافية (حتى 89%)راكب + سائقتمييز فوري عن المنافس
ضمان التوفر 8 دقائقراكبوعد واضح قابل للقياس
عقود B2B قبل الإطلاقالاثنانكسر معادلة الدجاجة والبيضة
+
+ +

2. الخطة التسويقية والإعلانية التفصيلية

+

الميزانية الإجمالية: 60,000$ — موزعة على 3 قنوات رئيسية:

+ +

أ) الحملات الرقمية المستمرة — 35,000$ (14 شهراً × 2,500$/شهر)

+
+ + + + + + + + + +
المنصةالميزانية الشهريةنوع المحتوى والهدف
Facebook & Instagram1,500$إعلانات ممولة موجهة جغرافياً لأحياء دمشق الراقية.
يوتيوب (YouTube Ads)500$إعلانات فيديو قابلة للتخطي تظهر للجمهور السوري لبناء الثقة.
Reels & Shorts500$فيديوهات قصيرة عالية الجودة تبرز تجربة استخدام التطبيق.
+
+ +

ب) حملات المؤثرين (Influencers) — 15,000$

+
+ + + + + + + + +
المعيارالتفصيل
تكلفة المؤثر الواحد500$ - 1,000$ (متوسط 750$ للفيديو)
عدد الفيديوهات الإجمالي20 فيديو مراجعة وتجربة حية
+
+ +

ج) الإعلانات الطرقية (Outdoor Billboards) — 10,000$

+
+ + + + + + + + +
الشهرالموقعالتكلفةالسبب الاستراتيجي
الشهر الرابعلوحة ضخمة في شارع رئيسي بدمشق5,000$دعم الأسطول المتصاعد وتحويل الانتباه من المنافسين
الشهر التاسعلوحة ضخمة في موقع استراتيجي آخر5,000$تجديد الزخم وتثبيت الهيمنة بعد ترسيخ الوجود
+
+
+ +
+ + + + + + + + + \ No newline at end of file