9

I have the exact same problem as described in the post Implementation of Paypal in single page application unfortunately nobody in this vast community seems to have an answer :( With lots of head banging I was able to implement a dirty hack as below and I know that this is not the right solution. Could any of the gurus kindly ponder over this question and answer/give feedback if my dirty hack is the right way or it can be better implemented. Below my dirty hack :( Many thanks in advance for your answers/comments.

I have a button to say pay with paypal and onClick I open a new window -> window.open("/paypalCreate", width = "20px", height = "20px"); and I capture this get request "/paypalCreate" in my node.js server and call create method which looks liek below

exports.create = function (req, res) {
    //Payment object
    var payment = {
       //fill details from DB
    };   

    //Passing the payment over to PayPal
    paypal.payment.create(payment, function (error, payment) {
        if (error) {
            console.log(error);
        } else {
            if (payment.payer.payment_method === 'paypal') {
                req.session.paymentId = payment.id;
                var redirectUrl;
                for (var i = 0; i < payment.links.length; i++) {
                    var link = payment.links[i];
                    if (link.method === 'REDIRECT') {
                        redirectUrl = link.href;
                    }
                }
                res.redirect(redirectUrl);
            }
        }
    });
};

This redirects user to paypal and once user confirms or cancels payment, the redirect urls are called. And in the success redirect url I capture the payment details into the databse and render a html in this opened window with the confirmation.

exports.execute = function (req, res) {
    var paymentId = req.session.paymentId;
    var payerId = req.param('PayerID');

    // 1. if this is executed, then that means the payment was successful, now store the paymentId, payerId and token into the database
    // 2. At the close of the popup window open a confirmation for the reserved listing
    var details = {"payer_id": payerId};
    paypal.payment.execute(paymentId, details, function (error, payment) {
        if (error) {
            console.log(error);
        } else {
            //res.send("Hell yeah!");
            res.render('paypalSuccess', {payerId: payerId, paymentId: paymentId});
        }
    });
};

Once the user closes the opened window in which paypal was being handled the orginal SPA window will be refreshed and thus getting the payment details from the DB and here you can handle the SPA in whatever way you want. I know that this is a dirty hack, but like you I couldnt find a better way. Please let me know if this works for you or if you have a found a better way to do tihs.

cheers, Chidan

Chidu Murthy
  • 688
  • 3
  • 10
  • 26

1 Answers1

12

Try this. It's what I use for my app.

var config = require("config3");
var paypal_api = require("paypal-rest-sdk");
paypal_api.configure(config.paypal);
var log = require("app/log");

function pay(creditCard, amount, description, callback) {
    var paypalOptions = {
        intent: "sale",
        payer: {
            payment_method: "credit_card",
            funding_instruments: [{credit_card: creditCard}]
        },
        transactions: [{
            amount: {
                total: amount,
                currency: "USD"
            },
            description: description
        }]
    };
    if (config.paypal.enabled) {
        paypal_api.payment.create(paypalOptions, function (error, response) {
            log.debug({
              err: error,
              response: response || (error && error.response)
            }, "paypal payment response");
            callback(error, response);
        });
    } else {
        setImmediate(function () {
            callback(null, {"fakePaypal": "is fake"});
        });
    }
}

module.exports = pay;

Edit: The config3 module would look like this. The docs for this module can be found here

module.exports = {
  paypal: {
    client_id: "Secret API key",
    client_secret: "Secret API key",
    host: "api.sandbox.paypal.com",
    enabled: true
  },
  mysql: {
    host: 'localhost',
    user: 'root',
    password: '',
    database: ''
  },
  redis: {
    host: "localhost",
    port: 6379
  },

As far as redirection you don't need to send your user to Paypal. On success just show a transaction completed message / page. On failure show the error and let them fix it.

BenH
  • 428
  • 5
  • 19
  • Hi Ben, thanks. I have 2 questions though, how does your config file look like? and this would work for payment by credit cards where there is no redirection to paypal site, but how can I handle the redirection to paypal site, and back to the success or cancel url? – Chidu Murthy Dec 22 '14 at 10:12
  • I updated my answer to your two questions. If this solved your issue please accept it as an accepted answer. Thanks – BenH Dec 29 '14 at 00:30