fix(server): avoid error when other prices added but logic is not released (#6191)

This commit is contained in:
Brooooooklyn
2024-03-22 08:39:11 +00:00
parent 75355867c7
commit aecc523663
6 changed files with 48 additions and 75 deletions
@@ -1,8 +1,4 @@
import { import { BadGatewayException, ForbiddenException } from '@nestjs/common';
BadGatewayException,
ForbiddenException,
InternalServerErrorException,
} from '@nestjs/common';
import { import {
Args, Args,
Context, Context,
@@ -48,11 +44,11 @@ class SubscriptionPrice {
@Field() @Field()
currency!: string; currency!: string;
@Field() @Field(() => Int, { nullable: true })
amount!: number; amount?: number | null;
@Field() @Field(() => Int, { nullable: true })
yearlyAmount!: number; yearlyAmount?: number | null;
} }
@ObjectType('UserSubscription') @ObjectType('UserSubscription')
@@ -176,64 +172,39 @@ export class SubscriptionResolver {
} }
); );
return Object.entries(group).map(([plan, prices]) => { function findPrice(plan: SubscriptionPlan) {
const yearly = prices.find( const prices = group[plan];
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
);
if (!yearly || !monthly) { if (!prices) {
throw new InternalServerErrorException( return null;
'The prices are not configured correctly.'
);
} }
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 { return {
type: 'fixed', currency,
plan: plan as SubscriptionPlan, amount: monthlyPrice?.unit_amount,
currency: monthly.currency, yearlyAmount: yearlyPrice?.unit_amount,
amount: monthly.unit_amount ?? 0,
yearlyAmount: yearly.unit_amount ?? 0,
}; };
});
}
/**
* @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,
});
if (!session.url) {
throw new BadGatewayException('Failed to create checkout session.');
} }
return session.url; // extend it when new plans are added
const fixedPlans = [SubscriptionPlan.Pro];
return fixedPlans.reduce((prices, plan) => {
const price = findPrice(plan);
if (price && (price.amount || price.yearlyAmount)) {
prices.push({
type: 'fixed',
plan,
...price,
});
}
return prices;
}, [] as SubscriptionPrice[]);
} }
@Mutation(() => String, { @Mutation(() => String, {
@@ -65,7 +65,9 @@ export class SubscriptionService {
) {} ) {}
async listPrices() { async listPrices() {
return this.stripe.prices.list(); return this.stripe.prices.list({
active: true,
});
} }
async createCheckoutSession({ async createCheckoutSession({
+2 -5
View File
@@ -114,9 +114,6 @@ type Mutation {
changeEmail(email: String!, token: String!): UserType! changeEmail(email: String!, token: String!): UserType!
changePassword(newPassword: 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""" """Create a subscription checkout link of stripe"""
createCheckoutSession(input: CreateCheckoutSessionInput!): String! createCheckoutSession(input: CreateCheckoutSessionInput!): String!
@@ -275,11 +272,11 @@ enum SubscriptionPlan {
} }
type SubscriptionPrice { type SubscriptionPrice {
amount: Int! amount: Int
currency: String! currency: String!
plan: SubscriptionPlan! plan: SubscriptionPlan!
type: String! type: String!
yearlyAmount: Int! yearlyAmount: Int
} }
enum SubscriptionRecurring { enum SubscriptionRecurring {
@@ -108,8 +108,8 @@ const SubscriptionSettings = () => {
? '0' ? '0'
: price : price
? recurring === SubscriptionRecurring.Monthly ? recurring === SubscriptionRecurring.Monthly
? String(price.amount / 100) ? String((price.amount ?? 0) / 100)
: String(price.yearlyAmount / 100) : String((price.yearlyAmount ?? 0) / 100)
: '?'; : '?';
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
@@ -51,11 +51,14 @@ const Settings = () => {
const detail = planDetail.get(price.plan); const detail = planDetail.get(price.plan);
if (detail?.type === 'fixed') { if (detail?.type === 'fixed') {
detail.price = (price.amount / 100).toFixed(2); detail.price = ((price.amount ?? 0) / 100).toFixed(2);
detail.yearlyPrice = (price.yearlyAmount / 100 / 12).toFixed(2); detail.yearlyPrice = ((price.yearlyAmount ?? 0) / 100 / 12).toFixed(2);
detail.discount = Math.floor( detail.discount =
(1 - price.yearlyAmount / 12 / price.amount) * 100 price.yearlyAmount && price.amount
).toString(); ? Math.floor(
(1 - price.yearlyAmount / 12 / price.amount) * 100
).toString()
: undefined;
} }
}); });
+2 -2
View File
@@ -538,8 +538,8 @@ export type PricesQuery = {
type: string; type: string;
plan: SubscriptionPlan; plan: SubscriptionPlan;
currency: string; currency: string;
amount: number; amount: number | null;
yearlyAmount: number; yearlyAmount: number | null;
}>; }>;
}; };