|
|
@@ -31,7 +31,10 @@ const RecurlyClient = require('./RecurlyClient')
|
|
|
const { AI_ADD_ON_CODE } = require('./RecurlyEntities')
|
|
|
|
|
|
/**
|
|
|
+ * @import { SubscriptionChangeDescription } from '../../../../types/subscription/subscription-change-preview'
|
|
|
* @import { SubscriptionChangePreview } from '../../../../types/subscription/subscription-change-preview'
|
|
|
+ * @import { RecurlySubscriptionChange } from './RecurlyEntities'
|
|
|
+ * @import { PaymentMethod } from './types'
|
|
|
*/
|
|
|
|
|
|
const groupPlanModalOptions = Settings.groupPlanModalOptions
|
|
|
@@ -516,38 +519,17 @@ async function previewAddonPurchase(req, res) {
|
|
|
)
|
|
|
|
|
|
/** @type {SubscriptionChangePreview} */
|
|
|
- const changePreview = {
|
|
|
- change: {
|
|
|
+ const changePreview = makeChangePreview(
|
|
|
+ {
|
|
|
type: 'add-on-purchase',
|
|
|
addOn: {
|
|
|
code: addOn.code,
|
|
|
name: addOn.name,
|
|
|
},
|
|
|
},
|
|
|
- currency: subscription.currency,
|
|
|
- immediateCharge: subscriptionChange.immediateCharge,
|
|
|
- paymentMethod: paymentMethod.toString(),
|
|
|
- nextInvoice: {
|
|
|
- date: subscription.periodEnd.toISOString(),
|
|
|
- plan: {
|
|
|
- name: subscriptionChange.nextPlanName,
|
|
|
- amount: subscriptionChange.nextPlanPrice,
|
|
|
- },
|
|
|
- addOns: subscriptionChange.nextAddOns.map(addOn => ({
|
|
|
- code: addOn.code,
|
|
|
- name: addOn.name,
|
|
|
- quantity: addOn.quantity,
|
|
|
- unitAmount: addOn.unitPrice,
|
|
|
- amount: addOn.preTaxTotal,
|
|
|
- })),
|
|
|
- subtotal: subscriptionChange.subtotal,
|
|
|
- tax: {
|
|
|
- rate: subscription.taxRate,
|
|
|
- amount: subscriptionChange.tax,
|
|
|
- },
|
|
|
- total: subscriptionChange.total,
|
|
|
- },
|
|
|
- }
|
|
|
+ subscriptionChange,
|
|
|
+ paymentMethod
|
|
|
+ )
|
|
|
|
|
|
res.render('subscriptions/preview-change', { changePreview })
|
|
|
}
|
|
|
@@ -619,6 +601,31 @@ async function removeAddon(req, res, next) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+async function previewSubscription(req, res, next) {
|
|
|
+ const planCode = req.query.planCode
|
|
|
+ if (!planCode) {
|
|
|
+ return HttpErrorHandler.notFound(req, res, 'Missing plan code')
|
|
|
+ }
|
|
|
+ const plan = await RecurlyClient.promises.getPlan(planCode)
|
|
|
+ const userId = SessionManager.getLoggedInUserId(req.session)
|
|
|
+ const subscriptionChange =
|
|
|
+ await SubscriptionHandler.promises.previewSubscriptionChange(
|
|
|
+ userId,
|
|
|
+ planCode
|
|
|
+ )
|
|
|
+ const paymentMethod = await RecurlyClient.promises.getPaymentMethod(userId)
|
|
|
+ const changePreview = makeChangePreview(
|
|
|
+ {
|
|
|
+ type: 'premium-subscription',
|
|
|
+ plan: { code: plan.code, name: plan.name },
|
|
|
+ },
|
|
|
+ subscriptionChange,
|
|
|
+ paymentMethod
|
|
|
+ )
|
|
|
+
|
|
|
+ res.render('subscriptions/preview-change', { changePreview })
|
|
|
+}
|
|
|
+
|
|
|
function updateSubscription(req, res, next) {
|
|
|
const origin = req && req.query ? req.query.origin : null
|
|
|
const user = SessionManager.getSessionUser(req.session)
|
|
|
@@ -887,6 +894,48 @@ async function getLatamCountryBannerDetails(req, res) {
|
|
|
return latamCountryBannerDetails
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Build a subscription change preview for display purposes
|
|
|
+ *
|
|
|
+ * @param {SubscriptionChangeDescription} subscriptionChangeDescription A description of the change for the frontend
|
|
|
+ * @param {RecurlySubscriptionChange} subscriptionChange The subscription change object coming from Recurly
|
|
|
+ * @param {PaymentMethod} paymentMethod The payment method associated to the user
|
|
|
+ * @return {SubscriptionChangePreview}
|
|
|
+ */
|
|
|
+function makeChangePreview(
|
|
|
+ subscriptionChangeDescription,
|
|
|
+ subscriptionChange,
|
|
|
+ paymentMethod
|
|
|
+) {
|
|
|
+ const subscription = subscriptionChange.subscription
|
|
|
+ return {
|
|
|
+ change: subscriptionChangeDescription,
|
|
|
+ currency: subscription.currency,
|
|
|
+ immediateCharge: subscriptionChange.immediateCharge,
|
|
|
+ paymentMethod: paymentMethod.toString(),
|
|
|
+ nextInvoice: {
|
|
|
+ date: subscription.periodEnd.toISOString(),
|
|
|
+ plan: {
|
|
|
+ name: subscriptionChange.nextPlanName,
|
|
|
+ amount: subscriptionChange.nextPlanPrice,
|
|
|
+ },
|
|
|
+ addOns: subscriptionChange.nextAddOns.map(addOn => ({
|
|
|
+ code: addOn.code,
|
|
|
+ name: addOn.name,
|
|
|
+ quantity: addOn.quantity,
|
|
|
+ unitAmount: addOn.unitPrice,
|
|
|
+ amount: addOn.preTaxTotal,
|
|
|
+ })),
|
|
|
+ subtotal: subscriptionChange.subtotal,
|
|
|
+ tax: {
|
|
|
+ rate: subscription.taxRate,
|
|
|
+ amount: subscriptionChange.tax,
|
|
|
+ },
|
|
|
+ total: subscriptionChange.total,
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
module.exports = {
|
|
|
plansPage: expressify(plansPage),
|
|
|
plansPageLightDesign: expressify(plansPageLightDesign),
|
|
|
@@ -896,6 +945,7 @@ module.exports = {
|
|
|
cancelSubscription,
|
|
|
canceledSubscription: expressify(canceledSubscription),
|
|
|
cancelV1Subscription,
|
|
|
+ previewSubscription: expressify(previewSubscription),
|
|
|
updateSubscription,
|
|
|
cancelPendingSubscriptionChange,
|
|
|
updateAccountEmailAddress,
|