classify admin

This commit is contained in:
Husanjonazamov
2026-02-24 12:52:01 +05:00
commit e0f1989655
769 changed files with 1263008 additions and 0 deletions

View File

@@ -0,0 +1,382 @@
<?php
namespace App\Services\Payment;
use Auth;
use PhonePe\PhonePe as PhonePeSDK;
use Illuminate\Support\Facades\Log;
use Exception;
class PhonePePayment implements PaymentInterface
{
private string $clientId;
private string $callbackUrl;
private string $transactionId;
private string $clientSecret;
private string $clientVersion;
private string $payment_mode;
private string $merchantId;
private string $pgUrl;
public function __construct($clientSecret, $clientId, $addtional_data_1,$addtional_data_2, $payment_mode)
{
// $this->clientId = 'TEST-CITYSURFONLINE_2508';
$this->clientId = $clientId;
$this->callbackUrl = url('/webhook/phonePe');
$this->transactionId = uniqid();
$this->clientSecret = $clientSecret;
$this->clientVersion = $addtional_data_1;
$this->payment_mode = $payment_mode;
$this->merchantId = $addtional_data_2;
$this->pgUrl = ($payment_mode == "UAT") ? "https://api-preprod.phonepe.com/apis/pg-sandbox" : "https://api.phonepe.com/apis/pg";
}
/**
* Create payment intent for PhonePe
*
* @param $amount
* @param $customMetaData
* @return array
* @throws Exception
*/
public function createPaymentIntent($amount, $customMetaData) {
Log::info("PhonePe Payment custome", [
'amount' => $amount,
'customMetaData' => $customMetaData,
]);
$amount = $this->minimumAmountValidation('INR', $amount);
$userMobile = Auth::user()->mobile;
$metaData = 't' . '-' . $customMetaData['payment_transaction_id'] . '-' . 'p' . '-' . $customMetaData['package_id'];
if ($customMetaData['platform_type'] == 'web') {
$transactionId = uniqid();
$mode = $this->payment_mode;
if ($mode === 'PROD') {
$tokenUrl = 'https://api.phonepe.com/apis/identity-manager/v1/oauth/token';
$orderUrl = 'https://api.phonepe.com/apis/pg/checkout/v2/sdk/order';
$payUrl = 'https://api.phonepe.com/apis/pg/checkout/v2/pay';
} else {
$tokenUrl = 'https://api-preprod.phonepe.com/apis/pg-sandbox/v1/oauth/token';
$orderUrl = 'https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/sdk/order';
$payUrl = 'https://api-preprod.phonepe.com/apis/pg-sandbox/checkout/v2/pay';
}
$tokenCurl = curl_init();
curl_setopt_array($tokenCurl, array(
CURLOPT_URL => $tokenUrl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => http_build_query([
'client_id' => $this->clientId,
'client_version' => $this->clientVersion,
'client_secret' => $this->clientSecret,
'grant_type' => 'client_credentials',
]),
CURLOPT_HTTPHEADER => array(
'Content-Type: application/x-www-form-urlencoded'
),
));
$response = curl_exec($tokenCurl);
curl_close($tokenCurl);
// Decode token response
$tokenResponse = json_decode($response, true);
$accessToken = $tokenResponse['access_token'] ?? null;
if (!$accessToken) {
dd("Failed to retrieve token", $response);
}
// Build JSON payload properly
$paymentData = [
'merchantOrderId' => $metaData,
'amount' => (int) round($amount * 100),
"metadata" => [
"package_id" => $customMetaData['package_id'],
"payment_transaction_id" => $customMetaData['payment_transaction_id'],
"user_id" => Auth::user()->id,
],
'paymentFlow' => [
'type' => 'PG_CHECKOUT',
'message' => 'Payment message used for collect requests',
'merchantUrls' => [
'redirectUrl' => route('phonepe.success.web'),
],
],
];
$payCUrl = curl_init();
curl_setopt_array($payCUrl, array(
CURLOPT_URL => $payUrl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => json_encode($paymentData),
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
'Authorization: O-Bearer ' . $accessToken,
),
));
$response = curl_exec($payCUrl);
$final_response = json_decode($response, true);
if (!empty($final_response)) {
$redirectURL = $final_response['redirectUrl'];
return $this->formatPaymentIntent($transactionId, $amount, 'INR', 'pending', $customMetaData, $redirectURL);
}
curl_close($payCUrl);
} else {
$redirectUrl = route('phonepe.success');
$orderId = 'TX' . time(); // unique order ID
$amount = (int) round($amount * 100); // amount in INR (not multiplied)
$expireAfter = 1200; // in seconds (20 mins)
$token = $this->getPhonePeToken();
$order = $this->createOrder($token, $orderId, $amount);
$order_data = json_decode($order, true);
$requestPayload = [
"orderId" => $order_data['orderId'],
// "state" => "PENDING",
'merchantOrderId' => $metaData,
"merchantId" => $this->merchantId,
"expireAT" => $expireAfter,
"token" => $order_data['token'],
"paymentMode" => [
"type" => "PAY_PAGE"
]
];
// Convert to JSON string as required by Flutter SDK
$requestString = json_encode($requestPayload);
if ($this->payment_mode == "UAT") {
$payment_mode = "SANDBOX";
} else {
$payment_mode = "PRODUCTION";
}
return [
"environment" => $payment_mode, // or "PRODUCTION"
"merchantId" => $this->merchantId,
"flowId" => $orderId,
"enableLogging" => true, // false in production
"request" => $requestPayload,
"appSchema" => "eclassify", // for iOS deep link return
"token" => $token,
];
}
throw new Exception("Error initiating payment: " . $redirectURL);
}
/**
* Create and format payment intent for PhonePe
*
* @param $amount
* @param $customMetaData
* @return array
* @throws Exception
*/
public function createAndFormatPaymentIntent($amount, $customMetaData): array
{
$paymentIntent = $this->createPaymentIntent($amount, $customMetaData);
$metaData = 't' . '-' . $customMetaData['payment_transaction_id'] . '-' . 'p' . '-' . $customMetaData['package_id'];
return $this->formatPaymentIntent(
id: $metaData,
amount: $amount,
currency: 'INR',
status: "PENDING",
metadata: $customMetaData,
paymentIntent: $paymentIntent
);
}
/**
* Retrieve payment intent (check payment status)
*
* @param $transactionId
* @return array
* @throws Exception
*/
public function retrievePaymentIntent($transactionId): array
{
$statusUrl = 'https://api.phonepe.com/v3/transaction/' . $transactionId . '/status';
$signature = $this->generateSignature(''); // Adjust if needed based on PhonePe requirements
$response = $this->sendRequest($statusUrl, '', $signature);
if ($response['success']) {
return $this->formatPaymentIntent($transactionId, $response['amount'], 'INR', $response['status'], [], $response);
}
throw new Exception("Error fetching payment status: " . $response['message']);
}
/**
* Format payment intent response
*
* @param $id
* @param $amount
* @param $currency
* @param $status
* @param $metadata
* @param $paymentIntent
* @return array
*/
public function formatPaymentIntent($id, $amount, $currency, $status, $metadata, $paymentIntent): array
{
return [
'id' => $id,
'amount' => $amount,
'currency' => $currency,
'metadata' => $metadata,
'status' => match ($status) {
"SUCCESS" => "succeeded",
"PENDING" => "pending",
"FAILED" => "failed",
default => "unknown"
},
'payment_gateway_response' => $paymentIntent
];
}
/**
* Minimum amount validation
*
* @param $currency
* @param $amount
* @return float|int
*/
public function minimumAmountValidation($currency, $amount)
{
$minimumAmount = match ($currency) {
'INR' => 1.00, // 1 Rupee
default => 0.50
};
return ($amount >= $minimumAmount) ? $amount : $minimumAmount;
}
/**
* Generate HMAC signature for PhonePe
*
* @param $encodedRequestBody
* @return string
*/
private function generateSignature($requestBody): string
{
// Concatenate raw JSON payload, endpoint, and salt key
$stringToHash = $requestBody . '/pg/v1/pay' . $this->saltKey;
// Hash the string using SHA256
$hash = hash('sha256', $stringToHash);
// Append salt index (Assumed to be 1 in this example)
return $hash . '###' . 1;
}
/**
* Send cURL request to PhonePe API
*
* @param $url
* @param $requestBody
* @param $signature
* @return array
*/
// private function sendRequest($url, $requestBody, $signature): array
// {
// // dd($requestBody);
// $ch = curl_init($url);
// curl_setopt($ch, CURLOPT_POST, 1);
// curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
// curl_setopt($ch, CURLOPT_HTTPHEADER, [
// 'Content-Type: application/json',
// 'X-VERIFY: ' . $signature,
// ]);
// curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// $response = curl_exec($ch);
// curl_close($ch);
// return json_decode($response, true);
// }
public function getPhonePeToken() {
$clientId = $this->clientId;
$clientSecret = $this->clientSecret;
$clientVersion = $this->clientVersion;
$postData = http_build_query([
'client_id' => $clientId,
'client_version' => $clientVersion,
'client_secret' => $clientSecret,
'grant_type' => 'client_credentials',
]);
if ($this->payment_mode == "UAT") {
$url = 'https://api-preprod.phonepe.com/apis/pg-sandbox/v1/oauth/token';
} else {
$url = 'https://api.phonepe.com/apis/identity-manager/v1/oauth/token';
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/x-www-form-urlencoded',
]);
$response = curl_exec($ch);
if (curl_errno($ch)) {
throw new \Exception('Curl error: ' . curl_error($ch));
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$responseData = json_decode($response, true);
if ($httpCode === 200 && isset($responseData['access_token'])) {
return $responseData['access_token'];
}
throw new \Exception('Failed to fetch PhonePe token. Response: ' . $response);
}
public function createOrder($token, $merchantOrderId, $amount) {
$url = $this->pgUrl . '/checkout/v2/sdk/order';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"merchantOrderId" => $merchantOrderId,
"amount" => $amount,
"paymentFlow" => [
"type" => "PG_CHECKOUT"
]
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: O-Bearer ' . $token,
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}