Files
tripz-llc/backend/bot/generate_price_tasks.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

211 lines
9.3 KiB
PHP

<?php
// =========================================================
// backend/bot/generate_price_tasks.php
// Cron Job: Runs every 15 minutes
// Generates random Short & Long trips in Damascus
// =========================================================
// CLI or Web execution
require_once __DIR__ . '/../core/bootstrap.php';
require_once __DIR__ . '/../functions.php';
try {
$con = Database::get('main');
} catch (Exception $e) {
die("Database connection failed\n");
}
// 1. Ensure Table Exists
$sql = "
CREATE TABLE IF NOT EXISTS `scraped_competitor_prices` (
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`task_id` varchar(100) DEFAULT NULL,
`app_name` varchar(100) NOT NULL,
`competitor_name` varchar(100) NOT NULL,
`start_location` varchar(255) NOT NULL,
`end_location` varchar(255) NOT NULL,
`start_lat` decimal(10,7) DEFAULT NULL,
`start_lng` decimal(10,7) DEFAULT NULL,
`end_lat` decimal(10,7) DEFAULT NULL,
`end_lng` decimal(10,7) DEFAULT NULL,
`price_amount` decimal(8,2) NOT NULL,
`price_per_km` decimal(8,2) NOT NULL,
`distance_km` decimal(8,2) DEFAULT NULL,
`duration_min` int DEFAULT NULL,
`currency` varchar(10) NOT NULL DEFAULT 'JOD',
`country_code` varchar(10) NOT NULL DEFAULT 'JO',
`scraped_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY `idx_app_name` (`app_name`),
KEY `idx_competitor_name` (`competitor_name`),
KEY `idx_start_location` (`start_location`),
KEY `idx_country_code` (`country_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
";
$con->exec($sql);
// [AI Formula Discovery] Create table for reverse-engineered formulas
$sqlFormula = "
CREATE TABLE IF NOT EXISTS `competitor_secret_formulas` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`competitor_name` varchar(100) NOT NULL,
`country_code` varchar(10) NOT NULL,
`tier` varchar(20) DEFAULT 'standard',
`base_fare` decimal(8,3) NOT NULL,
`price_per_km` decimal(8,3) NOT NULL,
`price_per_min` decimal(8,3) NOT NULL,
`min_fare` decimal(8,3) DEFAULT 0,
`rmse` decimal(10,4) DEFAULT 0,
`r_squared` decimal(10,4) DEFAULT 0,
`surge_multiplier` decimal(5,3) DEFAULT 1.0,
`sample_size` int DEFAULT 0,
`last_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY `idx_comp_country_tier` (`competitor_name`, `country_code`, `tier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
";
$con->exec($sqlFormula);
// Auto-patch existing table if upgrading
try {
$con->exec("ALTER TABLE `scraped_competitor_prices` ADD COLUMN `distance_km` decimal(8,2) DEFAULT NULL AFTER `price_per_km`");
$con->exec("ALTER TABLE `scraped_competitor_prices` ADD COLUMN `duration_min` int DEFAULT NULL AFTER `distance_km`");
} catch (Exception $e) {
// Columns might already exist, ignore error
}
// 2. Ten Key Regions in Damascus (Syria) and Amman (Jordan)
$countriesConfig = [
'SY' => [
'competitors' => ['yallago', 'zaken', 'tufaddal'],
'regions' => [
['name' => 'Umayyad Square', 'lat' => 33.5138, 'lng' => 36.2765],
['name' => 'Mezzeh', 'lat' => 33.5074, 'lng' => 36.2530],
['name' => 'Malki', 'lat' => 33.5220, 'lng' => 36.2840],
['name' => 'Kafersouseh', 'lat' => 33.4981, 'lng' => 36.2730],
['name' => 'Al-Midan', 'lat' => 33.4947, 'lng' => 36.2995],
['name' => 'Bab Tuma', 'lat' => 33.5126, 'lng' => 36.3150],
['name' => 'Rukneddine', 'lat' => 33.5350, 'lng' => 36.2950],
['name' => 'Dummar', 'lat' => 33.5385, 'lng' => 36.2250],
['name' => 'Baramkeh', 'lat' => 33.5100, 'lng' => 36.2885],
['name' => 'Muhajireen', 'lat' => 33.5320, 'lng' => 36.2720],
]
],
'JO' => [
'competitors' => ['com.careem.acma', 'com.ubercab', 'com.taxif.passenger', 'me.com.easytaxi'],
'regions' => [
['name' => 'Abdoun', 'lat' => 31.9392, 'lng' => 35.8942],
['name' => 'Jabal Amman', 'lat' => 31.9511, 'lng' => 35.9189],
['name' => 'Sweileh', 'lat' => 32.0167, 'lng' => 35.8333],
['name' => 'Khalda', 'lat' => 31.9861, 'lng' => 35.8450],
['name' => 'Al-Jubaiha', 'lat' => 32.0194, 'lng' => 35.8753],
['name' => 'Tla Al-Ali', 'lat' => 31.9961, 'lng' => 35.8647],
['name' => 'Shmeisani', 'lat' => 31.9680, 'lng' => 35.9020],
['name' => 'Um Uthaina', 'lat' => 31.9610, 'lng' => 35.8770],
['name' => 'Jabal Al-Weibdeh', 'lat' => 31.9560, 'lng' => 35.9220],
['name' => 'Marj Al-Hamam', 'lat' => 31.9000, 'lng' => 35.8500],
['name' => '7th Circle', 'lat' => 31.9525, 'lng' => 35.8600],
['name' => 'Zarqa New', 'lat' => 32.0833, 'lng' => 36.1000],
['name' => 'Zarqa Camp', 'lat' => 32.0667, 'lng' => 36.0833],
['name' => 'Russeifa', 'lat' => 32.0167, 'lng' => 36.0500],
['name' => 'Marka', 'lat' => 31.9833, 'lng' => 35.9833],
['name' => 'Taj Mall', 'lat' => 31.9423, 'lng' => 35.9038],
['name' => 'City Mall', 'lat' => 31.9806, 'lng' => 35.8353],
['name' => 'Mecca Mall', 'lat' => 31.9792, 'lng' => 35.8464],
['name' => 'Abdali Mall', 'lat' => 31.9644, 'lng' => 35.9117],
['name' => 'Alrabieh', 'lat' => 31.9722, 'lng' => 35.8814],
['name' => 'Dabouq', 'lat' => 31.9989, 'lng' => 35.8153],
['name' => 'Al-Fuheis', 'lat' => 32.0125, 'lng' => 35.7761],
['name' => 'Wadi Al-Seer', 'lat' => 31.9533, 'lng' => 35.8197],
['name' => 'Bayader', 'lat' => 31.9472, 'lng' => 35.8236],
['name' => 'Tariq', 'lat' => 32.0083, 'lng' => 35.9417],
['name' => 'Hashmi Shamali', 'lat' => 31.9800, 'lng' => 35.9556],
['name' => 'Jabal Al-Hussein', 'lat' => 31.9639, 'lng' => 35.9231],
['name' => 'Downtown Amman', 'lat' => 31.9517, 'lng' => 35.9333],
['name' => 'Al-Ashrafiyeh', 'lat' => 31.9361, 'lng' => 35.9417],
['name' => 'Al-Muqabalain', 'lat' => 31.9011, 'lng' => 35.9228],
['name' => 'Al-Wehdat', 'lat' => 31.9250, 'lng' => 35.9417],
['name' => 'Abu Nuseir', 'lat' => 32.0469, 'lng' => 35.8750],
['name' => 'Shafa Badran', 'lat' => 32.0417, 'lng' => 35.9083],
['name' => 'Al-Zaytoonah Uni', 'lat' => 31.8319, 'lng' => 35.9281],
['name' => 'German Jordan Uni','lat' => 31.7778, 'lng' => 35.8114],
['name' => 'Queen Alia Airport','lat'=> 31.7225, 'lng' => 35.9933],
['name' => 'Irbid Center', 'lat' => 32.5514, 'lng' => 35.8500],
['name' => 'Jerash', 'lat' => 32.2817, 'lng' => 35.8917],
['name' => 'Salt', 'lat' => 32.0333, 'lng' => 35.7333],
['name' => 'Madaba', 'lat' => 31.7167, 'lng' => 35.7950],
['name' => 'Dead Sea Hotels', 'lat' => 31.7161, 'lng' => 35.5878]
]
]
];
// Helper to generate a random point within a radius (in km)
function generateRandomPoint($lat, $lng, $radius) {
$radiusInDegrees = $radius / 111.0; // 1 degree is ~111km
$u = lcg_value();
$v = lcg_value();
$w = $radiusInDegrees * sqrt($u);
$t = 2 * pi() * $v;
$x = $w * cos($t);
$y = $w * sin($t);
// Adjust longitude based on latitude
$new_lng = $x / cos(deg2rad($lat));
$new_lat = $y;
return [
'lat' => $lat + $new_lat,
'lng' => $lng + $new_lng
];
}
$tasksCreated = 0;
foreach ($countriesConfig as $countryCode => $config) {
$competitors = $config['competitors'];
$regions = $config['regions'];
// Randomly select 20 regions (or all if less than 20)
shuffle($regions);
$selectedRegions = array_slice($regions, 0, 20);
foreach ($selectedRegions as $region) {
// A. Generate Start Point (within 2km of region center)
$start = generateRandomPoint($region['lat'], $region['lng'], 2);
// B. Generate Short Trip (2-5 km from start)
$shortDist = rand(20, 50) / 10.0;
$shortEnd = generateRandomPoint($start['lat'], $start['lng'], $shortDist);
// C. Generate Long Trip (10-15 km from start)
$longDist = rand(100, 150) / 10.0;
$longEnd = generateRandomPoint($start['lat'], $start['lng'], $longDist);
$trips = [$shortEnd, $longEnd];
foreach ($trips as $end) {
foreach ($competitors as $app) {
$taskId = "prc_" . uniqid();
$taskData = [
"task_id" => $taskId,
"type" => "price_check",
"app" => $app,
"payload" => [
"start_lat" => $start['lat'],
"start_lng" => $start['lng'],
"end_lat" => $end['lat'],
"end_lng" => $end['lng']
]
];
// Push to Redis Queue
$redis->lpush('queue:bot:tasks', json_encode($taskData));
$tasksCreated++;
}
}
}
}
echo "Successfully generated and queued $tasksCreated pricing tasks.\n";