48 add yearly monthly sub switch (#4577)
This commit is contained in:
@ -14,6 +14,7 @@ import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { CheckoutSessionInput } from 'src/engine/core-modules/billing/dto/checkout-session.input';
|
||||
import { SessionEntity } from 'src/engine/core-modules/billing/dto/session.entity';
|
||||
import { BillingSessionInput } from 'src/engine/core-modules/billing/dto/billing-session.input';
|
||||
import { UpdateBillingEntity } from 'src/engine/core-modules/billing/dto/update-billing.entity';
|
||||
|
||||
@Resolver()
|
||||
export class BillingResolver {
|
||||
@ -88,4 +89,12 @@ export class BillingResolver {
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@Mutation(() => UpdateBillingEntity)
|
||||
@UseGuards(JwtAuthGuard)
|
||||
async updateBillingSubscription(@AuthUser() user: User) {
|
||||
await this.billingService.updateBillingSubscription(user);
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,6 +154,32 @@ export class BillingService {
|
||||
return session.url;
|
||||
}
|
||||
|
||||
async updateBillingSubscription(user: User) {
|
||||
const billingSubscription = await this.getCurrentBillingSubscription({
|
||||
workspaceId: user.defaultWorkspaceId,
|
||||
});
|
||||
const newInterval =
|
||||
billingSubscription?.interval === 'year' ? 'month' : 'year';
|
||||
const billingSubscriptionItem = await this.getBillingSubscriptionItem(
|
||||
user.defaultWorkspaceId,
|
||||
);
|
||||
const stripeProductId = this.getProductStripeId(AvailableProduct.BasePlan);
|
||||
|
||||
if (!stripeProductId) {
|
||||
throw new Error('Stripe product id not found for basePlan');
|
||||
}
|
||||
const productPrices = await this.getProductPrices(stripeProductId);
|
||||
|
||||
const stripePriceId = productPrices.filter(
|
||||
(price) => price.recurringInterval === newInterval,
|
||||
)?.[0]?.stripePriceId;
|
||||
|
||||
await this.stripeService.updateBillingSubscriptionItem(
|
||||
billingSubscriptionItem,
|
||||
stripePriceId,
|
||||
);
|
||||
}
|
||||
|
||||
async computeCheckoutSessionURL(
|
||||
user: User,
|
||||
priceId: string,
|
||||
@ -230,6 +256,7 @@ export class BillingService {
|
||||
stripeCustomerId: data.object.customer as string,
|
||||
stripeSubscriptionId: data.object.id,
|
||||
status: data.object.status,
|
||||
interval: data.object.items.data[0].plan.interval,
|
||||
},
|
||||
{
|
||||
conflictPaths: ['stripeSubscriptionId'],
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
@ObjectType()
|
||||
export class UpdateBillingEntity {
|
||||
@Field(() => Boolean, {
|
||||
description: 'Boolean that confirms query was successful',
|
||||
})
|
||||
success: boolean;
|
||||
}
|
||||
@ -51,6 +51,10 @@ export class BillingSubscription {
|
||||
@Column({ nullable: false })
|
||||
status: Stripe.Subscription.Status;
|
||||
|
||||
@Field({ nullable: true })
|
||||
@Column({ nullable: true })
|
||||
interval: Stripe.Price.Recurring.Interval;
|
||||
|
||||
@OneToMany(
|
||||
() => BillingSubscriptionItem,
|
||||
(billingSubscriptionItem) => billingSubscriptionItem.billingSubscription,
|
||||
|
||||
@ -4,6 +4,7 @@ import Stripe from 'stripe';
|
||||
|
||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
|
||||
|
||||
@Injectable()
|
||||
export class StripeService {
|
||||
@ -105,4 +106,17 @@ export class StripeService {
|
||||
}
|
||||
await this.stripe.invoices.pay(latestInvoice.id);
|
||||
}
|
||||
|
||||
async updateBillingSubscriptionItem(
|
||||
stripeSubscriptionItem: BillingSubscriptionItem,
|
||||
stripePriceId: string,
|
||||
) {
|
||||
await this.stripe.subscriptionItems.update(
|
||||
stripeSubscriptionItem.stripeSubscriptionItemId,
|
||||
{
|
||||
price: stripePriceId,
|
||||
quantity: stripeSubscriptionItem.quantity,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,6 @@ import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
|
||||
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
|
||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||
|
||||
import { UserService } from './services/user.service';
|
||||
|
||||
@ -45,7 +44,6 @@ export class UserResolver {
|
||||
@InjectRepository(User, 'core')
|
||||
private readonly userRepository: Repository<User>,
|
||||
private readonly userService: UserService,
|
||||
private readonly userWorkspaceService: UserWorkspaceService,
|
||||
private readonly environmentService: EnvironmentService,
|
||||
private readonly fileUploadService: FileUploadService,
|
||||
) {}
|
||||
|
||||
Reference in New Issue
Block a user