Update: 2026-06-11 19:26:42

This commit is contained in:
Hamza-Ayed
2026-06-11 19:26:42 +03:00
parent 727068b668
commit b87477bec4
371 changed files with 67 additions and 14257 deletions

View File

@@ -1,44 +0,0 @@
<?php
//check_invoice_status.php
// تضمين ملف الاتصال والإعدادات الخاص بك
// يفترض أن هذا الملف يقوم بالاتصال بقاعدة البيانات ($con)
include "../connect.php";
// --- 1. استقبال البيانات من تطبيق فلاتر ---
$invoice_number = filterRequest("invoice_number");
// التحقق من أن رقم القسيمة قد تم إرساله
if (empty($invoice_number)) {
printFailure("invoice_number is required.");
exit();
}
// --- 2. البحث عن الفاتورة في قاعدة البيانات ---
try {
// إعداد الاستعلام للبحث عن حالة الفاتورة
$sql = "SELECT status FROM `invoices_sms` WHERE invoice_number = :invoice_number LIMIT 1";
$stmt = $con->prepare($sql);
$stmt->execute([
':invoice_number' => $invoice_number
]);
// جلب نتيجة الاستعلام
$invoice = $stmt->fetch(PDO::FETCH_ASSOC);
if ($invoice) {
// تم العثور على الفاتورة، أرجع حالتها الحالية
echo json_encode([
"status" => "success",
"invoice_status" => $invoice['status'] // سيكون "pending" أو "completed"
]);
} else {
// لم يتم العثور على فاتورة بهذا الرقم
printFailure("Invoice not found.");
}
} catch (PDOException $e) {
// في حال حدوث خطأ في قاعدة البيانات
printFailure("Database error: " . $e->getMessage());
}
?>

View File

@@ -1,36 +0,0 @@
<?php
// check_invoice_status_passenger.php
header('Content-Type: application/json; charset=utf-8');
// تضمين الاتصال بقاعدة البيانات ($con)
include "../connect.php";
// 1) استقبال رقم الفاتورة
$invoice_number = filterRequest("invoice_number");
// التحقق من المدخلات
if (empty($invoice_number)) {
printFailure("invoice_number is required.");
exit();
}
try {
// 2) البحث عن حالة الفاتورة في جدول الركّاب
$sql = "SELECT status FROM `invoices_sms_passenger` WHERE invoice_number = :invoice_number LIMIT 1";
$stmt = $con->prepare($sql);
$stmt->execute([':invoice_number' => $invoice_number]);
$invoice = $stmt->fetch(PDO::FETCH_ASSOC);
if ($invoice) {
echo json_encode([
"status" => "success",
"invoice_status" => $invoice['status'] // "pending" أو "completed" أو "failed"
]);
} else {
printFailure("Invoice not found.");
}
} catch (PDOException $e) {
printFailure("Database error: " . $e->getMessage());
}

View File

@@ -1,103 +0,0 @@
<?php
// create_invoice.php
// --- بداية التسجيل: تأكيد بدء تشغيل السكربت ---
//error_log("[CreateInvoice] --- Request Started ---");
// تضمين ملف الاتصال والإعدادات الخاص بك
// تأكد من أن هذا الملف لا يحتوي على أخطاء قد تسبب مشكلة Parse
include "../connect.php";
//error_log("[CreateInvoice] Included 'connect.php'");
try {
// --- 1. تسجيل واستقبال المدخلات ---
// تسجيل البيانات الخام القادمة من الطلب لمعرفة ما يصل بالضبط
// error_log("[CreateInvoice] Raw POST data: " . json_encode($_POST));
$driverID = filterRequest("driverID");
$user_phone = filterRequest("user_phone");
$amount_raw = filterRequest("amount");
// تسجيل البيانات بعد الفلترة
//error_log("[CreateInvoice] Filtered Input: driverID={$driverID}, user_phone={$user_phone}, amount_raw={$amount_raw}");
// تأكيد المبلغ كرقم
$amount = is_numeric($amount_raw) ? (float) $amount_raw : 0.0;
// --- 2. التحقق الأساسي من المدخلات ---
if (empty($driverID) || empty($user_phone) || $amount <= 0) {
error_log("[CreateInvoice] Validation Failed: Missing or invalid required parameters.");
printFailure("driverID, user_phone and a valid amount are required.");
exit;
}
// error_log("[CreateInvoice] Input validation passed.");
// --- 3. التحقق من وجود فاتورة معلقة ---
// error_log("[CreateInvoice] Checking for existing pending invoice for driverID: {$driverID}");
$sql_check = "SELECT id, invoice_number FROM invoices_sms WHERE driverID = :driverID AND user_phone = :user_phone AND status = 'pending' ORDER BY created_at DESC LIMIT 1";
$stmt_check = $con->prepare($sql_check);
$stmt_check->execute(['driverID' => $driverID, 'user_phone' => $user_phone]);
$existing = $stmt_check->fetch(PDO::FETCH_ASSOC);
// إنشاء رقم فاتورة جديد ومميز
$new_invoice_number = random_int(100000, 999999);
if ($existing) {
// --- 4a. تحديث الفاتورة المعلقة الحالية ---
// error_log("[CreateInvoice] Found existing pending invoice (ID: {$existing['id']}). Updating it.");
$sql_update = "UPDATE invoices_sms SET invoice_number = :invoice_number, amount = :amount, created_at = NOW() WHERE id = :id";
$stmt_update = $con->prepare($sql_update);
$stmt_update->execute([
':invoice_number' => $new_invoice_number,
':amount' => $amount,
':id' => $existing['id']
]);
// error_log("[CreateInvoice] Invoice updated. New invoice number: {$new_invoice_number}");
echo json_encode([
"status" => "success",
"message" => "Pending invoice updated.",
"invoice_number" => $new_invoice_number
]);
} else {
// --- 4b. إنشاء فاتورة جديدة ---
// error_log("[CreateInvoice] No pending invoice found. Creating a new one.");
$sql_insert = "INSERT INTO invoices_sms (invoice_number, driverID, user_phone, amount, status) VALUES (:invoice_number, :driverID, :user_phone, :amount, 'pending')";
$stmt_insert = $con->prepare($sql_insert);
$ok = $stmt_insert->execute([
':invoice_number' => $new_invoice_number,
':driverID' => $driverID,
':user_phone' => $user_phone,
':amount' => $amount
]);
if ($ok) {
// error_log("[CreateInvoice] New invoice created successfully. Invoice number: {$new_invoice_number}");
echo json_encode([
"status" => "success",
"message" => "New invoice created.",
"invoice_number" => $new_invoice_number
]);
} else {
// error_log("[CreateInvoice] CRITICAL: Failed to execute INSERT statement.");
printFailure("Failed to create invoice.");
}
}
} catch (PDOException $e) {
// تسجيل أخطاء قاعدة البيانات
// error_log("[CreateInvoice] PDOException: " . $e->getMessage());
printFailure("Database error: " . $e->getMessage());
} catch (Throwable $e) {
// تسجيل أي أخطاء أخرى غير متوقعة
// error_log("[CreateInvoice] Throwable Exception: " . $e->getMessage());
printFailure("An unexpected server error occurred.");
}
//error_log("[CreateInvoice] --- Request Ended ---");
?>

View File

@@ -1,126 +0,0 @@
<?php
// create_invoice_passenger.php
header('Content-Type: application/json; charset=utf-8');
// -------------------------------------
// تضمين الاتصال
// -------------------------------------
include "../connect.php";
error_log("[CreateInvoicePassenger] Included 'connect.php'");
error_log("[CreateInvoicePassenger] --- Request Started ---");
try {
// -------------------------------------
// 1) قراءة المدخلات
// -------------------------------------
$passengerID = filterRequest("passengerID");
$user_phone = filterRequest("user_phone");
$amount_raw = filterRequest("amount");
error_log("[CreateInvoicePassenger] Read inputs (passengerID, user_phone, amount)");
// -------------------------------------
// 2) تحويل/التحقق من المبلغ
// -------------------------------------
$amount = is_numeric($amount_raw) ? (float)$amount_raw : 0.0;
if (empty($passengerID) || empty($user_phone) || $amount <= 0) {
error_log("[CreateInvoicePassenger] Validation failed: missing/invalid parameters");
printFailure("passengerID, user_phone and a valid amount are required.");
exit;
}
error_log("[CreateInvoicePassenger] Input validation passed");
// -------------------------------------
// 3) التحقق من وجود فاتورة معلّقة لنفس الراكب ونفس الهاتف
// -------------------------------------
$sql_check = "
SELECT id, invoice_number
FROM invoices_sms_passenger
WHERE passengerID = :passengerID
AND user_phone = :user_phone
AND status = 'pending'
ORDER BY created_at DESC
LIMIT 1
";
$stmt_check = $con->prepare($sql_check);
$stmt_check->execute([
'passengerID' => $passengerID,
'user_phone' => $user_phone
]);
$existing = $stmt_check->fetch(PDO::FETCH_ASSOC);
error_log("[CreateInvoicePassenger] Checked for existing pending invoice");
// -------------------------------------
// 4) توليد رقم فاتورة جديد (6 أرقام)
// -------------------------------------
$new_invoice_number = random_int(100000, 999999);
error_log("[CreateInvoicePassenger] Generated invoice number");
if ($existing) {
// -------------------------------------
// 4a) تحديث الفاتورة المعلّقة الحالية
// -------------------------------------
error_log("[CreateInvoicePassenger] Existing pending invoice found. Updating...");
$sql_update = "
UPDATE invoices_sms_passenger
SET invoice_number = :invoice_number,
amount = :amount,
created_at = NOW()
WHERE id = :id
";
$stmt_update = $con->prepare($sql_update);
$stmt_update->execute([
':invoice_number' => $new_invoice_number,
':amount' => $amount,
':id' => $existing['id']
]);
error_log("[CreateInvoicePassenger] Invoice updated successfully");
echo json_encode([
"status" => "success",
"message" => "Pending passenger invoice updated.",
"invoice_number" => $new_invoice_number
]);
error_log("[CreateInvoicePassenger] Response sent (update)");
} else {
// -------------------------------------
// 4b) إنشاء فاتورة جديدة
// -------------------------------------
error_log("[CreateInvoicePassenger] No existing invoice. Creating new one...");
$sql_insert = "
INSERT INTO invoices_sms_passenger (invoice_number, passengerID, user_phone, amount, status)
VALUES (:invoice_number, :passengerID, :user_phone, :amount, 'pending')
";
$stmt_insert = $con->prepare($sql_insert);
$ok = $stmt_insert->execute([
':invoice_number' => $new_invoice_number,
':passengerID' => $passengerID,
':user_phone' => $user_phone,
':amount' => $amount
]);
if ($ok) {
error_log("[CreateInvoicePassenger] New invoice created successfully");
echo json_encode([
"status" => "success",
"message" => "New passenger invoice created.",
"invoice_number" => $new_invoice_number
]);
error_log("[CreateInvoicePassenger] Response sent (insert)");
} else {
error_log("[CreateInvoicePassenger] Failed to create passenger invoice (DB insert)");
printFailure("Failed to create passenger invoice.");
}
}
} catch (PDOException $e) {
error_log("[CreateInvoicePassenger] Database exception: " . $e->getMessage());
printFailure("Database error: " . $e->getMessage());
} catch (Throwable $e) {
error_log("[CreateInvoicePassenger] Unexpected exception: " . $e->getMessage());
printFailure("An unexpected server error occurred.");
}
error_log("[CreateInvoicePassenger] --- Request Ended ---");

View File

@@ -1,127 +0,0 @@
<?php
// finalize_payout.php
if (!function_exists('logPayoutError')) {
/**
* دالة مخصصة لتسجيل الأخطاء والخطوات في ملف سجل خاص بعمليات السحب.
*/
function logPayoutError($step, $message, $data = null) {
$logFile = __DIR__ . "/../logs/payout_finalization.log";
$logDir = dirname($logFile);
if (!is_dir($logDir)) { mkdir($logDir, 0755, true); }
$logEntry = "[" . date('Y-m-d H:i:s') . "] STEP {$step}: {$message}";
if ($data !== null) { $logEntry .= " | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE); }
file_put_contents($logFile, $logEntry . PHP_EOL, FILE_APPEND);
}
}
if (!function_exists('generateToken')) {
/**
* دالة لإنشاء توكن دفع فريد وحفظه في قاعدة البيانات.
*/
function generateToken(PDO $con, $driverId, $amount): ?string {
global $secretKey;
$data = $driverId . $amount . time() . ($secretKey ?? 'default_secret_for_token');
$hash = hash('sha256', $data);
$randomBytes = bin2hex(random_bytes(16));
$token = substr($hash . $randomBytes, 0, 64);
$stmt = $con->prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) VALUES (:token, :driverID, NOW(), :amount)");
$stmt->execute([':token' => $token, ':driverID' => $driverId, ':amount' => $amount]);
return $stmt->rowCount() > 0 ? $token : null;
}
}
if (!function_exists('generatePaymentID')) {
/**
* دالة لإنشاء سجل دفعة جديد وإرجاع الـ ID الخاص به.
* هذا السجل هو المرجع الأساسي للمعاملة.
*/
function generatePaymentID(PDO $con, $driverId, $amount, $method): ?string {
$stmt = $con->prepare("INSERT INTO paymentsDriverPoints (`amount`, `payment_method`, `driverID`) VALUES (:amount, :method, :driverID)");
$stmt->execute([':driverID' => $driverId, ':amount' => $amount, ':method' => $method]);
return $stmt->rowCount() > 0 ? $con->lastInsertId() : null;
}
}
if (!function_exists('finalizePayout')) {
/**
* دالة الإتمام الرئيسية لعمليات السحب.
* تقوم بتسجيل كل المعاملات في محافظ السائق والشركة وتحديث حالة الدفعات.
*/
function finalizePayout(PDO $con, int $payoutId) {
logPayoutError("START", "Starting finalization for payout ID: {$payoutId}");
try {
// 1. جلب بيانات طلب السحب المكتمل
$stmt = $con->prepare("SELECT * FROM `payout_requests` WHERE id = :id AND status = 'completed' LIMIT 1");
$stmt->execute([':id' => $payoutId]);
$payout = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$payout) {
logPayoutError("FETCH_PAYOUT", "Payout request not found or not completed.", ['payoutId' => $payoutId]);
return false;
}
$driverId = $payout['driver_id'];
$payoutFee = 3500;
$netAmount = (float)$payout['amount']-$payoutFee; // المبلغ الصافي الذي طلبه السائق
$totalDeducted = $netAmount; // المبلغ الإجمالي الذي سيتم خصمه
// 2. إنشاء معرف دفع رئيسي لهذه المعاملة
// نسجل المبلغ الإجمالي المخصوم بالسالب
$paymentID = generatePaymentID($con, $driverId, -$totalDeducted, 'payout');
if (!$paymentID) throw new Exception('Failed to generate master payment ID');
logPayoutError("GEN_PAYMENT_ID", "Master Payment ID created: {$paymentID}");
// 3. إنشاء التوكنات اللازمة
$tokenDriver = generateToken($con, $driverId, -$totalDeducted);
$tokenSefer = generateToken($con, $driverId, $payoutFee);
if (!$tokenDriver || !$tokenSefer) throw new Exception('Failed to generate required tokens');
logPayoutError("GEN_TOKENS", "Driver and Sefer tokens generated successfully.");
// 4. تسجيل معاملة الخصم في محفظة السائق (driverWallet)
$insertDriver = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) VALUES (:driverID, :paymentID, :amount, :paymentMethod)");
$insertDriver->execute([
':driverID' => $driverId,
':paymentID' => $paymentID,
':amount' => -$totalDeducted, // تسجيل المبلغ بالسالب
':paymentMethod' => 'payout'
]);
if ($insertDriver->rowCount() === 0) throw new Exception('Insert to driverWallet failed');
$con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenDriver]);
logPayoutError("DRIVER_WALLET", "Negative transaction of {$totalDeducted} recorded in driverWallet.");
// 5. تسجيل معاملة الربح (العمولة) في محفظة الشركة (seferWallet)
$insertSefer = $con->prepare("INSERT INTO seferWallet (driverId, passengerId, amount, paymentMethod, token) VALUES (:driverId, :passengerId, :amount, :paymentMethod, :token)");
$insertSefer->execute([
':driverId' => $driverId,
':passengerId' => 'payout_fee', // تمييز المعاملة كعمولة سحب
':amount' => $payoutFee, // تسجيل العمولة بالموجب
':paymentMethod' => 'payout_fee',
':token' => $tokenSefer
]);
if ($insertSefer->rowCount() === 0) throw new Exception('Insert to seferWallet failed');
$con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenSefer]);
logPayoutError("SEFER_WALLET", "Fee transaction of {$payoutFee} recorded in seferWallet.");
// 6. تحديث حالة الدفعات التي تم سحبها في جدول 'payments'
// هذا السطر يقوم بتحديث كل الدفعات المعلقة للسائق، معتبراً أن عملية السحب تغطيها
$updatePayments = $con->prepare("UPDATE payments SET isGiven = TRUE WHERE driverID = :driverId AND isGiven = FALSE");
$updatePayments->execute([':driverId' => $driverId]);
logPayoutError("UPDATE_PAYMENTS", "Marked pending payments as 'isGiven' for driver {$driverId}. Rows affected: " . $updatePayments->rowCount());
logPayoutError("SUCCESS", "Payout finalization completed successfully for payout ID: {$payoutId}");
return true;
} catch (Throwable $e) {
logPayoutError("EXCEPTION", "An exception occurred: " . $e->getMessage(), ['payoutId' => $payoutId]);
return false;
}
}
}
?>

View File

@@ -1,112 +0,0 @@
<?php
// wallet/finalize_wallet_payment.php
// لم نعد بحاجة لـ jwtconnect.php هنا لأن الاتصال يتم تمريره من السكربت الرئيسي
if (!function_exists('logError')) {
function logError($step, $message, $data = null) {
$logFile = __DIR__ . "/../logs/finalization.log";
$logDir = dirname($logFile);
if (!is_dir($logDir)) { mkdir($logDir, 0755, true); }
$logEntry = "[" . date('Y-m-d H:i:s') . "] STEP {$step}: {$message}";
if ($data !== null) { $logEntry .= " | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE); }
file_put_contents($logFile, $logEntry . PHP_EOL, FILE_APPEND);
}
}
/**
* دالة لإنشاء توكن دفع فريد وحفظه في قاعدة البيانات.
*/
function generateToken($con, $driverId, $amount): ?string {
// افترض أن secretKey تم تعريفه في ملف connect.php
global $secretKey;
$data = $driverId . $amount . time() . ($secretKey ?? 'default_secret_for_token');
$hash = hash('sha256', $data);
$randomBytes = bin2hex(random_bytes(16));
$token = substr($hash . $randomBytes, 0, 64);
$stmt = $con->prepare("INSERT INTO payment_tokens (token, driverID, dateCreated, amount) VALUES (:token, :driverID, NOW(), :amount)");
$stmt->execute([':token' => $token, ':driverID' => $driverId, ':amount' => $amount]);
return $stmt->rowCount() > 0 ? $token : null;
}
/**
* دالة لإنشاء سجل دفعة جديد وإرجاع الـ ID الخاص به.
*/
function generatePaymentID($con, $driverId, $amount, $method): ?string {
$stmt = $con->prepare("INSERT INTO paymentsDriverPoints (`amount`, `payment_method`, `driverID`) VALUES (:amount, :method, :driverID)");
$stmt->execute([':driverID' => $driverId, ':amount' => $amount, ':method' => $method]);
return $stmt->rowCount() > 0 ? $con->lastInsertId() : null;
}
/**
* دالة الإتمام الرئيسية، تم تعديلها لتستقبل ID الفاتورة مباشرة
*/
function finalizeWalletPaymentByInvoice($con, $invoiceId) {
logError("FINALIZE", "Starting finalization for invoice ID: {$invoiceId}");
try {
// 1. جلب بيانات الفاتورة المكتملة
$stmt = $con->prepare("SELECT * FROM `invoices_sms` WHERE id = :id AND status = 'completed' LIMIT 1");
$stmt->execute([':id' => $invoiceId]);
$invoice = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$invoice) {
logError("FINALIZE", "Invoice not found or not completed", ['invoiceId' => $invoiceId]);
return false;
}
$driverId = $invoice['driverID'];
$originalAmount = floatval($invoice['amount']);
$paymentMethod = $invoice['sender'] ?? 'sms';
// حساب المكافأة
$bonusAmount = match ((int)$originalAmount) {
10000 => 10000.0,
20000 => 21000.0,
40000 => 45000.0,
100000 => 110000.0,
default => $originalAmount,
};
// إنشاء التوكنات ومعرف الدفع
$tokenDriver = generateToken($con, $driverId, $bonusAmount);
$tokenSefer = generateToken($con, $driverId, $originalAmount);
$paymentID = generatePaymentID($con, $driverId, $bonusAmount, $paymentMethod);
if (!$tokenDriver || !$tokenSefer || !$paymentID) {
throw new Exception('Failed to generate required tokens or payment ID');
}
// --- تحديث المحافظ ---
// driverWallet
$insertDriver = $con->prepare("INSERT INTO driverWallet (driverID, paymentID, amount, paymentMethod) VALUES (:driverID, :paymentID, :amount, :paymentMethod)");
$insertDriver->execute([
':driverID' => $driverId, ':paymentID' => $paymentID,
':amount' => $bonusAmount, ':paymentMethod' => $paymentMethod
]);
if ($insertDriver->rowCount() === 0) throw new Exception('Insert to driverWallet failed');
$con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenDriver]);
// seferWallet
$insertSefer = $con->prepare("INSERT INTO seferWallet (driverId, passengerId, amount, paymentMethod, token) VALUES (:driverId, 'driver', :amount, :paymentMethod, :token)");
$insertSefer->execute([
':driverId' => $driverId, ':amount' => $originalAmount,
':paymentMethod' => $paymentMethod, ':token' => $tokenSefer
]);
if ($insertSefer->rowCount() === 0) throw new Exception('Insert to seferWallet failed');
$con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE token = :token")->execute([':token' => $tokenSefer]);
logError("FINALIZE", "SUCCESS: Wallets updated successfully for invoice ID: {$invoiceId}");
return true;
} catch (Throwable $e) {
logError("FINALIZE", "EXCEPTION: " . $e->getMessage(), ['invoiceId' => $invoiceId]);
return false;
}
}
?>

View File

@@ -1,255 +0,0 @@
<?php
/**
* process_passenger_sms_payment.php
* - يستخدم BASE_URL الموجودة مسبقًا (لا يُعرّف بديل).
* - يستخدم Gemini 2.5 Flash Lite.
* - لا يحدّث raw_sms_log الآن (لا mark processed/failed).
* - الدفع للراكب فقط: invoices_sms_passenger → bonus → generate token → add to wallets.
*/
header('Content-Type: application/json; charset=utf-8');
include_once __DIR__ . '/../../connect.php';
if (!defined('BASE_URL')) {
$APP_BASE_URL = rtrim(getenv('APP_BASE_URL') ?: '', '/');
if ($APP_BASE_URL === '') {
$scheme = isset($_SERVER['REQUEST_SCHEME']) ? $_SERVER['REQUEST_SCHEME'] : 'https';
$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
define('BASE_URL', $scheme . '://' . $host);
} else {
define('BASE_URL', $APP_BASE_URL);
}
}
/* ===== Gemini: Flash Lite ===== */
$geminiModel = 'gemini-2.5-flash-lite';
$geminiApiKey = getenv('GEMINI_API_KEY');
if (!$geminiApiKey) {
printFailure("Missing GEMINI_API_KEY");
exit;
}
$geminiApiUrl = "https://generativelanguage.googleapis.com/v1beta/models/{$geminiModel}:generateContent?key={$geminiApiKey}";
/* ===== اجلب رسالة واحدة pending (مع sender) ===== */
try {
$stmt = $con->prepare("
SELECT id, message_body, sender
FROM raw_sms_log
WHERE status = 'pending'
ORDER BY created_at ASC
LIMIT 1
");
$stmt->execute();
$sms = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$sms) {
echo json_encode(["status" => "idle", "message" => "No pending messages"]);
exit;
}
} catch (PDOException $e) {
printFailure("DB fetch error: " . $e->getMessage());
exit;
}
$smsId = (int)$sms['id'];
$body = (string)$sms['message_body'];
$sender = (string)$sms['sender']; // نستخدمه لاشتقاق طريقة الدفع
/* ===== Prompt لِـ Gemini ===== */
$prompt = "Analyze the following financial SMS and return ONLY a valid JSON object:
{
\"transaction_type\": \"income\" | \"payout\",
\"amount\": number,
\"currency\": \"SYP\" | string (3 letters),
\"phone_number\": string | null
}
SMS Text: \"$body\"";
$payload = ['contents' => [['parts' => [['text' => $prompt]]]]];
$ch = curl_init($geminiApiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload, JSON_UNESCAPED_UNICODE));
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlErr = curl_error($ch);
curl_close($ch);
if ($response === false) {
printFailure("Gemini curl error: " . $curlErr);
exit;
}
$gem = json_decode($response, true);
$gemText = $gem['candidates'][0]['content']['parts'][0]['text'] ?? null;
if ($httpCode !== 200 || !$gemText) {
printFailure("Gemini HTTP $httpCode / empty response");
exit;
}
/* Gemini أحيانًا يحيط الـ JSON بعلامات Markdown */
$clean = trim(str_replace(['```json','```JSON','```'], '', $gemText));
$data = json_decode($clean, true);
if (!is_array($data) || empty($data['transaction_type'])) {
printFailure("Failed to parse Gemini JSON");
exit;
}
/* ===== القيم المستخرجة ===== */
$trxType = strtolower((string)$data['transaction_type']);
$amount = isset($data['amount']) ? floatval($data['amount']) : 0.0;
$currency = isset($data['currency']) ? strtoupper((string)$data['currency']) : '';
$phone = isset($data['phone_number']) ? (string)$data['phone_number'] : '';
/* ===== طريقة الدفع من الـ sender (الآن ثابتة shamcash كما طلبت) ===== */
$paymentMethod = 'shamcash'; // أو اشتقاق ذكي: strpos(strtolower($sender),'sham') !== false ? 'shamcash' : 'unknown';
/* ===== فقط INCOME: نفّذ تدفّق الراكب ===== */
if ($trxType === 'income' && $amount > 0 && $phone !== '') {
try {
// ابحث عن فاتورة راكب حديثة متطابقة خلال 60 دقيقة
$q = $con->prepare("
SELECT id
FROM invoices_sms_passenger
WHERE status='pending'
AND user_phone = :p
AND amount = :a
AND created_at >= (NOW() - INTERVAL 60 MINUTE)
ORDER BY created_at DESC
LIMIT 1
");
$q->execute([':p' => $phone, ':a' => $amount]);
$inv = $q->fetch(PDO::FETCH_ASSOC);
if (!$inv) {
printFailure( "No matching passenger invoice");
exit;
}
$invoiceId = $inv['id'];
// حدّث حالة الفاتورة
$con->prepare("UPDATE invoices_sms_passenger SET status='completed', updated_at=NOW() WHERE id=:id")
->execute([':id' => $invoiceId]);
// احضر بيانات الفاتورة لمعرفة passengerID والمبلغ المؤكد
$st = $con->prepare("SELECT passengerID, amount FROM invoices_sms_passenger WHERE id=:id LIMIT 1");
$st->execute([':id' => $invoiceId]);
$row = $st->fetch(PDO::FETCH_ASSOC);
if (!$row) {
printFailure("Invoice row not found after update");
exit;
}
$passengerId = $row['passengerID'];
$amt = floatval($row['amount']);
// 1) Bonus
$finalAmount = calculateBonus($amt);
// 2) Generate payment token (للراكب)
$token = generatePaymentToken($passengerId, $finalAmount);
// 3) Add to Passenger Wallet
$walletResult = addToPassengerWallet($passengerId, $finalAmount, $token);
// 4) Add to Sefer Wallet (محاسبي) بطريقة الدفع المستخلصة من sender
$token2 = generatePaymentToken($passengerId, $amt);
$seferWalletResult = addToSeferWallet($passengerId, $amt, $paymentMethod, $token2);
printSuccess([
"message" => "Passenger income processed",
"invoice_id" => $invoiceId,
"passenger_id" => $passengerId,
"amount" => $amt,
"final_amount" => $finalAmount,
"payment_method" => $paymentMethod,
"wallet" => $walletResult,
"seferWallet" => $seferWalletResult,
"sender" => $sender
]);
exit;
} catch (PDOException $e) {
printFailure("DB income error: " . $e->getMessage());
exit;
}
}
/* غير مدعوم الآن (payout أو مدخلات ناقصة) */
printFailure([
"status" => "ignored",
"message" => "Unsupported or incomplete transaction",
"type" => $trxType,
"sender" => $sender
]);
exit;
/* ===== Helpers — تعتمد على BASE_URL الموجودة عندك ===== */
function calculateBonus($amount) {
if ($amount == 20000) return 20500;
if ($amount == 40000) return 42500;
if ($amount == 100000) return 104000;
return $amount;
}
function generatePaymentToken($passengerId, $amount) {
if (!defined('BASE_URL')) return null; // نعتمد وجودها لديك
$url = rtrim(BASE_URL, '/') . "/passengerWallet/addPaymentTokenPassenger.php";
$post = ['passengerId' => $passengerId, 'amount' => $amount];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code != 200 || !$resp) return null;
$j = json_decode($resp, true);
return $j['message'] ?? null;
}
function addToPassengerWallet($passengerId, $amount, $token) {
if (!defined('BASE_URL')) return null;
$url = rtrim(BASE_URL, '/') . "/passengerWallet/add.php";
$post = ['passenger_id' => $passengerId, 'balance' => $amount, 'token' => $token];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code != 200 || !$resp) return null;
return json_decode($resp, true);
}
function addToSeferWallet($passengerId, $amount, $paymentMethod, $token) {
if (!defined('BASE_URL')) return null;
$url = rtrim(BASE_URL, '/') . "/seferWallet/add.php";
$post = [
'amount' => $amount,
'paymentMethod' => $paymentMethod, // من sender
'passengerId' => $passengerId,
'token' => $token,
'driverId' => 'passenger'
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code != 200 || !$resp) return null;
return json_decode($resp, true);
}

View File

@@ -1,132 +0,0 @@
<?php
// تأكد من أن هذا السكربت لا يمكن الوصول إليه مباشرة من الويب (للحماية)
// يمكنك وضع ملف .htaccess في المجلد لمنع الوصول المباشر
// المسار الصحيح لملف الاتصال
// هذه الطريقة تضمن أن المسار صحيح دائمًا بغض النظر عن كيفية استدعاء السكربت
include_once __DIR__ . '/../../connect.php';
// يمكنك هنا تضمين أي ملفات مساعدة أخرى
// استخدام __DIR__ هنا أيضًا يضمن إيجاد الملف في نفس المجلد الحالي
include_once __DIR__ . '/finalize_wallet_payment.php';
// --- إعدادات Gemini API ---
// من الأفضل قراءة مفتاح API من متغيرات البيئة لزيادة الأمان
$geminiApiKey = getenv('GEMINI_API_KEY');
$geminiApiUrl = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent?key=" . $geminiApiKey;
// 1. جلب رسالة واحدة بحالة "pending" لمعالجتها
$stmt_fetch = $con->prepare("SELECT id, message_body FROM `raw_sms_log` WHERE `status` = 'pending' ORDER BY created_at ASC LIMIT 1");
$stmt_fetch->execute();
$sms = $stmt_fetch->fetch(PDO::FETCH_ASSOC);
if (!$sms) {
exit("No pending messages found.\n");
}
$sms_id = $sms['id'];
$sms_text = $sms['message_body'];
// 2. بناء الطلب (Prompt) الذكي إلى Gemini
$prompt = "Analyze the following financial SMS and return ONLY a valid JSON object.
- `transaction_type`: Must be 'income' (money received) or 'payout' (money sent).
- `amount`: Must be a number (float).
- `currency`: Must be a 3-letter code (e.g., SYP).
- `phone_number`: The phone number of the other party. Must be a string, or `null` if not found.
SMS Text: \"$sms_text\"";
$payload = ['contents' => [['parts' => [['text' => $prompt]]]]];
// 3. إرسال الطلب إلى Gemini API
$ch = curl_init($geminiApiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
$response = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 4. معالجة رد Gemini
$result = json_decode($response, true);
$gemini_text_response = $result['candidates'][0]['content']['parts'][0]['text'] ?? null;
if ($httpcode == 200 && $gemini_text_response) {
$clean_json_str = trim(str_replace(['```json', '```'], '', $gemini_text_response));
$data = json_decode($clean_json_str, true);
if ($data && isset($data['transaction_type'])) {
// --- نجحت المعالجة: استخراج البيانات ---
$phone_raw = $data['phone_number'] ?? null;
$amount = isset($data['amount']) ? (float)$data['amount'] : 0;
// توحيد صيغة رقم الهاتف (مثال بسيط)
$phone_norm = $phone_raw; // يمكنك إضافة منطق أكثر تعقيداً هنا إذا لزم الأمر
if ($data['transaction_type'] === 'income' && !empty($phone_norm) && $amount > 0) {
// البحث عن فاتورة مطابقة خلال آخر 60 دقيقة
$q = $con->prepare("SELECT id FROM invoices_sms WHERE status='pending' AND user_phone=:p AND amount=:a AND created_at >= (NOW() - INTERVAL 60 MINUTE) ORDER BY created_at DESC LIMIT 1");
$q->execute([':p' => $phone_norm, ':a' => $amount]);
$inv = $q->fetch(PDO::FETCH_ASSOC);
if ($inv) {
// تم العثور على فاتورة مطابقة -> قم بتحديثها وتنفيذ الإجراء النهائي
$con->prepare("UPDATE invoices_sms SET status='completed' WHERE id=:id")->execute([':id' => $inv['id']]);
// افترض أن هذه الدالة موجودة في ملف connect.php أو ملف مساعد آخر
$ok = function_exists('finalizeWalletPaymentByInvoice') ? finalizeWalletPaymentByInvoice($con, $inv['id']) : false;
$note = $ok ? 'finalized' : 'finalize_failed';
$con->prepare("UPDATE raw_sms_log SET status='processed', gemini_result=:r WHERE id=:id")->execute([':r' => json_encode($data, JSON_UNESCAPED_UNICODE), ':id' => $sms_id]);
echo "Income matched -> invoice {$inv['id']} -> $note\n";
} else {
// لم يتم العثور على فاتورة مطابقة
$con->prepare("UPDATE raw_sms_log SET status='failed', gemini_result=:r WHERE id=:id")->execute([':r' => json_encode(['warn' => 'no pending invoice match', 'parsed' => $data], JSON_UNESCAPED_UNICODE), ':id' => $sms_id]);
echo "No matching pending invoice found.\n";
}
} elseif ($data['transaction_type'] === 'payout' && !empty($phone_norm) && $amount > 0) {
// --- منطق معالجة الدفعات الصادرة ---
$q = $con->prepare("SELECT id FROM payout_requests WHERE status='pending' AND driver_phone=:p AND amount=:a ORDER BY created_at DESC LIMIT 1");
$q->execute([':p' => $phone_norm, ':a' => $amount]);
$payout = $q->fetch(PDO::FETCH_ASSOC);
if ($payout) {
// تم العثور على طلب سحب مطابق -> قم بتحديثه واستدعاء الإتمام
$payout_id = $payout['id'];
$con->prepare("UPDATE payout_requests SET status='completed', completed_at=NOW() WHERE id=:id")->execute([':id' => $payout_id]);
include_once __DIR__ . '/finalize_payout.php';
if (function_exists('finalizePayout')) {
finalizePayout($con, $payout_id);
$note = "Payout request {$payout_id} finalized.";
} else {
$note = "CRITICAL: finalizePayout function not found!";
}
$con->prepare("UPDATE raw_sms_log SET status='processed', gemini_result=:r WHERE id=:id")->execute([':r'=>json_encode($data), ':id'=>$sms_id]);
error_log("[ProcessGemini] $note");
} else {
// لم يتم العثور على طلب سحب مطابق
$con->prepare("UPDATE raw_sms_log SET status='failed', gemini_result=:r WHERE id=:id")->execute([':r'=>json_encode(['warn'=>'no pending payout match', 'parsed'=>$data]), ':id'=>$sms_id]);
error_log("[ProcessGemini] No matching pending payout found for SMS ID {$sms_id}");
}
}
} else {
// فشل تحليل رد Gemini
$stmt_update = $con->prepare("UPDATE `raw_sms_log` SET `status` = 'failed', `gemini_result` = :result WHERE `id` = :id");
$stmt_update->execute([':result' => json_encode(['error' => "Failed to parse Gemini's JSON response", 'response' => $gemini_text_response]), ':id' => $sms_id]);
echo "Failed to parse Gemini's JSON response for message ID $sms_id.\n";
}
} else {
// لم يتم استلام رد من Gemini أو حدث خطأ في الطلب
$stmt_update = $con->prepare("UPDATE `raw_sms_log` SET `status` = 'failed', `gemini_result` = :result WHERE `id` = :id");
$stmt_update->execute([':result' => json_encode(['error' => 'No valid response from Gemini API', 'http_code' => $httpcode]), ':id' => $sms_id]);
echo "No valid response from Gemini API for message ID $sms_id. HTTP Code: $httpcode\n";
}
?>

View File

@@ -1,84 +0,0 @@
<?php
// request_payout.php
include "../connect.php"; // ملف الاتصال الذي يتحقق من JWT
error_log("[RequestPayout] --- Request Started ---");
// --- 1. استقبال المدخلات ---
$driverId = filterRequest("driverId");
$amount_raw = filterRequest("amount");
$wallet_type = filterRequest("wallet_type") ?? 'Sham Cash'; // قيمة افتراضية
$phone = filterRequest("phone");
// تأكيد المبلغ كرقم
$amount = is_numeric($amount_raw) ? (float)$amount_raw : 0.0;
// تحقق أساسي
if (empty($driverId) || $amount <= 0) {
printFailure("driverId and a valid amount are required.");
exit;
}
try {
// --- 2. التحقق من بيانات السائق ورصيده ---
$stmt_driver = $con->prepare("
SELECT SUM(amount) AS balance
FROM driverWallet
WHERE driverID = :id
LIMIT 1
");
$stmt_driver->execute([':id' => $driverId]);
$driver = $stmt_driver->fetch(PDO::FETCH_ASSOC);
if (!$driver) {
printFailure("Driver not found.");
exit;
}
$payout_fee = 3500.00; // عمولة السحب
$total_deduction = $amount + $payout_fee; // المبلغ المطلوب مع العمولة
if ($driver['balance'] < $total_deduction) {
printFailure("Insufficient balance. Required: $total_deduction");
exit;
}
// --- 3. إنشاء طلب السحب في قاعدة البيانات ---
$sql = "
INSERT INTO payout_requests (driver_id, driver_phone, amount, wallet_type)
VALUES (:did, :phone, :amount, :wallet)
";
$stmt = $con->prepare($sql);
$stmt->execute([
':did' => $driverId,
':phone' => $phone,
':amount'=> $amount,
':wallet'=> $wallet_type
]);
if ($stmt->rowCount() > 0) {
// --- 4. إرسال إشعار لخدمة العملاء ---
$customerServicePhone = getenv('CUSTOMER_SERVICE_PHONE');
$message =
"⚠️ طلب دفع جديد:\n" .
"ID السائق: {$driverId}\n" .
"هاتف السائق: {$phone}\n" .
"نوع المحفظة: {$wallet_type}\n" .
"المبلغ: {$amount} SYP\n\n" .
"الرجاء من فريق خدمة العملاء تنفيذ عملية الدفع الآن.";
// الإرسال (الفنكشن مُضمّن لديك مسبقًا)
sendWhatsAppFromServer($customerServicePhone, $message);
error_log("[RequestPayout] Successfully created payout request for driver ID: $driverId");
printSuccess("Payout request created successfully. It will be processed shortly.");
} else {
printFailure("Failed to create payout request.");
}
} catch (PDOException $e) {
error_log("[RequestPayout] PDOException: " . $e->getMessage());
printFailure("A database error occurred.");
}
?>

View File

@@ -1,37 +0,0 @@
<?php
//save_raw_sms.php
// تضمين ملف الاتصال والإعدادات الرئيسي
// تأكد من أن هذا الملف يقوم بالتحقق من صحة JWT و HMAC القادم في الهيدرز
include __DIR__ . "/../connect.php";
// استقبال الرسالة الخام من تطبيق الأندرويد
$json_data = file_get_contents('php://input');
$data = json_decode($json_data, true);
// التحقق من وجود البيانات المطلوبة
if ($data && isset($data['sender']) && isset($data['message'])) {
try {
// حفظ الرسالة في جدول السجل الخام مع حالة "pending"
$sql = "INSERT INTO `raw_sms_log` (sender, message_body, status) VALUES (:sender, :message, 'pending')";
$stmt = $con->prepare($sql);
$stmt->execute([':sender' => $data['sender'], ':message' => $data['message']]);
// --- خطوة مهمة: تفعيل سكربت المعالجة في الخلفية ---
// هذا الأمر يجعل سكربت التحليل يعمل فورًا دون أن ينتظر المستخدم
// تأكد من أن المسار صحيح تمامًا على سيرفرك
$command = "php " . __DIR__ . "/process_with_gemini.php > /dev/null 2>&1 &";
shell_exec($command);
http_response_code(200);
echo json_encode(['status' => 'success', 'message' => 'SMS received and scheduled for processing.']);
} catch (PDOException $e) {
http_response_code(500);
echo json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]);
}
} else {
http_response_code(400);
echo json_encode(['status' => 'error', 'message' => 'Invalid data provided.']);
}
?>

View File

@@ -1,37 +0,0 @@
<?php
//save_raw_sms.php
// تضمين ملف الاتصال والإعدادات الرئيسي
// تأكد من أن هذا الملف يقوم بالتحقق من صحة JWT و HMAC القادم في الهيدرز
include __DIR__ . "/../connect.php";
// استقبال الرسالة الخام من تطبيق الأندرويد
$json_data = file_get_contents('php://input');
$data = json_decode($json_data, true);
// التحقق من وجود البيانات المطلوبة
if ($data && isset($data['sender']) && isset($data['message'])) {
try {
// حفظ الرسالة في جدول السجل الخام مع حالة "pending"
$sql = "INSERT INTO `raw_sms_log` (sender, message_body, status) VALUES (:sender, :message, 'pending')";
$stmt = $con->prepare($sql);
$stmt->execute([':sender' => $data['sender'], ':message' => $data['message']]);
// --- خطوة مهمة: تفعيل سكربت المعالجة في الخلفية ---
// هذا الأمر يجعل سكربت التحليل يعمل فورًا دون أن ينتظر المستخدم
// تأكد من أن المسار صحيح تمامًا على سيرفرك
$command = "php " . __DIR__ . "/process_passenger_sms_payment.php > /dev/null 2>&1 &";
shell_exec($command);
http_response_code(200);
echo json_encode(['status' => 'success', 'message' => 'SMS received and scheduled for processing.']);
} catch (PDOException $e) {
http_response_code(500);
echo json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]);
}
} else {
http_response_code(400);
echo json_encode(['status' => 'error', 'message' => 'Invalid data provided.']);
}
?>

View File

@@ -1,75 +0,0 @@
<?php
//webhook.php
// تضمين ملف الاتصال الذي يتحقق أيضاً من توكن JWT
include "../connect.php";
// --- 1. قراءة البيانات المرسلة ---
$json_data = file_get_contents('php://input');
$data = json_decode($json_data, true);
if ($data === null || !isset($data['sender']) || !isset($data['message'])) {
http_response_code(400); // Bad Request
echo json_encode(['status' => 'error', 'message' => 'Invalid JSON data received']);
exit();
}
// --- 2. استخراج البيانات ---
$sender = $data['sender'];
$message_body = $data['message'];
$received_at = date('Y-m-d H:i:s');
$log_entry = "[$received_at] From: $sender | Message: $message_body";
// --- 3. تحليل الرسالة (يركز على Orange Money حالياً) ---
$pattern_orangemoney_jo = '/تم استقبال حوالة مالية من (\d+)\s+من مزود الخدمة:\s+Orange Money إلى محفظتك بمبلغ ([\d,.]+)\s+دينار/';
if (preg_match($pattern_orangemoney_jo, $message_body, $matches)) {
$payer_phone_raw = $matches[1];
$amount_str = $matches[2];
$amount = (float) str_replace(',', '', $amount_str);
// توحيد صيغة رقم الهاتف (إزالة 0096 إذا وجدت وإضافة 0)
$payer_phone = $payer_phone_raw;
if (substr($payer_phone_raw, 0, 4) === '0096') {
$payer_phone = '0' . substr($payer_phone_raw, 4);
}
$log_entry .= " | MATCH: Orange Money | SUCCESS: Parsed Amount = $amount, Payer Phone = $payer_phone";
// --- 4. منطق تحديث الفاتورة ---
try {
// البحث عن أحدث فاتورة مطابقة (نفس الرقم والمبلغ) بحالة انتظار وتحديثها
$sql = "UPDATE invoices_sms SET status = 'completed'
WHERE user_phone = :phone
AND amount = :amount
AND status = 'pending'
ORDER BY created_at DESC
LIMIT 1";
$stmt = $con->prepare($sql);
$stmt->execute([
':phone' => $payer_phone,
':amount' => $amount
]);
if ($stmt->rowCount() > 0) {
$log_entry .= " | DB: SUCCESS - Invoice found and updated." . PHP_EOL;
// يمكنك هنا إضافة كود لإرسال إشعار للمستخدم
} else {
$log_entry .= " | DB: WARNING - No pending invoice found for this transaction." . PHP_EOL;
}
} catch (PDOException $e) {
$log_entry .= " | DB: ERROR - " . $e->getMessage() . PHP_EOL;
}
} else {
$log_entry .= " | INFO: Message did not match any known payment pattern. Ignored." . PHP_EOL;
}
// كتابة السجل (مهم لتصحيح الأخطاء)
file_put_contents('sms_log.txt', $log_entry, FILE_APPEND);
// إرسال رد إلى تطبيق الأندرويد
http_response_code(200);
echo json_encode(['status' => 'success', 'message' => 'Webhook processed.']);
?>