Files
tripz-llc/payment_server/v2/main/ride/mtn/driver/confirm_payment.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

126 lines
4.5 KiB
PHP
Executable File

<?php
// /v1/main/ride/mtn/driver/confirm_payment.php
include "../../../jwtconnect.php";
// It's better to use __DIR__ for reliable file path resolution.
// Assuming your private_key.pem is in the same directory as this script.
$privateKeyPath = __DIR__ . "/private_key.pem";
$baseUrl = rtrim(getenv('MTN_API_BASE_URL'), '/');
$terminalId = getenv('MTN_TERMINAL_ID');
$privateKey = openssl_pkey_get_private(file_get_contents($privateKeyPath));
$invoice = filterRequest('invoiceNumber');
$phone = filterRequest('phone');
$guid = filterRequest('guid');
$operationNumber = filterRequest('operationNumber');
$code = filterRequest('otp'); // The OTP
error_log("MTN Confirm (Driver): Start request for invoice={$invoice}, phone={$phone}, guid={$guid}, opNum={$operationNumber}");
if (!$invoice || !$phone || !$guid || !$operationNumber || !$code) {
error_log("MTN Confirm (Driver): Missing parameters");
printFailure("Missing parameters.");
exit;
}
// Encrypt the code
$hashBin = hash('sha256', $code, true);
$codeB64 = base64_encode($hashBin);
$body = [
'Invoice' => intval($invoice),
'Phone' => $phone,
'Guid' => $guid,
'OperationNumber' => intval($operationNumber),
'Code' => $codeB64
];
$bodyJson = json_encode($body, JSON_UNESCAPED_UNICODE);
error_log("MTN Confirm (Driver): Prepared body JSON: " . $bodyJson);
// Generate signature
$signResult = openssl_sign($bodyJson, $sig, $privateKey, OPENSSL_ALGO_SHA256);
if (!$signResult) {
error_log("MTN Confirm (Driver): Failed to generate signature");
printFailure("Signature error.");
exit;
}
$xSignature = base64_encode($sig);
error_log("MTN Confirm (Driver): Generated signature");
// Send the request
$ch = curl_init("{$baseUrl}/pos_web/payment_phone/confirm");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $bodyJson,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Request-Name: pos_web/payment_phone/confirm",
"Subject: {$terminalId}",
"X-Signature: {$xSignature}"
]
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
error_log("MTN Confirm (Driver): HTTP $httpCode - Response: $response");
if ($curlError) {
error_log("MTN Confirm (Driver): cURL error - $curlError");
}
// --- SOLUTION IMPLEMENTED HERE ---
// 1. Decode the response from MTN to check its contents.
$responseData = json_decode($response, true) ?: [];
// 2. First, check for network/gateway level failure.
if ($httpCode !== 200) {
error_log("MTN Confirm (Driver): HTTP failure for invoice {$invoice}. Code: {$httpCode}");
// Use printFailure to send a structured error to Flutter
printFailure(['message' => 'MTN Gateway Error', 'http' => $httpCode, 'details' => $responseData]);
exit;
}
// 3. Now, check for business-logic failure (like "Balance not enough").
$errno = $responseData['Errno'] ?? -1; // Default to an error state if Errno is missing
if ($errno !== 0) {
$apiError = $responseData['Error'] ?? 'Unknown MTN API Error';
error_log("MTN Confirm (Driver): Business failure for invoice {$invoice}. Errno: {$errno}, Reason: {$apiError}");
// This now sends the specific error message in the format Flutter expects!
printFailure(['message' => $apiError, 'errno' => $errno, 'details' => $responseData]);
exit;
}
// --- ONLY PROCEED TO DATABASE ON FULL SUCCESS (HTTP 200 AND Errno 0) ---
try {
$stmt = $con->prepare(
"UPDATE `paymentsLogSyriaDriver` SET status = 1, updated_at = NOW()
WHERE order_ref = :inv"
);
$stmt->execute([':inv' => $invoice]);
error_log("MTN Confirm (Driver): Payment updated successfully in DB for invoice={$invoice}");
// The file path correction from before remains important.
include_once __DIR__ . '/finalize_wallet_payment.php';
// Call the wallet finalization logic
if (function_exists('finalizeWalletPayment')) {
$_GET['orderRef'] = $invoice;
finalizeWalletPayment($con);
} else {
error_log("MTN Confirm (Driver): FATAL - finalizeWalletPayment() function does not exist after include.");
}
// On success, send a success response to Flutter
printSuccess(['message' => 'Payment confirmed successfully', 'details' => $responseData]);
} catch (PDOException $e) {
error_log("MTN Confirm (Driver): DB update error - " . $e->getMessage());
printFailure("Database processing error.");
}