/home/kueuepay/public_html/app/Http/Controllers/Api/V1/User/AddMoneyController.php
<?php

namespace App\Http\Controllers\Api\V1\User;

use Exception;
use App\Models\UserWallet;
use App\Models\Transaction;
use Illuminate\Http\Request;
use App\Models\TemporaryData;
use App\Http\Helpers\Response;
use App\Models\Admin\Currency;
use App\Models\UserNotification;
use Illuminate\Support\Facades\DB;
use App\Models\Admin\BasicSettings;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\RedirectResponse;
use App\Constants\PaymentGatewayConst;
use App\Traits\ControlDynamicInputFields;
use Illuminate\Support\Facades\Validator;
use App\Models\Admin\PaymentGatewayCurrency;
use Illuminate\Support\Facades\Notification;
use App\Traits\PaymentGateway\PaystackGateway;
use App\Notifications\User\AddMoneyNotification;
use App\Http\Helpers\PaymentGateway as PaymentGatewayHelper;

class AddMoneyController extends Controller
{
    use ControlDynamicInputFields, PaystackGateway;
    /**
     * Method for get the add money information
     * @return response
     */
    public function info(){
        $base_currency          = Currency::default();
        $currency_image_paths = [
            'base_url'          => url("/"),
            'path_location'     => files_asset_path_basename("currency-flag"),
            'default_image'     => files_asset_path_basename("currency-flag"),
        ];

        $user_wallet            = UserWallet::auth()->first();
        
        $payment_gateways            = PaymentGatewayCurrency::whereHas('gateway', function ($gateway) {
            $gateway->where('slug', PaymentGatewayConst::add_money_slug());
            $gateway->where('status', 1);
        })->get()->map(function($data){
            if($data->gateway->isManual()){
                $name = $data->name . '(' . ("Manual") .')';
            }else{
                $name = $data->name;
            }
            return [
                'name'              => $name,
                'alias'             => $data->alias,
                'code'              => $data->currency_code,
                'image'             => $data->gateway->image,
                'title'             => $data->gateway->title,
                'rate'              => get_amount($data->rate),
                'min_limit'         => get_amount($data->min_limit),
                'max_limit'         => get_amount($data->max_limit),
                'fixed_charge'      => get_amount($data->fixed_charge),
                'percent_charge'    => get_amount($data->percent_charge),
            ];
        });
        $image_paths = [
            'base_url'          => url("/"),
            'path_location'     => files_asset_path_basename("payment-gateways"),
            'default_image'     => files_asset_path_basename("payment-gateways"),
        ];

        $transactions               = Transaction::auth()->where('type',PaymentGatewayConst::TYPEADDMONEY)->get()->map(function($data){
            
            return [
                'type'              => $data->type,
                'trx_id'            => $data->trx_id,
                'payment_gateway'   => $data->payment_gateway->name,
                'request_amount'    => get_amount($data->request_amount),
                'fixed_charge'      => get_amount($data->fixed_charge),
                'percent_charge'    => get_amount($data->percent_charge),
                'total_charge'      => get_amount($data->total_charge),
                'total_payable'     => get_amount($data->total_payable),
                'request_currency'  => $data->request_currency,
                'payment_currency'  => $data->payment_currency,
                'remark'            => $data->remark,
                'attribute'         => $data->attribute,
                'status'            => $data->stringStatus->value,
            ];
            
        });
        
        return Response::success(['Transfer money fetch successfully.'],[
            'base_currency'          => $base_currency->code,
            'flag'                  => $base_currency->flag,
            'currency_image_paths'  => $currency_image_paths,
            'rate'                   => get_amount($base_currency->rate),
            'wallet'                 => [
                'code'               => $user_wallet->currency->code,
                'balance'            => get_amount($user_wallet->balance)
            ],
            'payment_gateways'       => $payment_gateways,
            'image_paths'            => $image_paths,
            'transactions'           => $transactions
        ],200);
    }
    /**
     * Method for confirm add money
     * @param Illuminate\Http\Request $request
     */
    public function confirm(Request $request){
        $validator              = Validator::make($request->all(),[
            'amount'            => 'required|numeric',
            'payment_gateway'   => 'required|string',
        ]);
        if($validator->fails()) return back()->withErrors($validator)->withInput($request->all());
        $validated              = $validator->validated();
        $request->merge(['currency' => $validated['payment_gateway']]);
        try{
            $instance = PaymentGatewayHelper::init($request->all())->type(PaymentGatewayConst::TYPEADDMONEY)->gateway()->api()->render();
            
            if($instance instanceof RedirectResponse === false && isset($instance['gateway_type']) && $instance['gateway_type'] == PaymentGatewayConst::MANUAL) {
                $data = $this->manualFields($request->all(),$instance);
                
                return Response::success([__('Request response fetch successfully!')],$data,200);
            }
        }catch(Exception $e) {
            return Response::error($e->getMessage(),[],400);
        }
        return Response::success([__('Payment gateway response successful')],[
            'redirect_url'          => $instance['redirect_url'],
            'redirect_links'        => $instance['redirect_links'],
            'action_type'           => $instance['type'] ?? false, 
            'address_info'          => $instance['address_info'] ?? [],
        ],200);
    }
    /**
     * Method for add money success method
     */
    public function success(Request $request, $gateway){
        try{
            $token = PaymentGatewayHelper::getToken($request->all(),$gateway);
            $temp_data = TemporaryData::where("identifier",$token)->first();

            if(!$temp_data) {
                if(Transaction::where('callback_ref',$token)->exists()) {
                    return Response::success([__('Transaction request sended successfully!')],[],400);
                }else {
                    return Response::error([__('Transaction failed. Record didn\'t saved properly. Please try again')],[],400);
                }
            }

            $update_temp_data = json_decode(json_encode($temp_data->data),true);
            $update_temp_data['callback_data']  = $request->all();
            $temp_data->update([
                'data'  => $update_temp_data,
            ]);
            $temp_data = $temp_data->toArray();
            $instance = PaymentGatewayHelper::init($temp_data)->type(PaymentGatewayConst::TYPEADDMONEY)->responseReceive();
            if($instance instanceof RedirectResponse) return $instance;
        }catch(Exception $e) {
            return Response::error('Something went wrong! Please try again.',400);
        }
        return Response::success(["Payment successful, please go back your app"],[],200);
    }
    public function cancel(Request $request, $gateway) {

        $token = PaymentGatewayHelper::getToken($request->all(),$gateway);

        if($temp_data = TemporaryData::where("type",PaymentGatewayConst::TYPEADDMONEY)->where("identifier",$token)->first()) {
            $temp_data->delete();
        }

        return Response::error(["Transaction Failed."],[],400);
    }

    public function postSuccess(Request $request, $gateway){
        try{
            $token = PaymentGatewayHelper::getToken($request->all(),$gateway);
            $temp_data = TemporaryData::where("identifier",$token)->first();
     
            if($temp_data && $temp_data->data->creator_guard != 'api') {
                Auth::guard($temp_data->data->creator_guard)->loginUsingId($temp_data->data->creator_id);
            }
        }catch(Exception $e) {
            return Response::error('Something went wrong! Please try again.',400);
        }
        return $this->success($request, $gateway);
    }

    public function postCancel(Request $request, $gateway){
        try{
            $token = PaymentGatewayHelper::getToken($request->all(),$gateway);
            $temp_data = TemporaryData::where("type",PaymentGatewayConst::TYPEADDMONEY)->where("identifier",$token)->first();
            if($temp_data && $temp_data->data->creator_guard != 'api') {
                Auth::guard($temp_data->data->creator_guard)->loginUsingId($temp_data->data->creator_id);
            }
        }catch(Exception $e) {
            return Response::error('Something went wrong! Please try again.',400);
        }

        return $this->cancel($request, $gateway);
    }
    /**
     * Redirect Users for collecting payment via Button Pay (JS Checkout)
     */
    public function redirectBtnPay(Request $request, $gateway){
        try{
            return PaymentGatewayHelper::init([])->type(PaymentGatewayConst::ADDMONEY)->handleBtnPay($gateway, $request->all());
        }catch(Exception $e) {
            return Response::error([$e->getMessage()], [], 500);
        }
    }
    /**
     * Method for paystack pay callback
     */
    public function paystackPayCallBack(Request $request){
        $instance = $this->paystackSuccess($request->all());
        return Response::success(["Payment successful, please go back your app"],[],200);
    }
    /**
    * Method for manual fields
    */
    function manualFields($request,$payment_info){
        $validator = Validator::make($request,[
            'payment_gateway'          => "required|string|exists:payment_gateway_currencies,alias",
        ]);
        if($validator->fails()) return Response::error($validator->errors()->all(),[],400);
        $validated = $validator->validate();
        $gateway_currency = PaymentGatewayCurrency::where("alias",$validated['payment_gateway'])->first();
       
        $gateway = $gateway_currency->gateway;

        
        // Insert temp data
        $info = [
            'type'          => PaymentGatewayConst::TYPEADDMONEY,
            'identifier'    => generate_unique_string("temporary_datas","identifier",16),
            'data'          => [
                'gateway_currency_id'    => $payment_info['currency']->id,
                'amount'                 => $payment_info['amount'],
                'wallet_id'              => $payment_info['wallet']->id,
            ],
        ];

        try{
            $temp_data = TemporaryData::create($info);
        }catch(Exception $e) {
            return Response::error('Something went wrong! Please try again.',400);
        }
        $data['identifier']         = $temp_data->identifier;
        $data['available']          = false;
        $data['desc']               = strip_tags($gateway->desc);
        $data['additional_fields']  = $gateway->input_fields;
        return $data;
    }
    public function manualInputFields(Request $request) {
       
        $validator = Validator::make($request->all(),[
            'alias'         => "required|string|exists:payment_gateway_currencies",
        ]);

        if($validator->fails()) {
            return Response::error($validator->errors()->all(),[],400);
        }

        $validated = $validator->validate();
        $gateway_currency = PaymentGatewayCurrency::where("alias",$validated['alias'])->first();

        $gateway = $gateway_currency->gateway;

        if(!$gateway->isManual()) return Response::error([__('Can\'t get fields. Requested gateway is automatic')],[],400);

        if(!$gateway->input_fields || !is_array($gateway->input_fields)) return Response::error([__("This payment gateway is under constructions. Please try with another payment gateway")],[],503);

        try{
            $input_fields = json_decode(json_encode($gateway->input_fields),true);
            $input_fields = array_reverse($input_fields);
        }catch(Exception $e) {
            return Response::error([__("Something went wrong! Please try again")],[],500);
        }
        
        return Response::success([__('Payment gateway input fields fetch successfully!')],[
            'gateway'           => [
                'desc'          => strip_tags($gateway->desc)
            ],
            'input_fields'      => $input_fields,
            'currency'          => $gateway_currency->only(['alias']),
        ],200);
    }

    /**
     * Method for submit manual data
     * @param Illuminate\Http\Request $request
     */
    public function manualSubmit(Request $request){
        $tempDataValidate = Validator::make($request->all(),[
            'identifier'        => "required|string|exists:temporary_datas",
        ])->validate();
        
        $tempData = TemporaryData::search($tempDataValidate['identifier'])->first();
        if(!$tempData || $tempData->data == null || !isset($tempData->data->gateway_currency_id)) return redirect()->route('user.add.money.index')->with(['error' => ['Invalid request']]);
        $gateway_currency = PaymentGatewayCurrency::find($tempData->data->gateway_currency_id);
        if(!$gateway_currency || !$gateway_currency->gateway->isManual()) return redirect()->route('user.add.money.index')->with(['error' => ['Selected gateway is invalid']]);
        $gateway = $gateway_currency->gateway;
        $amount = $tempData->data->amount ?? null;
        if(!$amount) return redirect()->route('user.add.money.index')->with(['error' => ['Transaction Failed. Failed to save information. Please try again']]);
        $wallet = UserWallet::find($tempData->data->wallet_id ?? null);
        if(!$wallet) return redirect()->route('user.add.money.index')->with(['error' => ['Your wallet is invalid!']]);

        $this->file_store_location = "transaction";
        $dy_validation_rules = $this->generateValidationRules($gateway->input_fields);
        $validated = Validator::make($request->all(),$dy_validation_rules)->validate();
        $get_values = $this->placeValueWithFields($gateway->input_fields,$validated);
        $trx_id = generateTrxString("transactions","trx_id","AM",8);
        // Make Transaction
        DB::beginTransaction();
        try{
            $id = DB::table("transactions")->insertGetId([
                'type'                          => PaymentGatewayConst::TYPEADDMONEY,
                'trx_id'                        => $trx_id,
                'user_id'                       => $wallet->user->id,
                'user_wallet_id'                => $wallet->id,
                'payment_gateway_currency_id'   => $gateway_currency->id,
                'request_amount'                => $amount->requested_amount,
                'fixed_charge'                  => $amount->fixed_charge,
                'percent_charge'                => $amount->percent_charge,
                'total_charge'                  => $amount->total_charge,
                'total_payable'                 => $amount->total_amount,
                'request_currency'              => get_default_currency_code(),
                'available_balance'             => $wallet->balance,
                'payment_currency'              => $gateway_currency->currency_code,
                'remark'                        => PaymentGatewayConst::MANUAL,
                'details'                       => json_encode(['input_values' => $get_values]),
                'attribute'                     => PaymentGatewayConst::RECEIVED,
                'status'                        => PaymentGatewayConst::STATUSPENDING,
                'created_at'                    => now(),
            ]);
            $basic_settings   = BasicSettings::first();
            if($basic_settings->email_notification == true){
                try{

                    Notification::route('mail',auth()->user()->email)->notify(new AddMoneyNotification($id));
                }catch(Exception $e){}
            }
            $transaction  = Transaction::with(['payment_gateway'])->where('trx_id',$trx_id)->first();
    
            UserNotification::create([
                'user_id'           => auth()->user()->id,
                'transaction_id'    => $id,
                'details'           => [
                    'title'         => 'Add Money using ' . $transaction->payment_gateway->name,
                    'receiver'      => "",
                    'amount'        => get_amount($transaction->request_amount),
                    'currency'      => $transaction->request_currency,
                    'message'       => "Successfully Received."
                ],
            ]);
            DB::table("temporary_datas")->where("identifier",$tempDataValidate['identifier'])->delete();
            DB::commit();
        }catch(Exception $e) {
            DB::rollBack();
            return Response::error(['Something went wrong! Please try again.']);
        }
        return Response::success(['Payment successful, please go back your app'],[],200);
    }
}
Initiate Payment

Initiate Payment

Initiates a new payment transaction.

Endpoint: POST create-order
Parameter Type Details
amount decimal Your Amount , Must be rounded at 2 precision.
currency string Currency Code, Must be in Upper Case (Alpha-3 code)
success_url string Enter your return or success URL
cancel_url string (optional) Enter your cancel or failed URL
                    
                        Request Example (guzzle)
                        

<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', $base_url.'create-order', [
'headers' => [
  'Authorization' => 'Bearer '. $authorizationToken,
  'accept' => 'application/json',
  'content-type' => 'application/json',
 ],
'form_params' => [
  'amount' => '$amount',
  'currency' => 'currency',
  'success_url' => 'success_url',
  'cancel_url' => 'cancel_url',
 ],
]);
echo $response->getBody();
                    
                        
**Response: SUCCESS (200 OK)**
{
 "message": {
 "success": [
  "Order created successfully."
 ]
},
"data": {
 "redirect_url":"https://example.com/login/OISADFDFSDFSF",
 "order_details":{
 "amount" : "10",
 "fixed_charge" : 2,
 "percent_charge" : 1,
 "total_charge" : 3,
 "total_payable" : 13,
 "currency" : "USD",
 "expiry_time": "2024-04-25T06:48:35.984285Z",
 "success_url": "http://127.0.0.1/nfcpay/user/transaction/success",
 "cancel_url": "http://127.0.0.1/nfcpay/user/transaction/cancel"
}
},
"type": "success"
}
                    
                        
**Response: ERROR (400 FAILED)**
{
 "message": {
 "error": [
  "Invalid token."
 ]
},
"data": null,
"type": "error"
}