diff --git a/system/paymentgateway/BankStkPush.php b/system/paymentgateway/BankStkPush.php new file mode 100644 index 0000000..1c3347d --- /dev/null +++ b/system/paymentgateway/BankStkPush.php @@ -0,0 +1,205 @@ +assign('_title', 'Bank Stk Push - ' . $config['CompanyName']); + $ui->display('bankstkpush.tpl'); +} + +function BankStkPush_save_config() +{ + global $admin, $_L; + $bankacc = _post('account'); + $bankname = _post('bankname'); + $d = ORM::for_table('tbl_appconfig')->where('setting', 'Stkbankacc')->find_one(); + if ($d) { + $d->value = $bankacc; + $d->save(); + } else { + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'Stkbankacc'; + $d->value = $bankacc; + $d->save(); + } + $d = ORM::for_table('tbl_appconfig')->where('setting', 'Stkbankname')->find_one(); + if ($d) { + $d->value = $bankname; + $d->save(); + } else { + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'Stkbankname'; + $d->value = $bankname; + $d->save(); + } + + _log('[' . $admin['username'] . ']: Stk Bank details ' . $_L['Settings_Saved_Successfully'], 'Admin', $admin['id']); + + r2(U . 'paymentgateway/BankStkPush', 's', $_L['Settings_Saved_Successfully']); +} + + +function BankStkPush_create_transaction($trx, $user ) +{ + $url=(U. "plugin/initiatebankstk"); + + $d = ORM::for_table('tbl_payment_gateway') + ->where('username', $user['username']) + ->where('status', 1) + ->find_one(); + $d->gateway_trx_id = ''; + $d->payment_method = 'Bank Stk Push'; + $d->pg_url_payment = $url; + $d->pg_request = ''; + $d->expired_date = date('Y-m-d H:i:s', strtotime("+5 minutes")); + $d->save(); + + r2(U . "order/view/" . $d['id'], 's', Lang::T("Create Transaction Success, Please click pay now to process payment")); + + die(); +} + +function BankStkPush_payment_notification() +{ + $captureLogs = file_get_contents("php://input"); + + $analizzare = json_decode($captureLogs); + /// sleep(10); + file_put_contents('back.log',$captureLogs,FILE_APPEND); + $response_code = $analizzare->Body->stkCallback->ResultCode; + $resultDesc = ($analizzare->Body->stkCallback->ResultDesc); + $merchant_req_id = ($analizzare->Body->stkCallback->MerchantRequestID); + $checkout_req_id = ($analizzare->Body->stkCallback->CheckoutRequestID); + + $amount_paid = ($analizzare->Body->stkCallback->CallbackMetadata->Item['0']->Value);//get the amount value + $mpesa_code = ($analizzare->Body->stkCallback->CallbackMetadata->Item['1']->Value);//mpesa transaction code.. + $sender_phone = ($analizzare->Body->stkCallback->CallbackMetadata->Item['4']->Value);//Telephone Number + + $PaymentGatewayRecord = ORM::for_table('tbl_payment_gateway') + ->where('checkout', $checkout_req_id) + ->where('status', 1) // Add this line to filter by status + ->order_by_desc('id') + ->find_one(); + + $uname=$PaymentGatewayRecord->username; + $plan_id=$PaymentGatewayRecord->plan_id; + $mac_address=$PaymentGatewayRecord->mac_address; + $user=$PaymentGatewayRecord; + + $userid = ORM::for_table('tbl_customers') + ->where('username', $uname) + ->order_by_desc('id') + ->find_one(); + + $userid->username=$uname; + $userid->save(); + $plans = ORM::for_table('tbl_plans') + ->where('id', $plan_id) + + ->order_by_desc('id') + ->find_one(); + + if ($response_code=="1032") + { + $now = date('Y-m-d H:i:s'); + $PaymentGatewayRecord->paid_date = $now; + $PaymentGatewayRecord->status = 4; + $PaymentGatewayRecord->save(); + + exit(); + } + if($response_code=="1037"){ + $PaymentGatewayRecord->status = 1; + $PaymentGatewayRecord->pg_paid_response = 'User failed to enter pin'; + $PaymentGatewayRecord->save(); + + exit(); + } + + if($response_code=="1"){ + $PaymentGatewayRecord->status = 1; + $PaymentGatewayRecord->pg_paid_response = 'Not enough balance'; + $PaymentGatewayRecord->save(); + + exit(); + } + + if($response_code=="2001"){ + $PaymentGatewayRecord->status = 1; + $PaymentGatewayRecord->pg_paid_response = 'Wrong Mpesa pin'; + $PaymentGatewayRecord->save(); + + exit(); + } + + if($response_code=="0"){ + + $now = date('Y-m-d H:i:s'); + $date = date('Y-m-d'); + $time= date('H:i:s'); + + $check_mpesa = ORM::for_table('tbl_payment_gateway') + ->where('gateway_trx_id', $mpesa_code) + ->find_one(); + + if($check_mpesa){ + echo "double callback, ignore one"; + + die; + } + + $plan_type=$plans->type; + $UserId=$userid->id; + + if (!Package::rechargeUser($UserId, $user['routers'], $user['plan_id'], $user['gateway'], $mpesa_code)){ + $PaymentGatewayRecord->status = 2; + $PaymentGatewayRecord->paid_date = $now; + $PaymentGatewayRecord->gateway_trx_id = $mpesa_code; + $PaymentGatewayRecord->save(); + $username = $PaymentGatewayRecord->username; + + // Check if a transaction with the same gateway_trx_id already exists + $existingTransaction = ORM::for_table('tbl_transactions') + ->where('mpesacode', $mpesa_code) + ->find_one(); + + if (!$existingTransaction) { + // Save transaction data to tbl_transactions + $transaction = ORM::for_table('tbl_transactions')->create(); + $transaction->invoice = $PaymentGatewayRecord->gateway_trx_id; // Set invoice to gateway_trx_id value + $transaction->username = $PaymentGatewayRecord->username; + $transaction->plan_name = $PaymentGatewayRecord->plan_name; + $transaction->price = $amount_paid; + $transaction->recharged_on = $date; + $transaction->recharged_time = $time; + $transaction->expiration = $now; + $transaction->time = $now; + $transaction->method = $PaymentGatewayRecord->payment_method; + $transaction->routers = 0; + $transaction->Type = 'Balance'; + $transaction->mpesacode = $mpesa_code; + $transaction->save(); + } else { + error_log("Duplicate transaction entry detected for gateway_trx_id: " . $PaymentGatewayRecord->gateway_trx_id); + } + } else { + // Update tbl_recharges + $PaymentGatewayRecord->status = 2; + $PaymentGatewayRecord->paid_date = $now; + $PaymentGatewayRecord->gateway_trx_id = $mpesa_code; + $PaymentGatewayRecord->save(); + } + + + } +} diff --git a/system/paymentgateway/flutterwave.php b/system/paymentgateway/flutterwave.php new file mode 100644 index 0000000..7754b49 --- /dev/null +++ b/system/paymentgateway/flutterwave.php @@ -0,0 +1,234 @@ +assign('_title', 'Flutterwave - Payment Gateway'); + $ui->assign('cur', json_decode(file_get_contents('system/paymentgateway/flutterwave_currency.json'), true)); + $ui->assign('channel', json_decode(file_get_contents('system/paymentgateway/flutterwave_channel.json'), true)); + $ui->display('flutterwave.tpl'); + } + + + function flutterwave_save_config() + { + global $admin, $_L; + $flutterwave_secret_key = _post('flutterwave_secret_key'); + $flutterwave_currency = _post('flutterwave_currency'); + $d = ORM::for_table('tbl_appconfig')->where('setting', 'flutterwave_secret_key')->find_one(); + if ($d) { + $d->value = $flutterwave_secret_key; + $d->save(); + } else { + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'flutterwave_secret_key'; + $d->value = $flutterwave_secret_key; + $d->save(); + } + $d = ORM::for_table('tbl_appconfig')->where('setting', 'flutterwave_currency')->find_one(); + if ($d) { + $d->value = $flutterwave_currency; + $d->save(); + } else { + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'flutterwave_currency'; + $d->value = $flutterwave_currency; + $d->save(); + } + $d = ORM::for_table('tbl_appconfig')->where('setting', 'flutterwave_channel')->find_one(); + if ($d) { + $d->value = implode(',', $_POST['flutterwave_channel']); + $d->save(); + } else { + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'flutterwave_channel'; + $d->value = implode(',', $_POST['flutterwave_channel']); + $d->save(); + } + _log('[' . $admin['username'] . ']: Flutterwave ' . $_L['Settings_Saved_Successfully'], 'Admin', $admin['id']); + + r2(U . 'paymentgateway/flutterwave', 's', $_L['Settings_Saved_Successfully']); + } + +function flutterwave_create_transaction($trx, $user) +{ + global $config; + $txref = uniqid('trx'); + $json = [ + 'tx_ref' => $txref, + 'amount' => $trx['price'], + 'currency' => $config['flutterwave_currency'], + 'payment_options' => explode(',', $config['flutterwave_channel']), + 'customer' => [ + 'email' => (empty($user['email'])) ? $user['username'] . '@' . $_SERVER['HTTP_HOST'] : $user['email'], + 'name' => $user['fullname'], + 'phonenumber' => $user['phonenumber'] + ], + 'meta' => [ + 'price' => $trx['price'], + 'username' => $user['username'], + 'trxid' => $trx['id'] + ], + + 'customizations' => [ + 'title' => $trx['plan_name'], + 'description' => $trx['plan_name'], + ], + + 'redirect_url' => U . 'callback/flutterwave' + ]; + // die(json_encode($json,JSON_PRETTY_PRINT)); + + $result = json_decode(Http::postJsonData(flutterwave_get_server() . 'payments', $json,[ + 'Authorization: Bearer ' . $config['flutterwave_secret_key'], + 'Cache-Control: no-cahe' + ], + ), +true); + +//die(json_encode($result,JSON_PRETTY_PRINT)); + +if ($result['status'] == 'error') { + Message::sendTelegram("Flutterwave payment failed\n\n" . json_encode($result, JSON_PRETTY_PRINT)); + r2(U . 'order/package', 'e', Lang::T("Failed to create transaction.\n".$result['message'])); + } + $d = ORM::for_table('tbl_payment_gateway') + ->where('username', $user['username']) + ->where('status', 1) + ->find_one(); + $d->gateway_trx_id = $txref; + $d->pg_url_payment = $result['data']['link']; + $d->pg_request = json_encode($result); + $d->expired_date = date('Y-m-d H:i:s', strtotime("+ 6 HOUR")); + $d->save(); + + header('Location: ' . $result['data']['link']); + exit(); + + r2(U . "order/view/" . $d['id'], 's', Lang::T("Create Transaction Success")); + + +} + +function flutterwave_payment_notification() +{ + global $config; +if(isset($_GET['status'])) + + { + //* check payment status + if($_GET['status'] == 'cancelled') + { + // die(json_encode($txref,JSON_PRETTY_PRINT)); + Message::sendTelegram("Flutterwave Payment Cancelled: \n\n"); + r2(U . 'order/package', 'e', Lang::T("Flutterwave Payment Cancelled.")); + } + elseif($_GET['status'] == 'successful') + { + + $txid = $_GET['transaction_id']; + $result = json_decode(Http::getData(flutterwave_get_server() . 'transactions/' . $txid. '/verify', [ + 'Authorization: Bearer ' . $config['flutterwave_secret_key'], + 'Cache-Control: no-cahe' + ]), true); + //die(json_encode($result,JSON_PRETTY_PRINT)); + { + $id = $result['data']['id']; + $amountPaid = $result['data']['charged_amount']; + $amountToPay = $result['data']['meta']['price']; + $username = $result['data']['meta']['username']; + $trxid = $result['data']['meta']['trxid']; + if($amountPaid >= $amountToPay) + { + // die(json_encode($trxid,JSON_PRETTY_PRINT)); + // echo 'Payment successful'; + $d = ORM::for_table('tbl_payment_gateway') + ->where('username', $username) + ->where('status', 1) + ->find_one(); + $d->gateway_trx_id = $id; + $d->save(); + r2(U . 'order/view/'.$trxid.'/check'); + // r2(U . 'order/package', 's', Lang::T("Flutterwave Payment Completed.")); + exit(); + //* Continue to give item to the user + } + else + { + // echo 'Fraud transactio detected'; + r2(U . 'order/package', 'e', Lang::T("Fraud transactions detected.")); + exit(); + } + } + } + } + } + + + function flutterwave_get_status($trx, $user) + { + global $config; + $trans_id = $trx['gateway_trx_id']; + $result = json_decode(Http::getData(flutterwave_get_server() . 'transactions/' . $trx['gateway_trx_id']. '/verify', [ + 'Authorization: Bearer ' . $config['flutterwave_secret_key'], + 'Cache-Control: no-cahe' + ]), true); + //die(json_encode($result,JSON_PRETTY_PRINT)); + if ($result['status'] == 'error') { + r2(U . "order/view/" . $trx['id'], 'w', Lang::T("Transaction still unpaid.")); + } else if (in_array($result['status'], ['success']) && $trx['status'] != 2) { + if (!Package::rechargeUser($user['id'], $trx['routers'], $trx['plan_id'], $trx['gateway'], 'Flutterwave')) { + r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Failed to activate your Package, please try again later.")); + } + $trx->pg_paid_response = json_encode($result); + $trx->payment_method = 'Flutterwave'; + $trx->payment_channel = $result['data']['payment_type']; + $trx->paid_date = date('Y-m-d H:i:s', strtotime( $result['data']['created_at'])); + $trx->status = 2; + $trx->save(); + + r2(U . "order/view/" . $trx['id'], 's', Lang::T("Transaction successful.")); + } else if ($result['status'] == 'EXPIRED') { + $trx->pg_paid_response = json_encode($result); + $trx->status = 3; + $trx->save(); + r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Transaction expired.")); + } else if ($trx['status'] == 2) { + r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Transaction has been paid..")); + }else{ + Message::sendTelegram("flutterwave_get_status: unknown result\n\n".json_encode($result, JSON_PRETTY_PRINT)); + r2(U . "order/view/" . $trx['id'], 'd', Lang::T("Unknown Command.")); + } + + } + + +function flutterwave_get_server() +{ + global $_app_stage; + if ($_app_stage == 'Live') { + return 'https://api.flutterwave.com/v3/'; + } else { + return 'https://api.flutterwave.com/v3/'; + } +} diff --git a/system/paymentgateway/flutterwave_channel.json b/system/paymentgateway/flutterwave_channel.json new file mode 100644 index 0000000..09e38c1 --- /dev/null +++ b/system/paymentgateway/flutterwave_channel.json @@ -0,0 +1,35 @@ +[ + + { + "id": "card", + "name": "Card Payment" + }, + { + "id": "ussd", + "name": "USSD" + }, + { + "id": "account", + "name": "Bank Account" + }, + { + "id": "banktransfer", + "name": "Bank Transfer" + }, + { + "id": "nqr", + "name": "QR payment" + }, + { + "id": "mpesa", + "name": "M-Pesa" + }, + { + "id": "mobilemoneyghana", + "name": "Mobile money Ghana" + }, + { + "id": "credit", + "name": "Credit payment" + } +] diff --git a/system/paymentgateway/flutterwave_currency.json b/system/paymentgateway/flutterwave_currency.json new file mode 100644 index 0000000..fe716ea --- /dev/null +++ b/system/paymentgateway/flutterwave_currency.json @@ -0,0 +1,30 @@ +[ + { + "id": "NGN", + "name": "Nigerian Naira" + }, + { + "id": "GHC", + "name": "Ghana Cedis" + }, + { + "id": "KES", + "name": "Kenyan Shilling" + }, + { + "id": "ZAR", + "name": "South African Rand" + }, + { + "id": "GBP", + "name": "British Pound Sterling" + }, + { + "id": "USD", + "name": "United States Dollar" + }, + { + "id": "TZS", + "name": "Tanzanian Shilling" + } +] diff --git a/system/paymentgateway/paypal.php b/system/paymentgateway/paypal.php new file mode 100644 index 0000000..4ab66af --- /dev/null +++ b/system/paymentgateway/paypal.php @@ -0,0 +1,210 @@ + + * + **/ + + +function paypal_validate_config() +{ + global $config; + if (empty($config['paypal_client_id']) || empty($config['paypal_secret_key'])) { + sendTelegram("PayPal payment gateway not configured"); + r2(U . 'order/package', 'w', "Admin has not yet setup Paypal payment gateway, please tell admin"); + } +} + +function paypal_show_config() +{ + global $ui; + $ui->assign('_title', 'Paypal - Payment Gateway'); + $ui->assign('currency', json_decode(file_get_contents('system/paymentgateway/paypal_currency.json'), true)); + $ui->display('paypal.tpl'); +} + + +function paypal_save_config() +{ + global $admin, $_L; + $paypal_client_id = _post('paypal_client_id'); + $paypal_secret_key = _post('paypal_secret_key'); + $paypal_currency = _post('paypal_currency'); + $d = ORM::for_table('tbl_appconfig')->where('setting', 'paypal_secret_key')->find_one(); + if ($d) { + $d->value = $paypal_secret_key; + $d->save(); + } else { + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'paypal_secret_key'; + $d->value = $paypal_secret_key; + $d->save(); + } + $d = ORM::for_table('tbl_appconfig')->where('setting', 'paypal_client_id')->find_one(); + if ($d) { + $d->value = $paypal_client_id; + $d->save(); + } else { + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'paypal_client_id'; + $d->value = $paypal_client_id; + $d->save(); + } + $d = ORM::for_table('tbl_appconfig')->where('setting', 'paypal_currency')->find_one(); + if ($d) { + $d->value = $paypal_currency; + $d->save(); + } else { + $d = ORM::for_table('tbl_appconfig')->create(); + $d->setting = 'paypal_currency'; + $d->value = $paypal_currency; + $d->save(); + } + _log('[' . $admin['username'] . ']: Paypal ' . Lang::T('Settings_Saved_Successfully'), 'Admin', $admin['id']); + + r2(U . 'paymentgateway/paypal', 's', Lang::T('Settings_Saved_Successfully')); +} + +function paypal_create_transaction($trx, $user) +{ + global $config; + $json = [ + 'intent' => 'CAPTURE', + 'purchase_units' => [ + [ + 'amount' => [ + 'currency_code' => $config['paypal_currency'], + 'value' => strval($trx['price']) + ] + ] + ], + "application_context" => [ + "return_url" => U . "order/view/" . $trx['id'] . '/check', + "cancel_url" => U . "order/view/" . $trx['id'], + ] + ]; + + $result = json_decode( + Http::postJsonData( + paypal_get_server() . 'checkout/orders', + $json, + [ + 'Prefer: return=minimal', + 'PayPal-Request-Id: paypal_' . $trx['id'], + 'Authorization: Bearer ' . paypalGetAccessToken() + ] + ), + true + ); + if (!$result['id']) { + sendTelegram("paypal_create_transaction FAILED: \n\n" . json_encode($result, JSON_PRETTY_PRINT)); + r2(U . 'order/package', 'e', "Failed to create Paypal transaction."); + } + $urlPayment = ""; + foreach ($result['links'] as $link) { + if ($link['rel'] == 'approve') { + $urlPayment = $link['href']; + break; + } + } + $d = ORM::for_table('tbl_payment_gateway') + ->where('username', $user['username']) + ->where('status', 1) + ->find_one(); + $d->gateway_trx_id = $result['id']; + $d->pg_url_payment = $urlPayment; + $d->pg_request = json_encode($result); + $d->expired_date = date('Y-m-d H:i:s', strtotime("+ 6 HOUR")); + $d->save(); + header('Location: ' . $urlPayment); + exit(); +} + +/* +*/ + +function paypal_payment_notification() +{ + // Not yet implemented + die('OK'); +} + +function paypal_get_status($trx, $user) +{ + $capture = []; + if (empty($trx->pg_paid_response)) { + $capture = paypal_capture_transaction($trx['gateway_trx_id']); + } else { + $capture = json_decode($trx->pg_paid_response, true)['paypal_capture']; + if (empty($capture)) { + $capture = paypal_capture_transaction($trx['gateway_trx_id']); + } + } + $result = json_decode(Http::getData(paypal_get_server() . 'checkout/orders/' . $trx['gateway_trx_id'], ['Authorization: Bearer ' . paypalGetAccessToken()]), true); + if (in_array($result['status'], ['APPROVED', 'COMPLETED']) && $trx['status'] != 2) { + if ($capture['status'] == 'COMPLETED' || ($capture['name'] == 'UNPROCESSABLE_ENTITY' && $capture['details'][0]['issue'] == 'ORDER_ALREADY_CAPTURED')) { + if (!Package::rechargeUser($user['id'], $trx['routers'], $trx['plan_id'], $trx['gateway'], 'Paypal')) { + r2(U . "order/view/" . $trx['id'], 'd', "Failed to activate your Package, try again later."); + } + $result['paypal_capture'] = json_encode($capture); + $trx->pg_paid_response = json_encode($result); + $trx->payment_method = 'PAYPAL'; + $trx->payment_channel = 'paypal'; + $trx->paid_date = date('Y-m-d H:i:s', strtotime($result['updated'])); + $trx->status = 2; + $trx->save(); + r2(U . "order/view/" . $trx['id'], 's', "Transaction has been paid."); + } else { + r2(U . "order/view/" . $trx['id'], 'e', "Transaction Success, but not yet captured."); + } + } else if ($result['status'] == 'VOIDED') { + $trx->pg_paid_response = json_encode($result); + $trx->status = 3; + $trx->save(); + r2(U . "order/view/" . $trx['id'], 'd', "Transaction expired."); + } else { + sendTelegram("xendit_get_status: unknown result\n\n" . json_encode($result, JSON_PRETTY_PRINT)); + r2(U . "order/view/" . $trx['id'], 'w', "Transaction status :" . $result['status']); + } +} + +function paypal_capture_transaction($trx_id) +{ + return json_decode( + Http::postJsonData( + paypal_get_server() . 'checkout/orders/' . $trx_id . '/capture', + [], + [ + 'PayPal-Partner-Attribution-Id: <BN-Code>', + 'Authorization: Bearer ' . paypalGetAccessToken() + ] + ), + true + ); +} + +function paypalGetAccessToken() +{ + global $config; + $result = Http::postData(str_replace('v2', 'v1', paypal_get_server()) . 'oauth2/token', [ + "grant_type" => "client_credentials" + ], [], $config['paypal_client_id'] . ":" . $config['paypal_secret_key']); + $json = json_decode($result, true); + return $json['access_token']; +} + + +function paypal_get_server() +{ + global $_app_stage; + if ($_app_stage == 'Live') { + return 'https://api-m.paypal.com/v2/'; + } else { + return 'https://api-m.sandbox.paypal.com/v2/'; + } +}