mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-30 20:31:34 +02:00
Merge pull request #24680 from overleaf/kh-rename-recurly-namespace
[web] rename recurly namespace GitOrigin-RevId: b7cfd26923d47bd7f3de4140be24d2d1ef20f6c8
This commit is contained in:
@@ -49,7 +49,7 @@ const Modules = require('../../infrastructure/Modules')
|
||||
const UserGetter = require('../User/UserGetter')
|
||||
const {
|
||||
isStandaloneAiAddOnPlanCode,
|
||||
} = require('../Subscription/RecurlyEntities')
|
||||
} = require('../Subscription/PaymentProviderEntities')
|
||||
const SubscriptionController = require('../Subscription/SubscriptionController.js')
|
||||
const { formatCurrency } = require('../../util/currency')
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ const UserGetter = require('../User/UserGetter')
|
||||
const AnalyticsManager = require('../Analytics/AnalyticsManager')
|
||||
const Queues = require('../../infrastructure/Queues')
|
||||
const Modules = require('../../infrastructure/Modules')
|
||||
const { AI_ADD_ON_CODE } = require('./RecurlyEntities')
|
||||
const { AI_ADD_ON_CODE } = require('./PaymentProviderEntities')
|
||||
|
||||
/**
|
||||
* Enqueue a job for refreshing features for the given user
|
||||
|
||||
@@ -9,7 +9,7 @@ const AI_ADD_ON_CODE = 'assistant'
|
||||
const MEMBERS_LIMIT_ADD_ON_CODE = 'additional-license'
|
||||
const STANDALONE_AI_ADD_ON_CODES = ['assistant', 'assistant-annual']
|
||||
|
||||
class RecurlySubscription {
|
||||
class PaymentProviderSubscription {
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {string} props.id
|
||||
@@ -17,7 +17,7 @@ class RecurlySubscription {
|
||||
* @param {string} props.planCode
|
||||
* @param {string} props.planName
|
||||
* @param {number} props.planPrice
|
||||
* @param {RecurlySubscriptionAddOn[]} [props.addOns]
|
||||
* @param {PaymentProviderSubscriptionAddOn[]} [props.addOns]
|
||||
* @param {number} props.subtotal
|
||||
* @param {number} [props.taxRate]
|
||||
* @param {number} [props.taxAmount]
|
||||
@@ -26,7 +26,7 @@ class RecurlySubscription {
|
||||
* @param {Date} props.periodStart
|
||||
* @param {Date} props.periodEnd
|
||||
* @param {string} props.collectionMethod
|
||||
* @param {RecurlySubscriptionChange} [props.pendingChange]
|
||||
* @param {PaymentProviderSubscriptionChange} [props.pendingChange]
|
||||
* @param {string} [props.service]
|
||||
* @param {string} [props.state]
|
||||
* @param {Date|null} [props.trialPeriodEnd]
|
||||
@@ -97,7 +97,7 @@ class RecurlySubscription {
|
||||
/**
|
||||
* Change this subscription's plan
|
||||
*
|
||||
* @return {RecurlySubscriptionChangeRequest}
|
||||
* @return {PaymentProviderSubscriptionChangeRequest}
|
||||
*/
|
||||
getRequestForPlanChange(planCode) {
|
||||
const currentPlan = PlansLocator.findLocalPlanInSettings(this.planCode)
|
||||
@@ -115,7 +115,7 @@ class RecurlySubscription {
|
||||
newPlan
|
||||
)
|
||||
|
||||
const changeRequest = new RecurlySubscriptionChangeRequest({
|
||||
const changeRequest = new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this,
|
||||
timeframe: shouldChangeAtTermEnd ? 'term_end' : 'now',
|
||||
planCode,
|
||||
@@ -127,7 +127,7 @@ class RecurlySubscription {
|
||||
(!shouldChangeAtTermEnd && this.hasAddOn(AI_ADD_ON_CODE)) ||
|
||||
(shouldChangeAtTermEnd && this.hasAddOnNextPeriod(AI_ADD_ON_CODE))
|
||||
) {
|
||||
const addOnUpdate = new RecurlySubscriptionAddOnUpdate({
|
||||
const addOnUpdate = new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: AI_ADD_ON_CODE,
|
||||
quantity: 1,
|
||||
})
|
||||
@@ -143,7 +143,7 @@ class RecurlySubscription {
|
||||
* @param {string} code
|
||||
* @param {number} [quantity]
|
||||
* @param {number} [unitPrice]
|
||||
* @return {RecurlySubscriptionChangeRequest} - the change request to send to
|
||||
* @return {PaymentProviderSubscriptionChangeRequest} - the change request to send to
|
||||
* Recurly
|
||||
*
|
||||
* @throws {DuplicateAddOnError} if the add-on is already present on the subscription
|
||||
@@ -158,9 +158,9 @@ class RecurlySubscription {
|
||||
|
||||
const addOnUpdates = this.addOns.map(addOn => addOn.toAddOnUpdate())
|
||||
addOnUpdates.push(
|
||||
new RecurlySubscriptionAddOnUpdate({ code, quantity, unitPrice })
|
||||
new PaymentProviderSubscriptionAddOnUpdate({ code, quantity, unitPrice })
|
||||
)
|
||||
return new RecurlySubscriptionChangeRequest({
|
||||
return new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this,
|
||||
timeframe: 'now',
|
||||
addOnUpdates,
|
||||
@@ -172,7 +172,7 @@ class RecurlySubscription {
|
||||
*
|
||||
* @param {string} code
|
||||
* @param {number} quantity
|
||||
* @return {RecurlySubscriptionChangeRequest} - the change request to send to
|
||||
* @return {PaymentProviderSubscriptionChangeRequest} - the change request to send to
|
||||
* Recurly
|
||||
*
|
||||
* @throws {AddOnNotPresentError} if the subscription doesn't have the add-on
|
||||
@@ -198,7 +198,7 @@ class RecurlySubscription {
|
||||
return update
|
||||
})
|
||||
|
||||
return new RecurlySubscriptionChangeRequest({
|
||||
return new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this,
|
||||
timeframe: 'now',
|
||||
addOnUpdates,
|
||||
@@ -209,7 +209,7 @@ class RecurlySubscription {
|
||||
* Remove an add-on from this subscription
|
||||
*
|
||||
* @param {string} code
|
||||
* @return {RecurlySubscriptionChangeRequest}
|
||||
* @return {PaymentProviderSubscriptionChangeRequest}
|
||||
*
|
||||
* @throws {AddOnNotPresentError} if the subscription doesn't have the add-on
|
||||
*/
|
||||
@@ -226,7 +226,7 @@ class RecurlySubscription {
|
||||
const addOnUpdates = this.addOns
|
||||
.filter(addOn => addOn.code !== code)
|
||||
.map(addOn => addOn.toAddOnUpdate())
|
||||
return new RecurlySubscriptionChangeRequest({
|
||||
return new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this,
|
||||
timeframe: 'term_end',
|
||||
addOnUpdates,
|
||||
@@ -237,19 +237,19 @@ class RecurlySubscription {
|
||||
* Upgrade group plan with the plan code provided
|
||||
*
|
||||
* @param {string} newPlanCode
|
||||
* @return {RecurlySubscriptionChangeRequest}
|
||||
* @return {PaymentProviderSubscriptionChangeRequest}
|
||||
*/
|
||||
getRequestForGroupPlanUpgrade(newPlanCode) {
|
||||
// Ensure all the existing add-ons are added to the new plan
|
||||
const addOns = this.addOns.map(
|
||||
addOn =>
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: addOn.code,
|
||||
quantity: addOn.quantity,
|
||||
})
|
||||
)
|
||||
|
||||
return new RecurlySubscriptionChangeRequest({
|
||||
return new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this,
|
||||
timeframe: 'now',
|
||||
addOnUpdates: addOns,
|
||||
@@ -270,7 +270,7 @@ class RecurlySubscription {
|
||||
/**
|
||||
* An add-on attached to a subscription
|
||||
*/
|
||||
class RecurlySubscriptionAddOn {
|
||||
class PaymentProviderSubscriptionAddOn {
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {string} props.code
|
||||
@@ -290,7 +290,7 @@ class RecurlySubscriptionAddOn {
|
||||
* Return an add-on update that doesn't modify the add-on
|
||||
*/
|
||||
toAddOnUpdate() {
|
||||
return new RecurlySubscriptionAddOnUpdate({
|
||||
return new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: this.code,
|
||||
quantity: this.quantity,
|
||||
unitPrice: this.unitPrice,
|
||||
@@ -298,17 +298,19 @@ class RecurlySubscriptionAddOn {
|
||||
}
|
||||
}
|
||||
|
||||
class RecurlySubscriptionChangeRequest {
|
||||
class PaymentProviderSubscriptionChangeRequest {
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {RecurlySubscription} props.subscription
|
||||
* @param {PaymentProviderSubscription} props.subscription
|
||||
* @param {"now" | "term_end"} props.timeframe
|
||||
* @param {string} [props.planCode]
|
||||
* @param {RecurlySubscriptionAddOnUpdate[]} [props.addOnUpdates]
|
||||
* @param {PaymentProviderSubscriptionAddOnUpdate[]} [props.addOnUpdates]
|
||||
*/
|
||||
constructor(props) {
|
||||
if (props.planCode == null && props.addOnUpdates == null) {
|
||||
throw new OError('Invalid RecurlySubscriptionChangeRequest', { props })
|
||||
throw new OError('Invalid PaymentProviderSubscriptionChangeRequest', {
|
||||
props,
|
||||
})
|
||||
}
|
||||
this.subscription = props.subscription
|
||||
this.timeframe = props.timeframe
|
||||
@@ -317,7 +319,7 @@ class RecurlySubscriptionChangeRequest {
|
||||
}
|
||||
}
|
||||
|
||||
class RecurlySubscriptionAddOnUpdate {
|
||||
class PaymentProviderSubscriptionAddOnUpdate {
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {string} props.code
|
||||
@@ -331,15 +333,15 @@ class RecurlySubscriptionAddOnUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
class RecurlySubscriptionChange {
|
||||
class PaymentProviderSubscriptionChange {
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {RecurlySubscription} props.subscription
|
||||
* @param {PaymentProviderSubscription} props.subscription
|
||||
* @param {string} props.nextPlanCode
|
||||
* @param {string} props.nextPlanName
|
||||
* @param {number} props.nextPlanPrice
|
||||
* @param {RecurlySubscriptionAddOn[]} props.nextAddOns
|
||||
* @param {RecurlyImmediateCharge} [props.immediateCharge]
|
||||
* @param {PaymentProviderSubscriptionAddOn[]} props.nextAddOns
|
||||
* @param {PaymentProviderImmediateCharge} [props.immediateCharge]
|
||||
*/
|
||||
constructor(props) {
|
||||
this.subscription = props.subscription
|
||||
@@ -349,7 +351,12 @@ class RecurlySubscriptionChange {
|
||||
this.nextAddOns = props.nextAddOns
|
||||
this.immediateCharge =
|
||||
props.immediateCharge ??
|
||||
new RecurlyImmediateCharge({ subtotal: 0, tax: 0, total: 0, discount: 0 })
|
||||
new PaymentProviderImmediateCharge({
|
||||
subtotal: 0,
|
||||
tax: 0,
|
||||
total: 0,
|
||||
discount: 0,
|
||||
})
|
||||
|
||||
this.subtotal = this.nextPlanPrice
|
||||
for (const addOn of this.nextAddOns) {
|
||||
@@ -388,7 +395,7 @@ class CreditCardPaymentMethod {
|
||||
}
|
||||
}
|
||||
|
||||
class RecurlyImmediateCharge {
|
||||
class PaymentProviderImmediateCharge {
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {number} props.subtotal
|
||||
@@ -407,7 +414,7 @@ class RecurlyImmediateCharge {
|
||||
/**
|
||||
* An add-on configuration, independent of any subscription
|
||||
*/
|
||||
class RecurlyAddOn {
|
||||
class PaymentProviderAddOn {
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {string} props.code
|
||||
@@ -422,7 +429,7 @@ class RecurlyAddOn {
|
||||
/**
|
||||
* A plan configuration
|
||||
*/
|
||||
class RecurlyPlan {
|
||||
class PaymentProviderPlan {
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {string} props.code
|
||||
@@ -437,7 +444,7 @@ class RecurlyPlan {
|
||||
/**
|
||||
* A coupon in the payment provider
|
||||
*/
|
||||
class RecurlyCoupon {
|
||||
class PaymentProviderCoupon {
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {string} props.code
|
||||
@@ -454,7 +461,7 @@ class RecurlyCoupon {
|
||||
/**
|
||||
* An account in the payment provider
|
||||
*/
|
||||
class RecurlyAccount {
|
||||
class PaymentProviderAccount {
|
||||
/**
|
||||
* @param {object} props
|
||||
* @param {string} props.code
|
||||
@@ -480,7 +487,7 @@ function isStandaloneAiAddOnPlanCode(planCode) {
|
||||
/**
|
||||
* Returns whether subscription change will have have the ai bundle once the change is processed
|
||||
*
|
||||
* @param {RecurlySubscriptionChange} subscriptionChange The subscription change object coming from Recurly
|
||||
* @param {PaymentProviderSubscriptionChange} subscriptionChange The subscription change object coming from payment provider
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
@@ -497,18 +504,18 @@ module.exports = {
|
||||
AI_ADD_ON_CODE,
|
||||
MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
STANDALONE_AI_ADD_ON_CODES,
|
||||
RecurlySubscription,
|
||||
RecurlySubscriptionAddOn,
|
||||
RecurlySubscriptionChange,
|
||||
RecurlySubscriptionChangeRequest,
|
||||
RecurlySubscriptionAddOnUpdate,
|
||||
PaymentProviderSubscription,
|
||||
PaymentProviderSubscriptionAddOn,
|
||||
PaymentProviderSubscriptionChange,
|
||||
PaymentProviderSubscriptionChangeRequest,
|
||||
PaymentProviderSubscriptionAddOnUpdate,
|
||||
PaypalPaymentMethod,
|
||||
CreditCardPaymentMethod,
|
||||
RecurlyAddOn,
|
||||
RecurlyPlan,
|
||||
RecurlyCoupon,
|
||||
RecurlyAccount,
|
||||
PaymentProviderAddOn,
|
||||
PaymentProviderPlan,
|
||||
PaymentProviderCoupon,
|
||||
PaymentProviderAccount,
|
||||
isStandaloneAiAddOnPlanCode,
|
||||
subscriptionChangeIsAiAssistUpgrade,
|
||||
RecurlyImmediateCharge,
|
||||
PaymentProviderImmediateCharge,
|
||||
}
|
||||
@@ -5,7 +5,7 @@ const logger = require('@overleaf/logger')
|
||||
const { callbackify } = require('util')
|
||||
|
||||
/**
|
||||
* @import { RecurlySubscription, RecurlyAccount, RecurlyCoupon } from "./RecurlyEntities"
|
||||
* @import { PaymentProviderSubscription, PaymentProviderAccount, PaymentProviderCoupon } from "./PaymentProviderEntities.js"
|
||||
* @import { ObjectId } from 'mongodb'
|
||||
*/
|
||||
|
||||
@@ -19,9 +19,9 @@ const { callbackify } = require('util')
|
||||
|
||||
/**
|
||||
* @typedef {object} PaymentRecord
|
||||
* @property {RecurlySubscription} subscription
|
||||
* @property {RecurlyAccount | null} account
|
||||
* @property {RecurlyCoupon[]} coupons
|
||||
* @property {PaymentProviderSubscription} subscription
|
||||
* @property {PaymentProviderAccount | null} account
|
||||
* @property {PaymentProviderCoupon[]} coupons
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,24 +7,24 @@ const OError = require('@overleaf/o-error')
|
||||
const { callbackify } = require('util')
|
||||
const UserGetter = require('../User/UserGetter')
|
||||
const {
|
||||
RecurlySubscription,
|
||||
RecurlySubscriptionAddOn,
|
||||
RecurlySubscriptionChange,
|
||||
PaymentProviderSubscription,
|
||||
PaymentProviderSubscriptionAddOn,
|
||||
PaymentProviderSubscriptionChange,
|
||||
PaypalPaymentMethod,
|
||||
CreditCardPaymentMethod,
|
||||
RecurlyAddOn,
|
||||
RecurlyPlan,
|
||||
RecurlyCoupon,
|
||||
RecurlyAccount,
|
||||
RecurlyImmediateCharge,
|
||||
} = require('./RecurlyEntities')
|
||||
PaymentProviderAddOn,
|
||||
PaymentProviderPlan,
|
||||
PaymentProviderCoupon,
|
||||
PaymentProviderAccount,
|
||||
PaymentProviderImmediateCharge,
|
||||
} = require('./PaymentProviderEntities')
|
||||
const {
|
||||
MissingBillingInfoError,
|
||||
SubtotalLimitExceededError,
|
||||
} = require('./Errors')
|
||||
|
||||
/**
|
||||
* @import { RecurlySubscriptionChangeRequest } from './RecurlyEntities'
|
||||
* @import { PaymentProviderSubscriptionChangeRequest } from './PaymentProviderEntities'
|
||||
* @import { PaymentMethod } from './types'
|
||||
*/
|
||||
|
||||
@@ -37,7 +37,7 @@ const client = new recurly.Client(recurlyApiKey)
|
||||
* Get account for a given user
|
||||
*
|
||||
* @param {string} userId
|
||||
* @return {Promise<RecurlyAccount | null>}
|
||||
* @return {Promise<PaymentProviderAccount | null>}
|
||||
*/
|
||||
async function getAccountForUserId(userId) {
|
||||
try {
|
||||
@@ -76,7 +76,7 @@ async function createAccountForUserId(userId) {
|
||||
* Get active coupons for a given user
|
||||
*
|
||||
* @param {string} userId
|
||||
* @return {Promise<RecurlyCoupon[]>}
|
||||
* @return {Promise<PaymentProviderCoupon[]>}
|
||||
*/
|
||||
async function getActiveCouponsForUserId(userId) {
|
||||
try {
|
||||
@@ -104,7 +104,7 @@ async function getActiveCouponsForUserId(userId) {
|
||||
* Get a subscription from Recurly
|
||||
*
|
||||
* @param {string} subscriptionId
|
||||
* @return {Promise<RecurlySubscription>}
|
||||
* @return {Promise<PaymentProviderSubscription>}
|
||||
*/
|
||||
async function getSubscription(subscriptionId) {
|
||||
const subscription = await client.getSubscription(`uuid-${subscriptionId}`)
|
||||
@@ -118,7 +118,7 @@ async function getSubscription(subscriptionId) {
|
||||
* error if the user has more than one subscription.
|
||||
*
|
||||
* @param {string} userId
|
||||
* @return {Promise<RecurlySubscription | null>}
|
||||
* @return {Promise<PaymentProviderSubscription | null>}
|
||||
*/
|
||||
async function getSubscriptionForUser(userId) {
|
||||
try {
|
||||
@@ -153,7 +153,7 @@ async function getSubscriptionForUser(userId) {
|
||||
/**
|
||||
* Request a susbcription change from Recurly
|
||||
*
|
||||
* @param {RecurlySubscriptionChangeRequest} changeRequest
|
||||
* @param {PaymentProviderSubscriptionChangeRequest} changeRequest
|
||||
*/
|
||||
async function applySubscriptionChangeRequest(changeRequest) {
|
||||
const body = subscriptionChangeRequestToApi(changeRequest)
|
||||
@@ -193,8 +193,8 @@ async function applySubscriptionChangeRequest(changeRequest) {
|
||||
/**
|
||||
* Preview a subscription change
|
||||
*
|
||||
* @param {RecurlySubscriptionChangeRequest} changeRequest
|
||||
* @return {Promise<RecurlySubscriptionChange>}
|
||||
* @param {PaymentProviderSubscriptionChangeRequest} changeRequest
|
||||
* @return {Promise<PaymentProviderSubscriptionChange>}
|
||||
*/
|
||||
async function previewSubscriptionChange(changeRequest) {
|
||||
const body = subscriptionChangeRequestToApi(changeRequest)
|
||||
@@ -303,7 +303,7 @@ async function getPaymentMethod(userId) {
|
||||
*
|
||||
* @param {string} planCode
|
||||
* @param {string} addOnCode
|
||||
* @return {Promise<RecurlyAddOn>}
|
||||
* @return {Promise<PaymentProviderAddOn>}
|
||||
*/
|
||||
async function getAddOn(planCode, addOnCode) {
|
||||
const addOn = await client.getPlanAddOn(
|
||||
@@ -317,7 +317,7 @@ async function getAddOn(planCode, addOnCode) {
|
||||
* Get the configuration for a given plan
|
||||
*
|
||||
* @param {string} planCode
|
||||
* @return {Promise<RecurlyPlan>}
|
||||
* @return {Promise<PaymentProviderPlan>}
|
||||
*/
|
||||
async function getPlan(planCode) {
|
||||
const plan = await client.getPlan(`code-${planCode}`)
|
||||
@@ -330,10 +330,10 @@ function subscriptionIsCanceledOrExpired(subscription) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a RecurlyAccount from Recurly API data
|
||||
* Build a PaymentProviderAccount from Recurly API data
|
||||
*
|
||||
* @param {recurly.Account} apiAccount
|
||||
* @return {RecurlyAccount}
|
||||
* @return {PaymentProviderAccount}
|
||||
*/
|
||||
function accountFromApi(apiAccount) {
|
||||
if (apiAccount.code == null || apiAccount.email == null) {
|
||||
@@ -341,7 +341,7 @@ function accountFromApi(apiAccount) {
|
||||
account: apiAccount,
|
||||
})
|
||||
}
|
||||
return new RecurlyAccount({
|
||||
return new PaymentProviderAccount({
|
||||
code: apiAccount.code,
|
||||
email: apiAccount.email,
|
||||
hasPastDueInvoice: apiAccount.hasPastDueInvoice ?? false,
|
||||
@@ -349,10 +349,10 @@ function accountFromApi(apiAccount) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a RecurlyCoupon from Recurly API data
|
||||
* Build a PaymentProviderCoupon from Recurly API data
|
||||
*
|
||||
* @param {recurly.CouponRedemption} apiRedemption
|
||||
* @return {RecurlyCoupon}
|
||||
* @return {PaymentProviderCoupon}
|
||||
*/
|
||||
function couponFromApi(apiRedemption) {
|
||||
if (apiRedemption.coupon == null || apiRedemption.coupon.code == null) {
|
||||
@@ -360,7 +360,7 @@ function couponFromApi(apiRedemption) {
|
||||
coupon: apiRedemption,
|
||||
})
|
||||
}
|
||||
return new RecurlyCoupon({
|
||||
return new PaymentProviderCoupon({
|
||||
code: apiRedemption.coupon.code,
|
||||
name: apiRedemption.coupon.name ?? '',
|
||||
description: apiRedemption.coupon.hostedPageDescription ?? '',
|
||||
@@ -368,10 +368,10 @@ function couponFromApi(apiRedemption) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a RecurlySubscription from Recurly API data
|
||||
* Build a PaymentProviderSubscription from Recurly API data
|
||||
*
|
||||
* @param {recurly.Subscription} apiSubscription
|
||||
* @return {RecurlySubscription}
|
||||
* @return {PaymentProviderSubscription}
|
||||
*/
|
||||
function subscriptionFromApi(apiSubscription) {
|
||||
if (
|
||||
@@ -394,7 +394,7 @@ function subscriptionFromApi(apiSubscription) {
|
||||
})
|
||||
}
|
||||
|
||||
const subscription = new RecurlySubscription({
|
||||
const subscription = new PaymentProviderSubscription({
|
||||
id: apiSubscription.uuid,
|
||||
userId: apiSubscription.account.code,
|
||||
planCode: apiSubscription.plan.code,
|
||||
@@ -427,10 +427,10 @@ function subscriptionFromApi(apiSubscription) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a RecurlySubscriptionAddOn from Recurly API data
|
||||
* Build a PaymentProviderSubscriptionAddOn from Recurly API data
|
||||
*
|
||||
* @param {recurly.SubscriptionAddOn} addOn
|
||||
* @return {RecurlySubscriptionAddOn}
|
||||
* @return {PaymentProviderSubscriptionAddOn}
|
||||
*/
|
||||
function subscriptionAddOnFromApi(addOn) {
|
||||
if (
|
||||
@@ -442,7 +442,7 @@ function subscriptionAddOnFromApi(addOn) {
|
||||
throw new OError('Invalid Recurly add-on', { addOn })
|
||||
}
|
||||
|
||||
return new RecurlySubscriptionAddOn({
|
||||
return new PaymentProviderSubscriptionAddOn({
|
||||
code: addOn.addOn.code,
|
||||
name: addOn.addOn.name,
|
||||
quantity: addOn.quantity ?? 1,
|
||||
@@ -451,11 +451,11 @@ function subscriptionAddOnFromApi(addOn) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a RecurlySubscriptionChange from Recurly API data
|
||||
* Build a PaymentProviderSubscriptionChange from Recurly API data
|
||||
*
|
||||
* @param {RecurlySubscription} subscription - the current subscription
|
||||
* @param {PaymentProviderSubscription} subscription - the current subscription
|
||||
* @param {recurly.SubscriptionChange} subscriptionChange - the subscription change returned from the API
|
||||
* @return {RecurlySubscriptionChange}
|
||||
* @return {PaymentProviderSubscriptionChange}
|
||||
*/
|
||||
function subscriptionChangeFromApi(subscription, subscriptionChange) {
|
||||
if (
|
||||
@@ -472,7 +472,7 @@ function subscriptionChangeFromApi(subscription, subscriptionChange) {
|
||||
subscriptionAddOnFromApi
|
||||
)
|
||||
|
||||
return new RecurlySubscriptionChange({
|
||||
return new PaymentProviderSubscriptionChange({
|
||||
subscription,
|
||||
nextPlanCode: subscriptionChange.plan.code,
|
||||
nextPlanName: subscriptionChange.plan.name,
|
||||
@@ -486,7 +486,7 @@ function subscriptionChangeFromApi(subscription, subscriptionChange) {
|
||||
* Compute immediate charge based on invoice collection
|
||||
*
|
||||
* @param {recurly.SubscriptionChange} subscriptionChange - the subscription change returned from the API
|
||||
* @return {RecurlyImmediateCharge}
|
||||
* @return {PaymentProviderImmediateCharge}
|
||||
*/
|
||||
function computeImmediateCharge(subscriptionChange) {
|
||||
const roundToTwoDecimal = (/** @type {number} */ num) =>
|
||||
@@ -506,7 +506,7 @@ function computeImmediateCharge(subscriptionChange) {
|
||||
tax = roundToTwoDecimal(tax + (creditInvoice.tax ?? 0))
|
||||
discount = roundToTwoDecimal(discount + (creditInvoice.discount ?? 0))
|
||||
}
|
||||
return new RecurlyImmediateCharge({
|
||||
return new PaymentProviderImmediateCharge({
|
||||
subtotal,
|
||||
total,
|
||||
tax,
|
||||
@@ -540,41 +540,41 @@ function paymentMethodFromApi(billingInfo) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a RecurlyAddOn from Recurly API data
|
||||
* Build a PaymentProviderAddOn from Recurly API data
|
||||
*
|
||||
* @param {recurly.AddOn} addOn
|
||||
* @return {RecurlyAddOn}
|
||||
* @return {PaymentProviderAddOn}
|
||||
*/
|
||||
function addOnFromApi(addOn) {
|
||||
if (addOn.code == null || addOn.name == null) {
|
||||
throw new OError('Invalid Recurly add-on', { addOn })
|
||||
}
|
||||
return new RecurlyAddOn({
|
||||
return new PaymentProviderAddOn({
|
||||
code: addOn.code,
|
||||
name: addOn.name,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a RecurlyPlan from Recurly API data
|
||||
* Build a PaymentProviderPlan from Recurly API data
|
||||
*
|
||||
* @param {recurly.Plan} plan
|
||||
* @return {RecurlyPlan}
|
||||
* @return {PaymentProviderPlan}
|
||||
*/
|
||||
function planFromApi(plan) {
|
||||
if (plan.code == null || plan.name == null) {
|
||||
throw new OError('Invalid Recurly add-on', { plan })
|
||||
}
|
||||
return new RecurlyPlan({
|
||||
return new PaymentProviderPlan({
|
||||
code: plan.code,
|
||||
name: plan.name,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an API request from a RecurlySubscriptionChangeRequest
|
||||
* Build an API request from a PaymentProviderSubscriptionChangeRequest
|
||||
*
|
||||
* @param {RecurlySubscriptionChangeRequest} changeRequest
|
||||
* @param {PaymentProviderSubscriptionChangeRequest} changeRequest
|
||||
* @return {recurly.SubscriptionChangeCreate}
|
||||
*/
|
||||
function subscriptionChangeRequestToApi(changeRequest) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const SplitTestHandler = require('../SplitTests/SplitTestHandler')
|
||||
const AnalyticsManager = require('../Analytics/AnalyticsManager')
|
||||
const SubscriptionEmailHandler = require('./SubscriptionEmailHandler')
|
||||
const { AI_ADD_ON_CODE } = require('./RecurlyEntities')
|
||||
const { AI_ADD_ON_CODE } = require('./PaymentProviderEntities')
|
||||
const { ObjectId } = require('mongodb-legacy')
|
||||
|
||||
const INVOICE_SUBSCRIPTION_LIMIT = 10
|
||||
|
||||
@@ -22,14 +22,14 @@ const Modules = require('../../infrastructure/Modules')
|
||||
const async = require('async')
|
||||
const HttpErrorHandler = require('../Errors/HttpErrorHandler')
|
||||
const RecurlyClient = require('./RecurlyClient')
|
||||
const { AI_ADD_ON_CODE } = require('./RecurlyEntities')
|
||||
const { AI_ADD_ON_CODE } = require('./PaymentProviderEntities')
|
||||
const PlansLocator = require('./PlansLocator')
|
||||
const RecurlyEntities = require('./RecurlyEntities')
|
||||
const PaymentProviderEntities = require('./PaymentProviderEntities')
|
||||
|
||||
/**
|
||||
* @import { SubscriptionChangeDescription } from '../../../../types/subscription/subscription-change-preview'
|
||||
* @import { SubscriptionChangePreview } from '../../../../types/subscription/subscription-change-preview'
|
||||
* @import { RecurlySubscriptionChange } from './RecurlyEntities'
|
||||
* @import { PaymentProviderSubscriptionChange } from './PaymentProviderEntities'
|
||||
* @import { PaymentMethod } from './types'
|
||||
*/
|
||||
|
||||
@@ -325,7 +325,9 @@ async function previewAddonPurchase(req, res) {
|
||||
const hasBundleViaWritefull =
|
||||
await FeaturesUpdater.promises.hasFeaturesViaWritefull(userId)
|
||||
const isAiUpgrade =
|
||||
RecurlyEntities.subscriptionChangeIsAiAssistUpgrade(subscriptionChange)
|
||||
PaymentProviderEntities.subscriptionChangeIsAiAssistUpgrade(
|
||||
subscriptionChange
|
||||
)
|
||||
if (hasBundleViaWritefull && isAiUpgrade) {
|
||||
return res.redirect(
|
||||
'/user/subscription?redirect-reason=writefull-entitled'
|
||||
@@ -724,7 +726,7 @@ function getPlanNameForDisplay(planName, planCode) {
|
||||
* 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 {PaymentProviderSubscriptionChange} subscriptionChange The subscription change object coming from Recurly
|
||||
* @param {PaymentMethod} paymentMethod The payment method associated to the user
|
||||
* @return {SubscriptionChangePreview}
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,7 @@ const RecurlyClient = require('./RecurlyClient')
|
||||
const PlansLocator = require('./PlansLocator')
|
||||
const SubscriptionHandler = require('./SubscriptionHandler')
|
||||
const GroupPlansData = require('./GroupPlansData')
|
||||
const { MEMBERS_LIMIT_ADD_ON_CODE } = require('./RecurlyEntities')
|
||||
const { MEMBERS_LIMIT_ADD_ON_CODE } = require('./PaymentProviderEntities')
|
||||
const {
|
||||
ManuallyCollectedError,
|
||||
PendingChangeError,
|
||||
|
||||
@@ -14,7 +14,7 @@ const UserUpdater = require('../User/UserUpdater')
|
||||
const { NotFoundError } = require('../Errors/Errors')
|
||||
|
||||
/**
|
||||
* @import { RecurlySubscription, RecurlySubscriptionChange } from './RecurlyEntities'
|
||||
* @import { PaymentProviderSubscription, PaymentProviderSubscriptionChange } from './PaymentProviderEntities'
|
||||
*/
|
||||
|
||||
async function validateNoSubscriptionInRecurly(userId) {
|
||||
@@ -69,7 +69,7 @@ async function createSubscription(user, subscriptionDetails, recurlyTokenIds) {
|
||||
*
|
||||
* @param {string} userId
|
||||
* @param {string} planCode
|
||||
* @return {Promise<RecurlySubscriptionChange>}
|
||||
* @return {Promise<PaymentProviderSubscriptionChange>}
|
||||
*/
|
||||
async function previewSubscriptionChange(userId, planCode) {
|
||||
const subscription = await getSubscriptionForUser(userId)
|
||||
@@ -283,7 +283,7 @@ async function _updateSubscriptionFromRecurly(subscription) {
|
||||
*
|
||||
* @param {string} userId
|
||||
* @param {string} addOnCode
|
||||
* @return {Promise<RecurlySubscriptionChange>}
|
||||
* @return {Promise<PaymentProviderSubscriptionChange>}
|
||||
*/
|
||||
async function previewAddonPurchase(userId, addOnCode) {
|
||||
const subscription = await getSubscriptionForUser(userId)
|
||||
@@ -353,7 +353,7 @@ async function removeAddon(userId, addOnCode) {
|
||||
* Throws a NotFoundError if the subscription can't be found
|
||||
*
|
||||
* @param {string} userId
|
||||
* @return {Promise<RecurlySubscription>}
|
||||
* @return {Promise<PaymentProviderSubscription>}
|
||||
*/
|
||||
async function getSubscriptionForUser(userId) {
|
||||
const subscription =
|
||||
|
||||
@@ -5,7 +5,7 @@ const logger = require('@overleaf/logger')
|
||||
const {
|
||||
AI_ADD_ON_CODE,
|
||||
isStandaloneAiAddOnPlanCode,
|
||||
} = require('./RecurlyEntities')
|
||||
} = require('./PaymentProviderEntities')
|
||||
require('./GroupPlansData') // make sure dynamic group plans are loaded
|
||||
|
||||
const SubscriptionLocator = {
|
||||
|
||||
@@ -5,7 +5,7 @@ const PlansLocator = require('./PlansLocator')
|
||||
const {
|
||||
isStandaloneAiAddOnPlanCode,
|
||||
MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
} = require('./RecurlyEntities')
|
||||
} = require('./PaymentProviderEntities')
|
||||
const SubscriptionFormatters = require('./SubscriptionFormatters')
|
||||
const SubscriptionLocator = require('./SubscriptionLocator')
|
||||
const SubscriptionUpdater = require('./SubscriptionUpdater')
|
||||
@@ -138,8 +138,6 @@ async function buildUsersSubscriptionViewModel(user, locale = 'en') {
|
||||
},
|
||||
})
|
||||
|
||||
const recurlySubscription = paymentRecord && paymentRecord.subscription
|
||||
|
||||
if (memberGroupSubscriptions == null) {
|
||||
memberGroupSubscriptions = []
|
||||
} else {
|
||||
@@ -214,14 +212,6 @@ async function buildUsersSubscriptionViewModel(user, locale = 'en') {
|
||||
personalSubscription.plan = plan
|
||||
}
|
||||
|
||||
// Subscription DB object contains a recurly property, used to cache trial info
|
||||
// on the project-list. However, this can cause the wrong template to render,
|
||||
// if we do not have any subscription data from Recurly (recurlySubscription)
|
||||
// TODO: Delete this workaround once recurly cache property name migration rolled out.
|
||||
if (personalSubscription) {
|
||||
delete personalSubscription.recurly
|
||||
}
|
||||
|
||||
function getPlanOnlyDisplayPrice(
|
||||
totalPlanPriceInCents,
|
||||
taxRate,
|
||||
@@ -243,7 +233,7 @@ async function buildUsersSubscriptionViewModel(user, locale = 'en') {
|
||||
return formatCurrency(
|
||||
totalPlanPriceInCents -
|
||||
allAddOnsTotalPriceInCentsExceptAdditionalLicensePrice,
|
||||
recurlySubscription.currency,
|
||||
paymentRecord.subscription.currency,
|
||||
locale
|
||||
)
|
||||
}
|
||||
@@ -257,7 +247,7 @@ async function buildUsersSubscriptionViewModel(user, locale = 'en') {
|
||||
if (totalPriceInCents > 0) {
|
||||
prev[curr.code] = formatCurrency(
|
||||
totalPriceInCents,
|
||||
recurlySubscription.currency,
|
||||
paymentRecord.subscription.currency,
|
||||
locale
|
||||
)
|
||||
}
|
||||
@@ -267,15 +257,15 @@ async function buildUsersSubscriptionViewModel(user, locale = 'en') {
|
||||
}, {})
|
||||
}
|
||||
|
||||
if (personalSubscription && recurlySubscription) {
|
||||
const tax = recurlySubscription.taxAmount || 0
|
||||
if (personalSubscription && paymentRecord && paymentRecord.subscription) {
|
||||
const tax = paymentRecord.subscription.taxAmount || 0
|
||||
// Some plans allow adding more seats than the base plan provides.
|
||||
// This is recorded as a subscription add on.
|
||||
// Note: taxAmount already includes the tax for any addon.
|
||||
let addOnPrice = 0
|
||||
let additionalLicenses = 0
|
||||
const addOns = recurlySubscription.addOns || []
|
||||
const taxRate = recurlySubscription.taxRate
|
||||
const addOns = paymentRecord.subscription.addOns || []
|
||||
const taxRate = paymentRecord.subscription.taxRate
|
||||
addOns.forEach(addOn => {
|
||||
addOnPrice += addOn.quantity * addOn.unitPrice
|
||||
if (addOn.code === plan.membersLimitAddOn) {
|
||||
@@ -283,7 +273,7 @@ async function buildUsersSubscriptionViewModel(user, locale = 'en') {
|
||||
}
|
||||
})
|
||||
const totalLicenses = (plan.membersLimit || 0) + additionalLicenses
|
||||
personalSubscription.recurly = {
|
||||
personalSubscription.payment = {
|
||||
taxRate,
|
||||
billingDetailsLink: buildHostedLink('billing-details'),
|
||||
accountManagementLink: buildHostedLink('account-management'),
|
||||
@@ -291,25 +281,26 @@ async function buildUsersSubscriptionViewModel(user, locale = 'en') {
|
||||
addOns,
|
||||
totalLicenses,
|
||||
nextPaymentDueAt: SubscriptionFormatters.formatDateTime(
|
||||
recurlySubscription.periodEnd
|
||||
paymentRecord.subscription.periodEnd
|
||||
),
|
||||
nextPaymentDueDate: SubscriptionFormatters.formatDate(
|
||||
recurlySubscription.periodEnd
|
||||
paymentRecord.subscription.periodEnd
|
||||
),
|
||||
currency: recurlySubscription.currency,
|
||||
state: recurlySubscription.state,
|
||||
currency: paymentRecord.subscription.currency,
|
||||
state: paymentRecord.subscription.state,
|
||||
trialEndsAtFormatted: SubscriptionFormatters.formatDateTime(
|
||||
recurlySubscription.trialPeriodEnd
|
||||
paymentRecord.subscription.trialPeriodEnd
|
||||
),
|
||||
trialEndsAt: recurlySubscription.trialPeriodEnd,
|
||||
trialEndsAt: paymentRecord.subscription.trialPeriodEnd,
|
||||
activeCoupons: paymentRecord.coupons,
|
||||
accountEmail: paymentRecord.account.email,
|
||||
hasPastDueInvoice: paymentRecord.account.hasPastDueInvoice,
|
||||
pausedAt: recurlySubscription.pausePeriodStart,
|
||||
remainingPauseCycles: recurlySubscription.remainingPauseCycles,
|
||||
pausedAt: paymentRecord.subscription.pausePeriodStart,
|
||||
remainingPauseCycles: paymentRecord.subscription.remainingPauseCycles,
|
||||
}
|
||||
if (recurlySubscription.pendingChange) {
|
||||
const pendingPlanCode = recurlySubscription.pendingChange.nextPlanCode
|
||||
if (paymentRecord.subscription.pendingChange) {
|
||||
const pendingPlanCode =
|
||||
paymentRecord.subscription.pendingChange.nextPlanCode
|
||||
const pendingPlan = PlansLocator.findLocalPlanInSettings(pendingPlanCode)
|
||||
if (pendingPlan == null) {
|
||||
throw new Error(`No plan found for planCode '${pendingPlanCode}'`)
|
||||
@@ -317,10 +308,10 @@ async function buildUsersSubscriptionViewModel(user, locale = 'en') {
|
||||
let pendingAdditionalLicenses = 0
|
||||
let pendingAddOnTax = 0
|
||||
let pendingAddOnPrice = 0
|
||||
if (recurlySubscription.pendingChange.nextAddOns) {
|
||||
const pendingRecurlyAddons =
|
||||
recurlySubscription.pendingChange.nextAddOns
|
||||
pendingRecurlyAddons.forEach(addOn => {
|
||||
if (paymentRecord.subscription.pendingChange.nextAddOns) {
|
||||
const pendingAddOns =
|
||||
paymentRecord.subscription.pendingChange.nextAddOns
|
||||
pendingAddOns.forEach(addOn => {
|
||||
pendingAddOnPrice += addOn.quantity * addOn.unitPrice
|
||||
if (addOn.code === pendingPlan.membersLimitAddOn) {
|
||||
pendingAdditionalLicenses += addOn.quantity
|
||||
@@ -328,50 +319,50 @@ async function buildUsersSubscriptionViewModel(user, locale = 'en') {
|
||||
})
|
||||
// Need to calculate tax ourselves as we don't get tax amounts for pending subs
|
||||
pendingAddOnTax =
|
||||
personalSubscription.recurly.taxRate * pendingAddOnPrice
|
||||
pendingPlan.addOns = pendingRecurlyAddons
|
||||
personalSubscription.payment.taxRate * pendingAddOnPrice
|
||||
pendingPlan.addOns = pendingAddOns
|
||||
}
|
||||
const pendingSubscriptionTax =
|
||||
personalSubscription.recurly.taxRate *
|
||||
recurlySubscription.pendingChange.nextPlanPrice
|
||||
personalSubscription.payment.taxRate *
|
||||
paymentRecord.subscription.pendingChange.nextPlanPrice
|
||||
const totalPrice =
|
||||
recurlySubscription.pendingChange.nextPlanPrice +
|
||||
paymentRecord.subscription.pendingChange.nextPlanPrice +
|
||||
pendingAddOnPrice +
|
||||
pendingAddOnTax +
|
||||
pendingSubscriptionTax
|
||||
|
||||
personalSubscription.recurly.displayPrice = formatCurrency(
|
||||
personalSubscription.payment.displayPrice = formatCurrency(
|
||||
totalPrice,
|
||||
recurlySubscription.currency,
|
||||
paymentRecord.subscription.currency,
|
||||
locale
|
||||
)
|
||||
personalSubscription.recurly.planOnlyDisplayPrice =
|
||||
personalSubscription.payment.planOnlyDisplayPrice =
|
||||
getPlanOnlyDisplayPrice(
|
||||
totalPrice,
|
||||
taxRate,
|
||||
recurlySubscription.pendingChange.nextAddOns
|
||||
paymentRecord.subscription.pendingChange.nextAddOns
|
||||
)
|
||||
personalSubscription.recurly.addOnDisplayPricesWithoutAdditionalLicense =
|
||||
personalSubscription.payment.addOnDisplayPricesWithoutAdditionalLicense =
|
||||
getAddOnDisplayPricesWithoutAdditionalLicense(
|
||||
taxRate,
|
||||
recurlySubscription.pendingChange.nextAddOns
|
||||
paymentRecord.subscription.pendingChange.nextAddOns
|
||||
)
|
||||
const pendingTotalLicenses =
|
||||
(pendingPlan.membersLimit || 0) + pendingAdditionalLicenses
|
||||
personalSubscription.recurly.pendingAdditionalLicenses =
|
||||
personalSubscription.payment.pendingAdditionalLicenses =
|
||||
pendingAdditionalLicenses
|
||||
personalSubscription.recurly.pendingTotalLicenses = pendingTotalLicenses
|
||||
personalSubscription.payment.pendingTotalLicenses = pendingTotalLicenses
|
||||
personalSubscription.pendingPlan = pendingPlan
|
||||
} else {
|
||||
const totalPrice = recurlySubscription.planPrice + addOnPrice + tax
|
||||
personalSubscription.recurly.displayPrice = formatCurrency(
|
||||
const totalPrice = paymentRecord.subscription.planPrice + addOnPrice + tax
|
||||
personalSubscription.payment.displayPrice = formatCurrency(
|
||||
totalPrice,
|
||||
recurlySubscription.currency,
|
||||
paymentRecord.subscription.currency,
|
||||
locale
|
||||
)
|
||||
personalSubscription.recurly.planOnlyDisplayPrice =
|
||||
personalSubscription.payment.planOnlyDisplayPrice =
|
||||
getPlanOnlyDisplayPrice(totalPrice, taxRate, addOns)
|
||||
personalSubscription.recurly.addOnDisplayPricesWithoutAdditionalLicense =
|
||||
personalSubscription.payment.addOnDisplayPricesWithoutAdditionalLicense =
|
||||
getAddOnDisplayPricesWithoutAdditionalLicense(taxRate, addOns)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { PaypalPaymentMethod, CreditCardPaymentMethod } from './RecurlyEntities'
|
||||
import {
|
||||
PaypalPaymentMethod,
|
||||
CreditCardPaymentMethod,
|
||||
} from './PaymentProviderEntities'
|
||||
|
||||
export type PaymentMethod = PaypalPaymentMethod | CreditCardPaymentMethod
|
||||
|
||||
@@ -23,9 +23,9 @@ block append meta
|
||||
meta(name="ol-showGroupDiscount", data-type="boolean", content=showGroupDiscount)
|
||||
meta(name="ol-groupSettingsEnabledFor", data-type="json" content=groupSettingsEnabledFor)
|
||||
meta(name="ol-user" data-type="json" content=user)
|
||||
if (personalSubscription && personalSubscription.recurly)
|
||||
if (personalSubscription && personalSubscription.payment)
|
||||
meta(name="ol-recurlyApiKey" content=settings.apis.recurly.publicKey)
|
||||
meta(name="ol-recommendedCurrency" content=personalSubscription.recurly.currency)
|
||||
meta(name="ol-recommendedCurrency" content=personalSubscription.payment.currency)
|
||||
meta(name="ol-groupPlans" data-type="json" content=groupPlans)
|
||||
|
||||
block content
|
||||
|
||||
@@ -15,7 +15,7 @@ import { debugConsole } from '@/utils/debugging'
|
||||
import * as eventTracking from '../../../../infrastructure/event-tracking'
|
||||
import PauseDuck from '../../images/pause-duck.svg'
|
||||
import GenericErrorAlert from './generic-error-alert'
|
||||
import { RecurlySubscription } from '../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../types/subscription/dashboard/subscription'
|
||||
|
||||
const pauseMonthDurationOptions = [1, 2, 3]
|
||||
|
||||
@@ -35,13 +35,13 @@ export default function PauseSubscriptionModal() {
|
||||
const location = useLocation()
|
||||
|
||||
function handleCancelSubscriptionClick() {
|
||||
const subscription = personalSubscription as RecurlySubscription
|
||||
const subscription = personalSubscription as PaidSubscription
|
||||
eventTracking.sendMB('subscription-page-cancel-button-click', {
|
||||
plan_code: subscription?.planCode,
|
||||
is_trial:
|
||||
subscription?.recurly.trialEndsAtFormatted &&
|
||||
subscription?.recurly.trialEndsAt &&
|
||||
new Date(subscription.recurly.trialEndsAt).getTime() > Date.now(),
|
||||
subscription?.payment.trialEndsAtFormatted &&
|
||||
subscription?.payment.trialEndsAt &&
|
||||
new Date(subscription.payment.trialEndsAt).getTime() > Date.now(),
|
||||
})
|
||||
setShowCancellation(true)
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ function PersonalSubscriptionRecurlySyncEmail() {
|
||||
runAsync(postJSON('/user/subscription/account/email'))
|
||||
}
|
||||
|
||||
if (!personalSubscription || !('recurly' in personalSubscription)) return null
|
||||
if (!personalSubscription || !('payment' in personalSubscription)) return null
|
||||
|
||||
const recurlyEmail = personalSubscription.recurly.accountEmail
|
||||
const recurlyEmail = personalSubscription.payment.accountEmail
|
||||
|
||||
if (!userEmail || recurlyEmail === userEmail) return null
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { RecurlySubscription } from '../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PausedSubscription } from './states/active/paused'
|
||||
import { ActiveSubscriptionNew } from '@/features/subscription/components/dashboard/states/active/active-new'
|
||||
import { CanceledSubscription } from './states/canceled'
|
||||
@@ -11,7 +11,7 @@ import OLNotification from '@/features/ui/components/ol/ol-notification'
|
||||
function PastDueSubscriptionAlert({
|
||||
subscription,
|
||||
}: {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
@@ -21,7 +21,7 @@ function PastDueSubscriptionAlert({
|
||||
<>
|
||||
{t('account_has_past_due_invoice_change_plan_warning')}{' '}
|
||||
<a
|
||||
href={subscription.recurly.accountManagementLink}
|
||||
href={subscription.payment.accountManagementLink}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
@@ -57,10 +57,10 @@ function RedirectAlerts() {
|
||||
function PersonalSubscriptionStates({
|
||||
subscription,
|
||||
}: {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const state = subscription?.recurly.state
|
||||
const state = subscription?.payment.state
|
||||
|
||||
if (state === 'active') {
|
||||
// This version handles subscriptions with and without addons
|
||||
@@ -83,7 +83,7 @@ function PersonalSubscription() {
|
||||
|
||||
if (!personalSubscription) return null
|
||||
|
||||
if (!('recurly' in personalSubscription)) {
|
||||
if (!('payment' in personalSubscription)) {
|
||||
return (
|
||||
<p>
|
||||
<Trans
|
||||
@@ -97,11 +97,11 @@ function PersonalSubscription() {
|
||||
return (
|
||||
<>
|
||||
<RedirectAlerts />
|
||||
{personalSubscription.recurly.hasPastDueInvoice && (
|
||||
{personalSubscription.payment.hasPastDueInvoice && (
|
||||
<PastDueSubscriptionAlert subscription={personalSubscription} />
|
||||
)}
|
||||
<PersonalSubscriptionStates
|
||||
subscription={personalSubscription as RecurlySubscription}
|
||||
subscription={personalSubscription as PaidSubscription}
|
||||
/>
|
||||
{recurlyLoadError && (
|
||||
<OLNotification
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useTranslation, Trans } from 'react-i18next'
|
||||
import { PriceExceptions } from '../../../shared/price-exceptions'
|
||||
import { useSubscriptionDashboardContext } from '../../../../context/subscription-dashboard-context'
|
||||
import { RecurlySubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { CancelSubscriptionButton } from './cancel-subscription-button'
|
||||
import { CancelSubscription } from './cancel-plan/cancel-subscription'
|
||||
import { TrialEnding } from './trial-ending'
|
||||
@@ -33,7 +33,7 @@ import Notification from '@/shared/components/notification'
|
||||
export function ActiveSubscriptionNew({
|
||||
subscription,
|
||||
}: {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
@@ -77,14 +77,14 @@ export function ActiveSubscriptionNew({
|
||||
}
|
||||
}
|
||||
const hasPendingPause = Boolean(
|
||||
subscription.recurly.state === 'active' &&
|
||||
subscription.recurly.remainingPauseCycles &&
|
||||
subscription.recurly.remainingPauseCycles > 0
|
||||
subscription.payment.state === 'active' &&
|
||||
subscription.payment.remainingPauseCycles &&
|
||||
subscription.payment.remainingPauseCycles > 0
|
||||
)
|
||||
|
||||
const isLegacyPlan =
|
||||
subscription.recurly.totalLicenses !==
|
||||
subscription.recurly.additionalLicenses
|
||||
subscription.payment.totalLicenses !==
|
||||
subscription.payment.additionalLicenses
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -103,7 +103,7 @@ export function ActiveSubscriptionNew({
|
||||
{subscription.plan.annual ? (
|
||||
<Trans
|
||||
i18nKey="billed_annually_at"
|
||||
values={{ price: subscription.recurly.displayPrice }}
|
||||
values={{ price: subscription.payment.displayPrice }}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
components={[
|
||||
@@ -116,7 +116,7 @@ export function ActiveSubscriptionNew({
|
||||
) : (
|
||||
<Trans
|
||||
i18nKey="billed_monthly_at"
|
||||
values={{ price: subscription.recurly.displayPrice }}
|
||||
values={{ price: subscription.payment.displayPrice }}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
components={[
|
||||
@@ -131,7 +131,7 @@ export function ActiveSubscriptionNew({
|
||||
<p className="mb-1">
|
||||
<Trans
|
||||
i18nKey="renews_on"
|
||||
values={{ date: subscription.recurly.nextPaymentDueDate }}
|
||||
values={{ date: subscription.payment.nextPaymentDueDate }}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
components={[<strong />]} // eslint-disable-line react/jsx-key
|
||||
@@ -139,7 +139,7 @@ export function ActiveSubscriptionNew({
|
||||
</p>
|
||||
<div>
|
||||
<a
|
||||
href={subscription.recurly.accountManagementLink}
|
||||
href={subscription.payment.accountManagementLink}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className="me-2"
|
||||
@@ -147,7 +147,7 @@ export function ActiveSubscriptionNew({
|
||||
{t('view_invoices')}
|
||||
</a>
|
||||
<a
|
||||
href={subscription.recurly.billingDetailsLink}
|
||||
href={subscription.payment.billingDetailsLink}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
@@ -171,21 +171,21 @@ export function ActiveSubscriptionNew({
|
||||
subscription.pendingPlan.name !== subscription.plan.name && (
|
||||
<p className="mb-1">{t('want_change_to_apply_before_plan_end')}</p>
|
||||
)}
|
||||
{isInFreeTrial(subscription.recurly.trialEndsAt) &&
|
||||
subscription.recurly.trialEndsAtFormatted && (
|
||||
{isInFreeTrial(subscription.payment.trialEndsAt) &&
|
||||
subscription.payment.trialEndsAtFormatted && (
|
||||
<TrialEnding
|
||||
trialEndsAtFormatted={subscription.recurly.trialEndsAtFormatted}
|
||||
trialEndsAtFormatted={subscription.payment.trialEndsAtFormatted}
|
||||
className="mb-1"
|
||||
/>
|
||||
)}
|
||||
{subscription.recurly.totalLicenses > 0 && (
|
||||
{subscription.payment.totalLicenses > 0 && (
|
||||
<p className="mb-1">
|
||||
{isLegacyPlan && subscription.recurly.additionalLicenses > 0 ? (
|
||||
{isLegacyPlan && subscription.payment.additionalLicenses > 0 ? (
|
||||
<Trans
|
||||
i18nKey="plus_x_additional_licenses_for_a_total_of_y_licenses"
|
||||
values={{
|
||||
count: subscription.recurly.totalLicenses,
|
||||
additionalLicenses: subscription.recurly.additionalLicenses,
|
||||
count: subscription.payment.totalLicenses,
|
||||
additionalLicenses: subscription.payment.additionalLicenses,
|
||||
}}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
@@ -194,7 +194,7 @@ export function ActiveSubscriptionNew({
|
||||
) : (
|
||||
<Trans
|
||||
i18nKey="supports_up_to_x_licenses"
|
||||
values={{ count: subscription.recurly.totalLicenses }}
|
||||
values={{ count: subscription.payment.totalLicenses }}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
components={[<strong />]} // eslint-disable-line react/jsx-key
|
||||
@@ -209,7 +209,7 @@ export function ActiveSubscriptionNew({
|
||||
i18nKey="your_subscription_will_pause_on"
|
||||
values={{
|
||||
planName: subscription.plan.name,
|
||||
pauseDate: subscription.recurly.nextPaymentDueAt,
|
||||
pauseDate: subscription.payment.nextPaymentDueAt,
|
||||
reactivationDate: getFormattedRenewalDate(),
|
||||
}}
|
||||
shouldUnescape
|
||||
@@ -227,10 +227,10 @@ export function ActiveSubscriptionNew({
|
||||
<p className="mb-1">
|
||||
{subscription.plan.annual
|
||||
? t('x_price_per_year', {
|
||||
price: subscription.recurly.planOnlyDisplayPrice,
|
||||
price: subscription.payment.planOnlyDisplayPrice,
|
||||
})
|
||||
: t('x_price_per_month', {
|
||||
price: subscription.recurly.planOnlyDisplayPrice,
|
||||
price: subscription.payment.planOnlyDisplayPrice,
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
@@ -261,7 +261,7 @@ export function ActiveSubscriptionNew({
|
||||
}
|
||||
|
||||
type PlanActionsProps = {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
onStandalonePlan: boolean
|
||||
handlePlanChange: () => void
|
||||
hasPendingPause: boolean
|
||||
@@ -301,7 +301,7 @@ function PlanActions({
|
||||
<FlexibleGroupLicensingActions subscription={subscription} />
|
||||
) : (
|
||||
<>
|
||||
{!hasPendingPause && !subscription.recurly.hasPastDueInvoice && (
|
||||
{!hasPendingPause && !subscription.payment.hasPastDueInvoice && (
|
||||
<OLButton variant="secondary" onClick={handlePlanChange}>
|
||||
{t('change_plan')}
|
||||
</OLButton>
|
||||
@@ -334,7 +334,7 @@ function PlanActions({
|
||||
function FlexibleGroupLicensingActions({
|
||||
subscription,
|
||||
}: {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useTranslation, Trans } from 'react-i18next'
|
||||
import { PriceExceptions } from '../../../shared/price-exceptions'
|
||||
import { useSubscriptionDashboardContext } from '../../../../context/subscription-dashboard-context'
|
||||
import { RecurlySubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { CancelSubscriptionButton } from './cancel-subscription-button'
|
||||
import { CancelSubscription } from './cancel-plan/cancel-subscription'
|
||||
import { PendingPlanChange } from './pending-plan-change'
|
||||
@@ -27,7 +27,7 @@ import LoadingSpinner from '@/shared/components/loading-spinner'
|
||||
export function ActiveSubscription({
|
||||
subscription,
|
||||
}: {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
@@ -46,9 +46,9 @@ export function ActiveSubscription({
|
||||
if (showCancellation) return <CancelSubscription />
|
||||
|
||||
const hasPendingPause =
|
||||
subscription.recurly.state === 'active' &&
|
||||
subscription.recurly.remainingPauseCycles &&
|
||||
subscription.recurly.remainingPauseCycles > 0
|
||||
subscription.payment.state === 'active' &&
|
||||
subscription.payment.remainingPauseCycles &&
|
||||
subscription.payment.remainingPauseCycles > 0
|
||||
|
||||
const handleCancelPendingPauseClick = async () => {
|
||||
try {
|
||||
@@ -96,19 +96,19 @@ export function ActiveSubscription({
|
||||
</>
|
||||
)}
|
||||
{!subscription.pendingPlan &&
|
||||
subscription.recurly.additionalLicenses > 0 && (
|
||||
subscription.payment.additionalLicenses > 0 && (
|
||||
<>
|
||||
{' '}
|
||||
<PendingAdditionalLicenses
|
||||
additionalLicenses={subscription.recurly.additionalLicenses}
|
||||
totalLicenses={subscription.recurly.totalLicenses}
|
||||
additionalLicenses={subscription.payment.additionalLicenses}
|
||||
totalLicenses={subscription.payment.totalLicenses}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!recurlyLoadError &&
|
||||
!subscription.groupPlan &&
|
||||
!hasPendingPause &&
|
||||
!subscription.recurly.hasPastDueInvoice && (
|
||||
!subscription.payment.hasPastDueInvoice && (
|
||||
<>
|
||||
{' '}
|
||||
<OLButton
|
||||
@@ -128,10 +128,10 @@ export function ActiveSubscription({
|
||||
{(!subscription.pendingPlan ||
|
||||
subscription.pendingPlan.name === subscription.plan.name) &&
|
||||
subscription.plan.groupPlan && <ContactSupportToChangeGroupPlan />}
|
||||
{isInFreeTrial(subscription.recurly.trialEndsAt) &&
|
||||
subscription.recurly.trialEndsAtFormatted && (
|
||||
{isInFreeTrial(subscription.payment.trialEndsAt) &&
|
||||
subscription.payment.trialEndsAtFormatted && (
|
||||
<TrialEnding
|
||||
trialEndsAtFormatted={subscription.recurly.trialEndsAtFormatted}
|
||||
trialEndsAtFormatted={subscription.payment.trialEndsAtFormatted}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -142,7 +142,7 @@ export function ActiveSubscription({
|
||||
i18nKey="your_subscription_will_pause_on"
|
||||
values={{
|
||||
planName: subscription.plan.name,
|
||||
pauseDate: subscription.recurly.nextPaymentDueAt,
|
||||
pauseDate: subscription.payment.nextPaymentDueAt,
|
||||
reactivationDate: getFormattedRenewalDate(),
|
||||
}}
|
||||
shouldUnescape
|
||||
@@ -174,7 +174,7 @@ export function ActiveSubscription({
|
||||
<Trans
|
||||
i18nKey="next_payment_of_x_collectected_on_y"
|
||||
values={{
|
||||
paymentAmmount: subscription.recurly.displayPrice,
|
||||
paymentAmmount: subscription.payment.displayPrice,
|
||||
collectionDate: getFormattedRenewalDate(),
|
||||
}}
|
||||
shouldUnescape
|
||||
@@ -192,7 +192,7 @@ export function ActiveSubscription({
|
||||
<PriceExceptions subscription={subscription} />
|
||||
<p className="d-inline-flex flex-wrap gap-1">
|
||||
<a
|
||||
href={subscription.recurly.billingDetailsLink}
|
||||
href={subscription.payment.billingDetailsLink}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className="btn btn-secondary-info btn-secondary"
|
||||
@@ -200,7 +200,7 @@ export function ActiveSubscription({
|
||||
{t('update_your_billing_details')}
|
||||
</a>{' '}
|
||||
<a
|
||||
href={subscription.recurly.accountManagementLink}
|
||||
href={subscription.payment.accountManagementLink}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className="btn btn-secondary-info btn-secondary"
|
||||
|
||||
@@ -9,11 +9,11 @@ import {
|
||||
AI_STANDALONE_PLAN_CODE,
|
||||
} from '@/features/subscription/data/add-on-codes'
|
||||
import sparkle from '@/shared/svgs/sparkle.svg'
|
||||
import { RecurlySubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { LICENSE_ADD_ON } from '@/features/group-management/components/upgrade-subscription/upgrade-subscription-plan-details'
|
||||
|
||||
type AddOnsProps = {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
onStandalonePlan: boolean
|
||||
handleCancelClick: (code: string) => void
|
||||
}
|
||||
@@ -106,9 +106,9 @@ function AddOns({
|
||||
const { t } = useTranslation()
|
||||
const addOnsDisplayPrices = onStandalonePlan
|
||||
? {
|
||||
[AI_STANDALONE_PLAN_CODE]: subscription.recurly.displayPrice,
|
||||
[AI_STANDALONE_PLAN_CODE]: subscription.payment.displayPrice,
|
||||
}
|
||||
: subscription.recurly.addOnDisplayPricesWithoutAdditionalLicense
|
||||
: subscription.payment.addOnDisplayPricesWithoutAdditionalLicense
|
||||
const addOnsToDisplay = onStandalonePlan
|
||||
? [{ addOnCode: AI_STANDALONE_PLAN_CODE }]
|
||||
: subscription.addOns?.filter(addOn => addOn.addOnCode !== LICENSE_ADD_ON)
|
||||
@@ -130,7 +130,7 @@ function AddOns({
|
||||
)
|
||||
}
|
||||
displayPrice={addOnsDisplayPrices[addOn.addOnCode]}
|
||||
nextBillingDate={subscription.recurly.nextPaymentDueDate}
|
||||
nextBillingDate={subscription.payment.nextPaymentDueDate}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
|
||||
@@ -155,14 +155,14 @@ export function CancelSubscription() {
|
||||
isSuccessSecondaryAction ||
|
||||
isSuccessCancel
|
||||
|
||||
if (!personalSubscription || !('recurly' in personalSubscription)) return null
|
||||
if (!personalSubscription || !('payment' in personalSubscription)) return null
|
||||
|
||||
const showDowngrade = showDowngradeOption(
|
||||
personalSubscription.plan.planCode,
|
||||
personalSubscription.plan.groupPlan,
|
||||
personalSubscription.recurly.trialEndsAt,
|
||||
personalSubscription.recurly.pausedAt,
|
||||
personalSubscription.recurly.remainingPauseCycles
|
||||
personalSubscription.payment.trialEndsAt,
|
||||
personalSubscription.payment.pausedAt,
|
||||
personalSubscription.payment.remainingPauseCycles
|
||||
)
|
||||
const planToDowngradeTo = plans.find(
|
||||
plan => plan.planCode === planCodeToDowngradeTo
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import * as eventTracking from '../../../../../../infrastructure/event-tracking'
|
||||
import { useSubscriptionDashboardContext } from '../../../../context/subscription-dashboard-context'
|
||||
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||
import { RecurlySubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
export function CancelSubscriptionButton() {
|
||||
@@ -14,16 +14,16 @@ export function CancelSubscriptionButton() {
|
||||
setShowCancellation,
|
||||
} = useSubscriptionDashboardContext()
|
||||
|
||||
const subscription = personalSubscription as RecurlySubscription
|
||||
const subscription = personalSubscription as PaidSubscription
|
||||
const isInTrial =
|
||||
subscription?.recurly.trialEndsAtFormatted &&
|
||||
subscription?.recurly.trialEndsAt &&
|
||||
new Date(subscription.recurly.trialEndsAt).getTime() > Date.now()
|
||||
subscription?.payment.trialEndsAtFormatted &&
|
||||
subscription?.payment.trialEndsAt &&
|
||||
new Date(subscription.payment.trialEndsAt).getTime() > Date.now()
|
||||
const hasPendingOrActivePause =
|
||||
subscription.recurly.state === 'paused' ||
|
||||
(subscription.recurly.state === 'active' &&
|
||||
subscription.recurly.remainingPauseCycles &&
|
||||
subscription.recurly.remainingPauseCycles > 0)
|
||||
subscription.payment.state === 'paused' ||
|
||||
(subscription.payment.state === 'active' &&
|
||||
subscription.payment.remainingPauseCycles &&
|
||||
subscription.payment.remainingPauseCycles > 0)
|
||||
const planIsEligibleForPause =
|
||||
!subscription.pendingPlan &&
|
||||
!subscription.groupPlan &&
|
||||
|
||||
@@ -3,17 +3,17 @@ import { useSubscriptionDashboardContext } from '../../../../../context/subscrip
|
||||
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
|
||||
import isInFreeTrial from '../../../../../util/is-in-free-trial'
|
||||
import { RecurlySubscription } from '../../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../../../types/subscription/dashboard/subscription'
|
||||
|
||||
export function ChangeToGroupPlan() {
|
||||
const { t } = useTranslation()
|
||||
const { handleOpenModal, personalSubscription } =
|
||||
useSubscriptionDashboardContext()
|
||||
|
||||
// TODO: Better way to get RecurlySubscription/trialEndsAt
|
||||
// TODO: Better way to get PaidSubscription/trialEndsAt
|
||||
const subscription =
|
||||
personalSubscription && 'recurly' in personalSubscription
|
||||
? (personalSubscription as RecurlySubscription)
|
||||
personalSubscription && 'payment' in personalSubscription
|
||||
? (personalSubscription as PaidSubscription)
|
||||
: null
|
||||
|
||||
const handleClick = () => {
|
||||
@@ -25,7 +25,7 @@ export function ChangeToGroupPlan() {
|
||||
<h2 style={{ marginTop: 0 }}>{t('looking_multiple_licenses')}</h2>
|
||||
<p style={{ margin: 0 }}>{t('reduce_costs_group_licenses')}</p>
|
||||
<br />
|
||||
{isInFreeTrial(subscription?.recurly?.trialEndsAt) ? (
|
||||
{isInFreeTrial(subscription?.payment?.trialEndsAt) ? (
|
||||
<>
|
||||
<OLTooltip
|
||||
id="disabled-change-to-group-plan"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useTranslation, Trans } from 'react-i18next'
|
||||
import { RecurlySubscription } from '../../../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PriceForDisplayData } from '../../../../../../../../../../types/subscription/plan'
|
||||
import { postJSON } from '../../../../../../../../infrastructure/fetch-json'
|
||||
import getMeta from '../../../../../../../../utils/meta'
|
||||
@@ -115,7 +115,7 @@ export function ChangeToGroupModal() {
|
||||
useContactUsModal({ autofillProjectUrl: false })
|
||||
const groupPlans = getMeta('ol-groupPlans')
|
||||
const showGroupDiscount = getMeta('ol-showGroupDiscount')
|
||||
const personalSubscription = getMeta('ol-subscription') as RecurlySubscription
|
||||
const personalSubscription = getMeta('ol-subscription') as PaidSubscription
|
||||
const [error, setError] = useState(false)
|
||||
const [inflight, setInflight] = useState(false)
|
||||
const location = useLocation()
|
||||
|
||||
@@ -12,7 +12,7 @@ import OLButton from '@/features/ui/components/ol/ol-button'
|
||||
import { postJSON } from '@/infrastructure/fetch-json'
|
||||
import { useLocation } from '@/shared/hooks/use-location'
|
||||
import OLNotification from '@/features/ui/components/ol/ol-notification'
|
||||
import { RecurlySubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
|
||||
export function ConfirmUnpauseSubscriptionModal() {
|
||||
const modalId: SubscriptionDashModalIds = 'unpause-subscription'
|
||||
@@ -22,7 +22,7 @@ export function ConfirmUnpauseSubscriptionModal() {
|
||||
const { handleCloseModal, modalIdShown, personalSubscription } =
|
||||
useSubscriptionDashboardContext()
|
||||
const location = useLocation()
|
||||
const subscription = personalSubscription as RecurlySubscription
|
||||
const subscription = personalSubscription as PaidSubscription
|
||||
|
||||
async function handleConfirmUnpause() {
|
||||
setError(false)
|
||||
@@ -70,7 +70,7 @@ export function ConfirmUnpauseSubscriptionModal() {
|
||||
<Trans
|
||||
i18nKey="lets_get_those_premium_features"
|
||||
values={{
|
||||
paymentAmount: subscription.recurly.displayPrice,
|
||||
paymentAmount: subscription.payment.displayPrice,
|
||||
}}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useSubscriptionDashboardContext } from '@/features/subscription/context/subscription-dashboard-context'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { RecurlySubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useLocation } from '@/shared/hooks/use-location'
|
||||
|
||||
@@ -17,7 +17,7 @@ export function FlashMessage() {
|
||||
'flash'
|
||||
) as FlashMessageName
|
||||
)
|
||||
const subscription = personalSubscription as RecurlySubscription
|
||||
const subscription = personalSubscription as PaidSubscription
|
||||
useEffect(() => {
|
||||
// clear any flash message IDs so they only show once
|
||||
if (location.toString()) {
|
||||
@@ -36,7 +36,7 @@ export function FlashMessage() {
|
||||
<Trans
|
||||
i18nKey="your_subscription_will_pause_on_short"
|
||||
values={{
|
||||
pauseDate: subscription.recurly.nextPaymentDueAt,
|
||||
pauseDate: subscription.payment.nextPaymentDueAt,
|
||||
}}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useTranslation, Trans } from 'react-i18next'
|
||||
import { useSubscriptionDashboardContext } from '../../../../context/subscription-dashboard-context'
|
||||
import { RecurlySubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { CancelSubscriptionButton } from './cancel-subscription-button'
|
||||
import { CancelSubscription } from './cancel-plan/cancel-subscription'
|
||||
import { ChangePlanModal } from './change-plan/modals/change-plan-modal'
|
||||
@@ -14,7 +14,7 @@ import { ConfirmUnpauseSubscriptionModal } from './confirm-unpause-modal'
|
||||
export function PausedSubscription({
|
||||
subscription,
|
||||
}: {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
@@ -67,7 +67,7 @@ export function PausedSubscription({
|
||||
|
||||
<p className="d-inline-flex flex-wrap gap-1">
|
||||
<a
|
||||
href={subscription.recurly.billingDetailsLink}
|
||||
href={subscription.payment.billingDetailsLink}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className="btn btn-secondary-info btn-secondary"
|
||||
@@ -75,7 +75,7 @@ export function PausedSubscription({
|
||||
{t('update_your_billing_details')}
|
||||
</a>{' '}
|
||||
<a
|
||||
href={subscription.recurly.accountManagementLink}
|
||||
href={subscription.payment.accountManagementLink}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className="btn btn-secondary-info btn-secondary"
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { Trans } from 'react-i18next'
|
||||
import { RecurlySubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PendingRecurlyPlan } from '../../../../../../../../types/subscription/plan'
|
||||
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PendingPaymentProviderPlan } from '../../../../../../../../types/subscription/plan'
|
||||
import { AI_ADD_ON_CODE, ADD_ON_NAME } from '../../../../data/add-on-codes'
|
||||
|
||||
export function PendingPlanChange({
|
||||
subscription,
|
||||
}: {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
}) {
|
||||
if (!subscription.pendingPlan) return null
|
||||
|
||||
const pendingPlan = subscription.pendingPlan as PendingRecurlyPlan
|
||||
const pendingPlan = subscription.pendingPlan as PendingPaymentProviderPlan
|
||||
|
||||
const hasAiAddon = subscription.addOns?.some(
|
||||
addOn => addOn.addOnCode === AI_ADD_ON_CODE
|
||||
@@ -21,9 +21,9 @@ export function PendingPlanChange({
|
||||
!pendingPlan.addOns?.some(addOn => addOn.code === AI_ADD_ON_CODE)
|
||||
|
||||
const pendingAdditionalLicenses =
|
||||
(subscription.recurly.pendingAdditionalLicenses &&
|
||||
subscription.recurly.pendingAdditionalLicenses > 0) ||
|
||||
subscription.recurly.additionalLicenses > 0
|
||||
(subscription.payment.pendingAdditionalLicenses &&
|
||||
subscription.payment.pendingAdditionalLicenses > 0) ||
|
||||
subscription.payment.additionalLicenses > 0
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -49,8 +49,8 @@ export function PendingPlanChange({
|
||||
i18nKey="pending_additional_licenses"
|
||||
values={{
|
||||
pendingAdditionalLicenses:
|
||||
subscription.recurly.pendingAdditionalLicenses,
|
||||
pendingTotalLicenses: subscription.recurly.pendingTotalLicenses,
|
||||
subscription.payment.pendingAdditionalLicenses,
|
||||
pendingTotalLicenses: subscription.payment.pendingTotalLicenses,
|
||||
}}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Trans } from 'react-i18next'
|
||||
import { RecurlySubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
|
||||
type SubscriptionRemainderProps = {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
hideTime?: boolean
|
||||
}
|
||||
|
||||
@@ -11,13 +11,13 @@ function SubscriptionRemainder({
|
||||
hideTime,
|
||||
}: SubscriptionRemainderProps) {
|
||||
const stillInATrial =
|
||||
subscription.recurly.trialEndsAtFormatted &&
|
||||
subscription.recurly.trialEndsAt &&
|
||||
new Date(subscription.recurly.trialEndsAt).getTime() > Date.now()
|
||||
subscription.payment.trialEndsAtFormatted &&
|
||||
subscription.payment.trialEndsAt &&
|
||||
new Date(subscription.payment.trialEndsAt).getTime() > Date.now()
|
||||
|
||||
const terminationDate = hideTime
|
||||
? subscription.recurly.nextPaymentDueDate
|
||||
: subscription.recurly.nextPaymentDueAt
|
||||
? subscription.payment.nextPaymentDueDate
|
||||
: subscription.payment.nextPaymentDueAt
|
||||
return stillInATrial ? (
|
||||
<Trans
|
||||
i18nKey="subscription_will_remain_active_until_end_of_trial_period_x"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useTranslation, Trans } from 'react-i18next'
|
||||
import { RecurlySubscription } from '../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../types/subscription/dashboard/subscription'
|
||||
import ReactivateSubscription from '../reactivate-subscription'
|
||||
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||
|
||||
export function CanceledSubscription({
|
||||
subscription,
|
||||
}: {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@@ -30,7 +30,7 @@ export function CanceledSubscription({
|
||||
<Trans
|
||||
i18nKey="subscription_canceled_and_terminate_on_x"
|
||||
values={{
|
||||
terminateDate: subscription.recurly.nextPaymentDueAt,
|
||||
terminateDate: subscription.payment.nextPaymentDueAt,
|
||||
}}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
@@ -42,7 +42,7 @@ export function CanceledSubscription({
|
||||
</p>
|
||||
<p>
|
||||
<OLButton
|
||||
href={subscription.recurly.accountManagementLink}
|
||||
href={subscription.payment.accountManagementLink}
|
||||
target="_blank"
|
||||
variant="secondary"
|
||||
rel="noopener noreferrer"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RecurlySubscription } from '../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../types/subscription/dashboard/subscription'
|
||||
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||
|
||||
export function ExpiredSubscription({
|
||||
subscription,
|
||||
}: {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@@ -14,7 +14,7 @@ export function ExpiredSubscription({
|
||||
<p>{t('your_subscription_has_expired')}</p>
|
||||
<p>
|
||||
<OLButton
|
||||
href={subscription.recurly.accountManagementLink}
|
||||
href={subscription.payment.accountManagementLink}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
variant="secondary"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RecurlySubscription } from '../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../types/subscription/dashboard/subscription'
|
||||
|
||||
type PriceExceptionsProps = {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
}
|
||||
|
||||
export function PriceExceptions({ subscription }: PriceExceptionsProps) {
|
||||
const { t } = useTranslation()
|
||||
const { activeCoupons } = subscription.recurly
|
||||
const { activeCoupons } = subscription.payment
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
ADD_ON_NAME,
|
||||
isStandaloneAiPlanCode,
|
||||
} from '../../data/add-on-codes'
|
||||
import { RecurlySubscription } from '../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../types/subscription/dashboard/subscription'
|
||||
|
||||
function SuccessfulSubscription() {
|
||||
const { t } = useTranslation()
|
||||
@@ -21,7 +21,7 @@ function SuccessfulSubscription() {
|
||||
const postCheckoutRedirect = getMeta('ol-postCheckoutRedirect')
|
||||
const { appName, adminEmail } = getMeta('ol-ExposedSettings')
|
||||
|
||||
if (!subscription || !('recurly' in subscription)) return null
|
||||
if (!subscription || !('payment' in subscription)) return null
|
||||
|
||||
const onAiStandalonePlan = isStandaloneAiPlanCode(subscription.planCode)
|
||||
|
||||
@@ -37,15 +37,15 @@ function SuccessfulSubscription() {
|
||||
type="success"
|
||||
content={
|
||||
<>
|
||||
{subscription.recurly.trialEndsAt && (
|
||||
{subscription.payment.trialEndsAt && (
|
||||
<>
|
||||
<p>
|
||||
<Trans
|
||||
i18nKey="next_payment_of_x_collectected_on_y"
|
||||
values={{
|
||||
paymentAmmount: subscription.recurly.displayPrice,
|
||||
paymentAmmount: subscription.payment.displayPrice,
|
||||
collectionDate:
|
||||
subscription.recurly.nextPaymentDueAt,
|
||||
subscription.payment.nextPaymentDueAt,
|
||||
}}
|
||||
shouldUnescape
|
||||
tOptions={{ interpolation: { escapeValue: true } }}
|
||||
@@ -126,7 +126,7 @@ function ThankYouSection({
|
||||
subscription,
|
||||
onAiStandalonePlan,
|
||||
}: {
|
||||
subscription: RecurlySubscription
|
||||
subscription: PaidSubscription
|
||||
onAiStandalonePlan: boolean
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
CustomSubscription,
|
||||
ManagedGroupSubscription,
|
||||
MemberGroupSubscription,
|
||||
RecurlySubscription,
|
||||
PaidSubscription,
|
||||
} from '../../../../../types/subscription/dashboard/subscription'
|
||||
import {
|
||||
Plan,
|
||||
@@ -52,7 +52,7 @@ type SubscriptionDashboardContextValue = {
|
||||
managedPublishers: Publisher[]
|
||||
updateManagedInstitution: (institution: ManagedInstitution) => void
|
||||
modalIdShown?: SubscriptionDashModalIds
|
||||
personalSubscription?: RecurlySubscription | CustomSubscription
|
||||
personalSubscription?: PaidSubscription | CustomSubscription
|
||||
hasSubscription: boolean
|
||||
plans: Plan[]
|
||||
planCodeToChangeTo?: string
|
||||
@@ -136,21 +136,21 @@ export function SubscriptionDashboardProvider({
|
||||
)
|
||||
|
||||
const hasValidActiveSubscription = Boolean(
|
||||
['active', 'canceled'].includes(personalSubscription?.recurly?.state) ||
|
||||
['active', 'canceled'].includes(personalSubscription?.payment?.state) ||
|
||||
institutionMemberships?.length > 0 ||
|
||||
memberGroupSubscriptions?.length > 0
|
||||
)
|
||||
|
||||
const getFormattedRenewalDate = useCallback(() => {
|
||||
if (
|
||||
!personalSubscription.recurly.pausedAt ||
|
||||
!personalSubscription.recurly.remainingPauseCycles
|
||||
!personalSubscription.payment.pausedAt ||
|
||||
!personalSubscription.payment.remainingPauseCycles
|
||||
) {
|
||||
return personalSubscription.recurly.nextPaymentDueAt
|
||||
return personalSubscription.payment.nextPaymentDueAt
|
||||
}
|
||||
const pausedDate = new Date(personalSubscription.recurly.pausedAt)
|
||||
const pausedDate = new Date(personalSubscription.payment.pausedAt)
|
||||
pausedDate.setMonth(
|
||||
pausedDate.getMonth() + personalSubscription.recurly.remainingPauseCycles
|
||||
pausedDate.getMonth() + personalSubscription.payment.remainingPauseCycles
|
||||
)
|
||||
return formatTime(pausedDate, 'MMMM Do, YYYY')
|
||||
}, [personalSubscription])
|
||||
@@ -167,9 +167,9 @@ export function SubscriptionDashboardProvider({
|
||||
if (
|
||||
isRecurlyLoaded() &&
|
||||
plansWithoutDisplayPrice &&
|
||||
personalSubscription?.recurly
|
||||
personalSubscription?.payment
|
||||
) {
|
||||
const { currency, taxRate } = personalSubscription.recurly
|
||||
const { currency, taxRate } = personalSubscription.payment
|
||||
const fetchPlansDisplayPrices = async () => {
|
||||
for (const plan of plansWithoutDisplayPrice) {
|
||||
try {
|
||||
@@ -203,11 +203,11 @@ export function SubscriptionDashboardProvider({
|
||||
groupPlanToChangeToCode &&
|
||||
groupPlanToChangeToSize &&
|
||||
groupPlanToChangeToUsage &&
|
||||
personalSubscription?.recurly
|
||||
personalSubscription?.payment
|
||||
) {
|
||||
setQueryingGroupPlanToChangeToPrice(true)
|
||||
|
||||
const { currency, taxRate } = personalSubscription.recurly
|
||||
const { currency, taxRate } = personalSubscription.payment
|
||||
const fetchGroupDisplayPrice = async () => {
|
||||
setGroupPlanToChangeToPriceError(false)
|
||||
let priceData
|
||||
|
||||
@@ -83,7 +83,7 @@ describe('<PersonalSubscription />', function () {
|
||||
'Your subscription has been canceled and will terminate on',
|
||||
{ exact: false }
|
||||
)
|
||||
screen.getByText(canceledSubscription.recurly!.nextPaymentDueAt, {
|
||||
screen.getByText(canceledSubscription.payment!.nextPaymentDueAt, {
|
||||
exact: false,
|
||||
})
|
||||
|
||||
@@ -134,7 +134,7 @@ describe('<PersonalSubscription />', function () {
|
||||
{},
|
||||
JSON.parse(JSON.stringify(annualActiveSubscription))
|
||||
)
|
||||
withStateDeleted.recurly.state = undefined
|
||||
withStateDeleted.payment.state = undefined
|
||||
renderWithSubscriptionDashContext(<PersonalSubscription />, {
|
||||
metaTags: [{ name: 'ol-subscription', value: withStateDeleted }],
|
||||
})
|
||||
@@ -194,7 +194,7 @@ describe('<PersonalSubscription />', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('shows different recurly email address section', async function () {
|
||||
it('shows different payment email address section', async function () {
|
||||
fetchMock.post('/user/subscription/account/email', 200)
|
||||
const usersEmail = 'foo@example.com'
|
||||
renderWithSubscriptionDashContext(<PersonalSubscription />, {
|
||||
@@ -208,7 +208,7 @@ describe('<PersonalSubscription />', function () {
|
||||
/your billing email address is currently/i
|
||||
).textContent
|
||||
expect(billingText).to.contain(
|
||||
`Your billing email address is currently ${annualActiveSubscription.recurly.accountEmail}.` +
|
||||
`Your billing email address is currently ${annualActiveSubscription.payment.accountEmail}.` +
|
||||
` If needed you can update your billing address to ${usersEmail}`
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { expect } from 'chai'
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/react'
|
||||
import * as eventTracking from '@/infrastructure/event-tracking'
|
||||
import { RecurlySubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
|
||||
import {
|
||||
annualActiveSubscription,
|
||||
groupActiveSubscription,
|
||||
@@ -36,7 +36,7 @@ describe('<ActiveSubscription />', function () {
|
||||
sendMBSpy.restore()
|
||||
})
|
||||
|
||||
function expectedInActiveSubscription(subscription: RecurlySubscription) {
|
||||
function expectedInActiveSubscription(subscription: PaidSubscription) {
|
||||
// sentence broken up by bolding
|
||||
screen.getByText('You are currently subscribed to the', { exact: false })
|
||||
screen.getByText(subscription.plan.name, { exact: false })
|
||||
@@ -45,11 +45,11 @@ describe('<ActiveSubscription />', function () {
|
||||
|
||||
// sentence broken up by bolding
|
||||
screen.getByText('The next payment of', { exact: false })
|
||||
screen.getByText(subscription.recurly.displayPrice, {
|
||||
screen.getByText(subscription.payment.displayPrice, {
|
||||
exact: false,
|
||||
})
|
||||
screen.getByText('will be collected on', { exact: false })
|
||||
const dates = screen.getAllByText(subscription.recurly.nextPaymentDueAt, {
|
||||
const dates = screen.getAllByText(subscription.payment.nextPaymentDueAt, {
|
||||
exact: false,
|
||||
})
|
||||
expect(dates.length).to.equal(2)
|
||||
@@ -110,7 +110,7 @@ describe('<ActiveSubscription />', function () {
|
||||
JSON.parse(JSON.stringify(annualActiveSubscription))
|
||||
)
|
||||
|
||||
activePastDueSubscription.recurly.hasPastDueInvoice = true
|
||||
activePastDueSubscription.payment.hasPastDueInvoice = true
|
||||
|
||||
renderActiveSubscription(activePastDueSubscription)
|
||||
|
||||
@@ -126,14 +126,14 @@ describe('<ActiveSubscription />', function () {
|
||||
})
|
||||
|
||||
screen.getByText(
|
||||
groupActiveSubscriptionWithPendingLicenseChange.recurly
|
||||
groupActiveSubscriptionWithPendingLicenseChange.payment
|
||||
.pendingAdditionalLicenses!
|
||||
)
|
||||
|
||||
screen.getByText('additional license(s) for a total of', { exact: false })
|
||||
|
||||
screen.getByText(
|
||||
groupActiveSubscriptionWithPendingLicenseChange.recurly
|
||||
groupActiveSubscriptionWithPendingLicenseChange.payment
|
||||
.pendingTotalLicenses!
|
||||
)
|
||||
|
||||
@@ -146,10 +146,10 @@ describe('<ActiveSubscription />', function () {
|
||||
|
||||
it('shows the pending license change message when plan change is not pending', function () {
|
||||
const subscription = Object.assign({}, groupActiveSubscription)
|
||||
subscription.recurly.additionalLicenses = 4
|
||||
subscription.recurly.totalLicenses =
|
||||
subscription.recurly.totalLicenses +
|
||||
subscription.recurly.additionalLicenses
|
||||
subscription.payment.additionalLicenses = 4
|
||||
subscription.payment.totalLicenses =
|
||||
subscription.payment.totalLicenses +
|
||||
subscription.payment.additionalLicenses
|
||||
|
||||
renderActiveSubscription(subscription)
|
||||
|
||||
@@ -157,11 +157,11 @@ describe('<ActiveSubscription />', function () {
|
||||
exact: false,
|
||||
})
|
||||
|
||||
screen.getByText(subscription.recurly.additionalLicenses)
|
||||
screen.getByText(subscription.payment.additionalLicenses)
|
||||
|
||||
screen.getByText('additional license(s) for a total of', { exact: false })
|
||||
|
||||
screen.getByText(subscription.recurly.totalLicenses)
|
||||
screen.getByText(subscription.payment.totalLicenses)
|
||||
})
|
||||
|
||||
it('shows when trial ends and first payment collected and when subscription would become inactive if cancelled', function () {
|
||||
@@ -169,14 +169,14 @@ describe('<ActiveSubscription />', function () {
|
||||
screen.getByText('You’re on a free trial which ends on', { exact: false })
|
||||
|
||||
const endDate = screen.getAllByText(
|
||||
trialSubscription.recurly.trialEndsAtFormatted!
|
||||
trialSubscription.payment.trialEndsAtFormatted!
|
||||
)
|
||||
expect(endDate.length).to.equal(3)
|
||||
})
|
||||
|
||||
it('shows current discounts', function () {
|
||||
const subscriptionWithActiveCoupons = cloneDeep(annualActiveSubscription)
|
||||
subscriptionWithActiveCoupons.recurly.activeCoupons = [
|
||||
subscriptionWithActiveCoupons.payment.activeCoupons = [
|
||||
{
|
||||
name: 'fake coupon name',
|
||||
code: 'fake-coupon',
|
||||
@@ -188,7 +188,7 @@ describe('<ActiveSubscription />', function () {
|
||||
/this does not include your current discounts, which will be applied automatically before your next payment/i
|
||||
)
|
||||
screen.getByText(
|
||||
subscriptionWithActiveCoupons.recurly.activeCoupons[0].name
|
||||
subscriptionWithActiveCoupons.payment.activeCoupons[0].name
|
||||
)
|
||||
})
|
||||
|
||||
@@ -225,7 +225,7 @@ describe('<ActiveSubscription />', function () {
|
||||
{ exact: false }
|
||||
)
|
||||
const dates = screen.getAllByText(
|
||||
annualActiveSubscription.recurly.nextPaymentDueAt,
|
||||
annualActiveSubscription.payment.nextPaymentDueAt,
|
||||
{
|
||||
exact: false,
|
||||
}
|
||||
@@ -244,7 +244,7 @@ describe('<ActiveSubscription />', function () {
|
||||
{ exact: false }
|
||||
)
|
||||
const dates = screen.getAllByText(
|
||||
trialSubscription.recurly.trialEndsAtFormatted!
|
||||
trialSubscription.payment.trialEndsAtFormatted!
|
||||
)
|
||||
expect(dates.length).to.equal(3)
|
||||
const button = screen.getByRole('button', {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
CustomSubscription,
|
||||
GroupSubscription,
|
||||
RecurlySubscription,
|
||||
PaidSubscription,
|
||||
} from '../../../../../types/subscription/dashboard/subscription'
|
||||
import dateformat from 'dateformat'
|
||||
|
||||
@@ -15,7 +15,7 @@ const sevenDaysFromTodayFormatted = dateformat(
|
||||
'dS mmmm yyyy'
|
||||
)
|
||||
|
||||
export const annualActiveSubscription: RecurlySubscription = {
|
||||
export const annualActiveSubscription: PaidSubscription = {
|
||||
manager_ids: ['abc123'],
|
||||
member_ids: [],
|
||||
invited_emails: [],
|
||||
@@ -33,7 +33,7 @@ export const annualActiveSubscription: RecurlySubscription = {
|
||||
annual: true,
|
||||
featureDescription: [],
|
||||
},
|
||||
recurly: {
|
||||
payment: {
|
||||
taxRate: 0,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink: '/user/subscription/recurly/account-management',
|
||||
@@ -55,7 +55,7 @@ export const annualActiveSubscription: RecurlySubscription = {
|
||||
},
|
||||
}
|
||||
|
||||
export const annualActiveSubscriptionEuro: RecurlySubscription = {
|
||||
export const annualActiveSubscriptionEuro: PaidSubscription = {
|
||||
manager_ids: ['abc123'],
|
||||
member_ids: [],
|
||||
invited_emails: [],
|
||||
@@ -73,7 +73,7 @@ export const annualActiveSubscriptionEuro: RecurlySubscription = {
|
||||
annual: true,
|
||||
featureDescription: [],
|
||||
},
|
||||
recurly: {
|
||||
payment: {
|
||||
taxRate: 0.24,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink: '/user/subscription/recurly/account-management',
|
||||
@@ -95,7 +95,7 @@ export const annualActiveSubscriptionEuro: RecurlySubscription = {
|
||||
},
|
||||
}
|
||||
|
||||
export const annualActiveSubscriptionPro: RecurlySubscription = {
|
||||
export const annualActiveSubscriptionPro: PaidSubscription = {
|
||||
manager_ids: ['abc123'],
|
||||
member_ids: [],
|
||||
invited_emails: [],
|
||||
@@ -112,7 +112,7 @@ export const annualActiveSubscriptionPro: RecurlySubscription = {
|
||||
price_in_cents: 4500,
|
||||
featureDescription: [],
|
||||
},
|
||||
recurly: {
|
||||
payment: {
|
||||
taxRate: 0,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink: '/user/subscription/recurly/account-management',
|
||||
@@ -134,7 +134,7 @@ export const annualActiveSubscriptionPro: RecurlySubscription = {
|
||||
},
|
||||
}
|
||||
|
||||
export const pastDueExpiredSubscription: RecurlySubscription = {
|
||||
export const pastDueExpiredSubscription: PaidSubscription = {
|
||||
manager_ids: ['abc123'],
|
||||
member_ids: [],
|
||||
invited_emails: [],
|
||||
@@ -152,7 +152,7 @@ export const pastDueExpiredSubscription: RecurlySubscription = {
|
||||
annual: true,
|
||||
featureDescription: [],
|
||||
},
|
||||
recurly: {
|
||||
payment: {
|
||||
taxRate: 0,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink: '/user/subscription/recurly/account-management',
|
||||
@@ -174,7 +174,7 @@ export const pastDueExpiredSubscription: RecurlySubscription = {
|
||||
},
|
||||
}
|
||||
|
||||
export const canceledSubscription: RecurlySubscription = {
|
||||
export const canceledSubscription: PaidSubscription = {
|
||||
manager_ids: ['abc123'],
|
||||
member_ids: [],
|
||||
invited_emails: [],
|
||||
@@ -192,7 +192,7 @@ export const canceledSubscription: RecurlySubscription = {
|
||||
annual: true,
|
||||
featureDescription: [],
|
||||
},
|
||||
recurly: {
|
||||
payment: {
|
||||
taxRate: 0,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink: '/user/subscription/recurly/account-management',
|
||||
@@ -214,7 +214,7 @@ export const canceledSubscription: RecurlySubscription = {
|
||||
},
|
||||
}
|
||||
|
||||
export const pendingSubscriptionChange: RecurlySubscription = {
|
||||
export const pendingSubscriptionChange: PaidSubscription = {
|
||||
manager_ids: ['abc123'],
|
||||
member_ids: [],
|
||||
invited_emails: [],
|
||||
@@ -232,7 +232,7 @@ export const pendingSubscriptionChange: RecurlySubscription = {
|
||||
annual: true,
|
||||
featureDescription: [],
|
||||
},
|
||||
recurly: {
|
||||
payment: {
|
||||
taxRate: 0,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink: '/user/subscription/recurly/account-management',
|
||||
@@ -283,7 +283,7 @@ export const groupActiveSubscription: GroupSubscription = {
|
||||
membersLimit: 10,
|
||||
membersLimitAddOn: 'additional-license',
|
||||
},
|
||||
recurly: {
|
||||
payment: {
|
||||
taxRate: 0,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink: '/user/subscription/recurly/account-management',
|
||||
@@ -328,7 +328,7 @@ export const groupActiveSubscriptionWithPendingLicenseChange: GroupSubscription
|
||||
membersLimit: 10,
|
||||
membersLimitAddOn: 'additional-license',
|
||||
},
|
||||
recurly: {
|
||||
payment: {
|
||||
taxRate: 0,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink: '/user/subscription/recurly/account-management',
|
||||
@@ -362,7 +362,7 @@ export const groupActiveSubscriptionWithPendingLicenseChange: GroupSubscription
|
||||
},
|
||||
}
|
||||
|
||||
export const trialSubscription: RecurlySubscription = {
|
||||
export const trialSubscription: PaidSubscription = {
|
||||
manager_ids: ['abc123'],
|
||||
member_ids: [],
|
||||
invited_emails: [],
|
||||
@@ -380,7 +380,7 @@ export const trialSubscription: RecurlySubscription = {
|
||||
featureDescription: [],
|
||||
hideFromUsers: true,
|
||||
},
|
||||
recurly: {
|
||||
payment: {
|
||||
taxRate: 0,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink: '/user/subscription/recurly/account-management',
|
||||
@@ -423,7 +423,7 @@ export const customSubscription: CustomSubscription = {
|
||||
customAccount: true,
|
||||
}
|
||||
|
||||
export const trialCollaboratorSubscription: RecurlySubscription = {
|
||||
export const trialCollaboratorSubscription: PaidSubscription = {
|
||||
manager_ids: ['abc123'],
|
||||
member_ids: [],
|
||||
invited_emails: [],
|
||||
@@ -441,7 +441,7 @@ export const trialCollaboratorSubscription: RecurlySubscription = {
|
||||
featureDescription: [],
|
||||
hideFromUsers: true,
|
||||
},
|
||||
recurly: {
|
||||
payment: {
|
||||
taxRate: 0,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink: '/user/subscription/recurly/account-management',
|
||||
@@ -463,7 +463,7 @@ export const trialCollaboratorSubscription: RecurlySubscription = {
|
||||
},
|
||||
}
|
||||
|
||||
export const monthlyActiveCollaborator: RecurlySubscription = {
|
||||
export const monthlyActiveCollaborator: PaidSubscription = {
|
||||
manager_ids: ['abc123'],
|
||||
member_ids: [],
|
||||
invited_emails: [],
|
||||
@@ -480,7 +480,7 @@ export const monthlyActiveCollaborator: RecurlySubscription = {
|
||||
price_in_cents: 212300900,
|
||||
featureDescription: [],
|
||||
},
|
||||
recurly: {
|
||||
payment: {
|
||||
taxRate: 0,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink: '/user/subscription/recurly/account-management',
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { ActiveSubscription } from '../../../../../frontend/js/features/subscription/components/dashboard/states/active/active'
|
||||
import { RecurlySubscription } from '../../../../../types/subscription/dashboard/subscription'
|
||||
import { PaidSubscription } from '../../../../../types/subscription/dashboard/subscription'
|
||||
import { groupPlans, plans } from '../fixtures/plans'
|
||||
import { renderWithSubscriptionDashContext } from './render-with-subscription-dash-context'
|
||||
import { MetaTag } from '@/utils/meta'
|
||||
import { CurrencyCode } from '../../../../../types/subscription/currency'
|
||||
|
||||
export function renderActiveSubscription(
|
||||
subscription: RecurlySubscription,
|
||||
subscription: PaidSubscription,
|
||||
tags: MetaTag[] = [],
|
||||
currencyCode?: CurrencyCode
|
||||
) {
|
||||
|
||||
@@ -4,7 +4,7 @@ const sinon = require('sinon')
|
||||
const { ObjectId } = require('mongodb-legacy')
|
||||
const {
|
||||
AI_ADD_ON_CODE,
|
||||
} = require('../../../../app/src/Features/Subscription/RecurlyEntities')
|
||||
} = require('../../../../app/src/Features/Subscription/PaymentProviderEntities')
|
||||
|
||||
const MODULE_PATH = '../../../../app/src/Features/Subscription/FeaturesUpdater'
|
||||
|
||||
|
||||
@@ -5,16 +5,17 @@ const { expect } = require('chai')
|
||||
const Errors = require('../../../../app/src/Features/Subscription/Errors')
|
||||
const {
|
||||
AI_ADD_ON_CODE,
|
||||
RecurlySubscriptionChangeRequest,
|
||||
RecurlySubscriptionChange,
|
||||
RecurlySubscription,
|
||||
RecurlySubscriptionAddOnUpdate,
|
||||
} = require('../../../../app/src/Features/Subscription/RecurlyEntities')
|
||||
PaymentProviderSubscriptionChangeRequest,
|
||||
PaymentProviderSubscriptionChange,
|
||||
PaymentProviderSubscription,
|
||||
PaymentProviderSubscriptionAddOnUpdate,
|
||||
} = require('../../../../app/src/Features/Subscription/PaymentProviderEntities')
|
||||
|
||||
const MODULE_PATH = '../../../../app/src/Features/Subscription/RecurlyEntities'
|
||||
const MODULE_PATH =
|
||||
'../../../../app/src/Features/Subscription/PaymentProviderEntities'
|
||||
|
||||
describe('RecurlyEntities', function () {
|
||||
describe('RecurlySubscription', function () {
|
||||
describe('PaymentProviderEntities', function () {
|
||||
describe('PaymentProviderSubscription', function () {
|
||||
beforeEach(function () {
|
||||
this.Settings = {
|
||||
plans: [
|
||||
@@ -26,7 +27,7 @@ describe('RecurlyEntities', function () {
|
||||
features: [],
|
||||
}
|
||||
|
||||
this.RecurlyEntities = SandboxedModule.require(MODULE_PATH, {
|
||||
this.PaymentProviderEntities = SandboxedModule.require(MODULE_PATH, {
|
||||
requires: {
|
||||
'@overleaf/settings': this.Settings,
|
||||
'./Errors': Errors,
|
||||
@@ -36,15 +37,17 @@ describe('RecurlyEntities', function () {
|
||||
|
||||
describe('with add-ons', function () {
|
||||
beforeEach(function () {
|
||||
const { RecurlySubscription, RecurlySubscriptionAddOn } =
|
||||
this.RecurlyEntities
|
||||
this.addOn = new RecurlySubscriptionAddOn({
|
||||
const {
|
||||
PaymentProviderSubscription,
|
||||
PaymentProviderSubscriptionAddOn,
|
||||
} = this.PaymentProviderEntities
|
||||
this.addOn = new PaymentProviderSubscriptionAddOn({
|
||||
code: 'add-on-code',
|
||||
name: 'My Add-On',
|
||||
quantity: 1,
|
||||
unitPrice: 2,
|
||||
})
|
||||
this.subscription = new RecurlySubscription({
|
||||
this.subscription = new PaymentProviderSubscription({
|
||||
id: 'subscription-id',
|
||||
userId: 'user-id',
|
||||
planCode: 'regular-plan',
|
||||
@@ -71,11 +74,12 @@ describe('RecurlyEntities', function () {
|
||||
|
||||
describe('getRequestForPlanChange()', function () {
|
||||
it('returns a change request for upgrades', function () {
|
||||
const { RecurlySubscriptionChangeRequest } = this.RecurlyEntities
|
||||
const { PaymentProviderSubscriptionChangeRequest } =
|
||||
this.PaymentProviderEntities
|
||||
const changeRequest =
|
||||
this.subscription.getRequestForPlanChange('premium-plan')
|
||||
expect(changeRequest).to.deep.equal(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
planCode: 'premium-plan',
|
||||
@@ -84,11 +88,12 @@ describe('RecurlyEntities', function () {
|
||||
})
|
||||
|
||||
it('returns a change request for downgrades', function () {
|
||||
const { RecurlySubscriptionChangeRequest } = this.RecurlyEntities
|
||||
const { PaymentProviderSubscriptionChangeRequest } =
|
||||
this.PaymentProviderEntities
|
||||
const changeRequest =
|
||||
this.subscription.getRequestForPlanChange('cheap-plan')
|
||||
expect(changeRequest).to.deep.equal(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'term_end',
|
||||
planCode: 'cheap-plan',
|
||||
@@ -97,17 +102,18 @@ describe('RecurlyEntities', function () {
|
||||
})
|
||||
|
||||
it('preserves the AI add-on on upgrades', function () {
|
||||
const { RecurlySubscriptionChangeRequest } = this.RecurlyEntities
|
||||
const { PaymentProviderSubscriptionChangeRequest } =
|
||||
this.PaymentProviderEntities
|
||||
this.addOn.code = AI_ADD_ON_CODE
|
||||
const changeRequest =
|
||||
this.subscription.getRequestForPlanChange('premium-plan')
|
||||
expect(changeRequest).to.deep.equal(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
planCode: 'premium-plan',
|
||||
addOnUpdates: [
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: AI_ADD_ON_CODE,
|
||||
quantity: 1,
|
||||
}),
|
||||
@@ -117,17 +123,18 @@ describe('RecurlyEntities', function () {
|
||||
})
|
||||
|
||||
it('preserves the AI add-on on downgrades', function () {
|
||||
const { RecurlySubscriptionChangeRequest } = this.RecurlyEntities
|
||||
const { PaymentProviderSubscriptionChangeRequest } =
|
||||
this.PaymentProviderEntities
|
||||
this.addOn.code = AI_ADD_ON_CODE
|
||||
const changeRequest =
|
||||
this.subscription.getRequestForPlanChange('cheap-plan')
|
||||
expect(changeRequest).to.deep.equal(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'term_end',
|
||||
planCode: 'cheap-plan',
|
||||
addOnUpdates: [
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: AI_ADD_ON_CODE,
|
||||
quantity: 1,
|
||||
}),
|
||||
@@ -137,18 +144,19 @@ describe('RecurlyEntities', function () {
|
||||
})
|
||||
|
||||
it('preserves the AI add-on on upgrades from the standalone AI plan', function () {
|
||||
const { RecurlySubscriptionChangeRequest } = this.RecurlyEntities
|
||||
const { PaymentProviderSubscriptionChangeRequest } =
|
||||
this.PaymentProviderEntities
|
||||
this.subscription.planCode = 'assistant-annual'
|
||||
this.subscription.addOns = []
|
||||
const changeRequest =
|
||||
this.subscription.getRequestForPlanChange('cheap-plan')
|
||||
expect(changeRequest).to.deep.equal(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'term_end',
|
||||
planCode: 'cheap-plan',
|
||||
addOnUpdates: [
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: AI_ADD_ON_CODE,
|
||||
quantity: 1,
|
||||
}),
|
||||
@@ -161,22 +169,22 @@ describe('RecurlyEntities', function () {
|
||||
describe('getRequestForAddOnPurchase()', function () {
|
||||
it('returns a change request', function () {
|
||||
const {
|
||||
RecurlySubscriptionChangeRequest,
|
||||
RecurlySubscriptionAddOnUpdate,
|
||||
} = this.RecurlyEntities
|
||||
PaymentProviderSubscriptionChangeRequest,
|
||||
PaymentProviderSubscriptionAddOnUpdate,
|
||||
} = this.PaymentProviderEntities
|
||||
const changeRequest =
|
||||
this.subscription.getRequestForAddOnPurchase('another-add-on')
|
||||
expect(changeRequest).to.deep.equal(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
addOnUpdates: [
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: this.addOn.code,
|
||||
quantity: this.addOn.quantity,
|
||||
unitPrice: this.addOn.unitPrice,
|
||||
}),
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: 'another-add-on',
|
||||
quantity: 1,
|
||||
}),
|
||||
@@ -187,9 +195,9 @@ describe('RecurlyEntities', function () {
|
||||
|
||||
it('returns a change request with quantity and unit price specified', function () {
|
||||
const {
|
||||
RecurlySubscriptionChangeRequest,
|
||||
RecurlySubscriptionAddOnUpdate,
|
||||
} = this.RecurlyEntities
|
||||
PaymentProviderSubscriptionChangeRequest,
|
||||
PaymentProviderSubscriptionAddOnUpdate,
|
||||
} = this.PaymentProviderEntities
|
||||
const quantity = 5
|
||||
const unitPrice = 10
|
||||
const changeRequest = this.subscription.getRequestForAddOnPurchase(
|
||||
@@ -198,16 +206,16 @@ describe('RecurlyEntities', function () {
|
||||
unitPrice
|
||||
)
|
||||
expect(changeRequest).to.deep.equal(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
addOnUpdates: [
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: this.addOn.code,
|
||||
quantity: this.addOn.quantity,
|
||||
unitPrice: this.addOn.unitPrice,
|
||||
}),
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: 'another-add-on',
|
||||
quantity,
|
||||
unitPrice,
|
||||
@@ -227,20 +235,20 @@ describe('RecurlyEntities', function () {
|
||||
describe('getRequestForAddOnUpdate()', function () {
|
||||
it('returns a change request', function () {
|
||||
const {
|
||||
RecurlySubscriptionChangeRequest,
|
||||
RecurlySubscriptionAddOnUpdate,
|
||||
} = this.RecurlyEntities
|
||||
PaymentProviderSubscriptionChangeRequest,
|
||||
PaymentProviderSubscriptionAddOnUpdate,
|
||||
} = this.PaymentProviderEntities
|
||||
const newQuantity = 2
|
||||
const changeRequest = this.subscription.getRequestForAddOnUpdate(
|
||||
'add-on-code',
|
||||
newQuantity
|
||||
)
|
||||
expect(changeRequest).to.deep.equal(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
addOnUpdates: [
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: this.addOn.code,
|
||||
quantity: newQuantity,
|
||||
unitPrice: this.addOn.unitPrice,
|
||||
@@ -263,7 +271,7 @@ describe('RecurlyEntities', function () {
|
||||
this.addOn.code
|
||||
)
|
||||
expect(changeRequest).to.deep.equal(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'term_end',
|
||||
addOnUpdates: [],
|
||||
@@ -283,13 +291,13 @@ describe('RecurlyEntities', function () {
|
||||
const changeRequest =
|
||||
this.subscription.getRequestForGroupPlanUpgrade('test_plan_code')
|
||||
const addOns = [
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: 'add-on-code',
|
||||
quantity: 1,
|
||||
}),
|
||||
]
|
||||
expect(changeRequest).to.deep.equal(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
addOnUpdates: addOns,
|
||||
@@ -301,8 +309,8 @@ describe('RecurlyEntities', function () {
|
||||
|
||||
describe('without add-ons', function () {
|
||||
beforeEach(function () {
|
||||
const { RecurlySubscription } = this.RecurlyEntities
|
||||
this.subscription = new RecurlySubscription({
|
||||
const { PaymentProviderSubscription } = this.PaymentProviderEntities
|
||||
this.subscription = new PaymentProviderSubscription({
|
||||
id: 'subscription-id',
|
||||
userId: 'user-id',
|
||||
planCode: 'regular-plan',
|
||||
@@ -325,17 +333,17 @@ describe('RecurlyEntities', function () {
|
||||
describe('getRequestForAddOnPurchase()', function () {
|
||||
it('returns a change request', function () {
|
||||
const {
|
||||
RecurlySubscriptionChangeRequest,
|
||||
RecurlySubscriptionAddOnUpdate,
|
||||
} = this.RecurlyEntities
|
||||
PaymentProviderSubscriptionChangeRequest,
|
||||
PaymentProviderSubscriptionAddOnUpdate,
|
||||
} = this.PaymentProviderEntities
|
||||
const changeRequest =
|
||||
this.subscription.getRequestForAddOnPurchase('some-add-on')
|
||||
expect(changeRequest).to.deep.equal(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
addOnUpdates: [
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: 'some-add-on',
|
||||
quantity: 1,
|
||||
}),
|
||||
@@ -356,10 +364,10 @@ describe('RecurlyEntities', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('RecurlySubscriptionChange', function () {
|
||||
describe('PaymentProviderSubscriptionChange', function () {
|
||||
describe('constructor', function () {
|
||||
it('rounds the amounts when calculating the taxes', function () {
|
||||
const subscription = new RecurlySubscription({
|
||||
const subscription = new PaymentProviderSubscription({
|
||||
id: 'subscription-id',
|
||||
userId: 'user-id',
|
||||
planCode: 'premium-plan',
|
||||
@@ -374,7 +382,7 @@ describe('RecurlyEntities', function () {
|
||||
periodEnd: new Date(),
|
||||
collectionMethod: 'automatic',
|
||||
})
|
||||
const change = new RecurlySubscriptionChange({
|
||||
const change = new PaymentProviderSubscriptionChange({
|
||||
subscription,
|
||||
nextPlanCode: 'promotional-plan',
|
||||
nextPlanName: 'Promotial plan',
|
||||
@@ -2,10 +2,10 @@ const sinon = require('sinon')
|
||||
const { expect } = require('chai')
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const {
|
||||
RecurlySubscription,
|
||||
RecurlyAccount,
|
||||
RecurlyCoupon,
|
||||
} = require('../../../../app/src/Features/Subscription/RecurlyEntities')
|
||||
PaymentProviderSubscription,
|
||||
PaymentProviderAccount,
|
||||
PaymentProviderCoupon,
|
||||
} = require('../../../../app/src/Features/Subscription/PaymentProviderEntities')
|
||||
|
||||
const MODULE_PATH = '../../../../app/src/Features/Subscription/PaymentService'
|
||||
|
||||
@@ -14,7 +14,7 @@ describe('PaymentService', function () {
|
||||
this.user = {
|
||||
_id: '123456',
|
||||
}
|
||||
this.recurlySubscription = new RecurlySubscription({
|
||||
this.recurlySubscription = new PaymentProviderSubscription({
|
||||
id: 'subscription-id',
|
||||
userId: this.user._id,
|
||||
currency: 'EUR',
|
||||
@@ -30,13 +30,13 @@ describe('PaymentService', function () {
|
||||
periodEnd: new Date(),
|
||||
collectionMethod: 'automatic',
|
||||
})
|
||||
this.recurlyAccount = new RecurlyAccount({
|
||||
this.recurlyAccount = new PaymentProviderAccount({
|
||||
code: this.user._id,
|
||||
email: 'example@example.com',
|
||||
hasPastDueInvoice: true,
|
||||
})
|
||||
this.recurlyCoupons = [
|
||||
new RecurlyCoupon({
|
||||
new PaymentProviderCoupon({
|
||||
code: 'coupon-code',
|
||||
name: 'coupon name',
|
||||
description: 'coupon description',
|
||||
|
||||
@@ -3,12 +3,12 @@ const { expect } = require('chai')
|
||||
const recurly = require('recurly')
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const {
|
||||
RecurlySubscription,
|
||||
RecurlySubscriptionChangeRequest,
|
||||
RecurlySubscriptionAddOnUpdate,
|
||||
RecurlyAccount,
|
||||
RecurlyCoupon,
|
||||
} = require('../../../../app/src/Features/Subscription/RecurlyEntities')
|
||||
PaymentProviderSubscription,
|
||||
PaymentProviderSubscriptionChangeRequest,
|
||||
PaymentProviderSubscriptionAddOnUpdate,
|
||||
PaymentProviderAccount,
|
||||
PaymentProviderCoupon,
|
||||
} = require('../../../../app/src/Features/Subscription/PaymentProviderEntities')
|
||||
|
||||
const MODULE_PATH = '../../../../app/src/Features/Subscription/RecurlyClient'
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('RecurlyClient', function () {
|
||||
preTaxTotal: 2,
|
||||
}
|
||||
|
||||
this.subscription = new RecurlySubscription({
|
||||
this.subscription = new PaymentProviderSubscription({
|
||||
id: 'subscription-id',
|
||||
userId: 'user-id',
|
||||
currency: 'EUR',
|
||||
@@ -156,7 +156,7 @@ describe('RecurlyClient', function () {
|
||||
const account = await this.RecurlyClient.promises.getAccountForUserId(
|
||||
this.user._id
|
||||
)
|
||||
const expectedAccount = new RecurlyAccount({
|
||||
const expectedAccount = new PaymentProviderAccount({
|
||||
code: this.user._id,
|
||||
email: this.user.email,
|
||||
hasPastDueInvoice: false,
|
||||
@@ -226,7 +226,7 @@ describe('RecurlyClient', function () {
|
||||
const coupons =
|
||||
await this.RecurlyClient.promises.getActiveCouponsForUserId('some-user')
|
||||
const expectedCoupons = [
|
||||
new RecurlyCoupon({
|
||||
new PaymentProviderCoupon({
|
||||
code: 'coupon-code',
|
||||
name: 'Coupon Name',
|
||||
description: 'hosted page description',
|
||||
@@ -329,7 +329,7 @@ describe('RecurlyClient', function () {
|
||||
|
||||
it('handles plan changes', async function () {
|
||||
await this.RecurlyClient.promises.applySubscriptionChangeRequest(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
planCode: 'new-plan',
|
||||
@@ -343,11 +343,11 @@ describe('RecurlyClient', function () {
|
||||
|
||||
it('handles add-on changes', async function () {
|
||||
await this.RecurlyClient.promises.applySubscriptionChangeRequest(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
addOnUpdates: [
|
||||
new RecurlySubscriptionAddOnUpdate({
|
||||
new PaymentProviderSubscriptionAddOnUpdate({
|
||||
code: 'new-add-on',
|
||||
quantity: 2,
|
||||
unitPrice: 8.99,
|
||||
@@ -514,7 +514,7 @@ describe('RecurlyClient', function () {
|
||||
})
|
||||
const { immediateCharge } =
|
||||
await this.RecurlyClient.promises.previewSubscriptionChange(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
planCode: 'new-plan',
|
||||
@@ -546,7 +546,7 @@ describe('RecurlyClient', function () {
|
||||
})
|
||||
const { immediateCharge } =
|
||||
await this.RecurlyClient.promises.previewSubscriptionChange(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
planCode: 'new-plan',
|
||||
@@ -570,7 +570,7 @@ describe('RecurlyClient', function () {
|
||||
.throws(new ValidationError())
|
||||
await expect(
|
||||
this.RecurlyClient.promises.previewSubscriptionChange(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
planCode: 'new-plan',
|
||||
@@ -583,7 +583,7 @@ describe('RecurlyClient', function () {
|
||||
this.client.previewSubscriptionChange = sinon.stub().throws(new Error())
|
||||
await expect(
|
||||
this.RecurlyClient.promises.previewSubscriptionChange(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.subscription,
|
||||
timeframe: 'now',
|
||||
planCode: 'new-plan',
|
||||
|
||||
@@ -15,12 +15,12 @@ describe('SubscriptionGroupHandler', function () {
|
||||
this.subscription_id = '31DSd1123D'
|
||||
this.adding = 1
|
||||
this.paymentMethod = { cardType: 'Visa', lastFour: '1111' }
|
||||
this.RecurlyEntities = {
|
||||
this.PaymentProviderEntities = {
|
||||
MEMBERS_LIMIT_ADD_ON_CODE: 'additional-license',
|
||||
}
|
||||
this.localPlanInSettings = {
|
||||
membersLimit: 5,
|
||||
membersLimitAddOn: this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
membersLimitAddOn: this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
}
|
||||
|
||||
this.subscription = {
|
||||
@@ -40,7 +40,7 @@ describe('SubscriptionGroupHandler', function () {
|
||||
id: 123,
|
||||
addOns: [
|
||||
{
|
||||
code: this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
code: this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
quantity: 1,
|
||||
},
|
||||
],
|
||||
@@ -98,7 +98,7 @@ describe('SubscriptionGroupHandler', function () {
|
||||
this.previewSubscriptionChange = {
|
||||
nextAddOns: [
|
||||
{
|
||||
code: this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
code: this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
quantity: this.recurlySubscription.addOns[0].quantity + this.adding,
|
||||
},
|
||||
],
|
||||
@@ -166,7 +166,7 @@ describe('SubscriptionGroupHandler', function () {
|
||||
},
|
||||
'./RecurlyClient': this.RecurlyClient,
|
||||
'./PlansLocator': this.PlansLocator,
|
||||
'./RecurlyEntities': this.RecurlyEntities,
|
||||
'./PaymentProviderEntities': this.PaymentProviderEntities,
|
||||
'../Authentication/SessionManager': this.SessionManager,
|
||||
'./GroupPlansData': this.GroupPlansData,
|
||||
},
|
||||
@@ -325,7 +325,8 @@ describe('SubscriptionGroupHandler', function () {
|
||||
},
|
||||
plan: {
|
||||
membersLimit: 5,
|
||||
membersLimitAddOn: this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
membersLimitAddOn:
|
||||
this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
canUseFlexibleLicensing: true,
|
||||
},
|
||||
recurlySubscription: this.recurlySubscription,
|
||||
@@ -347,14 +348,14 @@ describe('SubscriptionGroupHandler', function () {
|
||||
beforeEach(function () {
|
||||
this.recurlySubscription.addOns = [
|
||||
{
|
||||
code: this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
code: this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
quantity: 6,
|
||||
},
|
||||
]
|
||||
this.prevQuantity = this.recurlySubscription.addOns[0].quantity
|
||||
this.previewSubscriptionChange.nextAddOns = [
|
||||
{
|
||||
code: this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
code: this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
quantity: this.prevQuantity + this.adding,
|
||||
},
|
||||
]
|
||||
@@ -367,7 +368,7 @@ describe('SubscriptionGroupHandler', function () {
|
||||
|
||||
this.recurlySubscription.getRequestForAddOnUpdate
|
||||
.calledWith(
|
||||
this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
this.recurlySubscription.addOns[0].quantity + this.adding
|
||||
)
|
||||
.should.equal(true)
|
||||
@@ -391,7 +392,7 @@ describe('SubscriptionGroupHandler', function () {
|
||||
{
|
||||
type: 'add-on-update',
|
||||
addOn: {
|
||||
code: this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
code: this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
quantity:
|
||||
this.previewSubscriptionChange.nextAddOns[0].quantity,
|
||||
prevQuantity: this.prevQuantity,
|
||||
@@ -435,7 +436,7 @@ describe('SubscriptionGroupHandler', function () {
|
||||
this.prevQuantity = this.recurlySubscription.addOns[0]?.quantity ?? 0
|
||||
this.previewSubscriptionChange.nextAddOns = [
|
||||
{
|
||||
code: this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
code: this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
quantity: this.prevQuantity + this.adding,
|
||||
},
|
||||
]
|
||||
@@ -467,7 +468,7 @@ describe('SubscriptionGroupHandler', function () {
|
||||
{
|
||||
type: 'add-on-update',
|
||||
addOn: {
|
||||
code: this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
code: this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
quantity:
|
||||
this.previewSubscriptionChange.nextAddOns[0].quantity,
|
||||
prevQuantity: this.prevQuantity,
|
||||
@@ -493,7 +494,7 @@ describe('SubscriptionGroupHandler', function () {
|
||||
)
|
||||
this.recurlySubscription.getRequestForAddOnPurchase
|
||||
.calledWithExactly(
|
||||
this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
this.adding,
|
||||
this.GroupPlansData.enterprise.collaborator.USD[5]
|
||||
.additional_license_legacy_price_in_cents / 100
|
||||
@@ -513,7 +514,7 @@ describe('SubscriptionGroupHandler', function () {
|
||||
)
|
||||
this.recurlySubscription.getRequestForAddOnPurchase
|
||||
.calledWithExactly(
|
||||
this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
this.adding,
|
||||
undefined
|
||||
)
|
||||
@@ -538,7 +539,7 @@ describe('SubscriptionGroupHandler', function () {
|
||||
)
|
||||
this.recurlySubscription.getRequestForAddOnPurchase
|
||||
.calledWithExactly(
|
||||
this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
this.adding,
|
||||
this.GroupPlansData.enterprise.collaborator.USD[5]
|
||||
.additional_license_legacy_price_in_cents / 100
|
||||
@@ -563,7 +564,7 @@ describe('SubscriptionGroupHandler', function () {
|
||||
)
|
||||
this.recurlySubscription.getRequestForAddOnPurchase
|
||||
.calledWithExactly(
|
||||
this.RecurlyEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
this.PaymentProviderEntities.MEMBERS_LIMIT_ADD_ON_CODE,
|
||||
this.adding,
|
||||
undefined
|
||||
)
|
||||
|
||||
@@ -3,9 +3,9 @@ const sinon = require('sinon')
|
||||
const chai = require('chai')
|
||||
const { expect } = chai
|
||||
const {
|
||||
RecurlySubscription,
|
||||
RecurlySubscriptionChangeRequest,
|
||||
} = require('../../../../app/src/Features/Subscription/RecurlyEntities')
|
||||
PaymentProviderSubscription,
|
||||
PaymentProviderSubscriptionChangeRequest,
|
||||
} = require('../../../../app/src/Features/Subscription/PaymentProviderEntities')
|
||||
|
||||
const MODULE_PATH =
|
||||
'../../../../app/src/Features/Subscription/SubscriptionHandler'
|
||||
@@ -27,7 +27,7 @@ const mockRecurlySubscriptions = {
|
||||
}
|
||||
|
||||
const mockRecurlyClientSubscriptions = {
|
||||
'subscription-123-active': new RecurlySubscription({
|
||||
'subscription-123-active': new PaymentProviderSubscription({
|
||||
id: 'subscription-123-active',
|
||||
userId: 'user-id',
|
||||
planCode: 'collaborator',
|
||||
@@ -275,7 +275,7 @@ describe('SubscriptionHandler', function () {
|
||||
expect(
|
||||
this.RecurlyClient.promises.applySubscriptionChangeRequest
|
||||
).to.have.been.calledWith(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.activeRecurlyClientSubscription,
|
||||
timeframe: 'now',
|
||||
planCode: this.plan_code,
|
||||
@@ -388,7 +388,7 @@ describe('SubscriptionHandler', function () {
|
||||
expect(
|
||||
this.RecurlyClient.promises.applySubscriptionChangeRequest
|
||||
).to.be.calledWith(
|
||||
new RecurlySubscriptionChangeRequest({
|
||||
new PaymentProviderSubscriptionChangeRequest({
|
||||
subscription: this.activeRecurlyClientSubscription,
|
||||
timeframe: 'now',
|
||||
planCode: this.plan_code,
|
||||
|
||||
@@ -2,11 +2,11 @@ const SandboxedModule = require('sandboxed-module')
|
||||
const sinon = require('sinon')
|
||||
const { assert } = require('chai')
|
||||
const {
|
||||
RecurlyAccount,
|
||||
RecurlySubscription,
|
||||
RecurlySubscriptionAddOn,
|
||||
RecurlySubscriptionChange,
|
||||
} = require('../../../../app/src/Features/Subscription/RecurlyEntities')
|
||||
PaymentProviderAccount,
|
||||
PaymentProviderSubscription,
|
||||
PaymentProviderSubscriptionAddOn,
|
||||
PaymentProviderSubscriptionChange,
|
||||
} = require('../../../../app/src/Features/Subscription/PaymentProviderEntities')
|
||||
|
||||
const modulePath =
|
||||
'../../../../app/src/Features/Subscription/SubscriptionViewModelBuilder'
|
||||
@@ -33,7 +33,7 @@ describe('SubscriptionViewModelBuilder', function () {
|
||||
state: 'active',
|
||||
},
|
||||
}
|
||||
this.recurlySubscription = new RecurlySubscription({
|
||||
this.paymentRecord = new PaymentProviderSubscription({
|
||||
id: this.recurlySubscription_id,
|
||||
userId: this.user._id,
|
||||
currency: 'EUR',
|
||||
@@ -41,7 +41,7 @@ describe('SubscriptionViewModelBuilder', function () {
|
||||
planName: 'plan-name',
|
||||
planPrice: 13,
|
||||
addOns: [
|
||||
new RecurlySubscriptionAddOn({
|
||||
new PaymentProviderSubscriptionAddOn({
|
||||
code: 'addon-code',
|
||||
name: 'addon name',
|
||||
quantity: 1,
|
||||
@@ -265,7 +265,7 @@ describe('SubscriptionViewModelBuilder', function () {
|
||||
plan: this.plan,
|
||||
recurlySubscription_id: this.recurlySubscription_id,
|
||||
}
|
||||
this.recurlySubscription = {
|
||||
this.paymentRecord = {
|
||||
state: 'active',
|
||||
}
|
||||
this.SubscriptionLocator.promises.getUsersSubscription
|
||||
@@ -279,7 +279,7 @@ describe('SubscriptionViewModelBuilder', function () {
|
||||
.withArgs(this.individualSubscription.recurlySubscription_id, {
|
||||
includeAccount: true,
|
||||
})
|
||||
.resolves(this.recurlySubscription)
|
||||
.resolves(this.paymentRecord)
|
||||
|
||||
const usersBestSubscription =
|
||||
await this.SubscriptionViewModelBuilder.promises.getBestSubscription(
|
||||
@@ -293,7 +293,7 @@ describe('SubscriptionViewModelBuilder', function () {
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.SubscriptionUpdater.promises.updateSubscriptionFromRecurly,
|
||||
this.recurlySubscription,
|
||||
this.paymentRecord,
|
||||
this.individualSubscriptionWithoutRecurly
|
||||
)
|
||||
assert.deepEqual(usersBestSubscription, {
|
||||
@@ -507,14 +507,14 @@ describe('SubscriptionViewModelBuilder', function () {
|
||||
|
||||
describe('buildUsersSubscriptionViewModel', function () {
|
||||
describe('with a recurly subscription', function () {
|
||||
it('adds recurly data to the personal subscription', async function () {
|
||||
it('adds payment data to the personal subscription', async function () {
|
||||
this.SubscriptionLocator.getUsersSubscription.yields(
|
||||
null,
|
||||
this.individualSubscription
|
||||
)
|
||||
this.PaymentService.getPaymentFromRecord.yields(null, {
|
||||
subscription: this.recurlySubscription,
|
||||
account: new RecurlyAccount({
|
||||
subscription: this.paymentRecord,
|
||||
account: new PaymentProviderAccount({
|
||||
email: 'example@example.com',
|
||||
hasPastDueInvoice: false,
|
||||
}),
|
||||
@@ -524,7 +524,7 @@ describe('SubscriptionViewModelBuilder', function () {
|
||||
await this.SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
|
||||
this.user
|
||||
)
|
||||
assert.deepEqual(result.personalSubscription.recurly, {
|
||||
assert.deepEqual(result.personalSubscription.payment, {
|
||||
taxRate: 0.1,
|
||||
billingDetailsLink: '/user/subscription/recurly/billing-details',
|
||||
accountManagementLink:
|
||||
@@ -564,28 +564,29 @@ describe('SubscriptionViewModelBuilder', function () {
|
||||
null,
|
||||
this.individualSubscription
|
||||
)
|
||||
this.recurlySubscription.pendingChange = new RecurlySubscriptionChange({
|
||||
subscription: this.recurlySubscription,
|
||||
nextPlanCode: this.groupPlanCode,
|
||||
nextPlanName: 'Group Collaborator (Annual) 4 licenses',
|
||||
nextPlanPrice: 1400,
|
||||
nextAddOns: [
|
||||
new RecurlySubscriptionAddOn({
|
||||
code: 'additional-license',
|
||||
name: 'additional license',
|
||||
quantity: 8,
|
||||
unitPrice: 24.4,
|
||||
}),
|
||||
new RecurlySubscriptionAddOn({
|
||||
code: 'addon-code',
|
||||
name: 'addon name',
|
||||
quantity: 1,
|
||||
unitPrice: 2,
|
||||
}),
|
||||
],
|
||||
})
|
||||
this.paymentRecord.pendingChange =
|
||||
new PaymentProviderSubscriptionChange({
|
||||
subscription: this.paymentRecord,
|
||||
nextPlanCode: this.groupPlanCode,
|
||||
nextPlanName: 'Group Collaborator (Annual) 4 licenses',
|
||||
nextPlanPrice: 1400,
|
||||
nextAddOns: [
|
||||
new PaymentProviderSubscriptionAddOn({
|
||||
code: 'additional-license',
|
||||
name: 'additional license',
|
||||
quantity: 8,
|
||||
unitPrice: 24.4,
|
||||
}),
|
||||
new PaymentProviderSubscriptionAddOn({
|
||||
code: 'addon-code',
|
||||
name: 'addon name',
|
||||
quantity: 1,
|
||||
unitPrice: 2,
|
||||
}),
|
||||
],
|
||||
})
|
||||
this.PaymentService.getPaymentFromRecord.yields(null, {
|
||||
subscription: this.recurlySubscription,
|
||||
subscription: this.paymentRecord,
|
||||
account: {},
|
||||
coupons: [],
|
||||
})
|
||||
@@ -594,24 +595,24 @@ describe('SubscriptionViewModelBuilder', function () {
|
||||
this.user
|
||||
)
|
||||
assert.equal(
|
||||
result.personalSubscription.recurly.displayPrice,
|
||||
result.personalSubscription.payment.displayPrice,
|
||||
'€1,756.92'
|
||||
)
|
||||
assert.equal(
|
||||
result.personalSubscription.recurly.planOnlyDisplayPrice,
|
||||
result.personalSubscription.payment.planOnlyDisplayPrice,
|
||||
'€1,754.72'
|
||||
)
|
||||
assert.deepEqual(
|
||||
result.personalSubscription.recurly
|
||||
result.personalSubscription.payment
|
||||
.addOnDisplayPricesWithoutAdditionalLicense,
|
||||
{ 'addon-code': '€2.20' }
|
||||
)
|
||||
assert.equal(
|
||||
result.personalSubscription.recurly.pendingAdditionalLicenses,
|
||||
result.personalSubscription.payment.pendingAdditionalLicenses,
|
||||
8
|
||||
)
|
||||
assert.equal(
|
||||
result.personalSubscription.recurly.pendingTotalLicenses,
|
||||
result.personalSubscription.payment.pendingTotalLicenses,
|
||||
12
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { CurrencyCode } from '../currency'
|
||||
import { Nullable } from '../../utils'
|
||||
import { Plan, AddOn, RecurlyAddOn, PendingRecurlyPlan } from '../plan'
|
||||
import {
|
||||
Plan,
|
||||
AddOn,
|
||||
PaymentProviderAddOn,
|
||||
PendingPaymentProviderPlan,
|
||||
} from '../plan'
|
||||
import { User } from '../../user'
|
||||
|
||||
type SubscriptionState = 'active' | 'canceled' | 'expired' | 'paused'
|
||||
@@ -10,18 +15,18 @@ export type PurchasingAddOnCode = {
|
||||
code: string
|
||||
}
|
||||
|
||||
type RecurlyCoupon = {
|
||||
type PaymentProviderCoupon = {
|
||||
code: string
|
||||
name: string
|
||||
description: string
|
||||
}
|
||||
|
||||
type Recurly = {
|
||||
type PaymentProviderRecord = {
|
||||
taxRate: number
|
||||
billingDetailsLink: string
|
||||
accountManagementLink: string
|
||||
additionalLicenses: number
|
||||
addOns: RecurlyAddOn[]
|
||||
addOns: PaymentProviderAddOn[]
|
||||
totalLicenses: number
|
||||
nextPaymentDueAt: string
|
||||
nextPaymentDueDate: string
|
||||
@@ -29,7 +34,7 @@ type Recurly = {
|
||||
state?: SubscriptionState
|
||||
trialEndsAtFormatted: Nullable<string>
|
||||
trialEndsAt: Nullable<string>
|
||||
activeCoupons: RecurlyCoupon[]
|
||||
activeCoupons: PaymentProviderCoupon[]
|
||||
accountEmail: string
|
||||
hasPastDueInvoice: boolean
|
||||
displayPrice: string
|
||||
@@ -58,19 +63,19 @@ export type Subscription = {
|
||||
planCode: string
|
||||
recurlySubscription_id: string
|
||||
plan: Plan
|
||||
pendingPlan?: PendingRecurlyPlan
|
||||
pendingPlan?: PendingPaymentProviderPlan
|
||||
addOns?: AddOn[]
|
||||
}
|
||||
|
||||
export type RecurlySubscription = Subscription & {
|
||||
recurly: Recurly
|
||||
export type PaidSubscription = Subscription & {
|
||||
payment: PaymentProviderRecord
|
||||
}
|
||||
|
||||
export type CustomSubscription = Subscription & {
|
||||
customAccount: boolean
|
||||
}
|
||||
|
||||
export type GroupSubscription = RecurlySubscription & {
|
||||
export type GroupSubscription = PaidSubscription & {
|
||||
teamName: string
|
||||
teamNotice?: string
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ export type AddOn = {
|
||||
unitAmountInCents: number
|
||||
}
|
||||
|
||||
// add-ons directly accessed through recurly
|
||||
export type RecurlyAddOn = {
|
||||
// add-ons directly accessed through payment
|
||||
export type PaymentProviderAddOn = {
|
||||
code: string
|
||||
name: string
|
||||
quantity: number
|
||||
@@ -32,11 +32,11 @@ export type RecurlyAddOn = {
|
||||
displayPrice?: string
|
||||
}
|
||||
|
||||
export type PendingRecurlyPlan = {
|
||||
export type PendingPaymentProviderPlan = {
|
||||
annual?: boolean
|
||||
displayPrice?: string
|
||||
featureDescription?: Record<string, unknown>[]
|
||||
addOns?: RecurlyAddOn[]
|
||||
addOns?: PaymentProviderAddOn[]
|
||||
features?: Features
|
||||
groupPlan?: boolean
|
||||
hideFromUsers?: boolean
|
||||
|
||||
Reference in New Issue
Block a user