Skip to content

Commit

Permalink
fix(server): avoid error when other prices added but logic is not rel…
Browse files Browse the repository at this point in the history
…eased (#6191)
  • Loading branch information
forehalo committed Mar 22, 2024
1 parent 7535586 commit aecc523
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 74 deletions.
89 changes: 30 additions & 59 deletions packages/backend/server/src/plugins/payment/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
BadGatewayException,
ForbiddenException,
InternalServerErrorException,
} from '@nestjs/common';
import { BadGatewayException, ForbiddenException } from '@nestjs/common';
import {
Args,
Context,
Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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, {
Expand Down
4 changes: 3 additions & 1 deletion packages/backend/server/src/plugins/payment/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ export class SubscriptionService {
) {}

async listPrices() {
return this.stripe.prices.list();
return this.stripe.prices.list({
active: true,
});
}

async createCheckoutSession({
Expand Down
7 changes: 2 additions & 5 deletions packages/backend/server/src/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -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!

Expand Down Expand Up @@ -275,11 +272,11 @@ enum SubscriptionPlan {
}

type SubscriptionPrice {
amount: Int!
amount: Int
currency: String!
plan: SubscriptionPlan!
type: String!
yearlyAmount: Int!
yearlyAmount: Int
}

enum SubscriptionRecurring {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ const SubscriptionSettings = () => {
? '0'
: price
? recurring === SubscriptionRecurring.Monthly
? String(price.amount / 100)
: String(price.yearlyAmount / 100)
? String((price.amount ?? 0) / 100)
: String((price.yearlyAmount ?? 0) / 100)
: '?';

const t = useAFFiNEI18N();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,14 @@ const Settings = () => {
const detail = planDetail.get(price.plan);

if (detail?.type === 'fixed') {
detail.price = (price.amount / 100).toFixed(2);
detail.yearlyPrice = (price.yearlyAmount / 100 / 12).toFixed(2);
detail.discount = Math.floor(
(1 - price.yearlyAmount / 12 / price.amount) * 100
).toString();
detail.price = ((price.amount ?? 0) / 100).toFixed(2);
detail.yearlyPrice = ((price.yearlyAmount ?? 0) / 100 / 12).toFixed(2);
detail.discount =
price.yearlyAmount && price.amount
? Math.floor(
(1 - price.yearlyAmount / 12 / price.amount) * 100
).toString()
: undefined;
}
});

Expand Down
4 changes: 2 additions & 2 deletions packages/frontend/graphql/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -538,8 +538,8 @@ export type PricesQuery = {
type: string;
plan: SubscriptionPlan;
currency: string;
amount: number;
yearlyAmount: number;
amount: number | null;
yearlyAmount: number | null;
}>;
};

Expand Down

0 comments on commit aecc523

Please sign in to comment.