Files
tripz-llc/backend/bot/cron_empty_results_to_db.php
T
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

139 lines
4.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* cron_empty_results_to_db.php
* سكربت لتفريغ نتائج البوت من ملف results.json إلى قاعدة بيانات MySQL
* يُفضل تشغيله برمجياً كل ساعة أو حسب الحاجة
*/
// Allow script to run indefinitely
set_time_limit(0);
ini_set('memory_limit', '256M');
// Mock request to satisfy connect.php dependencies if any
$_SERVER['REQUEST_METHOD'] = 'POST';
require_once __DIR__ . '/../core/bootstrap.php';
require_once __DIR__ . '/../functions.php';
try {
$con = Database::get('main');
} catch (Exception $e) {
die("Database connection failed: " . $e->getMessage() . "\n");
}
$resultsFile = __DIR__ . '/results.json';
if (!file_exists($resultsFile)) {
die("No results file found.\n");
}
$content = file_get_contents($resultsFile);
$data = json_decode($content, true);
if (empty($data) || !is_array($data)) {
die("No data to process or invalid JSON.\n");
}
$insertedCount = 0;
$stmt = $con->prepare("INSERT INTO scraped_competitor_prices (task_id, app_name, competitor_name, start_location, end_location, start_lat, start_lng, end_lat, end_lng, price_amount, price_per_km, distance_km, duration_min, currency, country_code) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
foreach ($data as $row) {
if (isset($row['status']) && $row['status'] !== 'success') {
continue;
}
$taskId = $row['task_id'] ?? null;
$resultData = $row['result_data'] ?? [];
$appName = $resultData['app'] ?? $row['app'] ?? 'Unknown';
$competitorName = $appName; // Assuming app_name is competitor_name for now
$startLoc = $resultData['start_location'] ?? $row['start_location'] ?? '';
if (empty($startLoc) && !empty($resultData['start_lat'])) {
$startLoc = "Lat: {$resultData['start_lat']}, Lng: {$resultData['start_lng']}";
}
$endLoc = $resultData['end_location'] ?? $row['end_location'] ?? '';
if (empty($endLoc) && !empty($resultData['end_lat'])) {
$endLoc = "Lat: {$resultData['end_lat']}, Lng: {$resultData['end_lng']}";
}
$priceRaw = $resultData['price'] ?? $row['price'] ?? 0;
$amount = 0.0;
$currency = 'JOD';
if (is_numeric($priceRaw)) {
$amount = (float)$priceRaw;
} else {
$priceStr = (string)$priceRaw;
// Match numeric parts (including decimals) and text parts
if (preg_match('/([\d\.]+)\s*([A-Za-z]+|د\.ا)/', $priceStr, $matches)) {
$amount = (float)$matches[1];
$currency = $matches[2];
if ($currency === 'د.ا') {
$currency = 'JOD';
}
} else {
$amount = (float)$priceStr;
}
}
// Ignore invalid entries without an amount
if ($amount <= 0) {
continue;
}
$distanceKm = (float)($resultData['distance_km'] ?? 1);
$durationMin = isset($resultData['duration_min']) ? (int)$resultData['duration_min'] : null;
$startLat = $resultData['start_lat'] ?? null;
$startLng = $resultData['start_lng'] ?? null;
$endLat = $resultData['end_lat'] ?? null;
$endLng = $resultData['end_lng'] ?? null;
$countryCode = $row['country_code'] ?? 'JO'; // Default
// --- OSRM Integration (Dynamic Distance & Duration) ---
require_once __DIR__ . '/../core/osrm_routing.php';
if ($startLat && $endLat && (!$durationMin || $durationMin <= 0)) {
$osrmResult = getOsrmRouteDetails($startLat, $startLng, $endLat, $endLng, $countryCode);
if ($osrmResult) {
$distanceKm = $osrmResult['distance_km']; // Override with accurate OSRM distance
$durationMin = $osrmResult['duration_min'];
}
}
// ------------------------------------------------------
if ($distanceKm <= 0) $distanceKm = 1; // Prevent division by zero
$pricePerKm = $amount / $distanceKm;
$countryCode = $row['country_code'] ?? 'JO'; // Default
if ($stmt->execute([
$taskId,
$appName,
$competitorName,
$startLoc,
$endLoc,
$startLat,
$startLng,
$endLat,
$endLng,
$amount,
$pricePerKm,
$distanceKm,
$durationMin,
$currency,
$countryCode
])) {
$insertedCount++;
} else {
echo "Failed to insert task_id: $taskId. Error: " . implode(" ", $stmt->errorInfo()) . "\n";
}
}
// Clear the JSON file after successfully inserting data
file_put_contents($resultsFile, json_encode([], JSON_PRETTY_PRINT));
echo "Successfully inserted $insertedCount records into the database and cleared results.json.\n";