diff --git a/services/web/app/src/Features/Subscription/PlansLocator.js b/services/web/app/src/Features/Subscription/PlansLocator.js index c04f0c860d..1d4fe210d5 100644 --- a/services/web/app/src/Features/Subscription/PlansLocator.js +++ b/services/web/app/src/Features/Subscription/PlansLocator.js @@ -27,21 +27,26 @@ function ensurePlansAreSetupCorrectly() { } const recurlyPlanCodeToStripeLookupKey = { - 'professional-annual': 'professional_annual', - professional: 'professional_monthly', - professional_free_trial_7_days: 'professional_monthly', - 'collaborator-annual': 'standard_annual', - collaborator: 'standard_monthly', - collaborator_free_trial_7_days: 'standard_monthly', - 'student-annual': 'student_annual', - student: 'student_monthly', - student_free_trial_7_days: 'student_monthly', - group_professional: 'group_professional_enterprise', - group_professional_educational: 'group_professional_educational', + collaborator: 'collaborator_may2025', + 'collaborator-annual': 'collaborator_annual_may2025', + collaborator_free_trial_7_days: 'collaborator_may2025', + + professional: 'professional_may2025', + 'professional-annual': 'professional_annual_may2025', + professional_free_trial_7_days: 'professional_may2025', + + student: 'student_may2025', + 'student-annual': 'student_annual_may2025', + 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_educational: 'group_standard_educational', - 'assistant-annual': 'error_assist_annual', - assistant: 'error_assist_monthly', + group_professional: 'group_professional_enterprise', + 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 if (recurlyAddOnCode === 'assistant') { if (billingCycleInterval === 'month') { - return 'error_assist_monthly' + return 'assistant_may2025' } if (billingCycleInterval === 'year') { - return 'error_assist_annual' + return 'assistant_annual_may2025' } } return null @@ -77,21 +82,25 @@ function mapRecurlyAddOnCodeToStripeLookupKey( const recurlyPlanCodeToPlanTypeAndPeriod = { collaborator: { planType: 'individual', period: 'monthly' }, - collaborator_free_trial_7_days: { planType: 'individual', period: 'monthly' }, 'collaborator-annual': { planType: 'individual', period: 'annual' }, + collaborator_free_trial_7_days: { planType: 'individual', period: 'monthly' }, + professional: { planType: 'individual', period: 'monthly' }, + 'professional-annual': { planType: 'individual', period: 'annual' }, professional_free_trial_7_days: { planType: 'individual', period: 'monthly', }, - 'professional-annual': { planType: 'individual', period: 'annual' }, + student: { planType: 'student', period: 'monthly' }, - student_free_trial_7_days: { planType: 'student', period: 'monthly' }, 'student-annual': { planType: 'student', period: 'annual' }, - group_professional: { planType: 'group', period: 'annual' }, - group_professional_educational: { planType: 'group', period: 'annual' }, + student_free_trial_7_days: { planType: 'student', period: 'monthly' }, + group_collaborator: { 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-annual': { planType: null, period: 'annual' }, } diff --git a/services/web/app/views/subscriptions/dashboard-react.pug b/services/web/app/views/subscriptions/dashboard-react.pug index 8cc5ec1976..2b6251f2a3 100644 --- a/services/web/app/views/subscriptions/dashboard-react.pug +++ b/services/web/app/views/subscriptions/dashboard-react.pug @@ -27,7 +27,7 @@ block append meta meta(name="ol-user" data-type="json" content=user) if (personalSubscription && personalSubscription.payment) 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-groupPlans" data-type="json" content=groupPlans) diff --git a/services/web/frontend/js/features/subscription/util/handle-stripe-payment-action.ts b/services/web/frontend/js/features/subscription/util/handle-stripe-payment-action.ts index fd29674893..f533cba730 100644 --- a/services/web/frontend/js/features/subscription/util/handle-stripe-payment-action.ts +++ b/services/web/frontend/js/features/subscription/util/handle-stripe-payment-action.ts @@ -8,8 +8,9 @@ export default async function handleStripePaymentAction( const clientSecret = error?.data?.clientSecret if (clientSecret) { - const stripePublicKey = getMeta('ol-stripeApiKey') - const stripe = await loadStripe(stripePublicKey) + // TODO: support both US and UK Stripe accounts + const stripeUKPublicKey = getMeta('ol-stripeUKApiKey') + const stripe = await loadStripe(stripeUKPublicKey) if (stripe) { const manualConfirmationFlow = await stripe.confirmCardPayment(clientSecret) diff --git a/services/web/frontend/js/utils/meta.ts b/services/web/frontend/js/utils/meta.ts index 1dd4af88e0..f2692a0b7b 100644 --- a/services/web/frontend/js/utils/meta.ts +++ b/services/web/frontend/js/utils/meta.ts @@ -240,8 +240,8 @@ export interface Meta { 'ol-splitTestVariants': { [name: string]: string } 'ol-ssoDisabled': boolean 'ol-ssoErrorMessage': string - 'ol-stripeApiKey': string 'ol-stripeCustomerId': string + 'ol-stripeUKApiKey': string 'ol-subscription': any // TODO: mixed types, split into two fields 'ol-subscriptionChangePreview': SubscriptionChangePreview 'ol-subscriptionId': string diff --git a/services/web/test/unit/src/Subscription/PlansLocatorTests.js b/services/web/test/unit/src/Subscription/PlansLocatorTests.js index 0c7a6dca03..e0db2e825d 100644 --- a/services/web/test/unit/src/Subscription/PlansLocatorTests.js +++ b/services/web/test/unit/src/Subscription/PlansLocatorTests.js @@ -55,63 +55,63 @@ describe('PlansLocator', function () { const planCode = 'collaborator' const lookupKey = 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 () { const planCode = 'collaborator_free_trial_7_days' const lookupKey = 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 () { const planCode = 'collaborator-annual' const lookupKey = 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 () { const planCode = 'professional' const lookupKey = 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 () { const planCode = 'professional_free_trial_7_days' const lookupKey = 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 () { const planCode = 'professional-annual' const lookupKey = 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 () { const planCode = 'student' const lookupKey = 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 () { const planCode = 'student_free_trial_7_days' const lookupKey = 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 () { const planCode = 'student-annual' const lookupKey = 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, 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 () { @@ -151,7 +151,7 @@ describe('PlansLocator', function () { addOnCode, billingCycleInterval ) - expect(lookupKey).to.equal('error_assist_annual') + expect(lookupKey).to.equal('assistant_annual_may2025') }) }) diff --git a/services/web/test/unit/src/Subscription/SubscriptionViewModelBuilderTests.js b/services/web/test/unit/src/Subscription/SubscriptionViewModelBuilderTests.js index 0f666b888a..a7c02f1e65 100644 --- a/services/web/test/unit/src/Subscription/SubscriptionViewModelBuilderTests.js +++ b/services/web/test/unit/src/Subscription/SubscriptionViewModelBuilderTests.js @@ -589,7 +589,7 @@ describe('SubscriptionViewModelBuilder', function () { describe('isEligibleForGroupPlan', function () { it('is false for Stripe subscriptions', async function () { - this.paymentRecord.service = 'stripe' + this.paymentRecord.service = 'stripe-us' const result = await this.SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( this.user @@ -627,7 +627,7 @@ describe('SubscriptionViewModelBuilder', function () { describe('isEligibleForPause', function () { it('is false for Stripe subscriptions', async function () { - this.paymentRecord.service = 'stripe' + this.paymentRecord.service = 'stripe-us' const result = await this.SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( this.user @@ -777,7 +777,7 @@ describe('SubscriptionViewModelBuilder', function () { this.paymentRecord.pausePeriodStart = null this.paymentRecord.remainingPauseCycles = null this.paymentRecord.trialPeriodEnd = null - this.paymentRecord.service = 'stripe' + this.paymentRecord.service = 'stripe-us' const result = await this.SubscriptionViewModelBuilder.promises.buildUsersSubscriptionViewModel( this.user @@ -847,7 +847,7 @@ describe('SubscriptionViewModelBuilder', 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 .withArgs('getPaymentFromRecord', this.individualSubscription) .yields(null, [ diff --git a/services/web/types/admin/subscription.ts b/services/web/types/admin/subscription.ts index ad05fbac40..811ebf54bf 100644 --- a/services/web/types/admin/subscription.ts +++ b/services/web/types/admin/subscription.ts @@ -7,7 +7,7 @@ import { TeamInvite } from '../team-invite' type RecurlyAdminClientPaymentProvider = Record type StripeAdminClientPaymentProvider = PaymentProvider & { - service: 'stripe' + service: 'stripe-us' | 'stripe-uk' } export type Subscription = { diff --git a/services/web/types/subscription/dashboard/subscription.ts b/services/web/types/subscription/dashboard/subscription.ts index a1ee934423..92a61e8ddb 100644 --- a/services/web/types/subscription/dashboard/subscription.ts +++ b/services/web/types/subscription/dashboard/subscription.ts @@ -103,7 +103,7 @@ export type MemberGroupSubscription = Omit & { admin_id: User } -type PaymentProviderService = 'stripe' | 'recurly' +type PaymentProviderService = 'stripe-us' | 'stripe-uk' | 'recurly' export type PaymentProvider = { service: PaymentProviderService diff --git a/services/web/types/subscription/plan.ts b/services/web/types/subscription/plan.ts index 4759bb1255..5a0d40a695 100644 --- a/services/web/types/subscription/plan.ts +++ b/services/web/types/subscription/plan.ts @@ -91,15 +91,16 @@ export type RecurlyPlanCode = export type RecurlyAddOnCode = 'assistant' export type StripeLookupKey = - | 'standard_monthly' - | 'standard_annual' - | 'professional_monthly' - | 'professional_annual' - | 'student_monthly' - | 'student_annual' + | 'collaborator_may2025' + | 'collaborator_annual_may2025' + | 'professional_may2025' + | 'professional_annual_may2025' + | 'student_may2025' + | 'student_annual_may2025' + // 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' - | 'error_assist_annual' - | 'error_assist_monthly' + | 'assistant_annual_may2025' + | 'assistant_may2025'