Merge pull request #26087 from overleaf/mf-change-to-stripe-uk

[web] Configure to use Stripe UK account

GitOrigin-RevId: 0856f6da2caae8caf9887ec2acea8e7f0972e598
This commit is contained in:
Kristina
2025-06-09 08:05:09 +00:00
committed by Copybot
parent 9e9ad3c005
commit a8df91e91b
9 changed files with 60 additions and 49 deletions
@@ -27,21 +27,26 @@ function ensurePlansAreSetupCorrectly() {
} }
const recurlyPlanCodeToStripeLookupKey = { const recurlyPlanCodeToStripeLookupKey = {
'professional-annual': 'professional_annual', collaborator: 'collaborator_may2025',
professional: 'professional_monthly', 'collaborator-annual': 'collaborator_annual_may2025',
professional_free_trial_7_days: 'professional_monthly', collaborator_free_trial_7_days: 'collaborator_may2025',
'collaborator-annual': 'standard_annual',
collaborator: 'standard_monthly', professional: 'professional_may2025',
collaborator_free_trial_7_days: 'standard_monthly', 'professional-annual': 'professional_annual_may2025',
'student-annual': 'student_annual', professional_free_trial_7_days: 'professional_may2025',
student: 'student_monthly',
student_free_trial_7_days: 'student_monthly', student: 'student_may2025',
group_professional: 'group_professional_enterprise', 'student-annual': 'student_annual_may2025',
group_professional_educational: 'group_professional_educational', student_free_trial_7_days: 'student_may2025',
// TODO: change all group plans' lookup_keys to match the UK account after they have been added
group_collaborator: 'group_standard_enterprise', group_collaborator: 'group_standard_enterprise',
group_collaborator_educational: 'group_standard_educational', group_collaborator_educational: 'group_standard_educational',
'assistant-annual': 'error_assist_annual', group_professional: 'group_professional_enterprise',
assistant: 'error_assist_monthly', group_professional_educational: 'group_professional_educational',
assistant: 'assistant_may2025',
'assistant-annual': 'assistant_annual_may2025',
} }
/** /**
@@ -66,10 +71,10 @@ function mapRecurlyAddOnCodeToStripeLookupKey(
// Recurly always uses 'assistant' as the code regardless of the subscription duration // Recurly always uses 'assistant' as the code regardless of the subscription duration
if (recurlyAddOnCode === 'assistant') { if (recurlyAddOnCode === 'assistant') {
if (billingCycleInterval === 'month') { if (billingCycleInterval === 'month') {
return 'error_assist_monthly' return 'assistant_may2025'
} }
if (billingCycleInterval === 'year') { if (billingCycleInterval === 'year') {
return 'error_assist_annual' return 'assistant_annual_may2025'
} }
} }
return null return null
@@ -77,21 +82,25 @@ function mapRecurlyAddOnCodeToStripeLookupKey(
const recurlyPlanCodeToPlanTypeAndPeriod = { const recurlyPlanCodeToPlanTypeAndPeriod = {
collaborator: { planType: 'individual', period: 'monthly' }, collaborator: { planType: 'individual', period: 'monthly' },
collaborator_free_trial_7_days: { planType: 'individual', period: 'monthly' },
'collaborator-annual': { planType: 'individual', period: 'annual' }, 'collaborator-annual': { planType: 'individual', period: 'annual' },
collaborator_free_trial_7_days: { planType: 'individual', period: 'monthly' },
professional: { planType: 'individual', period: 'monthly' }, professional: { planType: 'individual', period: 'monthly' },
'professional-annual': { planType: 'individual', period: 'annual' },
professional_free_trial_7_days: { professional_free_trial_7_days: {
planType: 'individual', planType: 'individual',
period: 'monthly', period: 'monthly',
}, },
'professional-annual': { planType: 'individual', period: 'annual' },
student: { planType: 'student', period: 'monthly' }, student: { planType: 'student', period: 'monthly' },
student_free_trial_7_days: { planType: 'student', period: 'monthly' },
'student-annual': { planType: 'student', period: 'annual' }, 'student-annual': { planType: 'student', period: 'annual' },
group_professional: { planType: 'group', period: 'annual' }, student_free_trial_7_days: { planType: 'student', period: 'monthly' },
group_professional_educational: { planType: 'group', period: 'annual' },
group_collaborator: { planType: 'group', period: 'annual' }, group_collaborator: { planType: 'group', period: 'annual' },
group_collaborator_educational: { planType: 'group', period: 'annual' }, group_collaborator_educational: { planType: 'group', period: 'annual' },
group_professional: { planType: 'group', period: 'annual' },
group_professional_educational: { planType: 'group', period: 'annual' },
assistant: { planType: null, period: 'monthly' }, assistant: { planType: null, period: 'monthly' },
'assistant-annual': { planType: null, period: 'annual' }, 'assistant-annual': { planType: null, period: 'annual' },
} }
@@ -27,7 +27,7 @@ block append meta
meta(name="ol-user" data-type="json" content=user) meta(name="ol-user" data-type="json" content=user)
if (personalSubscription && personalSubscription.payment) if (personalSubscription && personalSubscription.payment)
meta(name="ol-recurlyApiKey" content=settings.apis.recurly.publicKey) meta(name="ol-recurlyApiKey" content=settings.apis.recurly.publicKey)
meta(name="ol-stripeApiKey" content=settings.apis.stripe.publishableKey) meta(name="ol-stripeUKApiKey" content=settings.apis.stripeUK.publishableKey)
meta(name="ol-recommendedCurrency" content=personalSubscription.payment.currency) meta(name="ol-recommendedCurrency" content=personalSubscription.payment.currency)
meta(name="ol-groupPlans" data-type="json" content=groupPlans) meta(name="ol-groupPlans" data-type="json" content=groupPlans)
@@ -8,8 +8,9 @@ export default async function handleStripePaymentAction(
const clientSecret = error?.data?.clientSecret const clientSecret = error?.data?.clientSecret
if (clientSecret) { if (clientSecret) {
const stripePublicKey = getMeta('ol-stripeApiKey') // TODO: support both US and UK Stripe accounts
const stripe = await loadStripe(stripePublicKey) const stripeUKPublicKey = getMeta('ol-stripeUKApiKey')
const stripe = await loadStripe(stripeUKPublicKey)
if (stripe) { if (stripe) {
const manualConfirmationFlow = const manualConfirmationFlow =
await stripe.confirmCardPayment(clientSecret) await stripe.confirmCardPayment(clientSecret)
+1 -1
View File
@@ -240,8 +240,8 @@ export interface Meta {
'ol-splitTestVariants': { [name: string]: string } 'ol-splitTestVariants': { [name: string]: string }
'ol-ssoDisabled': boolean 'ol-ssoDisabled': boolean
'ol-ssoErrorMessage': string 'ol-ssoErrorMessage': string
'ol-stripeApiKey': string
'ol-stripeCustomerId': string 'ol-stripeCustomerId': string
'ol-stripeUKApiKey': string
'ol-subscription': any // TODO: mixed types, split into two fields 'ol-subscription': any // TODO: mixed types, split into two fields
'ol-subscriptionChangePreview': SubscriptionChangePreview 'ol-subscriptionChangePreview': SubscriptionChangePreview
'ol-subscriptionId': string 'ol-subscriptionId': string
@@ -55,63 +55,63 @@ describe('PlansLocator', function () {
const planCode = 'collaborator' const planCode = 'collaborator'
const lookupKey = const lookupKey =
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode) this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
expect(lookupKey).to.equal('standard_monthly') expect(lookupKey).to.equal('collaborator_may2025')
}) })
it('should map "collaborator_free_trial_7_days" plan code to stripe lookup keys', function () { it('should map "collaborator_free_trial_7_days" plan code to stripe lookup keys', function () {
const planCode = 'collaborator_free_trial_7_days' const planCode = 'collaborator_free_trial_7_days'
const lookupKey = const lookupKey =
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode) this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
expect(lookupKey).to.equal('standard_monthly') expect(lookupKey).to.equal('collaborator_may2025')
}) })
it('should map "collaborator-annual" plan code to stripe lookup keys', function () { it('should map "collaborator-annual" plan code to stripe lookup keys', function () {
const planCode = 'collaborator-annual' const planCode = 'collaborator-annual'
const lookupKey = const lookupKey =
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode) this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
expect(lookupKey).to.equal('standard_annual') expect(lookupKey).to.equal('collaborator_annual_may2025')
}) })
it('should map "professional" plan code to stripe lookup keys', function () { it('should map "professional" plan code to stripe lookup keys', function () {
const planCode = 'professional' const planCode = 'professional'
const lookupKey = const lookupKey =
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode) this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
expect(lookupKey).to.equal('professional_monthly') expect(lookupKey).to.equal('professional_may2025')
}) })
it('should map "professional_free_trial_7_days" plan code to stripe lookup keys', function () { it('should map "professional_free_trial_7_days" plan code to stripe lookup keys', function () {
const planCode = 'professional_free_trial_7_days' const planCode = 'professional_free_trial_7_days'
const lookupKey = const lookupKey =
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode) this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
expect(lookupKey).to.equal('professional_monthly') expect(lookupKey).to.equal('professional_may2025')
}) })
it('should map "professional-annual" plan code to stripe lookup keys', function () { it('should map "professional-annual" plan code to stripe lookup keys', function () {
const planCode = 'professional-annual' const planCode = 'professional-annual'
const lookupKey = const lookupKey =
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode) this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
expect(lookupKey).to.equal('professional_annual') expect(lookupKey).to.equal('professional_annual_may2025')
}) })
it('should map "student" plan code to stripe lookup keys', function () { it('should map "student" plan code to stripe lookup keys', function () {
const planCode = 'student' const planCode = 'student'
const lookupKey = const lookupKey =
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode) this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
expect(lookupKey).to.equal('student_monthly') expect(lookupKey).to.equal('student_may2025')
}) })
it('shoult map "student_free_trial_7_days" plan code to stripe lookup keys', function () { it('shoult map "student_free_trial_7_days" plan code to stripe lookup keys', function () {
const planCode = 'student_free_trial_7_days' const planCode = 'student_free_trial_7_days'
const lookupKey = const lookupKey =
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode) this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
expect(lookupKey).to.equal('student_monthly') expect(lookupKey).to.equal('student_may2025')
}) })
it('should map "student-annual" plan code to stripe lookup keys', function () { it('should map "student-annual" plan code to stripe lookup keys', function () {
const planCode = 'student-annual' const planCode = 'student-annual'
const lookupKey = const lookupKey =
this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode) this.PlansLocator.mapRecurlyPlanCodeToStripeLookupKey(planCode)
expect(lookupKey).to.equal('student_annual') expect(lookupKey).to.equal('student_annual_may2025')
}) })
}) })
@@ -141,7 +141,7 @@ describe('PlansLocator', function () {
addOnCode, addOnCode,
billingCycleInterval billingCycleInterval
) )
expect(lookupKey).to.equal('error_assist_monthly') expect(lookupKey).to.equal('assistant_may2025')
}) })
it('returns the key for an annual AI assist add-on', function () { it('returns the key for an annual AI assist add-on', function () {
@@ -151,7 +151,7 @@ describe('PlansLocator', function () {
addOnCode, addOnCode,
billingCycleInterval billingCycleInterval
) )
expect(lookupKey).to.equal('error_assist_annual') expect(lookupKey).to.equal('assistant_annual_may2025')
}) })
}) })
@@ -589,7 +589,7 @@ describe('SubscriptionViewModelBuilder', function () {
describe('isEligibleForGroupPlan', function () { describe('isEligibleForGroupPlan', function () {
it('is false for Stripe subscriptions', async function () { it('is false for Stripe subscriptions', async function () {
this.paymentRecord.service = 'stripe' this.paymentRecord.service = 'stripe-us'
const result = const result =
await this.SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( await this.SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
this.user this.user
@@ -627,7 +627,7 @@ describe('SubscriptionViewModelBuilder', function () {
describe('isEligibleForPause', function () { describe('isEligibleForPause', function () {
it('is false for Stripe subscriptions', async function () { it('is false for Stripe subscriptions', async function () {
this.paymentRecord.service = 'stripe' this.paymentRecord.service = 'stripe-us'
const result = const result =
await this.SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( await this.SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
this.user this.user
@@ -777,7 +777,7 @@ describe('SubscriptionViewModelBuilder', function () {
this.paymentRecord.pausePeriodStart = null this.paymentRecord.pausePeriodStart = null
this.paymentRecord.remainingPauseCycles = null this.paymentRecord.remainingPauseCycles = null
this.paymentRecord.trialPeriodEnd = null this.paymentRecord.trialPeriodEnd = null
this.paymentRecord.service = 'stripe' this.paymentRecord.service = 'stripe-us'
const result = const result =
await this.SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( await this.SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel(
this.user this.user
@@ -847,7 +847,7 @@ describe('SubscriptionViewModelBuilder', function () {
}) })
it('does not add a billing details link for a Stripe subscription', async function () { it('does not add a billing details link for a Stripe subscription', async function () {
this.paymentRecord.service = 'stripe' this.paymentRecord.service = 'stripe-us'
this.Modules.hooks.fire this.Modules.hooks.fire
.withArgs('getPaymentFromRecord', this.individualSubscription) .withArgs('getPaymentFromRecord', this.individualSubscription)
.yields(null, [ .yields(null, [
+1 -1
View File
@@ -7,7 +7,7 @@ import { TeamInvite } from '../team-invite'
type RecurlyAdminClientPaymentProvider = Record<string, never> type RecurlyAdminClientPaymentProvider = Record<string, never>
type StripeAdminClientPaymentProvider = PaymentProvider & { type StripeAdminClientPaymentProvider = PaymentProvider & {
service: 'stripe' service: 'stripe-us' | 'stripe-uk'
} }
export type Subscription = { export type Subscription = {
@@ -103,7 +103,7 @@ export type MemberGroupSubscription = Omit<GroupSubscription, 'admin_id'> & {
admin_id: User admin_id: User
} }
type PaymentProviderService = 'stripe' | 'recurly' type PaymentProviderService = 'stripe-us' | 'stripe-uk' | 'recurly'
export type PaymentProvider = { export type PaymentProvider = {
service: PaymentProviderService service: PaymentProviderService
+9 -8
View File
@@ -91,15 +91,16 @@ export type RecurlyPlanCode =
export type RecurlyAddOnCode = 'assistant' export type RecurlyAddOnCode = 'assistant'
export type StripeLookupKey = export type StripeLookupKey =
| 'standard_monthly' | 'collaborator_may2025'
| 'standard_annual' | 'collaborator_annual_may2025'
| 'professional_monthly' | 'professional_may2025'
| 'professional_annual' | 'professional_annual_may2025'
| 'student_monthly' | 'student_may2025'
| 'student_annual' | 'student_annual_may2025'
// TODO: change all group plans' lookup_keys to match the UK account after they have been added
| 'group_standard_enterprise' | 'group_standard_enterprise'
| 'group_professional_enterprise' | 'group_professional_enterprise'
| 'group_standard_educational' | 'group_standard_educational'
| 'group_professional_educational' | 'group_professional_educational'
| 'error_assist_annual' | 'assistant_annual_may2025'
| 'error_assist_monthly' | 'assistant_may2025'