feat: استيراد كود سيرو إلى تريبز (سيرو @ecfe7568) — بلا تعديل
قرار المالك 2026-07-27: باك إند سيرو PHP هو المعتمد، وتطبيقاته المجرّبة ميدانياً تحل محل إعادة البناء المؤرشفة. سيرو نفسه لم يُمسّ. الخريطة: backend · payment_server · loction_server · ride_server · passenger_server · docker · dashboard · stress_test → الجذر siro_rider → apps/rider siro_driver → apps/driver siro_admin → dashboards/admin siro_service → dashboards/service android_bot → apps/android_bot socialBot → apps/socialBot نُسخ المتعقَّب في git سيرو فقط عبر `git archive` (3,198 ملفاً / ~169 م.ب) لا `cp -r` — فاستُثنيت مخلفات البناء تلقائياً. بلا أي تعديل محتوى عمداً: كل ما يلي يصير فرقاً مقروءاً مقابل المصدر. لم يُستورد وسببه: siromove.com (الموقع التسويقي يبقى marketing/ في تريبز، سيرو فيه 8 ملفات) · docs و planning (تريبز له docs/ الخاص) · deploy.sh (ليس نشراً على سيرفر بل `git add . && git push origin --all` — فخّ في مستودع آخر) · transit_dashboard (بانتظار قرار مصير backend-transit و dashboards/transit-web). ⚠️ لا يبني بعد — ثلاثة نواقص متوقعة ومقصودة: 1. `.env` و `lib/env/env.g.dart` غير متعقَّبين في سيرو (أسرار لكل مستأجر): كل تطبيق فلاتر يحتاج .env خاصاً ثم توليد env.g.dart بـ build_runner. 2. إعدادات Firebase (9 ملفات google-services.json و GoogleService-Info.plist) يستبعدها .gitignore تريبز — ولكل مستأجر مشروع Firebase خاص أصلاً. 3. apps/driver في سيرو يشير إلى `../../Intaleq/packages/get` خارج المستودع → يجب ضمّ الحزم داخله أسوة بـ apps/rider. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9909d9b4c1
commit
4d8414c96b
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
// ============================================================
|
||||
// pricing_helper.php
|
||||
// يحتوي على دوال التسعير الموحدة
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* الحصول على سعر الكيلومتر حسب نوع السيارة من جدول أسعار الدولة
|
||||
*
|
||||
* @param string $carType نوع السيارة
|
||||
* @param array $kazanRow صف من جدول kazan
|
||||
* @return float
|
||||
*/
|
||||
function getPerKmRate(string $carType, array $kazanRow): float {
|
||||
$rateColumns = [
|
||||
'Comfort' => 'comfortPrice',
|
||||
'Speed' => 'speedPrice',
|
||||
'Lady' => 'ladyPrice',
|
||||
'Electric' => 'electricPrice',
|
||||
'Van' => 'vanPrice',
|
||||
'Delivery' => 'deliveryPrice',
|
||||
'Mishwar Vip' => 'mishwarVipPrice',
|
||||
'Fixed Price' => 'fixedPrice',
|
||||
'Awfar Car' => 'awfarPrice',
|
||||
];
|
||||
|
||||
$column = $rateColumns[$carType] ?? 'speedPrice';
|
||||
|
||||
// دعم التوافق مع الإصدارات القديمة (backward compatibility)
|
||||
$rate = floatval($kazanRow[$column] ?? 0);
|
||||
|
||||
if ($rate <= 0) {
|
||||
$oldColumnMap = [
|
||||
'Lady' => 'familyPrice',
|
||||
'Mishwar Vip' => 'freePrice',
|
||||
'Electric' => 'naturePrice',
|
||||
'Van' => 'heavyPrice',
|
||||
];
|
||||
$oldColumn = $oldColumnMap[$carType] ?? null;
|
||||
if ($oldColumn && isset($kazanRow[$oldColumn])) {
|
||||
$rate = floatval($kazanRow[$oldColumn]);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback أخير
|
||||
if ($rate <= 0) {
|
||||
$rate = floatval($kazanRow['speedPrice'] ?? 36);
|
||||
}
|
||||
|
||||
return $rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* الحصول على سعر الدقيقة حسب وقت اليوم من جدول kazan
|
||||
*
|
||||
* @param array $countryPricing صف من جدول kazan
|
||||
* @return float
|
||||
*/
|
||||
function getPerMinRate(array $countryPricing): float {
|
||||
$hour = (int)date('H');
|
||||
|
||||
// قراءة الأسعار من الأعمدة الجديدة للدقيقة
|
||||
$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'; // افتراضي: ليرة سورية
|
||||
}
|
||||
|
||||
/**
|
||||
* يقدّر مقدار زيادة أجرة السائق عندنا مقارنة بأقرب منافس لنفس الرحلة.
|
||||
* يعتمد على معاملات المنافس المخزّنة بـ Redis (يحدّثها cron_ai_engine.php
|
||||
* كل 3 ساعات على مفتاح pricing:driver_comparison:{country_code}) — لا يوجد
|
||||
* أي استعلام مباشر لقاعدة البيانات هنا لتفادي أي تأخير وقت إنشاء الرحلة.
|
||||
*
|
||||
* @return array|null ['extra' => float, 'currency' => string, 'competitor_name' => string]
|
||||
* أو null إذا ما في بيانات كافية أو الفرق مش مجدي يُعرض
|
||||
*/
|
||||
function estimateDriverEarningsAdvantage(
|
||||
string $countryCode,
|
||||
float $distanceKm,
|
||||
float $durationMin,
|
||||
float $ourDriverPrice,
|
||||
$redis
|
||||
): ?array {
|
||||
if (!$redis || $ourDriverPrice <= 0) return null;
|
||||
|
||||
try {
|
||||
$json = $redis->get("pricing:driver_comparison:{$countryCode}");
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
if (!$json) return null;
|
||||
|
||||
$data = json_decode($json, true);
|
||||
if (!is_array($data) || empty($data['competitor_name'])) return null;
|
||||
|
||||
$competitorFare = (float)($data['base_fare'] ?? 0)
|
||||
+ (float)($data['km_rate'] ?? 0) * $distanceKm
|
||||
+ (float)($data['min_rate'] ?? 0) * $durationMin;
|
||||
|
||||
if ($competitorFare <= 0) return null;
|
||||
|
||||
$commissionPct = (float)($data['commission_pct'] ?? 20.0);
|
||||
$competitorDriverPayout = $competitorFare * (1 - $commissionPct / 100);
|
||||
|
||||
$extra = round($ourDriverPrice - $competitorDriverPayout, 2);
|
||||
|
||||
// حد أدنى نسبي (3% من أجرة سائق المنافس) حتى ما نعرض فرق تافه أو غير موثوق
|
||||
$minMeaningful = $competitorDriverPayout * 0.03;
|
||||
if ($extra <= $minMeaningful) return null;
|
||||
|
||||
return [
|
||||
'extra' => $extra,
|
||||
'currency' => $data['currency'] ?? 'SYP',
|
||||
'competitor_name' => $data['competitor_name'],
|
||||
];
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user