Update: 2026-06-11 19:26:42
This commit is contained in:
Binary file not shown.
@@ -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());
|
||||
}
|
||||
?>
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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 ---");
|
||||
?>
|
||||
|
||||
@@ -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 ---");
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
?>
|
||||
@@ -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.']);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -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.']);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -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.']);
|
||||
?>
|
||||
Reference in New Issue
Block a user