Bootstrap FreeKB - NodeJS - PayPal advanced integration checkout using NodeJS on Docker
NodeJS - PayPal advanced integration checkout using NodeJS on Docker

Updated:   |  NodeJS articles

Before trying this in a Docker container, it's easier to try this out using NodeJS on a Linux server. Check out my article PayPal advanced integration checkout using NodeJS.

If you have not yet followed my article PayPal standard integration checkout using NodeJS on Docker, you'll probably want to go with the standard integration before trying this advanced integration.

Let's say your Docker server is a Linux system. Move into your /tmp directory and clone the https://github.com/paypal-examples/docs-examples.git repository.

~]$ cd /tmp
~]$ git clone https://github.com/paypal-examples/docs-examples.git

 

Create the /usr/local/paypal-advanced-integration-v2 directory.

mkdir /usr/local/paypal-advanced-integration-v2

 

Copy the files and directories in /tmp/docs-examples/advanced-integration/v2 to /usr/local/paypal-advanced-integration-v2.

cp -R /tmp/docs-examples/advanced-integration/v2/* /usr/local/paypal-advanced-integration-v2

 

/usr/local/paypal-advanced-integration-v2/server/server.js will set the base constant to "https://api-m.sandbox.paypal.com" or "https://api-m.paypal.com". Let's comment out the base constant.

#const base = "https://api-m.sandbox.paypal.com";

 

/usr/local/paypal-advanced-integration-v2/server/server.js should have 3 references to the base constant.

const response = await fetch(`${base}/v1/oauth2/token`, {
const url = `${base}/v2/checkout/orders`;
const url = `${base}/v2/checkout/orders/${orderID}/capture`;

 

Let's update the lower case base constant to upper case.

const response = await fetch(`${BASE}/v1/oauth2/token`, {
const url = `${BASE}/v2/checkout/orders`;
const url = `${BASE}/v2/checkout/orders/${orderID}/capture`;

 

/usr/local/paypal-advanced-integration-v2/server/server.js should have something like this, a $100.00 USD currency charge.

value: "100.00",

 

Let's change this to CURRENCY_VALUE.

value: CURRENCY_VALUE,

 

Let's add the following constant to /usr/local/paypal-advanced-integration-v2/server/server.js.

const { BASE, PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PORT, CURRENCY_VALUE } = process.env;

 

Let's first set this up in the Sandbox environment.

  1. Go to https://developer.paypal.com/dashboard/applications/sandbox
  2. Select Create App and follow the prompts to create an app. You should get a Client ID and Secret.

Rename /usr/local/paypal-advanced-integration-v2/.env.example to .env and update .env to have your apps Client ID and Secret. as well as PORT, CURRENCY_VALUE, and BASE. This make it much cleaner if we need to toggle between sandbox and live as we only need to update the .env file.

PORT = 8888
CURRENCY_VALUE = "1.00"
# SANDBOX
#BASE="https://api-m.sandbox.paypal.com"
#PAYPAL_CLIENT_ID="YOUR_CLIENT_ID_GOES_HERE"
#PAYPAL_CLIENT_SECRET="YOUR_SECRET_GOES_HERE"
# LIVE
BASE="https://api-m.paypal.com"
PAYPAL_CLIENT_ID="YOUR_CLIENT_ID_GOES_HERE"
PAYPAL_CLIENT_SECRET="YOUR_SECRET_GOES_HERE"

 

By default, your sandbox app should be setup with support for the advanced integration.

 

However, your live app may not be setup with support for the advanced integration. I just had to click on the Learn More link and follow the prompts to setup my live app with support for the advanced integration.

 

By default, /usr/local/paypal-advanced-integration-v2/server/server.js will have USD 100.00 (e.g. $100.00). You probably want to change this to some other value.

const createOrder = async (cart) => {
  console.log(
    "shopping cart information passed from the frontend createOrder() callback:",
    cart,
  );

  const accessToken = await generateAccessToken();
  const url = `${base}/v2/checkout/orders`;
  const payload = {
    intent: "CAPTURE",
    purchase_units: [
      {
        amount: {
          currency_code: "USD",
          value: "100.00",
        },
      },
    ],
  };

 

Add "cors" to the dependencies in /usr/local/paypal-advanced-integration-v2/server/package.json.

{
  "name": "paypal-advanced-integration",
  "description": "Sample Node.js web app to integrate PayPal Advanced Checkout for online payments",
  "version": "1.0.0",
  "main": "server/server.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon server/server.js",
    "format": "npx prettier --write **/*.{js,md}",
    "format:check": "npx prettier --check **/*.{js,md}",
    "lint": "npx eslint server/*.js --env=node && npx eslint client/*.js --env=browser"
  },
  "license": "Apache-2.0",
  "dependencies": {
    "cors": "^2.8.5",
    "dotenv": "^16.3.1",
    "ejs": "^3.1.9",
    "express": "^4.18.2",
    "node-fetch": "^3.3.2"
  },
  "devDependencies": {
    "nodemon": "^3.0.1"
  }
}

 

While not necessary, I would add console.log lines to /usr/local/paypal-advanced-integration-v2/client/checkout.js, something like this, as this makes it much easier to understand what is happening and to troubleshoot problems.

async function createOrderCallback() {
  console.log(`This is the beginning of the createOrderCallback function`);

 

Then when pull up the app in your web browser, you should see the console.log events in the developer (f12) console.

 

Most importantly, I would add the following console.log lines to /usr/local/paypal-advanced-integration-v2/client/checkout.js so that you will know if the if cardField.isEligible() statement evaluated to true or false.

if (cardField.isEligible()) {
  console.log(`The if cardField.isEligible() statement evaluated to true`);
  . . .
} else {
  console.log(`The if cardField.isEligible() statement did NOT evaluate to true`);
  console.log(`cardField = ${JSON.stringify(cardField)}`);
  . . .
}

 

Create a file named Dockerfile in the /usr/local/paypal-advanced-integration-v2 directory.

touch /usr/local/paypal-advanced-integration-v2/Dockerfile

 

The Dockerfile should have something like this.

  • Use RUN npm install when creating the sandbox container
  • Use RUN npm install --omit=dev ​when creating the production container
FROM node:18-alpine
WORKDIR /src
COPY package.json /src/
RUN npm install

 

Move into the directory that contains the Dockerfile.

cd /usr/local/paypal-advanced-integration-v2

 

Use the docker build command to create the NodeJS image using the Dockerfile.

sudo docker build --file Dockerfile --tag paypal-nodejs:18-alpine .

 

The docker images command should return something like this.

~]$ sudo docker images
REPOSITORY       TAG          IMAGE ID       CREATED         SIZE
paypal-nodejs    18-alpine    824127ec51d1   4 seconds ago   154MB
node             18-alpine    24d8fcd7167f   3 weeks ago     132MB

 

The docker run command can be used to create and start a Docker container from the NodeJS image.

sudo docker run \
--name paypal-nodejs \
--publish 0.0.0.0:8888:8888 \
--detach \
--volume /usr/local/paypal-advanced-integration-v2/.env:/src/.env \
--volume /usr/local/paypal-advanced-integration-v2/client/checkout.js:/src/client/checkout.js \
--volume /usr/local/paypal-advanced-integration-v2/server/server.js:/src/server/server.js \
--volume /usr/local/paypal-advanced-integration-v2/server/views/checkout.ejs:/src/server/views/checkout.ejs \
paypal-nodejs:18-alpine \
npm start

 

The docker container ls command should show the container is up and running.

~]$ sudo docker container ls
CONTAINER ID   IMAGE                      COMMAND                  CREATED        STATUS                  PORTS                         NAMES
c19d5eab9a75   paypal-nodejs:18-alpine    "docker-entrypoint.s…"   2 weeks ago    Up 2 weeks              0.0.0.0:8888->8888/tcp     paypal-nodejs

 

The docker logs command should return something like this.

~]$ sudo docker logs paypal-nodejs
> paypal-advanced-integration@1.0.0 start
> nodemon server/server.js
[nodemon] 3.1.0
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node server/server.js`
Node server listening at http://localhost:8888/

 

Go to http://<your Docker servers hostname or IP address>:8888/. If something like this is displayed, this means render("#paypal-button-container") in /src/client/checkout.js in the Docker container was rendered. /src/server/views/checkout.ejs in the Docker container has <div id="paypal-button-container" class="paypal-button-container"></div> to render paypal-button-container.

 

On the other hand, if something like this should be displayed, then this should mean that cardField.isEligible() in /src/client/checkout.js in the Docker container evaluated to true and the advanced integration view has been rendered.

If you don't want the 2 yellow PayPal buttons to be displayed, check out my article Remove yellow PayPal buttons from PayPal advanced integration using NodeJS.

 

Viewing the page source should have something like this, which is your /src/server/views/checkout.ejs file in the Docker container.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css"
      href="https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css" />
    <title>PayPal JS SDK Advanced Integration - Checkout Flow</title>
  </head>
  <body>
    <div id="paypal-button-container" class="paypal-button-container"></div>
    <div id="card-form" class="card_container">
      <div id="card-name-field-container"></div>
      <div id="card-number-field-container"></div>
      <div id="card-expiry-field-container"></div>
      <div id="card-cvv-field-container"></div>
      <button id="multi-card-field-button" type="button">Pay now with Card</button>
    </div>
    <p id="result-message"></p>
    <script src="https://www.paypal.com/sdk/js?components=buttons,card-fields&client-id=abcdefg123456789abcdefg123456789abcdefg123456789"></script>
    <script src="checkout.js"></script>
  </body>
</html>

 

Let's say you want to customize the placeholder text, perhaps something like this, check out my article Customize PayPal advanced integration checkout input form placeholder using NodeJS.

 

Submit a payment and something like "Transaction COMPLETED" should be displayed.

 

In https://developer.paypal.com/dashboard/applications/sandbox, on the Event Logs tab, there should be 201 OK events for the completed transation.

 

And the docker logs command should have something like this.

~]$ sudo docker logs paypal-nodejs2
> paypal-advanced-integration@1.0.0 start
> nodemon server/server.js
[nodemon] 3.1.0
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node server/server.js`
Node server listening at http://localhost:8888/
shopping cart information passed from the frontend createOrder() callback: [ { id: 'YOUR_PRODUCT_ID', quantity: 'YOUR_PRODUCT_QUANTITY' } ]

 

/usr/local/paypal-advanced-integration-v2/server/server.js has the console.log that appends the event to the log.

const createOrder = async (cart) => {
  console.log(
    "shopping cart information passed from the frontend createOrder() callback:",
    cart,
  );

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter c3a424 in the box below so that we can be sure you are a human.