/api/administrator/subscriptions/create-coupon (POST)
await global.api.administrator.subscriptions.CreateCoupon.post(req) Located in Stripe Subscriptions module API
Returns object
Exceptions
These exceptions are thrown (NodeJS) or returned as JSON (HTTP) if you provide incorrect data or do not meet the requirements:
Exception | Circumstances |
---|---|
invalid posted couponid is not alphanumeric_ | |
invalid-couponid | missing posted couponid |
invalid posted amount_off | |
invalid-amount_off | missing posted amount_off |
invalid posted currency | |
invalid-currency | missing posted currency |
invalid-percent_off | invalid posted percent_off |
invalid-duration | invalid posted duration |
invalid posted duration_in_months | |
invalid-duration_in_months | missing posted duration_in_months |
invalid-redeem_by_meridiem | invalid posted redeem_by_meridiem |
invalid-redeem_by | invalid posted redeem_by |
Receives
API routes may receive parameters from the URL and POST supporting simple and multipart:
Field | Value | Required | Type |
---|---|---|---|
amount_off | integer, or percent_off | configurable as required | POST |
currency | string, if amount_off | configurable as required | POST |
duration | string | required | POST |
duration_in_months | string | configurable as required | POST |
expire date | string | configurable as required | POST |
percent_off | integer, or amount_off | configurable as required | POST |
NodeJS source (edit on github)
If you see a problem with the source submit a pull request on Github.
const dashboard = require('@userdashboard/dashboard')
const subscriptions = require('../../../../../index.js')
const stripeCache = require('../../../../stripe-cache.js')
module.exports = {
post: async (req) => {
if (!req.body || !req.body.couponid) {
throw new Error('invalid-couponid')
}
if (!req.body.couponid.match(/^[a-zA-Z0-9_]+$/) ||
global.minimumCouponLength > req.body.couponid.length ||
global.maximumCouponLength < req.body.couponid.length) {
throw new Error('invalid-couponid')
}
if (req.body.amount_off) {
try {
req.body.amount_off = parseInt(req.body.amount_off, 10)
if (!req.body.amount_off) {
throw new Error('invalid-amount_off')
}
} catch (s) {
throw new Error('invalid-amount_off')
}
if (req.body.amount_off < 0) {
throw new Error('invalid-amount_off')
}
if (!req.body.currency || req.body.currency.length !== 3) {
throw new Error('invalid-currency')
}
} else if (req.body.percent_off) {
try {
req.body.percent_off = parseInt(req.body.percent_off, 10)
if (!req.body.percent_off) {
throw new Error('invalid-percent_off')
}
} catch (s) {
throw new Error('invalid-percent_off')
}
if (req.body.percent_off < 0 || req.body.percent_off > 100) {
throw new Error('invalid-percent_off')
}
}
if (!req.body.amount_off && !req.body.percent_off) {
throw new Error('invalid-amount_off')
}
if (req.body.duration !== 'once' && req.body.duration !== 'repeating' && req.body.duration !== 'forever') {
throw new Error('invalid-duration')
}
if (req.body.duration === 'repeating') {
if (req.body.duration_in_months) {
try {
req.body.duration_in_months = parseInt(req.body.duration_in_months, 10)
if (!req.body.duration_in_months) {
throw new Error('invalid-duration_in_months')
}
} catch (s) {
throw new Error('invalid-duration_in_months')
}
if (req.body.duration_in_months < 1 || req.body.duration_in_months > 24) {
throw new Error('invalid-duration_in_months')
}
} else {
throw new Error('invalid-duration_in_months')
}
}
if (req.body.max_redemptions) {
try {
req.body.max_redemptions = parseInt(req.body.max_redemptions, 10)
if (!req.body.max_redemptions) {
throw new Error('invalid-max_redemptions')
}
} catch (s) {
throw new Error('invalid-max_redemptions')
}
if (req.body.max_redemptions < 0) {
throw new Error('invalid-max_redemptions')
}
}
let expires
if (
(req.body.redeem_by_day && req.body.redeem_by_day !== '0') ||
(req.body.redeem_by_month && req.body.redeem_by_month !== '0') ||
(req.body.redeem_by_year && req.body.redeem_by_year !== '0') ||
(req.body.redeem_by_hour && req.body.redeem_by_hour !== 'HH') ||
(req.body.redeem_by_minute && req.body.redeem_by_minute !== 'MM')) {
if (req.body.redeem_by_meridiem !== 'AM' && req.body.redeem_by_meridiem !== 'PM') {
throw new Error('invalid-redeem_by_meridiem')
}
try {
expires = new Date(
new Date().getFullYear().toString().substring(0, 2) + req.body.redeem_by_year,
req.body.redeem_by_month - 1,
req.body.redeem_by_day,
req.body.redeem_by_meridiem === 'PM' ? req.body.redeem_by_hour + 12 : req.body.redeem_by_hour,
req.body.redeem_by_minute,
0)
const expiresTimestamp = dashboard.Timestamp.create(expires)
if (expiresTimestamp - dashboard.Timestamp.now > 5 * 365 * 24 * 60 * 60) {
throw new Error('invalid-redeem_by')
}
} catch (s) {
throw new Error('invalid-redeem_by')
}
if (!expires) {
throw new Error('invalid-redeem_by')
}
req.body.redeem_by = dashboard.Timestamp.create(expires)
if (req.body.redeem_by < dashboard.Timestamp.now) {
throw new Error('invalid-redeem_by')
}
}
const couponInfo = {
id: req.body.couponid,
duration: req.body.duration || null,
redeem_by: req.body.redeem_by,
metadata: {
appid: req.appid
}
}
if (req.body.amount_off) {
couponInfo.amount_off = req.body.amount_off
couponInfo.currency = req.body.currency
} else {
couponInfo.percent_off = req.body.percent_off
}
if (req.body.duration_in_months) {
couponInfo.duration_in_months = req.body.duration_in_months
}
if (req.body.max_redemptions) {
couponInfo.max_redemptions = req.body.max_redemptions
}
if (req.body.published) {
couponInfo.metadata.published = dashboard.Timestamp.now
}
const coupon = await stripeCache.execute('coupons', 'create', couponInfo, req.stripeKey)
const indexing = {
[`${req.appid}/coupons`]: coupon.id
}
if (coupon.metadata.published) {
indexing[`${req.appid}/published/coupons`] = coupon.id
}
await subscriptions.StorageList.addMany(indexing)
return coupon
}
}
Test source (edit on github)
Tests perform real HTTP requests against a running Dashboard server.
/* eslint-env mocha */
const assert = require('assert')
const TestHelper = require('../../../../../test-helper.js')
describe('/api/administrator/subscriptions/create-coupon', () => {
describe('exceptions', () => {
describe('invalid-couponid', () => {
it('missing posted couponid', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: '',
amount_off: '',
percent_off: ''
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-couponid')
})
it('invalid posted couponid is not alphanumeric_', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: '#$%@#$%@#$%',
amount_off: '',
percent_off: ''
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-couponid')
})
})
describe('invalid-amount_off', () => {
it('missing posted amount_off', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
amount_off: '',
percent_off: ''
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-amount_off')
})
it('invalid posted amount_off', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
amount_off: 'invalid',
percent_off: ''
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-amount_off')
})
})
describe('invalid-currency', () => {
it('missing posted currency', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
amount_off: '1',
currency: ''
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-currency')
})
it('invalid posted currency', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
amount_off: '1',
currency: 'invalid'
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-currency')
})
})
describe('invalid-percent_off', () => {
it('invalid posted percent_off', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
percent_off: 'invalid'
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-percent_off')
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
percent_off: '101'
}
errorMessage = null
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-percent_off')
})
})
describe('invalid-duration', () => {
it('invalid posted duration', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
amount_off: '10',
currency: 'usd',
duration: 'invalid'
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-duration')
})
})
describe('invalid-duration_in_months', () => {
it('missing posted duration_in_months', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
amount_off: '10',
currency: 'usd',
duration: 'repeating',
duration_in_months: ''
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-duration_in_months')
})
it('invalid posted duration_in_months', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
amount_off: '10',
currency: 'usd',
duration: 'repeating',
duration_in_months: 'invalid'
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-duration_in_months')
})
})
describe('invalid-redeem_by_meridiem', () => {
it('invalid posted redeem_by_meridiem', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
amount_off: '10',
currency: 'usd',
duration: 'repeating',
duration_in_months: '1',
redeem_by_minute: '1',
redeem_by_hour: '1',
redeem_by_day: '1',
redeem_by_month: '1',
redeem_by_year: '1750',
redeem_by_meridiem: ''
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-redeem_by_meridiem')
})
})
describe('invalid-redeem_by', () => {
it('invalid posted redeem_by', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
amount_off: '10',
currency: 'usd',
duration: 'repeating',
duration_in_months: '1',
redeem_by_minute: '1',
redeem_by_hour: '1',
redeem_by_day: '1',
redeem_by_month: '1',
redeem_by_year: '1750',
redeem_by_meridiem: 'AM'
}
let errorMessage
try {
await req.post()
} catch (error) {
errorMessage = error.message
}
assert.strictEqual(errorMessage, 'invalid-redeem_by')
})
})
})
describe('receives', () => {
it('required posted duration', async () => {
})
it('optionally-required posted amount_off (integer, or percent_off)', async () => {
})
it('optionally-required posted currency (string, if amount_off)', async () => {
})
it('optionally-required posted percent_off (integer, or amount_off)', async () => {
})
it('optionally-required posted expire date ', async () => {
})
it('optionally-required posted duration_in_months', async () => {
})
})
describe('returns', () => {
it('object', async () => {
const administrator = await TestHelper.createOwner()
const req = TestHelper.createRequest('/api/administrator/subscriptions/create-coupon')
req.account = administrator.account
req.session = administrator.session
req.body = {
couponid: 'coupon' + new Date().getTime() + 'r' + Math.ceil(Math.random() * 1000),
amount_off: '10',
currency: 'usd',
duration: 'repeating',
duration_in_months: '1',
redeem_by_minute: '1',
redeem_by_hour: '1',
redeem_by_day: '1',
redeem_by_month: '1',
redeem_by_year: (new Date().getFullYear() + 1).toString().substring(2),
redeem_by_meridiem: 'AM'
}
req.filename = __filename
req.saveResponse = true
const coupon = await req.post()
assert.strictEqual(coupon.object, 'coupon')
})
})
})