From 55c706a3a162c2b70534a9a249467ec2b9dbccc9 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 18:45:17 +0100 Subject: [PATCH 001/112] format package.json --- package.json | 75 ++++++++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index 337ac0e..2a2c32a 100644 --- a/package.json +++ b/package.json @@ -1,43 +1,36 @@ { - "name": "voucherify", - "version": "1.23.1", - - "homepage": "http://www.voucherify.io", - "description": "Node.js SDK for Voucherify.", - - "author": "rspective", - "license": "MIT", - "main": "voucherify.js", - - "repository": { - "type": "git", - "url": "https://github.com/rspective/voucherify-nodejs-sdk.git" - }, - "bugs": { - "url": "https://github.com/rspective/voucherify-nodejs-sdk/issues", - "email": "dev@rspective.pl" - }, - - "keywords": [ - "voucherify", - "voucher", - "coupon", - "gift card", - "referral program", - "sdk", - "saas" - ], - - "dependencies": { - "request": "~2.54.0", - "when": "~3.7.3" - }, - - "devDependencies": { - "jasmine-node": "~1.14.5" - }, - - "scripts": { - "test": "./node_modules/.bin/jasmine-node ./test" - } + "name": "voucherify", + "version": "1.23.1", + "homepage": "http://www.voucherify.io", + "description": "Node.js SDK for Voucherify.", + "author": "rspective", + "license": "MIT", + "main": "voucherify.js", + "repository": { + "type": "git", + "url": "https://github.com/rspective/voucherify-nodejs-sdk.git" + }, + "bugs": { + "url": "https://github.com/rspective/voucherify-nodejs-sdk/issues", + "email": "dev@rspective.pl" + }, + "keywords": [ + "voucherify", + "voucher", + "coupon", + "gift card", + "referral program", + "sdk", + "saas" + ], + "dependencies": { + "request": "~2.54.0", + "when": "~3.7.3" + }, + "devDependencies": { + "jasmine-node": "~1.14.5", + }, + "scripts": { + "test": "./node_modules/.bin/jasmine-node ./test" + } } From 6ec20b4fa3061b55610d738b8b524e1b76f264c2 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 18:46:51 +0100 Subject: [PATCH 002/112] Introduce standardjs One JavaScript Style Guide to Rule Them All! --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 2a2c32a..6f7991f 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ }, "devDependencies": { "jasmine-node": "~1.14.5", + "standard": "^8.6.0" }, "scripts": { "test": "./node_modules/.bin/jasmine-node ./test" From 4f6f65b6aa8a80338a7569fcc5923c7a8bc9465e Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 18:48:42 +0100 Subject: [PATCH 003/112] drop semicolons --- examples/gift-voucher-example.js | 26 +-- examples/product.js | 28 +-- test/utils.spec.js | 86 ++++----- test/voucherify.spec.js | 12 +- utils.js | 74 ++++---- voucherify.js | 304 +++++++++++++++---------------- 6 files changed, 265 insertions(+), 265 deletions(-) diff --git a/examples/gift-voucher-example.js b/examples/gift-voucher-example.js index c7f201c..cc9970a 100644 --- a/examples/gift-voucher-example.js +++ b/examples/gift-voucher-example.js @@ -3,9 +3,9 @@ const voucherifyClient = require('../voucherify') var voucherify = voucherifyClient({ applicationId: "c70a6f00-cf91-4756-9df5-47628850002b", clientSecretKey: "3266b9f8-e246-4f79-bdf0-833929b1380c" -}); +}) -var voucher_code; +var voucher_code voucherify.create({ type: "GIFT_VOUCHER", @@ -17,22 +17,22 @@ voucherify.create({ expiration_date: "2016-12-31T23:59:59Z" }) .then(function (result) { - console.log("Voucher %s created. Redeeming...", result.code); - voucher_code = result.code; - return voucherify.redeem({voucher: result.code, order: {amount: 5000}}, "tester"); + console.log("Voucher %s created. Redeeming...", result.code) + voucher_code = result.code + return voucherify.redeem({voucher: result.code, order: {amount: 5000}}, "tester") }) .then(function (result) { - console.log("Voucher %s redeemed. Redemption id: %s, Rolling back...", result.voucher.code, result.id); - return voucherify.rollback(result.id, "just so", "tester"); + console.log("Voucher %s redeemed. Redemption id: %s, Rolling back...", result.voucher.code, result.id) + return voucherify.rollback(result.id, "just so", "tester") }) .then(function (result) { - console.log("Redemption %s rolled back. Rollback id: %s", result.redemption, result.id); - console.log(JSON.stringify(result, null, 4)); - return voucherify.delete(voucher_code, { force:true }); + console.log("Redemption %s rolled back. Rollback id: %s", result.redemption, result.id) + console.log(JSON.stringify(result, null, 4)) + return voucherify.delete(voucher_code, { force:true }) }) .then(function (result) { - console.log("Voucher %s deleted. Result: %j", voucher_code, result); + console.log("Voucher %s deleted. Result: %j", voucher_code, result) }) .catch(function (error) { - console.error("Error: %s", error); - }); \ No newline at end of file + console.error("Error: %s", error) + }) diff --git a/examples/product.js b/examples/product.js index 33203ab..75dd572 100644 --- a/examples/product.js +++ b/examples/product.js @@ -1,6 +1,6 @@ 'use strict' -const voucherifyClient = require('../voucherify'); +const voucherifyClient = require('../voucherify') const voucherify = voucherifyClient({ applicationId: "c70a6f00-cf91-4756-9df5-47628850002b", @@ -18,7 +18,7 @@ const payload = { ] } -let skuId = null; +let skuId = null console.log("==== CREATE ====") voucherify.product.create(payload) @@ -29,7 +29,7 @@ voucherify.product.create(payload) return voucherify.product.get(product.id) .then((result) => { console.log("Result: ", result) - return ; + return }) .then(() => { console.log("==== CREATE - SKU ====") @@ -48,8 +48,8 @@ voucherify.product.create(payload) console.log("Result: ", sku) console.log("==== UPDATE - SKU ====") - sku.sku = "eur"; - sku.price = 1000; + sku.sku = "eur" + sku.price = 1000 return voucherify.product.sku.update(product.id, sku) }) @@ -57,17 +57,17 @@ voucherify.product.create(payload) .then((sku) => { console.log("Result: ", sku) - skuId = sku.id; + skuId = sku.id - return product; - }); + return product + }) }) }) .then((product) => { console.log("==== UPDATE ====") - product.metadata = product.metadata || {}; - product.metadata.type = "premium"; + product.metadata = product.metadata || {} + product.metadata.type = "premium" return voucherify.product.update(product) .then((result) => { @@ -77,7 +77,7 @@ voucherify.product.create(payload) }) .then((product) => { if (!skuId) { - return product; + return product } console.log("==== DELETE - SKU ====") @@ -91,8 +91,8 @@ voucherify.product.create(payload) return product }) .then((product) => { - skuId = null; - return product; + skuId = null + return product }) }) }) @@ -109,4 +109,4 @@ voucherify.product.create(payload) }) .catch((err) => { console.error("Error: ", err, err.stack) - }) \ No newline at end of file + }) diff --git a/test/utils.spec.js b/test/utils.spec.js index 2f6c1ed..ffa5053 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -1,118 +1,118 @@ -var utils = require('../utils.js'); +var utils = require('../utils.js') describe('utils', function(){ // ------ calculateDiscount ------ // it('should calculate amount discount', function(){ - var basePrice = 50; + var basePrice = 50 var voucher = { discount: { type: "AMOUNT", amount_off: 1000 // 10.00 } - }; - var discount = utils.calculateDiscount(basePrice, voucher); + } + var discount = utils.calculateDiscount(basePrice, voucher) - expect(discount).toBe(10.00); - }); + expect(discount).toBe(10.00) + }) it('should calculate percent discount', function(){ - var basePrice = 50; + var basePrice = 50 var voucher = { discount: { type: "PERCENT", percent_off: 10.00 } - }; - var discount = utils.calculateDiscount(basePrice, voucher); + } + var discount = utils.calculateDiscount(basePrice, voucher) - expect(discount).toBe(5.00); - }); + expect(discount).toBe(5.00) + }) it('should calculate unit discount', function(){ - var basePrice = 50; - var unitPrice = 20; + var basePrice = 50 + var unitPrice = 20 var voucher = { discount: { type: "UNIT", unit_off: 1.00 } - }; - var discount = utils.calculateDiscount(basePrice, voucher, unitPrice); + } + var discount = utils.calculateDiscount(basePrice, voucher, unitPrice) - expect(discount).toBe(20.00); - }); + expect(discount).toBe(20.00) + }) it('should fail to calculate discount for gift voucher', function(){ - var basePrice = 50; - var unitPrice = 20; + var basePrice = 50 + var unitPrice = 20 var voucher = { gift: { amount: 1000 } - }; + } expect(function() { utils.calculateDiscount(basePrice, voucher) - }).toThrow(new Error("Unsupported voucher type.")); - }); + }).toThrow(new Error("Unsupported voucher type.")) + }) // ------ calculatePrice ------ // it('should calculate new price with amount discount', function(){ - var basePrice = 50; + var basePrice = 50 var voucher = { discount: { type: "AMOUNT", amount_off: 1000 // 10.00 } - }; - var discount = utils.calculatePrice(basePrice, voucher); + } + var discount = utils.calculatePrice(basePrice, voucher) - expect(discount).toBe(40.00); - }); + expect(discount).toBe(40.00) + }) it('should calculate new price with percent discount', function(){ - var basePrice = 50; + var basePrice = 50 var voucher = { discount: { type: "PERCENT", percent_off: 10.00 } - }; - var discount = utils.calculatePrice(basePrice, voucher); + } + var discount = utils.calculatePrice(basePrice, voucher) - expect(discount).toBe(45.00); - }); + expect(discount).toBe(45.00) + }) it('should calculate new price with unit discount', function(){ - var basePrice = 50; - var unitPrice = 20; + var basePrice = 50 + var unitPrice = 20 var voucher = { discount: { type: "UNIT", unit_off: 1.00 } - }; - var discount = utils.calculatePrice(basePrice, voucher, unitPrice); + } + var discount = utils.calculatePrice(basePrice, voucher, unitPrice) - expect(discount).toBe(30.00); - }); + expect(discount).toBe(30.00) + }) it('should fail to calculate price for gift voucher', function(){ - var basePrice = 50; + var basePrice = 50 var voucher = { gift: { amount: 1000 } - }; + } expect(function() { utils.calculatePrice(basePrice, voucher) - }).toThrow(new Error("Unsupported voucher type.")); - }); + }).toThrow(new Error("Unsupported voucher type.")) + }) -}); \ No newline at end of file +}) diff --git a/test/voucherify.spec.js b/test/voucherify.spec.js index a0d08c9..2f86cf5 100644 --- a/test/voucherify.spec.js +++ b/test/voucherify.spec.js @@ -1,4 +1,4 @@ -var voucherifyClient = require('../voucherify.js'); +var voucherifyClient = require('../voucherify.js') describe('voucherify', function() { @@ -7,15 +7,15 @@ describe('voucherify', function() { voucherifyClient({ clientSecretKey: "CLIENT-SECRET-KEY" }) - }).toThrow(new Error("Missing required option 'applicationId'")); - }); + }).toThrow(new Error("Missing required option 'applicationId'")) + }) it('should detect missing clientSecretKey', function () { expect(function () { voucherifyClient({ applicationId: "APPLICATION-ID" }) - }).toThrow(new Error("Missing required option 'clientSecretKey'")); - }); + }).toThrow(new Error("Missing required option 'clientSecretKey'")) + }) -}); +}) diff --git a/utils.js b/utils.js index 7e1f7fd..7acbdd0 100644 --- a/utils.js +++ b/utils.js @@ -1,86 +1,86 @@ -'use strict'; +'use strict' function roundMoney(value) { - return Math.round(value * (100 + 0.001)) / 100; + return Math.round(value * (100 + 0.001)) / 100 } function validatePercentDiscount(discount) { if (!discount || discount < 0 || discount > 100) { - throw new Error('Invalid voucher, percent discount should be between 0-100.'); + throw new Error('Invalid voucher, percent discount should be between 0-100.') } } function validateAmountDiscount(discount) { if (!discount || discount < 0) { - throw new Error("Invalid voucher, amount discount must be higher than zero."); + throw new Error("Invalid voucher, amount discount must be higher than zero.") } } function validateUnitDiscount(discount) { if (!discount || discount < 0) { - throw new Error("Invalid voucher, unit discount must be higher than zero."); + throw new Error("Invalid voucher, unit discount must be higher than zero.") } } module.exports = { calculatePrice: function (basePrice, voucher, unitPrice) { - var e = 100; // Number of digits after the decimal separator. - var discount; + var e = 100 // Number of digits after the decimal separator. + var discount if (!voucher.discount) { - throw new Error("Unsupported voucher type."); + throw new Error("Unsupported voucher type.") } if (voucher.discount.type === 'PERCENT') { - discount = voucher.discount.percent_off; - validatePercentDiscount(discount); - var priceDiscount = basePrice * (discount / 100); - return roundMoney(basePrice - priceDiscount); + discount = voucher.discount.percent_off + validatePercentDiscount(discount) + var priceDiscount = basePrice * (discount / 100) + return roundMoney(basePrice - priceDiscount) } else if (voucher.discount.type === 'AMOUNT') { - discount = voucher.discount.amount_off / e; - validateAmountDiscount(discount); - var newPrice = basePrice - discount; - return roundMoney(newPrice > 0 ? newPrice : 0); + discount = voucher.discount.amount_off / e + validateAmountDiscount(discount) + var newPrice = basePrice - discount + return roundMoney(newPrice > 0 ? newPrice : 0) } else if (voucher.discount.type === 'UNIT') { - discount = voucher.discount.unit_off; - validateUnitDiscount(discount); - var newPrice = basePrice - unitPrice * discount; - return roundMoney(newPrice > 0 ? newPrice : 0); + discount = voucher.discount.unit_off + validateUnitDiscount(discount) + var newPrice = basePrice - unitPrice * discount + return roundMoney(newPrice > 0 ? newPrice : 0) } else { - throw new Error("Unsupported discount type."); + throw new Error("Unsupported discount type.") } }, calculateDiscount: function(basePrice, voucher, unitPrice) { - var e = 100; // Number of digits after the decimal separator. - var discount; + var e = 100 // Number of digits after the decimal separator. + var discount if (!voucher.discount) { - throw new Error("Unsupported voucher type."); + throw new Error("Unsupported voucher type.") } if (voucher.discount.type === 'PERCENT') { - discount = voucher.discount.percent_off; - validatePercentDiscount(discount); - return roundMoney(basePrice * (discount/100)); + discount = voucher.discount.percent_off + validatePercentDiscount(discount) + return roundMoney(basePrice * (discount/100)) } else if (voucher.discount.type === 'AMOUNT') { - discount = voucher.discount.amount_off / e; - validateAmountDiscount(discount); - var newPrice = basePrice - discount; - return roundMoney(newPrice > 0 ? discount : basePrice); + discount = voucher.discount.amount_off / e + validateAmountDiscount(discount) + var newPrice = basePrice - discount + return roundMoney(newPrice > 0 ? discount : basePrice) } else if (voucher.discount.type === 'UNIT') { - discount = voucher.discount.unit_off; - validateUnitDiscount(discount); - var priceDiscount = unitPrice * discount; - return roundMoney(priceDiscount > basePrice ? basePrice : priceDiscount); + discount = voucher.discount.unit_off + validateUnitDiscount(discount) + var priceDiscount = unitPrice * discount + return roundMoney(priceDiscount > basePrice ? basePrice : priceDiscount) } else { - throw new Error("Unsupported discount type."); + throw new Error("Unsupported discount type.") } } -}; \ No newline at end of file +} diff --git a/voucherify.js b/voucherify.js index 46fe705..7d068ea 100644 --- a/voucherify.js +++ b/voucherify.js @@ -1,60 +1,60 @@ -"use strict"; +"use strict" -var util = require("util"); +var util = require("util") -var request = require("request"); -var when = require("when"); +var request = require("request") +var when = require("when") -var backendUrl = "https://api.voucherify.io/v1"; +var backendUrl = "https://api.voucherify.io/v1" module.exports = function(options) { var headers = { "X-App-Id": requiredOption("applicationId"), "X-App-Token": requiredOption("clientSecretKey"), "X-Voucherify-Channel": "Node.js-SDK" - }; + } function requiredOption(name) { if (!options[name]) { - throw new Error("Missing required option '" + name + "'"); + throw new Error("Missing required option '" + name + "'") } - return options[name]; + return options[name] } function errorMessage(statusCode, body) { - body = body || {}; + body = body || {} body.toString = function() { - return util.format("Unexpected status code: %d - Details: %j", statusCode, body); - }; - return body; + return util.format("Unexpected status code: %d - Details: %j", statusCode, body) + } + return body } function prepare(callback) { - var deferred = when.defer(); + var deferred = when.defer() if (typeof(callback) === "function") { return { callback: function(error, res, body) { if (error || res.statusCode >= 400) { - callback(error || errorMessage(res.statusCode, body)); - return; + callback(error || errorMessage(res.statusCode, body)) + return } - callback(null, body); + callback(null, body) } - }; + } } else { return { promise: deferred.promise, callback: function(error, res, body) { if (error || res.statusCode >= 400) { - deferred.reject(error || errorMessage(res.statusCode, body)); - return; + deferred.reject(error || errorMessage(res.statusCode, body)) + return } - deferred.resolve(body); + deferred.resolve(body) } - }; + } } } @@ -63,104 +63,104 @@ module.exports = function(options) { * List vouchers. Sample query: { limit: 100, skip: 200, category: "Loyalty" } */ list: function(query, callback) { - var url = util.format("%s/vouchers/", backendUrl); - var handler = prepare(callback); + var url = util.format("%s/vouchers/", backendUrl) + var handler = prepare(callback) - request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback); + request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) - return handler.promise; + return handler.promise }, get: function(code, callback) { - var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(code)); - var handler = prepare(callback); + var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(code)) + var handler = prepare(callback) - request.get({ url: url, headers: headers, json: true }, handler.callback); + request.get({ url: url, headers: headers, json: true }, handler.callback) - return handler.promise; + return handler.promise }, create: function(voucher, callback) { - var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher.code || "")); - var handler = prepare(callback); + var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher.code || "")) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: voucher }, handler.callback); + request.post({ url: url, headers: headers, json: voucher }, handler.callback) - return handler.promise; + return handler.promise }, delete: function(voucher_code, params, callback) { if (typeof(params) === "undefined") { - params = {}; + params = {} } if (typeof(params) === "function") { - callback = params; - params = {}; + callback = params + params = {} } - var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher_code || "")); - if (params.force) { url += "?force=true"; } + var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher_code || "")) + if (params.force) { url += "?force=true" } - var handler = prepare(callback); + var handler = prepare(callback) - request.del({ url: url, headers: headers }, handler.callback); + request.del({ url: url, headers: headers }, handler.callback) - return handler.promise; + return handler.promise }, update: function(voucher, callback) { - var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher.code)); - var handler = prepare(callback); + var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher.code)) + var handler = prepare(callback) - request.put({ url: url, headers: headers, json: voucher }, handler.callback); + request.put({ url: url, headers: headers, json: voucher }, handler.callback) - return handler.promise; + return handler.promise }, enable: function(code, callback) { - var url = util.format("%s/vouchers/%s/enable", backendUrl, encodeURIComponent(code)); - var handler = prepare(callback); + var url = util.format("%s/vouchers/%s/enable", backendUrl, encodeURIComponent(code)) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: true }, handler.callback); + request.post({ url: url, headers: headers, json: true }, handler.callback) - return handler.promise; + return handler.promise }, disable: function(code, callback) { - var url = util.format("%s/vouchers/%s/disable", backendUrl, encodeURIComponent(code)); - var handler = prepare(callback); + var url = util.format("%s/vouchers/%s/disable", backendUrl, encodeURIComponent(code)) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: true }, handler.callback); + request.post({ url: url, headers: headers, json: true }, handler.callback) - return handler.promise; + return handler.promise }, validate: function(code, context, callback) { if (typeof(context) === "undefined") { - context = {}; + context = {} } if (typeof(context) === "function") { - callback = context; - context = {}; + callback = context + context = {} } - var handler = prepare(callback); - var url = util.format("%s/vouchers/%s/validate", backendUrl, encodeURIComponent(code)); + var handler = prepare(callback) + var url = util.format("%s/vouchers/%s/validate", backendUrl, encodeURIComponent(code)) - request.post({ url: url, headers: headers, json: context }, handler.callback); + request.post({ url: url, headers: headers, json: context }, handler.callback) - return handler.promise; + return handler.promise }, redemption: function(code, callback) { - var url = util.format("%s/vouchers/%s/redemption", backendUrl, encodeURIComponent(code)); - var handler = prepare(callback); + var url = util.format("%s/vouchers/%s/redemption", backendUrl, encodeURIComponent(code)) + var handler = prepare(callback) - request.get({ url: url, headers: headers, json: true }, handler.callback); + request.get({ url: url, headers: headers, json: true }, handler.callback) - return handler.promise; + return handler.promise }, /* @@ -174,214 +174,214 @@ module.exports = function(options) { * } */ redemptions: function(query, callback) { - var url = util.format("%s/redemptions/", backendUrl); - var handler = prepare(callback); + var url = util.format("%s/redemptions/", backendUrl) + var handler = prepare(callback) - request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback); + request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) - return handler.promise; + return handler.promise }, redeem: function(code, trackingId, callback) { - var context = {}; + var context = {} if (typeof(code) === "object") { - context = code; - code = context.voucher; - delete context.voucher; + context = code + code = context.voucher + delete context.voucher } // No `tracking_id` passed here, // use callback from 2n argument. if (typeof(trackingId) === "function") { - callback = trackingId; - trackingId = undefined; + callback = trackingId + trackingId = undefined } - var handler = prepare(callback); - var url = util.format("%s/vouchers/%s/redemption", backendUrl, encodeURIComponent(code)); + var handler = prepare(callback) + var url = util.format("%s/vouchers/%s/redemption", backendUrl, encodeURIComponent(code)) // If `tracking_id` passed, use it in query string. if (typeof(trackingId) === "string" && trackingId) { - url += "?tracking_id=" + encodeURIComponent(trackingId); + url += "?tracking_id=" + encodeURIComponent(trackingId) } - request.post({ url: url, headers: headers, json: context }, handler.callback); + request.post({ url: url, headers: headers, json: context }, handler.callback) - return handler.promise; + return handler.promise }, rollback: function(redemptionId, data, callback) { if (typeof(data) === "function") { - callback = data; - data = undefined; + callback = data + data = undefined } - var qs = {}; - var payload = {}; + var qs = {} + var payload = {} // If `reason` passed, use it in query string. if (typeof(data) === "string") { - qs["reason"] = encodeURIComponent(data); + qs["reason"] = encodeURIComponent(data) } if (typeof(data) === "object") { - qs["reason"] = data["reason"] || undefined; - qs["tracking_id"] = data["tracking_id"] || undefined; - payload["customer"] = data["customer"] || undefined; + qs["reason"] = data["reason"] || undefined + qs["tracking_id"] = data["tracking_id"] || undefined + payload["customer"] = data["customer"] || undefined } - var handler = prepare(callback); - var url = util.format("%s/redemptions/%s/rollback", backendUrl, encodeURIComponent(redemptionId)); + var handler = prepare(callback) + var url = util.format("%s/redemptions/%s/rollback", backendUrl, encodeURIComponent(redemptionId)) - request.post({ url: url, headers: headers, qs: qs, body: payload, json: true }, handler.callback); + request.post({ url: url, headers: headers, qs: qs, body: payload, json: true }, handler.callback) - return handler.promise; + return handler.promise }, publish: function(campaignName, callback) { - var url = util.format("%s/vouchers/publish", backendUrl); - var payload = {}; + var url = util.format("%s/vouchers/publish", backendUrl) + var payload = {} if (typeof(campaignName) === "string") { - url += "?campaign=" + encodeURIComponent(campaignName); + url += "?campaign=" + encodeURIComponent(campaignName) } if (typeof(campaignName) === "object") { - payload = campaignName; + payload = campaignName } - var handler = prepare(callback); + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: payload }, handler.callback); + request.post({ url: url, headers: headers, json: payload }, handler.callback) - return handler.promise; + return handler.promise }, campaign: { voucher: { create: function(campaignName, voucher, callback) { - var url = util.format("%s/campaigns/%s/vouchers", backendUrl, encodeURIComponent(campaignName || "")); - var handler = prepare(callback); + var url = util.format("%s/campaigns/%s/vouchers", backendUrl, encodeURIComponent(campaignName || "")) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: voucher || {} }, handler.callback); + request.post({ url: url, headers: headers, json: voucher || {} }, handler.callback) - return handler.promise; + return handler.promise } } }, customer: { create: function(customer, callback) { - var url = util.format("%s/customers", backendUrl); - var handler = prepare(callback); + var url = util.format("%s/customers", backendUrl) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: customer }, handler.callback); + request.post({ url: url, headers: headers, json: customer }, handler.callback) - return handler.promise; + return handler.promise }, get: function(customerId, callback) { - var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customerId || "")); - var handler = prepare(callback); + var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customerId || "")) + var handler = prepare(callback) - request.get({ url: url, headers: headers, json: true }, handler.callback); + request.get({ url: url, headers: headers, json: true }, handler.callback) - return handler.promise; + return handler.promise }, update: function(customer, callback) { - var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customer.id || "")); - var handler = prepare(callback); + var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customer.id || "")) + var handler = prepare(callback) - request.put({ url: url, headers: headers, json: customer }, handler.callback); + request.put({ url: url, headers: headers, json: customer }, handler.callback) - return handler.promise; + return handler.promise }, delete: function(customerId, callback) { - var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customerId || "")); - var handler = prepare(callback); + var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customerId || "")) + var handler = prepare(callback) - request.del({ url: url, headers: headers }, handler.callback); + request.del({ url: url, headers: headers }, handler.callback) - return handler.promise; + return handler.promise } }, product: { create: function (product, callback) { - var url = util.format("%s/products", backendUrl); - var handler = prepare(callback); + var url = util.format("%s/products", backendUrl) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: product }, handler.callback); + request.post({ url: url, headers: headers, json: product }, handler.callback) - return handler.promise; + return handler.promise }, get: function (productId, callback) { - var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(productId || "")); - var handler = prepare(callback); + var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(productId || "")) + var handler = prepare(callback) - request.get({ url: url, headers: headers }, handler.callback); + request.get({ url: url, headers: headers }, handler.callback) - return handler.promise; + return handler.promise }, update: function (product, callback) { - var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(product.id || "")); - var handler = prepare(callback); + var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(product.id || "")) + var handler = prepare(callback) - request.put({ url: url, headers: headers, json: product }, handler.callback); + request.put({ url: url, headers: headers, json: product }, handler.callback) - return handler.promise; + return handler.promise }, delete: function (productId, callback) { - var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(productId || "")); - var handler = prepare(callback); + var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(productId || "")) + var handler = prepare(callback) - request.del({ url: url, headers: headers }, handler.callback); + request.del({ url: url, headers: headers }, handler.callback) - return handler.promise; + return handler.promise }, sku: { create: function (productId, sku, callback) { var url = util.format("%s/products/%s/skus", backendUrl, - encodeURIComponent(productId || "")); - var handler = prepare(callback); + encodeURIComponent(productId || "")) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: sku }, handler.callback); + request.post({ url: url, headers: headers, json: sku }, handler.callback) - return handler.promise; + return handler.promise }, get: function (productId, skuId, callback) { var url = util.format("%s/products/%s/skus/%s", backendUrl, - encodeURIComponent(productId || ""), encodeURIComponent(skuId || "")); - var handler = prepare(callback); + encodeURIComponent(productId || ""), encodeURIComponent(skuId || "")) + var handler = prepare(callback) - request.get({ url: url, headers: headers }, handler.callback); + request.get({ url: url, headers: headers }, handler.callback) - return handler.promise; + return handler.promise }, update: function (productId, sku, callback) { var url = util.format("%s/products/%s/skus/%s", backendUrl, - encodeURIComponent(productId || ""), encodeURIComponent(sku.id || "")); - var handler = prepare(callback); + encodeURIComponent(productId || ""), encodeURIComponent(sku.id || "")) + var handler = prepare(callback) - request.put({ url: url, headers: headers, json: sku }, handler.callback); + request.put({ url: url, headers: headers, json: sku }, handler.callback) - return handler.promise; + return handler.promise }, delete: function (productId, skuId, callback) { var url = util.format("%s/products/%s/skus/%s", backendUrl, - encodeURIComponent(productId || ""), encodeURIComponent(skuId || "")); - var handler = prepare(callback); + encodeURIComponent(productId || ""), encodeURIComponent(skuId || "")) + var handler = prepare(callback) - request.del({ url: url, headers: headers }, handler.callback); + request.del({ url: url, headers: headers }, handler.callback) - return handler.promise; + return handler.promise } } } - }; -}; \ No newline at end of file + } +} From e86b67de10e691c1c63cbcac73cbb063ced5aafd Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 18:55:40 +0100 Subject: [PATCH 004/112] use single quote --- examples/customer.js | 38 ++++----- examples/gift-voucher-example.js | 26 +++---- examples/product.js | 58 +++++++------- test/utils.spec.js | 16 ++-- test/voucherify.spec.js | 4 +- utils.js | 12 +-- voucherify.js | 128 +++++++++++++++---------------- 7 files changed, 141 insertions(+), 141 deletions(-) diff --git a/examples/customer.js b/examples/customer.js index 77f0be6..9d6c2eb 100644 --- a/examples/customer.js +++ b/examples/customer.js @@ -3,53 +3,53 @@ const voucherifyClient = require('../voucherify') const voucherify = voucherifyClient({ - applicationId: "c70a6f00-cf91-4756-9df5-47628850002b", - clientSecretKey: "3266b9f8-e246-4f79-bdf0-833929b1380c" + applicationId: 'c70a6f00-cf91-4756-9df5-47628850002b', + clientSecretKey: '3266b9f8-e246-4f79-bdf0-833929b1380c' }) const payload = { - "name": "John Doe", - "email": "email@example.com", - "description": "Premium user, ACME Inc.", - "metadata": { - "lang": "en" + 'name': 'John Doe', + 'email': 'email@example.com', + 'description': 'Premium user, ACME Inc.', + 'metadata': { + 'lang': 'en' } } -console.log("==== CREATE ====") +console.log('==== CREATE ====') voucherify.customer.create(payload) .then((customer) => { - console.log("New Customer: ", customer) + console.log('New Customer: ', customer) - console.log("==== READ ====") + console.log('==== READ ====') return voucherify.customer.get(customer.id) .then((result) => { - console.log("Result: ", result) + console.log('Result: ', result) return customer }) }) .then((customer) => { - console.log("==== UPDATE ====") + console.log('==== UPDATE ====') - customer.metadata.type = "premium" + customer.metadata.type = 'premium' return voucherify.customer.update(customer) .then((result) => { - console.log("Result: ", result) + console.log('Result: ', result) return customer }) }) .then((customer) => { - console.log("==== DELETE ====") + console.log('==== DELETE ====') return voucherify.customer.delete(customer.id) .then(() => { - console.log("Checking...") + console.log('Checking...') return voucherify.customer.get(customer.id) .catch((err) => { - console.log("Result:", err) + console.log('Result:', err) }) }) }) .catch((err) => { - console.error("Error: ", err, err.stack) - }) \ No newline at end of file + console.error('Error: ', err, err.stack) + }) diff --git a/examples/gift-voucher-example.js b/examples/gift-voucher-example.js index cc9970a..bde8683 100644 --- a/examples/gift-voucher-example.js +++ b/examples/gift-voucher-example.js @@ -1,38 +1,38 @@ const voucherifyClient = require('../voucherify') var voucherify = voucherifyClient({ - applicationId: "c70a6f00-cf91-4756-9df5-47628850002b", - clientSecretKey: "3266b9f8-e246-4f79-bdf0-833929b1380c" + applicationId: 'c70a6f00-cf91-4756-9df5-47628850002b', + clientSecretKey: '3266b9f8-e246-4f79-bdf0-833929b1380c' }) var voucher_code voucherify.create({ - type: "GIFT_VOUCHER", + type: 'GIFT_VOUCHER', gift: { amount: 10000 }, - category: "Node SDK Test", - start_date: "2016-01-01T00:00:00Z", - expiration_date: "2016-12-31T23:59:59Z" + category: 'Node SDK Test', + start_date: '2016-01-01T00:00:00Z', + expiration_date: '2016-12-31T23:59:59Z' }) .then(function (result) { - console.log("Voucher %s created. Redeeming...", result.code) + console.log('Voucher %s created. Redeeming...', result.code) voucher_code = result.code - return voucherify.redeem({voucher: result.code, order: {amount: 5000}}, "tester") + return voucherify.redeem({voucher: result.code, order: {amount: 5000}}, 'tester') }) .then(function (result) { - console.log("Voucher %s redeemed. Redemption id: %s, Rolling back...", result.voucher.code, result.id) - return voucherify.rollback(result.id, "just so", "tester") + console.log('Voucher %s redeemed. Redemption id: %s, Rolling back...', result.voucher.code, result.id) + return voucherify.rollback(result.id, 'just so', 'tester') }) .then(function (result) { - console.log("Redemption %s rolled back. Rollback id: %s", result.redemption, result.id) + console.log('Redemption %s rolled back. Rollback id: %s', result.redemption, result.id) console.log(JSON.stringify(result, null, 4)) return voucherify.delete(voucher_code, { force:true }) }) .then(function (result) { - console.log("Voucher %s deleted. Result: %j", voucher_code, result) + console.log('Voucher %s deleted. Result: %j', voucher_code, result) }) .catch(function (error) { - console.error("Error: %s", error) + console.error('Error: %s', error) }) diff --git a/examples/product.js b/examples/product.js index 75dd572..a6ba8c8 100644 --- a/examples/product.js +++ b/examples/product.js @@ -3,59 +3,59 @@ const voucherifyClient = require('../voucherify') const voucherify = voucherifyClient({ - applicationId: "c70a6f00-cf91-4756-9df5-47628850002b", - clientSecretKey: "3266b9f8-e246-4f79-bdf0-833929b1380c" + applicationId: 'c70a6f00-cf91-4756-9df5-47628850002b', + clientSecretKey: '3266b9f8-e246-4f79-bdf0-833929b1380c' }) const payload = { - name: "Apple iPhone 6", + name: 'Apple iPhone 6', metadata: { - type: "normal" + type: 'normal' }, attributes: [ - "attr_one", - "attr_two" + 'attr_one', + 'attr_two' ] } let skuId = null -console.log("==== CREATE ====") +console.log('==== CREATE ====') voucherify.product.create(payload) .then((product) => { - console.log("New Product: ", product) + console.log('New Product: ', product) - console.log("==== READ ====") + console.log('==== READ ====') return voucherify.product.get(product.id) .then((result) => { - console.log("Result: ", result) - return + console.log('Result: ', result) + return }) .then(() => { - console.log("==== CREATE - SKU ====") + console.log('==== CREATE - SKU ====') var sku = { - sku: "APPLE_IPHONE_6_BLACK" + sku: 'APPLE_IPHONE_6_BLACK' } return voucherify.product.sku.create(product.id, sku) .then((sku) => { - console.log("Result: ", sku) - console.log("==== GET - SKU ====") + console.log('Result: ', sku) + console.log('==== GET - SKU ====') return voucherify.product.sku.get(product.id, sku.id) .then((sku) => { - console.log("Result: ", sku) - console.log("==== UPDATE - SKU ====") + console.log('Result: ', sku) + console.log('==== UPDATE - SKU ====') - sku.sku = "eur" + sku.sku = 'eur' sku.price = 1000 return voucherify.product.sku.update(product.id, sku) }) }) .then((sku) => { - console.log("Result: ", sku) + console.log('Result: ', sku) skuId = sku.id @@ -64,14 +64,14 @@ voucherify.product.create(payload) }) }) .then((product) => { - console.log("==== UPDATE ====") + console.log('==== UPDATE ====') product.metadata = product.metadata || {} - product.metadata.type = "premium" + product.metadata.type = 'premium' return voucherify.product.update(product) .then((result) => { - console.log("Result: ", JSON.stringify(result, null, 2)) + console.log('Result: ', JSON.stringify(result, null, 2)) return product }) }) @@ -80,14 +80,14 @@ voucherify.product.create(payload) return product } - console.log("==== DELETE - SKU ====") + console.log('==== DELETE - SKU ====') return voucherify.product.sku.delete(product.id, skuId) .then(() => { - console.log("Checking...") + console.log('Checking...') return voucherify.product.sku.get(product.id, skuId) .catch((err) => { - console.log("Result:", err) + console.log('Result:', err) return product }) .then((product) => { @@ -97,16 +97,16 @@ voucherify.product.create(payload) }) }) .then((product) => { - console.log("==== DELETE ====") + console.log('==== DELETE ====') return voucherify.product.delete(product.id) .then(() => { - console.log("Checking...") + console.log('Checking...') return voucherify.product.get(product.id) .catch((err) => { - console.log("Result:", err) + console.log('Result:', err) }) }) }) .catch((err) => { - console.error("Error: ", err, err.stack) + console.error('Error: ', err, err.stack) }) diff --git a/test/utils.spec.js b/test/utils.spec.js index ffa5053..af051a8 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -8,7 +8,7 @@ describe('utils', function(){ var basePrice = 50 var voucher = { discount: { - type: "AMOUNT", + type: 'AMOUNT', amount_off: 1000 // 10.00 } } @@ -21,7 +21,7 @@ describe('utils', function(){ var basePrice = 50 var voucher = { discount: { - type: "PERCENT", + type: 'PERCENT', percent_off: 10.00 } } @@ -35,7 +35,7 @@ describe('utils', function(){ var unitPrice = 20 var voucher = { discount: { - type: "UNIT", + type: 'UNIT', unit_off: 1.00 } } @@ -55,7 +55,7 @@ describe('utils', function(){ expect(function() { utils.calculateDiscount(basePrice, voucher) - }).toThrow(new Error("Unsupported voucher type.")) + }).toThrow(new Error('Unsupported voucher type.')) }) // ------ calculatePrice ------ // @@ -64,7 +64,7 @@ describe('utils', function(){ var basePrice = 50 var voucher = { discount: { - type: "AMOUNT", + type: 'AMOUNT', amount_off: 1000 // 10.00 } } @@ -77,7 +77,7 @@ describe('utils', function(){ var basePrice = 50 var voucher = { discount: { - type: "PERCENT", + type: 'PERCENT', percent_off: 10.00 } } @@ -91,7 +91,7 @@ describe('utils', function(){ var unitPrice = 20 var voucher = { discount: { - type: "UNIT", + type: 'UNIT', unit_off: 1.00 } } @@ -111,7 +111,7 @@ describe('utils', function(){ expect(function() { utils.calculatePrice(basePrice, voucher) - }).toThrow(new Error("Unsupported voucher type.")) + }).toThrow(new Error('Unsupported voucher type.')) }) diff --git a/test/voucherify.spec.js b/test/voucherify.spec.js index 2f86cf5..1cd1cd1 100644 --- a/test/voucherify.spec.js +++ b/test/voucherify.spec.js @@ -5,7 +5,7 @@ describe('voucherify', function() { it('should detect missing applicationId', function () { expect(function () { voucherifyClient({ - clientSecretKey: "CLIENT-SECRET-KEY" + clientSecretKey: 'CLIENT-SECRET-KEY' }) }).toThrow(new Error("Missing required option 'applicationId'")) }) @@ -13,7 +13,7 @@ describe('voucherify', function() { it('should detect missing clientSecretKey', function () { expect(function () { voucherifyClient({ - applicationId: "APPLICATION-ID" + applicationId: 'APPLICATION-ID' }) }).toThrow(new Error("Missing required option 'clientSecretKey'")) }) diff --git a/utils.js b/utils.js index 7acbdd0..eccd9f8 100644 --- a/utils.js +++ b/utils.js @@ -12,13 +12,13 @@ function validatePercentDiscount(discount) { function validateAmountDiscount(discount) { if (!discount || discount < 0) { - throw new Error("Invalid voucher, amount discount must be higher than zero.") + throw new Error('Invalid voucher, amount discount must be higher than zero.') } } function validateUnitDiscount(discount) { if (!discount || discount < 0) { - throw new Error("Invalid voucher, unit discount must be higher than zero.") + throw new Error('Invalid voucher, unit discount must be higher than zero.') } } @@ -28,7 +28,7 @@ module.exports = { var discount if (!voucher.discount) { - throw new Error("Unsupported voucher type.") + throw new Error('Unsupported voucher type.') } if (voucher.discount.type === 'PERCENT') { @@ -50,7 +50,7 @@ module.exports = { return roundMoney(newPrice > 0 ? newPrice : 0) } else { - throw new Error("Unsupported discount type.") + throw new Error('Unsupported discount type.') } }, @@ -59,7 +59,7 @@ module.exports = { var discount if (!voucher.discount) { - throw new Error("Unsupported voucher type.") + throw new Error('Unsupported voucher type.') } if (voucher.discount.type === 'PERCENT') { @@ -80,7 +80,7 @@ module.exports = { return roundMoney(priceDiscount > basePrice ? basePrice : priceDiscount) } else { - throw new Error("Unsupported discount type.") + throw new Error('Unsupported discount type.') } } } diff --git a/voucherify.js b/voucherify.js index 7d068ea..d13f005 100644 --- a/voucherify.js +++ b/voucherify.js @@ -1,22 +1,22 @@ -"use strict" +'use strict' -var util = require("util") +var util = require('util') -var request = require("request") -var when = require("when") +var request = require('request') +var when = require('when') -var backendUrl = "https://api.voucherify.io/v1" +var backendUrl = 'https://api.voucherify.io/v1' module.exports = function(options) { var headers = { - "X-App-Id": requiredOption("applicationId"), - "X-App-Token": requiredOption("clientSecretKey"), - "X-Voucherify-Channel": "Node.js-SDK" + 'X-App-Id': requiredOption('applicationId'), + 'X-App-Token': requiredOption('clientSecretKey'), + 'X-Voucherify-Channel': 'Node.js-SDK' } function requiredOption(name) { if (!options[name]) { - throw new Error("Missing required option '" + name + "'") + throw new Error(`Missing required option '${name}'`) } return options[name] } @@ -24,7 +24,7 @@ module.exports = function(options) { function errorMessage(statusCode, body) { body = body || {} body.toString = function() { - return util.format("Unexpected status code: %d - Details: %j", statusCode, body) + return util.format('Unexpected status code: %d - Details: %j', statusCode, body) } return body } @@ -32,7 +32,7 @@ module.exports = function(options) { function prepare(callback) { var deferred = when.defer() - if (typeof(callback) === "function") { + if (typeof(callback) === 'function') { return { callback: function(error, res, body) { if (error || res.statusCode >= 400) { @@ -60,10 +60,10 @@ module.exports = function(options) { return { /* - * List vouchers. Sample query: { limit: 100, skip: 200, category: "Loyalty" } + * List vouchers. Sample query: { limit: 100, skip: 200, category: 'Loyalty' } */ list: function(query, callback) { - var url = util.format("%s/vouchers/", backendUrl) + var url = util.format('%s/vouchers/', backendUrl) var handler = prepare(callback) request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) @@ -72,7 +72,7 @@ module.exports = function(options) { }, get: function(code, callback) { - var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(code)) + var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(code)) var handler = prepare(callback) request.get({ url: url, headers: headers, json: true }, handler.callback) @@ -81,7 +81,7 @@ module.exports = function(options) { }, create: function(voucher, callback) { - var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher.code || "")) + var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code || '')) var handler = prepare(callback) request.post({ url: url, headers: headers, json: voucher }, handler.callback) @@ -90,17 +90,17 @@ module.exports = function(options) { }, delete: function(voucher_code, params, callback) { - if (typeof(params) === "undefined") { + if (typeof(params) === 'undefined') { params = {} } - if (typeof(params) === "function") { + if (typeof(params) === 'function') { callback = params params = {} } - var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher_code || "")) - if (params.force) { url += "?force=true" } + var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher_code || '')) + if (params.force) { url += '?force=true' } var handler = prepare(callback) @@ -110,7 +110,7 @@ module.exports = function(options) { }, update: function(voucher, callback) { - var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher.code)) + var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code)) var handler = prepare(callback) request.put({ url: url, headers: headers, json: voucher }, handler.callback) @@ -119,7 +119,7 @@ module.exports = function(options) { }, enable: function(code, callback) { - var url = util.format("%s/vouchers/%s/enable", backendUrl, encodeURIComponent(code)) + var url = util.format('%s/vouchers/%s/enable', backendUrl, encodeURIComponent(code)) var handler = prepare(callback) request.post({ url: url, headers: headers, json: true }, handler.callback) @@ -128,7 +128,7 @@ module.exports = function(options) { }, disable: function(code, callback) { - var url = util.format("%s/vouchers/%s/disable", backendUrl, encodeURIComponent(code)) + var url = util.format('%s/vouchers/%s/disable', backendUrl, encodeURIComponent(code)) var handler = prepare(callback) request.post({ url: url, headers: headers, json: true }, handler.callback) @@ -137,17 +137,17 @@ module.exports = function(options) { }, validate: function(code, context, callback) { - if (typeof(context) === "undefined") { + if (typeof(context) === 'undefined') { context = {} } - if (typeof(context) === "function") { + if (typeof(context) === 'function') { callback = context context = {} } var handler = prepare(callback) - var url = util.format("%s/vouchers/%s/validate", backendUrl, encodeURIComponent(code)) + var url = util.format('%s/vouchers/%s/validate', backendUrl, encodeURIComponent(code)) request.post({ url: url, headers: headers, json: context }, handler.callback) @@ -155,7 +155,7 @@ module.exports = function(options) { }, redemption: function(code, callback) { - var url = util.format("%s/vouchers/%s/redemption", backendUrl, encodeURIComponent(code)) + var url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) var handler = prepare(callback) request.get({ url: url, headers: headers, json: true }, handler.callback) @@ -168,13 +168,13 @@ module.exports = function(options) { * { * limit: 1000, * page: 0, - * start_date: "2016-04-01T00:00:00", - * end_date: "2016-04-30T23:59:59", - * result: "Success" + * start_date: '2016-04-01T00:00:00', + * end_date: '2016-04-30T23:59:59', + * result: 'Success' * } */ redemptions: function(query, callback) { - var url = util.format("%s/redemptions/", backendUrl) + var url = util.format('%s/redemptions/', backendUrl) var handler = prepare(callback) request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) @@ -184,24 +184,24 @@ module.exports = function(options) { redeem: function(code, trackingId, callback) { var context = {} - if (typeof(code) === "object") { + if (typeof(code) === 'object') { context = code code = context.voucher delete context.voucher } // No `tracking_id` passed here, // use callback from 2n argument. - if (typeof(trackingId) === "function") { + if (typeof(trackingId) === 'function') { callback = trackingId trackingId = undefined } var handler = prepare(callback) - var url = util.format("%s/vouchers/%s/redemption", backendUrl, encodeURIComponent(code)) + var url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) // If `tracking_id` passed, use it in query string. - if (typeof(trackingId) === "string" && trackingId) { - url += "?tracking_id=" + encodeURIComponent(trackingId) + if (typeof(trackingId) === 'string' && trackingId) { + url += '?tracking_id=' + encodeURIComponent(trackingId) } request.post({ url: url, headers: headers, json: context }, handler.callback) @@ -210,7 +210,7 @@ module.exports = function(options) { }, rollback: function(redemptionId, data, callback) { - if (typeof(data) === "function") { + if (typeof(data) === 'function') { callback = data data = undefined } @@ -219,18 +219,18 @@ module.exports = function(options) { var payload = {} // If `reason` passed, use it in query string. - if (typeof(data) === "string") { - qs["reason"] = encodeURIComponent(data) + if (typeof(data) === 'string') { + qs['reason'] = encodeURIComponent(data) } - if (typeof(data) === "object") { - qs["reason"] = data["reason"] || undefined - qs["tracking_id"] = data["tracking_id"] || undefined - payload["customer"] = data["customer"] || undefined + if (typeof(data) === 'object') { + qs['reason'] = data['reason'] || undefined + qs['tracking_id'] = data['tracking_id'] || undefined + payload['customer'] = data['customer'] || undefined } var handler = prepare(callback) - var url = util.format("%s/redemptions/%s/rollback", backendUrl, encodeURIComponent(redemptionId)) + var url = util.format('%s/redemptions/%s/rollback', backendUrl, encodeURIComponent(redemptionId)) request.post({ url: url, headers: headers, qs: qs, body: payload, json: true }, handler.callback) @@ -238,12 +238,12 @@ module.exports = function(options) { }, publish: function(campaignName, callback) { - var url = util.format("%s/vouchers/publish", backendUrl) + var url = util.format('%s/vouchers/publish', backendUrl) var payload = {} - if (typeof(campaignName) === "string") { - url += "?campaign=" + encodeURIComponent(campaignName) + if (typeof(campaignName) === 'string') { + url += '?campaign=' + encodeURIComponent(campaignName) } - if (typeof(campaignName) === "object") { + if (typeof(campaignName) === 'object') { payload = campaignName } var handler = prepare(callback) @@ -256,7 +256,7 @@ module.exports = function(options) { campaign: { voucher: { create: function(campaignName, voucher, callback) { - var url = util.format("%s/campaigns/%s/vouchers", backendUrl, encodeURIComponent(campaignName || "")) + var url = util.format('%s/campaigns/%s/vouchers', backendUrl, encodeURIComponent(campaignName || '')) var handler = prepare(callback) request.post({ url: url, headers: headers, json: voucher || {} }, handler.callback) @@ -268,7 +268,7 @@ module.exports = function(options) { customer: { create: function(customer, callback) { - var url = util.format("%s/customers", backendUrl) + var url = util.format('%s/customers', backendUrl) var handler = prepare(callback) request.post({ url: url, headers: headers, json: customer }, handler.callback) @@ -277,7 +277,7 @@ module.exports = function(options) { }, get: function(customerId, callback) { - var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customerId || "")) + var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) var handler = prepare(callback) request.get({ url: url, headers: headers, json: true }, handler.callback) @@ -286,7 +286,7 @@ module.exports = function(options) { }, update: function(customer, callback) { - var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customer.id || "")) + var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customer.id || '')) var handler = prepare(callback) request.put({ url: url, headers: headers, json: customer }, handler.callback) @@ -295,7 +295,7 @@ module.exports = function(options) { }, delete: function(customerId, callback) { - var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customerId || "")) + var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) var handler = prepare(callback) request.del({ url: url, headers: headers }, handler.callback) @@ -306,7 +306,7 @@ module.exports = function(options) { product: { create: function (product, callback) { - var url = util.format("%s/products", backendUrl) + var url = util.format('%s/products', backendUrl) var handler = prepare(callback) request.post({ url: url, headers: headers, json: product }, handler.callback) @@ -315,7 +315,7 @@ module.exports = function(options) { }, get: function (productId, callback) { - var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(productId || "")) + var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) var handler = prepare(callback) request.get({ url: url, headers: headers }, handler.callback) @@ -324,7 +324,7 @@ module.exports = function(options) { }, update: function (product, callback) { - var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(product.id || "")) + var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(product.id || '')) var handler = prepare(callback) request.put({ url: url, headers: headers, json: product }, handler.callback) @@ -333,7 +333,7 @@ module.exports = function(options) { }, delete: function (productId, callback) { - var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(productId || "")) + var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) var handler = prepare(callback) request.del({ url: url, headers: headers }, handler.callback) @@ -343,8 +343,8 @@ module.exports = function(options) { sku: { create: function (productId, sku, callback) { - var url = util.format("%s/products/%s/skus", backendUrl, - encodeURIComponent(productId || "")) + var url = util.format('%s/products/%s/skus', backendUrl, + encodeURIComponent(productId || '')) var handler = prepare(callback) request.post({ url: url, headers: headers, json: sku }, handler.callback) @@ -353,8 +353,8 @@ module.exports = function(options) { }, get: function (productId, skuId, callback) { - var url = util.format("%s/products/%s/skus/%s", backendUrl, - encodeURIComponent(productId || ""), encodeURIComponent(skuId || "")) + var url = util.format('%s/products/%s/skus/%s', backendUrl, + encodeURIComponent(productId || ''), encodeURIComponent(skuId || '')) var handler = prepare(callback) request.get({ url: url, headers: headers }, handler.callback) @@ -363,8 +363,8 @@ module.exports = function(options) { }, update: function (productId, sku, callback) { - var url = util.format("%s/products/%s/skus/%s", backendUrl, - encodeURIComponent(productId || ""), encodeURIComponent(sku.id || "")) + var url = util.format('%s/products/%s/skus/%s', backendUrl, + encodeURIComponent(productId || ''), encodeURIComponent(sku.id || '')) var handler = prepare(callback) request.put({ url: url, headers: headers, json: sku }, handler.callback) @@ -373,8 +373,8 @@ module.exports = function(options) { }, delete: function (productId, skuId, callback) { - var url = util.format("%s/products/%s/skus/%s", backendUrl, - encodeURIComponent(productId || ""), encodeURIComponent(skuId || "")) + var url = util.format('%s/products/%s/skus/%s', backendUrl, + encodeURIComponent(productId || ''), encodeURIComponent(skuId || '')) var handler = prepare(callback) request.del({ url: url, headers: headers }, handler.callback) From 9a28d72a989b9c0785cba9c61f8a8282961cff34 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 19:06:56 +0100 Subject: [PATCH 005/112] fix other standard.js errors --- examples/gift-voucher-example.js | 62 ++-- examples/product.js | 178 +++++----- test/utils.spec.js | 227 ++++++------ test/voucherify.spec.js | 33 +- utils.js | 22 +- voucherify.js | 582 +++++++++++++++---------------- 6 files changed, 550 insertions(+), 554 deletions(-) diff --git a/examples/gift-voucher-example.js b/examples/gift-voucher-example.js index bde8683..55cec93 100644 --- a/examples/gift-voucher-example.js +++ b/examples/gift-voucher-example.js @@ -1,38 +1,38 @@ const voucherifyClient = require('../voucherify') var voucherify = voucherifyClient({ - applicationId: 'c70a6f00-cf91-4756-9df5-47628850002b', - clientSecretKey: '3266b9f8-e246-4f79-bdf0-833929b1380c' + applicationId: 'c70a6f00-cf91-4756-9df5-47628850002b', + clientSecretKey: '3266b9f8-e246-4f79-bdf0-833929b1380c' }) -var voucher_code +var voucherCode voucherify.create({ - type: 'GIFT_VOUCHER', - gift: { - amount: 10000 - }, - category: 'Node SDK Test', - start_date: '2016-01-01T00:00:00Z', - expiration_date: '2016-12-31T23:59:59Z' - }) - .then(function (result) { - console.log('Voucher %s created. Redeeming...', result.code) - voucher_code = result.code - return voucherify.redeem({voucher: result.code, order: {amount: 5000}}, 'tester') - }) - .then(function (result) { - console.log('Voucher %s redeemed. Redemption id: %s, Rolling back...', result.voucher.code, result.id) - return voucherify.rollback(result.id, 'just so', 'tester') - }) - .then(function (result) { - console.log('Redemption %s rolled back. Rollback id: %s', result.redemption, result.id) - console.log(JSON.stringify(result, null, 4)) - return voucherify.delete(voucher_code, { force:true }) - }) - .then(function (result) { - console.log('Voucher %s deleted. Result: %j', voucher_code, result) - }) - .catch(function (error) { - console.error('Error: %s', error) - }) + type: 'GIFT_VOUCHER', + gift: { + amount: 10000 + }, + category: 'Node SDK Test', + start_date: '2016-01-01T00:00:00Z', + expiration_date: '2016-12-31T23:59:59Z' +}) +.then(function (result) { + console.log('Voucher %s created. Redeeming...', result.code) + voucherCode = result.code + return voucherify.redeem({voucher: result.code, order: {amount: 5000}}, 'tester') +}) +.then(function (result) { + console.log('Voucher %s redeemed. Redemption id: %s, Rolling back...', result.voucher.code, result.id) + return voucherify.rollback(result.id, 'just so', 'tester') +}) +.then(function (result) { + console.log('Redemption %s rolled back. Rollback id: %s', result.redemption, result.id) + console.log(JSON.stringify(result, null, 4)) + return voucherify.delete(voucherCode, { force: true }) +}) +.then(function (result) { + console.log('Voucher %s deleted. Result: %j', voucherCode, result) +}) +.catch(function (error) { + console.error('Error: %s', error) +}) diff --git a/examples/product.js b/examples/product.js index a6ba8c8..00fb5f4 100644 --- a/examples/product.js +++ b/examples/product.js @@ -3,110 +3,110 @@ const voucherifyClient = require('../voucherify') const voucherify = voucherifyClient({ - applicationId: 'c70a6f00-cf91-4756-9df5-47628850002b', - clientSecretKey: '3266b9f8-e246-4f79-bdf0-833929b1380c' + applicationId: 'c70a6f00-cf91-4756-9df5-47628850002b', + clientSecretKey: '3266b9f8-e246-4f79-bdf0-833929b1380c' }) const payload = { - name: 'Apple iPhone 6', - metadata: { - type: 'normal' - }, - attributes: [ - 'attr_one', - 'attr_two' - ] + name: 'Apple iPhone 6', + metadata: { + type: 'normal' + }, + attributes: [ + 'attr_one', + 'attr_two' + ] } let skuId = null console.log('==== CREATE ====') voucherify.product.create(payload) - .then((product) => { - console.log('New Product: ', product) - - console.log('==== READ ====') - return voucherify.product.get(product.id) - .then((result) => { - console.log('Result: ', result) - return - }) - .then(() => { - console.log('==== CREATE - SKU ====') - - var sku = { - sku: 'APPLE_IPHONE_6_BLACK' - } - - return voucherify.product.sku.create(product.id, sku) - .then((sku) => { - console.log('Result: ', sku) - console.log('==== GET - SKU ====') - - return voucherify.product.sku.get(product.id, sku.id) - .then((sku) => { - console.log('Result: ', sku) - console.log('==== UPDATE - SKU ====') - - sku.sku = 'eur' - sku.price = 1000 - - return voucherify.product.sku.update(product.id, sku) - }) - }) - .then((sku) => { - console.log('Result: ', sku) - - skuId = sku.id - - return product - }) - }) +.then((product) => { + console.log('New Product: ', product) + + console.log('==== READ ====') + return voucherify.product.get(product.id) + .then((result) => { + console.log('Result: ', result) + return + }) + .then(() => { + console.log('==== CREATE - SKU ====') + + var sku = { + sku: 'APPLE_IPHONE_6_BLACK' + } + + return voucherify.product.sku.create(product.id, sku) + .then((sku) => { + console.log('Result: ', sku) + console.log('==== GET - SKU ====') + + return voucherify.product.sku.get(product.id, sku.id) + .then((sku) => { + console.log('Result: ', sku) + console.log('==== UPDATE - SKU ====') + + sku.sku = 'eur' + sku.price = 1000 + + return voucherify.product.sku.update(product.id, sku) + }) }) - .then((product) => { - console.log('==== UPDATE ====') + .then((sku) => { + console.log('Result: ', sku) - product.metadata = product.metadata || {} - product.metadata.type = 'premium' + skuId = sku.id - return voucherify.product.update(product) - .then((result) => { - console.log('Result: ', JSON.stringify(result, null, 2)) - return product - }) + return product }) - .then((product) => { - if (!skuId) { - return product - } - - console.log('==== DELETE - SKU ====') - - return voucherify.product.sku.delete(product.id, skuId) - .then(() => { - console.log('Checking...') - return voucherify.product.sku.get(product.id, skuId) - .catch((err) => { - console.log('Result:', err) - return product - }) - .then((product) => { - skuId = null - return product - }) - }) + }) +}) +.then((product) => { + console.log('==== UPDATE ====') + + product.metadata = product.metadata || {} + product.metadata.type = 'premium' + + return voucherify.product.update(product) + .then((result) => { + console.log('Result: ', JSON.stringify(result, null, 2)) + return product + }) +}) +.then((product) => { + if (!skuId) { + return product + } + + console.log('==== DELETE - SKU ====') + + return voucherify.product.sku.delete(product.id, skuId) + .then(() => { + console.log('Checking...') + return voucherify.product.sku.get(product.id, skuId) + .catch((err) => { + console.log('Result:', err) + return product }) .then((product) => { - console.log('==== DELETE ====') - return voucherify.product.delete(product.id) - .then(() => { - console.log('Checking...') - return voucherify.product.get(product.id) - .catch((err) => { - console.log('Result:', err) - }) - }) + skuId = null + return product }) + }) +}) +.then((product) => { + console.log('==== DELETE ====') + return voucherify.product.delete(product.id) + .then(() => { + console.log('Checking...') + return voucherify.product.get(product.id) .catch((err) => { - console.error('Error: ', err, err.stack) + console.log('Result:', err) }) + }) +}) +.catch((err) => { + console.error('Error: ', err, err.stack) +}) diff --git a/test/utils.spec.js b/test/utils.spec.js index af051a8..353e479 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -1,118 +1,115 @@ +/* global describe, it, expect */ var utils = require('../utils.js') -describe('utils', function(){ - - // ------ calculateDiscount ------ // - - it('should calculate amount discount', function(){ - var basePrice = 50 - var voucher = { - discount: { - type: 'AMOUNT', - amount_off: 1000 // 10.00 - } - } - var discount = utils.calculateDiscount(basePrice, voucher) - - expect(discount).toBe(10.00) - }) - - it('should calculate percent discount', function(){ - var basePrice = 50 - var voucher = { - discount: { - type: 'PERCENT', - percent_off: 10.00 - } - } - var discount = utils.calculateDiscount(basePrice, voucher) - - expect(discount).toBe(5.00) - }) - - it('should calculate unit discount', function(){ - var basePrice = 50 - var unitPrice = 20 - var voucher = { - discount: { - type: 'UNIT', - unit_off: 1.00 - } - } - var discount = utils.calculateDiscount(basePrice, voucher, unitPrice) - - expect(discount).toBe(20.00) - }) - - it('should fail to calculate discount for gift voucher', function(){ - var basePrice = 50 - var unitPrice = 20 - var voucher = { - gift: { - amount: 1000 - } - } - - expect(function() { - utils.calculateDiscount(basePrice, voucher) - }).toThrow(new Error('Unsupported voucher type.')) - }) - - // ------ calculatePrice ------ // - - it('should calculate new price with amount discount', function(){ - var basePrice = 50 - var voucher = { - discount: { - type: 'AMOUNT', - amount_off: 1000 // 10.00 - } - } - var discount = utils.calculatePrice(basePrice, voucher) - - expect(discount).toBe(40.00) - }) - - it('should calculate new price with percent discount', function(){ - var basePrice = 50 - var voucher = { - discount: { - type: 'PERCENT', - percent_off: 10.00 - } - } - var discount = utils.calculatePrice(basePrice, voucher) - - expect(discount).toBe(45.00) - }) - - it('should calculate new price with unit discount', function(){ - var basePrice = 50 - var unitPrice = 20 - var voucher = { - discount: { - type: 'UNIT', - unit_off: 1.00 - } - } - var discount = utils.calculatePrice(basePrice, voucher, unitPrice) - - expect(discount).toBe(30.00) - }) - - - it('should fail to calculate price for gift voucher', function(){ - var basePrice = 50 - var voucher = { - gift: { - amount: 1000 - } - } - - expect(function() { - utils.calculatePrice(basePrice, voucher) - }).toThrow(new Error('Unsupported voucher type.')) - }) - - +describe('utils', function () { + // ------ calculateDiscount ------ // + + it('should calculate amount discount', function () { + var basePrice = 50 + var voucher = { + discount: { + type: 'AMOUNT', + amount_off: 1000 // 10.00 + } + } + var discount = utils.calculateDiscount(basePrice, voucher) + + expect(discount).toBe(10.00) + }) + + it('should calculate percent discount', function () { + var basePrice = 50 + var voucher = { + discount: { + type: 'PERCENT', + percent_off: 10.00 + } + } + var discount = utils.calculateDiscount(basePrice, voucher) + + expect(discount).toBe(5.00) + }) + + it('should calculate unit discount', function () { + var basePrice = 50 + var unitPrice = 20 + var voucher = { + discount: { + type: 'UNIT', + unit_off: 1.00 + } + } + var discount = utils.calculateDiscount(basePrice, voucher, unitPrice) + + expect(discount).toBe(20.00) + }) + + it('should fail to calculate discount for gift voucher', function () { + var basePrice = 50 + var unitPrice = 20 + var voucher = { + gift: { + amount: 1000 + } + } + + expect(function () { + utils.calculateDiscount(basePrice, voucher) + }).toThrow(new Error('Unsupported voucher type.')) + }) + + // ------ calculatePrice ------ // + + it('should calculate new price with amount discount', function () { + var basePrice = 50 + var voucher = { + discount: { + type: 'AMOUNT', + amount_off: 1000 // 10.00 + } + } + var discount = utils.calculatePrice(basePrice, voucher) + + expect(discount).toBe(40.00) + }) + + it('should calculate new price with percent discount', function () { + var basePrice = 50 + var voucher = { + discount: { + type: 'PERCENT', + percent_off: 10.00 + } + } + var discount = utils.calculatePrice(basePrice, voucher) + + expect(discount).toBe(45.00) + }) + + it('should calculate new price with unit discount', function () { + var basePrice = 50 + var unitPrice = 20 + var voucher = { + discount: { + type: 'UNIT', + unit_off: 1.00 + } + } + var discount = utils.calculatePrice(basePrice, voucher, unitPrice) + + expect(discount).toBe(30.00) + }) + + it('should fail to calculate price for gift voucher', function () { + var basePrice = 50 + var voucher = { + gift: { + amount: 1000 + } + } + + expect(function () { + utils.calculatePrice(basePrice, voucher) + }).toThrow(new Error('Unsupported voucher type.')) + }) }) diff --git a/test/voucherify.spec.js b/test/voucherify.spec.js index 1cd1cd1..6855e98 100644 --- a/test/voucherify.spec.js +++ b/test/voucherify.spec.js @@ -1,21 +1,20 @@ +/* global describe, it, expect */ var voucherifyClient = require('../voucherify.js') -describe('voucherify', function() { - - it('should detect missing applicationId', function () { - expect(function () { - voucherifyClient({ - clientSecretKey: 'CLIENT-SECRET-KEY' - }) - }).toThrow(new Error("Missing required option 'applicationId'")) - }) - - it('should detect missing clientSecretKey', function () { - expect(function () { - voucherifyClient({ - applicationId: 'APPLICATION-ID' - }) - }).toThrow(new Error("Missing required option 'clientSecretKey'")) - }) +describe('voucherify', function () { + it('should detect missing applicationId', function () { + expect(function () { + voucherifyClient({ + clientSecretKey: 'CLIENT-SECRET-KEY' + }) + }).toThrow(new Error("Missing required option 'applicationId'")) + }) + it('should detect missing clientSecretKey', function () { + expect(function () { + voucherifyClient({ + applicationId: 'APPLICATION-ID' + }) + }).toThrow(new Error("Missing required option 'clientSecretKey'")) + }) }) diff --git a/utils.js b/utils.js index eccd9f8..c0ccf53 100644 --- a/utils.js +++ b/utils.js @@ -1,22 +1,22 @@ 'use strict' -function roundMoney(value) { +function roundMoney (value) { return Math.round(value * (100 + 0.001)) / 100 } -function validatePercentDiscount(discount) { +function validatePercentDiscount (discount) { if (!discount || discount < 0 || discount > 100) { throw new Error('Invalid voucher, percent discount should be between 0-100.') } } -function validateAmountDiscount(discount) { +function validateAmountDiscount (discount) { if (!discount || discount < 0) { throw new Error('Invalid voucher, amount discount must be higher than zero.') } } -function validateUnitDiscount(discount) { +function validateUnitDiscount (discount) { if (!discount || discount < 0) { throw new Error('Invalid voucher, unit discount must be higher than zero.') } @@ -35,26 +35,26 @@ module.exports = { discount = voucher.discount.percent_off validatePercentDiscount(discount) var priceDiscount = basePrice * (discount / 100) - return roundMoney(basePrice - priceDiscount) + return roundMoney(basePrice - priceDiscount) } else if (voucher.discount.type === 'AMOUNT') { discount = voucher.discount.amount_off / e validateAmountDiscount(discount) var newPrice = basePrice - discount - return roundMoney(newPrice > 0 ? newPrice : 0) + return roundMoney(newPrice > 0 ? newPrice : 0) } else if (voucher.discount.type === 'UNIT') { discount = voucher.discount.unit_off validateUnitDiscount(discount) var newPrice = basePrice - unitPrice * discount - return roundMoney(newPrice > 0 ? newPrice : 0) + return roundMoney(newPrice > 0 ? newPrice : 0) } else { throw new Error('Unsupported discount type.') } }, - calculateDiscount: function(basePrice, voucher, unitPrice) { + calculateDiscount: function (basePrice, voucher, unitPrice) { var e = 100 // Number of digits after the decimal separator. var discount @@ -65,20 +65,20 @@ module.exports = { if (voucher.discount.type === 'PERCENT') { discount = voucher.discount.percent_off validatePercentDiscount(discount) - return roundMoney(basePrice * (discount/100)) + return roundMoney(basePrice * (discount / 100)) } else if (voucher.discount.type === 'AMOUNT') { discount = voucher.discount.amount_off / e validateAmountDiscount(discount) var newPrice = basePrice - discount - return roundMoney(newPrice > 0 ? discount : basePrice) + return roundMoney(newPrice > 0 ? discount : basePrice) } else if (voucher.discount.type === 'UNIT') { discount = voucher.discount.unit_off validateUnitDiscount(discount) var priceDiscount = unitPrice * discount - return roundMoney(priceDiscount > basePrice ? basePrice : priceDiscount) + return roundMoney(priceDiscount > basePrice ? basePrice : priceDiscount) } else { throw new Error('Unsupported discount type.') } diff --git a/voucherify.js b/voucherify.js index d13f005..035ed54 100644 --- a/voucherify.js +++ b/voucherify.js @@ -7,381 +7,381 @@ var when = require('when') var backendUrl = 'https://api.voucherify.io/v1' -module.exports = function(options) { - var headers = { - 'X-App-Id': requiredOption('applicationId'), - 'X-App-Token': requiredOption('clientSecretKey'), - 'X-Voucherify-Channel': 'Node.js-SDK' +module.exports = function (options) { + var headers = { + 'X-App-Id': requiredOption('applicationId'), + 'X-App-Token': requiredOption('clientSecretKey'), + 'X-Voucherify-Channel': 'Node.js-SDK' + } + + function requiredOption (name) { + if (!options[name]) { + throw new Error(`Missing required option '${name}'`) } + return options[name] + } - function requiredOption(name) { - if (!options[name]) { - throw new Error(`Missing required option '${name}'`) - } - return options[name] + function errorMessage (statusCode, body) { + body = body || {} + body.toString = function () { + return util.format('Unexpected status code: %d - Details: %j', statusCode, body) } + return body + } - function errorMessage(statusCode, body) { - body = body || {} - body.toString = function() { - return util.format('Unexpected status code: %d - Details: %j', statusCode, body) - } - return body - } + function prepare (callback) { + var deferred = when.defer() + + if (typeof (callback) === 'function') { + return { + callback: function (error, res, body) { + if (error || res.statusCode >= 400) { + callback(error || errorMessage(res.statusCode, body)) + return + } - function prepare(callback) { - var deferred = when.defer() - - if (typeof(callback) === 'function') { - return { - callback: function(error, res, body) { - if (error || res.statusCode >= 400) { - callback(error || errorMessage(res.statusCode, body)) - return - } - - callback(null, body) - } - } - } else { - return { - promise: deferred.promise, - callback: function(error, res, body) { - if (error || res.statusCode >= 400) { - deferred.reject(error || errorMessage(res.statusCode, body)) - return - } - - deferred.resolve(body) - } - } + callback(null, body) } + } + } else { + return { + promise: deferred.promise, + callback: function (error, res, body) { + if (error || res.statusCode >= 400) { + deferred.reject(error || errorMessage(res.statusCode, body)) + return + } + + deferred.resolve(body) + } + } } + } - return { - /* - * List vouchers. Sample query: { limit: 100, skip: 200, category: 'Loyalty' } - */ - list: function(query, callback) { - var url = util.format('%s/vouchers/', backendUrl) - var handler = prepare(callback) + return { + /* + * List vouchers. Sample query: { limit: 100, skip: 200, category: 'Loyalty' } + */ + list: function (query, callback) { + var url = util.format('%s/vouchers/', backendUrl) + var handler = prepare(callback) - request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) + request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) - return handler.promise - }, + return handler.promise + }, - get: function(code, callback) { - var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(code)) - var handler = prepare(callback) + get: function (code, callback) { + var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(code)) + var handler = prepare(callback) - request.get({ url: url, headers: headers, json: true }, handler.callback) + request.get({ url: url, headers: headers, json: true }, handler.callback) - return handler.promise - }, + return handler.promise + }, - create: function(voucher, callback) { - var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code || '')) - var handler = prepare(callback) + create: function (voucher, callback) { + var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code || '')) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: voucher }, handler.callback) + request.post({ url: url, headers: headers, json: voucher }, handler.callback) - return handler.promise - }, - - delete: function(voucher_code, params, callback) { - if (typeof(params) === 'undefined') { - params = {} - } - - if (typeof(params) === 'function') { - callback = params - params = {} - } - - var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher_code || '')) - if (params.force) { url += '?force=true' } - - var handler = prepare(callback) - - request.del({ url: url, headers: headers }, handler.callback) - - return handler.promise - }, + return handler.promise + }, - update: function(voucher, callback) { - var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code)) - var handler = prepare(callback) + delete: function (voucherCode, params, callback) { + if (typeof (params) === 'undefined') { + params = {} + } - request.put({ url: url, headers: headers, json: voucher }, handler.callback) + if (typeof (params) === 'function') { + callback = params + params = {} + } - return handler.promise - }, + var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucherCode || '')) + if (params.force) { url += '?force=true' } - enable: function(code, callback) { - var url = util.format('%s/vouchers/%s/enable', backendUrl, encodeURIComponent(code)) - var handler = prepare(callback) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: true }, handler.callback) + request.del({ url: url, headers: headers }, handler.callback) - return handler.promise - }, + return handler.promise + }, - disable: function(code, callback) { - var url = util.format('%s/vouchers/%s/disable', backendUrl, encodeURIComponent(code)) - var handler = prepare(callback) + update: function (voucher, callback) { + var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code)) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: true }, handler.callback) + request.put({ url: url, headers: headers, json: voucher }, handler.callback) - return handler.promise - }, + return handler.promise + }, - validate: function(code, context, callback) { - if (typeof(context) === 'undefined') { - context = {} - } + enable: function (code, callback) { + var url = util.format('%s/vouchers/%s/enable', backendUrl, encodeURIComponent(code)) + var handler = prepare(callback) - if (typeof(context) === 'function') { - callback = context - context = {} - } + request.post({ url: url, headers: headers, json: true }, handler.callback) - var handler = prepare(callback) - var url = util.format('%s/vouchers/%s/validate', backendUrl, encodeURIComponent(code)) + return handler.promise + }, - request.post({ url: url, headers: headers, json: context }, handler.callback) + disable: function (code, callback) { + var url = util.format('%s/vouchers/%s/disable', backendUrl, encodeURIComponent(code)) + var handler = prepare(callback) - return handler.promise - }, + request.post({ url: url, headers: headers, json: true }, handler.callback) - redemption: function(code, callback) { - var url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) - var handler = prepare(callback) + return handler.promise + }, - request.get({ url: url, headers: headers, json: true }, handler.callback) + validate: function (code, context, callback) { + if (typeof (context) === 'undefined') { + context = {} + } - return handler.promise - }, + if (typeof (context) === 'function') { + callback = context + context = {} + } - /* - * List redemptions. Sample query (1000 successful redemptions from April 2016): - * { - * limit: 1000, - * page: 0, - * start_date: '2016-04-01T00:00:00', - * end_date: '2016-04-30T23:59:59', - * result: 'Success' - * } - */ - redemptions: function(query, callback) { - var url = util.format('%s/redemptions/', backendUrl) - var handler = prepare(callback) - - request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) - - return handler.promise - }, + var handler = prepare(callback) + var url = util.format('%s/vouchers/%s/validate', backendUrl, encodeURIComponent(code)) - redeem: function(code, trackingId, callback) { - var context = {} - if (typeof(code) === 'object') { - context = code - code = context.voucher - delete context.voucher - } - // No `tracking_id` passed here, - // use callback from 2n argument. - if (typeof(trackingId) === 'function') { - callback = trackingId - trackingId = undefined - } - - var handler = prepare(callback) - var url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) - - // If `tracking_id` passed, use it in query string. - if (typeof(trackingId) === 'string' && trackingId) { - url += '?tracking_id=' + encodeURIComponent(trackingId) - } - - request.post({ url: url, headers: headers, json: context }, handler.callback) - - return handler.promise - }, + request.post({ url: url, headers: headers, json: context }, handler.callback) - rollback: function(redemptionId, data, callback) { - if (typeof(data) === 'function') { - callback = data - data = undefined - } + return handler.promise + }, - var qs = {} - var payload = {} + redemption: function (code, callback) { + var url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) + var handler = prepare(callback) - // If `reason` passed, use it in query string. - if (typeof(data) === 'string') { - qs['reason'] = encodeURIComponent(data) - } + request.get({ url: url, headers: headers, json: true }, handler.callback) - if (typeof(data) === 'object') { - qs['reason'] = data['reason'] || undefined - qs['tracking_id'] = data['tracking_id'] || undefined - payload['customer'] = data['customer'] || undefined - } + return handler.promise + }, - var handler = prepare(callback) - var url = util.format('%s/redemptions/%s/rollback', backendUrl, encodeURIComponent(redemptionId)) + /* + * List redemptions. Sample query (1000 successful redemptions from April 2016): + * { + * limit: 1000, + * page: 0, + * start_date: '2016-04-01T00:00:00', + * end_date: '2016-04-30T23:59:59', + * result: 'Success' + * } + */ + redemptions: function (query, callback) { + var url = util.format('%s/redemptions/', backendUrl) + var handler = prepare(callback) - request.post({ url: url, headers: headers, qs: qs, body: payload, json: true }, handler.callback) + request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) - return handler.promise - }, + return handler.promise + }, - publish: function(campaignName, callback) { - var url = util.format('%s/vouchers/publish', backendUrl) - var payload = {} - if (typeof(campaignName) === 'string') { - url += '?campaign=' + encodeURIComponent(campaignName) - } - if (typeof(campaignName) === 'object') { - payload = campaignName - } - var handler = prepare(callback) + redeem: function (code, trackingId, callback) { + var context = {} + if (typeof (code) === 'object') { + context = code + code = context.voucher + delete context.voucher + } + // No `tracking_id` passed here, + // use callback from 2n argument. + if (typeof (trackingId) === 'function') { + callback = trackingId + trackingId = undefined + } - request.post({ url: url, headers: headers, json: payload }, handler.callback) + var handler = prepare(callback) + var url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) - return handler.promise - }, + // If `tracking_id` passed, use it in query string. + if (typeof (trackingId) === 'string' && trackingId) { + url += '?tracking_id=' + encodeURIComponent(trackingId) + } - campaign: { - voucher: { - create: function(campaignName, voucher, callback) { - var url = util.format('%s/campaigns/%s/vouchers', backendUrl, encodeURIComponent(campaignName || '')) - var handler = prepare(callback) + request.post({ url: url, headers: headers, json: context }, handler.callback) - request.post({ url: url, headers: headers, json: voucher || {} }, handler.callback) + return handler.promise + }, - return handler.promise - } - } - }, + rollback: function (redemptionId, data, callback) { + if (typeof (data) === 'function') { + callback = data + data = undefined + } + + var qs = {} + var payload = {} + + // If `reason` passed, use it in query string. + if (typeof (data) === 'string') { + qs['reason'] = encodeURIComponent(data) + } + + if (typeof (data) === 'object') { + qs['reason'] = data['reason'] || undefined + qs['tracking_id'] = data['tracking_id'] || undefined + payload['customer'] = data['customer'] || undefined + } + + var handler = prepare(callback) + var url = util.format('%s/redemptions/%s/rollback', backendUrl, encodeURIComponent(redemptionId)) + + request.post({ url: url, headers: headers, qs: qs, body: payload, json: true }, handler.callback) + + return handler.promise + }, + + publish: function (campaignName, callback) { + var url = util.format('%s/vouchers/publish', backendUrl) + var payload = {} + if (typeof (campaignName) === 'string') { + url += '?campaign=' + encodeURIComponent(campaignName) + } + if (typeof (campaignName) === 'object') { + payload = campaignName + } + var handler = prepare(callback) + + request.post({ url: url, headers: headers, json: payload }, handler.callback) + + return handler.promise + }, + + campaign: { + voucher: { + create: function (campaignName, voucher, callback) { + var url = util.format('%s/campaigns/%s/vouchers', backendUrl, encodeURIComponent(campaignName || '')) + var handler = prepare(callback) + + request.post({ url: url, headers: headers, json: voucher || {} }, handler.callback) + + return handler.promise + } + } + }, - customer: { - create: function(customer, callback) { - var url = util.format('%s/customers', backendUrl) - var handler = prepare(callback) + customer: { + create: function (customer, callback) { + var url = util.format('%s/customers', backendUrl) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: customer }, handler.callback) + request.post({ url: url, headers: headers, json: customer }, handler.callback) - return handler.promise - }, + return handler.promise + }, - get: function(customerId, callback) { - var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) - var handler = prepare(callback) + get: function (customerId, callback) { + var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) + var handler = prepare(callback) - request.get({ url: url, headers: headers, json: true }, handler.callback) + request.get({ url: url, headers: headers, json: true }, handler.callback) - return handler.promise - }, + return handler.promise + }, - update: function(customer, callback) { - var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customer.id || '')) - var handler = prepare(callback) + update: function (customer, callback) { + var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customer.id || '')) + var handler = prepare(callback) - request.put({ url: url, headers: headers, json: customer }, handler.callback) + request.put({ url: url, headers: headers, json: customer }, handler.callback) - return handler.promise - }, + return handler.promise + }, - delete: function(customerId, callback) { - var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) - var handler = prepare(callback) + delete: function (customerId, callback) { + var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) + var handler = prepare(callback) - request.del({ url: url, headers: headers }, handler.callback) + request.del({ url: url, headers: headers }, handler.callback) - return handler.promise - } - }, + return handler.promise + } + }, - product: { - create: function (product, callback) { - var url = util.format('%s/products', backendUrl) - var handler = prepare(callback) + product: { + create: function (product, callback) { + var url = util.format('%s/products', backendUrl) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: product }, handler.callback) + request.post({ url: url, headers: headers, json: product }, handler.callback) - return handler.promise - }, + return handler.promise + }, - get: function (productId, callback) { - var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) - var handler = prepare(callback) + get: function (productId, callback) { + var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) + var handler = prepare(callback) - request.get({ url: url, headers: headers }, handler.callback) + request.get({ url: url, headers: headers }, handler.callback) - return handler.promise - }, + return handler.promise + }, - update: function (product, callback) { - var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(product.id || '')) - var handler = prepare(callback) + update: function (product, callback) { + var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(product.id || '')) + var handler = prepare(callback) - request.put({ url: url, headers: headers, json: product }, handler.callback) + request.put({ url: url, headers: headers, json: product }, handler.callback) - return handler.promise - }, + return handler.promise + }, - delete: function (productId, callback) { - var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) - var handler = prepare(callback) + delete: function (productId, callback) { + var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) + var handler = prepare(callback) - request.del({ url: url, headers: headers }, handler.callback) + request.del({ url: url, headers: headers }, handler.callback) - return handler.promise - }, + return handler.promise + }, - sku: { - create: function (productId, sku, callback) { - var url = util.format('%s/products/%s/skus', backendUrl, - encodeURIComponent(productId || '')) - var handler = prepare(callback) + sku: { + create: function (productId, sku, callback) { + var url = util.format('%s/products/%s/skus', backendUrl, + encodeURIComponent(productId || '')) + var handler = prepare(callback) - request.post({ url: url, headers: headers, json: sku }, handler.callback) + request.post({ url: url, headers: headers, json: sku }, handler.callback) - return handler.promise - }, + return handler.promise + }, - get: function (productId, skuId, callback) { - var url = util.format('%s/products/%s/skus/%s', backendUrl, - encodeURIComponent(productId || ''), encodeURIComponent(skuId || '')) - var handler = prepare(callback) + get: function (productId, skuId, callback) { + var url = util.format('%s/products/%s/skus/%s', backendUrl, + encodeURIComponent(productId || ''), encodeURIComponent(skuId || '')) + var handler = prepare(callback) - request.get({ url: url, headers: headers }, handler.callback) + request.get({ url: url, headers: headers }, handler.callback) - return handler.promise - }, + return handler.promise + }, - update: function (productId, sku, callback) { - var url = util.format('%s/products/%s/skus/%s', backendUrl, - encodeURIComponent(productId || ''), encodeURIComponent(sku.id || '')) - var handler = prepare(callback) + update: function (productId, sku, callback) { + var url = util.format('%s/products/%s/skus/%s', backendUrl, + encodeURIComponent(productId || ''), encodeURIComponent(sku.id || '')) + var handler = prepare(callback) - request.put({ url: url, headers: headers, json: sku }, handler.callback) + request.put({ url: url, headers: headers, json: sku }, handler.callback) - return handler.promise - }, + return handler.promise + }, - delete: function (productId, skuId, callback) { - var url = util.format('%s/products/%s/skus/%s', backendUrl, - encodeURIComponent(productId || ''), encodeURIComponent(skuId || '')) - var handler = prepare(callback) + delete: function (productId, skuId, callback) { + var url = util.format('%s/products/%s/skus/%s', backendUrl, + encodeURIComponent(productId || ''), encodeURIComponent(skuId || '')) + var handler = prepare(callback) - request.del({ url: url, headers: headers }, handler.callback) + request.del({ url: url, headers: headers }, handler.callback) - return handler.promise - } - } + return handler.promise } + } } + } } From a210006bc318c25af330b0864c394f015e4f2bde Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 19:07:54 +0100 Subject: [PATCH 006/112] drop not used variable --- test/utils.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/utils.spec.js b/test/utils.spec.js index 353e479..3477ef3 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -46,7 +46,6 @@ describe('utils', function () { it('should fail to calculate discount for gift voucher', function () { var basePrice = 50 - var unitPrice = 20 var voucher = { gift: { amount: 1000 From 89959cb20048bc0bc11bd9424d8bd04065354d4f Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 19:16:17 +0100 Subject: [PATCH 007/112] Add standard.js badge --- README.md | 94 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 26558d3..a5319a0 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ ## Voucherify Node.js SDK +[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) + [Voucherify](http://voucherify.io?utm_source=github&utm_medium=sdk&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: * an API-first SaaS platform that enables customisation of every aspect of coupon campaigns @@ -46,7 +48,7 @@ voucherify.get("v1GiJYuuS", function(error, result) { ``` If you prefer to use promises then the code goes like this: - + ```javascript voucherify.get("v1GiJYuuS") .then(function (result) { @@ -207,8 +209,8 @@ You can define how to generate the code in `code_config` including following pro - `prefix` - A text appended before the code. - `postfix` - A text appended after the code. - `pattern` - A pattern for codes where hashes (#) will be replaced with random characters. Overrides `length`. - -Example: + +Example: ```javascript voucherify.create({ @@ -248,7 +250,7 @@ You can modify following fields: Other fields than listed above won't be modified. Even if provided they will be silently skipped. -Example: +Example: ```javascript voucherify.update({ @@ -319,7 +321,7 @@ Result: "quantity": 0, "data_ref": "redemption_entries", "redeemed_quantity": 0, - "redemption_entries": [] + "redemption_entries": [] }, "active": true, "additional_info": "New voucher", @@ -335,7 +337,7 @@ Result: In param object you can pass `force` flag which tells whether voucher will be removed permanently. It means that afterwards user will be able to create next voucher with the same code. -Example: +Example: ```javascript voucherify.delete("v1GiJYuuS", { force: true }) @@ -355,7 +357,7 @@ Result: `voucherify.disable(voucher_code, callback*)` -Example: +Example: ```javascript voucherify.disable("v1GiJYuuS") @@ -376,7 +378,7 @@ Result: `voucherify.enable(voucher_code, callback*)` -Example: +Example: ```javascript voucherify.enable("v1GiJYuuS") @@ -526,9 +528,9 @@ Validation lets you check if given voucher code can be successfully redeemed. `voucherify.validate(code, context)` -The `context` param is generally optional unless you are validating a gift voucher or a voucher with order validation rules. +The `context` param is generally optional unless you are validating a gift voucher or a voucher with order validation rules. For gift voucher you have to pass `order.amount` expressed in cents (e.g. $10 is 1000). -Validation rules also require to pass `order.items` as a list of objects including `product_id`, `sku_id` and `quantity`. +Validation rules also require to pass `order.items` as a list of objects including `product_id`, `sku_id` and `quantity`. Example: @@ -557,7 +559,7 @@ Successful validation result: valid: true, gift: { amount: 10000 - }, + }, tracking_id: "john@lemon.com" } ``` @@ -721,7 +723,7 @@ Result: ##### 3. With customer profile -You can record a detailed customer profile consisting of a `source_id`, `name`, `email`, `description` and a `metadata` section that can include any data you wish. +You can record a detailed customer profile consisting of a `source_id`, `name`, `email`, `description` and a `metadata` section that can include any data you wish. Voucherify will create (or update) provided customer profile in its database. ```javascript @@ -749,7 +751,7 @@ voucherify.redeem({ ##### 4. With customer id -If you already created a customer profile in Voucherify's database, whether it was implicitly by providing it to the `redeem` function or explicitly by invoking the [`customer.create`](#create-customer) method, you can identify your customer in following redemptions by a generated id (starting with `cust_`). +If you already created a customer profile in Voucherify's database, whether it was implicitly by providing it to the `redeem` function or explicitly by invoking the [`customer.create`](#create-customer) method, you can identify your customer in following redemptions by a generated id (starting with `cust_`). ```javascript voucherify.redeem({ @@ -802,7 +804,7 @@ Filter parameters: - limit (default: 100) - page (default: 0) -- start_date (default: beginning of current month) +- start_date (default: beginning of current month) - end_date (default: end of current month) - result - Success | Failure-NotExist | Failure-Inactive - customer @@ -831,13 +833,13 @@ voucherify.redemptions(filter) #### Rollback a redemption Use `voucherify.rollback(redemption_id, options*, callback*)` to revert a redemption. -It will create a rollback entry in `redemption.redemption_entries` and give 1 redemption back to the pool +It will create a rollback entry in `redemption.redemption_entries` and give 1 redemption back to the pool (decrease `redeemed_quantity` by 1). Parameter `options` passed as object supports following attributes: - `reason` - reason why rollback is perform - `tracking_id` - attribute for tracking customer - `customer` - customer id or customer object - + Possible errors are: - 404 - Resource not found - if voucher with given `redemption_id` doesn't exist - 400 - Already rolled back - if redemption with given `redemption_id` has been rolled back already @@ -1111,7 +1113,7 @@ var payload = { "color", "memory" ], - "metadata": { + "metadata": { "type": "normal" } } @@ -1128,7 +1130,7 @@ voucherify.product.create(payload) Result: ```json -{ +{ "id": "prod_YWnt2mNigm76oA", "object": "product", "name": "Apple iPhone 6", @@ -1136,15 +1138,15 @@ Result: "color", "memory" ], - "metadata": { + "metadata": { "type": "normal" }, "created_at": "2016-07-29T13:15:24Z", - "skus": { - "object": "list", - "total": 0, - "data": [] - } + "skus": { + "object": "list", + "total": 0, + "data": [] + } } ``` @@ -1168,7 +1170,7 @@ voucherify.product.get(productId) Result: ```json -{ +{ "id": "prod_YWnt2mNigm76oA", "object": "product", "name": "Apple iPhone 6", @@ -1176,14 +1178,14 @@ Result: "color", "memory" ], - "metadata": { + "metadata": { "type": "normal" }, "created_at": "2016-07-29T13:15:24Z", - "skus": { - "object": "list", - "total": 0, - "data": [] + "skus": { + "object": "list", + "total": 0, + "data": [] } } ``` @@ -1194,7 +1196,7 @@ Result: Example: ```javascript -var payload = { +var payload = { "id": "prod_YWnt2mNigm76oA", "object": "product", "name": "Apple iPhone 6", @@ -1202,15 +1204,15 @@ var payload = { "color", "memory" ], - "metadata": { + "metadata": { "type": "ultra premium" }, "created_at": "2016-07-29T13:15:24Z", - "skus": { - "object": "list", - "total": 0, - "data": [] - } + "skus": { + "object": "list", + "total": 0, + "data": [] + } } voucherify.product.update(payload) @@ -1225,7 +1227,7 @@ voucherify.product.update(payload) Result: ```json -{ +{ "id": "prod_YWnt2mNigm76oA", "object": "product", "name": "Apple iPhone 6", @@ -1233,15 +1235,15 @@ Result: "color", "memory" ], - "metadata": { + "metadata": { "type": "ultra premium" }, "created_at": "2016-07-29T13:15:24Z", - "skus": { - "object": "list", - "total": 0, - "data": [] - } + "skus": { + "object": "list", + "total": 0, + "data": [] + } } ``` @@ -1413,7 +1415,7 @@ Result: var utils = require('voucherify/utils'); ``` -Utils don't need callbacks or promises. They return results immediately. +Utils don't need callbacks or promises. They return results immediately. #### Available methods @@ -1460,7 +1462,7 @@ Utils don't need callbacks or promises. They return results immediately. - **2016-04-07** - `1.8.0` - List redemptions with filtering. - **2016-04-04** - `1.7.1` - Updated API URL. - **2016-03-08** - `1.7.0` - List vouchers with filtering. -- **2016-01-22** - `1.6.0` - Added publish voucher method. +- **2016-01-22** - `1.6.0` - Added publish voucher method. - **2015-12-10** - `1.5.0` - New discount model. Added UNIT - a new discount type. - **2015-11-23** - `1.4.1` - Added `X-Voucherify-Channel` header. - **2015-11-10** - `1.4.0` - Add `VoucherifyUtils` which includes `calculatePrice` for computing product/cart price From e31e5f29d0ca6d264c19b2e5667edaf71109a862 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 19:20:26 +0100 Subject: [PATCH 008/112] add lint script --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 6f7991f..2e81b60 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "standard": "^8.6.0" }, "scripts": { - "test": "./node_modules/.bin/jasmine-node ./test" + "test": "./node_modules/.bin/jasmine-node ./test", + "lint": "standard" } } From 7bc01077f1f15de59d103ab662aa7943bebfbf4f Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 19:38:47 +0100 Subject: [PATCH 009/112] move sources to src dir --- package.json | 2 +- src/utils.js | 86 +++++++++++++++++++++++++++++ voucherify.js => src/voucherify.js | 0 test/utils.spec.js | 2 +- test/voucherify.spec.js | 2 +- utils.js | 88 ++---------------------------- 6 files changed, 93 insertions(+), 87 deletions(-) create mode 100644 src/utils.js rename voucherify.js => src/voucherify.js (100%) diff --git a/package.json b/package.json index 2e81b60..bd90f2c 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "description": "Node.js SDK for Voucherify.", "author": "rspective", "license": "MIT", - "main": "voucherify.js", + "main": "./src/voucherify.js", "repository": { "type": "git", "url": "https://github.com/rspective/voucherify-nodejs-sdk.git" diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..c0ccf53 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,86 @@ +'use strict' + +function roundMoney (value) { + return Math.round(value * (100 + 0.001)) / 100 +} + +function validatePercentDiscount (discount) { + if (!discount || discount < 0 || discount > 100) { + throw new Error('Invalid voucher, percent discount should be between 0-100.') + } +} + +function validateAmountDiscount (discount) { + if (!discount || discount < 0) { + throw new Error('Invalid voucher, amount discount must be higher than zero.') + } +} + +function validateUnitDiscount (discount) { + if (!discount || discount < 0) { + throw new Error('Invalid voucher, unit discount must be higher than zero.') + } +} + +module.exports = { + calculatePrice: function (basePrice, voucher, unitPrice) { + var e = 100 // Number of digits after the decimal separator. + var discount + + if (!voucher.discount) { + throw new Error('Unsupported voucher type.') + } + + if (voucher.discount.type === 'PERCENT') { + discount = voucher.discount.percent_off + validatePercentDiscount(discount) + var priceDiscount = basePrice * (discount / 100) + + return roundMoney(basePrice - priceDiscount) + } else if (voucher.discount.type === 'AMOUNT') { + discount = voucher.discount.amount_off / e + validateAmountDiscount(discount) + var newPrice = basePrice - discount + + return roundMoney(newPrice > 0 ? newPrice : 0) + } else if (voucher.discount.type === 'UNIT') { + discount = voucher.discount.unit_off + validateUnitDiscount(discount) + var newPrice = basePrice - unitPrice * discount + + return roundMoney(newPrice > 0 ? newPrice : 0) + } else { + throw new Error('Unsupported discount type.') + } + }, + + calculateDiscount: function (basePrice, voucher, unitPrice) { + var e = 100 // Number of digits after the decimal separator. + var discount + + if (!voucher.discount) { + throw new Error('Unsupported voucher type.') + } + + if (voucher.discount.type === 'PERCENT') { + discount = voucher.discount.percent_off + validatePercentDiscount(discount) + + return roundMoney(basePrice * (discount / 100)) + } else if (voucher.discount.type === 'AMOUNT') { + discount = voucher.discount.amount_off / e + validateAmountDiscount(discount) + var newPrice = basePrice - discount + + return roundMoney(newPrice > 0 ? discount : basePrice) + } else if (voucher.discount.type === 'UNIT') { + discount = voucher.discount.unit_off + validateUnitDiscount(discount) + var priceDiscount = unitPrice * discount + + return roundMoney(priceDiscount > basePrice ? basePrice : priceDiscount) + } else { + throw new Error('Unsupported discount type.') + } + } +} diff --git a/voucherify.js b/src/voucherify.js similarity index 100% rename from voucherify.js rename to src/voucherify.js diff --git a/test/utils.spec.js b/test/utils.spec.js index 3477ef3..c2538b2 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -1,5 +1,5 @@ /* global describe, it, expect */ -var utils = require('../utils.js') +var utils = require('../src/utils.js') describe('utils', function () { // ------ calculateDiscount ------ // diff --git a/test/voucherify.spec.js b/test/voucherify.spec.js index 6855e98..45de3ff 100644 --- a/test/voucherify.spec.js +++ b/test/voucherify.spec.js @@ -1,5 +1,5 @@ /* global describe, it, expect */ -var voucherifyClient = require('../voucherify.js') +var voucherifyClient = require('../src/voucherify.js') describe('voucherify', function () { it('should detect missing applicationId', function () { diff --git a/utils.js b/utils.js index c0ccf53..086e7d0 100644 --- a/utils.js +++ b/utils.js @@ -1,86 +1,6 @@ 'use strict' -function roundMoney (value) { - return Math.round(value * (100 + 0.001)) / 100 -} - -function validatePercentDiscount (discount) { - if (!discount || discount < 0 || discount > 100) { - throw new Error('Invalid voucher, percent discount should be between 0-100.') - } -} - -function validateAmountDiscount (discount) { - if (!discount || discount < 0) { - throw new Error('Invalid voucher, amount discount must be higher than zero.') - } -} - -function validateUnitDiscount (discount) { - if (!discount || discount < 0) { - throw new Error('Invalid voucher, unit discount must be higher than zero.') - } -} - -module.exports = { - calculatePrice: function (basePrice, voucher, unitPrice) { - var e = 100 // Number of digits after the decimal separator. - var discount - - if (!voucher.discount) { - throw new Error('Unsupported voucher type.') - } - - if (voucher.discount.type === 'PERCENT') { - discount = voucher.discount.percent_off - validatePercentDiscount(discount) - var priceDiscount = basePrice * (discount / 100) - - return roundMoney(basePrice - priceDiscount) - } else if (voucher.discount.type === 'AMOUNT') { - discount = voucher.discount.amount_off / e - validateAmountDiscount(discount) - var newPrice = basePrice - discount - - return roundMoney(newPrice > 0 ? newPrice : 0) - } else if (voucher.discount.type === 'UNIT') { - discount = voucher.discount.unit_off - validateUnitDiscount(discount) - var newPrice = basePrice - unitPrice * discount - - return roundMoney(newPrice > 0 ? newPrice : 0) - } else { - throw new Error('Unsupported discount type.') - } - }, - - calculateDiscount: function (basePrice, voucher, unitPrice) { - var e = 100 // Number of digits after the decimal separator. - var discount - - if (!voucher.discount) { - throw new Error('Unsupported voucher type.') - } - - if (voucher.discount.type === 'PERCENT') { - discount = voucher.discount.percent_off - validatePercentDiscount(discount) - - return roundMoney(basePrice * (discount / 100)) - } else if (voucher.discount.type === 'AMOUNT') { - discount = voucher.discount.amount_off / e - validateAmountDiscount(discount) - var newPrice = basePrice - discount - - return roundMoney(newPrice > 0 ? discount : basePrice) - } else if (voucher.discount.type === 'UNIT') { - discount = voucher.discount.unit_off - validateUnitDiscount(discount) - var priceDiscount = unitPrice * discount - - return roundMoney(priceDiscount > basePrice ? basePrice : priceDiscount) - } else { - throw new Error('Unsupported discount type.') - } - } -} +/** + * Goal of this file is to provide backward compatibility with previous SDK versions. + */ +module.exports = require('./src/utils') From b25eb26a09d289e620fee573470fc62fdb61c3f1 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 19:40:20 +0100 Subject: [PATCH 010/112] drop direct path to jasmine exec bin of local modules is available though npm scripts --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bd90f2c..23b8362 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "standard": "^8.6.0" }, "scripts": { - "test": "./node_modules/.bin/jasmine-node ./test", + "test": "jasmine-node ./test", "lint": "standard" } } From 39ecd0f6f2c66f9c5a3e6893864d2a16c4ecb5bc Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 21:10:05 +0100 Subject: [PATCH 011/112] Introduce babel This will make sure our code is working for everyone. --- .babelrc | 3 +++ .gitignore | 3 ++- gulpfile.js | 12 ++++++++++++ package.json | 8 ++++++-- utils.js | 2 +- 5 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 .babelrc create mode 100644 gulpfile.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..2303342 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2016"] +} diff --git a/.gitignore b/.gitignore index af95561..9dbb68e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Logs logs *.log +lib/ # Runtime data pids @@ -28,4 +29,4 @@ node_modules # IntelliJ IDEA files: *.iml -.idea/ \ No newline at end of file +.idea/ diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..5b35c49 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,12 @@ +'use strict' + +const gulp = require('gulp') +const babel = require('gulp-babel') + +gulp.task('release', function () { + return gulp.src('src/**/*.js') + .pipe(babel()) + .pipe(gulp.dest('lib')) +}) + +gulp.task('default', ['release']) diff --git a/package.json b/package.json index 23b8362..7fad881 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "description": "Node.js SDK for Voucherify.", "author": "rspective", "license": "MIT", - "main": "./src/voucherify.js", + "main": "./lib/voucherify.js", "repository": { "type": "git", "url": "https://github.com/rspective/voucherify-nodejs-sdk.git" @@ -28,11 +28,15 @@ "when": "~3.7.3" }, "devDependencies": { + "babel-preset-es2016": "^6.16.0", + "gulp": "^3.9.1", + "gulp-babel": "^6.1.2", "jasmine-node": "~1.14.5", "standard": "^8.6.0" }, "scripts": { "test": "jasmine-node ./test", - "lint": "standard" + "lint": "standard", + "prepublish": "gulp release" } } diff --git a/utils.js b/utils.js index 086e7d0..f112d12 100644 --- a/utils.js +++ b/utils.js @@ -3,4 +3,4 @@ /** * Goal of this file is to provide backward compatibility with previous SDK versions. */ -module.exports = require('./src/utils') +module.exports = require('./lib/utils') From 2678edb702fca8e2d42a86b34230ca1c29e12d2f Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 21:14:32 +0100 Subject: [PATCH 012/112] use const and let --- README.md | 42 +++++------ examples/gift-voucher-example.js | 4 +- examples/product.js | 2 +- src/utils.js | 18 ++--- src/voucherify.js | 124 +++++++++++++++---------------- test/utils.spec.js | 50 ++++++------- test/voucherify.spec.js | 2 +- 7 files changed, 121 insertions(+), 121 deletions(-) diff --git a/README.md b/README.md index a5319a0..0f48815 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ Full documentation is located at [voucherify.readme.io](https://voucherify.readm ![](https://www.filepicker.io/api/file/WKYkl2bSAWKHccEN9tEG) ```javascript -var voucherifyClient = require("voucherify"); +const voucherifyClient = require("voucherify"); -var voucherify = voucherifyClient({ +const voucherify = voucherifyClient({ applicationId: "YOUR-APPLICATION-ID-OBTAINED-FROM-CONFIGURATION", clientSecretKey: "YOUR-CLIENT-SECRET-KEY-OBTAINED-FROM-CONFIGURATION" }); @@ -279,7 +279,7 @@ This method is responsible for adding new voucher to campaign based on voucher d Example: ```javascript -var payload = { +const payload = { "additional_info": "New voucher", "metadata": { "test": true @@ -812,7 +812,7 @@ Filter parameters: Example - 1000 successful redemptions from April 2016: ```javascript -var filter = { +const filter = { limit: 1000, page: 0, start_date: "2016-04-01T00:00:00", @@ -967,7 +967,7 @@ Result: Example: ```javascript -var payload = { +const payload = { "source_id": "your-tracking-id", "name": "John Doe", "email": "email@example.com", @@ -1009,7 +1009,7 @@ Result: Example: ```javascript -var customerId = "cust_c2SlN2rKajDdMycd3BmVawJk" +const customerId = "cust_c2SlN2rKajDdMycd3BmVawJk" voucherify.customer.get(customerId) .then(function (result) { @@ -1043,7 +1043,7 @@ Result: Example: ```javascript -var payload = { +const payload = { "name": "John Doe", "email": "email@example.com", "description":"Premium user, ACME Inc.", @@ -1086,7 +1086,7 @@ Result: Example: ```javascript -var customerId = "cust_c2SlN2rKajDdMycd3BmVawJk" +const customerId = "cust_c2SlN2rKajDdMycd3BmVawJk" voucherify.customer.delete(customerId) .then(function (result) { @@ -1107,7 +1107,7 @@ Result: Example: ```javascript -var payload = { +const payload = { "name": "Apple iPhone 6", "attributes": [ "color", @@ -1156,7 +1156,7 @@ Result: Example: ```javascript -var productId = "prod_YWnt2mNigm76oA" +const productId = "prod_YWnt2mNigm76oA" voucherify.product.get(productId) .then(function (result) { @@ -1196,7 +1196,7 @@ Result: Example: ```javascript -var payload = { +const payload = { "id": "prod_YWnt2mNigm76oA", "object": "product", "name": "Apple iPhone 6", @@ -1253,7 +1253,7 @@ Result: Example: ```javascript -var productId = "prod_YWnt2mNigm76oA" +const productId = "prod_YWnt2mNigm76oA" voucherify.product.delete(productId) .then(function (result) { @@ -1275,9 +1275,9 @@ Result: Example: ```javascript -var productId = "prod_e8uLMegXZJ4GGS"; +const productId = "prod_e8uLMegXZJ4GGS"; -var sku = { +const sku = { sku: "APPLE_IPHONE_6_BLACK", currency: "EUR", price: 12000, @@ -1314,9 +1314,9 @@ Result: Example: ```javascript -var productId = "prod_YWnt2mNigm76oA"; +const productId = "prod_YWnt2mNigm76oA"; -var skuId = "sku_JXYGfsGbpvsfjv"; +const skuId = "sku_JXYGfsGbpvsfjv"; voucherify.product.sku.get(productId, skuId) .then(function (result) { @@ -1345,7 +1345,7 @@ Result: Example: ```javascript -var sku = { +const sku = { "id": "sku_JXYGfsGbpvsfjv", "product_id": "prod_e8uLMegXZJ4GGS", "sku": "APPLE_IPHONE_6_BLACK", @@ -1356,7 +1356,7 @@ var sku = { sku.currency = "EUR"; sku.price = 1000; -var productId = sku.product_id; +const productId = sku.product_id; voucherify.product.sku.update(productId, sku) .then(function (result) { @@ -1388,9 +1388,9 @@ Example: ```javascript -var productId = "prod_e8uLMegXZJ4GGS"; +const productId = "prod_e8uLMegXZJ4GGS"; -var skuId = "sku_JXYGfsGbpvsfjv"; +const skuId = "sku_JXYGfsGbpvsfjv"; voucherify.product.sku.delete(productId, skuId) .then(function (result) { @@ -1412,7 +1412,7 @@ Result: #### Usage ``` -var utils = require('voucherify/utils'); +const utils = require('voucherify/utils'); ``` Utils don't need callbacks or promises. They return results immediately. diff --git a/examples/gift-voucher-example.js b/examples/gift-voucher-example.js index 55cec93..150eb02 100644 --- a/examples/gift-voucher-example.js +++ b/examples/gift-voucher-example.js @@ -1,11 +1,11 @@ const voucherifyClient = require('../voucherify') -var voucherify = voucherifyClient({ +const voucherify = voucherifyClient({ applicationId: 'c70a6f00-cf91-4756-9df5-47628850002b', clientSecretKey: '3266b9f8-e246-4f79-bdf0-833929b1380c' }) -var voucherCode +let voucherCode voucherify.create({ type: 'GIFT_VOUCHER', diff --git a/examples/product.js b/examples/product.js index 00fb5f4..fa49a87 100644 --- a/examples/product.js +++ b/examples/product.js @@ -34,7 +34,7 @@ voucherify.product.create(payload) .then(() => { console.log('==== CREATE - SKU ====') - var sku = { + const sku = { sku: 'APPLE_IPHONE_6_BLACK' } diff --git a/src/utils.js b/src/utils.js index c0ccf53..587677d 100644 --- a/src/utils.js +++ b/src/utils.js @@ -24,8 +24,8 @@ function validateUnitDiscount (discount) { module.exports = { calculatePrice: function (basePrice, voucher, unitPrice) { - var e = 100 // Number of digits after the decimal separator. - var discount + const e = 100 // Number of digits after the decimal separator. + let discount if (!voucher.discount) { throw new Error('Unsupported voucher type.') @@ -34,19 +34,19 @@ module.exports = { if (voucher.discount.type === 'PERCENT') { discount = voucher.discount.percent_off validatePercentDiscount(discount) - var priceDiscount = basePrice * (discount / 100) + const priceDiscount = basePrice * (discount / 100) return roundMoney(basePrice - priceDiscount) } else if (voucher.discount.type === 'AMOUNT') { discount = voucher.discount.amount_off / e validateAmountDiscount(discount) - var newPrice = basePrice - discount + const newPrice = basePrice - discount return roundMoney(newPrice > 0 ? newPrice : 0) } else if (voucher.discount.type === 'UNIT') { discount = voucher.discount.unit_off validateUnitDiscount(discount) - var newPrice = basePrice - unitPrice * discount + const newPrice = basePrice - unitPrice * discount return roundMoney(newPrice > 0 ? newPrice : 0) } else { @@ -55,8 +55,8 @@ module.exports = { }, calculateDiscount: function (basePrice, voucher, unitPrice) { - var e = 100 // Number of digits after the decimal separator. - var discount + const e = 100 // Number of digits after the decimal separator. + let discount if (!voucher.discount) { throw new Error('Unsupported voucher type.') @@ -70,13 +70,13 @@ module.exports = { } else if (voucher.discount.type === 'AMOUNT') { discount = voucher.discount.amount_off / e validateAmountDiscount(discount) - var newPrice = basePrice - discount + const newPrice = basePrice - discount return roundMoney(newPrice > 0 ? discount : basePrice) } else if (voucher.discount.type === 'UNIT') { discount = voucher.discount.unit_off validateUnitDiscount(discount) - var priceDiscount = unitPrice * discount + const priceDiscount = unitPrice * discount return roundMoney(priceDiscount > basePrice ? basePrice : priceDiscount) } else { diff --git a/src/voucherify.js b/src/voucherify.js index 035ed54..4d5e0d4 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -1,14 +1,14 @@ 'use strict' -var util = require('util') +const util = require('util') -var request = require('request') -var when = require('when') +const request = require('request') +const when = require('when') -var backendUrl = 'https://api.voucherify.io/v1' +const backendUrl = 'https://api.voucherify.io/v1' module.exports = function (options) { - var headers = { + const headers = { 'X-App-Id': requiredOption('applicationId'), 'X-App-Token': requiredOption('clientSecretKey'), 'X-Voucherify-Channel': 'Node.js-SDK' @@ -30,7 +30,7 @@ module.exports = function (options) { } function prepare (callback) { - var deferred = when.defer() + const deferred = when.defer() if (typeof (callback) === 'function') { return { @@ -63,8 +63,8 @@ module.exports = function (options) { * List vouchers. Sample query: { limit: 100, skip: 200, category: 'Loyalty' } */ list: function (query, callback) { - var url = util.format('%s/vouchers/', backendUrl) - var handler = prepare(callback) + const url = util.format('%s/vouchers/', backendUrl) + const handler = prepare(callback) request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) @@ -72,8 +72,8 @@ module.exports = function (options) { }, get: function (code, callback) { - var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(code)) - var handler = prepare(callback) + const url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(code)) + const handler = prepare(callback) request.get({ url: url, headers: headers, json: true }, handler.callback) @@ -81,8 +81,8 @@ module.exports = function (options) { }, create: function (voucher, callback) { - var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code || '')) - var handler = prepare(callback) + const url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code || '')) + const handler = prepare(callback) request.post({ url: url, headers: headers, json: voucher }, handler.callback) @@ -99,10 +99,10 @@ module.exports = function (options) { params = {} } - var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucherCode || '')) + let url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucherCode || '')) if (params.force) { url += '?force=true' } - var handler = prepare(callback) + const handler = prepare(callback) request.del({ url: url, headers: headers }, handler.callback) @@ -110,8 +110,8 @@ module.exports = function (options) { }, update: function (voucher, callback) { - var url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code)) - var handler = prepare(callback) + const url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code)) + const handler = prepare(callback) request.put({ url: url, headers: headers, json: voucher }, handler.callback) @@ -119,8 +119,8 @@ module.exports = function (options) { }, enable: function (code, callback) { - var url = util.format('%s/vouchers/%s/enable', backendUrl, encodeURIComponent(code)) - var handler = prepare(callback) + const url = util.format('%s/vouchers/%s/enable', backendUrl, encodeURIComponent(code)) + const handler = prepare(callback) request.post({ url: url, headers: headers, json: true }, handler.callback) @@ -128,8 +128,8 @@ module.exports = function (options) { }, disable: function (code, callback) { - var url = util.format('%s/vouchers/%s/disable', backendUrl, encodeURIComponent(code)) - var handler = prepare(callback) + const url = util.format('%s/vouchers/%s/disable', backendUrl, encodeURIComponent(code)) + const handler = prepare(callback) request.post({ url: url, headers: headers, json: true }, handler.callback) @@ -146,8 +146,8 @@ module.exports = function (options) { context = {} } - var handler = prepare(callback) - var url = util.format('%s/vouchers/%s/validate', backendUrl, encodeURIComponent(code)) + const handler = prepare(callback) + const url = util.format('%s/vouchers/%s/validate', backendUrl, encodeURIComponent(code)) request.post({ url: url, headers: headers, json: context }, handler.callback) @@ -155,8 +155,8 @@ module.exports = function (options) { }, redemption: function (code, callback) { - var url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) - var handler = prepare(callback) + const url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) + const handler = prepare(callback) request.get({ url: url, headers: headers, json: true }, handler.callback) @@ -174,8 +174,8 @@ module.exports = function (options) { * } */ redemptions: function (query, callback) { - var url = util.format('%s/redemptions/', backendUrl) - var handler = prepare(callback) + const url = util.format('%s/redemptions/', backendUrl) + const handler = prepare(callback) request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) @@ -183,7 +183,7 @@ module.exports = function (options) { }, redeem: function (code, trackingId, callback) { - var context = {} + let context = {} if (typeof (code) === 'object') { context = code code = context.voucher @@ -196,8 +196,8 @@ module.exports = function (options) { trackingId = undefined } - var handler = prepare(callback) - var url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) + const handler = prepare(callback) + let url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) // If `tracking_id` passed, use it in query string. if (typeof (trackingId) === 'string' && trackingId) { @@ -215,8 +215,8 @@ module.exports = function (options) { data = undefined } - var qs = {} - var payload = {} + const qs = {} + const payload = {} // If `reason` passed, use it in query string. if (typeof (data) === 'string') { @@ -229,8 +229,8 @@ module.exports = function (options) { payload['customer'] = data['customer'] || undefined } - var handler = prepare(callback) - var url = util.format('%s/redemptions/%s/rollback', backendUrl, encodeURIComponent(redemptionId)) + const handler = prepare(callback) + const url = util.format('%s/redemptions/%s/rollback', backendUrl, encodeURIComponent(redemptionId)) request.post({ url: url, headers: headers, qs: qs, body: payload, json: true }, handler.callback) @@ -238,15 +238,15 @@ module.exports = function (options) { }, publish: function (campaignName, callback) { - var url = util.format('%s/vouchers/publish', backendUrl) - var payload = {} + let url = util.format('%s/vouchers/publish', backendUrl) + let payload = {} if (typeof (campaignName) === 'string') { url += '?campaign=' + encodeURIComponent(campaignName) } if (typeof (campaignName) === 'object') { payload = campaignName } - var handler = prepare(callback) + const handler = prepare(callback) request.post({ url: url, headers: headers, json: payload }, handler.callback) @@ -256,8 +256,8 @@ module.exports = function (options) { campaign: { voucher: { create: function (campaignName, voucher, callback) { - var url = util.format('%s/campaigns/%s/vouchers', backendUrl, encodeURIComponent(campaignName || '')) - var handler = prepare(callback) + const url = util.format('%s/campaigns/%s/vouchers', backendUrl, encodeURIComponent(campaignName || '')) + const handler = prepare(callback) request.post({ url: url, headers: headers, json: voucher || {} }, handler.callback) @@ -268,8 +268,8 @@ module.exports = function (options) { customer: { create: function (customer, callback) { - var url = util.format('%s/customers', backendUrl) - var handler = prepare(callback) + const url = util.format('%s/customers', backendUrl) + const handler = prepare(callback) request.post({ url: url, headers: headers, json: customer }, handler.callback) @@ -277,8 +277,8 @@ module.exports = function (options) { }, get: function (customerId, callback) { - var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) - var handler = prepare(callback) + const url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) + const handler = prepare(callback) request.get({ url: url, headers: headers, json: true }, handler.callback) @@ -286,8 +286,8 @@ module.exports = function (options) { }, update: function (customer, callback) { - var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customer.id || '')) - var handler = prepare(callback) + const url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customer.id || '')) + const handler = prepare(callback) request.put({ url: url, headers: headers, json: customer }, handler.callback) @@ -295,8 +295,8 @@ module.exports = function (options) { }, delete: function (customerId, callback) { - var url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) - var handler = prepare(callback) + const url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) + const handler = prepare(callback) request.del({ url: url, headers: headers }, handler.callback) @@ -306,8 +306,8 @@ module.exports = function (options) { product: { create: function (product, callback) { - var url = util.format('%s/products', backendUrl) - var handler = prepare(callback) + const url = util.format('%s/products', backendUrl) + const handler = prepare(callback) request.post({ url: url, headers: headers, json: product }, handler.callback) @@ -315,8 +315,8 @@ module.exports = function (options) { }, get: function (productId, callback) { - var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) - var handler = prepare(callback) + const url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) + const handler = prepare(callback) request.get({ url: url, headers: headers }, handler.callback) @@ -324,8 +324,8 @@ module.exports = function (options) { }, update: function (product, callback) { - var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(product.id || '')) - var handler = prepare(callback) + const url = util.format('%s/products/%s', backendUrl, encodeURIComponent(product.id || '')) + const handler = prepare(callback) request.put({ url: url, headers: headers, json: product }, handler.callback) @@ -333,8 +333,8 @@ module.exports = function (options) { }, delete: function (productId, callback) { - var url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) - var handler = prepare(callback) + const url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) + const handler = prepare(callback) request.del({ url: url, headers: headers }, handler.callback) @@ -343,9 +343,9 @@ module.exports = function (options) { sku: { create: function (productId, sku, callback) { - var url = util.format('%s/products/%s/skus', backendUrl, + const url = util.format('%s/products/%s/skus', backendUrl, encodeURIComponent(productId || '')) - var handler = prepare(callback) + const handler = prepare(callback) request.post({ url: url, headers: headers, json: sku }, handler.callback) @@ -353,9 +353,9 @@ module.exports = function (options) { }, get: function (productId, skuId, callback) { - var url = util.format('%s/products/%s/skus/%s', backendUrl, + const url = util.format('%s/products/%s/skus/%s', backendUrl, encodeURIComponent(productId || ''), encodeURIComponent(skuId || '')) - var handler = prepare(callback) + const handler = prepare(callback) request.get({ url: url, headers: headers }, handler.callback) @@ -363,9 +363,9 @@ module.exports = function (options) { }, update: function (productId, sku, callback) { - var url = util.format('%s/products/%s/skus/%s', backendUrl, + const url = util.format('%s/products/%s/skus/%s', backendUrl, encodeURIComponent(productId || ''), encodeURIComponent(sku.id || '')) - var handler = prepare(callback) + const handler = prepare(callback) request.put({ url: url, headers: headers, json: sku }, handler.callback) @@ -373,9 +373,9 @@ module.exports = function (options) { }, delete: function (productId, skuId, callback) { - var url = util.format('%s/products/%s/skus/%s', backendUrl, + const url = util.format('%s/products/%s/skus/%s', backendUrl, encodeURIComponent(productId || ''), encodeURIComponent(skuId || '')) - var handler = prepare(callback) + const handler = prepare(callback) request.del({ url: url, headers: headers }, handler.callback) diff --git a/test/utils.spec.js b/test/utils.spec.js index c2538b2..bb342a8 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -1,52 +1,52 @@ /* global describe, it, expect */ -var utils = require('../src/utils.js') +const utils = require('../src/utils.js') describe('utils', function () { // ------ calculateDiscount ------ // it('should calculate amount discount', function () { - var basePrice = 50 - var voucher = { + const basePrice = 50 + const voucher = { discount: { type: 'AMOUNT', amount_off: 1000 // 10.00 } } - var discount = utils.calculateDiscount(basePrice, voucher) + const discount = utils.calculateDiscount(basePrice, voucher) expect(discount).toBe(10.00) }) it('should calculate percent discount', function () { - var basePrice = 50 - var voucher = { + const basePrice = 50 + const voucher = { discount: { type: 'PERCENT', percent_off: 10.00 } } - var discount = utils.calculateDiscount(basePrice, voucher) + const discount = utils.calculateDiscount(basePrice, voucher) expect(discount).toBe(5.00) }) it('should calculate unit discount', function () { - var basePrice = 50 - var unitPrice = 20 - var voucher = { + const basePrice = 50 + const unitPrice = 20 + const voucher = { discount: { type: 'UNIT', unit_off: 1.00 } } - var discount = utils.calculateDiscount(basePrice, voucher, unitPrice) + const discount = utils.calculateDiscount(basePrice, voucher, unitPrice) expect(discount).toBe(20.00) }) it('should fail to calculate discount for gift voucher', function () { - var basePrice = 50 - var voucher = { + const basePrice = 50 + const voucher = { gift: { amount: 1000 } @@ -60,48 +60,48 @@ describe('utils', function () { // ------ calculatePrice ------ // it('should calculate new price with amount discount', function () { - var basePrice = 50 - var voucher = { + const basePrice = 50 + const voucher = { discount: { type: 'AMOUNT', amount_off: 1000 // 10.00 } } - var discount = utils.calculatePrice(basePrice, voucher) + const discount = utils.calculatePrice(basePrice, voucher) expect(discount).toBe(40.00) }) it('should calculate new price with percent discount', function () { - var basePrice = 50 - var voucher = { + const basePrice = 50 + const voucher = { discount: { type: 'PERCENT', percent_off: 10.00 } } - var discount = utils.calculatePrice(basePrice, voucher) + const discount = utils.calculatePrice(basePrice, voucher) expect(discount).toBe(45.00) }) it('should calculate new price with unit discount', function () { - var basePrice = 50 - var unitPrice = 20 - var voucher = { + const basePrice = 50 + const unitPrice = 20 + const voucher = { discount: { type: 'UNIT', unit_off: 1.00 } } - var discount = utils.calculatePrice(basePrice, voucher, unitPrice) + const discount = utils.calculatePrice(basePrice, voucher, unitPrice) expect(discount).toBe(30.00) }) it('should fail to calculate price for gift voucher', function () { - var basePrice = 50 - var voucher = { + const basePrice = 50 + const voucher = { gift: { amount: 1000 } diff --git a/test/voucherify.spec.js b/test/voucherify.spec.js index 45de3ff..03a148f 100644 --- a/test/voucherify.spec.js +++ b/test/voucherify.spec.js @@ -1,5 +1,5 @@ /* global describe, it, expect */ -var voucherifyClient = require('../src/voucherify.js') +const voucherifyClient = require('../src/voucherify.js') describe('voucherify', function () { it('should detect missing applicationId', function () { From 82c94dcc7b94c13e382b23cf94fa9dea959d3cb0 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 21:16:28 +0100 Subject: [PATCH 013/112] drop semicolons --- README.md | 240 +++++++++++++++++++++++++++--------------------------- 1 file changed, 120 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index 0f48815..e865cda 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,12 @@ Full documentation is located at [voucherify.readme.io](https://voucherify.readm ![](https://www.filepicker.io/api/file/WKYkl2bSAWKHccEN9tEG) ```javascript -const voucherifyClient = require("voucherify"); +const voucherifyClient = require("voucherify") const voucherify = voucherifyClient({ applicationId: "YOUR-APPLICATION-ID-OBTAINED-FROM-CONFIGURATION", clientSecretKey: "YOUR-CLIENT-SECRET-KEY-OBTAINED-FROM-CONFIGURATION" -}); +}) ``` @@ -40,11 +40,11 @@ If you want to use callbacks just pass them as a last parameter. For example: voucherify.get("v1GiJYuuS", function(error, result) { if (error) { // handle error - return; + return } // do the work -}); +}) ``` If you prefer to use promises then the code goes like this: @@ -52,11 +52,11 @@ If you prefer to use promises then the code goes like this: ```javascript voucherify.get("v1GiJYuuS") .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` All other examples in the readme use promises but they could be as well written with callbacks. @@ -80,11 +80,11 @@ Example: ```javascript voucherify.list({limit: 10, skip: 20, category: "API Test"}) .then(function(vouchers) { - console.log(vouchers); + console.log(vouchers) }) .catch(function(error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -156,11 +156,11 @@ Example: ```javascript voucherify.get("v1GiJYuuS") .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -229,11 +229,11 @@ Example: expiration_date: "2016-12-31T23:59:59Z" }) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` #### Updating a voucher @@ -260,11 +260,11 @@ Example: expiration_date: "2017-07-31T23:59:59Z" }) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` #### Add voucher to existing Campaign @@ -291,11 +291,11 @@ const payload = { voucherify.campaign.voucher.create("Campaign-Name", payload) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -342,11 +342,11 @@ Example: ```javascript voucherify.delete("v1GiJYuuS", { force: true }) .then(function (result) { - console.log("Voucher deleted."); + console.log("Voucher deleted.") }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -362,11 +362,11 @@ Example: ```javascript voucherify.disable("v1GiJYuuS") .then(function (result) { - console.log("Voucher disabled."); + console.log("Voucher disabled.") }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -383,11 +383,11 @@ Example: ```javascript voucherify.enable("v1GiJYuuS") .then(function (result) { - console.log("Voucher enabled."); + console.log("Voucher enabled.") }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -404,11 +404,11 @@ Example: ```javascript voucherify.redemption("v1GiJYuuS") .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -446,11 +446,11 @@ By campaign name: ```javascript voucherify.publish("First Ride") .then(function (result) { - console.log(JSON.stringify(result, null, " ")); + console.log(JSON.stringify(result, null, " ")) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` By object with campaign name: @@ -458,11 +458,11 @@ By object with campaign name: ```javascript voucherify.publish({campaign: "First Ride", channel: "Email", customer: "donny.roll@mail.com"}) .then(function (result) { - console.log(JSON.stringify(result, null, " ")); + console.log(JSON.stringify(result, null, " ")) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` By object with voucher code: @@ -470,11 +470,11 @@ By object with voucher code: ```javascript voucherify.publish({voucher: "FR-zT-u9I7zG", channel: "Email", customer: "donny.roll@mail.com"}) .then(function (result) { - console.log(JSON.stringify(result, null, " ")); + console.log(JSON.stringify(result, null, " ")) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -596,11 +596,11 @@ Example: ```javascript voucherify.redeem("v1GiJYuuS") .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result (voucher details after redemption): @@ -664,11 +664,11 @@ You can provide a tracking id (e.g. your customer's login or a generated id) to ```javascript voucherify.redeem("v1GiJYuuS", "alice.morgan") .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -741,11 +741,11 @@ voucherify.redeem({ } }) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` @@ -760,11 +760,11 @@ voucherify.redeem({ id: "cust_C9qJ3xKgZFqkpMw7b21MF2ow" }) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` ##### 5. With order amount @@ -818,15 +818,15 @@ const filter = { start_date: "2016-04-01T00:00:00", end_date: "2016-04-30T23:59:59", result: "Success" -}; +} voucherify.redemptions(filter) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` @@ -851,11 +851,11 @@ Option is a `reason`: ```javascript voucherify.rollback("r_irOQWUTAjthQwnkn5JQM1V6N", "Wrong user") .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Object which contains following options of `reason`, _customer id_ as `customer`: @@ -865,11 +865,11 @@ voucherify.rollback("r_irOQWUTAjthQwnkn5JQM1V6N", { "customer": "cust_1V6NirOQWUwnkn5JQMTAjthQ", }) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Object which contains customer data: @@ -883,22 +883,22 @@ voucherify.rollback("r_irOQWUTAjthQwnkn5JQM1V6N", { }, }) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` ```javascript voucherify.rollback("r_irOQWUTAjthQwnkn5JQM1V6N", "wrong user") .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -979,11 +979,11 @@ const payload = { voucherify.customer.create(payload) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1013,11 +1013,11 @@ const customerId = "cust_c2SlN2rKajDdMycd3BmVawJk" voucherify.customer.get(customerId) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1055,11 +1055,11 @@ const payload = { voucherify.customer.update(payload) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1090,11 +1090,11 @@ const customerId = "cust_c2SlN2rKajDdMycd3BmVawJk" voucherify.customer.delete(customerId) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1120,11 +1120,11 @@ const payload = { voucherify.product.create(payload) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1160,11 +1160,11 @@ const productId = "prod_YWnt2mNigm76oA" voucherify.product.get(productId) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1217,11 +1217,11 @@ const payload = { voucherify.product.update(payload) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1257,11 +1257,11 @@ const productId = "prod_YWnt2mNigm76oA" voucherify.product.delete(productId) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1275,7 +1275,7 @@ Result: Example: ```javascript -const productId = "prod_e8uLMegXZJ4GGS"; +const productId = "prod_e8uLMegXZJ4GGS" const sku = { sku: "APPLE_IPHONE_6_BLACK", @@ -1285,15 +1285,15 @@ const sku = { color: "BLACK", memory: "16GB" } -}; +} voucherify.product.sku.create(productId, payload) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1314,17 +1314,17 @@ Result: Example: ```javascript -const productId = "prod_YWnt2mNigm76oA"; +const productId = "prod_YWnt2mNigm76oA" -const skuId = "sku_JXYGfsGbpvsfjv"; +const skuId = "sku_JXYGfsGbpvsfjv" voucherify.product.sku.get(productId, skuId) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1351,20 +1351,20 @@ const sku = { "sku": "APPLE_IPHONE_6_BLACK", "created_at": "2016-08-02T16:43:47Z", "object": "sku" -}; +} -sku.currency = "EUR"; -sku.price = 1000; +sku.currency = "EUR" +sku.price = 1000 -const productId = sku.product_id; +const productId = sku.product_id voucherify.product.sku.update(productId, sku) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1388,17 +1388,17 @@ Example: ```javascript -const productId = "prod_e8uLMegXZJ4GGS"; +const productId = "prod_e8uLMegXZJ4GGS" -const skuId = "sku_JXYGfsGbpvsfjv"; +const skuId = "sku_JXYGfsGbpvsfjv" voucherify.product.sku.delete(productId, skuId) .then(function (result) { - console.log(result); + console.log(result) }) .catch(function (error) { - console.error("Error: %s", error); - }); + console.error("Error: %s", error) + }) ``` Result: @@ -1412,15 +1412,15 @@ Result: #### Usage ``` -const utils = require('voucherify/utils'); +const utils = require('voucherify/utils') ``` Utils don't need callbacks or promises. They return results immediately. #### Available methods -- `utils.calculatePrice(basePrice, voucher);` -- `utils.calculateDiscount(basePrice, voucher);` +- `utils.calculatePrice(basePrice, voucher)` +- `utils.calculateDiscount(basePrice, voucher)` ### Changelog From 131d75f54270408e6267f13d36ece99d3ec5d090 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 21:17:04 +0100 Subject: [PATCH 014/112] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e865cda..e5c1fd1 100644 --- a/README.md +++ b/README.md @@ -1415,7 +1415,7 @@ Result: const utils = require('voucherify/utils') ``` -Utils don't need callbacks or promises. They return results immediately. +Utils don't need callbacks nor promises. They return results immediately. #### Available methods From e295f7c3c7e0b9795ea2c27ea916f10158e650f5 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 21:25:30 +0100 Subject: [PATCH 015/112] clean ignores --- .gitignore | 31 +------------------------------ .npmignore | 4 ++++ 2 files changed, 5 insertions(+), 30 deletions(-) create mode 100644 .npmignore diff --git a/.gitignore b/.gitignore index 9dbb68e..560af40 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1,3 @@ -# Logs -logs -*.log lib/ - -# Runtime data -pids -*.pid -*.seed - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directory -# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git -node_modules - -# IntelliJ IDEA files: -*.iml +node_modules/ .idea/ diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..e77603d --- /dev/null +++ b/.npmignore @@ -0,0 +1,4 @@ +node_modules/ +.idea/ +test/ +examples/ From 0cb9413558b7f6783721d7ab34004546ad02aff9 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 21:32:28 +0100 Subject: [PATCH 016/112] add preset-es2015 --- .babelrc | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.babelrc b/.babelrc index 2303342..101443a 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,3 @@ { - "presets": ["es2016"] + "presets": ["es2015", "es2016"] } diff --git a/package.json b/package.json index 7fad881..356df6a 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "when": "~3.7.3" }, "devDependencies": { + "babel-preset-es2015": "^6.18.0", "babel-preset-es2016": "^6.16.0", "gulp": "^3.9.1", "gulp-babel": "^6.1.2", From acca08c90f0a2b9a712bbc7336cc101fa92abbb5 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 22:10:05 +0100 Subject: [PATCH 017/112] move raw raw query methods to separate class --- src/ApiClient.js | 100 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/ApiClient.js diff --git a/src/ApiClient.js b/src/ApiClient.js new file mode 100644 index 0000000..63729e8 --- /dev/null +++ b/src/ApiClient.js @@ -0,0 +1,100 @@ +'use strict' + +const request = require('request') +const when = require('when') + +const errorMessage = (statusCode, body) => { + body = body || {} + body.toString = function () { + return `Unexpected status code: ${statusCode} - Details: ${JSON.stringify(body)}` + } + return body +} + +const prepare = (callback) => { + const deferred = when.defer() + + if (typeof (callback) === 'function') { + return { + callback: function (error, res, body) { + if (error || res.statusCode >= 400) { + callback(error || errorMessage(res.statusCode, body)) + return + } + + callback(null, body) + } + } + } else { + return { + promise: deferred.promise, + callback: function (error, res, body) { + if (error || res.statusCode >= 400) { + deferred.reject(error || errorMessage(res.statusCode, body)) + return + } + + deferred.resolve(body) + } + } + } +} + +module.exports = class ApiClient { + constructor ({applicationId, clientSecretKey}) { + this.basePath = 'https://api.voucherify.io/v1' + this.headers = { + 'X-App-Id': applicationId, + 'X-App-Token': clientSecretKey, + 'X-Voucherify-Channel': 'Node.js-SDK' + } + } + + prepareUrl (path) { + return `${this.basePath}/${path}` + } + + get (path, qs, callback) { + const handler = prepare(callback) + request.get({ + url: this.prepareUrl(path), + qs, + headers: this.headers, + json: true // TODO check that !!!! + }, handler.callback) + + return handler.promise + } + + post (path, json, callback) { + const handler = prepare(callback) + request.get({ + url: this.prepareUrl(path), + headers: this.headers, + json + }, handler.callback) + + return handler.promise + } + + put (path, json, callback) { + const handler = prepare(callback) + request.put({ + url: this.prepareUrl(path), + headers: this.headers, + json + }, handler.callback) + + return handler.promise + } + + delete (path, json, callback) { + const handler = prepare(callback) + request.del({ + url: this.prepareUrl(path), + headers: this.headers + }, handler.callback) + + return handler.promise + } +} From 2b39a177b988f4fec4ecf58400b22cc06191084f Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 22:32:45 +0100 Subject: [PATCH 018/112] allow for additional request options --- src/ApiClient.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ApiClient.js b/src/ApiClient.js index 63729e8..5b053c6 100644 --- a/src/ApiClient.js +++ b/src/ApiClient.js @@ -66,13 +66,13 @@ module.exports = class ApiClient { return handler.promise } - post (path, json, callback) { + post (path, json, callback, options = {}) { const handler = prepare(callback) - request.get({ + request.get(Object.assign({ url: this.prepareUrl(path), headers: this.headers, - json - }, handler.callback) + json: json || true + }, options), handler.callback) return handler.promise } From d66029b6c3c0350540aa3f08e59b4a796f5deb98 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 22:34:24 +0100 Subject: [PATCH 019/112] always expect json request & response --- src/ApiClient.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ApiClient.js b/src/ApiClient.js index 5b053c6..10d99ec 100644 --- a/src/ApiClient.js +++ b/src/ApiClient.js @@ -60,29 +60,31 @@ module.exports = class ApiClient { url: this.prepareUrl(path), qs, headers: this.headers, - json: true // TODO check that !!!! + json: true }, handler.callback) return handler.promise } - post (path, json, callback, options = {}) { + post (path, body, callback, options = {}) { const handler = prepare(callback) request.get(Object.assign({ url: this.prepareUrl(path), headers: this.headers, - json: json || true + body, + json: true }, options), handler.callback) return handler.promise } - put (path, json, callback) { + put (path, body, callback) { const handler = prepare(callback) request.put({ url: this.prepareUrl(path), headers: this.headers, - json + body, + json: true }, handler.callback) return handler.promise From 2285214f2882f5927ee2a47a2a638633e309461b Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 23:01:52 +0100 Subject: [PATCH 020/112] adopt ApiClient --- src/voucherify.js | 304 +++++++++++----------------------------------- 1 file changed, 72 insertions(+), 232 deletions(-) diff --git a/src/voucherify.js b/src/voucherify.js index 4d5e0d4..53d244e 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -1,95 +1,28 @@ 'use strict' -const util = require('util') - -const request = require('request') -const when = require('when') - -const backendUrl = 'https://api.voucherify.io/v1' +const ApiClient = require('./ApiClient') module.exports = function (options) { - const headers = { - 'X-App-Id': requiredOption('applicationId'), - 'X-App-Token': requiredOption('clientSecretKey'), - 'X-Voucherify-Channel': 'Node.js-SDK' - } - - function requiredOption (name) { - if (!options[name]) { - throw new Error(`Missing required option '${name}'`) - } - return options[name] - } - - function errorMessage (statusCode, body) { - body = body || {} - body.toString = function () { - return util.format('Unexpected status code: %d - Details: %j', statusCode, body) - } - return body - } - - function prepare (callback) { - const deferred = when.defer() - - if (typeof (callback) === 'function') { - return { - callback: function (error, res, body) { - if (error || res.statusCode >= 400) { - callback(error || errorMessage(res.statusCode, body)) - return - } - - callback(null, body) - } - } - } else { - return { - promise: deferred.promise, - callback: function (error, res, body) { - if (error || res.statusCode >= 400) { - deferred.reject(error || errorMessage(res.statusCode, body)) - return - } - - deferred.resolve(body) - } - } - } - } + const client = new ApiClient(options) return { /* * List vouchers. Sample query: { limit: 100, skip: 200, category: 'Loyalty' } */ - list: function (query, callback) { - const url = util.format('%s/vouchers/', backendUrl) - const handler = prepare(callback) - - request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) - - return handler.promise + list: (query, callback) => { + return client.get('/vouchers/', query, callback) }, - get: function (code, callback) { - const url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(code)) - const handler = prepare(callback) - - request.get({ url: url, headers: headers, json: true }, handler.callback) - - return handler.promise + get: (code, callback) => { + return client.get(`/vouchers/${encodeURIComponent(code)}`, null, callback) }, - create: function (voucher, callback) { - const url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code || '')) - const handler = prepare(callback) - - request.post({ url: url, headers: headers, json: voucher }, handler.callback) - - return handler.promise + create: (voucher, callback) => { + const code = voucher.code || '' + return client.post(`/vouchers/${encodeURIComponent(code)}`, voucher, callback) }, - delete: function (voucherCode, params, callback) { + delete: (voucherCode, params, callback) => { if (typeof (params) === 'undefined') { params = {} } @@ -99,44 +32,29 @@ module.exports = function (options) { params = {} } - let url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucherCode || '')) - if (params.force) { url += '?force=true' } - - const handler = prepare(callback) - - request.del({ url: url, headers: headers }, handler.callback) + const code = voucherCode || '' + let path = `/vouchers/${encodeURIComponent(code)}` + if (params.force) { + path += '?force=true' + } - return handler.promise + return client.delete(path, callback) }, - update: function (voucher, callback) { - const url = util.format('%s/vouchers/%s', backendUrl, encodeURIComponent(voucher.code)) - const handler = prepare(callback) - - request.put({ url: url, headers: headers, json: voucher }, handler.callback) - - return handler.promise + update: (voucher, callback) => { + const code = voucher.code || '' + return client.put(`/vouchers/${encodeURIComponent(code)}`, voucher, callback) }, - enable: function (code, callback) { - const url = util.format('%s/vouchers/%s/enable', backendUrl, encodeURIComponent(code)) - const handler = prepare(callback) - - request.post({ url: url, headers: headers, json: true }, handler.callback) - - return handler.promise + enable: (code, callback) => { + return client.post(`/vouchers/${encodeURIComponent(code)}/enable`, null, callback) }, - disable: function (code, callback) { - const url = util.format('%s/vouchers/%s/disable', backendUrl, encodeURIComponent(code)) - const handler = prepare(callback) - - request.post({ url: url, headers: headers, json: true }, handler.callback) - - return handler.promise + disable: (code, callback) => { + return client.post(`/vouchers/${encodeURIComponent(code)}/disable`, null, callback) }, - validate: function (code, context, callback) { + validate: (code, context, callback) => { if (typeof (context) === 'undefined') { context = {} } @@ -146,21 +64,11 @@ module.exports = function (options) { context = {} } - const handler = prepare(callback) - const url = util.format('%s/vouchers/%s/validate', backendUrl, encodeURIComponent(code)) - - request.post({ url: url, headers: headers, json: context }, handler.callback) - - return handler.promise + return client.post(`/vouchers/${encodeURIComponent(code)}/validate`, context, callback) }, - redemption: function (code, callback) { - const url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) - const handler = prepare(callback) - - request.get({ url: url, headers: headers, json: true }, handler.callback) - - return handler.promise + redemption: (code, callback) => { + return client.get(`/vouchers/${encodeURIComponent(code)}/redemption`, null, callback) }, /* @@ -173,16 +81,11 @@ module.exports = function (options) { * result: 'Success' * } */ - redemptions: function (query, callback) { - const url = util.format('%s/redemptions/', backendUrl) - const handler = prepare(callback) - - request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback) - - return handler.promise + redemptions: (query, callback) => { + return client.get('/redemptions/', query, callback) }, - redeem: function (code, trackingId, callback) { + redeem: (code, trackingId, callback) => { let context = {} if (typeof (code) === 'object') { context = code @@ -196,20 +99,16 @@ module.exports = function (options) { trackingId = undefined } - const handler = prepare(callback) - let url = util.format('%s/vouchers/%s/redemption', backendUrl, encodeURIComponent(code)) - + let url = `/vouchers/${encodeURIComponent(code)}/redemption` // If `tracking_id` passed, use it in query string. if (typeof (trackingId) === 'string' && trackingId) { - url += '?tracking_id=' + encodeURIComponent(trackingId) + url += `?tracking_id=${encodeURIComponent(trackingId)}` } - request.post({ url: url, headers: headers, json: context }, handler.callback) - - return handler.promise + return client.post(url, context, callback) }, - rollback: function (redemptionId, data, callback) { + rollback: (redemptionId, data, callback) => { if (typeof (data) === 'function') { callback = data data = undefined @@ -229,157 +128,98 @@ module.exports = function (options) { payload['customer'] = data['customer'] || undefined } - const handler = prepare(callback) - const url = util.format('%s/redemptions/%s/rollback', backendUrl, encodeURIComponent(redemptionId)) - - request.post({ url: url, headers: headers, qs: qs, body: payload, json: true }, handler.callback) - - return handler.promise + return client.post( + `/redemptions/${encodeURIComponent(redemptionId)}/rollback`, + payload, callback, {qs} + ) }, publish: function (campaignName, callback) { - let url = util.format('%s/vouchers/publish', backendUrl) + let path = '/vouchers/publish' let payload = {} if (typeof (campaignName) === 'string') { - url += '?campaign=' + encodeURIComponent(campaignName) + path += '?campaign=' + encodeURIComponent(campaignName) } if (typeof (campaignName) === 'object') { payload = campaignName } - const handler = prepare(callback) - - request.post({ url: url, headers: headers, json: payload }, handler.callback) - return handler.promise + return client.post(path, payload, callback) }, campaign: { voucher: { - create: function (campaignName, voucher, callback) { - const url = util.format('%s/campaigns/%s/vouchers', backendUrl, encodeURIComponent(campaignName || '')) - const handler = prepare(callback) - - request.post({ url: url, headers: headers, json: voucher || {} }, handler.callback) - - return handler.promise + create: (campaignName, voucher, callback) => { + return client.post( + `/campaigns/${encodeURIComponent(campaignName || '')}/vouchers`, + // TODO if voucher is optional, secure against callback version + voucher || {}, + callback + ) } } }, customer: { - create: function (customer, callback) { - const url = util.format('%s/customers', backendUrl) - const handler = prepare(callback) - - request.post({ url: url, headers: headers, json: customer }, handler.callback) - - return handler.promise + create: (customer, callback) => { + return client.post('/customers', customer, callback) }, - get: function (customerId, callback) { - const url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) - const handler = prepare(callback) - - request.get({ url: url, headers: headers, json: true }, handler.callback) - - return handler.promise + get: (customerId, callback) => { + // TODO why fallback to empty string ?! shall we rather throw an error? print warning? + return client.get(`/customers/${encodeURIComponent(customerId || '')}`, null, callback) }, update: function (customer, callback) { - const url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customer.id || '')) - const handler = prepare(callback) - - request.put({ url: url, headers: headers, json: customer }, handler.callback) - - return handler.promise + return client.put(`/customers/${encodeURIComponent(customer.id || '')}`, customer, callback) }, delete: function (customerId, callback) { - const url = util.format('%s/customers/%s', backendUrl, encodeURIComponent(customerId || '')) - const handler = prepare(callback) - - request.del({ url: url, headers: headers }, handler.callback) - - return handler.promise + return client.delete(`/customers/${encodeURIComponent(customerId || '')}`, callback) } }, product: { create: function (product, callback) { - const url = util.format('%s/products', backendUrl) - const handler = prepare(callback) - - request.post({ url: url, headers: headers, json: product }, handler.callback) - - return handler.promise + return client.post('/products', product, callback) }, get: function (productId, callback) { - const url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) - const handler = prepare(callback) - - request.get({ url: url, headers: headers }, handler.callback) - - return handler.promise + return client.get(`/products/${encodeURIComponent(productId || '')}`, null, callback) }, update: function (product, callback) { - const url = util.format('%s/products/%s', backendUrl, encodeURIComponent(product.id || '')) - const handler = prepare(callback) - - request.put({ url: url, headers: headers, json: product }, handler.callback) - - return handler.promise + return client.put(`/products/${encodeURIComponent(product.id || '')}`, product, callback) }, delete: function (productId, callback) { - const url = util.format('%s/products/%s', backendUrl, encodeURIComponent(productId || '')) - const handler = prepare(callback) - - request.del({ url: url, headers: headers }, handler.callback) - - return handler.promise + return client.delete(`/products/${encodeURIComponent(productId || '')}`, callback) }, sku: { create: function (productId, sku, callback) { - const url = util.format('%s/products/%s/skus', backendUrl, - encodeURIComponent(productId || '')) - const handler = prepare(callback) - - request.post({ url: url, headers: headers, json: sku }, handler.callback) - - return handler.promise + return client.post(`/products/${encodeURIComponent(productId || '')}/skus`, sku, callback) }, get: function (productId, skuId, callback) { - const url = util.format('%s/products/%s/skus/%s', backendUrl, - encodeURIComponent(productId || ''), encodeURIComponent(skuId || '')) - const handler = prepare(callback) - - request.get({ url: url, headers: headers }, handler.callback) - - return handler.promise + return client.get( + `/products/${encodeURIComponent(productId || '')}/skus/${encodeURIComponent(skuId || '')}`, + null, callback + ) }, update: function (productId, sku, callback) { - const url = util.format('%s/products/%s/skus/%s', backendUrl, - encodeURIComponent(productId || ''), encodeURIComponent(sku.id || '')) - const handler = prepare(callback) - - request.put({ url: url, headers: headers, json: sku }, handler.callback) - - return handler.promise + return client.put( + `/products/${encodeURIComponent(productId || '')}/skus/${encodeURIComponent(sku.id || '')}`, + sku, callback + ) }, delete: function (productId, skuId, callback) { - const url = util.format('%s/products/%s/skus/%s', backendUrl, - encodeURIComponent(productId || ''), encodeURIComponent(skuId || '')) - const handler = prepare(callback) - - request.del({ url: url, headers: headers }, handler.callback) - - return handler.promise + return client.delete( + `/products/${encodeURIComponent(productId || '')}/skus/${encodeURIComponent(skuId || '')}`, + callback + ) } } } From c4bfe0e7d3854c4806dedb8de6906cafd937621d Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 23:02:20 +0100 Subject: [PATCH 021/112] use v6 of node for development --- .nvmrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..1e8b314 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +6 From 69d3faa0720dd9eede0eeae06c9929c8b24ae335 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 23:35:05 +0100 Subject: [PATCH 022/112] assert options --- src/voucherify.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/voucherify.js b/src/voucherify.js index 53d244e..b06b74e 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -2,7 +2,16 @@ const ApiClient = require('./ApiClient') +const assertOption = (options, name) => { + if (!options[name]) { + throw new Error(`Missing required option '${name}'`) + } +} + module.exports = function (options) { + assertOption(options, 'applicationId') + assertOption(options, 'clientSecretKey') + const client = new ApiClient(options) return { From 4081ac204ddb6e429abec6abdc019a4671111588 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 24 Nov 2016 23:57:35 +0100 Subject: [PATCH 023/112] put encode shortcut --- src/voucherify.js | 55 ++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/voucherify.js b/src/voucherify.js index b06b74e..e86ab40 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -8,6 +8,10 @@ const assertOption = (options, name) => { } } +const encode = (value = '') => { + return encodeURIComponent(value) +} + module.exports = function (options) { assertOption(options, 'applicationId') assertOption(options, 'clientSecretKey') @@ -23,12 +27,11 @@ module.exports = function (options) { }, get: (code, callback) => { - return client.get(`/vouchers/${encodeURIComponent(code)}`, null, callback) + return client.get(`/vouchers/${encode(code)}`, null, callback) }, create: (voucher, callback) => { - const code = voucher.code || '' - return client.post(`/vouchers/${encodeURIComponent(code)}`, voucher, callback) + return client.post(`/vouchers/${encode(voucher.code)}`, voucher, callback) }, delete: (voucherCode, params, callback) => { @@ -41,8 +44,7 @@ module.exports = function (options) { params = {} } - const code = voucherCode || '' - let path = `/vouchers/${encodeURIComponent(code)}` + let path = `/vouchers/${encode(voucherCode)}` if (params.force) { path += '?force=true' } @@ -51,16 +53,15 @@ module.exports = function (options) { }, update: (voucher, callback) => { - const code = voucher.code || '' - return client.put(`/vouchers/${encodeURIComponent(code)}`, voucher, callback) + return client.put(`/vouchers/${encode(voucher.code)}`, voucher, callback) }, enable: (code, callback) => { - return client.post(`/vouchers/${encodeURIComponent(code)}/enable`, null, callback) + return client.post(`/vouchers/${encode(code)}/enable`, null, callback) }, disable: (code, callback) => { - return client.post(`/vouchers/${encodeURIComponent(code)}/disable`, null, callback) + return client.post(`/vouchers/${encode(code)}/disable`, null, callback) }, validate: (code, context, callback) => { @@ -73,11 +74,11 @@ module.exports = function (options) { context = {} } - return client.post(`/vouchers/${encodeURIComponent(code)}/validate`, context, callback) + return client.post(`/vouchers/${encode(code)}/validate`, context, callback) }, redemption: (code, callback) => { - return client.get(`/vouchers/${encodeURIComponent(code)}/redemption`, null, callback) + return client.get(`/vouchers/${encode(code)}/redemption`, null, callback) }, /* @@ -108,10 +109,10 @@ module.exports = function (options) { trackingId = undefined } - let url = `/vouchers/${encodeURIComponent(code)}/redemption` + let url = `/vouchers/${encode(code)}/redemption` // If `tracking_id` passed, use it in query string. if (typeof (trackingId) === 'string' && trackingId) { - url += `?tracking_id=${encodeURIComponent(trackingId)}` + url += `?tracking_id=${encode(trackingId)}` } return client.post(url, context, callback) @@ -128,7 +129,7 @@ module.exports = function (options) { // If `reason` passed, use it in query string. if (typeof (data) === 'string') { - qs['reason'] = encodeURIComponent(data) + qs['reason'] = encode(data) } if (typeof (data) === 'object') { @@ -138,7 +139,7 @@ module.exports = function (options) { } return client.post( - `/redemptions/${encodeURIComponent(redemptionId)}/rollback`, + `/redemptions/${encode(redemptionId)}/rollback`, payload, callback, {qs} ) }, @@ -147,7 +148,7 @@ module.exports = function (options) { let path = '/vouchers/publish' let payload = {} if (typeof (campaignName) === 'string') { - path += '?campaign=' + encodeURIComponent(campaignName) + path += '?campaign=' + encode(campaignName) } if (typeof (campaignName) === 'object') { payload = campaignName @@ -160,7 +161,7 @@ module.exports = function (options) { voucher: { create: (campaignName, voucher, callback) => { return client.post( - `/campaigns/${encodeURIComponent(campaignName || '')}/vouchers`, + `/campaigns/${encode(campaignName)}/vouchers`, // TODO if voucher is optional, secure against callback version voucher || {}, callback @@ -176,15 +177,15 @@ module.exports = function (options) { get: (customerId, callback) => { // TODO why fallback to empty string ?! shall we rather throw an error? print warning? - return client.get(`/customers/${encodeURIComponent(customerId || '')}`, null, callback) + return client.get(`/customers/${encode(customerId)}`, null, callback) }, update: function (customer, callback) { - return client.put(`/customers/${encodeURIComponent(customer.id || '')}`, customer, callback) + return client.put(`/customers/${encode(customer.id)}`, customer, callback) }, delete: function (customerId, callback) { - return client.delete(`/customers/${encodeURIComponent(customerId || '')}`, callback) + return client.delete(`/customers/${encode(customerId)}`, callback) } }, @@ -194,39 +195,39 @@ module.exports = function (options) { }, get: function (productId, callback) { - return client.get(`/products/${encodeURIComponent(productId || '')}`, null, callback) + return client.get(`/products/${encode(productId)}`, null, callback) }, update: function (product, callback) { - return client.put(`/products/${encodeURIComponent(product.id || '')}`, product, callback) + return client.put(`/products/${encode(product.id)}`, product, callback) }, delete: function (productId, callback) { - return client.delete(`/products/${encodeURIComponent(productId || '')}`, callback) + return client.delete(`/products/${encode(productId)}`, callback) }, sku: { create: function (productId, sku, callback) { - return client.post(`/products/${encodeURIComponent(productId || '')}/skus`, sku, callback) + return client.post(`/products/${encode(productId)}/skus`, sku, callback) }, get: function (productId, skuId, callback) { return client.get( - `/products/${encodeURIComponent(productId || '')}/skus/${encodeURIComponent(skuId || '')}`, + `/products/${encode(productId)}/skus/${encode(skuId)}`, null, callback ) }, update: function (productId, sku, callback) { return client.put( - `/products/${encodeURIComponent(productId || '')}/skus/${encodeURIComponent(sku.id || '')}`, + `/products/${encode(productId)}/skus/${encode(sku.id)}`, sku, callback ) }, delete: function (productId, skuId, callback) { return client.delete( - `/products/${encodeURIComponent(productId || '')}/skus/${encodeURIComponent(skuId || '')}`, + `/products/${encode(productId)}/skus/${encode(skuId)}`, callback ) } From 4a6f353d13e185249fd4c07b503182a639cb87c1 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 00:04:07 +0100 Subject: [PATCH 024/112] use arrow function --- src/voucherify.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/voucherify.js b/src/voucherify.js index e86ab40..732dc38 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -180,52 +180,52 @@ module.exports = function (options) { return client.get(`/customers/${encode(customerId)}`, null, callback) }, - update: function (customer, callback) { + update: (customer, callback) => { return client.put(`/customers/${encode(customer.id)}`, customer, callback) }, - delete: function (customerId, callback) { + delete: (customerId, callback) => { return client.delete(`/customers/${encode(customerId)}`, callback) } }, product: { - create: function (product, callback) { + create: (product, callback) => { return client.post('/products', product, callback) }, - get: function (productId, callback) { + get: (productId, callback) => { return client.get(`/products/${encode(productId)}`, null, callback) }, - update: function (product, callback) { + update: (product, callback) => { return client.put(`/products/${encode(product.id)}`, product, callback) }, - delete: function (productId, callback) { + delete: (productId, callback) => { return client.delete(`/products/${encode(productId)}`, callback) }, sku: { - create: function (productId, sku, callback) { + create: (productId, sku, callback) => { return client.post(`/products/${encode(productId)}/skus`, sku, callback) }, - get: function (productId, skuId, callback) { + get: (productId, skuId, callback) => { return client.get( `/products/${encode(productId)}/skus/${encode(skuId)}`, null, callback ) }, - update: function (productId, sku, callback) { + update: (productId, sku, callback) => { return client.put( `/products/${encode(productId)}/skus/${encode(sku.id)}`, sku, callback ) }, - delete: function (productId, skuId, callback) { + delete: (productId, skuId, callback) => { return client.delete( `/products/${encode(productId)}/skus/${encode(skuId)}`, callback From 69344ab4e8468ec1b6c8575faaf8e9c2eb4aecd3 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 00:19:06 +0100 Subject: [PATCH 025/112] add comment header to each transpiled source --- .babelrc | 7 ++++++- .npmignore | 1 + package.json | 1 + release-sources-header.txt | 5 +++++ 4 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 release-sources-header.txt diff --git a/.babelrc b/.babelrc index 101443a..2501393 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,8 @@ { - "presets": ["es2015", "es2016"] + "presets": ["es2015", "es2016"], + "plugins": [ + ["add-header-comment", { + "header": ["?release-sources-header.txt"] + }] + ] } diff --git a/.npmignore b/.npmignore index e77603d..e274abb 100644 --- a/.npmignore +++ b/.npmignore @@ -2,3 +2,4 @@ node_modules/ .idea/ test/ examples/ +release-sources-header.txt diff --git a/package.json b/package.json index 356df6a..4ac5933 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "when": "~3.7.3" }, "devDependencies": { + "babel-plugin-add-header-comment": "^1.0.3", "babel-preset-es2015": "^6.18.0", "babel-preset-es2016": "^6.16.0", "gulp": "^3.9.1", diff --git a/release-sources-header.txt b/release-sources-header.txt new file mode 100644 index 0000000..3362b07 --- /dev/null +++ b/release-sources-header.txt @@ -0,0 +1,5 @@ +This file is result of 'babel' transpiler, so it can work with older ECMAScript engines. +Downside is it might be slightly unreadable. +Check `src` directory to see origin soruces. + +Voucherify Team (c) 2016 From a5a5095feb6be92a3807a33e18951cfe9b9d77d8 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 00:31:06 +0100 Subject: [PATCH 026/112] use default args --- src/voucherify.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/voucherify.js b/src/voucherify.js index 732dc38..03f3379 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -34,11 +34,7 @@ module.exports = function (options) { return client.post(`/vouchers/${encode(voucher.code)}`, voucher, callback) }, - delete: (voucherCode, params, callback) => { - if (typeof (params) === 'undefined') { - params = {} - } - + delete: (voucherCode, params = {}, callback = null) => { if (typeof (params) === 'function') { callback = params params = {} @@ -64,11 +60,7 @@ module.exports = function (options) { return client.post(`/vouchers/${encode(code)}/disable`, null, callback) }, - validate: (code, context, callback) => { - if (typeof (context) === 'undefined') { - context = {} - } - + validate: (code, context = {}, callback = null) => { if (typeof (context) === 'function') { callback = context context = {} From 66df5f05622dbc0ba0875ee6ad3901fd82b1848d Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 08:50:28 +0100 Subject: [PATCH 027/112] make one line func --- src/voucherify.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/voucherify.js b/src/voucherify.js index 03f3379..503d2c0 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -8,9 +8,8 @@ const assertOption = (options, name) => { } } -const encode = (value = '') => { - return encodeURIComponent(value) -} +const encode = (value = '') => encodeURIComponent(value) + module.exports = function (options) { assertOption(options, 'applicationId') From 398869124ad913eb2a0379ee6b24ba2bdcb8a3c8 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 08:52:28 +0100 Subject: [PATCH 028/112] extract isString function --- src/voucherify.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/voucherify.js b/src/voucherify.js index 503d2c0..c9b0809 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -9,7 +9,7 @@ const assertOption = (options, name) => { } const encode = (value = '') => encodeURIComponent(value) - +const isString = (value) => typeof (value) === 'string' module.exports = function (options) { assertOption(options, 'applicationId') @@ -119,7 +119,7 @@ module.exports = function (options) { const payload = {} // If `reason` passed, use it in query string. - if (typeof (data) === 'string') { + if (isString(data)) { qs['reason'] = encode(data) } @@ -138,8 +138,8 @@ module.exports = function (options) { publish: function (campaignName, callback) { let path = '/vouchers/publish' let payload = {} - if (typeof (campaignName) === 'string') { - path += '?campaign=' + encode(campaignName) + if (isString(campaignName)) { + qs = {campaign: encode(campaignName)} } if (typeof (campaignName) === 'object') { payload = campaignName From 9c4b07220b0902cf071abbf1c13bb215e51b62c2 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 09:06:36 +0100 Subject: [PATCH 029/112] extract isObject function with some additional check if not an array --- src/voucherify.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/voucherify.js b/src/voucherify.js index c9b0809..8e1a7a4 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -10,6 +10,7 @@ const assertOption = (options, name) => { const encode = (value = '') => encodeURIComponent(value) const isString = (value) => typeof (value) === 'string' +const isObject = (value) => typeof (value) === 'object' && !Array.isArray(value) module.exports = function (options) { assertOption(options, 'applicationId') @@ -88,7 +89,7 @@ module.exports = function (options) { redeem: (code, trackingId, callback) => { let context = {} - if (typeof (code) === 'object') { + if (isObject(code)) { context = code code = context.voucher delete context.voucher @@ -123,10 +124,10 @@ module.exports = function (options) { qs['reason'] = encode(data) } - if (typeof (data) === 'object') { qs['reason'] = data['reason'] || undefined qs['tracking_id'] = data['tracking_id'] || undefined payload['customer'] = data['customer'] || undefined + if (isObject(data)) { } return client.post( @@ -141,7 +142,7 @@ module.exports = function (options) { if (isString(campaignName)) { qs = {campaign: encode(campaignName)} } - if (typeof (campaignName) === 'object') { + if (isObject(campaignName)) { payload = campaignName } From c572d5dfbff5016d3ff5e77f9f2a26059f7bef2f Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 09:11:34 +0100 Subject: [PATCH 030/112] extract isFunction function --- src/voucherify.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/voucherify.js b/src/voucherify.js index 8e1a7a4..b6b71ec 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -11,6 +11,7 @@ const assertOption = (options, name) => { const encode = (value = '') => encodeURIComponent(value) const isString = (value) => typeof (value) === 'string' const isObject = (value) => typeof (value) === 'object' && !Array.isArray(value) +const isFunction = (value) => typeof (value) === 'function' module.exports = function (options) { assertOption(options, 'applicationId') @@ -35,7 +36,7 @@ module.exports = function (options) { }, delete: (voucherCode, params = {}, callback = null) => { - if (typeof (params) === 'function') { + if (isFunction(params)) { callback = params params = {} } @@ -61,7 +62,7 @@ module.exports = function (options) { }, validate: (code, context = {}, callback = null) => { - if (typeof (context) === 'function') { + if (isFunction(context)) { callback = context context = {} } @@ -96,7 +97,7 @@ module.exports = function (options) { } // No `tracking_id` passed here, // use callback from 2n argument. - if (typeof (trackingId) === 'function') { + if (isFunction(trackingId)) { callback = trackingId trackingId = undefined } @@ -111,7 +112,7 @@ module.exports = function (options) { }, rollback: (redemptionId, data, callback) => { - if (typeof (data) === 'function') { + if (isFunction(data)) { callback = data data = undefined } From d4cd1378bc278a31d282e4bb3199fec6293199dc Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 09:13:57 +0100 Subject: [PATCH 031/112] use isString --- src/voucherify.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/voucherify.js b/src/voucherify.js index b6b71ec..6f1238c 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -104,7 +104,7 @@ module.exports = function (options) { let url = `/vouchers/${encode(code)}/redemption` // If `tracking_id` passed, use it in query string. - if (typeof (trackingId) === 'string' && trackingId) { + if (isString(trackingId) && trackingId) { url += `?tracking_id=${encode(trackingId)}` } From 5ed064227a387fe174d5465d0fb718412d307968 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 09:24:13 +0100 Subject: [PATCH 032/112] simplify code --- src/voucherify.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/voucherify.js b/src/voucherify.js index 6f1238c..72eb714 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -117,18 +117,18 @@ module.exports = function (options) { data = undefined } - const qs = {} - const payload = {} + let qs = {} + let payload = {} // If `reason` passed, use it in query string. if (isString(data)) { - qs['reason'] = encode(data) + qs.reason = encode(data) } - qs['reason'] = data['reason'] || undefined - qs['tracking_id'] = data['tracking_id'] || undefined - payload['customer'] = data['customer'] || undefined if (isObject(data)) { + const {reason, tracking_id, customer} = data + qs = {reason, tracking_id} + payload = {customer} } return client.post( @@ -137,17 +137,18 @@ module.exports = function (options) { ) }, - publish: function (campaignName, callback) { - let path = '/vouchers/publish' + publish: (campaignName, callback) => { + let qs = {} let payload = {} + if (isString(campaignName)) { - qs = {campaign: encode(campaignName)} + qs.campaign = encode(campaignName) } if (isObject(campaignName)) { payload = campaignName } - return client.post(path, payload, callback) + return client.post('/vouchers/publish', payload, callback, {qs}) }, campaign: { From 6b2bfb18b24b1e23b9eadf10ec100201c88bbdff Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 09:26:32 +0100 Subject: [PATCH 033/112] check if not null --- src/voucherify.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/voucherify.js b/src/voucherify.js index 72eb714..6516e1f 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -10,7 +10,7 @@ const assertOption = (options, name) => { const encode = (value = '') => encodeURIComponent(value) const isString = (value) => typeof (value) === 'string' -const isObject = (value) => typeof (value) === 'object' && !Array.isArray(value) +const isObject = (value) => typeof (value) === 'object' && !Array.isArray(value) && value !== null const isFunction = (value) => typeof (value) === 'function' module.exports = function (options) { From 8ce44f06be9ce76446811482e8aa64d684f195b3 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 09:45:42 +0100 Subject: [PATCH 034/112] exclude logs --- .gitignore | 1 + .npmignore | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 560af40..ed3bf00 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ lib/ node_modules/ .idea/ +*.log diff --git a/.npmignore b/.npmignore index e274abb..a94a810 100644 --- a/.npmignore +++ b/.npmignore @@ -3,3 +3,4 @@ node_modules/ test/ examples/ release-sources-header.txt +*.log From bd2bd64c4b5b53f02347c63f0bf587d2ddb0eac6 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 09:46:25 +0100 Subject: [PATCH 035/112] don't use undefined; drop pointless comments --- src/voucherify.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/voucherify.js b/src/voucherify.js index 6516e1f..3ce4dfb 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -95,15 +95,13 @@ module.exports = function (options) { code = context.voucher delete context.voucher } - // No `tracking_id` passed here, - // use callback from 2n argument. if (isFunction(trackingId)) { callback = trackingId - trackingId = undefined + trackingId = null } let url = `/vouchers/${encode(code)}/redemption` - // If `tracking_id` passed, use it in query string. + if (isString(trackingId) && trackingId) { url += `?tracking_id=${encode(trackingId)}` } @@ -114,7 +112,7 @@ module.exports = function (options) { rollback: (redemptionId, data, callback) => { if (isFunction(data)) { callback = data - data = undefined + data = null } let qs = {} From 86bb1f6921a2ebecefd8740c2370e4c2dfd641e9 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 11:49:50 +0100 Subject: [PATCH 036/112] Add Travis CI config --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..265536c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +install: + - npm install From ab02eb1b8b0c154b83502d23c7254cb56475f53b Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 12:01:00 +0100 Subject: [PATCH 037/112] add Travis CI badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e5c1fd1..5881266 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ## Voucherify Node.js SDK [![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) +[![Build Status](https://travis-ci.org/rspective/voucherify-nodejs-sdk.svg?branch=refactor-and-new-methods)](https://travis-ci.org/rspective/voucherify-nodejs-sdk) [Voucherify](http://voucherify.io?utm_source=github&utm_medium=sdk&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: From 9fb3095504697bbc5f6657b9bdd3dccbc71e2549 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 13:29:28 +0100 Subject: [PATCH 038/112] run lint on ci --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 265536c..5f49be9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,6 @@ language: node_js install: - npm install +script: + - npm test + - npm run lint From 62b424b9c976cf7ac4a17b0675c42219c4d98c8a Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 15:39:03 +0100 Subject: [PATCH 039/112] extract helper methods --- src/helpers.js | 20 ++++++++++++++++++++ src/voucherify.js | 19 ++++++++----------- 2 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 src/helpers.js diff --git a/src/helpers.js b/src/helpers.js new file mode 100644 index 0000000..5879271 --- /dev/null +++ b/src/helpers.js @@ -0,0 +1,20 @@ +'use strict' + +const assertOption = (options, name) => { + if (!options[name]) { + throw new Error(`Missing required option '${name}'`) + } +} + +const encode = (value = '') => encodeURIComponent(value) +const isString = (value) => typeof (value) === 'string' +const isObject = (value) => typeof (value) === 'object' && !Array.isArray(value) && value !== null +const isFunction = (value) => typeof (value) === 'function' + +module.exports = { + assertOption, + encode, + isString, + isObject, + isFunction +} diff --git a/src/voucherify.js b/src/voucherify.js index 3ce4dfb..51d466b 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -1,17 +1,14 @@ 'use strict' const ApiClient = require('./ApiClient') - -const assertOption = (options, name) => { - if (!options[name]) { - throw new Error(`Missing required option '${name}'`) - } -} - -const encode = (value = '') => encodeURIComponent(value) -const isString = (value) => typeof (value) === 'string' -const isObject = (value) => typeof (value) === 'object' && !Array.isArray(value) && value !== null -const isFunction = (value) => typeof (value) === 'function' +const Vouchers = require('./Vouchers') +const { + assertOption, + encode, + isString, + isObject, + isFunction +} = require('./helpers') module.exports = function (options) { assertOption(options, 'applicationId') From cf039a731214c8ad910371656c5728942093029f Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 15:39:15 +0100 Subject: [PATCH 040/112] extract Vouchers namespace --- src/Vouchers.js | 64 +++++++++++++++++++++++++++++++++++++++++++++ src/voucherify.js | 66 +++++++++-------------------------------------- 2 files changed, 76 insertions(+), 54 deletions(-) create mode 100644 src/Vouchers.js diff --git a/src/Vouchers.js b/src/Vouchers.js new file mode 100644 index 0000000..1cf10e1 --- /dev/null +++ b/src/Vouchers.js @@ -0,0 +1,64 @@ +'use strict' + +const {encode, isFunction, isString, isObject} = require('./helpers') + +module.exports = class Vouchers { + constructor (client) { + this.client = client + } + + create (voucher, callback) { + return this.client.post(`/vouchers/${encode(voucher.code)}`, voucher, callback) + } + + get (code, callback) { + return this.client.get(`/vouchers/${encode(code)}`, null, callback) + } + + update (voucher, callback) { + return this.client.put(`/vouchers/${encode(voucher.code)}`, voucher, callback) + } + + delete (voucherCode, params = {}, callback = null) { + if (isFunction(params)) { + callback = params + params = {} + } + + let path = `/vouchers/${encode(voucherCode)}` + if (params.force) { + path += '?force=true' + } + + return this.client.delete(path, callback) + } + + list (query, callback) { + return this.client.get('/vouchers/', query, callback) + } + + publish (campaignName, callback) { + let qs = {} + let payload = {} + + if (isString(campaignName)) { + qs.campaign = encode(campaignName) + } + if (isObject(campaignName)) { + payload = campaignName + } + + return this.client.post('/vouchers/publish', payload, callback, {qs}) + } + + enable (code, callback) { + return this.client.post(`/vouchers/${encode(code)}/enable`, null, callback) + } + + disable (code, callback) { + return this.client.post(`/vouchers/${encode(code)}/disable`, null, callback) + } + + // TODO implement + ipmort () {} +} diff --git a/src/voucherify.js b/src/voucherify.js index 51d466b..81303d4 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -15,48 +15,20 @@ module.exports = function (options) { assertOption(options, 'clientSecretKey') const client = new ApiClient(options) + const vouchers = new Vouchers(client) return { - /* - * List vouchers. Sample query: { limit: 100, skip: 200, category: 'Loyalty' } - */ - list: (query, callback) => { - return client.get('/vouchers/', query, callback) - }, - - get: (code, callback) => { - return client.get(`/vouchers/${encode(code)}`, null, callback) - }, - - create: (voucher, callback) => { - return client.post(`/vouchers/${encode(voucher.code)}`, voucher, callback) - }, - - delete: (voucherCode, params = {}, callback = null) => { - if (isFunction(params)) { - callback = params - params = {} - } - - let path = `/vouchers/${encode(voucherCode)}` - if (params.force) { - path += '?force=true' - } - - return client.delete(path, callback) - }, - - update: (voucher, callback) => { - return client.put(`/vouchers/${encode(voucher.code)}`, voucher, callback) - }, - - enable: (code, callback) => { - return client.post(`/vouchers/${encode(code)}/enable`, null, callback) - }, - - disable: (code, callback) => { - return client.post(`/vouchers/${encode(code)}/disable`, null, callback) - }, + vouchers, + + // leaving for backward compatibility + list: (query, callback) => vouchers.list(query, callback), + get: (code, callback) => vouchers.get(code, callback), + create: (voucher, callback) => vouchers.create(voucher, callback), + delete: (code, params, callback) => vouchers.delete(code, params, callback), + update: (voucher, callback) => vouchers.update(voucher, callback), + enable: (code, callback) => vouchers.enable(code, callback), + disable: (code, callback) => vouchers.disable(code, callback), + publish: (campaignName, callback) => vouchers.publish(campaignName, callback), validate: (code, context = {}, callback = null) => { if (isFunction(context)) { @@ -132,20 +104,6 @@ module.exports = function (options) { ) }, - publish: (campaignName, callback) => { - let qs = {} - let payload = {} - - if (isString(campaignName)) { - qs.campaign = encode(campaignName) - } - if (isObject(campaignName)) { - payload = campaignName - } - - return client.post('/vouchers/publish', payload, callback, {qs}) - }, - campaign: { voucher: { create: (campaignName, voucher, callback) => { From 247a5d548f3f98f6d61880762a9370717dc86808 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 15:45:08 +0100 Subject: [PATCH 041/112] extract Campaigns namespace --- src/Campaigns.js | 18 ++++++++++++++++++ src/voucherify.js | 12 ++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 src/Campaigns.js diff --git a/src/Campaigns.js b/src/Campaigns.js new file mode 100644 index 0000000..ea2051f --- /dev/null +++ b/src/Campaigns.js @@ -0,0 +1,18 @@ +'use strict' + +const {encode} = require('./helpers') + +module.exports = class Campaigns { + constructor (client) { + this.client = client + } + + addVoucher (campaignName, voucher, callback) { + return this.client.post( + `/campaigns/${encode(campaignName)}/vouchers`, + // TODO if voucher is optional, secure against callback version + voucher || {}, + callback + ) + } +} diff --git a/src/voucherify.js b/src/voucherify.js index 81303d4..1e1eb32 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -1,6 +1,7 @@ 'use strict' const ApiClient = require('./ApiClient') +const Campaigns = require('./Campaigns') const Vouchers = require('./Vouchers') const { assertOption, @@ -16,9 +17,11 @@ module.exports = function (options) { const client = new ApiClient(options) const vouchers = new Vouchers(client) + const campaigns = new Campaigns(client) return { vouchers, + campaigns, // leaving for backward compatibility list: (query, callback) => vouchers.list(query, callback), @@ -106,14 +109,7 @@ module.exports = function (options) { campaign: { voucher: { - create: (campaignName, voucher, callback) => { - return client.post( - `/campaigns/${encode(campaignName)}/vouchers`, - // TODO if voucher is optional, secure against callback version - voucher || {}, - callback - ) - } + create: (campaignName, voucher, callback) => campaigns.addVoucher(campaignName, voucher, callback) } }, From 4fccd133a647678ffcac6cc81291d4714e5545ec Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 15:50:26 +0100 Subject: [PATCH 042/112] extract Validations namespace --- src/Validations.js | 18 ++++++++++++++++++ src/voucherify.js | 12 ++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 src/Validations.js diff --git a/src/Validations.js b/src/Validations.js new file mode 100644 index 0000000..aa3df37 --- /dev/null +++ b/src/Validations.js @@ -0,0 +1,18 @@ +'use strict' + +const {encode, isFunction} = require('./helpers') + +module.exports = class Validations { + constructor (client) { + this.client = client + } + + validateVoucher (code, context = {}, callback = null) { + if (isFunction(context)) { + callback = context + context = {} + } + + return this.client.post(`/vouchers/${encode(code)}/validate`, context, callback) + } +} diff --git a/src/voucherify.js b/src/voucherify.js index 1e1eb32..13151ba 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -3,6 +3,7 @@ const ApiClient = require('./ApiClient') const Campaigns = require('./Campaigns') const Vouchers = require('./Vouchers') +const Validations = require('./Validations') const { assertOption, encode, @@ -18,10 +19,12 @@ module.exports = function (options) { const client = new ApiClient(options) const vouchers = new Vouchers(client) const campaigns = new Campaigns(client) + const validations = new Validations(client) return { vouchers, campaigns, + validations, // leaving for backward compatibility list: (query, callback) => vouchers.list(query, callback), @@ -33,14 +36,7 @@ module.exports = function (options) { disable: (code, callback) => vouchers.disable(code, callback), publish: (campaignName, callback) => vouchers.publish(campaignName, callback), - validate: (code, context = {}, callback = null) => { - if (isFunction(context)) { - callback = context - context = {} - } - - return client.post(`/vouchers/${encode(code)}/validate`, context, callback) - }, + validate: (code, context, callback) => validations.validateVoucher(code, context, callback), redemption: (code, callback) => { return client.get(`/vouchers/${encode(code)}/redemption`, null, callback) From 8bcdadd1a1c1e7aef67372a6e679691ae6492071 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 16:08:21 +0100 Subject: [PATCH 043/112] extract Redemptions namespace --- src/Redemptions.js | 74 +++++++++++++++++++++++++++++++++++++++++++ src/voucherify.js | 78 ++++++---------------------------------------- 2 files changed, 84 insertions(+), 68 deletions(-) create mode 100644 src/Redemptions.js diff --git a/src/Redemptions.js b/src/Redemptions.js new file mode 100644 index 0000000..fae89e7 --- /dev/null +++ b/src/Redemptions.js @@ -0,0 +1,74 @@ +'use strict' + +const {encode, isFunction, isObject, isString} = require('./helpers') + +module.exports = class Redemptions { + constructor (client) { + this.client = client + } + + redeem (code, trackingId, callback) { + let context = {} + if (isObject(code)) { + context = code + code = context.voucher + delete context.voucher + } + if (isFunction(trackingId)) { + callback = trackingId + trackingId = null + } + + let url = `/vouchers/${encode(code)}/redemption` + + if (isString(trackingId) && trackingId) { + url += `?tracking_id=${encode(trackingId)}` + } + + return this.client.post(url, context, callback) + } + + /* + * List redemptions. Sample query (1000 successful redemptions from April 2016): + * { + * limit: 1000, + * page: 0, + * start_date: '2016-04-01T00:00:00', + * end_date: '2016-04-30T23:59:59', + * result: 'Success' + * } + */ + list (query, callback) { + return this.client.get('/redemptions/', query, callback) + } + + getForVoucher (code, callback) { + return this.client.get(`/vouchers/${encode(code)}/redemption`, null, callback) + } + + rollback (redemptionId, data, callback) { + if (isFunction(data)) { + callback = data + data = null + } + + let qs = {} + let payload = {} + + // If `reason` passed, use it in query string. + if (isString(data)) { + qs.reason = encode(data) + } + + if (isObject(data)) { + const {reason, tracking_id, customer} = data + qs = {reason, tracking_id} + payload = {customer} + } + + return this.client.post( + `/redemptions/${encode(redemptionId)}/rollback`, + payload, callback, {qs} + ) + } +} diff --git a/src/voucherify.js b/src/voucherify.js index 13151ba..19132e8 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -4,12 +4,11 @@ const ApiClient = require('./ApiClient') const Campaigns = require('./Campaigns') const Vouchers = require('./Vouchers') const Validations = require('./Validations') +const Redemptions = require('./Redemptions') + const { assertOption, - encode, - isString, - isObject, - isFunction + encode } = require('./helpers') module.exports = function (options) { @@ -20,11 +19,13 @@ module.exports = function (options) { const vouchers = new Vouchers(client) const campaigns = new Campaigns(client) const validations = new Validations(client) + const redemptions = new Redemptions(client) return { vouchers, campaigns, validations, + redemptions, // leaving for backward compatibility list: (query, callback) => vouchers.list(query, callback), @@ -38,70 +39,11 @@ module.exports = function (options) { validate: (code, context, callback) => validations.validateVoucher(code, context, callback), - redemption: (code, callback) => { - return client.get(`/vouchers/${encode(code)}/redemption`, null, callback) - }, - - /* - * List redemptions. Sample query (1000 successful redemptions from April 2016): - * { - * limit: 1000, - * page: 0, - * start_date: '2016-04-01T00:00:00', - * end_date: '2016-04-30T23:59:59', - * result: 'Success' - * } - */ - redemptions: (query, callback) => { - return client.get('/redemptions/', query, callback) - }, - - redeem: (code, trackingId, callback) => { - let context = {} - if (isObject(code)) { - context = code - code = context.voucher - delete context.voucher - } - if (isFunction(trackingId)) { - callback = trackingId - trackingId = null - } - - let url = `/vouchers/${encode(code)}/redemption` - - if (isString(trackingId) && trackingId) { - url += `?tracking_id=${encode(trackingId)}` - } - - return client.post(url, context, callback) - }, - - rollback: (redemptionId, data, callback) => { - if (isFunction(data)) { - callback = data - data = null - } - - let qs = {} - let payload = {} - - // If `reason` passed, use it in query string. - if (isString(data)) { - qs.reason = encode(data) - } - - if (isObject(data)) { - const {reason, tracking_id, customer} = data - qs = {reason, tracking_id} - payload = {customer} - } - - return client.post( - `/redemptions/${encode(redemptionId)}/rollback`, - payload, callback, {qs} - ) - }, + redemption: (code, callback) => redemptions.getForVoucher(code, callback), + // FIXME handle previous methods, copy and extend `list` function prototype + // redemptions: (query, callback) => redemptions.list(query, callback), + redeem: (code, trackingId, callback) => redemptions.redeem(code, trackingId, callback), + rollback: (redemptionId, data, callback) => redemptions.rollback(redemptionId, data, callback), campaign: { voucher: { From f73b26ff19c4884fb1a0362798c5fd8630628328 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 16:12:03 +0100 Subject: [PATCH 044/112] extract Customers namespace --- src/Customers.js | 22 ++++++++++++++++++++++ src/voucherify.js | 22 ++++------------------ 2 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 src/Customers.js diff --git a/src/Customers.js b/src/Customers.js new file mode 100644 index 0000000..2a9f90f --- /dev/null +++ b/src/Customers.js @@ -0,0 +1,22 @@ +'use strict' + +const {encode} = require('./helpers') + +module.exports = class Customers { + create (customer, callback) { + return this.client.post('/customers', customer, callback) + } + + get (customerId, callback) { + // TODO why fallback to empty string ?! shall we rather throw an error? print warning? + return this.client.get(`/customers/${encode(customerId)}`, null, callback) + } + + update (customer, callback) { + return this.client.put(`/customers/${encode(customer.id)}`, customer, callback) + } + + delete (customerId, callback) { + return this.client.delete(`/customers/${encode(customerId)}`, callback) + } +} diff --git a/src/voucherify.js b/src/voucherify.js index 19132e8..649c415 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -5,6 +5,7 @@ const Campaigns = require('./Campaigns') const Vouchers = require('./Vouchers') const Validations = require('./Validations') const Redemptions = require('./Redemptions') +const Customers = require('./Customers') const { assertOption, @@ -20,12 +21,14 @@ module.exports = function (options) { const campaigns = new Campaigns(client) const validations = new Validations(client) const redemptions = new Redemptions(client) + const customers = new Customers(client) return { vouchers, campaigns, validations, redemptions, + customers, // leaving for backward compatibility list: (query, callback) => vouchers.list(query, callback), @@ -51,24 +54,7 @@ module.exports = function (options) { } }, - customer: { - create: (customer, callback) => { - return client.post('/customers', customer, callback) - }, - - get: (customerId, callback) => { - // TODO why fallback to empty string ?! shall we rather throw an error? print warning? - return client.get(`/customers/${encode(customerId)}`, null, callback) - }, - - update: (customer, callback) => { - return client.put(`/customers/${encode(customer.id)}`, customer, callback) - }, - - delete: (customerId, callback) => { - return client.delete(`/customers/${encode(customerId)}`, callback) - } - }, + customer: customers, product: { create: (product, callback) => { From 2dbff93e7a6ea0b4e2843529ac3bf60ab192d834 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 16:20:02 +0100 Subject: [PATCH 045/112] extract Products namespace --- src/Products.js | 50 +++++++++++++++++++++++++++++++++++++++++ src/voucherify.js | 57 ++++++++++------------------------------------- 2 files changed, 62 insertions(+), 45 deletions(-) create mode 100644 src/Products.js diff --git a/src/Products.js b/src/Products.js new file mode 100644 index 0000000..de8303b --- /dev/null +++ b/src/Products.js @@ -0,0 +1,50 @@ +'use strict' + +const {encode} = require('./helpers') + +module.exports = class Products { + constructor (client) { + this.client = client + } + + create (product, callback) { + return this.client.post('/products', product, callback) + } + + get (productId, callback) { + return this.client.get(`/products/${encode(productId)}`, null, callback) + } + + update (product, callback) { + return this.client.put(`/products/${encode(product.id)}`, product, callback) + } + + delete (productId, callback) { + return this.client.delete(`/products/${encode(productId)}`, callback) + } + + createSku (productId, sku, callback) { + return this.client.post(`/products/${encode(productId)}/skus`, sku, callback) + } + + getSku (productId, skuId, callback) { + return this.client.get( + `/products/${encode(productId)}/skus/${encode(skuId)}`, + null, callback + ) + } + + updateSku (productId, sku, callback) { + return this.client.put( + `/products/${encode(productId)}/skus/${encode(sku.id)}`, + sku, callback + ) + } + + deleteSku (productId, skuId, callback) { + return this.client.delete( + `/products/${encode(productId)}/skus/${encode(skuId)}`, + callback + ) + } +} diff --git a/src/voucherify.js b/src/voucherify.js index 649c415..6e4d7fe 100644 --- a/src/voucherify.js +++ b/src/voucherify.js @@ -6,11 +6,8 @@ const Vouchers = require('./Vouchers') const Validations = require('./Validations') const Redemptions = require('./Redemptions') const Customers = require('./Customers') - -const { - assertOption, - encode -} = require('./helpers') +const Products = require('./Products') +const {assertOption} = require('./helpers') module.exports = function (options) { assertOption(options, 'applicationId') @@ -22,6 +19,7 @@ module.exports = function (options) { const validations = new Validations(client) const redemptions = new Redemptions(client) const customers = new Customers(client) + const products = new Products(client) return { vouchers, @@ -29,6 +27,7 @@ module.exports = function (options) { validations, redemptions, customers, + products, // leaving for backward compatibility list: (query, callback) => vouchers.list(query, callback), @@ -57,47 +56,15 @@ module.exports = function (options) { customer: customers, product: { - create: (product, callback) => { - return client.post('/products', product, callback) - }, - - get: (productId, callback) => { - return client.get(`/products/${encode(productId)}`, null, callback) - }, - - update: (product, callback) => { - return client.put(`/products/${encode(product.id)}`, product, callback) - }, - - delete: (productId, callback) => { - return client.delete(`/products/${encode(productId)}`, callback) - }, - + create: (product, callback) => products.create(product, callback), + get: (productId, callback) => products.get(productId, callback), + update: (product, callback) => products.update(product, callback), + delete: (productId, callback) => products.delete(productId), sku: { - create: (productId, sku, callback) => { - return client.post(`/products/${encode(productId)}/skus`, sku, callback) - }, - - get: (productId, skuId, callback) => { - return client.get( - `/products/${encode(productId)}/skus/${encode(skuId)}`, - null, callback - ) - }, - - update: (productId, sku, callback) => { - return client.put( - `/products/${encode(productId)}/skus/${encode(sku.id)}`, - sku, callback - ) - }, - - delete: (productId, skuId, callback) => { - return client.delete( - `/products/${encode(productId)}/skus/${encode(skuId)}`, - callback - ) - } + create: (productId, sku, callback) => products.createSku(productId, sku, callback), + get: (productId, skuId, callback) => products.getSku(productId, skuId, callback), + update: (productId, sku, callback) => products.updateSku(productId, sku, callback), + delete: (productId, skuId, callback) => products.deleteSku(productId, skuId, callback) } } } From f8b863ae30ecc7cdc37e06e9124244e966ffcf56 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 16:23:37 +0100 Subject: [PATCH 046/112] rename voucherify.js -> index.js --- package.json | 2 +- src/{voucherify.js => index.js} | 0 test/voucherify.spec.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{voucherify.js => index.js} (100%) diff --git a/package.json b/package.json index 4ac5933..7fba447 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "description": "Node.js SDK for Voucherify.", "author": "rspective", "license": "MIT", - "main": "./lib/voucherify.js", + "main": "./lib/index.js", "repository": { "type": "git", "url": "https://github.com/rspective/voucherify-nodejs-sdk.git" diff --git a/src/voucherify.js b/src/index.js similarity index 100% rename from src/voucherify.js rename to src/index.js diff --git a/test/voucherify.spec.js b/test/voucherify.spec.js index 03a148f..454f95f 100644 --- a/test/voucherify.spec.js +++ b/test/voucherify.spec.js @@ -1,5 +1,5 @@ /* global describe, it, expect */ -const voucherifyClient = require('../src/voucherify.js') +const voucherifyClient = require('../src/index.js') describe('voucherify', function () { it('should detect missing applicationId', function () { From 6b6f8ed631ded1984a4b0ca4e7a12879ff66d129 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 17:31:04 +0100 Subject: [PATCH 047/112] expose deprecated redemptions list method --- src/index.js | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index 6e4d7fe..26d6ecd 100644 --- a/src/index.js +++ b/src/index.js @@ -21,15 +21,36 @@ module.exports = function (options) { const customers = new Customers(client) const products = new Products(client) + /** + * Copy redemptions.list method and extend it so we can run: + * + * // deprecated + * api.redemptions(query, callback) + * + * // new + * api.redemptions.list(query, callback) + * api.redemptions.redeem(code, trackingId, callback) + * // ... + */ + const backwardCompatibleRedemptions = redemptions.list.bind(redemptions) + // add to func object all redemption functions bound to it's context + for (const i in redemptions) { + if (typeof (redemptions[i]) === 'function') { + backwardCompatibleRedemptions[i].redemptions[i].bind(redemptions) + } + } + return { vouchers, campaigns, validations, - redemptions, + redemptions: backwardCompatibleRedemptions, customers, products, // leaving for backward compatibility + + // vouchers list: (query, callback) => vouchers.list(query, callback), get: (code, callback) => vouchers.get(code, callback), create: (voucher, callback) => vouchers.create(voucher, callback), @@ -38,23 +59,21 @@ module.exports = function (options) { enable: (code, callback) => vouchers.enable(code, callback), disable: (code, callback) => vouchers.disable(code, callback), publish: (campaignName, callback) => vouchers.publish(campaignName, callback), - + // validations validate: (code, context, callback) => validations.validateVoucher(code, context, callback), - + // redemptions redemption: (code, callback) => redemptions.getForVoucher(code, callback), - // FIXME handle previous methods, copy and extend `list` function prototype - // redemptions: (query, callback) => redemptions.list(query, callback), redeem: (code, trackingId, callback) => redemptions.redeem(code, trackingId, callback), rollback: (redemptionId, data, callback) => redemptions.rollback(redemptionId, data, callback), - + // campaigns campaign: { voucher: { create: (campaignName, voucher, callback) => campaigns.addVoucher(campaignName, voucher, callback) } }, - + // customers customer: customers, - + // products product: { create: (product, callback) => products.create(product, callback), get: (productId, callback) => products.get(productId, callback), From 5f41b32cc2e87ded33b5b5d8524963a9c866684e Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 25 Nov 2016 17:37:08 +0100 Subject: [PATCH 048/112] simplify and clarify --- src/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 26d6ecd..efd6d96 100644 --- a/src/index.js +++ b/src/index.js @@ -7,7 +7,7 @@ const Validations = require('./Validations') const Redemptions = require('./Redemptions') const Customers = require('./Customers') const Products = require('./Products') -const {assertOption} = require('./helpers') +const {assertOption, isFunction} = require('./helpers') module.exports = function (options) { assertOption(options, 'applicationId') @@ -33,9 +33,9 @@ module.exports = function (options) { * // ... */ const backwardCompatibleRedemptions = redemptions.list.bind(redemptions) - // add to func object all redemption functions bound to it's context + // copy to func object all redemption methods bound to it's context for (const i in redemptions) { - if (typeof (redemptions[i]) === 'function') { + if (isFunction(redemptions[i])) { backwardCompatibleRedemptions[i].redemptions[i].bind(redemptions) } } From 5cbe6a0be90a49dd6902a9801aff042303c32be8 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 07:41:28 +0100 Subject: [PATCH 049/112] allow override request options --- src/ApiClient.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ApiClient.js b/src/ApiClient.js index 10d99ec..6e45ad0 100644 --- a/src/ApiClient.js +++ b/src/ApiClient.js @@ -78,24 +78,24 @@ module.exports = class ApiClient { return handler.promise } - put (path, body, callback) { + put (path, body, callback, options = {}) { const handler = prepare(callback) - request.put({ + request.put(Object.assign({ url: this.prepareUrl(path), headers: this.headers, body, json: true - }, handler.callback) + }, options), handler.callback) return handler.promise } - delete (path, json, callback) { + delete (path, json, callback, options = {}) { const handler = prepare(callback) - request.del({ + request.del(Object.assign({ url: this.prepareUrl(path), headers: this.headers - }, handler.callback) + }, options), handler.callback) return handler.promise } From 2a956e30739766916c14c58bacc4b43c81e99370 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 07:42:09 +0100 Subject: [PATCH 050/112] code simplification --- src/Vouchers.js | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/Vouchers.js b/src/Vouchers.js index 1cf10e1..69addf9 100644 --- a/src/Vouchers.js +++ b/src/Vouchers.js @@ -25,12 +25,9 @@ module.exports = class Vouchers { params = {} } - let path = `/vouchers/${encode(voucherCode)}` - if (params.force) { - path += '?force=true' - } - - return this.client.delete(path, callback) + return this.client.delete(`/vouchers/${encode(voucherCode)}`, callback, { + qs: {force: !!params.force} + }) } list (query, callback) { @@ -38,17 +35,15 @@ module.exports = class Vouchers { } publish (campaignName, callback) { - let qs = {} - let payload = {} - if (isString(campaignName)) { - qs.campaign = encode(campaignName) + return this.client.post('/vouchers/publish', null, callback, { + qs: {campaign: encode(campaignName)} + }) } + if (isObject(campaignName)) { - payload = campaignName + return this.client.post('/vouchers/publish', campaignName, callback) } - - return this.client.post('/vouchers/publish', payload, callback, {qs}) } enable (code, callback) { From 56f5c1683eaaac940b0b7c2168640dd792a89e7a Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 07:44:40 +0100 Subject: [PATCH 051/112] add vouchers import --- src/Vouchers.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Vouchers.js b/src/Vouchers.js index 69addf9..63000f4 100644 --- a/src/Vouchers.js +++ b/src/Vouchers.js @@ -54,6 +54,7 @@ module.exports = class Vouchers { return this.client.post(`/vouchers/${encode(code)}/disable`, null, callback) } - // TODO implement - ipmort () {} + import (vouchers, callback) { + return this.client.post(`/vouchers/import`, vouchers, callback) + } } From d98574f41b62a3b9d34f8368220c05f265cc26ff Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 08:12:39 +0100 Subject: [PATCH 052/112] extract preparing options --- src/ApiClient.js | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/src/ApiClient.js b/src/ApiClient.js index 6e45ad0..13b0ce7 100644 --- a/src/ApiClient.js +++ b/src/ApiClient.js @@ -50,53 +50,35 @@ module.exports = class ApiClient { } } - prepareUrl (path) { - return `${this.basePath}/${path}` + prepareOptions (path, options) { + return Object.assign({ + url: `${this.basePath}${path}`, + headers: this.headers, + json: true + }, options) } get (path, qs, callback) { const handler = prepare(callback) - request.get({ - url: this.prepareUrl(path), - qs, - headers: this.headers, - json: true - }, handler.callback) - + request.get(this.prepareOptions(path, {qs}), handler.callback) return handler.promise } post (path, body, callback, options = {}) { const handler = prepare(callback) - request.get(Object.assign({ - url: this.prepareUrl(path), - headers: this.headers, - body, - json: true - }, options), handler.callback) - + request.post(this.prepareOptions(path, {body, ...options}), handler.callback) return handler.promise } put (path, body, callback, options = {}) { const handler = prepare(callback) - request.put(Object.assign({ - url: this.prepareUrl(path), - headers: this.headers, - body, - json: true - }, options), handler.callback) - + request.put(this.prepareOptions(path, {body, ...options}), handler.callback) return handler.promise } - delete (path, json, callback, options = {}) { + delete (path, callback, options = {}) { const handler = prepare(callback) - request.del(Object.assign({ - url: this.prepareUrl(path), - headers: this.headers - }, options), handler.callback) - + request.del(this.prepareOptions(path, options), handler.callback) return handler.promise } } From 67e32370dccb7165219e58c05cb67408e795c054 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 08:24:14 +0100 Subject: [PATCH 053/112] rename --- src/Vouchers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Vouchers.js b/src/Vouchers.js index 63000f4..a0cb0b4 100644 --- a/src/Vouchers.js +++ b/src/Vouchers.js @@ -19,13 +19,13 @@ module.exports = class Vouchers { return this.client.put(`/vouchers/${encode(voucher.code)}`, voucher, callback) } - delete (voucherCode, params = {}, callback = null) { + delete (code, params = {}, callback = null) { if (isFunction(params)) { callback = params params = {} } - return this.client.delete(`/vouchers/${encode(voucherCode)}`, callback, { + return this.client.delete(`/vouchers/${encode(code)}`, callback, { qs: {force: !!params.force} }) } From a603e1defd25851f2661e1e266ce7c081fceb0f0 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 08:24:31 +0100 Subject: [PATCH 054/112] add missing campaign api methods --- src/Campaigns.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Campaigns.js b/src/Campaigns.js index ea2051f..efe7cbd 100644 --- a/src/Campaigns.js +++ b/src/Campaigns.js @@ -7,6 +7,14 @@ module.exports = class Campaigns { this.client = client } + create (campaign, callback) { + return this.client.post('/campaigns', campaign, callback) + } + + get (name, callback) { + return this.client.get(`/campaigns/${encode(name)}`, null, callback) + } + addVoucher (campaignName, voucher, callback) { return this.client.post( `/campaigns/${encode(campaignName)}/vouchers`, @@ -15,4 +23,8 @@ module.exports = class Campaigns { callback ) } + + importVouchers (campaignName, vouchers, callback) { + return this.client.post(`/campaigns/${encode(campaignName)}/import`, vouchers, callback) + } } From 1f8c53f00d03f14ea2f71c3aed5e09d85a48df9f Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 08:33:57 +0100 Subject: [PATCH 055/112] not required / --- src/Redemptions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Redemptions.js b/src/Redemptions.js index fae89e7..65fa21f 100644 --- a/src/Redemptions.js +++ b/src/Redemptions.js @@ -39,7 +39,7 @@ module.exports = class Redemptions { * } */ list (query, callback) { - return this.client.get('/redemptions/', query, callback) + return this.client.get('/redemptions', query, callback) } getForVoucher (code, callback) { From 69b942a8c2343adcd254499b8663cccaf7e9ca87 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 08:34:15 +0100 Subject: [PATCH 056/112] add missing Product API methods --- src/Products.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Products.js b/src/Products.js index de8303b..5ea51cf 100644 --- a/src/Products.js +++ b/src/Products.js @@ -23,6 +23,10 @@ module.exports = class Products { return this.client.delete(`/products/${encode(productId)}`, callback) } + list (callback) { + return this.client.get('/products', null, callback) + } + createSku (productId, sku, callback) { return this.client.post(`/products/${encode(productId)}/skus`, sku, callback) } @@ -47,4 +51,8 @@ module.exports = class Products { callback ) } + + listSkus (productId, callback) { + return this.client.get(`/products/${encode(productId)}/skus`, null, callback) + } } From 784d2f72ae8198e3fd67ce70c648bbc672b4efc8 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 12:26:28 +0100 Subject: [PATCH 057/112] use Object.assign instead of object rest/spread not yet available in LTS node implementation --- src/ApiClient.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ApiClient.js b/src/ApiClient.js index 13b0ce7..0f53017 100644 --- a/src/ApiClient.js +++ b/src/ApiClient.js @@ -66,13 +66,13 @@ module.exports = class ApiClient { post (path, body, callback, options = {}) { const handler = prepare(callback) - request.post(this.prepareOptions(path, {body, ...options}), handler.callback) + request.post(this.prepareOptions(path, Object.assign({}, body, {options})), handler.callback) return handler.promise } put (path, body, callback, options = {}) { const handler = prepare(callback) - request.put(this.prepareOptions(path, {body, ...options}), handler.callback) + request.put(this.prepareOptions(path, Object.assign({}, body, {options})), handler.callback) return handler.promise } From 1744dae861a33f5690ac56f0251312c951e2096a Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 14:21:52 +0100 Subject: [PATCH 058/112] more verbose test report --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7fba447..ffbc575 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "standard": "^8.6.0" }, "scripts": { - "test": "jasmine-node ./test", + "test": "jasmine-node --verbose --captureExceptions ./test", "lint": "standard", "prepublish": "gulp release" } From ef463ffbbcfa53bee623f415e6f1b3b111af1a78 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 14:22:29 +0100 Subject: [PATCH 059/112] cover getting vouchers with tests --- package.json | 1 + test/utils.js | 18 ++++++++++++++++++ test/vouchers-api.spec.js | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 test/utils.js create mode 100644 test/vouchers-api.spec.js diff --git a/package.json b/package.json index ffbc575..c608438 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "gulp": "^3.9.1", "gulp-babel": "^6.1.2", "jasmine-node": "~1.14.5", + "nock": "^9.0.2", "standard": "^8.6.0" }, "scripts": { diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 0000000..3007276 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,18 @@ +'use strict' + +module.exports = { + validateCallbackResult: (done, server) => { + return (err, result) => { + expect(err).toBeNull() + server.done() + done() + } + }, + + validateResolvedPromise: (done, server) => { + return () => { + server.done() + done() + } + } +} diff --git a/test/vouchers-api.spec.js b/test/vouchers-api.spec.js new file mode 100644 index 0000000..9f4a5e9 --- /dev/null +++ b/test/vouchers-api.spec.js @@ -0,0 +1,38 @@ +/* eslint-env jasmine */ +const nock = require('nock') +const VoucherifyClient = require('../src/index') +const { + validateCallbackResult, + validateResolvedPromise +} = require('./utils') +nock.disableNetConnect() + +describe('Vouchers API', function () { + const client = new VoucherifyClient({ + applicationId: 'node-sdk-test-id', + clientSecretKey: 'node-sdk-test-secret' + }) + + describe('get voucher', function () { + let server + beforeEach(function () { + server = nock('https://api.voucherify.io') + .get('/v1/vouchers/test-code') + .reply(200, {}) + }) + + it('should execute request (callback)', function (done) { + client.vouchers.get('test-code', validateCallbackResult(done, server)) + }) + + it('should execute request', function (done) { + client.vouchers.get('test-code') + .then(validateResolvedPromise(done, server)) + }) + + it('should execute request (deprected method)', function (done) { + client.get('test-code') + .then(validateResolvedPromise(done, server)) + }) + }) +}) From 70a520dc9ca57b8c61aa9c8c71995e34ed560ffa Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 14:42:05 +0100 Subject: [PATCH 060/112] bug fix wrong object merge --- src/ApiClient.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ApiClient.js b/src/ApiClient.js index 0f53017..07bd85f 100644 --- a/src/ApiClient.js +++ b/src/ApiClient.js @@ -66,13 +66,13 @@ module.exports = class ApiClient { post (path, body, callback, options = {}) { const handler = prepare(callback) - request.post(this.prepareOptions(path, Object.assign({}, body, {options})), handler.callback) + request.post(this.prepareOptions(path, Object.assign({}, {body}, options)), handler.callback) return handler.promise } put (path, body, callback, options = {}) { const handler = prepare(callback) - request.put(this.prepareOptions(path, Object.assign({}, body, {options})), handler.callback) + request.put(this.prepareOptions(path, Object.assign({}, {body}, options)), handler.callback) return handler.promise } From 8a47ef08c9b23de68eff1f1448b184f5d7fe2d7e Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 14:42:28 +0100 Subject: [PATCH 061/112] proper eslint-env --- test/utils.spec.js | 2 +- test/voucherify.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utils.spec.js b/test/utils.spec.js index bb342a8..b9b595f 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -1,4 +1,4 @@ -/* global describe, it, expect */ +/* eslint-env jasmine */ const utils = require('../src/utils.js') describe('utils', function () { diff --git a/test/voucherify.spec.js b/test/voucherify.spec.js index 454f95f..3a99006 100644 --- a/test/voucherify.spec.js +++ b/test/voucherify.spec.js @@ -1,4 +1,4 @@ -/* global describe, it, expect */ +/* eslint-env jasmine */ const voucherifyClient = require('../src/index.js') describe('voucherify', function () { From 360b2d5978fd049bfacabd9874a37685359f2e3e Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 15:10:10 +0100 Subject: [PATCH 062/112] cover all Vouchers API methods with tests --- src/Vouchers.js | 2 +- test/utils.js | 18 ---- test/vouchers-api.spec.js | 184 ++++++++++++++++++++++++++++++++++---- 3 files changed, 168 insertions(+), 36 deletions(-) delete mode 100644 test/utils.js diff --git a/src/Vouchers.js b/src/Vouchers.js index a0cb0b4..c06cac5 100644 --- a/src/Vouchers.js +++ b/src/Vouchers.js @@ -31,7 +31,7 @@ module.exports = class Vouchers { } list (query, callback) { - return this.client.get('/vouchers/', query, callback) + return this.client.get('/vouchers', query, callback) } publish (campaignName, callback) { diff --git a/test/utils.js b/test/utils.js deleted file mode 100644 index 3007276..0000000 --- a/test/utils.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict' - -module.exports = { - validateCallbackResult: (done, server) => { - return (err, result) => { - expect(err).toBeNull() - server.done() - done() - } - }, - - validateResolvedPromise: (done, server) => { - return () => { - server.done() - done() - } - } -} diff --git a/test/vouchers-api.spec.js b/test/vouchers-api.spec.js index 9f4a5e9..a496aa1 100644 --- a/test/vouchers-api.spec.js +++ b/test/vouchers-api.spec.js @@ -1,10 +1,6 @@ /* eslint-env jasmine */ const nock = require('nock') const VoucherifyClient = require('../src/index') -const { - validateCallbackResult, - validateResolvedPromise -} = require('./utils') nock.disableNetConnect() describe('Vouchers API', function () { @@ -13,26 +9,180 @@ describe('Vouchers API', function () { clientSecretKey: 'node-sdk-test-secret' }) - describe('get voucher', function () { - let server - beforeEach(function () { - server = nock('https://api.voucherify.io') - .get('/v1/vouchers/test-code') + it('should create voucher', function (done) { + const server = nock('https://api.voucherify.io') + .post('/v1/vouchers/test-code', { + code: 'test-code', + type: 'DISCOUNT_VOUCHER' + }) + .reply(200, {}) + + client.vouchers.create({ + code: 'test-code', + type: 'DISCOUNT_VOUCHER' + }) + .then(() => { + server.done() + done() + }) + }) + + it('should get voucher', function (done) { + const server = nock('https://api.voucherify.io') + .get('/v1/vouchers/test-code') + .reply(200, {}) + + client.vouchers.get('test-code') + .then(() => { + server.done() + done() + }) + }) + + it('should update voucher', function (done) { + const server = nock('https://api.voucherify.io') + .put('/v1/vouchers/test-code', { + code: 'test-code', + type: 'DISCOUNT_VOUCHER' + }) + .reply(200, {}) + + client.vouchers.update({ + code: 'test-code', + type: 'DISCOUNT_VOUCHER' + }) + .then(() => { + server.done() + done() + }) + }) + + describe('delete voucher', function () { + it('should delete, but not permanently', function (done) { + const server = nock('https://api.voucherify.io') + .delete('/v1/vouchers/test-code') + .query({force: false}) .reply(200, {}) + + client.vouchers.delete('test-code') + .then(() => { + server.done() + done() + }) }) - it('should execute request (callback)', function (done) { - client.vouchers.get('test-code', validateCallbackResult(done, server)) + it('should delete, but not permanently (callback)', function (done) { + const server = nock('https://api.voucherify.io') + .delete('/v1/vouchers/test-code') + .query({force: false}) + .reply(200, {}) + + client.vouchers.delete('test-code', (err) => { + expect(err).toBeNull() + server.done() + done() + }) }) - it('should execute request', function (done) { - client.vouchers.get('test-code') - .then(validateResolvedPromise(done, server)) + it('should delete permanently', function (done) { + const server = nock('https://api.voucherify.io') + .delete('/v1/vouchers/test-code') + .query({force: true}) + .reply(200, {}) + + client.vouchers.delete('test-code', {force: true}) + .then(() => { + server.done() + done() + }) }) + }) + + it('should list vouchers by query', function (done) { + const server = nock('https://api.voucherify.io') + .get('/v1/vouchers') + .query({campaign: 'test-campaign'}) + .reply(200, {}) + + client.vouchers.list({campaign: 'test-campaign'}) + .then(() => { + server.done() + done() + }) + }) + + describe('publish voucher', function () { + it('should publish by camaign name', function (done) { + const server = nock('https://api.voucherify.io') + .post('/v1/vouchers/publish') + .query({campaign: 'test-campaign'}) + .reply(200, {}) + + client.vouchers.publish('test-campaign') + .then(() => { + server.done() + done() + }) + }) + + it('should publish by voucher', function (done) { + const server = nock('https://api.voucherify.io') + .post('/v1/vouchers/publish', { + campaign: 'test-campaign', + voucher: 'test-voucher' + }) + .reply(200, {}) + + client.vouchers.publish({ + campaign: 'test-campaign', + voucher: 'test-voucher' + }) + .then(() => { + server.done() + done() + }) + }) + }) + + it('should enable voucher', function (done) { + const server = nock('https://api.voucherify.io') + .post('/v1/vouchers/test-voucher/enable') + .reply(200, {}) + + client.vouchers.enable('test-voucher') + .then(() => { + server.done() + done() + }) + }) + + it('should disable voucher', function (done) { + const server = nock('https://api.voucherify.io') + .post('/v1/vouchers/test-voucher/disable') + .reply(200, {}) + + client.vouchers.disable('test-voucher') + .then(() => { + server.done() + done() + }) + }) + + it('should import vouchers', function (done) { + const server = nock('https://api.voucherify.io') + .post('/v1/vouchers/import', [ + {code: 'test-voucher1'}, + {code: 'test-voucher2'} + ]) + .reply(200, {}) - it('should execute request (deprected method)', function (done) { - client.get('test-code') - .then(validateResolvedPromise(done, server)) + client.vouchers.import([ + {code: 'test-voucher1'}, + {code: 'test-voucher2'} + ]) + .then(() => { + server.done() + done() }) }) }) From 0512962024c6d5e7b22b7ab416837febfec058b1 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 15:21:55 +0100 Subject: [PATCH 063/112] add reqheaders --- test/fixtures.js | 7 +++++++ test/vouchers-api.spec.js | 25 +++++++++++++------------ 2 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 test/fixtures.js diff --git a/test/fixtures.js b/test/fixtures.js new file mode 100644 index 0000000..9944bc4 --- /dev/null +++ b/test/fixtures.js @@ -0,0 +1,7 @@ +module.exports = { + reqheaders: { + 'X-App-Id': 'node-sdk-test-id', + 'X-App-Token': 'node-sdk-test-secret', + 'X-Voucherify-Channel': 'Node.js-SDK' + } +} diff --git a/test/vouchers-api.spec.js b/test/vouchers-api.spec.js index a496aa1..f6ff1f0 100644 --- a/test/vouchers-api.spec.js +++ b/test/vouchers-api.spec.js @@ -1,6 +1,7 @@ /* eslint-env jasmine */ const nock = require('nock') const VoucherifyClient = require('../src/index') +const {reqheaders} = require('./fixtures') nock.disableNetConnect() describe('Vouchers API', function () { @@ -10,7 +11,7 @@ describe('Vouchers API', function () { }) it('should create voucher', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .post('/v1/vouchers/test-code', { code: 'test-code', type: 'DISCOUNT_VOUCHER' @@ -28,7 +29,7 @@ describe('Vouchers API', function () { }) it('should get voucher', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .get('/v1/vouchers/test-code') .reply(200, {}) @@ -40,7 +41,7 @@ describe('Vouchers API', function () { }) it('should update voucher', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .put('/v1/vouchers/test-code', { code: 'test-code', type: 'DISCOUNT_VOUCHER' @@ -59,7 +60,7 @@ describe('Vouchers API', function () { describe('delete voucher', function () { it('should delete, but not permanently', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .delete('/v1/vouchers/test-code') .query({force: false}) .reply(200, {}) @@ -72,7 +73,7 @@ describe('Vouchers API', function () { }) it('should delete, but not permanently (callback)', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .delete('/v1/vouchers/test-code') .query({force: false}) .reply(200, {}) @@ -85,7 +86,7 @@ describe('Vouchers API', function () { }) it('should delete permanently', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .delete('/v1/vouchers/test-code') .query({force: true}) .reply(200, {}) @@ -99,7 +100,7 @@ describe('Vouchers API', function () { }) it('should list vouchers by query', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .get('/v1/vouchers') .query({campaign: 'test-campaign'}) .reply(200, {}) @@ -113,7 +114,7 @@ describe('Vouchers API', function () { describe('publish voucher', function () { it('should publish by camaign name', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .post('/v1/vouchers/publish') .query({campaign: 'test-campaign'}) .reply(200, {}) @@ -126,7 +127,7 @@ describe('Vouchers API', function () { }) it('should publish by voucher', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .post('/v1/vouchers/publish', { campaign: 'test-campaign', voucher: 'test-voucher' @@ -145,7 +146,7 @@ describe('Vouchers API', function () { }) it('should enable voucher', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .post('/v1/vouchers/test-voucher/enable') .reply(200, {}) @@ -157,7 +158,7 @@ describe('Vouchers API', function () { }) it('should disable voucher', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .post('/v1/vouchers/test-voucher/disable') .reply(200, {}) @@ -169,7 +170,7 @@ describe('Vouchers API', function () { }) it('should import vouchers', function (done) { - const server = nock('https://api.voucherify.io') + const server = nock('https://api.voucherify.io', {reqheaders}) .post('/v1/vouchers/import', [ {code: 'test-voucher1'}, {code: 'test-voucher2'} From b964c6f2426f4af78049c9c025fed6f5a3c4e9bf Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 16:02:14 +0100 Subject: [PATCH 064/112] cover Campaigns API with tests --- test/camapigns-api.spec.js | 72 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 test/camapigns-api.spec.js diff --git a/test/camapigns-api.spec.js b/test/camapigns-api.spec.js new file mode 100644 index 0000000..34c7d90 --- /dev/null +++ b/test/camapigns-api.spec.js @@ -0,0 +1,72 @@ +/* eslint-env jasmine */ +const nock = require('nock') +const VoucherifyClient = require('../src/index') +const {reqheaders} = require('./fixtures') +nock.disableNetConnect() + +describe('Campaigns API', function () { + const client = new VoucherifyClient({ + applicationId: 'node-sdk-test-id', + clientSecretKey: 'node-sdk-test-secret' + }) + + it('should create campaign', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/campaigns', { + name: 'test campaign' + }) + .reply(200, {}) + + client.campaigns.create({ + name: 'test campaign' + }) + .then(() => { + server.done() + done() + }) + }) + + it('should get camaign', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .get('/v1/campaigns/test%20campaign') + .reply(200, {}) + + client.campaigns.get('test campaign') + .then(() => { + server.done() + done() + }) + }) + + it('should add voucher', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/campaigns/test%20campaign/vouchers', { + code: 'test voucher' + }) + .reply(200, {}) + + client.campaigns.addVoucher('test campaign', { + code: 'test voucher' + }) + .then(() => { + server.done() + done() + }) + }) + + it('should add voucher', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/campaigns/test%20campaign/import', [{ + code: 'test voucher' + }]) + .reply(200, {}) + + client.campaigns.importVouchers('test campaign', [{ + code: 'test voucher' + }]) + .then(() => { + server.done() + done() + }) + }) +}) From 4389dc512e3f8bd6272c6d4fa26be15276fbb1ec Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 16:10:38 +0100 Subject: [PATCH 065/112] cover Validations API with tests --- test/validations-api.spec.js | 54 ++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 test/validations-api.spec.js diff --git a/test/validations-api.spec.js b/test/validations-api.spec.js new file mode 100644 index 0000000..654fff7 --- /dev/null +++ b/test/validations-api.spec.js @@ -0,0 +1,54 @@ +/* eslint-env jasmine */ +const nock = require('nock') +const VoucherifyClient = require('../src/index') +const {reqheaders} = require('./fixtures') +nock.disableNetConnect() + +describe('Validations API', function () { + const client = new VoucherifyClient({ + applicationId: 'node-sdk-test-id', + clientSecretKey: 'node-sdk-test-secret' + }) + + describe('validate voucher', function () { + it('should validate without additional context', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/vouchers/test%20code/validate') + .reply(200, {}) + + client.validations.validateVoucher('test code') + .then(() => { + server.done() + done() + }) + }) + + it('should validate without additional context (callback)', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/vouchers/test%20code/validate') + .reply(200, {}) + + client.validations.validateVoucher('test code', (err) => { + expect(err).toBeNull() + server.done() + done() + }) + }) + + it('should validate with additional context', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/vouchers/test%20code/validate', { + tracking_id: 'tracking-id' + }) + .reply(200, {}) + + client.validations.validateVoucher('test code', { + tracking_id: 'tracking-id' + }) + .then(() => { + server.done() + done() + }) + }) + }) +}) From 1ad12b033835ee0ba53e9bca80c7b402d7d3a61a Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 18:05:46 +0100 Subject: [PATCH 066/112] handle optional query --- src/Redemptions.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Redemptions.js b/src/Redemptions.js index 65fa21f..14142bb 100644 --- a/src/Redemptions.js +++ b/src/Redemptions.js @@ -39,6 +39,11 @@ module.exports = class Redemptions { * } */ list (query, callback) { + if (isFunction(query)) { + callback = query + query = null + } + return this.client.get('/redemptions', query, callback) } From e208627da4f939052c9307da63c6d775aeb1092b Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 18:06:17 +0100 Subject: [PATCH 067/112] bugfix wrongly exposed backward compatible redemptions --- src/index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index efd6d96..a73e200 100644 --- a/src/index.js +++ b/src/index.js @@ -34,9 +34,11 @@ module.exports = function (options) { */ const backwardCompatibleRedemptions = redemptions.list.bind(redemptions) // copy to func object all redemption methods bound to it's context - for (const i in redemptions) { - if (isFunction(redemptions[i])) { - backwardCompatibleRedemptions[i].redemptions[i].bind(redemptions) + const exposedFunctions = Object.getOwnPropertyNames(Object.getPrototypeOf(redemptions)) + + for (const name of exposedFunctions) { + if (name !== 'constructor' && isFunction(redemptions[name])) { + backwardCompatibleRedemptions[name] = redemptions[name].bind(redemptions) } } From 447aa53d03bb561490a8d2a228814742bfdee8b8 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 18:13:40 +0100 Subject: [PATCH 068/112] cover Redemptions API with tests --- test/redemptions-api.spec.js | 186 +++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 test/redemptions-api.spec.js diff --git a/test/redemptions-api.spec.js b/test/redemptions-api.spec.js new file mode 100644 index 0000000..3fb9ea7 --- /dev/null +++ b/test/redemptions-api.spec.js @@ -0,0 +1,186 @@ +/* eslint-env jasmine */ +const nock = require('nock') +const VoucherifyClient = require('../src/index') +const {reqheaders} = require('./fixtures') +nock.disableNetConnect() + +describe('Redemptions API', function () { + const client = new VoucherifyClient({ + applicationId: 'node-sdk-test-id', + clientSecretKey: 'node-sdk-test-secret' + }) + + describe('redeem', function () { + it('should redeem by code', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/vouchers/test-code/redemption') + .reply(200, {}) + + client.redemptions.redeem('test-code') + .then(() => { + server.done() + done() + }) + }) + + it('should redeem by code (callback)', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/vouchers/test-code/redemption') + .reply(200, {}) + + client.redemptions.redeem('test-code', (err) => { + expect(err).toBeNull() + server.done() + done() + }) + }) + + it('should redeem by voucher', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/vouchers/test-code/redemption', { + customer: { + id: 'test-customer-id' + } + }) + .reply(200, {}) + + client.redemptions.redeem({ + voucher: 'test-code', + customer: { + id: 'test-customer-id' + } + }) + .then(() => { + server.done() + done() + }) + }) + + it('should redeem with tracking ID', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/vouchers/test-code/redemption') + .query({tracking_id: 'test-tracking-id'}) + .reply(200, {}) + + client.redemptions.redeem('test-code', 'test-tracking-id') + .then(() => { + server.done() + done() + }) + }) + }) + + describe('list', function () { + it('should list by query', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .get('/v1/redemptions') + .query({limit: 100}) + .reply(200, {}) + + client.redemptions.list({ + limit: 100 + }) + .then(() => { + server.done() + done() + }) + }) + + it('should list all', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .get('/v1/redemptions') + .reply(200, {}) + + client.redemptions.list() + .then(() => { + server.done() + done() + }) + }) + + it('should list all (callback)', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .get('/v1/redemptions') + .reply(200, {}) + + client.redemptions.list((err) => { + expect(err).toBeNull() + server.done() + done() + }) + }) + }) + + it('should get voucher redemptions', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .get('/v1/vouchers/test-code/redemption') + .reply(200, {}) + + client.redemptions.getForVoucher('test-code', (err) => { + expect(err).toBeNull() + server.done() + done() + }) + }) + + describe('rollback', function () { + it('should rollback without customer details', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/redemptions/test-redemption-id/rollback') + .reply(200, {}) + + client.redemptions.rollback('test-redemption-id') + .then(() => { + server.done() + done() + }) + }) + + it('should rollback without customer details (callback)', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/redemptions/test-redemption-id/rollback') + .reply(200, {}) + + client.redemptions.rollback('test-redemption-id', (err) => { + expect(err).toBeNull() + server.done() + done() + }) + }) + + it('should rollback with customer details', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/redemptions/test-redemption-id/rollback', { + customer: { + id: 'test-customer-id' + } + }) + .reply(200, {}) + + client.redemptions.rollback('test-redemption-id', { + customer: { + id: 'test-customer-id' + } + }) + .then(() => { + server.done() + done() + }) + }) + + it('should rollback with a reason', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/redemptions/test-redemption-id/rollback') + .query({ + reason: 'test%20reason' + }) + .reply(200, {}) + + client.redemptions.rollback('test-redemption-id', 'test reason') + .then(() => { + server.done() + done() + }) + }) + }) +}) From 5d78ddb141382dc5273573fe2f0dc20124dc7429 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 18:30:38 +0100 Subject: [PATCH 069/112] don't want to have empty query strings --- src/Redemptions.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Redemptions.js b/src/Redemptions.js index 14142bb..a2ebefa 100644 --- a/src/Redemptions.js +++ b/src/Redemptions.js @@ -67,7 +67,11 @@ module.exports = class Redemptions { if (isObject(data)) { const {reason, tracking_id, customer} = data - qs = {reason, tracking_id} + + qs = { + reason: reason ? encode(reason) : undefined, + tracking_id: tracking_id ? encode(tracking_id) : undefined // eslint-disable-line camelcase + } payload = {customer} } From 38cc2a01cadcb6e09323af827b13e29eb3abea14 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 18:30:56 +0100 Subject: [PATCH 070/112] cover rollback case with all details provided --- test/redemptions-api.spec.js | 58 ++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/test/redemptions-api.spec.js b/test/redemptions-api.spec.js index 3fb9ea7..1be87b0 100644 --- a/test/redemptions-api.spec.js +++ b/test/redemptions-api.spec.js @@ -73,9 +73,9 @@ describe('Redemptions API', function () { describe('list', function () { it('should list by query', function (done) { const server = nock('https://api.voucherify.io', {reqheaders}) - .get('/v1/redemptions') - .query({limit: 100}) - .reply(200, {}) + .get('/v1/redemptions') + .query({limit: 100}) + .reply(200, {}) client.redemptions.list({ limit: 100 @@ -100,8 +100,8 @@ describe('Redemptions API', function () { it('should list all (callback)', function (done) { const server = nock('https://api.voucherify.io', {reqheaders}) - .get('/v1/redemptions') - .reply(200, {}) + .get('/v1/redemptions') + .reply(200, {}) client.redemptions.list((err) => { expect(err).toBeNull() @@ -126,8 +126,8 @@ describe('Redemptions API', function () { describe('rollback', function () { it('should rollback without customer details', function (done) { const server = nock('https://api.voucherify.io', {reqheaders}) - .post('/v1/redemptions/test-redemption-id/rollback') - .reply(200, {}) + .post('/v1/redemptions/test-redemption-id/rollback') + .reply(200, {}) client.redemptions.rollback('test-redemption-id') .then(() => { @@ -138,8 +138,8 @@ describe('Redemptions API', function () { it('should rollback without customer details (callback)', function (done) { const server = nock('https://api.voucherify.io', {reqheaders}) - .post('/v1/redemptions/test-redemption-id/rollback') - .reply(200, {}) + .post('/v1/redemptions/test-redemption-id/rollback') + .reply(200, {}) client.redemptions.rollback('test-redemption-id', (err) => { expect(err).toBeNull() @@ -150,14 +150,40 @@ describe('Redemptions API', function () { it('should rollback with customer details', function (done) { const server = nock('https://api.voucherify.io', {reqheaders}) - .post('/v1/redemptions/test-redemption-id/rollback', { + .post('/v1/redemptions/test-redemption-id/rollback', { + customer: { + id: 'test-customer-id' + } + }) + .reply(200, {}) + + client.redemptions.rollback('test-redemption-id', { customer: { id: 'test-customer-id' } }) - .reply(200, {}) + .then(() => { + server.done() + done() + }) + }) + + it('should rollback with customer details, reason and tracking_id', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/redemptions/test-redemption-id/rollback', { + customer: { + id: 'test-customer-id' + } + }) + .query({ + reason: 'test%20reason', + tracking_id: 'test-tracking-id' + }) + .reply(200, {}) client.redemptions.rollback('test-redemption-id', { + reason: 'test reason', + tracking_id: 'test-tracking-id', customer: { id: 'test-customer-id' } @@ -170,11 +196,11 @@ describe('Redemptions API', function () { it('should rollback with a reason', function (done) { const server = nock('https://api.voucherify.io', {reqheaders}) - .post('/v1/redemptions/test-redemption-id/rollback') - .query({ - reason: 'test%20reason' - }) - .reply(200, {}) + .post('/v1/redemptions/test-redemption-id/rollback') + .query({ + reason: 'test%20reason' + }) + .reply(200, {}) client.redemptions.rollback('test-redemption-id', 'test reason') .then(() => { From 9647b263b2551be188c98648f3d60396c7ed572f Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 19:00:09 +0100 Subject: [PATCH 071/112] bugfix missing api client instance --- src/Customers.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Customers.js b/src/Customers.js index 2a9f90f..9ee3690 100644 --- a/src/Customers.js +++ b/src/Customers.js @@ -3,6 +3,10 @@ const {encode} = require('./helpers') module.exports = class Customers { + constructor (client) { + this.client = client + } + create (customer, callback) { return this.client.post('/customers', customer, callback) } From b6cb335b36c6bdaedf5a570aad66e1b32b6e7a53 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 19:00:23 +0100 Subject: [PATCH 072/112] cover Customers API with tests --- test/customers-api.spec.js | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 test/customers-api.spec.js diff --git a/test/customers-api.spec.js b/test/customers-api.spec.js new file mode 100644 index 0000000..0e5998d --- /dev/null +++ b/test/customers-api.spec.js @@ -0,0 +1,69 @@ +/* eslint-env jasmine */ +const nock = require('nock') +const VoucherifyClient = require('../src/index') +const {reqheaders} = require('./fixtures') +nock.disableNetConnect() + +describe('Customers API', function () { + const client = new VoucherifyClient({ + applicationId: 'node-sdk-test-id', + clientSecretKey: 'node-sdk-test-secret' + }) + + it('should create customer', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/customers', { + name: 'customer name' + }) + .reply(200, {}) + + client.customers.create({ + name: 'customer name' + }) + .then(() => { + server.done() + done() + }) + }) + + it('should get customer', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .get('/v1/customers/cust_test-id') + .reply(200, {}) + + client.customers.get('cust_test-id') + .then(() => { + server.done() + done() + }) + }) + + it('should update customer', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .put('/v1/customers/cust_test-id', { + name: 'customer name' + }) + .reply(200, {}) + + client.customers.update({ + id: 'cust_test-id', + name: 'customer name' + }) + .then(() => { + server.done() + done() + }) + }) + + it('should delete customer', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .delete('/v1/customers/cust_test-id') + .reply(200, {}) + + client.customers.delete('cust_test-id') + .then(() => { + server.done() + done() + }) + }) +}) From e1ad5563da125242363dd4efa3a32ece0c453fdc Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 19:12:24 +0100 Subject: [PATCH 073/112] cover Products API with tests --- test/products-api.spec.js | 156 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 test/products-api.spec.js diff --git a/test/products-api.spec.js b/test/products-api.spec.js new file mode 100644 index 0000000..6a532f0 --- /dev/null +++ b/test/products-api.spec.js @@ -0,0 +1,156 @@ +/* eslint-env jasmine */ +const nock = require('nock') +const VoucherifyClient = require('../src/index') +const {reqheaders} = require('./fixtures') +nock.disableNetConnect() + +describe('Products API', function () { + const client = new VoucherifyClient({ + applicationId: 'node-sdk-test-id', + clientSecretKey: 'node-sdk-test-secret' + }) + + it('should create product', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/products', { + name: 'product name' + }) + .reply(200, {}) + + client.products.create({ + name: 'product name' + }) + .then(() => { + server.done() + done() + }) + }) + + it('should get product', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .get('/v1/products/prod_test-id') + .reply(200, {}) + + client.products.get('prod_test-id') + .then(() => { + server.done() + done() + }) + }) + + it('should update product', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .put('/v1/products/prod_test-id', { + name: 'product name' + }) + .reply(200, {}) + + client.products.update({ + id: 'prod_test-id', + name: 'product name' + }) + .then(() => { + server.done() + done() + }) + }) + + it('should delete product', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .delete('/v1/products/prod_test-id') + .reply(200, {}) + + client.products.delete('prod_test-id') + .then(() => { + server.done() + done() + }) + }) + + it('should list products', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .get('/v1/products') + .reply(200, {}) + + client.products.list() + .then(() => { + server.done() + done() + }) + }) + + describe('SKU', function () { + it('should create SKU', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .post('/v1/products/prod_test-id/skus', { + sku: 'test sku' + }) + .reply(200, {}) + + client.products.createSku('prod_test-id', { + sku: 'test sku' + }) + .then(() => { + server.done() + done() + }) + }) + + it('should get SKU', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .get('/v1/products/prod_test-id/skus/test-sku') + .reply(200, {}) + + client.products.getSku('prod_test-id', 'test-sku') + .then(() => { + server.done() + done() + }) + }) + + it('should update SKU', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .put('/v1/products/prod_test-id/skus/test-sku', { + metadata: { + isTestSku: true + } + }) + .reply(200, {}) + + client.products.updateSku('prod_test-id', { + id: 'test-sku', + metadata: { + isTestSku: true + } + }) + .then(() => { + server.done() + done() + }) + }) + + it('should delete SKU', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .delete('/v1/products/prod_test-id/skus/test-sku') + .reply(200, {}) + + client.products.deleteSku('prod_test-id', 'test-sku') + .then(() => { + server.done() + done() + }) + }) + + it('should list SKUs', function (done) { + const server = nock('https://api.voucherify.io', {reqheaders}) + .get('/v1/products/prod_test-id/skus') + .reply(200, {}) + + client.products.listSkus('prod_test-id') + .then(() => { + server.done() + done() + }) + }) + }) +}) From af178c670585e5176cd98f7ec3723c17710aa8a2 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 20:42:21 +0100 Subject: [PATCH 074/112] add more badges --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 5881266..058222b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ [![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) [![Build Status](https://travis-ci.org/rspective/voucherify-nodejs-sdk.svg?branch=refactor-and-new-methods)](https://travis-ci.org/rspective/voucherify-nodejs-sdk) +[![NPM Version](https://img.shields.io/npm/v/voucherify.svg)](https://www.npmjs.com/package/voucherify) +[![NPM Downloads](https://img.shields.io/npm/dm/voucherify.svg)](https://www.npmjs.com/package/voucherify) +[![Dependencies](https://david-dm.org/rspective/voucherify-nodejs-sdk.svg)](https://www.npmjs.com/package/voucherify) [Voucherify](http://voucherify.io?utm_source=github&utm_medium=sdk&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: From 2ad30b1367f40f1447257ff94c08028a6581d8ed Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 21:55:19 +0100 Subject: [PATCH 075/112] check content-type and accept headers --- test/camapigns-api.spec.js | 10 +++++----- test/customers-api.spec.js | 10 +++++----- test/fixtures.js | 20 ++++++++++++++++---- test/products-api.spec.js | 22 +++++++++++----------- test/redemptions-api.spec.js | 28 ++++++++++++++-------------- test/validations-api.spec.js | 8 ++++---- test/vouchers-api.spec.js | 26 +++++++++++++------------- 7 files changed, 68 insertions(+), 56 deletions(-) diff --git a/test/camapigns-api.spec.js b/test/camapigns-api.spec.js index 34c7d90..03765f2 100644 --- a/test/camapigns-api.spec.js +++ b/test/camapigns-api.spec.js @@ -1,7 +1,7 @@ /* eslint-env jasmine */ const nock = require('nock') const VoucherifyClient = require('../src/index') -const {reqheaders} = require('./fixtures') +const {reqWithoutBody, reqWithBody} = require('./fixtures') nock.disableNetConnect() describe('Campaigns API', function () { @@ -11,7 +11,7 @@ describe('Campaigns API', function () { }) it('should create campaign', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/campaigns', { name: 'test campaign' }) @@ -27,7 +27,7 @@ describe('Campaigns API', function () { }) it('should get camaign', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/campaigns/test%20campaign') .reply(200, {}) @@ -39,7 +39,7 @@ describe('Campaigns API', function () { }) it('should add voucher', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/campaigns/test%20campaign/vouchers', { code: 'test voucher' }) @@ -55,7 +55,7 @@ describe('Campaigns API', function () { }) it('should add voucher', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/campaigns/test%20campaign/import', [{ code: 'test voucher' }]) diff --git a/test/customers-api.spec.js b/test/customers-api.spec.js index 0e5998d..317cad3 100644 --- a/test/customers-api.spec.js +++ b/test/customers-api.spec.js @@ -1,7 +1,7 @@ /* eslint-env jasmine */ const nock = require('nock') const VoucherifyClient = require('../src/index') -const {reqheaders} = require('./fixtures') +const {reqWithoutBody, reqWithBody} = require('./fixtures') nock.disableNetConnect() describe('Customers API', function () { @@ -11,7 +11,7 @@ describe('Customers API', function () { }) it('should create customer', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/customers', { name: 'customer name' }) @@ -27,7 +27,7 @@ describe('Customers API', function () { }) it('should get customer', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/customers/cust_test-id') .reply(200, {}) @@ -39,7 +39,7 @@ describe('Customers API', function () { }) it('should update customer', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .put('/v1/customers/cust_test-id', { name: 'customer name' }) @@ -56,7 +56,7 @@ describe('Customers API', function () { }) it('should delete customer', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .delete('/v1/customers/cust_test-id') .reply(200, {}) diff --git a/test/fixtures.js b/test/fixtures.js index 9944bc4..fd14f14 100644 --- a/test/fixtures.js +++ b/test/fixtures.js @@ -1,7 +1,19 @@ module.exports = { - reqheaders: { - 'X-App-Id': 'node-sdk-test-id', - 'X-App-Token': 'node-sdk-test-secret', - 'X-Voucherify-Channel': 'Node.js-SDK' + reqWithBody: { + reqheaders: { + 'X-App-Id': 'node-sdk-test-id', + 'X-App-Token': 'node-sdk-test-secret', + 'X-Voucherify-Channel': 'Node.js-SDK', + 'accept': 'application/json', + 'content-type': 'application/json' + } + }, + reqWithoutBody: { + reqheaders: { + 'X-App-Id': 'node-sdk-test-id', + 'X-App-Token': 'node-sdk-test-secret', + 'X-Voucherify-Channel': 'Node.js-SDK', + 'accept': 'application/json' + } } } diff --git a/test/products-api.spec.js b/test/products-api.spec.js index 6a532f0..3035227 100644 --- a/test/products-api.spec.js +++ b/test/products-api.spec.js @@ -1,7 +1,7 @@ /* eslint-env jasmine */ const nock = require('nock') const VoucherifyClient = require('../src/index') -const {reqheaders} = require('./fixtures') +const {reqWithoutBody, reqWithBody} = require('./fixtures') nock.disableNetConnect() describe('Products API', function () { @@ -11,7 +11,7 @@ describe('Products API', function () { }) it('should create product', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/products', { name: 'product name' }) @@ -27,7 +27,7 @@ describe('Products API', function () { }) it('should get product', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/products/prod_test-id') .reply(200, {}) @@ -39,7 +39,7 @@ describe('Products API', function () { }) it('should update product', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .put('/v1/products/prod_test-id', { name: 'product name' }) @@ -56,7 +56,7 @@ describe('Products API', function () { }) it('should delete product', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .delete('/v1/products/prod_test-id') .reply(200, {}) @@ -68,7 +68,7 @@ describe('Products API', function () { }) it('should list products', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/products') .reply(200, {}) @@ -81,7 +81,7 @@ describe('Products API', function () { describe('SKU', function () { it('should create SKU', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/products/prod_test-id/skus', { sku: 'test sku' }) @@ -97,7 +97,7 @@ describe('Products API', function () { }) it('should get SKU', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/products/prod_test-id/skus/test-sku') .reply(200, {}) @@ -109,7 +109,7 @@ describe('Products API', function () { }) it('should update SKU', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .put('/v1/products/prod_test-id/skus/test-sku', { metadata: { isTestSku: true @@ -130,7 +130,7 @@ describe('Products API', function () { }) it('should delete SKU', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .delete('/v1/products/prod_test-id/skus/test-sku') .reply(200, {}) @@ -142,7 +142,7 @@ describe('Products API', function () { }) it('should list SKUs', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/products/prod_test-id/skus') .reply(200, {}) diff --git a/test/redemptions-api.spec.js b/test/redemptions-api.spec.js index 1be87b0..83a9240 100644 --- a/test/redemptions-api.spec.js +++ b/test/redemptions-api.spec.js @@ -1,7 +1,7 @@ /* eslint-env jasmine */ const nock = require('nock') const VoucherifyClient = require('../src/index') -const {reqheaders} = require('./fixtures') +const {reqWithoutBody, reqWithBody} = require('./fixtures') nock.disableNetConnect() describe('Redemptions API', function () { @@ -12,7 +12,7 @@ describe('Redemptions API', function () { describe('redeem', function () { it('should redeem by code', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test-code/redemption') .reply(200, {}) @@ -24,7 +24,7 @@ describe('Redemptions API', function () { }) it('should redeem by code (callback)', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test-code/redemption') .reply(200, {}) @@ -36,7 +36,7 @@ describe('Redemptions API', function () { }) it('should redeem by voucher', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test-code/redemption', { customer: { id: 'test-customer-id' @@ -57,7 +57,7 @@ describe('Redemptions API', function () { }) it('should redeem with tracking ID', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test-code/redemption') .query({tracking_id: 'test-tracking-id'}) .reply(200, {}) @@ -72,7 +72,7 @@ describe('Redemptions API', function () { describe('list', function () { it('should list by query', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/redemptions') .query({limit: 100}) .reply(200, {}) @@ -87,7 +87,7 @@ describe('Redemptions API', function () { }) it('should list all', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/redemptions') .reply(200, {}) @@ -99,7 +99,7 @@ describe('Redemptions API', function () { }) it('should list all (callback)', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/redemptions') .reply(200, {}) @@ -112,7 +112,7 @@ describe('Redemptions API', function () { }) it('should get voucher redemptions', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/vouchers/test-code/redemption') .reply(200, {}) @@ -125,7 +125,7 @@ describe('Redemptions API', function () { describe('rollback', function () { it('should rollback without customer details', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/redemptions/test-redemption-id/rollback') .reply(200, {}) @@ -137,7 +137,7 @@ describe('Redemptions API', function () { }) it('should rollback without customer details (callback)', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/redemptions/test-redemption-id/rollback') .reply(200, {}) @@ -149,7 +149,7 @@ describe('Redemptions API', function () { }) it('should rollback with customer details', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/redemptions/test-redemption-id/rollback', { customer: { id: 'test-customer-id' @@ -169,7 +169,7 @@ describe('Redemptions API', function () { }) it('should rollback with customer details, reason and tracking_id', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/redemptions/test-redemption-id/rollback', { customer: { id: 'test-customer-id' @@ -195,7 +195,7 @@ describe('Redemptions API', function () { }) it('should rollback with a reason', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/redemptions/test-redemption-id/rollback') .query({ reason: 'test%20reason' diff --git a/test/validations-api.spec.js b/test/validations-api.spec.js index 654fff7..6d546d0 100644 --- a/test/validations-api.spec.js +++ b/test/validations-api.spec.js @@ -1,7 +1,7 @@ /* eslint-env jasmine */ const nock = require('nock') const VoucherifyClient = require('../src/index') -const {reqheaders} = require('./fixtures') +const {reqWithoutBody, reqWithBody} = require('./fixtures') nock.disableNetConnect() describe('Validations API', function () { @@ -12,7 +12,7 @@ describe('Validations API', function () { describe('validate voucher', function () { it('should validate without additional context', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test%20code/validate') .reply(200, {}) @@ -24,7 +24,7 @@ describe('Validations API', function () { }) it('should validate without additional context (callback)', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test%20code/validate') .reply(200, {}) @@ -36,7 +36,7 @@ describe('Validations API', function () { }) it('should validate with additional context', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test%20code/validate', { tracking_id: 'tracking-id' }) diff --git a/test/vouchers-api.spec.js b/test/vouchers-api.spec.js index f6ff1f0..4571a24 100644 --- a/test/vouchers-api.spec.js +++ b/test/vouchers-api.spec.js @@ -1,7 +1,7 @@ /* eslint-env jasmine */ const nock = require('nock') const VoucherifyClient = require('../src/index') -const {reqheaders} = require('./fixtures') +const {reqWithoutBody, reqWithBody} = require('./fixtures') nock.disableNetConnect() describe('Vouchers API', function () { @@ -11,7 +11,7 @@ describe('Vouchers API', function () { }) it('should create voucher', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test-code', { code: 'test-code', type: 'DISCOUNT_VOUCHER' @@ -29,7 +29,7 @@ describe('Vouchers API', function () { }) it('should get voucher', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/vouchers/test-code') .reply(200, {}) @@ -41,7 +41,7 @@ describe('Vouchers API', function () { }) it('should update voucher', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .put('/v1/vouchers/test-code', { code: 'test-code', type: 'DISCOUNT_VOUCHER' @@ -60,7 +60,7 @@ describe('Vouchers API', function () { describe('delete voucher', function () { it('should delete, but not permanently', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .delete('/v1/vouchers/test-code') .query({force: false}) .reply(200, {}) @@ -73,7 +73,7 @@ describe('Vouchers API', function () { }) it('should delete, but not permanently (callback)', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .delete('/v1/vouchers/test-code') .query({force: false}) .reply(200, {}) @@ -86,7 +86,7 @@ describe('Vouchers API', function () { }) it('should delete permanently', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .delete('/v1/vouchers/test-code') .query({force: true}) .reply(200, {}) @@ -100,7 +100,7 @@ describe('Vouchers API', function () { }) it('should list vouchers by query', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/vouchers') .query({campaign: 'test-campaign'}) .reply(200, {}) @@ -114,7 +114,7 @@ describe('Vouchers API', function () { describe('publish voucher', function () { it('should publish by camaign name', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/publish') .query({campaign: 'test-campaign'}) .reply(200, {}) @@ -127,7 +127,7 @@ describe('Vouchers API', function () { }) it('should publish by voucher', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/publish', { campaign: 'test-campaign', voucher: 'test-voucher' @@ -146,7 +146,7 @@ describe('Vouchers API', function () { }) it('should enable voucher', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test-voucher/enable') .reply(200, {}) @@ -158,7 +158,7 @@ describe('Vouchers API', function () { }) it('should disable voucher', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test-voucher/disable') .reply(200, {}) @@ -170,7 +170,7 @@ describe('Vouchers API', function () { }) it('should import vouchers', function (done) { - const server = nock('https://api.voucherify.io', {reqheaders}) + const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/import', [ {code: 'test-voucher1'}, {code: 'test-voucher2'} From d5edc37741ead1befae3a923ea1d3296cd7146a2 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 22:00:03 +0100 Subject: [PATCH 076/112] update dependencies --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c608438..8bbd8aa 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,8 @@ "saas" ], "dependencies": { - "request": "~2.54.0", - "when": "~3.7.3" + "request": "~2.79.0", + "when": "~3.7.7" }, "devDependencies": { "babel-plugin-add-header-comment": "^1.0.3", From e86b1f9d1f3d8486e6577eeb9c36381bbf30fc58 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sat, 26 Nov 2016 22:02:32 +0100 Subject: [PATCH 077/112] fix lint error --- test/validations-api.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/validations-api.spec.js b/test/validations-api.spec.js index 6d546d0..c839d35 100644 --- a/test/validations-api.spec.js +++ b/test/validations-api.spec.js @@ -1,7 +1,7 @@ /* eslint-env jasmine */ const nock = require('nock') const VoucherifyClient = require('../src/index') -const {reqWithoutBody, reqWithBody} = require('./fixtures') +const {reqWithBody} = require('./fixtures') nock.disableNetConnect() describe('Validations API', function () { From c1d8af7312860f7888a224909c6503dab010f158 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sun, 27 Nov 2016 19:01:30 +0100 Subject: [PATCH 078/112] rename file --- test/{voucherify.spec.js => voucherify-client.spec.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{voucherify.spec.js => voucherify-client.spec.js} (100%) diff --git a/test/voucherify.spec.js b/test/voucherify-client.spec.js similarity index 100% rename from test/voucherify.spec.js rename to test/voucherify-client.spec.js From 6cca501cdcd492a4918aa4e59d0a1c0c81600ac1 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sun, 27 Nov 2016 19:33:29 +0100 Subject: [PATCH 079/112] group initialisation tests --- test/voucherify-client.spec.js | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/test/voucherify-client.spec.js b/test/voucherify-client.spec.js index 3a99006..4f95a29 100644 --- a/test/voucherify-client.spec.js +++ b/test/voucherify-client.spec.js @@ -1,20 +1,22 @@ /* eslint-env jasmine */ const voucherifyClient = require('../src/index.js') -describe('voucherify', function () { - it('should detect missing applicationId', function () { - expect(function () { - voucherifyClient({ - clientSecretKey: 'CLIENT-SECRET-KEY' - }) - }).toThrow(new Error("Missing required option 'applicationId'")) - }) +describe('VocherifyClient', function () { + describe('Initialization', function () { + it('should detect missing applicationId', function () { + expect(function () { + voucherifyClient({ + clientSecretKey: 'CLIENT-SECRET-KEY' + }) + }).toThrow(new Error("Missing required option 'applicationId'")) + }) - it('should detect missing clientSecretKey', function () { - expect(function () { - voucherifyClient({ - applicationId: 'APPLICATION-ID' - }) - }).toThrow(new Error("Missing required option 'clientSecretKey'")) + it('should detect missing clientSecretKey', function () { + expect(function () { + voucherifyClient({ + applicationId: 'APPLICATION-ID' + }) + }).toThrow(new Error("Missing required option 'clientSecretKey'")) + }) }) }) From 96a6d3134531c9dd044a5c06cd989c96a8230b4a Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Sun, 27 Nov 2016 20:11:14 +0100 Subject: [PATCH 080/112] test handling errors --- test/voucherify-client.spec.js | 47 ++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/test/voucherify-client.spec.js b/test/voucherify-client.spec.js index 4f95a29..a35849d 100644 --- a/test/voucherify-client.spec.js +++ b/test/voucherify-client.spec.js @@ -1,4 +1,5 @@ /* eslint-env jasmine */ +const nock = require('nock') const voucherifyClient = require('../src/index.js') describe('VocherifyClient', function () { @@ -19,4 +20,50 @@ describe('VocherifyClient', function () { }).toThrow(new Error("Missing required option 'clientSecretKey'")) }) }) + + describe('Error handling', function () { + const client = voucherifyClient({ + applicationId: 'node-sdk-test-id', + clientSecretKey: 'node-sdk-test-secret' + }) + + it('should return error details', function (done) { + const server = nock('https://api.voucherify.io') + .post('/v1/customers', {name: 'customer name'}) + .reply(400, { + code: 400, + message: 'Duplicate resource key', + details: 'Campaign with name: test campaign already exists.', + key: 'duplicate_resource_key' + }) + + client.customers.create({ + name: 'customer name' + }) + .catch((error) => { + expect(error.code).toEqual(400) + expect(error.message).toEqual('Duplicate resource key') + expect(error.details).toEqual('Campaign with name: test campaign already exists.') + expect(error.key).toEqual('duplicate_resource_key') + server.done() + done() + }) + }) + + it('should return error details (callback)', function (done) { + const server = nock('https://api.voucherify.io') + .post('/v1/customers', {name: 'customer name'}) + .reply(401, { + code: 401, + message: 'No such app.' + }) + + client.customers.create({name: 'customer name'}, (error) => { + expect(error.code).toEqual(401) + expect(error.message).toEqual('No such app.') + server.done() + done() + }) + }) + }) }) From 7e88364c29ef703e2c22dbdc459ffd7406c5540c Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Wed, 30 Nov 2016 16:28:36 +0100 Subject: [PATCH 081/112] add optional query to products list --- src/Products.js | 10 +++++++--- test/products-api.spec.js | 39 +++++++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/Products.js b/src/Products.js index 5ea51cf..ab1a88e 100644 --- a/src/Products.js +++ b/src/Products.js @@ -1,6 +1,6 @@ 'use strict' -const {encode} = require('./helpers') +const {encode, isFunction} = require('./helpers') module.exports = class Products { constructor (client) { @@ -23,8 +23,12 @@ module.exports = class Products { return this.client.delete(`/products/${encode(productId)}`, callback) } - list (callback) { - return this.client.get('/products', null, callback) + list (query, callback) { + if (isFunction(query)) { + callback = query + query = {} + } + return this.client.get('/products', query, callback) } createSku (productId, sku, callback) { diff --git a/test/products-api.spec.js b/test/products-api.spec.js index 3035227..d903c30 100644 --- a/test/products-api.spec.js +++ b/test/products-api.spec.js @@ -67,15 +67,42 @@ describe('Products API', function () { }) }) - it('should list products', function (done) { - const server = nock('https://api.voucherify.io', reqWithoutBody) + describe('list products', function () { + it('should list all', function (done) { + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/products') .reply(200, {}) - client.products.list() - .then(() => { - server.done() - done() + client.products.list() + .then(() => { + server.done() + done() + }) + }) + + it('should list all (callback)', function (done) { + const server = nock('https://api.voucherify.io', reqWithoutBody) + .get('/v1/products') + .reply(200, []) + + client.products.list((err) => { + expect(err).toBeNull() + server.done() + done() + }) + }) + + it('should list by query', function (done) { + const server = nock('https://api.voucherify.io', reqWithoutBody) + .get('/v1/products') + .query({limit: 100}) + .reply(200, {}) + + client.products.list({limit: 100}) + .then(() => { + server.done() + done() + }) }) }) From 94cd315ed2eae9e80344ce5d5cd8198852f6dbf0 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Wed, 30 Nov 2016 16:39:58 +0100 Subject: [PATCH 082/112] rename --- src/Vouchers.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Vouchers.js b/src/Vouchers.js index c06cac5..a2d8dbe 100644 --- a/src/Vouchers.js +++ b/src/Vouchers.js @@ -34,15 +34,13 @@ module.exports = class Vouchers { return this.client.get('/vouchers', query, callback) } - publish (campaignName, callback) { - if (isString(campaignName)) { - return this.client.post('/vouchers/publish', null, callback, { - qs: {campaign: encode(campaignName)} - }) + publish (params, callback) { + if (isString(params)) { + return this.client.post('/vouchers/publish', {campaign: encode(params)}, callback) } - if (isObject(campaignName)) { - return this.client.post('/vouchers/publish', campaignName, callback) + if (isObject(params)) { + return this.client.post('/vouchers/publish', params, callback) } } From a8be695b5f5d38add9bb0e652708ce5559271823 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Wed, 30 Nov 2016 17:21:08 +0100 Subject: [PATCH 083/112] force first redeem argument is a string, always preserve bacward compatibility --- src/Redemptions.js | 30 ++++++++++++++++++++---------- test/redemptions-api.spec.js | 22 +++++++++++++++++++++- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/Redemptions.js b/src/Redemptions.js index a2ebefa..5b6833d 100644 --- a/src/Redemptions.js +++ b/src/Redemptions.js @@ -7,25 +7,35 @@ module.exports = class Redemptions { this.client = client } - redeem (code, trackingId, callback) { + redeem (code, params, callback) { let context = {} + let qs = {} + let isDeprecated = false if (isObject(code)) { + isDeprecated = true + console.warn('This redeem method invocation is deprecated. First argument should be always a code, check docs for more details.') + if (isObject(params)) { + console.warn('This redeem method invocation is deprecated. Params being an object will be ingored.') + } + context = code code = context.voucher delete context.voucher - } - if (isFunction(trackingId)) { - callback = trackingId - trackingId = null + } else { + context = params || {} } - let url = `/vouchers/${encode(code)}/redemption` - - if (isString(trackingId) && trackingId) { - url += `?tracking_id=${encode(trackingId)}` + if (isFunction(params)) { + callback = params + context = isDeprecated ? context : null + } else if (isString(params) && params.length > 0) { + // FIXME put to body: {customer: tracking_id}, test it with working API + qs = { + tracking_id: encode(params) + } } - return this.client.post(url, context, callback) + return this.client.post(`/vouchers/${encode(code)}/redemption`, context, callback, {qs}) } /* diff --git a/test/redemptions-api.spec.js b/test/redemptions-api.spec.js index 83a9240..b2766d5 100644 --- a/test/redemptions-api.spec.js +++ b/test/redemptions-api.spec.js @@ -35,7 +35,7 @@ describe('Redemptions API', function () { }) }) - it('should redeem by voucher', function (done) { + it('should redeem by voucher (DEPRECATED!)', function (done) { const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test-code/redemption', { customer: { @@ -56,6 +56,26 @@ describe('Redemptions API', function () { }) }) + it('should redeem by voucher', function (done) { + const server = nock('https://api.voucherify.io', reqWithBody) + .post('/v1/vouchers/test-code/redemption', { + customer: { + id: 'test-customer-id' + } + }) + .reply(200, {}) + + client.redemptions.redeem('test-code', { + customer: { + id: 'test-customer-id' + } + }) + .then(() => { + server.done() + done() + }) + }) + it('should redeem with tracking ID', function (done) { const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test-code/redemption') From 115fa23425343b261513b1977be6e7ba24244329 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Wed, 30 Nov 2016 17:27:24 +0100 Subject: [PATCH 084/112] cleaning --- src/Redemptions.js | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/Redemptions.js b/src/Redemptions.js index 5b6833d..034a1e9 100644 --- a/src/Redemptions.js +++ b/src/Redemptions.js @@ -30,24 +30,12 @@ module.exports = class Redemptions { context = isDeprecated ? context : null } else if (isString(params) && params.length > 0) { // FIXME put to body: {customer: tracking_id}, test it with working API - qs = { - tracking_id: encode(params) - } + qs.tracking_id = encode(params) } return this.client.post(`/vouchers/${encode(code)}/redemption`, context, callback, {qs}) } - /* - * List redemptions. Sample query (1000 successful redemptions from April 2016): - * { - * limit: 1000, - * page: 0, - * start_date: '2016-04-01T00:00:00', - * end_date: '2016-04-30T23:59:59', - * result: 'Success' - * } - */ list (query, callback) { if (isFunction(query)) { callback = query @@ -70,12 +58,9 @@ module.exports = class Redemptions { let qs = {} let payload = {} - // If `reason` passed, use it in query string. if (isString(data)) { qs.reason = encode(data) - } - - if (isObject(data)) { + } else if (isObject(data)) { const {reason, tracking_id, customer} = data qs = { From 5792dd27d139b2a257ffdcb68ec8fc6e0f443973 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Wed, 30 Nov 2016 17:30:47 +0100 Subject: [PATCH 085/112] optional vouchers list query --- src/Vouchers.js | 9 +++++++-- test/vouchers-api.spec.js | 40 ++++++++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/Vouchers.js b/src/Vouchers.js index a2d8dbe..071fa96 100644 --- a/src/Vouchers.js +++ b/src/Vouchers.js @@ -30,8 +30,13 @@ module.exports = class Vouchers { }) } - list (query, callback) { - return this.client.get('/vouchers', query, callback) + list (params, callback) { + if (isFunction(params)) { + callback = params + params = {} + } + + return this.client.get('/vouchers', params, callback) } publish (params, callback) { diff --git a/test/vouchers-api.spec.js b/test/vouchers-api.spec.js index 4571a24..bfb4aee 100644 --- a/test/vouchers-api.spec.js +++ b/test/vouchers-api.spec.js @@ -99,16 +99,42 @@ describe('Vouchers API', function () { }) }) - it('should list vouchers by query', function (done) { - const server = nock('https://api.voucherify.io', reqWithoutBody) + describe('list', function () { + it('should list all vouchers', function (done) { + const server = nock('https://api.voucherify.io', reqWithoutBody) + .get('/v1/vouchers') + .reply(200, []) + + client.vouchers.list() + .then(() => { + server.done() + done() + }) + }) + + it('should list all vouchers (callback)', function (done) { + const server = nock('https://api.voucherify.io', reqWithoutBody) + .get('/v1/vouchers') + .reply(200, []) + + client.vouchers.list((err) => { + expect(err).toBeNull() + server.done() + done() + }) + }) + + it('should list vouchers by query', function (done) { + const server = nock('https://api.voucherify.io', reqWithoutBody) .get('/v1/vouchers') .query({campaign: 'test-campaign'}) - .reply(200, {}) + .reply(200, []) - client.vouchers.list({campaign: 'test-campaign'}) - .then(() => { - server.done() - done() + client.vouchers.list({campaign: 'test-campaign'}) + .then(() => { + server.done() + done() + }) }) }) From 1dec3c86e06f794221fc0121b6d89f9141654620 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Wed, 30 Nov 2016 17:52:37 +0100 Subject: [PATCH 086/112] rename --- src/Validations.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Validations.js b/src/Validations.js index aa3df37..805eb6d 100644 --- a/src/Validations.js +++ b/src/Validations.js @@ -7,12 +7,12 @@ module.exports = class Validations { this.client = client } - validateVoucher (code, context = {}, callback = null) { - if (isFunction(context)) { - callback = context - context = {} + validateVoucher (code, params = {}, callback = null) { + if (isFunction(params)) { + callback = params + params = {} } - return this.client.post(`/vouchers/${encode(code)}/validate`, context, callback) + return this.client.post(`/vouchers/${encode(code)}/validate`, params, callback) } } From 5c75e97e7e0af7f65d74610d666335322fad105f Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Wed, 30 Nov 2016 17:53:05 +0100 Subject: [PATCH 087/112] make optional params for add voucher method --- src/Campaigns.js | 12 +++++++---- test/camapigns-api.spec.js | 42 +++++++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/Campaigns.js b/src/Campaigns.js index efe7cbd..c979ad6 100644 --- a/src/Campaigns.js +++ b/src/Campaigns.js @@ -1,6 +1,6 @@ 'use strict' -const {encode} = require('./helpers') +const {encode, isFunction} = require('./helpers') module.exports = class Campaigns { constructor (client) { @@ -15,11 +15,15 @@ module.exports = class Campaigns { return this.client.get(`/campaigns/${encode(name)}`, null, callback) } - addVoucher (campaignName, voucher, callback) { + addVoucher (campaignName, params, callback) { + if (isFunction(params)) { + callback = params + params = {} + } + return this.client.post( `/campaigns/${encode(campaignName)}/vouchers`, - // TODO if voucher is optional, secure against callback version - voucher || {}, + params || {}, callback ) } diff --git a/test/camapigns-api.spec.js b/test/camapigns-api.spec.js index 03765f2..45d363f 100644 --- a/test/camapigns-api.spec.js +++ b/test/camapigns-api.spec.js @@ -38,23 +38,45 @@ describe('Campaigns API', function () { }) }) - it('should add voucher', function (done) { - const server = nock('https://api.voucherify.io', reqWithBody) - .post('/v1/campaigns/test%20campaign/vouchers', { - code: 'test voucher' + describe('add voucher', function () { + it('should add voucher with concrete code', function (done) { + const server = nock('https://api.voucherify.io', reqWithBody) + .post('/v1/campaigns/test%20campaign/vouchers', {code: 'test voucher'}) + .reply(200, {}) + + client.campaigns.addVoucher('test campaign', {code: 'test voucher'}) + .then(() => { + server.done() + done() }) + }) + + it('should add voucher without params', function (done) { + const server = nock('https://api.voucherify.io', reqWithBody) + .post('/v1/campaigns/test%20campaign/vouchers', {}) .reply(200, {}) - client.campaigns.addVoucher('test campaign', { - code: 'test voucher' + client.campaigns.addVoucher('test campaign') + .then(() => { + server.done() + done() + }) }) - .then(() => { - server.done() - done() + + it('should add voucher without params (callback)', function (done) { + const server = nock('https://api.voucherify.io', reqWithBody) + .post('/v1/campaigns/test%20campaign/vouchers', {}) + .reply(200, {}) + + client.campaigns.addVoucher('test campaign', (err) => { + expect(err).toBeNull() + server.done() + done() + }) }) }) - it('should add voucher', function (done) { + it('should import vouchers', function (done) { const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/campaigns/test%20campaign/import', [{ code: 'test voucher' From c5cdcf6f1a88ab8b29b9f028f5ab4dfaf34a6784 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Wed, 30 Nov 2016 17:56:56 +0100 Subject: [PATCH 088/112] renames --- src/Products.js | 10 +++++----- src/Redemptions.js | 26 +++++++++++++------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Products.js b/src/Products.js index ab1a88e..b2ce06f 100644 --- a/src/Products.js +++ b/src/Products.js @@ -23,12 +23,12 @@ module.exports = class Products { return this.client.delete(`/products/${encode(productId)}`, callback) } - list (query, callback) { - if (isFunction(query)) { - callback = query - query = {} + list (params, callback) { + if (isFunction(params)) { + callback = params + params = {} } - return this.client.get('/products', query, callback) + return this.client.get('/products', params, callback) } createSku (productId, sku, callback) { diff --git a/src/Redemptions.js b/src/Redemptions.js index 034a1e9..92b5ae9 100644 --- a/src/Redemptions.js +++ b/src/Redemptions.js @@ -36,32 +36,32 @@ module.exports = class Redemptions { return this.client.post(`/vouchers/${encode(code)}/redemption`, context, callback, {qs}) } - list (query, callback) { - if (isFunction(query)) { - callback = query - query = null + list (params, callback) { + if (isFunction(params)) { + callback = params + params = {} } - return this.client.get('/redemptions', query, callback) + return this.client.get('/redemptions', params, callback) } getForVoucher (code, callback) { return this.client.get(`/vouchers/${encode(code)}/redemption`, null, callback) } - rollback (redemptionId, data, callback) { - if (isFunction(data)) { - callback = data - data = null + rollback (redemptionId, params, callback) { + if (isFunction(params)) { + callback = params + params = null } let qs = {} let payload = {} - if (isString(data)) { - qs.reason = encode(data) - } else if (isObject(data)) { - const {reason, tracking_id, customer} = data + if (isString(params)) { + qs.reason = encode(params) + } else if (isObject(params)) { + const {reason, tracking_id, customer} = params qs = { reason: reason ? encode(reason) : undefined, From 3521256c87acf1021075ee76d2b14b424132e974 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 09:43:04 +0100 Subject: [PATCH 089/112] init work on README refactor --- README.md | 1452 ++++------------------------------------------------- 1 file changed, 103 insertions(+), 1349 deletions(-) diff --git a/README.md b/README.md index 058222b..f5e34e2 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,59 @@ -## Voucherify Node.js SDK - -[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) -[![Build Status](https://travis-ci.org/rspective/voucherify-nodejs-sdk.svg?branch=refactor-and-new-methods)](https://travis-ci.org/rspective/voucherify-nodejs-sdk) -[![NPM Version](https://img.shields.io/npm/v/voucherify.svg)](https://www.npmjs.com/package/voucherify) -[![NPM Downloads](https://img.shields.io/npm/dm/voucherify.svg)](https://www.npmjs.com/package/voucherify) -[![Dependencies](https://david-dm.org/rspective/voucherify-nodejs-sdk.svg)](https://www.npmjs.com/package/voucherify) - -[Voucherify](http://voucherify.io?utm_source=github&utm_medium=sdk&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: - -* an API-first SaaS platform that enables customisation of every aspect of coupon campaigns -* a management console that helps cut down maintenance and reporting overhead -* an infrastructure to scale up coupon activity in no time - -Here you can find a library that makes it easier to integrate Voucherify with your Node.js server. - -Full documentation is located at [voucherify.readme.io](https://voucherify.readme.io). - - -### Usage - -#### Authentication +

+ +

+ +

Official Voucherify Node.js SDK

+ +

+ JavaScript Style Guide + Build Status + NPM Version + NPM Downloads + Dependencies +

+
+ + +

+Setup +| +Callback or Promise? +| +API +| +Error handling +| +Contributing +| +Changelog +| +License +

+
+ +## Setup + +`npm install voucherify --save` [Log-in](http://app.voucherify.io/#/login) to Voucherify web interface and obtain your Application Keys from [Configuration](https://app.voucherify.io/#/app/configuration): -![](https://www.filepicker.io/api/file/WKYkl2bSAWKHccEN9tEG) - ```javascript -const voucherifyClient = require("voucherify") +const voucherifyClient = require('voucherify') -const voucherify = voucherifyClient({ - applicationId: "YOUR-APPLICATION-ID-OBTAINED-FROM-CONFIGURATION", - clientSecretKey: "YOUR-CLIENT-SECRET-KEY-OBTAINED-FROM-CONFIGURATION" +const client = voucherifyClient({ + applicationId: 'YOUR-APPLICATION-ID', + clientSecretKey: 'YOUR-CLIENT-SECRET-KEY' }) ``` - -#### Callback or Promise? +## Callback or Promise? All methods in the SDK provide both callback based as well as promise based interactions. -If you want to use callbacks just pass them as a last parameter. For example: +If you want to use callback just pass it as a last parameter. For example: ```javascript -voucherify.get("v1GiJYuuS", function(error, result) { +client.vouchers.get('v1GiJYuuS', (error, result) => { if (error) { // handle error return @@ -54,1360 +66,102 @@ voucherify.get("v1GiJYuuS", function(error, result) { If you prefer to use promises then the code goes like this: ```javascript -voucherify.get("v1GiJYuuS") - .then(function (result) { +client.vouchers.get('v1GiJYuuS') + .then((result) => { console.log(result) }) - .catch(function (error) { + .catch((error) => { console.error("Error: %s", error) }) ``` All other examples in the readme use promises but they could be as well written with callbacks. +## API -#### Listing vouchers - -`voucherify.list(filter, callback*)` - -Filter parameters: - -- code_query -- limit (default 10) -- skip (default 0) -- category -- campaign -- customer - -Example: - -```javascript -voucherify.list({limit: 10, skip: 20, category: "API Test"}) - .then(function(vouchers) { - console.log(vouchers) - }) - .catch(function(error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -[{ - "code": "9mYBpIk", - "campaign": null, - "category": "API Test", - "discount": { - "type": "AMOUNT", - "amount_off": 400 - }, - "start_date": "2016-03-01T12:00:00Z", - "expiration_date": null, - "publish": { - "object": "list", - "count": 0, - "data_ref": "entries", - "entries": [] - }, - "redemption": { - "object": "list", - "quantity": 1, - "data_ref": "redemption_entries", - "redeemed_quantity": 0, - "redemption_entries": [] - }, - "active": true, - "additional_info": null, - "metadata": null -}, { - "code": "AzTsIH", - "campaign": null, - "category": "API Test", - "discount": { - "type": "AMOUNT", - "amount_off": 400 - }, - "start_date": "2016-03-01T10:00:00Z", - "expiration_date": null, - "publish": { - "object": "list", - "count": 0, - "data_ref": "entries", - "entries": [] - }, - "redemption": { - "object": "list", - "quantity": 1, - "data_ref": "redemption_entries", - "redeemed_quantity": 0, - "redeemed_amount": 0, - "redemption_entries": [] - }, - "active": true, - "additional_info": null, - "metadata": null -}] -``` - - -#### Getting voucher details - -`voucherify.get(voucher_code, callback*)` - -Example: - -```javascript -voucherify.get("v1GiJYuuS") - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "code": "v1GiJYuuS", - "campaign": "vip", - "discount": { - "percent_off": 10.0, - "type": "PERCENT" - }, - "expiration_date": "2016-12-31T23:59:59Z", - "publish": { - "object": "list", - "count": 0, - "data_ref": "entries", - "entries": [] - }, - "redemption": { - "object": "list", - "quantity": 1, - "data_ref": "redemption_entries", - "redeemed_quantity": 0, - "redemption_entries": [{ - "id": "r_gQzOnTwmhn2nTLwW4sZslNKY", - "object": "redemption", - "date": "2016-04-24T06:03:35Z", - "customer_id": null, - "tracking_id": "GENERATED-OR-PROVIDED-TRACKING-ID" - }] - }, - "additional_info": "" -} -``` - - -#### Creating a voucher - -`voucherify.create(voucher, callback*)` - -You can create a voucher with a specified code or let Voucherify generate one. -You can define how to generate the code in `code_config` including following properties: -- `length` - Number of characters in a generated code (excluding prefix and postfix) -- `charset` - Characters that can appear in the code. -- `prefix` - A text appended before the code. -- `postfix` - A text appended after the code. -- `pattern` - A pattern for codes where hashes (#) will be replaced with random characters. Overrides `length`. - -Example: - -```javascript - voucherify.create({ - code_config: { - length: 5, - charset: "01234567890", - prefix: "PROMO-", - postfix: "-2016" - }, - discount: { - type: "AMOUNT", - amount_off: 1000 // 10.00 - }, - category: "Test", - start_date: "2016-01-01T00:00:00Z", - expiration_date: "2016-12-31T23:59:59Z" - }) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -#### Updating a voucher - -`voucherify.update(voucher, callback*)` - -You can modify following fields: -- category -- start_date -- expiration_date -- active -- additional_info -- metadata - -Other fields than listed above won't be modified. Even if provided they will be silently skipped. - -Example: - -```javascript - voucherify.update({ - code: "v1GiJYuuS", - category: "Updated", - start_date: "2016-08-01T00:00:00Z", - expiration_date: "2017-07-31T23:59:59Z" - }) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -#### Add voucher to existing Campaign - -This method is responsible for adding new voucher to campaign based on voucher definition inherited from campaign. You can give custom values for following fields: -- category -- additional_info -- metadata -- redemption.quantity - - -Example: - -```javascript -const payload = { - "additional_info": "New voucher", - "metadata": { - "test": true - }, - "redemption": { - "quantity": 5 - } -} - -voucherify.campaign.voucher.create("Campaign-Name", payload) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "code": "pK0ZSfaB", - "campaign": "Campaign-Name", - "category": null, - "type": "DISCOUNT_VOUCHER", - "discount": { "type": "AMOUNT", "amount_off": 1000 }, - "gift": null, - "start_date": "2016-09-14T22:00:00Z", - "expiration_date": "2016-09-30T21:59:59Z", - "publish": { - "object": "list", - "count": 0, - "data_ref": "entries", - "entries": [] - }, - "redemption": { - "object": "list", - "quantity": 0, - "data_ref": "redemption_entries", - "redeemed_quantity": 0, - "redemption_entries": [] - }, - "active": true, - "additional_info": "New voucher", - "metadata": { - "test": true - } -} -``` - -#### Deleting a voucher - -`voucherify.delete(voucher_code, params*, callback*)` - -In param object you can pass `force` flag which tells whether voucher will be removed permanently. It means that afterwards user will be able to create next voucher with the same code. - -Example: - -```javascript - voucherify.delete("v1GiJYuuS", { force: true }) - .then(function (result) { - console.log("Voucher deleted.") - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -`Result is an empty body` - -#### Disabling a voucher - -`voucherify.disable(voucher_code, callback*)` - -Example: - -```javascript - voucherify.disable("v1GiJYuuS") - .then(function (result) { - console.log("Voucher disabled.") - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -`Result is an empty body` - - -#### Enabling a voucher - -`voucherify.enable(voucher_code, callback*)` - -Example: - -```javascript - voucherify.enable("v1GiJYuuS") - .then(function (result) { - console.log("Voucher enabled.") - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -`Result is an empty body` - - -#### Getting voucher redemption - -`voucherify.redemption(voucher_code, callback*)` - -Example: - -```javascript -voucherify.redemption("v1GiJYuuS") - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "quantity": 3, - "redeemed_quantity": 1, - "redemption_entries": [ - { - "id": "r_gQzOnTwmhn2nTLwW4sZslNKY", - "object": "redemption", - "date": "2016-04-24T06:03:35Z", - "customer_id": null, - "tracking_id": "GENERATED-OR-PROVIDED-TRACKING-ID" - } - ] -} -``` - - -#### Publishing voucher - -`voucherify.publish(campaign_name, callback*)` - -`voucherify.publish(params, callback*)` - -This method selects a voucher that is suitable for publication, adds a publish entry and returns the voucher. -A voucher is suitable for publication when it's active and hasn't been published more times than the redemption limit. - -Example: - -By campaign name: - -```javascript -voucherify.publish("First Ride") - .then(function (result) { - console.log(JSON.stringify(result, null, " ")) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -By object with campaign name: - -```javascript -voucherify.publish({campaign: "First Ride", channel: "Email", customer: "donny.roll@mail.com"}) - .then(function (result) { - console.log(JSON.stringify(result, null, " ")) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -By object with voucher code: - -```javascript -voucherify.publish({voucher: "FR-zT-u9I7zG", channel: "Email", customer: "donny.roll@mail.com"}) - .then(function (result) { - console.log(JSON.stringify(result, null, " ")) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` +- [Vouchers](#vouchers-api) +- [Campaigns](#campaigns-api) +- [Validations](#validations-api) +- [Redemptions](#redemptions-api) +- [Customers](#customers-api) +- [Products](#products-api) +- [Deprecated methods](#deprecated-api) -Result: +This SDK is fully consistent with restufl API Voucherify provides. +Detalied description and example responsesx you will find at [official docs](https://docs.voucherify.io/reference). -```json -{ - "code": "FR-zT-u9I7zG", - "campaign": "First Ride", - "category": null, - "discount": { - "type": "PERCENT", - "amount_off": 50 - }, - "start_date": "2015-01-01T00:00:00Z", - "expiration_date": "2016-12-31T23:59:59Z", - "publish": { - "object": "list", - "count": 1, - "data_ref": "entries", - "entries": [{ - "channel": "Email", - "customer": "donny.roll@mail.com", - "customer_id": "cust_1fnSUBno3iimKTPNDCkjg4xV", - "published_at": "2016-01-22T09:25:07Z" - }] - }, - "redemption": { - "object": "list", - "quantity": 0, - "data_ref": "redemption_entries", - "redeemed_quantity": 0, - "redemption_entries": [] - }, - "active": true, - "additional_info": null -} -``` +### Vouchers API +Methods are provided withing `client.vouchers.*` namespace. -Error: +#### Create Voucher +`client.vouchers.create(voucher)` -```json -{ - "code": 400, - "message": "Couldn't find any voucher suitable for publication." -} -``` +See [possible voucher fields](https://docs.voucherify.io/docs/vouchers#the-voucher-object) and [example results](https://docs.voucherify.io/reference#create-voucher). -#### Validating vouchers - -Validation lets you check if given voucher code can be successfully redeemed. - -`voucherify.validate(code, context)` - -The `context` param is generally optional unless you are validating a gift voucher or a voucher with order validation rules. -For gift voucher you have to pass `order.amount` expressed in cents (e.g. $10 is 1000). -Validation rules also require to pass `order.items` as a list of objects including `product_id`, `sku_id` and `quantity`. - -Example: - -``` -validation_result = voucherify.validate("91Ft4U", { - tracking_id: "john@lemon.com", - customer: { - id: "cust_07sVjVsr71Ewot9lVZSrIVLH", - source_id: "john@lemon.com", - name: "John Lemon" - }, - order: { - amount: 1250 - items: [ - { product_id: "prod_ELvEXqF4qzB7Rs", sku_id: "sku_GoXSOI4FwJZafb", quantity: 1 }, - { product_id: "prod_wye1naw5JO5dh3", sku_id: "sku_U3rHSlfOCGUnbo", quantity: 2 } - ] - } -}) -``` - -Successful validation result: -``` -{ - code: "91Ft4U", - valid: true, - gift: { - amount: 10000 - }, - tracking_id: "john@lemon.com" -} -``` +#### Get Voucher +`client.vouchers.get(code)` -Failed validation result: -``` -{ - code: "91Ft4U", - valid: false, - reason: "gift amount exceeded", - tracking_id: "john@lemon.com" -} -``` +#### Update Voucher +`client.vouchers.update(voucher)` -There are several reasons why validation may fail (`valid: false` response). You can find the actual cause in the `reason` field: +#### Delete Voucher +`client.vouchers.delete(code, [params])` -- `voucher not found` -- `voucher is disabled` -- `voucher not active yet` -- `voucher expired` -- `quantity exceeded` -- `gift amount exceeded` -- `customer does not match segment rules` -- `order does not match validation rules` +See available optional [delete params](https://docs.voucherify.io/reference#delete-voucher). -#### Redeeming vouchers +#### List Vouchers +`client.vouchers.list(query)` -`voucherify.redeem(voucher_code, tracking_id|customer_profile*, callback*)` +See available [query params](https://docs.voucherify.io/reference#list-vouchers). -##### 1. Just by code +#### Publish Voucher +- by campaign name +`client.vouchers.publish(campaignName)` +- by param +`client.vouchers.publish(bodyParams)` +See available [params](https://docs.voucherify.io/reference#publish-voucher). -Example: +#### Enable Voucher +- `client.vouchers.enable(code)` -```javascript -voucherify.redeem("v1GiJYuuS") - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` +#### Disable Voucher +- `client.vouchers.disable(code)` -Result (voucher details after redemption): +#### Import Vouchers +- `client.vouchers.import(vouchersArray)` -```json -{ - "id": "r_yRmanaA6EgSE9uDYvMQ5Evfp", - "object": "redemption", - "date": "2016-04-25T10:34:57Z", - "customer_id": null, - "tracking_id": "(tracking_id not set)", - "voucher": { - "code": "v1GiJYuuS", - "campaign": "vip", - "discount": { - "percent_off": 10.0, - "type": "PERCENT" - }, - "expiration_date": "2016-12-31T23:59:59Z", - "redemption": { - "quantity": 3, - "redeemed_quantity": 2, - "redemption_entries": [ - { - "id": "r_gQzOnTwmhn2nTLwW4sZslNKY", - "object": "redemption", - "date": "2016-04-24T06:03:35Z", - "customer_id": null, - "tracking_id": "(tracking_id not set)" - }, - { - "id": "r_yRmanaA6EgSE9uDYvMQ5Evfp", - "object": "redemption", - "date": "2016-04-25T10:34:57Z", - "customer_id": null, - "tracking_id": "(tracking_id not set)" - } - ] - }, - "active": true, - "additional_info": "" - } -} -``` +### Deprecated methods -Error: +We strongly encourage you to update your code with new methods. +Each deprecated method has corresponding new namespaced one with the same params, +so migration will go smooth. -```json -{ - "code": 400, - "message": "voucher expired or quantity exceeded", - "details": "v1GiJYuuS" -} -``` +- `client.list(filter)` - see [client.vouchers.list](#list-vouchers) +- `client.get(voucher_code)`- see [client.vouchers.get](#get-voucher) +- `client.create(voucher)` - see [client.vouchers.create](#create-voucher) +- `client.update(voucher)` - see [client.vouchers.update](#update-voucher) +- `client.delete(voucher_code, [params])` - see [client.vouchers.delete](#delete-voucher) +- `client.campaign.voucher.create(campaignName, payload)` - see [client.campaigns.addVoucher](#add-voucher-to-campaign) -##### 2. With tracking id +- `voucherify.disable(voucher_code)` +- `voucherify.enable(voucher_code)` -You can provide a tracking id (e.g. your customer's login or a generated id) to the voucher redemption request. -```javascript -voucherify.redeem("v1GiJYuuS", "alice.morgan") - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` +- `voucherify.redemption(voucher_code)` -Result: +- `voucherify.publish(campaign_name)` -```json -{ - "id": "r_yRmanaA6EgSE9uDYvMQ5Evfp", - "object": "redemption", - "date": "2016-04-25T10:34:57Z", - "customer_id": "cust_C9qJ3xKgZFqkpMw7b21MF2ow", - "tracking_id": "alice.morgan", - "voucher": { - "code": "v1GiJYuuS", - "campaign": "vip", - "discount": { - "percent_off": 10.0, - "type": "PERCENT" - }, - "expiration_date": "2016-12-31T23:59:59Z", - "redemption": { - "quantity": 3, - "redeemed_quantity": 3, - "redemption_entries": [ - { - "id": "r_gQzOnTwmhn2nTLwW4sZslNKY", - "object": "redemption", - "date": "2016-04-24T06:03:35Z", - "customer_id": null, - "tracking_id": "(tracking_id not set)" - }, - { - "id": "r_yRmanaA6EgSE9uDYvMQ5Evfp", - "object": "redemption", - "date": "2016-04-25T10:34:57Z", - "customer_id": null, - "tracking_id": "(tracking_id not set)" - }, - { - "id": "r_irOQWUTAjthQwnkn5JQM1V6N", - "object": "redemption", - "date": "2016-04-25T12:04:08Z", - "customer_id": "cust_C9qJ3xKgZFqkpMw7b21MF2ow", - "tracking_id": "alice.morgan" - } - ] - }, - "active": true, - "additional_info": "" - } -} -``` +- `voucherify.publish(params)` -##### 3. With customer profile +- `voucherify.validate(code, context)` -You can record a detailed customer profile consisting of a `source_id`, `name`, `email`, `description` and a `metadata` section that can include any data you wish. -Voucherify will create (or update) provided customer profile in its database. +- `voucherify.redeem(voucher_code, tracking_id|customer_profile*)` -```javascript -voucherify.redeem({ - voucher: "v1GiJYuuS", - customer: { - soruce_id: "alice.morgan", - name: "Alice Morgan", - email: "alice@morgan.com", - description: "", - metadata: { - locale: "en-GB", - shoeSize: 5, - favourite_brands: ["Armani", "L’Autre Chose", "Vicini"] - } - }) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - - -##### 4. With customer id - -If you already created a customer profile in Voucherify's database, whether it was implicitly by providing it to the `redeem` function or explicitly by invoking the [`customer.create`](#create-customer) method, you can identify your customer in following redemptions by a generated id (starting with `cust_`). - -```javascript -voucherify.redeem({ - voucher: "v1GiJYuuS", - customer: { - id: "cust_C9qJ3xKgZFqkpMw7b21MF2ow" - }) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -##### 5. With order amount - -Redeeming a gift voucher requires to pass an amount that you wish to withdraw from the voucher. -The same applies to vouchers with validation rules on order's total amount. -Order amount have to be expressed in cents, as an integer. For example $22.50 should be provided as 2250: - -```javascript -voucherify.redeem({ - voucher: "91Ft4U", - order: { - amount: 2250 - }) -``` - -##### 6. With order items - -Vouchers with validation rules regarding products or SKUs require to pass `order.items`. -Items are a list of objects consisting of `product_id`, `sku_id` and `quantity`. - -```javascript -voucherify.redeem({ - voucher: "91Ft4U", - order: { - items: [ - { product_id: "prod_ELvEXqF4qzB7Rs", sku_id: "sku_GoXSOI4FwJZafb", quantity: 1 }, - { product_id: "prod_wye1naw5JO5dh3", sku_id: "sku_U3rHSlfOCGUnbo", quantity: 2 } - ] - }) -``` - -### Listing redemptions - -Use `voucherify.redemptions(filter, callback*)` to get a filtered list of redemptions. -Filter parameters: - -- limit (default: 100) -- page (default: 0) -- start_date (default: beginning of current month) -- end_date (default: end of current month) -- result - Success | Failure-NotExist | Failure-Inactive -- customer - -Example - 1000 successful redemptions from April 2016: - -```javascript -const filter = { - limit: 1000, - page: 0, - start_date: "2016-04-01T00:00:00", - end_date: "2016-04-30T23:59:59", - result: "Success" -} - -voucherify.redemptions(filter) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - - -#### Rollback a redemption - -Use `voucherify.rollback(redemption_id, options*, callback*)` to revert a redemption. -It will create a rollback entry in `redemption.redemption_entries` and give 1 redemption back to the pool -(decrease `redeemed_quantity` by 1). -Parameter `options` passed as object supports following attributes: -- `reason` - reason why rollback is perform -- `tracking_id` - attribute for tracking customer -- `customer` - customer id or customer object - -Possible errors are: -- 404 - Resource not found - if voucher with given `redemption_id` doesn't exist -- 400 - Already rolled back - if redemption with given `redemption_id` has been rolled back already -- 400 - Invalid redemption id - when trying to rollback a rollback. - -Example: - -Option is a `reason`: -```javascript -voucherify.rollback("r_irOQWUTAjthQwnkn5JQM1V6N", "Wrong user") - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Object which contains following options of `reason`, _customer id_ as `customer`: -```javascript -voucherify.rollback("r_irOQWUTAjthQwnkn5JQM1V6N", { - "reason": "Wrong user ID", - "customer": "cust_1V6NirOQWUwnkn5JQMTAjthQ", - }) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Object which contains customer data: -* Object customer will upsert customer data if exists or will create new if not. -```javascript -voucherify.rollback("r_irOQWUTAjthQwnkn5JQM1V6N", { - "customer": { - "name": "Alice Morgan", - "source_id": "alice.morgan", - "email": "alice.morgan@mail.com" - }, - }) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - - -```javascript -voucherify.rollback("r_irOQWUTAjthQwnkn5JQM1V6N", "wrong user") - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -``` -{ - "id": "rr_1634wLkb8glgRXrTmsxRzDBd", - "object": "redemption_rollback", - "date": "2016-04-25T10:35:02Z", - "tracking_id": "alice.morgan", - "customer_id": "cust_1V6NirOQWUwnkn5JQMTAjthQ", - "redemption": "r_irOQWUTAjthQwnkn5JQM1V6N", - "reason": "wrong user" - "voucher": { - "code": "v1GiJYuuS", - "campaign": "vip", - "discount": { - "percent_off": 10.0, - "type": "PERCENT" - }, - "expiration_date": "2016-12-31T23:59:59Z", - "redemption": { - "quantity": 3, - "redeemed_quantity": 2, - "redemption_entries": [ - { - "id": "r_gQzOnTwmhn2nTLwW4sZslNKY", - "object": "redemption", - "date": "2016-04-24T06:03:35Z", - "customer_id": null, - "tracking_id": "(tracking_id not set)" - }, - { - "id": "r_yRmanaA6EgSE9uDYvMQ5Evfp", - "object": "redemption", - "date": "2016-04-25T10:34:57Z", - "customer_id": null, - "tracking_id": "(tracking_id not set)" - }, - { - "id": "r_irOQWUTAjthQwnkn5JQM1V6N", - "object": "redemption", - "customer_id": "cust_C9qJ3xKgZFqkpMw7b21MF2ow" - "date": "2016-04-25T12:04:08Z", - "tracking_id": "alice.morgan" - }, - { - "id": "rr_1634wLkb8glgRXrTmsxRzDBd", - "object": "redemption_rollback", - "date": "2016-04-25T10:35:02Z", - "customer_id": null, - "tracking_id": "alice.morgan", - "redemption": "r_irOQWUTAjthQwnkn5JQM1V6N" - } - ] - }, - "active": true, - "additional_info": "" - } -} -``` - - -#### Create Customer - -Example: - -```javascript -const payload = { - "source_id": "your-tracking-id", - "name": "John Doe", - "email": "email@example.com", - "description": "Premium user, ACME Inc.", - "metadata": { - "lang":"en" - } -} - -voucherify.customer.create(payload) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "id": "cust_dJRcBf3P9HvmHK5TOrhRUHzL", - "object": "customer", - "source_id": "your-tracking-id", - "name": "John Doe", - "email": "email@example.com", - "description": "Premium user, ACME Inc.", - "metadata": { - "lang": "en" - }, - "created_at": "2016-06-06T17:14:55Z" -} -``` - - -#### Get Customer - -Example: - -```javascript -const customerId = "cust_c2SlN2rKajDdMycd3BmVawJk" - -voucherify.customer.get(customerId) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "id": "cust_c2SlN2rKajDdMycd3BmVawJk", - "object": "customer", - "source_id": "your-tracking-id", - "name": "John Doe", - "email": "email@example.com", - "description": "Premium user, ACME Inc.", - "metadata": { - "lang": "en" - }, - "created_at": "2016-06-07T07:35:59Z" -} -``` - - -#### Update Customer - -Example: - -```javascript -const payload = { - "name": "John Doe", - "email": "email@example.com", - "description":"Premium user, ACME Inc.", - "metadata": { - "lang":"en", - "type":"premium" - } -} - -voucherify.customer.update(payload) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "id": "cust_c2SlN2rKajDdMycd3BmVawJk", - "object": "customer", - "source_id": "your-tracking-id", - "name": "John Doe", - "email": "email@example.com", - "description": "Premium user, ACME Inc.", - "metadata": { - "lang": "en", - "type": "premium" - }, - "created_at": "2016-06-06T17:14:55Z" -} -``` - - -#### Delete Customer - -Example: - -```javascript -const customerId = "cust_c2SlN2rKajDdMycd3BmVawJk" - -voucherify.customer.delete(customerId) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -`Result is an empty body` - - -#### Create Product - -Example: - -```javascript -const payload = { - "name": "Apple iPhone 6", - "attributes": [ - "color", - "memory" - ], - "metadata": { - "type": "normal" - } -} - -voucherify.product.create(payload) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "id": "prod_YWnt2mNigm76oA", - "object": "product", - "name": "Apple iPhone 6", - "attributes": [ - "color", - "memory" - ], - "metadata": { - "type": "normal" - }, - "created_at": "2016-07-29T13:15:24Z", - "skus": { - "object": "list", - "total": 0, - "data": [] - } -} -``` - - -#### Get Product - -Example: - -```javascript -const productId = "prod_YWnt2mNigm76oA" - -voucherify.product.get(productId) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "id": "prod_YWnt2mNigm76oA", - "object": "product", - "name": "Apple iPhone 6", - "attributes": [ - "color", - "memory" - ], - "metadata": { - "type": "normal" - }, - "created_at": "2016-07-29T13:15:24Z", - "skus": { - "object": "list", - "total": 0, - "data": [] - } -} -``` - - -#### Update Product - -Example: - -```javascript -const payload = { - "id": "prod_YWnt2mNigm76oA", - "object": "product", - "name": "Apple iPhone 6", - "attributes": [ - "color", - "memory" - ], - "metadata": { - "type": "ultra premium" - }, - "created_at": "2016-07-29T13:15:24Z", - "skus": { - "object": "list", - "total": 0, - "data": [] - } -} - -voucherify.product.update(payload) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "id": "prod_YWnt2mNigm76oA", - "object": "product", - "name": "Apple iPhone 6", - "attributes": [ - "color", - "memory" - ], - "metadata": { - "type": "ultra premium" - }, - "created_at": "2016-07-29T13:15:24Z", - "skus": { - "object": "list", - "total": 0, - "data": [] - } -} -``` - - -#### Delete Product - -Example: - -```javascript -const productId = "prod_YWnt2mNigm76oA" - -voucherify.product.delete(productId) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -`Result is an empty body` - - - -#### Create Sku - -Example: - -```javascript -const productId = "prod_e8uLMegXZJ4GGS" - -const sku = { - sku: "APPLE_IPHONE_6_BLACK", - currency: "EUR", - price: 12000, - attributes: { - color: "BLACK", - memory: "16GB" - } -} - -voucherify.product.sku.create(productId, payload) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "id": "sku_JXYGfsGbpvsfjv", - "product_id": "prod_e8uLMegXZJ4GGS", - "sku": "APPLE_IPHONE_6_BLACK", - "created_at": "2016-08-02T16:43:47Z", - "object": "sku" -} -``` - - -#### Get Sku - -Example: - -```javascript -const productId = "prod_YWnt2mNigm76oA" - -const skuId = "sku_JXYGfsGbpvsfjv" - -voucherify.product.sku.get(productId, skuId) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "id": "sku_JXYGfsGbpvsfjv", - "product_id": "prod_e8uLMegXZJ4GGS", - "sku": "APPLE_IPHONE_6_BLACK", - "created_at": "2016-08-02T16:43:47Z", - "object": "sku" -} -``` - - -#### Update Sku - -Example: - -```javascript -const sku = { - "id": "sku_JXYGfsGbpvsfjv", - "product_id": "prod_e8uLMegXZJ4GGS", - "sku": "APPLE_IPHONE_6_BLACK", - "created_at": "2016-08-02T16:43:47Z", - "object": "sku" -} - -sku.currency = "EUR" -sku.price = 1000 - -const productId = sku.product_id - -voucherify.product.sku.update(productId, sku) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` - -Result: - -```json -{ - "id": "sku_JXYGfsGbpvsfjv", - "product_id": "prod_e8uLMegXZJ4GGS", - "sku": "APPLE_IPHONE_6_BLACK", - "currency": "EUR", - "price": 1000, - "created_at": "2016-08-02T16:43:47Z", - "object": "sku" -} -``` - - -#### Delete Sku - -Example: - -```javascript - -const productId = "prod_e8uLMegXZJ4GGS" - -const skuId = "sku_JXYGfsGbpvsfjv" - -voucherify.product.sku.delete(productId, skuId) - .then(function (result) { - console.log(result) - }) - .catch(function (error) { - console.error("Error: %s", error) - }) -``` -Result: +- `voucherify.redemptions(filter)` -`Result is an empty body` +- `voucherify.rollback(redemption_id, options*)` From c8d5ccb997e10b5070569e4d81fb15870a383c55 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 15:14:12 +0100 Subject: [PATCH 090/112] update sdk logo --- .npmignore | 1 + README.md | 3 +-- voucherify-nodejs-sdk.png | Bin 0 -> 46712 bytes 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 voucherify-nodejs-sdk.png diff --git a/.npmignore b/.npmignore index a94a810..fe3cbd6 100644 --- a/.npmignore +++ b/.npmignore @@ -4,3 +4,4 @@ test/ examples/ release-sources-header.txt *.log +voucherify-nodejs-sdk diff --git a/README.md b/README.md index f5e34e2..3a368e4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@

- +

Official Voucherify Node.js SDK

diff --git a/voucherify-nodejs-sdk.png b/voucherify-nodejs-sdk.png new file mode 100644 index 0000000000000000000000000000000000000000..18cb4063fd0fe30a8eab701427e4f1ff4a7446a2 GIT binary patch literal 46712 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 Date: Thu, 1 Dec 2016 15:14:57 +0100 Subject: [PATCH 091/112] fix deps badge status --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a368e4..39db59c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Build Status NPM Version NPM Downloads - Dependencies + Dependencies


From 3ea2c8f03e5570ce755721a376c8aa2668cb2fa4 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 15:16:53 +0100 Subject: [PATCH 092/112] add sub nav with API links --- README.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 39db59c..f035d24 100644 --- a/README.md +++ b/README.md @@ -19,16 +19,30 @@ | Callback or Promise? | -API -| Error handling | Contributing | Changelog +

+ +

+API: +Vouchers +| +Campaigns +| +Validations | -License +Redemptions +| +Customers +| +Products +| +Deprecated Methods

+
## Setup @@ -78,14 +92,6 @@ All other examples in the readme use promises but they could be as well written ## API -- [Vouchers](#vouchers-api) -- [Campaigns](#campaigns-api) -- [Validations](#validations-api) -- [Redemptions](#redemptions-api) -- [Customers](#customers-api) -- [Products](#products-api) -- [Deprecated methods](#deprecated-api) - This SDK is fully consistent with restufl API Voucherify provides. Detalied description and example responsesx you will find at [official docs](https://docs.voucherify.io/reference). From 42c67e8507a038ffdec94a03ed8114c450023e04 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 15:40:50 +0100 Subject: [PATCH 093/112] new vouchers api description --- README.md | 56 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index f035d24..fff9181 100644 --- a/README.md +++ b/README.md @@ -93,47 +93,44 @@ All other examples in the readme use promises but they could be as well written ## API This SDK is fully consistent with restufl API Voucherify provides. -Detalied description and example responsesx you will find at [official docs](https://docs.voucherify.io/reference). +Detalied description and example responses you will find at [official docs](https://docs.voucherify.io/reference). +Method headers point to more detalied params description you can use. ### Vouchers API -Methods are provided withing `client.vouchers.*` namespace. +Methods are provided within `client.vouchers.*` namespace. -#### Create Voucher +#### [Create Voucher] `client.vouchers.create(voucher)` -See [possible voucher fields](https://docs.voucherify.io/docs/vouchers#the-voucher-object) and [example results](https://docs.voucherify.io/reference#create-voucher). +See [full voucher oject](https://docs.voucherify.io/reference#the-voucher-object). -#### Get Voucher +#### [Get Voucher] `client.vouchers.get(code)` -#### Update Voucher +#### [Update Voucher] `client.vouchers.update(voucher)` -#### Delete Voucher -`client.vouchers.delete(code, [params])` +#### [Delete Voucher] +``` +client.vouchers.delete(code) +client.vouchers.delete(code, {force: true}) +``` + +#### [List Vouchers] +`client.vouchers.list(params)` -See available optional [delete params](https://docs.voucherify.io/reference#delete-voucher). +#### [Enable Voucher] +`client.vouchers.enable(code)` -#### List Vouchers -`client.vouchers.list(query)` +#### [Disable Voucher] +`client.vouchers.disable(code)` -See available [query params](https://docs.voucherify.io/reference#list-vouchers). +#### [Import Vouchers] +`client.vouchers.import(vouchers)` -#### Publish Voucher -- by campaign name -`client.vouchers.publish(campaignName)` -- by param -`client.vouchers.publish(bodyParams)` -See available [params](https://docs.voucherify.io/reference#publish-voucher). -#### Enable Voucher -- `client.vouchers.enable(code)` -#### Disable Voucher -- `client.vouchers.disable(code)` -#### Import Vouchers -- `client.vouchers.import(vouchersArray)` ### Deprecated methods @@ -251,3 +248,14 @@ Utils don't need callbacks nor promises. They return results immediately. - Authentication - Voucher informations: *get*, *usage* - Voucher operations: *use* + +[Create Voucher]: https://docs.voucherify.io/reference#create-voucher +[Get Voucher]: https://docs.voucherify.io/reference#vouchers-get +[Update Voucher]: https://docs.voucherify.io/reference#update-voucher +[Delete Voucher]: https://docs.voucherify.io/reference#delete-voucher +[List Vouchers]: https://docs.voucherify.io/reference#list-vouchers +[Enable Voucher]: https://docs.voucherify.io/reference#enable-voucher +[Disable Voucher]: https://docs.voucherify.io/reference#disable-voucher +[Import Vouchers]: https://docs.voucherify.io/reference#import-vouchers-1 + +[Publish Voucher]: https://docs.voucherify.io/reference#publish-voucher From de036d27c95ba4de41bca4f9aaa8d67a7c8d6e22 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 15:50:09 +0100 Subject: [PATCH 094/112] move voucher publish to Distributions API --- README.md | 9 +++++++ src/Distributions.js | 19 ++++++++++++++ src/Vouchers.js | 12 +-------- src/index.js | 5 +++- test/distributions-api.spec.js | 45 ++++++++++++++++++++++++++++++++++ test/vouchers-api.spec.js | 33 ------------------------- 6 files changed, 78 insertions(+), 45 deletions(-) create mode 100644 src/Distributions.js create mode 100644 test/distributions-api.spec.js diff --git a/README.md b/README.md index fff9181..05b04b3 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ API: | Campaigns | +Distributions +| Validations | Redemptions @@ -129,8 +131,15 @@ client.vouchers.delete(code, {force: true}) `client.vouchers.import(vouchers)` +### Distributions API +Methods are provided within `client.distributions.*` namespace. +#### [Publish Voucher] +``` +client.distributions.publish(campaignName) +client.distributions.publish(params) +``` ### Deprecated methods diff --git a/src/Distributions.js b/src/Distributions.js new file mode 100644 index 0000000..24b6334 --- /dev/null +++ b/src/Distributions.js @@ -0,0 +1,19 @@ +'use strict' + +const {encode, isString, isObject} = require('./helpers') + +module.exports = class Distributions { + constructor (client) { + this.client = client + } + + publish (params, callback) { + if (isString(params)) { + return this.client.post('/vouchers/publish', {campaign: encode(params)}, callback) + } + + if (isObject(params)) { + return this.client.post('/vouchers/publish', params, callback) + } + } +} diff --git a/src/Vouchers.js b/src/Vouchers.js index 071fa96..806faa8 100644 --- a/src/Vouchers.js +++ b/src/Vouchers.js @@ -1,6 +1,6 @@ 'use strict' -const {encode, isFunction, isString, isObject} = require('./helpers') +const {encode, isFunction} = require('./helpers') module.exports = class Vouchers { constructor (client) { @@ -39,16 +39,6 @@ module.exports = class Vouchers { return this.client.get('/vouchers', params, callback) } - publish (params, callback) { - if (isString(params)) { - return this.client.post('/vouchers/publish', {campaign: encode(params)}, callback) - } - - if (isObject(params)) { - return this.client.post('/vouchers/publish', params, callback) - } - } - enable (code, callback) { return this.client.post(`/vouchers/${encode(code)}/enable`, null, callback) } diff --git a/src/index.js b/src/index.js index a73e200..db83bc2 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ const ApiClient = require('./ApiClient') const Campaigns = require('./Campaigns') +const Distributions = require('./Distributions') const Vouchers = require('./Vouchers') const Validations = require('./Validations') const Redemptions = require('./Redemptions') @@ -16,6 +17,7 @@ module.exports = function (options) { const client = new ApiClient(options) const vouchers = new Vouchers(client) const campaigns = new Campaigns(client) + const distributions = new Distributions(client) const validations = new Validations(client) const redemptions = new Redemptions(client) const customers = new Customers(client) @@ -45,6 +47,7 @@ module.exports = function (options) { return { vouchers, campaigns, + distributions, validations, redemptions: backwardCompatibleRedemptions, customers, @@ -60,7 +63,7 @@ module.exports = function (options) { update: (voucher, callback) => vouchers.update(voucher, callback), enable: (code, callback) => vouchers.enable(code, callback), disable: (code, callback) => vouchers.disable(code, callback), - publish: (campaignName, callback) => vouchers.publish(campaignName, callback), + publish: (campaignName, callback) => distributions.publish(campaignName, callback), // validations validate: (code, context, callback) => validations.validateVoucher(code, context, callback), // redemptions diff --git a/test/distributions-api.spec.js b/test/distributions-api.spec.js new file mode 100644 index 0000000..fff3626 --- /dev/null +++ b/test/distributions-api.spec.js @@ -0,0 +1,45 @@ +/* eslint-env jasmine */ +const nock = require('nock') +const VoucherifyClient = require('../src/index') +const {reqWithBody} = require('./fixtures') +nock.disableNetConnect() + +describe('Distributions API', function () { + const client = new VoucherifyClient({ + applicationId: 'node-sdk-test-id', + clientSecretKey: 'node-sdk-test-secret' + }) + + describe('publish voucher', function () { + it('should publish by camaign name', function (done) { + const server = nock('https://api.voucherify.io', reqWithBody) + .post('/v1/vouchers/publish') + .query({campaign: 'test-campaign'}) + .reply(200, {}) + + client.distributions.publish('test-campaign') + .then(() => { + server.done() + done() + }) + }) + + it('should publish by voucher', function (done) { + const server = nock('https://api.voucherify.io', reqWithBody) + .post('/v1/vouchers/publish', { + campaign: 'test-campaign', + voucher: 'test-voucher' + }) + .reply(200, {}) + + client.distributions.publish({ + campaign: 'test-campaign', + voucher: 'test-voucher' + }) + .then(() => { + server.done() + done() + }) + }) + }) +}) diff --git a/test/vouchers-api.spec.js b/test/vouchers-api.spec.js index bfb4aee..019b254 100644 --- a/test/vouchers-api.spec.js +++ b/test/vouchers-api.spec.js @@ -138,39 +138,6 @@ describe('Vouchers API', function () { }) }) - describe('publish voucher', function () { - it('should publish by camaign name', function (done) { - const server = nock('https://api.voucherify.io', reqWithBody) - .post('/v1/vouchers/publish') - .query({campaign: 'test-campaign'}) - .reply(200, {}) - - client.vouchers.publish('test-campaign') - .then(() => { - server.done() - done() - }) - }) - - it('should publish by voucher', function (done) { - const server = nock('https://api.voucherify.io', reqWithBody) - .post('/v1/vouchers/publish', { - campaign: 'test-campaign', - voucher: 'test-voucher' - }) - .reply(200, {}) - - client.vouchers.publish({ - campaign: 'test-campaign', - voucher: 'test-voucher' - }) - .then(() => { - server.done() - done() - }) - }) - }) - it('should enable voucher', function (done) { const server = nock('https://api.voucherify.io', reqWithBody) .post('/v1/vouchers/test-voucher/enable') From db69af5b034fa56c5ee7e01863f41ecf5a7dd534 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 16:24:17 +0100 Subject: [PATCH 095/112] test raw html header --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 05b04b3..68f6147 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,9 @@ Method headers point to more detalied params description you can use. ### Vouchers API Methods are provided within `client.vouchers.*` namespace. -#### [Create Voucher] +

+Create Voucher

+ `client.vouchers.create(voucher)` See [full voucher oject](https://docs.voucherify.io/reference#the-voucher-object). From e48e1ac39ff777b03db2ee72e44ccb7b4c95b089 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 17:19:30 +0100 Subject: [PATCH 096/112] update docs --- README.md | 276 ++++++++++++++++++++++++++++++++++++++--------- src/Customers.js | 1 - 2 files changed, 227 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 68f6147..67cf672 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

-

Official Voucherify Node.js SDK

+

Official Voucherify Node.js SDK

JavaScript Style Guide @@ -100,88 +100,238 @@ Method headers point to more detalied params description you can use. ### Vouchers API Methods are provided within `client.vouchers.*` namespace. - -

-Create Voucher

- -`client.vouchers.create(voucher)` - -See [full voucher oject](https://docs.voucherify.io/reference#the-voucher-object). +- [Create Voucher](#create-voucher) +- [Get Voucher](#get-voucher) +- [Update Voucher](#update-voucher) +- [Delete Voucher](#delete-voucher) +- [List Vouchers](#list-vouchers) +- [Enable Voucher](#enable-voucher) +- [Disable Voucher](#disable-voucher) +- [Import Vouchers](#import-vouchers) + +#### [Create Voucher] +```javascript +client.vouchers.create(voucher) +``` +Check [voucher oject](https://docs.voucherify.io/reference#the-voucher-object). #### [Get Voucher] -`client.vouchers.get(code)` - +```javascript +client.vouchers.get(code) +``` #### [Update Voucher] -`client.vouchers.update(voucher)` - -#### [Delete Voucher] +```javascript +client.vouchers.update(voucher) ``` +#### [Delete Voucher] +```javascript client.vouchers.delete(code) client.vouchers.delete(code, {force: true}) ``` - #### [List Vouchers] -`client.vouchers.list(params)` - +```javascript +client.vouchers.list() +client.vouchers.list(params) +``` #### [Enable Voucher] -`client.vouchers.enable(code)` - +```javascript +client.vouchers.enable() +client.vouchers.enable(code) +``` #### [Disable Voucher] -`client.vouchers.disable(code)` - +```javascript +client.vouchers.disable() +client.vouchers.disable(code) +``` #### [Import Vouchers] -`client.vouchers.import(vouchers)` +```javascript +client.vouchers.import(vouchers) +``` +### Campaigns API +Methods are provided within `client.campaigns.*` namespace. +- [Create Campaign](#create-campaign) +- [Get Campaign](#get-campaign) +- [Add Voucher to Campaign](#add-voucher-to-campaign) +- [Import Vouchers to Campaign](#import-vouchers-to-campaign) -### Distributions API +#### [Create Campaign] +```javascript +client.campaigns.create(campaign) +``` +#### [Get Campaign] +```javascript +client.campaigns.get(name) +``` +#### [Add Voucher to Campaign] +```javascript +client.campaigns.addVoucher(campaignName) +client.campaigns.addVoucher(campaignName, params) +``` +#### [Import Vouchers to Campaign] +```javascript +client.campaigns.importVouchers(campaignName, vouchers, callback) +``` +### Distributions API Methods are provided within `client.distributions.*` namespace. #### [Publish Voucher] -``` +```javascript client.distributions.publish(campaignName) client.distributions.publish(params) ``` -### Deprecated methods - -We strongly encourage you to update your code with new methods. -Each deprecated method has corresponding new namespaced one with the same params, -so migration will go smooth. - -- `client.list(filter)` - see [client.vouchers.list](#list-vouchers) -- `client.get(voucher_code)`- see [client.vouchers.get](#get-voucher) -- `client.create(voucher)` - see [client.vouchers.create](#create-voucher) -- `client.update(voucher)` - see [client.vouchers.update](#update-voucher) -- `client.delete(voucher_code, [params])` - see [client.vouchers.delete](#delete-voucher) -- `client.campaign.voucher.create(campaignName, payload)` - see [client.campaigns.addVoucher](#add-voucher-to-campaign) - - -- `voucherify.disable(voucher_code)` -- `voucherify.enable(voucher_code)` - +### Validations API +Methods are provided within `client.validations.*` namespace. -- `voucherify.redemption(voucher_code)` +#### [Validate Voucher] +```javascript +client.validations.validateVoucher(code) +client.validations.validateVoucher(code, params) +``` -- `voucherify.publish(campaign_name)` +### Redemptions API +Methods are provided within `client.redemptions.*` namespace. -- `voucherify.publish(params)` +- [Redeem Voucher](#redeem-voucher) +- [List Redemptions](#list-redemptions) +- [Get Voucher's Redemptions](#get-voucher's-redemptions) +- [Rollback Redemption](#rollback-redemption) -- `voucherify.validate(code, context)` +#### [Redeem Voucher] +```javascript +client.redemptions.redeem(code) +client.redemptions.redeem(code, {object} params) +// Deprecated! +client.redemptions.redeem({code, ...params}) +client.redemptions.redeem({code, ...params}, {string} tracking_id) +client.redemptions.redeem(code, {string} tracking_id) +``` +#### [List Redemptions] +```javascript +client.redemptions.list() +client.redemptions.list(params) +``` +#### [Get Voucher's Redemptions] +```javascript +client.redemptions.getForVoucher(code) +``` +#### [Rollback Redemption] +```javascript +client.redemptions.rollback(redemptionId) +client.redemptions.rollback(redemptionId, {object} params) +client.redemptions.rollback(redemptionId, {string} reason) +``` +Check [redemption rollback object](https://docs.voucherify.io/reference#the-redemption-rollback-object). -- `voucherify.redeem(voucher_code, tracking_id|customer_profile*)` +### Customers API +Methods are provided within `client.customers.*` namespace. +- [Create Customer](#create-customer) +- [Get Customer](#get-customer) +- [Update Customer](#update-customer) +- [Delete Customer](#delete-customer) -- `voucherify.redemptions(filter)` +#### [Create Customer] +```javascript +client.customers.create(customer) +``` +Check [customer object](https://docs.voucherify.io/reference#the-customer-object). +#### [Get Customer] +```javascript +client.customers.get(customerId) +``` +#### [Update Customer] +```javascript +client.customers.update(customer) +``` +#### [Delete Customer] +```javascript +client.customers.delete(customerId) +``` +### Products API +Methods are provided within `client.products.*` namespace. + +- [Create Product](#create-product) +- [Get Product](#get-product) +- [Update Product](#update-product) +- [Delete Product](#delete-product) +- [List Products](#list-products) +- [Create SKU](#create-sku) +- [Get SKU](#get-sku) +- [Update SKU](#update-sku) +- [Delete SKU](#delete-sku) +- [List all product SKUs](#list-all-product-skus) + +#### [Create Product] +```javascript +client.products.create(product) +``` +Check [product object](https://docs.voucherify.io/reference#the-product-object). +#### [Get Product] +```javascript +client.products.get(productId) +``` +#### [Update Product] +```javascript +client.products.update(product) +``` +#### [Delete Product] +```javascript +client.products.delete(productId) +``` +#### [List Products] +```javascript +client.products.list() +client.products.list(params) +``` +#### [Create SKU] +```javascript +client.products.createSku(productId, sku) +``` +Check [SKU object](https://docs.voucherify.io/reference#the-sku-object). +#### [Get SKU] +```javascript +client.products.getSku(productId, skuId) +``` +#### [Update SKU] +```javascript +client.products.updateSku(productId, sku) +``` +#### [Delete SKU] +```javascript +client.products.deleteSku(productId, skuId) +``` +#### [List all product SKUs] +```javascript +client.products.listSkus(productId) +``` -- `voucherify.rollback(redemption_id, options*)` +### Deprecated methods +We strongly encourage you to update your code with new methods. +Each deprecated method has corresponding new namespaced one with the same params, +so migration will go smooth. +- `client.list(filter)` - [client.vouchers.list](#list-vouchers) +- `client.get(voucher_code)`- [client.vouchers.get](#get-voucher) +- `client.create(voucher)` - [client.vouchers.create](#create-voucher) +- `client.update(voucher)` - [client.vouchers.update](#update-voucher) +- `client.delete(voucher_code, [params])` - [client.vouchers.delete](#delete-voucher) +- `client.disable(voucher_code)` - [client.vouchers.disable](#disable-voucher) +- `client.enable(voucher_code)`- [client.vouchers.enable](#enable-voucher) +- `client.campaign.voucher.create(campaignName, payload)` - see [client.campaigns.addVoucher](#add-voucher-to-campaign) +- `client.redemption(voucher_code)` - +- `client.publish(campaign_name)` +- `client.publish(params)` +- `client.validate(code, context)` +- `client.redeem(voucher_code, tracking_id|customer_profile*)` +- `client.redemptions(filter)` +- `client.rollback(redemption_id, options*)` ### Utils -#### Usage - ``` const utils = require('voucherify/utils') ``` @@ -269,4 +419,32 @@ Utils don't need callbacks nor promises. They return results immediately. [Disable Voucher]: https://docs.voucherify.io/reference#disable-voucher [Import Vouchers]: https://docs.voucherify.io/reference#import-vouchers-1 +[Create Campaign]: https://docs.voucherify.io/reference#create-campaign +[Get Campaign]: https://docs.voucherify.io/reference#get-campaign +[Add Voucher to Campaign]: https://docs.voucherify.io/reference#add-voucher-to-campaign +[Import Vouchers to Campaign]: https://docs.voucherify.io/reference#import-vouchers + [Publish Voucher]: https://docs.voucherify.io/reference#publish-voucher + +[Validate Voucher]: https://docs.voucherify.io/reference#validate-voucher + +[Redeem Voucher]: https://docs.voucherify.io/reference#redeem-voucher +[List Redemptions]: https://docs.voucherify.io/reference#list-redemptions +[Get Voucher's Redemptions]: https://docs.voucherify.io/reference#vouchers-redemptions +[Rollback Redemption]: https://docs.voucherify.io/reference#rollback-redemption + +[Create Customer]: https://docs.voucherify.io/reference#create-customer +[Get Customer]: https://docs.voucherify.io/reference#read-customer +[Update Customer]: https://docs.voucherify.io/reference#update-customer +[Delete Customer]: https://docs.voucherify.io/reference#delete-customer + +[Create Product]: https://docs.voucherify.io/reference#create-product +[Get Product]: https://docs.voucherify.io/reference#get-product +[Update Product]: https://docs.voucherify.io/reference#update-product +[Delete Product]: https://docs.voucherify.io/reference#delete-product +[List Products]: https://docs.voucherify.io/reference#list-products +[Create SKU]: https://docs.voucherify.io/reference#create-sku +[Get SKU]: https://docs.voucherify.io/reference#get-sku +[Update SKU]: https://docs.voucherify.io/reference#update-sku +[Delete SKU]: https://docs.voucherify.io/reference#delete-sku +[List all product SKUs]: https://docs.voucherify.io/reference#list-skus diff --git a/src/Customers.js b/src/Customers.js index 9ee3690..c7f7542 100644 --- a/src/Customers.js +++ b/src/Customers.js @@ -12,7 +12,6 @@ module.exports = class Customers { } get (customerId, callback) { - // TODO why fallback to empty string ?! shall we rather throw an error? print warning? return this.client.get(`/customers/${encode(customerId)}`, null, callback) } From b307439a4f58b3a00d77077f87a832efa75d02fb Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 18:56:13 +0100 Subject: [PATCH 097/112] update deprecated methods docs --- README.md | 28 +++++++++++++++------------- src/index.js | 2 +- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 67cf672..1f20f1e 100644 --- a/README.md +++ b/README.md @@ -314,21 +314,23 @@ We strongly encourage you to update your code with new methods. Each deprecated method has corresponding new namespaced one with the same params, so migration will go smooth. -- `client.list(filter)` - [client.vouchers.list](#list-vouchers) -- `client.get(voucher_code)`- [client.vouchers.get](#get-voucher) +- `client.list(params)` - [client.vouchers.list](#list-vouchers) +- `client.get(voucherCode) - [client.vouchers.get](#get-voucher) - `client.create(voucher)` - [client.vouchers.create](#create-voucher) - `client.update(voucher)` - [client.vouchers.update](#update-voucher) -- `client.delete(voucher_code, [params])` - [client.vouchers.delete](#delete-voucher) -- `client.disable(voucher_code)` - [client.vouchers.disable](#disable-voucher) -- `client.enable(voucher_code)`- [client.vouchers.enable](#enable-voucher) -- `client.campaign.voucher.create(campaignName, payload)` - see [client.campaigns.addVoucher](#add-voucher-to-campaign) -- `client.redemption(voucher_code)` - -- `client.publish(campaign_name)` -- `client.publish(params)` -- `client.validate(code, context)` -- `client.redeem(voucher_code, tracking_id|customer_profile*)` -- `client.redemptions(filter)` -- `client.rollback(redemption_id, options*)` +- `client.delete(voucherCode, [params])` - [client.vouchers.delete](#delete-voucher) +- `client.disable(voucherCode)` - [client.vouchers.disable](#disable-voucher) +- `client.enable(voucherCode) - [client.vouchers.enable](#enable-voucher) +- `client.campaign.voucher.create(campaignName)` - [client.campaigns.addVoucher](#add-voucher-to-campaign) +- `client.redemption(voucherCode)` - [client.redemptions.getForVoucher](#get-voucher's-redemptions) +- `client.publish(campaign_name|params)` - [client.distributions.publish](#publish-voucher) +- `client.validate(voucherCode, params)` - [client.validations.validateVoucher](#validate-voucher) +- `client.redeem(voucherCode, tracking_id|params)` - [client.redemptions.redeem](#redeem-voucher) +- `client.redemptions(params)` - [client.redemptions.list](#list-redemptions) +- `client.rollback(redemptionId, params)` - [client.redemptions.rollback](#rollback-redemption) +- `client.customer.*` - changed namespace to [client.customers.\*](#customers-api) +- `client.product.*` - changed namespace to [client.products.\*](#products-api) +- `client.product.sku.*` - changed namespace to [client.products.\*](#products-api) ### Utils diff --git a/src/index.js b/src/index.js index db83bc2..127aba6 100644 --- a/src/index.js +++ b/src/index.js @@ -65,7 +65,7 @@ module.exports = function (options) { disable: (code, callback) => vouchers.disable(code, callback), publish: (campaignName, callback) => distributions.publish(campaignName, callback), // validations - validate: (code, context, callback) => validations.validateVoucher(code, context, callback), + validate: (code, params, callback) => validations.validateVoucher(code, params, callback), // redemptions redemption: (code, callback) => redemptions.getForVoucher(code, callback), redeem: (code, trackingId, callback) => redemptions.redeem(code, trackingId, callback), From 1c60ec9a1cca39fcc7b75c29950fc924c748d517 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 18:57:24 +0100 Subject: [PATCH 098/112] deprecated methods link fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f20f1e..bf2b2db 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ API: | Products | -Deprecated Methods +Deprecated Methods


From f5b7b4645600bca84db950ae5810b11821f6122f Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 18:59:19 +0100 Subject: [PATCH 099/112] fix link --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bf2b2db..7c2cb4a 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,7 @@ Methods are provided within `client.redemptions.*` namespace. - [Redeem Voucher](#redeem-voucher) - [List Redemptions](#list-redemptions) -- [Get Voucher's Redemptions](#get-voucher's-redemptions) +- [Get Voucher's Redemptions](#get-vouchers-redemptions) - [Rollback Redemption](#rollback-redemption) #### [Redeem Voucher] @@ -322,7 +322,7 @@ so migration will go smooth. - `client.disable(voucherCode)` - [client.vouchers.disable](#disable-voucher) - `client.enable(voucherCode) - [client.vouchers.enable](#enable-voucher) - `client.campaign.voucher.create(campaignName)` - [client.campaigns.addVoucher](#add-voucher-to-campaign) -- `client.redemption(voucherCode)` - [client.redemptions.getForVoucher](#get-voucher's-redemptions) +- `client.redemption(voucherCode)` - [client.redemptions.getForVoucher](#get-vouchers-redemptions) - `client.publish(campaign_name|params)` - [client.distributions.publish](#publish-voucher) - `client.validate(voucherCode, params)` - [client.validations.validateVoucher](#validate-voucher) - `client.redeem(voucherCode, tracking_id|params)` - [client.redemptions.redeem](#redeem-voucher) From d9f581b23c270b2f98b0dda909c8a13495af5b12 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 19:00:28 +0100 Subject: [PATCH 100/112] add hr elements between api chapters --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7c2cb4a..2ced11b 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ client.vouchers.disable(code) ```javascript client.vouchers.import(vouchers) ``` - +
### Campaigns API Methods are provided within `client.campaigns.*` namespace. - [Create Campaign](#create-campaign) @@ -172,7 +172,7 @@ client.campaigns.addVoucher(campaignName, params) ```javascript client.campaigns.importVouchers(campaignName, vouchers, callback) ``` - +
### Distributions API Methods are provided within `client.distributions.*` namespace. @@ -181,7 +181,7 @@ Methods are provided within `client.distributions.*` namespace. client.distributions.publish(campaignName) client.distributions.publish(params) ``` - +
### Validations API Methods are provided within `client.validations.*` namespace. @@ -190,7 +190,7 @@ Methods are provided within `client.validations.*` namespace. client.validations.validateVoucher(code) client.validations.validateVoucher(code, params) ``` - +
### Redemptions API Methods are provided within `client.redemptions.*` namespace. @@ -224,7 +224,7 @@ client.redemptions.rollback(redemptionId, {object} params) client.redemptions.rollback(redemptionId, {string} reason) ``` Check [redemption rollback object](https://docs.voucherify.io/reference#the-redemption-rollback-object). - +
### Customers API Methods are provided within `client.customers.*` namespace. @@ -250,6 +250,7 @@ client.customers.update(customer) ```javascript client.customers.delete(customerId) ``` +
### Products API Methods are provided within `client.products.*` namespace. @@ -307,7 +308,7 @@ client.products.deleteSku(productId, skuId) ```javascript client.products.listSkus(productId) ``` - +
### Deprecated methods We strongly encourage you to update your code with new methods. From ccb692bf63694de75556e5c03d9f02eb09990694 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 19:18:45 +0100 Subject: [PATCH 101/112] fixes, add error handling and contributing section --- README.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2ced11b..54fccd7 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,9 @@ API: | Deprecated Methods

+| +Utils +


@@ -316,7 +319,7 @@ Each deprecated method has corresponding new namespaced one with the same params so migration will go smooth. - `client.list(params)` - [client.vouchers.list](#list-vouchers) -- `client.get(voucherCode) - [client.vouchers.get](#get-voucher) +- `client.get(voucherCode)` - [client.vouchers.get](#get-voucher) - `client.create(voucher)` - [client.vouchers.create](#create-voucher) - `client.update(voucher)` - [client.vouchers.update](#update-voucher) - `client.delete(voucherCode, [params])` - [client.vouchers.delete](#delete-voucher) @@ -333,6 +336,7 @@ so migration will go smooth. - `client.product.*` - changed namespace to [client.products.\*](#products-api) - `client.product.sku.*` - changed namespace to [client.products.\*](#products-api) +
### Utils ``` @@ -346,7 +350,16 @@ Utils don't need callbacks nor promises. They return results immediately. - `utils.calculatePrice(basePrice, voucher)` - `utils.calculateDiscount(basePrice, voucher)` -### Changelog +## Error handling + +Depending what you have choose `error` object of rejected Promise or first argument of provided callback has +consistent structure, described in details in our [API reference](https://docs.voucherify.io/reference#errors). + +## Contributing + +Bug reports and pull requests are welcome through [GitHub Issues](https://github.com/voucherifyio/voucherify-nodejs-sdk/issues). + +## Changelog - **2016-11-15** - `1.23.1` - Validate init options - **2016-10-26** - `1.23.0` - Error handling improved - passing error object in response to rejected request From 94597706e848e8133d5947bf11285879146127d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Wiktor?= Date: Thu, 1 Dec 2016 15:38:57 +0100 Subject: [PATCH 102/112] utils - support gift vouchers cherry pick of 8c782b5 slightly adopted --- README.md | 1 + package.json | 2 +- src/utils.js | 10 +++++++++ test/utils.spec.js | 56 +++++++++++++++++++++++++++++++++++----------- 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 54fccd7..1a7bf66 100644 --- a/README.md +++ b/README.md @@ -361,6 +361,7 @@ Bug reports and pull requests are welcome through [GitHub Issues](https://github ## Changelog +- **2016-12-01** - `1.23.2` - Support gift vouchers in utils - **2016-11-15** - `1.23.1` - Validate init options - **2016-10-26** - `1.23.0` - Error handling improved - passing error object in response to rejected request - **2016-10-03** - `1.22.0` - Added customer parameter to the rollback method diff --git a/package.json b/package.json index 8bbd8aa..1ab9219 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "voucherify", - "version": "1.23.1", + "version": "1.23.2", "homepage": "http://www.voucherify.io", "description": "Node.js SDK for Voucherify.", "author": "rspective", diff --git a/src/utils.js b/src/utils.js index 587677d..0b58823 100644 --- a/src/utils.js +++ b/src/utils.js @@ -27,6 +27,11 @@ module.exports = { const e = 100 // Number of digits after the decimal separator. let discount + if (voucher.gift) { + discount = Math.min(voucher.gift.balance / e, basePrice) + return roundMoney(basePrice - discount) + } + if (!voucher.discount) { throw new Error('Unsupported voucher type.') } @@ -58,6 +63,11 @@ module.exports = { const e = 100 // Number of digits after the decimal separator. let discount + if (voucher.gift) { + discount = Math.min(voucher.gift.balance / e, basePrice) + return roundMoney(discount) + } + if (!voucher.discount) { throw new Error('Unsupported voucher type.') } diff --git a/test/utils.spec.js b/test/utils.spec.js index b9b595f..8d9677d 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -44,23 +44,38 @@ describe('utils', function () { expect(discount).toBe(20.00) }) - it('should fail to calculate discount for gift voucher', function () { - const basePrice = 50 + it('should calculate discount for gift voucher when balance is less than base price', function () { + const basePrice = 75 const voucher = { gift: { - amount: 1000 + amount: 10000, + balance: 5000 } } - expect(function () { - utils.calculateDiscount(basePrice, voucher) - }).toThrow(new Error('Unsupported voucher type.')) + const discount = utils.calculateDiscount(basePrice, voucher) + + expect(discount).toBe(50.00) + }) + + it('should calculate discount for gift voucher when balance is greater than base price', function () { + const basePrice = 75.00 + const voucher = { + gift: { + amount: 10000, + balance: 10000 + } + } + + const discount = utils.calculateDiscount(basePrice, voucher) + + expect(discount).toBe(75.00) }) // ------ calculatePrice ------ // it('should calculate new price with amount discount', function () { - const basePrice = 50 + const basePrice = 50.00 const voucher = { discount: { type: 'AMOUNT', @@ -99,16 +114,31 @@ describe('utils', function () { expect(discount).toBe(30.00) }) - it('should fail to calculate price for gift voucher', function () { - const basePrice = 50 + it('should calculate new price for gift voucher when balance is less than base price', function () { + const basePrice = 75.00 + const voucher = { + gift: { + amount: 10000, + balance: 5000 + } + } + + const discount = utils.calculatePrice(basePrice, voucher) + + expect(discount).toBe(25.00) + }) + + it('should calculate new price for gift voucher when balance is greater than base price', function () { + const basePrice = 75.00 const voucher = { gift: { - amount: 1000 + amount: 10000, + balance: 10000 } } - expect(function () { - utils.calculatePrice(basePrice, voucher) - }).toThrow(new Error('Unsupported voucher type.')) + const discount = utils.calculatePrice(basePrice, voucher) + + expect(discount).toBe(0.00) }) }) From 15f71521902e3921d3ec2cfd40bdf1584b5d3cfe Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 19:54:15 +0100 Subject: [PATCH 103/112] bump version to 2.0.0 --- README.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a7bf66..7c23bc6 100644 --- a/README.md +++ b/README.md @@ -361,6 +361,7 @@ Bug reports and pull requests are welcome through [GitHub Issues](https://github ## Changelog +- **2016-11-15** - `2.0.0` - Rewritten SDK, added missing API methods, updated README. Backward capability is provided but we strongly recommend to migrate [deprecated methods](#deprecated-methods) to new namespaces - **2016-12-01** - `1.23.2` - Support gift vouchers in utils - **2016-11-15** - `1.23.1` - Validate init options - **2016-10-26** - `1.23.0` - Error handling improved - passing error object in response to rejected request diff --git a/package.json b/package.json index 1ab9219..d9bd9ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "voucherify", - "version": "1.23.2", + "version": "2.0.0", "homepage": "http://www.voucherify.io", "description": "Node.js SDK for Voucherify.", "author": "rspective", From a6b66fe330bceb57acfb935c9adb868300b557ab Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 20:23:46 +0100 Subject: [PATCH 104/112] fix not closed code text --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c23bc6..a222519 100644 --- a/README.md +++ b/README.md @@ -324,7 +324,7 @@ so migration will go smooth. - `client.update(voucher)` - [client.vouchers.update](#update-voucher) - `client.delete(voucherCode, [params])` - [client.vouchers.delete](#delete-voucher) - `client.disable(voucherCode)` - [client.vouchers.disable](#disable-voucher) -- `client.enable(voucherCode) - [client.vouchers.enable](#enable-voucher) +- `client.enable(voucherCode)` - [client.vouchers.enable](#enable-voucher) - `client.campaign.voucher.create(campaignName)` - [client.campaigns.addVoucher](#add-voucher-to-campaign) - `client.redemption(voucherCode)` - [client.redemptions.getForVoucher](#get-vouchers-redemptions) - `client.publish(campaign_name|params)` - [client.distributions.publish](#publish-voucher) From 3298cd755641e73ba9e862aa388999e911a60122 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 20:27:17 +0100 Subject: [PATCH 105/112] fix utils link --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index a222519..283cd1c 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,7 @@ API: | Products | -Deprecated Methods -

+Deprecated Methods | Utils

From df9a1cfb9456703d8ca746ccf9515e51107f638a Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 22:43:50 +0100 Subject: [PATCH 106/112] adopt examples --- examples/customer.js | 12 +++++----- ...ift-voucher-example.js => gift-voucher.js} | 10 ++++----- examples/product.js | 22 +++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) rename examples/{gift-voucher-example.js => gift-voucher.js} (74%) diff --git a/examples/customer.js b/examples/customer.js index 9d6c2eb..508def4 100644 --- a/examples/customer.js +++ b/examples/customer.js @@ -1,6 +1,6 @@ 'use strict' -const voucherifyClient = require('../voucherify') +const voucherifyClient = require('../src/index') const voucherify = voucherifyClient({ applicationId: 'c70a6f00-cf91-4756-9df5-47628850002b', @@ -17,12 +17,12 @@ const payload = { } console.log('==== CREATE ====') -voucherify.customer.create(payload) +voucherify.customers.create(payload) .then((customer) => { console.log('New Customer: ', customer) console.log('==== READ ====') - return voucherify.customer.get(customer.id) + return voucherify.customers.get(customer.id) .then((result) => { console.log('Result: ', result) return customer @@ -33,7 +33,7 @@ voucherify.customer.create(payload) customer.metadata.type = 'premium' - return voucherify.customer.update(customer) + return voucherify.customers.update(customer) .then((result) => { console.log('Result: ', result) return customer @@ -41,10 +41,10 @@ voucherify.customer.create(payload) }) .then((customer) => { console.log('==== DELETE ====') - return voucherify.customer.delete(customer.id) + return voucherify.customers.delete(customer.id) .then(() => { console.log('Checking...') - return voucherify.customer.get(customer.id) + return voucherify.customers.get(customer.id) .catch((err) => { console.log('Result:', err) }) diff --git a/examples/gift-voucher-example.js b/examples/gift-voucher.js similarity index 74% rename from examples/gift-voucher-example.js rename to examples/gift-voucher.js index 150eb02..436193f 100644 --- a/examples/gift-voucher-example.js +++ b/examples/gift-voucher.js @@ -1,4 +1,4 @@ -const voucherifyClient = require('../voucherify') +const voucherifyClient = require('../src/index') const voucherify = voucherifyClient({ applicationId: 'c70a6f00-cf91-4756-9df5-47628850002b', @@ -7,7 +7,7 @@ const voucherify = voucherifyClient({ let voucherCode -voucherify.create({ +voucherify.vouchers.create({ type: 'GIFT_VOUCHER', gift: { amount: 10000 @@ -19,16 +19,16 @@ voucherify.create({ .then(function (result) { console.log('Voucher %s created. Redeeming...', result.code) voucherCode = result.code - return voucherify.redeem({voucher: result.code, order: {amount: 5000}}, 'tester') + return voucherify.redemptions.redeem({voucher: result.code, order: {amount: 5000}}, 'tester') }) .then(function (result) { console.log('Voucher %s redeemed. Redemption id: %s, Rolling back...', result.voucher.code, result.id) - return voucherify.rollback(result.id, 'just so', 'tester') + return voucherify.redemptions.rollback(result.id, 'just so', 'tester') }) .then(function (result) { console.log('Redemption %s rolled back. Rollback id: %s', result.redemption, result.id) console.log(JSON.stringify(result, null, 4)) - return voucherify.delete(voucherCode, { force: true }) + return voucherify.vouchers.delete(voucherCode, { force: true }) }) .then(function (result) { console.log('Voucher %s deleted. Result: %j', voucherCode, result) diff --git a/examples/product.js b/examples/product.js index fa49a87..f62b94e 100644 --- a/examples/product.js +++ b/examples/product.js @@ -1,6 +1,6 @@ 'use strict' -const voucherifyClient = require('../voucherify') +const voucherifyClient = require('../src/index') const voucherify = voucherifyClient({ applicationId: 'c70a6f00-cf91-4756-9df5-47628850002b', @@ -21,12 +21,12 @@ const payload = { let skuId = null console.log('==== CREATE ====') -voucherify.product.create(payload) +voucherify.products.create(payload) .then((product) => { console.log('New Product: ', product) console.log('==== READ ====') - return voucherify.product.get(product.id) + return voucherify.products.get(product.id) .then((result) => { console.log('Result: ', result) return @@ -38,12 +38,12 @@ voucherify.product.create(payload) sku: 'APPLE_IPHONE_6_BLACK' } - return voucherify.product.sku.create(product.id, sku) + return voucherify.products.createSku(product.id, sku) .then((sku) => { console.log('Result: ', sku) console.log('==== GET - SKU ====') - return voucherify.product.sku.get(product.id, sku.id) + return voucherify.products.getSku(product.id, sku.id) .then((sku) => { console.log('Result: ', sku) console.log('==== UPDATE - SKU ====') @@ -51,7 +51,7 @@ voucherify.product.create(payload) sku.sku = 'eur' sku.price = 1000 - return voucherify.product.sku.update(product.id, sku) + return voucherify.products.updateSku(product.id, sku) }) }) .then((sku) => { @@ -69,7 +69,7 @@ voucherify.product.create(payload) product.metadata = product.metadata || {} product.metadata.type = 'premium' - return voucherify.product.update(product) + return voucherify.products.update(product) .then((result) => { console.log('Result: ', JSON.stringify(result, null, 2)) return product @@ -82,10 +82,10 @@ voucherify.product.create(payload) console.log('==== DELETE - SKU ====') - return voucherify.product.sku.delete(product.id, skuId) + return voucherify.products.deleteSku(product.id, skuId) .then(() => { console.log('Checking...') - return voucherify.product.sku.get(product.id, skuId) + return voucherify.products.getSku(product.id, skuId) .catch((err) => { console.log('Result:', err) return product @@ -98,10 +98,10 @@ voucherify.product.create(payload) }) .then((product) => { console.log('==== DELETE ====') - return voucherify.product.delete(product.id) + return voucherify.products.delete(product.id) .then(() => { console.log('Checking...') - return voucherify.product.get(product.id) + return voucherify.products.get(product.id) .catch((err) => { console.log('Result:', err) }) From f9d52286ab702ba107c0e07875f0320a86576851 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 23:07:39 +0100 Subject: [PATCH 107/112] better migration instructions --- README.md | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 283cd1c..3e0ed9f 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@

+Migration from 1.x +| Setup | Callback or Promise? @@ -42,8 +44,6 @@ API: | Products | -Deprecated Methods -| Utils

@@ -204,11 +204,12 @@ Methods are provided within `client.redemptions.*` namespace. #### [Redeem Voucher] ```javascript client.redemptions.redeem(code) -client.redemptions.redeem(code, {object} params) +client.redemptions.redeem(code, params) + // Deprecated! client.redemptions.redeem({code, ...params}) -client.redemptions.redeem({code, ...params}, {string} tracking_id) -client.redemptions.redeem(code, {string} tracking_id) +client.redemptions.redeem({code, ...params}, tracking_id) +client.redemptions.redeem(code, tracking_id) // use: client.redemptions.redeem(code, {customer: {source_id}}) ``` #### [List Redemptions] ```javascript @@ -222,8 +223,8 @@ client.redemptions.getForVoucher(code) #### [Rollback Redemption] ```javascript client.redemptions.rollback(redemptionId) -client.redemptions.rollback(redemptionId, {object} params) -client.redemptions.rollback(redemptionId, {string} reason) +client.redemptions.rollback(redemptionId, params) +client.redemptions.rollback(redemptionId, reason) ``` Check [redemption rollback object](https://docs.voucherify.io/reference#the-redemption-rollback-object).
@@ -311,11 +312,16 @@ client.products.deleteSku(productId, skuId) client.products.listSkus(productId) ```
-### Deprecated methods +### Migration from 1.x + +Version 2.x of the SDK is fully backward compatible with version 1.x. +Changes made in version 2.x mostly relate to grouping methods within namespaces. +So all you need to do is to follow the list bellow and just replace deprecated methods +with their namespaced equivalent. -We strongly encourage you to update your code with new methods. -Each deprecated method has corresponding new namespaced one with the same params, -so migration will go smooth. +We also recommend to adopt [voucher redemption](#redeem-voucher) method, and don't use deprecated invocation. + +#### Deprecated methods - `client.list(params)` - [client.vouchers.list](#list-vouchers) - `client.get(voucherCode)` - [client.vouchers.get](#get-voucher) @@ -338,7 +344,7 @@ so migration will go smooth.
### Utils -``` +```javascript const utils = require('voucherify/utils') ``` @@ -360,7 +366,7 @@ Bug reports and pull requests are welcome through [GitHub Issues](https://github ## Changelog -- **2016-11-15** - `2.0.0` - Rewritten SDK, added missing API methods, updated README. Backward capability is provided but we strongly recommend to migrate [deprecated methods](#deprecated-methods) to new namespaces +- **2016-11-15** - `2.0.0` - Rewritten SDK, added missing API methods, updated README. Backward capability is provided but we strongly recommend to follow the [migration from version 1.x](#migration-from-1.x) - **2016-12-01** - `1.23.2` - Support gift vouchers in utils - **2016-11-15** - `1.23.1` - Validate init options - **2016-10-26** - `1.23.0` - Error handling improved - passing error object in response to rejected request From a515eabcf43c1ce90a8dc95c373d8b71206916a9 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 23:08:52 +0100 Subject: [PATCH 108/112] fix link --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3e0ed9f..a1253e8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@

-Migration from 1.x +Migration from 1.x | Setup | @@ -366,7 +366,7 @@ Bug reports and pull requests are welcome through [GitHub Issues](https://github ## Changelog -- **2016-11-15** - `2.0.0` - Rewritten SDK, added missing API methods, updated README. Backward capability is provided but we strongly recommend to follow the [migration from version 1.x](#migration-from-1.x) +- **2016-11-15** - `2.0.0` - Rewritten SDK, added missing API methods, updated README. Backward capability is provided but we strongly recommend to follow the [migration from version 1.x](#migration-from-1x) - **2016-12-01** - `1.23.2` - Support gift vouchers in utils - **2016-11-15** - `1.23.1` - Validate init options - **2016-10-26** - `1.23.0` - Error handling improved - passing error object in response to rejected request From 4dd48266f29519f1e3e0d37626e6c37415c812d6 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Thu, 1 Dec 2016 23:14:09 +0100 Subject: [PATCH 109/112] update change log date --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1253e8..5d45936 100644 --- a/README.md +++ b/README.md @@ -366,7 +366,7 @@ Bug reports and pull requests are welcome through [GitHub Issues](https://github ## Changelog -- **2016-11-15** - `2.0.0` - Rewritten SDK, added missing API methods, updated README. Backward capability is provided but we strongly recommend to follow the [migration from version 1.x](#migration-from-1x) +- **2016-12-02** - `2.0.0` - Rewritten SDK, added missing API methods, updated README. Backward capability is provided but we strongly recommend to follow the [migration from version 1.x](#migration-from-1x) - **2016-12-01** - `1.23.2` - Support gift vouchers in utils - **2016-11-15** - `1.23.1` - Validate init options - **2016-10-26** - `1.23.0` - Error handling improved - passing error object in response to rejected request From 2519dc31a44ef6576769fe4707a6a4220a727cd3 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 2 Dec 2016 13:56:27 +0100 Subject: [PATCH 110/112] update address and author --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index d9bd9ad..f63c790 100644 --- a/package.json +++ b/package.json @@ -3,16 +3,16 @@ "version": "2.0.0", "homepage": "http://www.voucherify.io", "description": "Node.js SDK for Voucherify.", - "author": "rspective", + "author": "Voucherify", "license": "MIT", "main": "./lib/index.js", "repository": { "type": "git", - "url": "https://github.com/rspective/voucherify-nodejs-sdk.git" + "url": "https://github.com/voucherifyio/voucherify-nodejs-sdk.git" }, "bugs": { - "url": "https://github.com/rspective/voucherify-nodejs-sdk/issues", - "email": "dev@rspective.pl" + "url": "https://github.com/voucherifyio/voucherify-nodejs-sdk/issues", + "email": "support@voucherify.io" }, "keywords": [ "voucherify", From 137b5d6e6d3e5a8aa531da833b3b2d38a5991b2a Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 2 Dec 2016 13:56:37 +0100 Subject: [PATCH 111/112] cosmetic title change --- README.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5d45936..ac56037 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

-

Official Voucherify Node.js SDK

+

Official Voucherify SDK for Node.js

JavaScript Style Guide diff --git a/package.json b/package.json index f63c790..a0c0814 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "voucherify", "version": "2.0.0", "homepage": "http://www.voucherify.io", - "description": "Node.js SDK for Voucherify.", + "description": "Official Voucherify SDK for Node.js", "author": "Voucherify", "license": "MIT", "main": "./lib/index.js", From 91e17da6c6c8c35b7e087f0988be982284214c83 Mon Sep 17 00:00:00 2001 From: Tomasz Sikora Date: Fri, 2 Dec 2016 14:06:31 +0100 Subject: [PATCH 112/112] add tracking query params to our all urls --- README.md | 92 +++++++++++++++++++++++++++---------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index ac56037..a9d97ba 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ API: `npm install voucherify --save` -[Log-in](http://app.voucherify.io/#/login) to Voucherify web interface and obtain your Application Keys from [Configuration](https://app.voucherify.io/#/app/configuration): +[Log-in](http://app.voucherify.io/?utm_source=github&utm_medium=sdk&utm_campaign=acq#/login) to Voucherify web interface and obtain your Application Keys from [Configuration](https://app.voucherify.io/?utm_source=github&utm_medium=sdk&utm_campaign=acq#/app/configuration): ```javascript const voucherifyClient = require('voucherify') @@ -97,7 +97,7 @@ All other examples in the readme use promises but they could be as well written ## API This SDK is fully consistent with restufl API Voucherify provides. -Detalied description and example responses you will find at [official docs](https://docs.voucherify.io/reference). +Detalied description and example responses you will find at [official docs](https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq). Method headers point to more detalied params description you can use. ### Vouchers API @@ -115,7 +115,7 @@ Methods are provided within `client.vouchers.*` namespace. ```javascript client.vouchers.create(voucher) ``` -Check [voucher oject](https://docs.voucherify.io/reference#the-voucher-object). +Check [voucher oject](https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#the-voucher-object). #### [Get Voucher] ```javascript @@ -226,7 +226,7 @@ client.redemptions.rollback(redemptionId) client.redemptions.rollback(redemptionId, params) client.redemptions.rollback(redemptionId, reason) ``` -Check [redemption rollback object](https://docs.voucherify.io/reference#the-redemption-rollback-object). +Check [redemption rollback object](https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#the-redemption-rollback-object).


### Customers API Methods are provided within `client.customers.*` namespace. @@ -240,7 +240,7 @@ Methods are provided within `client.customers.*` namespace. ```javascript client.customers.create(customer) ``` -Check [customer object](https://docs.voucherify.io/reference#the-customer-object). +Check [customer object](https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#the-customer-object). #### [Get Customer] ```javascript client.customers.get(customerId) @@ -272,7 +272,7 @@ Methods are provided within `client.products.*` namespace. ```javascript client.products.create(product) ``` -Check [product object](https://docs.voucherify.io/reference#the-product-object). +Check [product object](https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#the-product-object). #### [Get Product] ```javascript client.products.get(productId) @@ -294,7 +294,7 @@ client.products.list(params) ```javascript client.products.createSku(productId, sku) ``` -Check [SKU object](https://docs.voucherify.io/reference#the-sku-object). +Check [SKU object](https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#the-sku-object). #### [Get SKU] ```javascript client.products.getSku(productId, skuId) @@ -358,7 +358,7 @@ Utils don't need callbacks nor promises. They return results immediately. ## Error handling Depending what you have choose `error` object of rejected Promise or first argument of provided callback has -consistent structure, described in details in our [API reference](https://docs.voucherify.io/reference#errors). +consistent structure, described in details in our [API reference](https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#errors). ## Contributing @@ -433,41 +433,41 @@ Bug reports and pull requests are welcome through [GitHub Issues](https://github - Voucher informations: *get*, *usage* - Voucher operations: *use* -[Create Voucher]: https://docs.voucherify.io/reference#create-voucher -[Get Voucher]: https://docs.voucherify.io/reference#vouchers-get -[Update Voucher]: https://docs.voucherify.io/reference#update-voucher -[Delete Voucher]: https://docs.voucherify.io/reference#delete-voucher -[List Vouchers]: https://docs.voucherify.io/reference#list-vouchers -[Enable Voucher]: https://docs.voucherify.io/reference#enable-voucher -[Disable Voucher]: https://docs.voucherify.io/reference#disable-voucher -[Import Vouchers]: https://docs.voucherify.io/reference#import-vouchers-1 - -[Create Campaign]: https://docs.voucherify.io/reference#create-campaign -[Get Campaign]: https://docs.voucherify.io/reference#get-campaign -[Add Voucher to Campaign]: https://docs.voucherify.io/reference#add-voucher-to-campaign -[Import Vouchers to Campaign]: https://docs.voucherify.io/reference#import-vouchers - -[Publish Voucher]: https://docs.voucherify.io/reference#publish-voucher - -[Validate Voucher]: https://docs.voucherify.io/reference#validate-voucher - -[Redeem Voucher]: https://docs.voucherify.io/reference#redeem-voucher -[List Redemptions]: https://docs.voucherify.io/reference#list-redemptions -[Get Voucher's Redemptions]: https://docs.voucherify.io/reference#vouchers-redemptions -[Rollback Redemption]: https://docs.voucherify.io/reference#rollback-redemption - -[Create Customer]: https://docs.voucherify.io/reference#create-customer -[Get Customer]: https://docs.voucherify.io/reference#read-customer -[Update Customer]: https://docs.voucherify.io/reference#update-customer -[Delete Customer]: https://docs.voucherify.io/reference#delete-customer - -[Create Product]: https://docs.voucherify.io/reference#create-product -[Get Product]: https://docs.voucherify.io/reference#get-product -[Update Product]: https://docs.voucherify.io/reference#update-product -[Delete Product]: https://docs.voucherify.io/reference#delete-product -[List Products]: https://docs.voucherify.io/reference#list-products -[Create SKU]: https://docs.voucherify.io/reference#create-sku -[Get SKU]: https://docs.voucherify.io/reference#get-sku -[Update SKU]: https://docs.voucherify.io/reference#update-sku -[Delete SKU]: https://docs.voucherify.io/reference#delete-sku -[List all product SKUs]: https://docs.voucherify.io/reference#list-skus +[Create Voucher]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#create-voucher +[Get Voucher]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#vouchers-get +[Update Voucher]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#update-voucher +[Delete Voucher]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#delete-voucher +[List Vouchers]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#list-vouchers +[Enable Voucher]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#enable-voucher +[Disable Voucher]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#disable-voucher +[Import Vouchers]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#import-vouchers-1 + +[Create Campaign]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#create-campaign +[Get Campaign]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#get-campaign +[Add Voucher to Campaign]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#add-voucher-to-campaign +[Import Vouchers to Campaign]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#import-vouchers + +[Publish Voucher]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#publish-voucher + +[Validate Voucher]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#validate-voucher + +[Redeem Voucher]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#redeem-voucher +[List Redemptions]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#list-redemptions +[Get Voucher's Redemptions]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#vouchers-redemptions +[Rollback Redemption]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#rollback-redemption + +[Create Customer]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#create-customer +[Get Customer]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#read-customer +[Update Customer]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#update-customer +[Delete Customer]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#delete-customer + +[Create Product]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#create-product +[Get Product]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#get-product +[Update Product]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#update-product +[Delete Product]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#delete-product +[List Products]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#list-products +[Create SKU]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#create-sku +[Get SKU]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#get-sku +[Update SKU]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#update-sku +[Delete SKU]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#delete-sku +[List all product SKUs]: https://docs.voucherify.io/reference?utm_source=github&utm_medium=sdk&utm_campaign=acq#list-skus