Files
tripz-llc/payment_server/v2/main/ride/shamcash/save_transactions.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

145 lines
5.8 KiB
PHP
Executable File

<?php
// shamcash/save_transactions.php
ini_set('display_errors', 0);
error_reporting(E_ALL);
header("Content-Type: application/json");
$log_file = __DIR__ . '/transactions.log';
$last_id_file = __DIR__ . '/last_id.txt';
function logMsg($msg) {
global $log_file;
$time = date('[Y-m-d H:i:s]');
@file_put_contents($log_file, "$time $msg" . PHP_EOL, FILE_APPEND);
}
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
// 🔐 HMAC Signature Verification
$sharedSecret = getenv('SHAMCASH_WEBHOOK_SECRET');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_TIMESTAMP'] ?? '';
$rawBody = file_get_contents('php://input');
if (!empty($sharedSecret)) {
if (empty($signature) || empty($timestamp)) {
http_response_code(401);
exit(json_encode(["status" => "error", "msg" => "Missing authentication headers"]));
}
// Verify timestamp is within 5 minutes
if (abs(time() - (int)$timestamp) > 300) {
http_response_code(401);
exit(json_encode(["status" => "error", "msg" => "Request expired"]));
}
$expectedSig = hash_hmac('sha256', $timestamp . '.' . $rawBody, $sharedSecret);
if (!hash_equals($expectedSig, $signature)) {
logMsg("SECURITY: Invalid webhook signature");
http_response_code(403);
exit(json_encode(["status" => "error", "msg" => "Invalid signature"]));
}
logMsg("SECURITY: Webhook signature verified");
}
// الاتصال بقاعدة البيانات
$paths = [__DIR__.'/../jwtconnect.php', __DIR__.'/../../jwtconnect.php', __DIR__.'/../../../jwtconnect.php'];
foreach ($paths as $p) { if (file_exists($p)) { include $p; } }
if (!isset($con) || !$con) { logMsg("CRITICAL: DB Connection Failed"); exit(json_encode(["status" => "error", "msg" => "DB Failed"])); }
if (file_exists(__DIR__ . "/finalize_deposit.php")) include_once __DIR__ . "/finalize_deposit.php";
if (file_exists(__DIR__ . "/passenger/finalize_deposit.php")) include_once __DIR__ . "/passenger/finalize_deposit.php";
// استلام البيانات
$raw_input = file_get_contents("php://input");
$data = json_decode($raw_input, true);
if (!$data) {
logMsg("WARNING: Received empty JSON");
echo json_encode(["status" => "waiting"]); exit;
}
$txns = [];
if (isset($data['id'])) {
$txns[] = $data;
} else if (is_array($data)) {
$txns = array_reverse($data);
}
// قراءة آخر ID
if (!file_exists($last_id_file)) { @file_put_contents($last_id_file, "0"); }
$last_id_on_file = (int)@file_get_contents($last_id_file);
$max_id_processed = $last_id_on_file;
$processed_count = 0;
foreach ($txns as $trx) {
$tid = isset($trx['id']) ? (int)preg_replace('/[^0-9]/', '', $trx['id']) : 0;
$amt = (float)($trx['amount'] ?? 0);
$note = $trx['note'] ?? ''; // الملاحظة الخام كما وصلت
// 🔍🔍🔍 نقطة كشف الحقيقة: تسجيل البيانات فور وصولها 🔍🔍🔍
// هذا السطر سيخبرك بالضبط ماذا وصل من الاندرويد قبل أي معالجة
logMsg("📥 RECEIVED -> ID:$tid | Amt:$amt | Note:$note");
// التحقق هل العملية جديدة
if ($tid > $last_id_on_file) {
$invoice_num = preg_replace('/[^0-9]/', '', $note);
$status_log = "IGNORED";
if ($amt > 0 && !empty($invoice_num) && strlen($invoice_num) >= 4) {
// 1. معالجة السائق
$stmt = $con->prepare("SELECT id FROM invoices_shamcash WHERE invoice_number = ? AND amount = ? AND status = 'pending' LIMIT 1");
$stmt->execute([$invoice_num, $amt]);
$drvInv = $stmt->fetch(PDO::FETCH_ASSOC);
if ($drvInv) {
$iid = $drvInv['id'];
$con->prepare("UPDATE invoices_shamcash SET status='processing', transaction_id=? WHERE id=?")->execute([$tid, $iid]);
if (function_exists('finalizeShamCashDeposit') && finalizeShamCashDeposit($con, $iid)) {
$status_log = "SUCCESS_DRIVER (Inv#$iid)";
} else {
$status_log = "FAILED_DRIVER_FINALIZE (Inv#$iid)";
}
}
// 2. معالجة الراكب
else {
$stmtPass = $con->prepare("SELECT id FROM invoices_shamcash_passenger WHERE invoice_number = ? AND amount = ? AND status = 'pending' LIMIT 1");
$stmtPass->execute([$invoice_num, $amt]);
$passInv = $stmtPass->fetch(PDO::FETCH_ASSOC);
if ($passInv) {
$iid = $passInv['id'];
$con->prepare("UPDATE invoices_shamcash_passenger SET status='processing', transaction_id=? WHERE id=?")->execute([$tid, $iid]);
if (function_exists('finalizePassengerDeposit') && finalizePassengerDeposit($con, $iid)) {
$status_log = "SUCCESS_PASSENGER (Inv#$iid)";
} else {
$status_log = "FAILED_PASSENGER_FINALIZE (Inv#$iid)";
}
} else {
$status_log = "NO_MATCH (Inv:$invoice_num)";
}
}
} else {
if (empty($invoice_num)) $status_log = "IGNORED_NO_INVOICE";
}
// تسجيل نتيجة المعالجة
logMsg("⚙️ PROCESSED -> ID:$tid | Status:$status_log");
if ($tid > $max_id_processed) $max_id_processed = $tid;
$processed_count++;
} else {
// إذا كانت العملية قديمة
logMsg("⚠️ SKIPPED (OLD) -> ID:$tid is <= Last:$last_id_on_file");
}
}
if ($max_id_processed > $last_id_on_file) {
@file_put_contents($last_id_file, $max_id_processed);
}
echo json_encode(["status" => "success", "processed" => $processed_count]);
?>