Retrieve subscription change timeline
Use the fetchChangeSubscriptionOptions function to control when a subscription change made in the Self-Serve Portal takes effect: either immediately or at the end of the current term. Chargebee invokes this function when a customer changes their subscription and uses the value you return to schedule the change.
This function is one of the two functions supported by Portal Custom Code.
Usage and invocation
Write your business logic to classify each subscription change, and return end_of_term to tell Chargebee when to apply it:
- Set
end_of_termtofalseto apply the change immediately. - Set
end_of_termtotrueto apply the change at the end of the term.
Example
Apply upgrades immediately so the customer gets the added value right away, and defer downgrades to the end of the term so the customer keeps what they paid for until the term ends.
Warning
If multi-decimal support is enabled for your site, read the plan quantity from subscription_changes.plan_quantity_in_decimal and each addon quantity from subscription_changes.addons[].quantity_in_decimal. On these sites, the portal sends the quantity in the *_in_decimal fields, and plan_quantity is null. Custom code that reads plan_quantity receives null and applies the change incorrectly.
These *_in_decimal fields are strings, so wrap them in Number(...) before you compare them.
Requirements
- Write the function in JavaScript.
- Make sure the function runs in a Node.js v6.0 environment.
- Use the resources that Chargebee passes to the function to write your business logic. These resources use the same format as the output of the Node.js client library.
- To retrieve additional resources, use Chargebee's Node.js client library, provided you've already configured it with your API key and secret key.
- Return a JavaScript object that matches the JSON schema on this page.
Parameters
| Parameter | Type | Description |
|---|---|---|
data | Object | The resources that Chargebee passes to your custom code. |
data.subscription | Object | The subscription object. |
data.subscription_changes | Object | The updated plan and addons selected by the customer for the subscription. |
data.subscription_changes.plan_id | String, required | Item price ID of the plan. |
data.subscription_changes.plan_quantity | Integer | Quantity of the plan. When multi-decimal support is enabled for your site, this field is null; read plan_quantity_in_decimal instead. |
data.subscription_changes.plan_quantity_in_decimal | String | Quantity of the plan as a decimal string. Provided when multi-decimal support is enabled for your site. Use this field instead of plan_quantity on multi-decimal sites, and wrap it in Number() before comparing. |
data.subscription_changes.addons | Array<Object> | List of addons. |
data.subscription_changes.addons[].id | String, required | Item price ID of the addon. |
data.subscription_changes.addons[].quantity | Integer | Quantity of the addon. When multi-decimal support is enabled for your site, this field is null; read quantity_in_decimal instead. |
data.subscription_changes.addons[].quantity_in_decimal | String | Quantity of the addon as a decimal string. Provided when multi-decimal support is enabled for your site. Wrap it in Number() before comparing. |
data.customer | Object | The customer object. |
data.item_prices | Array<Object> | The plan and addon item prices currently part of the subscription. |
callback | Function | Function to send the output of the custom code to Chargebee. |
callback.error | Object | Error details to be sent to Chargebee when the custom code has not been successfully executed. |
callback.success | Object | Output of the custom code to be sent to Chargebee when the custom code has been successfully executed. |
logger | Function | Helps log debug information for your custom code. To emit a log entry, call logger.debug('key', 'value') in your custom code. The logs appear in Chargebee Billing on the Custom Codes page at https://YOUR_SUBDOMAIN.chargebee.com/custom_codes, under the Execution section, after you execute the custom code. |
Example
This function treats a change as a downgrade when the customer reduces the quantity of the current plan or moves to a lower-priced plan, and defers those downgrades to the end of the term. All other changes apply immediately.
var chargebee = require("chargebee")
exports.fetchChangeSubscriptionOptions = function ({ subscription, subscription_changes, item_prices }, callback, logger) {
try {
const changeSubPlanItemPrice = item_prices.find(({ item_price }) => item_price.id === subscription_changes.plan_id);
const subPlanItemPrice = subscription.subscription_items.find(subItem => subItem.item_type === 'plan')
const subPlanId = subPlanItemPrice.item_price_id;
let downgrade = false;
// On multi-decimal sites, the quantity is in the *_in_decimal fields; fall back to the integer fields otherwise.
let changedPlanQuantity = Number(subscription_changes.plan_quantity_in_decimal || subscription_changes.plan_quantity);
let currentPlanQuantity = Number(subPlanItemPrice.quantity_in_decimal || subPlanItemPrice.quantity);
let changedPlanUnitPrice = changeSubPlanItemPrice.item_price.price;
// Same plan, quantity reduced.
if (subPlanId == subscription_changes.plan_id && changedPlanQuantity < currentPlanQuantity) {
downgrade = true;
}
// Different plan at a lower price.
if (subPlanId != subscription_changes.plan_id && subPlanItemPrice.unit_price > changedPlanUnitPrice) {
downgrade = true;
}
callback(null, { end_of_term: downgrade })
} catch (err) {
callback(err);
}
}Sample output
{
"end_of_term": true
}Apply upgrades immediately and downgrades at the end of the term
The basic example inspects the plan only. This version also treats a change as a downgrade when the customer reduces an addon quantity or removes an addon. Any of these changes is deferred to the end of the term; otherwise, the change applies immediately. Use this approach when your subscriptions include quantity-based addons.
Custom code
let chargebee = require("chargebee");
exports.fetchChangeSubscriptionOptions = function ({ subscription, subscription_changes, item_prices }, callback, logger) {
try {
// On multi-decimal sites, quantities are in the *_in_decimal fields; fall back to the integer fields otherwise.
const qty = (item) => Number(item.quantity_in_decimal || item.quantity);
// Current plan item on the subscription.
const subPlanItemPrice = subscription.subscription_items.find(subItem => subItem.item_type === 'plan');
// Addons currently on the subscription.
const addonsBefore = subscription.subscription_items.filter(item => item.item_type === 'addon');
// Addons selected in the change.
const addonsAfter = subscription_changes.addons || [];
let downgrade = false;
// Same plan, quantity reduced.
if (Number(subscription_changes.plan_quantity_in_decimal || subscription_changes.plan_quantity) < qty(subPlanItemPrice)) {
downgrade = true;
}
// Any addon removed or reduced in quantity.
for (const before of addonsBefore) {
const after = addonsAfter.find(a => a.id === before.item_price_id);
if (!after || qty(after) < qty(before)) {
downgrade = true;
break;
}
}
callback(null, { end_of_term: downgrade });
} catch (err) {
callback(err);
}
}Sample output
{
"end_of_term": true
}Expected JSON schema for the output
The return value must match the following JSON schema.
JSON schema
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {},
"properties": {
"end_of_term": {
"type": "boolean",
"default": false,
"examples": [
true
]
}
},
"additionalProperties": false
}Was this article helpful?