diff --git a/packages/backend/server/src/plugins/payment/resolver.ts b/packages/backend/server/src/plugins/payment/resolver.ts index e3f5462d99751..7fcb95c2fc6db 100644 --- a/packages/backend/server/src/plugins/payment/resolver.ts +++ b/packages/backend/server/src/plugins/payment/resolver.ts @@ -1,8 +1,4 @@ -import { - BadGatewayException, - ForbiddenException, - InternalServerErrorException, -} from '@nestjs/common'; +import { BadGatewayException, ForbiddenException } from '@nestjs/common'; import { Args, Context, @@ -48,11 +44,11 @@ class SubscriptionPrice { @Field() currency!: string; - @Field() - amount!: number; + @Field(() => Int, { nullable: true }) + amount?: number | null; - @Field() - yearlyAmount!: number; + @Field(() => Int, { nullable: true }) + yearlyAmount?: number | null; } @ObjectType('UserSubscription') @@ -176,64 +172,39 @@ export class SubscriptionResolver { } ); - return Object.entries(group).map(([plan, prices]) => { - const yearly = prices.find( - price => - decodeLookupKey( - // @ts-expect-error empty lookup key is filtered out - price.lookup_key - )[1] === SubscriptionRecurring.Yearly - ); - const monthly = prices.find( - price => - decodeLookupKey( - // @ts-expect-error empty lookup key is filtered out - price.lookup_key - )[1] === SubscriptionRecurring.Monthly - ); + function findPrice(plan: SubscriptionPlan) { + const prices = group[plan]; - if (!yearly || !monthly) { - throw new InternalServerErrorException( - 'The prices are not configured correctly.' - ); + if (!prices) { + return null; } + const monthlyPrice = prices.find(p => p.recurring?.interval === 'month'); + const yearlyPrice = prices.find(p => p.recurring?.interval === 'year'); + const currency = monthlyPrice?.currency ?? yearlyPrice?.currency ?? 'usd'; return { - type: 'fixed', - plan: plan as SubscriptionPlan, - currency: monthly.currency, - amount: monthly.unit_amount ?? 0, - yearlyAmount: yearly.unit_amount ?? 0, + currency, + amount: monthlyPrice?.unit_amount, + yearlyAmount: yearlyPrice?.unit_amount, }; - }); - } + } - /** - * @deprecated - */ - @Mutation(() => String, { - deprecationReason: 'use `createCheckoutSession` instead', - description: 'Create a subscription checkout link of stripe', - }) - async checkout( - @CurrentUser() user: CurrentUser, - @Args({ name: 'recurring', type: () => SubscriptionRecurring }) - recurring: SubscriptionRecurring, - @Args('idempotencyKey') idempotencyKey: string - ) { - const session = await this.service.createCheckoutSession({ - user, - plan: SubscriptionPlan.Pro, - recurring, - redirectUrl: `${this.config.baseUrl}/upgrade-success`, - idempotencyKey, - }); + // extend it when new plans are added + const fixedPlans = [SubscriptionPlan.Pro]; - if (!session.url) { - throw new BadGatewayException('Failed to create checkout session.'); - } + return fixedPlans.reduce((prices, plan) => { + const price = findPrice(plan); - return session.url; + if (price && (price.amount || price.yearlyAmount)) { + prices.push({ + type: 'fixed', + plan, + ...price, + }); + } + + return prices; + }, [] as SubscriptionPrice[]); } @Mutation(() => String, { diff --git a/packages/backend/server/src/plugins/payment/service.ts b/packages/backend/server/src/plugins/payment/service.ts index a23fe51c8d2aa..57728032ac7d1 100644 --- a/packages/backend/server/src/plugins/payment/service.ts +++ b/packages/backend/server/src/plugins/payment/service.ts @@ -65,7 +65,9 @@ export class SubscriptionService { ) {} async listPrices() { - return this.stripe.prices.list(); + return this.stripe.prices.list({ + active: true, + }); } async createCheckoutSession({ diff --git a/packages/backend/server/src/schema.gql b/packages/backend/server/src/schema.gql index 2d18df9e2759b..fd605ad8be902 100644 --- a/packages/backend/server/src/schema.gql +++ b/packages/backend/server/src/schema.gql @@ -114,9 +114,6 @@ type Mutation { changeEmail(email: String!, token: String!): UserType! changePassword(newPassword: String!, token: String!): UserType! - """Create a subscription checkout link of stripe""" - checkout(idempotencyKey: String!, recurring: SubscriptionRecurring!): String! @deprecated(reason: "use `createCheckoutSession` instead") - """Create a subscription checkout link of stripe""" createCheckoutSession(input: CreateCheckoutSessionInput!): String! @@ -275,11 +272,11 @@ enum SubscriptionPlan { } type SubscriptionPrice { - amount: Int! + amount: Int currency: String! plan: SubscriptionPlan! type: String! - yearlyAmount: Int! + yearlyAmount: Int } enum SubscriptionRecurring { diff --git a/packages/frontend/graphql/src/schema.ts b/packages/frontend/graphql/src/schema.ts index 2675c9ed6a48f..6cca406181700 100644 --- a/packages/frontend/graphql/src/schema.ts +++ b/packages/frontend/graphql/src/schema.ts @@ -87,6 +87,7 @@ export enum ServerFeature { } export enum SubscriptionPlan { + AI = 'AI', Enterprise = 'Enterprise', Free = 'Free', Pro = 'Pro',