Files
Hamza-AyedandClaude Opus 5 4d8414c96b 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>
2026-07-27 05:14:13 +03:00

123 lines
3.7 KiB
PHP

<?php
/**
* auto_adapt.php
* Auto-Adaptive Pricing — تعديل أسعار kazan الأساسية تلقائياً
*
* المعادلة: سعر_الكيلو_الجديد = أقل_متوسط_سعر_منافس × 0.92
* الحماية: ما ينزل عن 85% من السعر الحالي ولا يزيد عن 115%
*
* التشغيل: cron job كل 30-60 دقيقة
* CLI: php backend/ride/pricing/auto_adapt.php
* HTTP: curl -X POST https://.../backend/ride/pricing/auto_adapt.php -H "X-Internal-Key: ..."
*/
require_once __DIR__ . '/../../core/bootstrap.php';
try {
$con = Database::get('main');
} catch (Exception $e) {
error_log("[AutoAdapt] DB connection failed: " . $e->getMessage());
exit(1);
}
$countries = [
'Syria' => 'SY',
'Jordan' => 'JO',
'Egypt' => 'EG',
'Iraq' => 'IQ'
];
$undercutFactor = 0.92;
$minFloorRatio = 0.85;
$maxCeilRatio = 1.15;
$kmColumns = [
'speedPrice', 'comfortPrice', 'ladyPrice', 'electricPrice',
'vanPrice', 'deliveryPrice', 'mishwarVipPrice', 'fixedPrice', 'awfarPrice'
];
$logEntries = [];
foreach ($countries as $country => $cc) {
// 1. متوسط سعر الكيلو لكل منافس (آخر 24 ساعة)
$sql = "SELECT competitor_name, AVG(price_per_km) AS avg_ppm
FROM scraped_competitor_prices
WHERE country_code = :cc
AND created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND price_per_km > 0
GROUP BY competitor_name
ORDER BY avg_ppm ASC";
$stmt = $con->prepare($sql);
$stmt->execute([':cc' => $cc]);
$competitorAvgs = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($competitorAvgs)) {
error_log("[AutoAdapt] $country — لا توجد بيانات منافسين");
continue;
}
$lowestAvg = (float)$competitorAvgs[0]['avg_ppm'];
// 2. الأسعار الحالية من kazan
$kazanSql = "SELECT * FROM kazan WHERE country = :country LIMIT 1";
$stmtK = $con->prepare($kazanSql);
$stmtK->execute([':country' => $country]);
$kazanRow = $stmtK->fetch(PDO::FETCH_ASSOC);
if (!$kazanRow) {
error_log("[AutoAdapt] $country — لا يوجد صف في kazan");
continue;
}
$currentSpeed = (float)$kazanRow['speedPrice'];
$targetSpeed = $lowestAvg * $undercutFactor;
$minAllowed = $currentSpeed * $minFloorRatio;
$maxAllowed = $currentSpeed * $maxCeilRatio;
if ($targetSpeed < $minAllowed) {
$targetSpeed = $minAllowed;
} elseif ($targetSpeed > $maxAllowed) {
$targetSpeed = $maxAllowed;
}
$ratio = $targetSpeed / $currentSpeed;
$updates = [];
$params = [':country' => $country];
foreach ($kmColumns as $col) {
$oldVal = (float)($kazanRow[$col] ?? 0);
if ($oldVal > 0) {
$newVal = round($oldVal * $ratio, 2);
$updates[] = "`$col` = :$col";
$params[":$col"] = (string)$newVal;
}
}
if (empty($updates)) {
continue;
}
$updateSql = "UPDATE kazan SET " . implode(', ', $updates) . " WHERE country = :country";
$stmtU = $con->prepare($updateSql);
$stmtU->execute($params);
$logEntries[] = [
'country' => $country,
'code' => $cc,
'old_speed' => $currentSpeed,
'new_speed' => $targetSpeed,
'lowest_competitor' => $lowestAvg,
'ratio' => round($ratio, 4),
];
error_log("[AutoAdapt] ✅ $country ($cc): speedPrice $currentSpeed → $targetSpeed (ratio: $ratio)");
}
if (php_sapi_name() === 'cli') {
echo json_encode(['status' => 'success', 'updates' => $logEntries], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
} else {
echo json_encode(['status' => 'success', 'updates' => $logEntries]);
}