Skip to content

A simple basket & product manager for the PayPal-node SDK

License

Notifications You must be signed in to change notification settings

notixbit/paypal-basket

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

paypal-basket

GitHub license Build Status npm version

A simple basket & product manager for the PayPal-node SDK.

This module will assist you in managing your products and baskets, in order to craft the Paypal payment request (JSON doc).
Ultimatively it can also request the actual PayPal payment details for you.

Features:

  • Easy product & basket management
  • ES8, ES6, ES5 support
  • Async/Await, Promises & Callbacks
  • Tests

Variants:

Due to migration of the package over the last years, it comes in 3 variants.
All of them share the same code, version, receive all future updates, and
you won't have to update your package.json:

@notixbit/paypal-basket
@burnett01/paypal-basket
paypal-basket


Table of contents


API Reference

Basket:

Basket(
    [Object {
        label: String='',
        urls: Object { 
            return_url: String='',
            cancel_url: String=''
        }
    } options]
) -> Object {
    /* Constants */
    options:  Object=options,
    products: Array=[Product, ...],
    total:    Number=0.00,

    /* Methods */
    add:  [Product, Number=amount, (ErrorClass err) => {}] | Promise
    del:  [Product, (ErrorClass err) => {}] | Promise
    clear:  [(ErrorClass err) => {}] | Promise
    sell: [Object {
        currency: String='USD',
        description: String='',
        norequest: Boolean=false
    } options, (ErrorClass err, String manifest) => {}] | Promise
}

Product:

Product(
    [Object {
        sku: String='',
        name: String='',
        price: Number=0.00,
        currency: String='USD',
    } options]
) -> Object {
    sku:   String=sku
    name:  String=name
    price: Number=price
    currency: String=currency
}

Property reference:

Property Description
options An object with some options (optional)
label Description of the basket (eg. Mike's basket)
urls return_url = Url to return on successfull payment
cancel_url = Url to return on erronous payment
products Array of products in the basket
total Current total of cash in the basket
currency ISO 4217 currency code
description Description of the payment
norequest Whether to perform actual payment request
manifest Crafted JSON document for paypal sdk
.payment = Actual payment request (links, id, ..)
sku Stock Keeping Unit / short product name
name Product name
price Product price (float) (eg. 5.00)

Function reference:

Creating a basket

Available options:

Required
label Description of the basket (eg. Mike's basket) Yes
urls return_url = Url to return to, on successfull payment Yes
cancel_url = Url to return to, on erroneous payment
const demoBasket = new Basket({
  label: 'My Demo Basket',
  urls: {
      return_url: 'http://return.url',
      cancel_url: 'http://cancel.url'
  }
})

Creating a product

Available options:

Required
sku Stock Keeping Unit (eg. myawesomeproduct) Yes
name Product name (eg. My Awesome Product) Yes
price Product price (float) (eg. 5.00) Yes
currency ISO 4217 currency code (eg. USD, EUR, GBP,...) No
const demoProduct = new Product({
  sku: 'mydemoproduct',
  name: 'My Demo Product',
  price: 5.00
})

Adding products to a basket

/* Synchronous */
demoBasket.add(demoProduct)
demoBasket.add(demoProduct, 10)

/* Async/Await */
await demoBasket.add(demoProduct)
await demoBasket.add(demoProduct, 10)

/* Promise */
demoBasket.add(demoProduct)
  .then(() => console.log('Product has been added!'))
  .catch(err => console.log(err))

/* Promise batch */
demoBasket.add(demoProduct)
  .then(demoBasket.add(demoProduct))
  .then(demoBasket.add(demoProduct))
  .then(demoBasket.add(demoProduct))

/* Callback */
demoBasket.add(demoProduct, err => {
  if (err) { return console.log(err) }
  console.log('Product has been added!')
})

Deleting products from a basket

/* Synchronous */
demoBasket.del(demoProduct)

/* Async/Await */
await demoBasket.del(demoProduct)

/* Promise */
demoBasket.del(demoProduct)
  .then(() => console.log('Product has been removed!'))
  .catch(err => console.log(err))

/* Promise batch */
demoBasket.del(demoProduct)
  .then(demoBasket.del(demoProduct))
  .then(demoBasket.del(demoProduct))
  .then(demoBasket.del(demoProduct))

/* Callback */
demoBasket.del(demoProduct, err => {
  if (err) { return console.log(err) }
  console.log('Product has been removed!')
})

Empty a basket

/* Synchronous */
demoBasket.clear()

/* Async/Await */
await demoBasket.clear()

/* Promise */
demoBasket.clear()
  .then(() => console.log('Basket has been cleared!'))
  .catch( err => console.log(err))

/* Callback */
demoBasket.clear(err  => {
  if (err) { return console.log(err) }
  console.log('Basket has been cleared!')
})

Selling a basket (crafting manifest / payment request)

Available options:

Required
currency ISO 4217 currency code (eg. USD, EUR, GBP,...) No
description Describe the payment (eg. Mike's payment) No
norequest Enable/Disable payment-request processing by paypal-basket. No
If this option is set to true, paypal-basket will not perform the actual payment-request.
In addition, the .payment property of the manifest won't be available.
If this option is set to false, paypal-basket will perform the actual payment-request,
and the .payment property of the manifest will be available.

Auto payment-request processing:

/* Async/Await */
const manifest = await demoBasket.sell({ 'currency': 'USD' })
// Payment request has been performed and you can access
// the data (links, timestamp, etc) by using manifest.payment
console.log("Payment ID: " + manifest.payment.id)
console.log("Payment created: " + manifest.payment.create_time)
console.log("Payment URL: " + manifest.payment.links[1].href)

/* Promise */
demoBasket.sell({ 'currency': 'USD' })
  .then(manifest => {
    // Payment request has been performed and you can access
    // the data (links, timestamp, etc) by using manifest.payment
    console.log("Payment ID: " + manifest.payment.id)
    console.log("Payment created: " + manifest.payment.create_time)
    console.log("Payment URL: " + manifest.payment.links[1].href)
  })
  .catch(err => console.log(err))

/* Callback */
demoBasket.sell({ 'currency': 'USD' }, (err, manifest) => {
  if (err) { return console.log(err) }
  // Payment request has been performed and you can access
  // the data (links, timestamp, etc) by using manifest.payment
  console.log("Payment ID: " + manifest.payment.id)
  console.log("Payment created: " + manifest.payment.create_time)
  console.log("Payment URL: " + manifest.payment.links[1].href)
})

Manual payment-request processing:

const paypal = require('paypal-rest-sdk')

/* Async/Await */
const manifest = await demoBasket.sell({ 'currency': 'USD', 'norequest': true })
// Payment request has not been performed and you can use
// the manifest to perform it yourself
const payment = await paypal.payment.create(manifest)
console.log("Payment ID: " + payment.id)
console.log("Payment created: " + payment.create_time)
console.log("Payment URL: " + payment.links[1].href)

/* Promise */
demoBasket.sell({ 'currency': 'USD', 'norequest': true })
  .then(manifest => {
    // Payment request has not been performed and you can use
    // the manifest to perform it yourself
    paypal.payment.create(manifest, (errPP, payment) => {
      if (errPP){ console.log(errPP) }
      console.log("Payment ID: " + payment.id)
      console.log("Payment created: " + payment.create_time)
      console.log("Payment URL: " + payment.links[1].href)
    })
  })
  .catch(err => console.log(err))

/* Callback */
demoBasket.sell({ currency: 'USD', 'norequest': true }, (err, manifest) => {
  if (err) { return console.log(err) }
  // Payment request has not been performed and you can use
  // the manifest to perform it yourself
  paypal.payment.create(manifest, (errPP, payment) => {
    if (errPP) { console.log(errPP) }
    console.log("Payment ID: " + payment.id)
    console.log("Payment created: " + payment.create_time)
    console.log("Payment URL: " + payment.links[1].href)
  })
})

Payment request-data:


Examples

Example 1 (Music Store)

In this example paypal-basket will craft the manifest and request the actual payment by using the internal Paypal-SDK.

const { Paypal, Basket, Product } = require('@notixbit/paypal-basket')

/* Configure paypal sdk */
Paypal.configure({
  mode: 'sandbox',
  client_id: '',
  client_secret: ''
})

/* A JSON collection of music albums */
const albums = [
  {
    "sku": "davidguettalisten",
    "name": "David Guetta - Listen",
    "price": "5.00"
  },
  {
    "sku": "michaeljacksonworld",
    "name": "Michael Jackson - World",
    "price": "10.00"
  },
  {
    "sku": "simplyredthrillme",
    "name": "Simply Red - Thrill me",
    "price": "10.00"
  }
]

/* 
  A collection of music products
  to contain the actual album products
*/
const products = {}

/* 
  Create products from albums 
  and push to collection
*/
for(const index in albums) {
  const album = albums[index]
  products[album.sku] = new Product(album)
}

/* 
  At this point you can access a product like:

  products['michaeljacksonworld']
  products['davidguettalisten']
*/

/* Create a basket (eg. for a customer) */
const sessionxyzBasket = new Basket({
  label: 'Basket of session xyz',
  urls: {
    return_url: 'http://return.url',
    cancel_url: 'http://cancel.url'
  }
})

/* 
  Now let the customer add/del 
  some products to/from their basket.
  Presumably via website
*/
sessionxyzBasket.add(products['davidguettalisten'])
sessionxyzBasket.add(products['michaeljacksonworld'])
sessionxyzBasket.add(products['simplyredthrillme'])
sessionxyzBasket.del(products['davidguettalisten'])

/* Print current total */
console.log('Current total is: $' + sessionxyzBasket.total)

/*
  Now sell the basket (generate manifest)
  and request actual payment details
*/
try {
  const manifest = await sessionxyzBasket.sell({ 'currency': 'USD' })
  console.log("Payment Response:")
  console.log(manifest.payment)
} catch (err) {
  console.log(err)
}

Result:

Example 2 (Manual payment-request)

In this example paypal-basket will craft the payment manifest, but it won't perform the actual payment request.
Just perform the request yourself.

Make sure norequest is true.

const paypal = require('paypal-rest-sdk')
const { Basket, Product } = require('@notixbit/paypal-basket')

/* Configure external paypal sdk */
paypal.configure({
  mode: 'sandbox',
  client_id: '',
  client_secret: ''
})

/* Some sample products */
const demoProduct1 = new Product({
  sku: 'demoproduct1',
  name: 'Demo Product 1',
  price: 15.00
})

const demoProduct2 = new Product({
  sku: 'demoproduct2',
  name: 'Demo Product 2',
  price: 6.53
})

/* Create a basket (eg. for a customer) */
const demoBasket = new Basket({
  label: 'Demo Basket',
  urls: {
    return_url: 'http://return.url',
    cancel_url: 'http://cancel.url'
  }
})

/* 
  Add the demo products
*/
demoBasket.add(demoProduct1)
demoBasket.add(demoProduct2)

/* Print current total */
console.log('Current total is: $' + demoBasket.total)

/*
  Now sell the basket (generate manifest)
  and perform actual payment request with external paypal sdk
*/
try {
  const manifest = await demoBasket.sell({ currency: 'USD', norequest: true })
  const payment = await paypal.payment.create(manifest)
  console.log("Payment Response:")
  console.log(payment)
} catch (err) {
  console.log(err)
}

Setup / Install

Use npm install @notixbit/paypal-basket

const { Paypal, Basket, Product } = require('@notixbit/paypal-basket')

/*
  Configure paypal SDK
  Grab your developer details here:
  https://developer.paypal.com/
*/
Paypal.configure({
  mode: 'sandbox',
  client_id: '',
  client_secret: ''
})

/* Now check examples above */

Unit-Tests

The testing-framework used by this module is Mocha with the BDD / TDD assertion library Chai.

Various tests are performed to make sure this module runs as smoothly as possible.

  • test/test.default.js Performs 6 tests | Source

Output using Mocha spec reporter:

Default reporter: list

Make

make test

NPM

npm test


Contributing

You're very welcome and free to contribute. Thank you.


License

MIT