mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
Merge pull request #26397 from overleaf/kh-use-new-price-lookups
[web] use new price lookup keys GitOrigin-RevId: f4c077d946100862aaea0288d5035a34d6188e83
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
// TODO: This file may be deleted when Stripe is fully implemented to all users, so, consider deleting it
|
||||
// @ts-check
|
||||
|
||||
const Settings = require('@overleaf/settings')
|
||||
const logger = require('@overleaf/logger')
|
||||
|
||||
/**
|
||||
* @typedef {import('../../../../types/subscription/plan').RecurlyPlanCode} RecurlyPlanCode
|
||||
* @typedef {import('../../../../types/subscription/plan').RecurlyAddOnCode} RecurlyAddOnCode
|
||||
* @typedef {import('../../../../types/subscription/plan').StripeLookupKey} StripeLookupKey
|
||||
* @typedef {import('../../../../types/subscription/plan').StripeBaseLookupKey} StripeBaseLookupKey
|
||||
* @typedef {import('../../../../types/subscription/plan').Plan} Plan
|
||||
* @typedef {import('../../../../types/subscription/currency').StripeCurrencyCode} StripeCurrencyCode
|
||||
* @typedef {import('stripe').Stripe.Price.Recurring.Interval} BillingCycleInterval
|
||||
*/
|
||||
|
||||
@@ -26,18 +29,21 @@ function ensurePlansAreSetupCorrectly() {
|
||||
})
|
||||
}
|
||||
|
||||
const recurlyPlanCodeToStripeLookupKey = {
|
||||
collaborator: 'collaborator_may2025',
|
||||
'collaborator-annual': 'collaborator_annual_may2025',
|
||||
collaborator_free_trial_7_days: 'collaborator_may2025',
|
||||
/**
|
||||
* @type {Record<RecurlyPlanCode, StripeBaseLookupKey>}
|
||||
*/
|
||||
const recurlyCodeToStripeBaseLookupKey = {
|
||||
collaborator: 'standard_monthly',
|
||||
'collaborator-annual': 'standard_annual',
|
||||
collaborator_free_trial_7_days: 'standard_monthly',
|
||||
|
||||
professional: 'professional_may2025',
|
||||
'professional-annual': 'professional_annual_may2025',
|
||||
professional_free_trial_7_days: 'professional_may2025',
|
||||
professional: 'professional_monthly',
|
||||
'professional-annual': 'professional_annual',
|
||||
professional_free_trial_7_days: 'professional_monthly',
|
||||
|
||||
student: 'student_may2025',
|
||||
'student-annual': 'student_annual_may2025',
|
||||
student_free_trial_7_days: 'student_may2025',
|
||||
student: 'student_monthly',
|
||||
'student-annual': 'student_annual',
|
||||
student_free_trial_7_days: 'student_monthly',
|
||||
|
||||
// TODO: change all group plans' lookup_keys to match the UK account after they have been added
|
||||
group_collaborator: 'group_standard_enterprise',
|
||||
@@ -45,41 +51,46 @@ const recurlyPlanCodeToStripeLookupKey = {
|
||||
group_professional: 'group_professional_enterprise',
|
||||
group_professional_educational: 'group_professional_educational',
|
||||
|
||||
assistant: 'assistant_may2025',
|
||||
'assistant-annual': 'assistant_annual_may2025',
|
||||
assistant: 'assistant_monthly',
|
||||
'assistant-annual': 'assistant_annual',
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {RecurlyPlanCode} recurlyPlanCode
|
||||
* @returns {StripeLookupKey}
|
||||
*/
|
||||
function mapRecurlyPlanCodeToStripeLookupKey(recurlyPlanCode) {
|
||||
return recurlyPlanCodeToStripeLookupKey[recurlyPlanCode]
|
||||
}
|
||||
const LATEST_STRIPE_LOOKUP_KEY_VERSION = 'jun2025'
|
||||
|
||||
/**
|
||||
* Build the Stripe lookup key, will be in this format:
|
||||
* `${productCode}_${billingInterval}_${latestVersion}_${currency}`
|
||||
* (for example: 'assistant_annual_jun2025_clp')
|
||||
*
|
||||
* @param {RecurlyAddOnCode} recurlyAddOnCode
|
||||
* @param {BillingCycleInterval} billingCycleInterval
|
||||
* @param {RecurlyPlanCode} recurlyCode
|
||||
* @param {StripeCurrencyCode} currency
|
||||
* @param {BillingCycleInterval} [billingCycleInterval] -- needed for handling 'assistant' add-on
|
||||
* @returns {StripeLookupKey|null}
|
||||
*/
|
||||
function mapRecurlyAddOnCodeToStripeLookupKey(
|
||||
recurlyAddOnCode,
|
||||
billingCycleInterval
|
||||
) {
|
||||
function buildStripeLookupKey(recurlyCode, currency, billingCycleInterval) {
|
||||
let stripeBaseLookupKey = recurlyCodeToStripeBaseLookupKey[recurlyCode]
|
||||
|
||||
// Recurly always uses 'assistant' as the code regardless of the subscription duration
|
||||
if (recurlyAddOnCode === 'assistant') {
|
||||
if (recurlyCode === 'assistant' && billingCycleInterval) {
|
||||
if (billingCycleInterval === 'month') {
|
||||
return 'assistant_may2025'
|
||||
stripeBaseLookupKey = 'assistant_monthly'
|
||||
}
|
||||
if (billingCycleInterval === 'year') {
|
||||
return 'assistant_annual_may2025'
|
||||
stripeBaseLookupKey = 'assistant_annual'
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
||||
if (stripeBaseLookupKey == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return `${stripeBaseLookupKey}_${LATEST_STRIPE_LOOKUP_KEY_VERSION}_${currency}`
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {{ planType: 'individual' | 'group' | 'student' | null, period: 'annual' | 'monthly' }} PlanTypeAndPeriod
|
||||
* @type {Record<RecurlyPlanCode, PlanTypeAndPeriod>}
|
||||
*/
|
||||
const recurlyPlanCodeToPlanTypeAndPeriod = {
|
||||
collaborator: { planType: 'individual', period: 'monthly' },
|
||||
'collaborator-annual': { planType: 'individual', period: 'annual' },
|
||||
@@ -106,14 +117,17 @@ const recurlyPlanCodeToPlanTypeAndPeriod = {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {RecurlyPlanCode} recurlyPlanCode
|
||||
* @returns {{ planType: 'individual' | 'group' | 'student' | null, period: 'annual' | 'monthly'}}
|
||||
* @returns {PlanTypeAndPeriod}
|
||||
*/
|
||||
function getPlanTypeAndPeriodFromRecurlyPlanCode(recurlyPlanCode) {
|
||||
return recurlyPlanCodeToPlanTypeAndPeriod[recurlyPlanCode]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|null} [planCode]
|
||||
* @returns {Plan|null}
|
||||
*/
|
||||
function findLocalPlanInSettings(planCode) {
|
||||
for (const plan of Settings.plans) {
|
||||
if (plan.planCode === planCode) {
|
||||
@@ -126,7 +140,6 @@ function findLocalPlanInSettings(planCode) {
|
||||
module.exports = {
|
||||
ensurePlansAreSetupCorrectly,
|
||||
findLocalPlanInSettings,
|
||||
mapRecurlyPlanCodeToStripeLookupKey,
|
||||
mapRecurlyAddOnCodeToStripeLookupKey,
|
||||
buildStripeLookupKey,
|
||||
getPlanTypeAndPeriodFromRecurlyPlanCode,
|
||||
}
|
||||
|
||||
@@ -839,7 +839,7 @@ function makeChangePreview(
|
||||
paymentMethod: paymentMethod?.toString(),
|
||||
netTerms: subscription.netTerms,
|
||||
nextPlan: {
|
||||
annual: nextPlan.annual ?? false,
|
||||
annual: nextPlan?.annual ?? false,
|
||||
},
|
||||
nextInvoice: {
|
||||
date: subscription.periodEnd.toISOString(),
|
||||
|
||||
@@ -66,6 +66,7 @@ async function _getGroupSubscriptionPlanCode(userId) {
|
||||
const plan = PlansLocator.findLocalPlanInSettings(subscription.planCode)
|
||||
if (
|
||||
plan &&
|
||||
plan.features &&
|
||||
FeaturesHelper.isFeatureSetBetter(plan.features, bestFeatures)
|
||||
) {
|
||||
bestPlanCode = plan.planCode
|
||||
|
||||
@@ -50,84 +50,111 @@ describe('PlansLocator', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('mapRecurlyPlanCodeToStripeLookupKey', function () {
|
||||
describe('buildStripeLookupKey', function () {
|
||||
it('should map "collaborator" plan code to stripe lookup keys', function () {
|
||||
const planCode = 'collaborator'
|
||||
const lookupKey =
|
||||
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
|
||||
expect(lookupKey).to.equal('collaborator_may2025')
|
||||
const currency = 'eur'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
planCode,
|
||||
currency
|
||||
)
|
||||
expect(lookupKey).to.equal('standard_monthly_jun2025_eur')
|
||||
})
|
||||
|
||||
it('should map "collaborator_free_trial_7_days" plan code to stripe lookup keys', function () {
|
||||
const planCode = 'collaborator_free_trial_7_days'
|
||||
const lookupKey =
|
||||
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
|
||||
expect(lookupKey).to.equal('collaborator_may2025')
|
||||
const currency = 'eur'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
planCode,
|
||||
currency
|
||||
)
|
||||
expect(lookupKey).to.equal('standard_monthly_jun2025_eur')
|
||||
})
|
||||
|
||||
it('should map "collaborator-annual" plan code to stripe lookup keys', function () {
|
||||
const planCode = 'collaborator-annual'
|
||||
const lookupKey =
|
||||
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
|
||||
expect(lookupKey).to.equal('collaborator_annual_may2025')
|
||||
const currency = 'eur'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
planCode,
|
||||
currency
|
||||
)
|
||||
expect(lookupKey).to.equal('standard_annual_jun2025_eur')
|
||||
})
|
||||
|
||||
it('should map "professional" plan code to stripe lookup keys', function () {
|
||||
const planCode = 'professional'
|
||||
const lookupKey =
|
||||
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
|
||||
expect(lookupKey).to.equal('professional_may2025')
|
||||
const currency = 'eur'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
planCode,
|
||||
currency
|
||||
)
|
||||
expect(lookupKey).to.equal('professional_monthly_jun2025_eur')
|
||||
})
|
||||
|
||||
it('should map "professional_free_trial_7_days" plan code to stripe lookup keys', function () {
|
||||
const planCode = 'professional_free_trial_7_days'
|
||||
const lookupKey =
|
||||
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
|
||||
expect(lookupKey).to.equal('professional_may2025')
|
||||
const currency = 'eur'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
planCode,
|
||||
currency
|
||||
)
|
||||
expect(lookupKey).to.equal('professional_monthly_jun2025_eur')
|
||||
})
|
||||
|
||||
it('should map "professional-annual" plan code to stripe lookup keys', function () {
|
||||
const planCode = 'professional-annual'
|
||||
const lookupKey =
|
||||
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
|
||||
expect(lookupKey).to.equal('professional_annual_may2025')
|
||||
const currency = 'eur'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
planCode,
|
||||
currency
|
||||
)
|
||||
expect(lookupKey).to.equal('professional_annual_jun2025_eur')
|
||||
})
|
||||
|
||||
it('should map "student" plan code to stripe lookup keys', function () {
|
||||
const planCode = 'student'
|
||||
const lookupKey =
|
||||
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
|
||||
expect(lookupKey).to.equal('student_may2025')
|
||||
const currency = 'eur'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
planCode,
|
||||
currency
|
||||
)
|
||||
expect(lookupKey).to.equal('student_monthly_jun2025_eur')
|
||||
})
|
||||
|
||||
it('shoult map "student_free_trial_7_days" plan code to stripe lookup keys', function () {
|
||||
const planCode = 'student_free_trial_7_days'
|
||||
const lookupKey =
|
||||
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
|
||||
expect(lookupKey).to.equal('student_may2025')
|
||||
const currency = 'eur'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
planCode,
|
||||
currency
|
||||
)
|
||||
expect(lookupKey).to.equal('student_monthly_jun2025_eur')
|
||||
})
|
||||
|
||||
it('should map "student-annual" plan code to stripe lookup keys', function () {
|
||||
const planCode = 'student-annual'
|
||||
const lookupKey =
|
||||
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
|
||||
expect(lookupKey).to.equal('student_annual_may2025')
|
||||
const currency = 'eur'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
planCode,
|
||||
currency
|
||||
)
|
||||
expect(lookupKey).to.equal('student_annual_jun2025_eur')
|
||||
})
|
||||
})
|
||||
|
||||
describe('mapRecurlyAddOnCodeToStripeLookupKey', function () {
|
||||
it('should return null for unknown add-on codes', function () {
|
||||
const billingCycleInterval = 'month'
|
||||
const addOnCode = 'unknown_addon'
|
||||
const lookupKey = this.PlansLocator.mapRecurlyAddOnCodeToStripeLookupKey(
|
||||
const currency = 'gbp'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
addOnCode,
|
||||
currency,
|
||||
billingCycleInterval
|
||||
)
|
||||
expect(lookupKey).to.equal(null)
|
||||
})
|
||||
|
||||
it('should handle missing input', function () {
|
||||
const lookupKey = this.PlansLocator.mapRecurlyAddOnCodeToStripeLookupKey(
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
undefined,
|
||||
undefined
|
||||
)
|
||||
@@ -137,21 +164,25 @@ describe('PlansLocator', function () {
|
||||
it('returns the key for a monthly AI assist add-on', function () {
|
||||
const billingCycleInterval = 'month'
|
||||
const addOnCode = this.AI_ADD_ON_CODE
|
||||
const lookupKey = this.PlansLocator.mapRecurlyAddOnCodeToStripeLookupKey(
|
||||
const currency = 'gbp'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
addOnCode,
|
||||
currency,
|
||||
billingCycleInterval
|
||||
)
|
||||
expect(lookupKey).to.equal('assistant_may2025')
|
||||
expect(lookupKey).to.equal('assistant_monthly_jun2025_gbp')
|
||||
})
|
||||
|
||||
it('returns the key for an annual AI assist add-on', function () {
|
||||
const billingCycleInterval = 'year'
|
||||
const addOnCode = this.AI_ADD_ON_CODE
|
||||
const lookupKey = this.PlansLocator.mapRecurlyAddOnCodeToStripeLookupKey(
|
||||
const currency = 'gbp'
|
||||
const lookupKey = this.PlansLocator.buildStripeLookupKey(
|
||||
addOnCode,
|
||||
currency,
|
||||
billingCycleInterval
|
||||
)
|
||||
expect(lookupKey).to.equal('assistant_annual_may2025')
|
||||
expect(lookupKey).to.equal('assistant_annual_jun2025_gbp')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { StripeCurrencyCode } from './currency'
|
||||
|
||||
type Features = {
|
||||
collaborators: number
|
||||
compileGroup: string
|
||||
@@ -60,6 +62,7 @@ export type Plan = {
|
||||
name: string
|
||||
planCode: string
|
||||
price_in_cents: number
|
||||
canUseFlexibleLicensing?: boolean
|
||||
}
|
||||
|
||||
export type PriceForDisplayData = {
|
||||
@@ -90,17 +93,22 @@ export type RecurlyPlanCode =
|
||||
|
||||
export type RecurlyAddOnCode = 'assistant'
|
||||
|
||||
export type StripeLookupKey =
|
||||
| 'collaborator_may2025'
|
||||
| 'collaborator_annual_may2025'
|
||||
| 'professional_may2025'
|
||||
| 'professional_annual_may2025'
|
||||
| 'student_may2025'
|
||||
| 'student_annual_may2025'
|
||||
export type StripeBaseLookupKey =
|
||||
| 'standard_monthly'
|
||||
| 'standard_annual'
|
||||
| 'professional_monthly'
|
||||
| 'professional_annual'
|
||||
| 'student_monthly'
|
||||
| 'student_annual'
|
||||
| 'assistant_annual'
|
||||
| 'assistant_monthly'
|
||||
// TODO: change all group plans' lookup_keys to match the UK account after they have been added
|
||||
| 'group_standard_enterprise'
|
||||
| 'group_professional_enterprise'
|
||||
| 'group_standard_educational'
|
||||
| 'group_professional_educational'
|
||||
| 'assistant_annual_may2025'
|
||||
| 'assistant_may2025'
|
||||
|
||||
export type StripeLookupKeyVersion = 'jun2025'
|
||||
|
||||
export type StripeLookupKey =
|
||||
`${StripeBaseLookupKey}_${StripeLookupKeyVersion}_${StripeCurrencyCode}`
|
||||
|
||||
Reference in New Issue
Block a user