How to Pay with PayPal in NodeJS

Cronjob

Payment gateway, Paypal is one of the very common payment gateway which are used in mostly E-commerce applications. So today we will learn to intigrate Paypal with nodejs.

So we will use ejs for templating and mongodb for storing the product details and payment details for the app.

So lets move to accomplish the task step by step

Creating Paypal Secret and Client Id

We can create paypal id and client id by visiting the developer site of the paypal, link is developer.paypal.com. Follow the instructions there to get the payment auth details. For payment related stuff we have two mode one is sandbox mode which is used while testing the app, so that amount cannot deduct. Once testing is over and app is ready then payment mode is converted from sandbox mode to live. So when going live Paypal Secret and Client id is required to change so that payment amount can be deducted from the customer account and trasfer to the shopping platform.

Creating MongoDB Collections

product collection:

{
    "_id" : ObjectId("577af2eea8342f99d345121"),
    "name" : "Casual  Shirts",
    "price" : 190,
    "description" : "Casual shirt for professional as well as patry wear",
    "image" : "shirt.jpeg",
    "sku" : "9999900",
    "createdAt" : ISODate("2017-01-05T01:23:42.201Z")
}

 

Now lets have a look on our folder structure

node_modules/
publicData
utils
views
package-lock.json
package.json
server.js

 

Now lets start from bottom to top, So have a look in the code inside server.js

 
'use strict';
// basic packages
let app = require("express")(),
express = require("express"),
http = require('http').Server(app);
// config files
let config =require('./utils/config.js')(app),
db = require("./utils/db.js");
// for media folder browsable
app.use('/static', express.static('publicData'))
// routing
require('./utils/routes.js')(app);
// server creation.
http.listen(3000,function(){
console.log("App listening on port :3000");
});
 

 

In the above code we can see at the top of the files we have basic packages added to create a basic app in nodejs. Below that we have included our config files and db configuration files. Below that we have made the media files for the publicly available to browse over browser. Below that we have routing for the demo. And at the bottom of the page we have started the nodejs app.

Now come to the next one i.e., package.json

 
{
"name": "PayWithPaypal",
"version": "1.0.0",
"description": "N/A",
"author": "Suraj Roy",
"main": "server.js",
"license": "MIT",
"dependencies": {
"body-parser": "^1.18.3",
"ejs": "^2.6.1",
"express": "^4.16.3",
"express-session": "^1.15.6",
"mongodb": "^2.2.35",
"paypal-rest-sdk": "^1.8.1"
}
}
 

 

In the above file we can see the node package needed for our demo.

Now our next section is under utils where we have written our entire logical code in nodejs. Inside utils we have 4 files named config.js, db.js, helper.js, routes.js

lets have a look code inside config.js

 
let express = require("express"),
    path= require('path');
 
let method=config.prototype;
 
function config(app){
    
    app.set('view engine', 'ejs'); // Set .html as the default template extension
    app.engine('html', require('ejs').renderFile); // Initialize the ejs template engine
    app.set('views', (__dirname + '/../views')); // Tell express where it can find the templates
    app.use(express.static(path.join('publicData')));// Make the files of public folder available to the world
}
 
method.get_config=function(){
    return this;
}
 
module.exports = config;
 

 

In the above file we have set .html as default template extension, initialised the ejs template engine, tell the express where it can be find the templates and make the files of public folder available to the world.

Now move to the next file this is, db.js

 
"use strict";
 
const mongodb=require('mongodb');
const MongoClient = mongodb.MongoClient;
const ObjectID = mongodb.ObjectID;
const assert = require('assert');
const MongoUrl='mongodb://localhost:27017/NodejsPaypal';
 
module.exports.onConnect = function(callback){  
    MongoClient.connect(MongoUrl, function(err, db) {
        assert.equal(null, err);
        callback(db,ObjectID);
    });
}
 

 

In the above file we have db connection for the nodejs app.

Now we have next file helper.js. Lets have a look the code inside the file.

 
'use strict';
let Mongodb = require("./db"),
    paypal = require('paypal-rest-sdk');
 
// paypal auth configuration
let config = {
"port" : 5000,
"api" : {
"host" : "api.sandbox.paypal.com",
    "port" : "",
    //"mode" : "live", // uncomment this line when payment is in live environment...
"client_id" : "<enter client id here>", // your paypal application client id
"client_secret" : "<enter client secret here>" // your paypal application secret id
}
}
paypal.configure(config.api);
 
let self={
    insertPayment:function(data,callback){
        var response={};
        Mongodb.onConnect(function(db,ObjectID){
            db.collection('payments').insertOne(data,function(err, result) {
                if(err){
                    response.isPaymentAdded = false;
                    response.message = "Something went Wrong,try after sometime.";
                }else{
                    response.isPaymentAdded = true;
                    response.id=result.ops[0]._id;
                    response.message = "Payment added.";
                }
                callback(response); 
            });
        });
    },  
    getAllProducts:function(data,callback){
        Mongodb.onConnect(function(db,ObjectID){
            db.collection('products').find().toArray(function(err, result){
                callback(result);
                db.close();
            });
        });
    },
    payNow:function(paymentData,callback){
        var response ={};
 
        /* JSON for Paypal starts */
        const payment = {
            "intent": "authorize",
            "payer": {
                "payment_method": "paypal"
            },
            "redirect_urls": {
                "return_url": "http://127.0.0.1:3000/execute",
                "cancel_url": "http://127.0.0.1:3000/cancel"
            },
            "transactions": [{
                "amount": {
                    "total": paymentData.data.price,
                    "currency": "USD"
                },
                "description": paymentData.data.productName
            }]
        };
        /* JSON for Paypal ends */
 
        /* Creating Paypal Payment for Paypal starts */
        paypal.payment.create(payment, function (error, payment) {
            if (error) {
                console.log(error);
            } else {
             if(payment.payer.payment_method === 'paypal') {
                 response.paymentId = payment.id;
                 var redirectUrl;
                 response.payment = payment;
                 for(var i=0; i < payment.links.length; i++) {
                     var link = payment.links[i];
                     if (link.method === 'REDIRECT') {
                         redirectUrl = link.href;
                     }
                 }
                 response.redirectUrl = redirectUrl;
             }
         }
         callback(error,response);
        });
    },
    getResponse:function(data,PayerID,callback){
 
        var response = {};
        
        const serverAmount = parseFloat(data.paypalData.payment.transactions[0].amount.total);
        const clientAmount = parseFloat(data.clientData.price);
        const paymentId = data.paypalData.paymentId;
        const details = {
            "payer_id": PayerID
        };
 
        response.userData= {
            userID : data.sessionData.userID,
            name : data.sessionData.name
        };
 
        if (serverAmount !== clientAmount) {
            response.error = true;
            response.message = "Payment amount doesn't matched.";
            callback(response);
        } else{
            
            paypal.payment.execute(paymentId, details, function (error, payment) {
                if (error) {
                    console.log(error);
                    response.error = false;
                    response.message = "Payment Successful.";
                    callback(response);
                } else {
 
                    const insertPayment={
                     userId : data.sessionData.userID,
                     paymentId : paymentId,
                     createTime : payment.create_time,
                     state : payment.state,
                     currency : "USD",
                     amount: serverAmount,
                     createAt : new Date().toISOString()
                    }
 
                    self.insertPayment(insertPayment,function(result){
 
                        if(! result.isPaymentAdded){
                            response.error = true;
                            response.message = "Payment Successful, but not stored.";
                            callback(response);
                        }else{
                            response.error = false;
                            response.message = "Payment Successful.";
                            callback(response);
                        };
                    });
                };
            });
        };
}
}
module.exports = self;
 

 

In the above file at the top we have config variable having auth data of paypal. Below that we have separated method for inserting payment data after success payment, method for fetching product from the database, method for sending payment request to paypal and a getResponse method.

 

Now lets move to next file routes.js. have a look on the code inside this file.

 
'use strict';
const bodyParser = require('body-parser');
var Session = require('express-session');
 
var Session = Session({
    secret:'ilovejsonworld',
    saveUninitialized: true,
    resave: true
});
const helper = require('./helper');
 
var method=routes.prototype;
 
function routes(app){
    
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({
        extended: true
    }));
    app.use(Session);   
    var sessionInfo;
 
    /*
* Rendering login page
*/
    app.get('/', function(req, res){
        res.redirect("/home");
        res.end();
    });
 
    app.get('/home',function(req, res){
        sessionInfo = req.session;
        sessionInfo.sessionData = {
            userID:1,
            name:"jsonworld"
        };
 
            var response ={};
         const data={
                ID : sessionInfo.sessionData.userID,
                name : sessionInfo.sessionData.name
            };
 
            helper.getAllProducts(data,function(products){
                response.products = products;
                response.userData = {};
                response.userData.name = sessionInfo.sessionData.name;
                //console.log(response.userData.name,'pankaj----');
                res.render('home',{
                    response : response
                });
            });
    });
 
    app.post('/paynow',function(req, res){
        sessionInfo = req.session;
        if (typeof sessionInfo.sessionData == "undefined" || sessionInfo.sessionData=="") {
            res.redirect("/");
            res.end();
        } else{
            const data ={
                userID : sessionInfo.sessionData.userID,
                data : req.body
            }
            helper.payNow(data,function(error,result){
                if(error){
                    res.writeHead(200, {'Content-Type': 'text/plain'});
                    res.end(JSON.stringify(error));
                }else{
                    sessionInfo.paypalData = result;
                    sessionInfo.clientData = req.body;
                    res.redirect(result.redirectUrl);
                }               
            });         
        }   
    });
 
    /*
    * payment success url
    */
    app.get('/execute',function(req, res){      
        sessionInfo = req.session;  
        var response = {};
        const PayerID = req.query.PayerID;
        if (typeof sessionInfo.sessionData == "undefined" || sessionInfo.sessionData=="") {
            res.redirect("/");
            res.end();
        } else{
            sessionInfo.state ="success";
            helper.getResponse(sessionInfo,PayerID,function(response) {
                res.render('successPayement',{
                    response : response
                });
            });
        };
    });
 
    /*
    * payment cancel url
    */
    app.get('/cancel',function(req, res){
        sessionInfo = req.session;
        if (typeof sessionInfo.sessionData == "undefined" || sessionInfo.sessionData=="") {
            res.redirect("/");
            res.end();
        } else{
            var response ={};
            response.error = true;
            response.message = "Payment unsuccessful.";
            response.userData = {
                name : sessionInfo.sessionData.name
            };
                            
            res.render('successPayement',{
                response : response
            });
        }
    });
 
 
}
 
method.getroutes=function(){
    return this;
}
 
module.exports = routes;
 

In the above file you can see we have set here basic routing.

 

Now let move to front end part i.e., inside view folder. In side this folder we have two files first is home.ejs & second is successPayment.ejs. First page initiates payment and second page for showing success message after success payment. You can find these files inside the zipped code available over this site.

This way you can easily create a demo for Pay with paypal in nodejs.However, our application is not yet live.

Let me know your thoughts over the email demo.jsonworld@gmail.com. I would love to hear them and If you like this article, share with your friends. 

 

 

 

You can download complete code from here. Download Code