Search code examples
phplaravelsleeppayment-processing

Delaying PHP code for some time when reaching out to a Payment Gateway


I am working on a Laravel PHP project whereby I reach out to an Payment API to check the status if the user has paid and redirect the user to a payment-confirm page.

By default the payment status from the Payment gateway is 0. When a user pays the status changes to 1. After user hits payment button on the website, I need to delay the execution of the PHP code (to allow the user some time to transact payment through his/her phone).

After 15 seconds, I reach out to the payment gateway to check if the status has changes to 1, if true redirect the user to payment-confirmation page.

I have tried to use sleep but it isn't working... I have also tested using a sandbox account while paying but it isn't redirecting as expected after the 15 seconds.

Sample JSON object I get from the API depending on the payment status

//When not paid
{
    status: 0,
    message: 'Not Paid',
    amount: 20
}

//When paid
{
    status: 1,
    message: 'Paid',
    amount: 20
}

//When cancelled
{
    status: 2,
    message: 'Cancelled',
    amount: 20
}

AJAX code am using to post data to the controller

<script type="text/javascript">
  //Mpesa Payment code
$('.mpesa').on('click', function () {

    //Gets the MPESA type
    var type = $('.mpesa').prop('id');
    var quote = $('#quote').val();
    var phone = $('#phone').val();
    //Converts to a JSON object
    var type ={
      'type': type,
      'quote' : quote,
      'phone' : phone,
    };

    console.log(type);

    $.ajax({
        //Contains controller of payment
        type: 'POST',
        url: 'paymentFinal',
        data: JSON.stringify(type),
        contentType: 'application/json',
        dataType: "json",
        success: function success(response) {
            window.location.href="success" ;
        },
        error: function error(data) {
            console.log(data);
        }
    });
});
//End Payment API

Laravel Controller am posting data to from above AJAX code

 public
    function payFinal(Request $request)
    {
        // dd($request->all());

         //Convert to a JSON object the request 
        $data =(object)$request->all();

        //Session get of some data fetched from another controller
        $quote = $request->session()->get('quoteID');

        //Store all the data in an array
         $all = array(
            'phone' => $data->phone,
            'quote_id' => $quote,
            'payment_type' => $data->type,
        );

        //Posts data to Payment Checkout using curl
        $response = $this->global_Curl($all, 'api/payment/checkout');
        //dd($response);

        //Get checkoutresponseId from response
        $checkID = $response->data->CheckoutRequestID;

        //Payment type
        $type = $data->type;

        $data = array(
            'payment_reference' => $checkID,
            'payment_type' => $type
        );

        //1st call to the Payment API before sleep
        $paySt = $this->global_Curl($data, 'api/payment/status')->data;

        sleep(15);

        //Second call to the API after sleep to check if status has changed
        $payStat = $this->global_Curl($data, 'api/payment/status')->data;

        if($payStat->status == '1'){
            return 'true';   
        }
    }

New AJAX code am using

$('.mpesa').on('click', function () {
    setInterval(function() {
       alert('clicked');
      //Gets the MPESA type
       var type = $('.mpesa').prop('id');
      var quote = $('#quote').val();
      var phone = $('#phone').val();
      //Converts to a JSON object
      var type ={
        'type': type,
        'quote' : quote,
        'phone' : phone,
      };

    console.log(type);
    $.ajax({
        //Contains controller of payment
        type: 'POST',
        url: 'paymentFinal',
        data: JSON.stringify(type),
        contentType: 'application/json',
        dataType: "json",
        success: function success(response) {
          if(response) {
              window.location.href="success";
          }
        },
        error: function error(data) {
            console.log(data);
        }
    });
}, 15000); // Execute every 15 seconds
});

Solution

  • Ok, so lets break your problem down. First of all, you want to delay your AJAX code to execute every 15 seconds. For this, you wrap your AJAX in a setInterval() javascript method. So it should end up looking like this:

    setInterval(function() {
        $.ajax({
            //Contains controller of payment
            type: 'POST',
            url: 'paymentFinal',
            data: JSON.stringify(type),
            contentType: 'application/json',
            dataType: "json",
            success: function success(response) {
                window.location.href="success" ;
            },
            error: function error(data) {
                console.log(data);
            }
        });
    }, 15000); // Execute every 15 seconds
    

    Next, you want to do something based on the status that your code returns. For this, you need to change the success case of your AJAX method to something like this:

        success: function success(response) {
            if(response) {
                window.location.href="success"
            }
        }
    

    That's it for the javascript side. For the PHP side, you can remove this because you are now handling the interval on the frontend:

        sleep(15);
    
        //Second call to the API after sleep to check if status has changed
        $payStat = $this->global_Curl($data, 'api/payment/status')->data;
    

    And also change the return type from a string to a boolean:

    if($payStat->status == 1){
            return response()->json(true);   // Sends back a JSON response to your AJAX
        }
    

    And that should do what you want it to do.

    Now, a few suggestions on your code:

    • You might want to make provisions for more cases than just the success AJAX case
    • Make sure you disable the button when the user clicks the payment button, or else every time they press it it will start a new 15 second interval
    • Try wrapping your PHP code in a try-catch block to allow for graceful error handling
    • Make provisions for more than just the success case