/api/user/subscriptions/set-subscription-item-quantity (PATCH)
Account information like email addresses is generated with faker-js it is not real user information.
await global.api.user.subscriptions.SetSubscriptionItemQuantity.patch(req)Returns object
{
"subscriptionitemid": "si_LwHKsO0Q0Fmfs4",
"object": "subscriptionitem",
"stripeObject": {
"id": "si_LwHKsO0Q0Fmfs4",
"object": "subscription_item",
"billing_thresholds": null,
"created": 1656124274,
"metadata": {},
"plan": {
"id": "price_1LEOm9HHqepMFuCXPKQ0zvdF",
"object": "plan",
"active": true,
"aggregate_usage": null,
"amount": 1000,
"amount_decimal": "1000",
"billing_scheme": "per_unit",
"created": 1656124269,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {},
"nickname": null,
"product": "prod_LwHKpBBLECvSz7",
"tiers_mode": null,
"transform_usage": null,
"trial_period_days": null,
"usage_type": "licensed"
},
"price": {
"id": "price_1LEOm9HHqepMFuCXPKQ0zvdF",
"object": "price",
"active": true,
"billing_scheme": "per_unit",
"created": 1656124269,
"currency": "usd",
"custom_unit_amount": null,
"livemode": false,
"lookup_key": null,
"metadata": {},
"nickname": null,
"product": "prod_LwHKpBBLECvSz7",
"recurring": {
"aggregate_usage": null,
"interval": "month",
"interval_count": 1,
"trial_period_days": null,
"usage_type": "licensed"
},
"tax_behavior": "inclusive",
"tiers_mode": null,
"transform_quantity": null,
"type": "recurring",
"unit_amount": 1000,
"unit_amount_decimal": "1000"
},
"quantity": 2,
"subscription": "sub_1LEOmDHHqepMFuCX8u8ITAQ9",
"tax_rates": []
},
"accountid": "acct_791e5a6848138589",
"subscriptionid": "sub_1LEOmDHHqepMFuCX8u8ITAQ9",
"customerid": "cus_LwHKjWpVRcFaJr",
"appid": "tests_1656124268",
"createdAt": "2022-06-25T02:31:16.220Z",
"updatedAt": "2022-06-25T02:31:19.965Z"
}
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-account | ineligible accessing account |
invalid-quantity | invalid posted quantity |
invalid posted quantity is unchanged | |
invalid posted quantity is negative | |
invalid posted quantity is zero | |
invalid-subscriptionitemid | missing querystring subscriptionitemid |
invalid querystring subscriptionitemid |
NodeJS source (view on github)
const dashboard = require('@layeredapps/dashboard')
const stripeCache = require('../../../../stripe-cache.js')
const subscriptions = require('../../../../../index.js')
module.exports = {
patch: async (req) => {
if (!req.query || !req.query.subscriptionitemid) {
throw new Error('invalid-subscriptionitemid')
}
const subscriptionItem = await global.api.user.subscriptions.SubscriptionItem.get(req)
if (!subscriptionItem) {
throw new Error('invalid-subscriptionitemid')
}
if (subscriptionItem.accountid !== req.account.accountid) {
throw new Error('invalid-account')
}
if (!req.body || !req.body.quantity) {
throw new Error('invalid-quantity')
}
try {
const quantity = parseInt(req.body.quantity, 10)
if (quantity < 1 || quantity.toString() !== req.body.quantity) {
throw new Error('invalid-quantity')
}
if (subscriptionItem.stripeObject.quantity === quantity) {
throw new Error('invalid-quantity')
}
} catch (error) {
throw new Error('invalid-quantity')
}
const updateInfo = {
items: [{
id: req.query.subscriptionitemid,
quantity: req.body.quantity
}]
}
const subscriptionNow = await stripeCache.execute('subscriptions', 'update', subscriptionItem.subscriptionid, updateInfo, req.stripeKey)
if (!subscriptionNow) {
throw new Error('unknown-error')
}
await subscriptions.Storage.Subscription.update({
stripeObject: subscriptionNow
}, {
where: {
subscriptionid: subscriptionItem.subscriptionid,
appid: req.appid || global.appid
}
})
for (const item of subscriptionNow.items.data) {
if (item.id !== req.query.subscriptionitemid) {
continue
}
await subscriptions.Storage.SubscriptionItem.update({
stripeObject: item
}, {
where: {
subscriptionitemid: subscriptionItem.subscriptionitemid,
appid: req.appid || global.appid
}
})
break
}
await dashboard.StorageCache.remove(subscriptionItem.subscriptionid)
await dashboard.StorageCache.remove(req.query.subscriptionitemid)
return global.api.user.subscriptions.SubscriptionItem.get(req)
}
}
Test source (view on github)
/* eslint-env mocha */
const assert = require('assert')
const TestHelper = require('../../../../../test-helper.js')
const TestStripeAccounts = require('../../../../../test-stripe-accounts.js')
const DashboardTestHelper = require('@layeredapps/dashboard/test-helper.js')
describe('/api/user/subscriptions/set-subscription-item-quantity', function () {
before(TestHelper.disableMetrics)
after(TestHelper.enableMetrics)
let cachedResponses
async function bundledData (retryNumber) {
if (retryNumber > 0) {
cachedResponses = {}
}
if (cachedResponses && cachedResponses.finished) {
return
}
cachedResponses = {}
await TestHelper.setupBefore()
await DashboardTestHelper.setupBeforeEach()
await TestHelper.setupBeforeEach()
const administrator = await TestStripeAccounts.createOwnerWithPrice()
const user = await TestStripeAccounts.createUserWithPaidSubscription(administrator.price)
const user2 = await TestHelper.createUser()
// missing and invalid id
let req = TestHelper.createRequest('/api/user/subscriptions/set-subscription-item-quantity')
req.account = user.account
req.session = user.session
req.body = {
quantity: '10'
}
try {
await req.patch()
} catch (error) {
cachedResponses.missing = error.message
}
req = TestHelper.createRequest('/api/user/subscriptions/set-subscription-item-quantity?subscriptionitemid=invalid')
req.account = user.account
req.session = user.session
req.body = {
quantity: '10'
}
try {
await req.patch()
} catch (error) {
cachedResponses.invalid = error.message
}
// invalid account
req = TestHelper.createRequest(`/api/user/subscriptions/set-subscription-item-quantity?subscriptionitemid=${user.subscription.stripeObject.items.data[0].id}`)
req.account = user2.account
req.session = user2.session
req.body = {
quantity: '1'
}
try {
await req.patch()
} catch (error) {
cachedResponses.account = error.message
}
// invalid quantity
req = TestHelper.createRequest(`/api/user/subscriptions/set-subscription-item-quantity?subscriptionitemid=${user.subscription.stripeObject.items.data[0].id}`)
req.account = user.account
req.session = user.session
req.body = {
quantity: 'letters'
}
try {
await req.patch()
} catch (error) {
cachedResponses.invalidQuantity = error.message
}
req = TestHelper.createRequest(`/api/user/subscriptions/set-subscription-item-quantity?subscriptionitemid=${user.subscription.stripeObject.items.data[0].id}`)
req.account = user.account
req.session = user.session
req.body = {
quantity: '1'
}
try {
await req.patch()
} catch (error) {
cachedResponses.unchangedQuantity = error.message
}
req = TestHelper.createRequest(`/api/user/subscriptions/set-subscription-item-quantity?subscriptionitemid=${user.subscription.stripeObject.items.data[0].id}`)
req.account = user.account
req.session = user.session
req.body = {
quantity: '-1'
}
try {
await req.patch()
} catch (error) {
cachedResponses.negativeQuantity = error.message
}
req = TestHelper.createRequest(`/api/user/subscriptions/set-subscription-item-quantity?subscriptionitemid=${user.subscription.stripeObject.items.data[0].id}`)
req.account = user.account
req.session = user.session
req.body = {
quantity: '0'
}
try {
await req.patch()
} catch (error) {
cachedResponses.zeroQuantity = error.message
}
// returns
req = TestHelper.createRequest(`/api/user/subscriptions/set-subscription-item-quantity?subscriptionitemid=${user.subscription.stripeObject.items.data[0].id}`)
req.account = user.account
req.session = user.session
req.body = {
quantity: '2'
}
req.filename = __filename
req.saveResponse = true
cachedResponses.returns = await req.patch()
cachedResponses.finished = true
}
describe('exceptions', () => {
describe('invalid-subscriptionitemid', () => {
it('missing querystring subscriptionitemid', async function () {
await bundledData(this.test.currentRetry())
const errorMessage = cachedResponses.missing
assert.strictEqual(errorMessage, 'invalid-subscriptionitemid')
})
it('invalid querystring subscriptionitemid', async function () {
await bundledData(this.test.currentRetry())
const errorMessage = cachedResponses.invalid
assert.strictEqual(errorMessage, 'invalid-subscriptionitemid')
})
})
describe('invalid-account', () => {
it('ineligible accessing account', async function () {
await bundledData(this.test.currentRetry())
const errorMessage = cachedResponses.account
assert.strictEqual(errorMessage, 'invalid-account')
})
})
describe('invalid-quantity', () => {
it('invalid posted quantity', async function () {
await bundledData(this.test.currentRetry())
const errorMessage = cachedResponses.invalidQuantity
assert.strictEqual(errorMessage, 'invalid-quantity')
})
it('invalid posted quantity is unchanged', async function () {
await bundledData(this.test.currentRetry())
const errorMessage = cachedResponses.unchangedQuantity
assert.strictEqual(errorMessage, 'invalid-quantity')
})
it('invalid posted quantity is negative', async function () {
await bundledData(this.test.currentRetry())
const errorMessage = cachedResponses.negativeQuantity
assert.strictEqual(errorMessage, 'invalid-quantity')
})
it('invalid posted quantity is zero', async function () {
await bundledData(this.test.currentRetry())
const errorMessage = cachedResponses.zeroQuantity
assert.strictEqual(errorMessage, 'invalid-quantity')
})
})
})
describe('returns', () => {
it('object', async () => {
const subscriptionItemNow = cachedResponses.returns
assert.strictEqual(subscriptionItemNow.stripeObject.quantity, 2)
})
})
})