├── Procfile ├── blob ├── app-keys.png ├── sample_app.png ├── deploy-finish.png ├── deploy-window.png └── client-address.png ├── public ├── slack.png ├── favicon.ico ├── voucherify.png ├── voucherify_logo.png ├── voucherify_product.jpg ├── styles.css └── scripts.js ├── config └── default.json ├── index.js ├── .gitignore ├── app.json ├── LICENSE ├── package.json ├── routes └── index.js ├── lib └── voucherifyService.js ├── README.md └── views └── index.html /Procfile: -------------------------------------------------------------------------------- 1 | web: node index.js 2 | 3 | -------------------------------------------------------------------------------- /blob/app-keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voucherifyio/voucherify-nodejs-example/HEAD/blob/app-keys.png -------------------------------------------------------------------------------- /public/slack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voucherifyio/voucherify-nodejs-example/HEAD/public/slack.png -------------------------------------------------------------------------------- /blob/sample_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voucherifyio/voucherify-nodejs-example/HEAD/blob/sample_app.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voucherifyio/voucherify-nodejs-example/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /blob/deploy-finish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voucherifyio/voucherify-nodejs-example/HEAD/blob/deploy-finish.png -------------------------------------------------------------------------------- /blob/deploy-window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voucherifyio/voucherify-nodejs-example/HEAD/blob/deploy-window.png -------------------------------------------------------------------------------- /public/voucherify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voucherifyio/voucherify-nodejs-example/HEAD/public/voucherify.png -------------------------------------------------------------------------------- /blob/client-address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voucherifyio/voucherify-nodejs-example/HEAD/blob/client-address.png -------------------------------------------------------------------------------- /public/voucherify_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voucherifyio/voucherify-nodejs-example/HEAD/public/voucherify_logo.png -------------------------------------------------------------------------------- /public/voucherify_product.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voucherifyio/voucherify-nodejs-example/HEAD/public/voucherify_product.jpg -------------------------------------------------------------------------------- /config/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "voucherifyNodeJsExampleApp": { 3 | "email": "email@example.com", 4 | "applicationKeys": { 5 | "applicationId": null, 6 | "applicationSecretKey": null 7 | }, 8 | "clientSideKeys": { 9 | "clientApplicationId": null, 10 | "clientPublicKey": null 11 | }, 12 | "numberOfSuppliedTestVouchers": 5, 13 | "testVouchersCategory": "voucherify-nodejs-example" 14 | } 15 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const bodyParser = require('body-parser') 4 | const express = require('express') 5 | const swig = require('swig') 6 | 7 | const routes = require('./routes') 8 | 9 | const app = express() 10 | 11 | app.engine('html', swig.renderFile) 12 | app.set('view engine', 'html') 13 | app.set('port', (process.env.PORT || 5000)) 14 | app.use(express.static(__dirname + '/public')) 15 | app.use(bodyParser.json()) 16 | app.use(bodyParser.urlencoded({ 17 | extended: true 18 | })) 19 | 20 | app.use(routes()) 21 | 22 | app.listen(app.get('port'), () => { 23 | console.log(`Node app is running at localhost:${app.get('port')}`) 24 | }) 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | 35 | # Jetbrains 36 | .idea 37 | 38 | # Configuration 39 | config 40 | !config/default.json 41 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Voucherify Node.js Example", 3 | "description": "A sample Node.js implementation of Voucherify SDK", 4 | "repository": "https://github.com/voucherifyio/voucherify-nodejs-example", 5 | "logo": "https://raw.githubusercontent.com/voucherifyio/voucherify-nodejs-example/master/public/voucherify.png", 6 | "keywords": ["voucherify", "node", "heroku", "express"], 7 | "env": { 8 | "EMAIL": { 9 | "description": "Leave your Email address to check the voucher tracking feature!", 10 | "value": "email@example.com" 11 | }, 12 | "APPLICATION_ID": { 13 | "description": "Voucherify Application ID", 14 | "value": "" 15 | }, 16 | "APPLICATION_SECRET_KEY": { 17 | "description": "Voucherify Application Secret Key", 18 | "value": "" 19 | }, 20 | "CLIENT_APPLICATION_ID": { 21 | "description": "Voucherify Client Application ID", 22 | "value": "" 23 | }, 24 | "CLIENT_PUBLIC_KEY": { 25 | "description": "Voucherify Client Public Key", 26 | "value": "" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 rspective 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "voucherify-nodejs-example", 3 | "version": "0.1.0", 4 | "description": "A sample Node.js implementation of Voucherify SDK", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node --optimize_for_size --max_old_space_size=460 --gc_interval=100 index.js", 8 | "test": "echo 'Tests are not defined yet' && exit 0", 9 | "postinstall": "echo 'No postinstall scripts yet' && exit 0", 10 | "heroku-prebuild": "echo 'This runs before Heroku installs your dependencies' && exit 0" , 11 | "heroku-postbuild": "echo 'This runs after Heroku builds your app' && exit 0" 12 | }, 13 | "dependencies": { 14 | "bluebird": "^3.4.0", 15 | "body-parser": "^1.15.1", 16 | "config": "^1.20.1", 17 | "express": "^4.13.3", 18 | "lodash": "^4.12.0", 19 | "moment": "^2.13.0", 20 | "swig": "^1.4.2", 21 | "voucherify": "^1.10.0" 22 | }, 23 | "engines": { 24 | "node": "4.2.6" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/voucherifyio/voucherify-nodejs-example" 29 | }, 30 | "keywords": [ 31 | "voucherify", 32 | "node", 33 | "heroku", 34 | "express" 35 | ], 36 | "license": "MIT" 37 | } 38 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const _ = require('lodash') 4 | const config = require('config').get('voucherifyNodeJsExampleApp') 5 | const express = require('express') 6 | 7 | const voucherifyService = require('./../lib/voucherifyService') 8 | 9 | const clientSideKeys = config.get('clientSideKeys') 10 | 11 | const email = process.env.EMAIL || config.get('email') 12 | const clientApplicationId = process.env.CLIENT_APPLICATION_ID || clientSideKeys.get('clientApplicationId') 13 | const clientPublicKey = process.env.CLIENT_PUBLIC_KEY || clientSideKeys.get('clientPublicKey') 14 | 15 | const prepareUnhandledErrorResponse = (err, res) => { 16 | console.error('Error: %s', err) 17 | return res.status(500).json({message: 'Internal Server Error!'}) 18 | } 19 | 20 | const Routes = function () { 21 | const router = express.Router() 22 | 23 | router.get('/', (req, res) => { 24 | console.log('GET /') 25 | 26 | res.render('index', { 27 | userIdentity: email, 28 | clientConfig: { 29 | clientApplicationId: clientApplicationId, 30 | clientPublicKey: clientPublicKey 31 | } 32 | }) 33 | }) 34 | 35 | router.get('/vouchers.json', (req, res) => { 36 | console.log('GET /vouchers.json') 37 | 38 | voucherifyService.getValidVouchers() 39 | .then((result) => { 40 | res.json(result) 41 | }) 42 | .catch((err) => prepareUnhandledErrorResponse(err, res)) 43 | }) 44 | 45 | router.post('/redeem', (req, res) => { 46 | console.log('POST /redeem', req.body) 47 | 48 | const voucherCode = req.body.voucher_code 49 | const userTrackingId = req.body.tracking_id 50 | 51 | voucherifyService.redeemVoucher(voucherCode, userTrackingId) 52 | .then((result) => { 53 | res.json(result) 54 | }) 55 | .catch((err) => prepareUnhandledErrorResponse(err, res)) 56 | }) 57 | 58 | return router 59 | } 60 | 61 | module.exports = Routes 62 | -------------------------------------------------------------------------------- /lib/voucherifyService.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const _ = require('lodash') 4 | const config = require('config').get('voucherifyNodeJsExampleApp') 5 | const moment = require('moment') 6 | const Promise = require('bluebird') 7 | const voucherifyClient = require('voucherify') 8 | 9 | const applicationKeys = config.get('applicationKeys') 10 | 11 | const testVouchersCategory = config.get('testVouchersCategory') 12 | const numberOfSuppliedTestVouchers = config.get('numberOfSuppliedTestVouchers') 13 | 14 | const voucherify = voucherifyClient({ 15 | applicationId: process.env.APPLICATION_ID || applicationKeys.applicationId, 16 | clientSecretKey: process.env.APPLICATION_SECRET_KEY || applicationKeys.applicationSecretKey 17 | }) 18 | 19 | const isVoucherRedeemed = (voucher) => { 20 | return _.get(voucher, 'redemption.quantity') === _.get(voucher, 'redemption.redeemed_quantity') 21 | } 22 | 23 | function VoucherService () { 24 | this.createRandomVoucher = function () { 25 | return voucherify.create(this.generateVoucherBody()) 26 | .then((newVoucher) => { 27 | console.log('[VoucherifyService] New voucher: %s', _.get(newVoucher, 'code')) 28 | return newVoucher 29 | }) 30 | .catch((err) => { 31 | console.log('[VoucherifyService] Error: %s', err) 32 | }) 33 | } 34 | 35 | this.getVouchers = function () { 36 | return voucherify.list({category: testVouchersCategory}) 37 | } 38 | 39 | this.getValidVouchers = function () { 40 | return this.getVouchers() 41 | .then((vouchers) => _.filter(vouchers, (voucher) => !isVoucherRedeemed(voucher))) 42 | } 43 | 44 | this.redeemVoucher = function (voucherCode, userTrackingId) { 45 | return voucherify.redeem(voucherCode, userTrackingId) 46 | .then((result) => { 47 | const voucher = _.get(result, 'voucher') 48 | 49 | if (_.isEmpty(voucher)) { 50 | return Promise.reject(new Error('No voucher object after redemption')) 51 | } 52 | 53 | if (isVoucherRedeemed(voucher)) { 54 | return this.createRandomVoucher() 55 | } 56 | 57 | return voucher 58 | }) 59 | } 60 | 61 | this.generateVoucherBody = function () { 62 | const amount = { 63 | type: 'AMOUNT', 64 | amount_off: _.random(10.00, 40.00, true).toFixed(2) * 100 // 10.00 = 1000 65 | } 66 | 67 | const percent = { 68 | type: 'PERCENT', 69 | percent_off: _.random(10, 100) 70 | } 71 | 72 | const unit = { 73 | type: 'UNIT', 74 | unit_type: 'time', 75 | unit_off: 1 76 | } 77 | 78 | return { 79 | discount: _.sample([amount, percent, unit]), 80 | category: testVouchersCategory, 81 | redemption: ({ 82 | quantity: _.random(1, 5), 83 | redeemed_quantity: 0, 84 | redemption_entries: [] 85 | }), 86 | active: true, 87 | start_date: moment().toISOString() 88 | } 89 | } 90 | 91 | this.init = function () { 92 | return this.getValidVouchers() 93 | .then((vouchers) => { 94 | if (_.isEmpty(vouchers)) { 95 | return Promise.all(_.times(numberOfSuppliedTestVouchers, this.createRandomVoucher.bind(this))) 96 | } 97 | 98 | if (_.size(vouchers) < numberOfSuppliedTestVouchers){ 99 | const nbOfMissingVouchers = numberOfSuppliedTestVouchers - _.size(vouchers) 100 | return Promise.all(_.times(nbOfMissingVouchers, this.createRandomVoucher.bind(this))) 101 | } 102 | }) 103 | } 104 | 105 | this.init() 106 | 107 | return this 108 | } 109 | 110 | module.exports = new VoucherService() 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Voucherify - Node.js SDK sample application 2 | 3 | ## Overview 4 | 5 | This sample application shows the [basic workflow](https://voucherify.readme.io/docs/voucher-lifecycle) of Voucherify and presents the supported [voucher types](https://voucherify.readme.io/docs/vouchers). You can try out the [Live Version](https://voucherify-sample-nodejs.herokuapp.com/) or deploy an instance bound to your [account](https://app.voucherify.io/#/signup?plan=standard) through Heroku button. 6 | 7 | Implemented with our [Node.js SDK](https://voucherify.readme.io/docs/nodejs-tutorial) and [Voucheriy.js](https://voucherify.readme.io/docs/voucherifyjs) client library. 8 | 9 | --- 10 | [Voucherify](http://voucherify.io?utm_source=github&utm_medium=demo&utm_campaign=acq) is an API-first platform for software developers who are dissatisfied with high-maintenance custom coupon software. Our product is a coupon infrastructure through API that provides a quicker way to build coupon generation, distribution and tracking. Unlike legacy coupon software we have: 11 | 12 | * an API-first SaaS platform that enables customisation of every aspect of coupon campaigns 13 | * a management console that helps cut down maintenance and reporting overhead 14 | * an infrastructure to scale up coupon activity in no time 15 | 16 |  17 | 18 | ## Setup 19 | 20 | It is really simple to setup this app. Only what you need to do is follow the steps listed below: 21 | 22 | 1. You need a set of *Application Keys* and *Client-side Keys* to connect with **Voucherify Platform**. Visit App. 23 | 24 | 2. After signing up you need also add your domain to Voucherify's whitelist. 25 | When you go to configuration view of Voucherify account, "Your website URL" is used for allowing client requests only from given domain. You have to put there your website url or set * if you want to enable requests from any origin. 26 | 27 |  28 | 29 | 3. Press this button to create a Heroku app 30 | 31 | [](https://heroku.com/deploy?template=https://github.com/voucherifyio/voucherify-nodejs-example) 32 | 33 | Wait until the Deploy Window is open. 34 | 35 | 4. After opening the Deploy Window, please go to the [**Configuration**](https://app.voucherify.io/#/app/configuration) page. 36 | 37 | Copy App Keys from the Configuration page and paste these keys into proper input fields in the Deploy Window. 38 | 39 |  40 | 41 | 5. In the Deploy Window after filling all required inputs click a Deploy Button located on the end of page. Wait until the Deploying Process is finish. 42 | 43 |  44 | 45 | 6. After finishing process you can go to the Manage Panel or visit the Voucherify Example page. 46 | 47 |  48 | 49 | 50 | ## Commands 51 | 52 | * `$ npm run start` - runs the application 53 | 54 | ## Help 55 | 56 | * Found a bug? Have a suggestion for improvement? Want to tell us we're awesome? [**Submit an issue**](https://github.com/voucherifyio/voucherify-nodejs-example/issues/new) 57 | * Trouble with your integration? Contact [**Voucherify Support**](https://voucherify.readme.io/docs/support) / [**support@voucherify.io**](mailto:support@voucherify.io) 58 | * Want to contribute? [**Submit a pull request**](https://github.com/voucherifyio/voucherify-nodejs-example/compare) 59 | 60 | ## Disclaimer 61 | 62 | This code is provided as is and is only intended to be used for illustration purposes. This code is not production-ready and is not meant to be used in a production environment. This repository is to be used as a tool to help developers learn how to integrate with Voucherify. Any use of this repository or any of its code in a production environment is highly discouraged. 63 | -------------------------------------------------------------------------------- /views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
18 |
26 | 43 | This sample application presents Voucherify's basic workflow. Follow these steps: 44 |
45 |