Ayb4btu
Ayb4btu

Reputation: 3398

PayPal express checkout: checking payment can be performed on button click

I'm using PayPal express checkout (checkout.js V4.0.0) with asp.net mvc to allow a user to pay for data transactions. What I need to do when the express checkout button is clicked is perform some checks on the database and confirm that PayPal can proceed (this is also time related, as the database could be in a locked processing state).

I've setup the Advanced Server Integration and I then call the create-payment controller from the payment section in paypal.Button.render, but this expects a json object with a PaymentID element to be returned. At what point am I able to perform these checks on server side and abort from the paypal process if PayPal can't continue? If a check fails, the server side also needs to return an appropriate error page or message to be displayed.

This is the paypal button code:

<script src="https://www.paypalobjects.com/api/checkout.js"></script>
<script>
    paypal.Button.render({
        env: 'sandbox',
        payment: function (resolve, reject) {
            var CREATE_PAYMENT_URL = '@Url.Action("PayTransactions","Pending")';

        paypal.request.post(CREATE_PAYMENT_URL)
            .then(function (data) { resolve(data.paymentID); })
            .catch(function (err) { reject(err); });
        },
        onAuthorize: function(data) {
            var EXECUTE_PAYMENT_URL = 'https://my-store.com/paypal/execute-payment';

            paypal.request.post(EXECUTE_PAYMENT_URL,
            {
                paymentID: data.paymentID,
                payerID: data.payerID
            })
                .then(function(data) { /* Go to a success page */ })
                .catch(function (err) { /* Go to an error page  */ });
        },
        onCancel: function (data, actions) {
            return actions.redirect();
        },
        onError: function (err) {
            // Show an error page here, when an error occurs
        }
    }, '#paypal-button');
</script>

which at the payment section calls this:

public async Task<string> PayTransactions()
{
    // check if payment is still necessary or end of month is running
    var condition = await CheckDatabaseIsUsable();

    switch (condition)
    {
        case 1:
            ModelState.AddModelError("error", "some error message");
            return RedirectToAction("Index", "Pending");

        case 2:
            ModelState.AddModelError("error", "some other error");
            return RedirectToAction("Index", "Pending");
    }

    var paypalPayment = FormPayPalPaymentObject();

    return JsonConvert.SerializeObject(new { paymentID = paypalPayment.PaymentId });
}

The problem is that I am now mixing the ActionResult and json string return types.

Upvotes: 0

Views: 827

Answers (2)

animalito maquina
animalito maquina

Reputation: 2414

You can return json also for the redirection responses and control with javascript when it is a redirection or and ok response.

Server side:

  return JsonConvert.SerializeObject(new { redirect= Url.Action("Index", "Pending") });

Javascript:

     paypal.request.post(CREATE_PAYMENT_URL)
            .then(function (data) {
                if(data.redirect)
                {
                    //cancel the flow and redirect if needed
                    window.location.href = data.redirect;
                }else{
                    resolve(data.paymentID); 
                }
            })
            .catch(function (err) { reject(err); });
        },

Using an IActionResult object as the return value for the PayTransactions is preferable

public async Task<IActionResult> PayTransactions()
{

    ...

    return Json(new { paymentID = paypalPayment.PaymentId });
}

Also consider that the modelstate errors you are adding are useless because of the redirection.

Upvotes: 1

bluepnume
bluepnume

Reputation: 17128

You can call reject(error) to cancel the payment.

Upvotes: 0

Related Questions