You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
444 lines
20 KiB
444 lines
20 KiB
<?php
|
|
|
|
/**
|
|
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
|
*
|
|
* Payment Gateway PipraPay
|
|
* Fixed Version - Auto Verification & Router Data
|
|
**/
|
|
|
|
// PipraPay Configuration
|
|
$piprapay_config = [
|
|
'api_key' => '186691761268d6f85579c84532234998155044887968d6f85579c891167595247',
|
|
'base_url' => 'https://pay.wifibills.com/api',
|
|
'gateway_name' => 'PipraPay'
|
|
];
|
|
|
|
// Status mapping: 1 = Unpaid, 2 = Paid, 3 = Failed, 4 = Cancelled
|
|
define('PIPRAPAY_STATUS_UNPAID', 1);
|
|
define('PIPRAPAY_STATUS_PAID', 2);
|
|
define('PIPRAPAY_STATUS_FAILED', 3);
|
|
define('PIPRAPAY_STATUS_CANCELLED', 4);
|
|
|
|
function piprapay_validate_config()
|
|
{
|
|
global $piprapay_config;
|
|
}
|
|
|
|
function piprapay_show_config()
|
|
{
|
|
global $ui, $piprapay_config;
|
|
|
|
$ui->assign('_title', $piprapay_config['gateway_name'] . ' - Payment Gateway');
|
|
|
|
echo '
|
|
<div class="row">
|
|
<div class="col-sm-12 col-md-12">
|
|
<div class="panel panel-primary panel-hovered panel-stacked mb30">
|
|
<div class="panel-heading">' . $piprapay_config['gateway_name'] . ' Configuration</div>
|
|
<div class="panel-body">
|
|
<div class="alert alert-info">
|
|
<h4><i class="fa fa-info-circle"></i> ' . $piprapay_config['gateway_name'] . ' Gateway</h4>
|
|
<p>This payment gateway is pre-configured and ready to use.</p>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="col-md-3 control-label">API Key</label>
|
|
<div class="col-md-9">
|
|
<input type="text" class="form-control" readonly value="' . $piprapay_config['api_key'] . '">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="col-md-3 control-label">Base URL</label>
|
|
<div class="col-md-9">
|
|
<input type="text" class="form-control" readonly value="' . $piprapay_config['base_url'] . '">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="col-md-3 control-label">Callback URL</label>
|
|
<div class="col-md-9">
|
|
<input type="text" class="form-control" readonly value="' . U . 'callback/piprapay">
|
|
<span class="help-block">PipraPay will redirect users to this URL after payment</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alert alert-success">
|
|
<strong><i class="fa fa-check-circle"></i> Gateway Active</strong><br>
|
|
' . $piprapay_config['gateway_name'] . ' is ready to accept payments.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>';
|
|
}
|
|
|
|
function piprapay_save_config()
|
|
{
|
|
global $admin;
|
|
_log('[' . $admin['username'] . ']: ' . Lang::T('PipraPay_Configuration_Viewed'), 'Admin', $admin['id']);
|
|
r2(U . 'paymentgateway/piprapay', 's', Lang::T('PipraPay_is_preconfigured'));
|
|
}
|
|
|
|
function piprapay_create_transaction($trx, $user)
|
|
{
|
|
global $piprapay_config;
|
|
|
|
try {
|
|
// Use direct URL format
|
|
$success_url = APP_URL . '/?_route=callback/piprapay&invoice_id=' . $trx['id'];
|
|
$cancel_url = U . 'order/view/' . $trx['id'];
|
|
|
|
// Create metadata
|
|
$metadata = [
|
|
'invoice_id' => $trx['id'],
|
|
'customer_id' => $user['id'],
|
|
'customer_name' => $user['fullname'] ?: $user['username'],
|
|
'plan_id' => $trx['plan_id']
|
|
];
|
|
|
|
// Payload with required fields
|
|
$payload = [
|
|
'full_name' => $user['fullname'] ?: $user['username'],
|
|
'email_mobile' => $user['email'] ?: ($user['phonenumber'] ?: 'user@example.com'),
|
|
'amount' => number_format($trx['price'], 2, '.', ''),
|
|
'redirect_url' => $success_url,
|
|
'return_type' => 'GET',
|
|
'cancel_url' => $cancel_url,
|
|
'webhook_url' => U . 'callback/piprapay',
|
|
'currency' => 'BDT',
|
|
'metadata' => $metadata
|
|
];
|
|
|
|
$headers = [
|
|
'accept: application/json',
|
|
'content-type: application/json',
|
|
'mh-piprapay-api-key: ' . $piprapay_config['api_key']
|
|
];
|
|
|
|
$create_charge_url = $piprapay_config['base_url'] . '/create-charge';
|
|
|
|
_log("PipraPay Create Transaction Request - Invoice: " . $trx['id'], 'PipraPay');
|
|
|
|
// Make the API call
|
|
$response = Http::postJsonData($create_charge_url, $payload, $headers);
|
|
$result = json_decode($response, true);
|
|
|
|
_log("PipraPay Create Transaction Response: " . $response, 'PipraPay');
|
|
|
|
// Check for success
|
|
if (isset($result['status']) && $result['status'] === true) {
|
|
if (isset($result['pp_url'])) {
|
|
$pp_id = $result['pp_id']; // PipraPay's payment ID
|
|
|
|
// FIXED: Get router information properly like bKash plugin
|
|
$router = ORM::for_table('tbl_routers')->find_one($trx['routers']);
|
|
$router_name = $router ? $router['name'] : 'Unknown';
|
|
$router_id = $router ? $router['id'] : $trx['routers'];
|
|
|
|
// Get plan information for expiry date
|
|
$plan = ORM::for_table('tbl_plans')->find_one($trx['plan_id']);
|
|
$expired_date = date('Y-m-d H:i:s');
|
|
if ($plan && !empty($plan['validity'])) {
|
|
$expired_date = date('Y-m-d H:i:s', strtotime('+' . $plan['validity'] . ' days'));
|
|
} else {
|
|
// Fallback to +1 day if plan validity not found
|
|
$expired_date = date('Y-m-d H:i:s', strtotime('+1 day'));
|
|
}
|
|
|
|
// Create payment gateway record
|
|
$d = ORM::for_table('tbl_payment_gateway')->create();
|
|
$d->username = $user['username'];
|
|
$d->user_id = $user['id'];
|
|
$d->gateway = 'piprapay';
|
|
$d->gateway_trx_id = $pp_id;
|
|
$d->plan_id = $trx['plan_id'];
|
|
$d->plan_name = $trx['plan_name'];
|
|
|
|
// FIXED: Set router data properly - no more null values
|
|
$d->routers_id = $router_id;
|
|
$d->routers = $router_name;
|
|
|
|
$d->price = $trx['price'];
|
|
$d->pg_url_payment = $result['pp_url'];
|
|
$d->pg_request = json_encode($result);
|
|
|
|
// FIXED: Set expired_date from plan validity instead of +1 day
|
|
$d->expired_date = $expired_date;
|
|
|
|
$d->trx_invoice = $trx['id'];
|
|
$d->status = PIPRAPAY_STATUS_UNPAID; // 1 = Unpaid
|
|
$d->created_date = date('Y-m-d H:i:s');
|
|
$d->payment_method = '';
|
|
$d->payment_channel = '';
|
|
$d->save();
|
|
|
|
// Update the main transaction with gateway_trx_id
|
|
$trx->gateway_trx_id = $pp_id;
|
|
$trx->save();
|
|
|
|
_log("PipraPay - Payment record created. Transaction: " . $trx['id'] . ", PP ID: " . $pp_id . ", Router ID: " . $router_id . ", Router Name: " . $router_name, 'PipraPay');
|
|
|
|
// Redirect to payment gateway
|
|
header('Location: ' . $result['pp_url']);
|
|
exit();
|
|
} else {
|
|
$error_message = 'Payment URL not received from gateway';
|
|
_log("PipraPay Error: " . $error_message, 'PipraPay');
|
|
r2(U . 'order/package', 'e', Lang::T("Failed to create transaction. ") . $error_message);
|
|
}
|
|
} else {
|
|
$error_message = $result['message'] ?? 'Failed to create payment';
|
|
_log("PipraPay API Error: " . $error_message, 'PipraPay');
|
|
r2(U . 'order/package', 'e', Lang::T("Failed to create transaction. ") . $error_message);
|
|
}
|
|
} catch (Exception $e) {
|
|
_log("PipraPay Exception: " . $e->getMessage(), 'PipraPay');
|
|
r2(U . 'order/package', 'e', Lang::T("System error occurred. Please try again."));
|
|
}
|
|
}
|
|
|
|
function piprapay_get_status($trx, $user)
|
|
{
|
|
global $piprapay_config;
|
|
|
|
try {
|
|
// Use gateway_trx_id (pp_id) for verification
|
|
if (empty($trx['gateway_trx_id'])) {
|
|
_log("PipraPay Verification - No gateway_trx_id found for transaction: " . $trx['id'], 'PipraPay');
|
|
r2(U . "order/view/" . $trx['id'], 'e', Lang::T("Payment verification failed."));
|
|
}
|
|
|
|
$pp_id = $trx['gateway_trx_id'];
|
|
|
|
_log("PipraPay Verification - Transaction: " . $trx['id'] . ", PP ID: " . $pp_id, 'PipraPay');
|
|
|
|
// Verify using the gateway transaction ID
|
|
$verify_url = $piprapay_config['base_url'] . '/verify-payments';
|
|
$payload = ['pp_id' => $pp_id];
|
|
|
|
$headers = [
|
|
'accept: application/json',
|
|
'content-type: application/json',
|
|
'mh-piprapay-api-key: ' . $piprapay_config['api_key']
|
|
];
|
|
|
|
_log("PipraPay Verification Request - PP ID: " . $pp_id, 'PipraPay');
|
|
|
|
$response = Http::postJsonData($verify_url, $payload, $headers);
|
|
$result = json_decode($response, true);
|
|
|
|
_log("PipraPay Verification Response: " . $response, 'PipraPay');
|
|
|
|
if (!$result || !is_array($result)) {
|
|
_log("PipraPay Verification - Invalid response format", 'PipraPay');
|
|
r2(U . "order/view/" . $trx['id'], 'e', Lang::T("Invalid response from payment gateway."));
|
|
}
|
|
|
|
// Check if transaction is already paid using numeric status
|
|
if ($trx['status'] == PIPRAPAY_STATUS_PAID || $trx['status'] == 2) {
|
|
_log("PipraPay Verification - Transaction already paid", 'PipraPay');
|
|
r2(U . "order/view/" . $trx['id'], 's', Lang::T("Transaction has been paid."));
|
|
}
|
|
|
|
_log("PipraPay Verification Parsed Result: " . json_encode($result), 'PipraPay');
|
|
|
|
// Check the actual response structure from PipraPay
|
|
if (isset($result['status'])) {
|
|
$payment_status = strtolower(trim($result['status']));
|
|
$is_paid = ($payment_status === 'completed');
|
|
|
|
_log("PipraPay Payment Analysis - Status: " . $payment_status . ", Is Paid: " . ($is_paid ? 'Yes' : 'No'), 'PipraPay');
|
|
|
|
if ($is_paid) {
|
|
_log("PipraPay Payment Successful - Activating package", 'PipraPay');
|
|
|
|
// Update payment gateway record
|
|
$pg_trx = ORM::for_table('tbl_payment_gateway')
|
|
->where('gateway_trx_id', $pp_id)
|
|
->find_one();
|
|
|
|
if ($pg_trx) {
|
|
$pg_trx->pg_paid_response = json_encode($result);
|
|
$pg_trx->payment_method = $result['payment_method'] ?? $piprapay_config['gateway_name'];
|
|
$pg_trx->payment_channel = $result['payment_method'] ?? $piprapay_config['gateway_name'];
|
|
$pg_trx->paid_date = date('Y-m-d H:i:s');
|
|
$pg_trx->status = PIPRAPAY_STATUS_PAID; // 2 = Paid
|
|
$pg_trx->save();
|
|
_log("PipraPay - Updated payment gateway record: " . $pg_trx['id'], 'PipraPay');
|
|
}
|
|
|
|
// FIXED: Activate user package with proper parameters like bKash
|
|
if (!Package::rechargeUser($user['id'], $trx['routers'], $trx['plan_id'], 'piprapay', $piprapay_config['gateway_name'])) {
|
|
_log("PipraPay - Failed to activate package for user: " . $user['id'], 'PipraPay');
|
|
r2(U . "order/view/" . $trx['id'], 'e', Lang::T("Failed to activate your Package, try again later."));
|
|
}
|
|
|
|
// Update transaction
|
|
$trx->pg_paid_response = json_encode($result);
|
|
$trx->payment_method = $result['payment_method'] ?? $piprapay_config['gateway_name'];
|
|
$trx->payment_channel = $result['payment_method'] ?? $piprapay_config['gateway_name'];
|
|
$trx->paid_date = date('Y-m-d H:i:s');
|
|
$trx->status = PIPRAPAY_STATUS_PAID; // FIXED: Use numeric status value (2 = Paid)
|
|
$trx->save();
|
|
|
|
_log("PipraPay - Transaction marked as paid: " . $trx['id'], 'PipraPay');
|
|
r2(U . "order/view/" . $trx['id'], 's', Lang::T("Payment successful! Your package has been activated."));
|
|
} else {
|
|
_log("PipraPay Payment Not Successful - Status: " . $payment_status, 'PipraPay');
|
|
|
|
// Map payment status to numeric values
|
|
$numeric_status = PIPRAPAY_STATUS_UNPAID; // Default to unpaid
|
|
if ($payment_status === 'failed') {
|
|
$numeric_status = PIPRAPAY_STATUS_FAILED;
|
|
} elseif ($payment_status === 'cancelled') {
|
|
$numeric_status = PIPRAPAY_STATUS_CANCELLED;
|
|
}
|
|
|
|
// Update transaction status
|
|
$trx->status = $numeric_status;
|
|
$trx->save();
|
|
|
|
r2(U . "order/view/" . $trx['id'], 'w', Lang::T("Payment status: ") . $payment_status);
|
|
}
|
|
} else {
|
|
_log("PipraPay - No status field in response", 'PipraPay');
|
|
$error_message = $result['message'] ?? 'Payment verification failed';
|
|
_log("PipraPay API Error: " . $error_message, 'PipraPay');
|
|
r2(U . "order/view/" . $trx['id'], 'e', Lang::T("Payment failed: ") . $error_message);
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
_log("PipraPay Verification Exception: " . $e->getMessage(), 'PipraPay');
|
|
r2(U . "order/view/" . $trx['id'], 'e', Lang::T("System error during verification."));
|
|
}
|
|
}
|
|
|
|
// REQUIRED: This function is called by the callback router
|
|
function piprapay_payment_notification()
|
|
{
|
|
global $piprapay_config;
|
|
|
|
_log("=== PIPRAPAY PAYMENT NOTIFICATION CALLED ===", 'PipraPay');
|
|
_log("GET Parameters: " . json_encode($_GET), 'PipraPay');
|
|
_log("POST Parameters: " . json_encode($_POST), 'PipraPay');
|
|
_log("Request Method: " . $_SERVER['REQUEST_METHOD'], 'PipraPay');
|
|
|
|
// Call the main callback handler
|
|
piprapay_callback_handler();
|
|
}
|
|
|
|
// FIXED: Enhanced callback handler for auto-verification
|
|
function piprapay_callback_handler()
|
|
{
|
|
global $piprapay_config;
|
|
|
|
_log("PipraPay Callback Handler Started", 'PipraPay');
|
|
|
|
try {
|
|
// Handle GET requests (user redirects from PipraPay)
|
|
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|
_log("PipraPay - Processing GET Request (User Redirect)", 'PipraPay');
|
|
|
|
// FIXED: Auto-verify when user returns from payment
|
|
if (isset($_GET['invoice_id'])) {
|
|
$invoice_id = intval($_GET['invoice_id']);
|
|
|
|
_log("PipraPay Callback - Auto-verifying Invoice ID: " . $invoice_id, 'PipraPay');
|
|
|
|
// Find transaction by internal ID
|
|
$trx = ORM::for_table('tbl_transactions')->find_one($invoice_id);
|
|
if (!$trx) {
|
|
_log("PipraPay Callback - Transaction not found: " . $invoice_id, 'PipraPay');
|
|
r2(U . 'order/package', 'e', Lang::T("Transaction not found."));
|
|
}
|
|
|
|
// Find user
|
|
$user = ORM::for_table('tbl_customers')->find_one($trx['customer_id']);
|
|
if (!$user) {
|
|
_log("PipraPay Callback - User not found for transaction: " . $invoice_id, 'PipraPay');
|
|
r2(U . 'order/package', 'e', Lang::T("User not found."));
|
|
}
|
|
|
|
// FIXED: Auto-verify payment immediately when user returns
|
|
_log("PipraPay - Auto-verifying payment for transaction: " . $trx['id'], 'PipraPay');
|
|
piprapay_get_status($trx, $user);
|
|
}
|
|
|
|
// Handle cancelled payment
|
|
if (isset($_GET['status']) && $_GET['status'] == 'cancel') {
|
|
r2(U . 'order/package', 'w', Lang::T("Payment was cancelled. Please try again."));
|
|
}
|
|
|
|
// Default redirect
|
|
_log("PipraPay Callback - No invoice_id found", 'PipraPay');
|
|
r2(U . 'order/package');
|
|
}
|
|
|
|
// Handle POST requests (webhooks/auto-verify from system)
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
_log("PipraPay - Processing POST Request", 'PipraPay');
|
|
|
|
// Handle auto-verify requests from system
|
|
if (isset($_POST['action']) && $_POST['action'] === 'auto_verify') {
|
|
_log("PipraPay - System auto-verify request detected", 'PipraPay');
|
|
|
|
// Find the most recent unpaid transaction
|
|
$pg_trx = ORM::for_table('tbl_payment_gateway')
|
|
->where('status', PIPRAPAY_STATUS_UNPAID) // 1 = Unpaid
|
|
->where('gateway', 'piprapay')
|
|
->order_by_desc('id')
|
|
->find_one();
|
|
|
|
if ($pg_trx && !empty($pg_trx['trx_invoice'])) {
|
|
$trx = ORM::for_table('tbl_transactions')->find_one($pg_trx['trx_invoice']);
|
|
$user = ORM::for_table('tbl_customers')->find_one($pg_trx['user_id']);
|
|
|
|
if ($trx && $user) {
|
|
_log("PipraPay - System auto-verifying transaction: " . $trx['id'], 'PipraPay');
|
|
piprapay_get_status($trx, $user);
|
|
}
|
|
}
|
|
|
|
http_response_code(200);
|
|
echo json_encode(['status' => 'processed']);
|
|
exit;
|
|
}
|
|
|
|
// Handle PipraPay webhook notifications
|
|
if (isset($_POST['pp_id']) || isset($_POST['paymentID'])) {
|
|
$pp_id = $_POST['pp_id'] ?? $_POST['paymentID'] ?? '';
|
|
_log("PipraPay - Webhook notification for PP ID: " . $pp_id, 'PipraPay');
|
|
|
|
if (!empty($pp_id)) {
|
|
// Find transaction by gateway_trx_id
|
|
$trx = ORM::for_table('tbl_transactions')
|
|
->where('gateway_trx_id', $pp_id)
|
|
->find_one();
|
|
|
|
if ($trx) {
|
|
$user = ORM::for_table('tbl_customers')->find_one($trx['customer_id']);
|
|
if ($user) {
|
|
_log("PipraPay - Webhook auto-verifying transaction: " . $trx['id'], 'PipraPay');
|
|
piprapay_get_status($trx, $user);
|
|
}
|
|
}
|
|
}
|
|
|
|
http_response_code(200);
|
|
echo json_encode(['status' => 'received']);
|
|
exit;
|
|
}
|
|
|
|
// Default response for POST
|
|
http_response_code(200);
|
|
echo json_encode(['status' => 'received']);
|
|
exit;
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
_log("PipraPay Callback Exception: " . $e->getMessage(), 'PipraPay');
|
|
r2(U . 'order/package', 'e', Lang::T("System error occurred."));
|
|
}
|
|
}
|