import { Body, Controller, Get, HttpException, Param, Post, Req } from '@nestjs/common'; import { SubscriptionService } from '@gitroom/nestjs-libraries/database/prisma/subscriptions/subscription.service'; import { StripeService } from '@gitroom/nestjs-libraries/services/stripe.service'; import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request'; import { Organization, User } from '@prisma/client'; import { BillingSubscribeDto } from '@gitroom/nestjs-libraries/dtos/billing/billing.subscribe.dto'; import { ApiTags } from '@nestjs/swagger'; import { GetUserFromRequest } from '@gitroom/nestjs-libraries/user/user.from.request'; import { NotificationService } from '@gitroom/nestjs-libraries/database/prisma/notifications/notification.service'; import { Request } from 'express'; import { AuthService } from '@gitroom/helpers/auth/auth.service'; @ApiTags('Billing') @Controller('/billing') export class BillingController { constructor( private _subscriptionService: SubscriptionService, private _stripeService: StripeService, private _notificationService: NotificationService ) {} @Get('/check/:id') async checkId( @GetOrgFromRequest() org: Organization, @Param('id') body: string ) { return { status: await this._stripeService.checkSubscription(org.id, body), }; } @Get('/check-discount') async checkDiscount(@GetOrgFromRequest() org: Organization) { return { offerCoupon: !(await this._stripeService.checkDiscount(org.paymentId)) ? false : AuthService.signJWT({ discount: true }), }; } @Post('/apply-discount') async applyDiscount(@GetOrgFromRequest() org: Organization) { await this._stripeService.applyDiscount(org.paymentId); } @Post('/finish-trial') async finishTrial(@GetOrgFromRequest() org: Organization) { try { await this._stripeService.finishTrial(org.paymentId); } catch (err) {} return { finish: true, }; } @Get('/is-trial-finished') async isTrialFinished(@GetOrgFromRequest() org: Organization) { return { finished: !org.isTrailing, }; } @Post('/embedded') embedded( @GetOrgFromRequest() org: Organization, @GetUserFromRequest() user: User, @Body() body: BillingSubscribeDto, @Req() req: Request ) { const uniqueId = req?.cookies?.track; return this._stripeService.embedded( uniqueId, org.id, user.id, body, org.allowTrial ); } @Post('/subscribe') subscribe( @GetOrgFromRequest() org: Organization, @GetUserFromRequest() user: User, @Body() body: BillingSubscribeDto, @Req() req: Request ) { const uniqueId = req?.cookies?.track; return this._stripeService.subscribe( uniqueId, org.id, user.id, body, org.allowTrial ); } @Get('/portal') async modifyPayment(@GetOrgFromRequest() org: Organization) { const customer = await this._stripeService.getCustomerByOrganizationId( org.id ); const { url } = await this._stripeService.createBillingPortalLink(customer); return { portal: url, }; } @Get('/') getCurrentBilling(@GetOrgFromRequest() org: Organization) { return this._subscriptionService.getSubscriptionByOrganizationId(org.id); } @Post('/cancel') async cancel( @GetOrgFromRequest() org: Organization, @GetUserFromRequest() user: User, @Body() body: { feedback: string } ) { await this._notificationService.sendEmail( process.env.EMAIL_FROM_ADDRESS, 'Subscription Cancelled', `Organization ${org.name} has cancelled their subscription because: ${body.feedback}`, user.email ); return this._stripeService.setToCancel(org.id); } @Post('/prorate') prorate( @GetOrgFromRequest() org: Organization, @Body() body: BillingSubscribeDto ) { return this._stripeService.prorate(org.id, body); } @Get('/charges') async getCharges( @GetUserFromRequest() user: User, @GetOrgFromRequest() org: Organization ) { if (!user.isSuperAdmin) { throw new HttpException('Unauthorized', 400); } return this._stripeService.getCharges(org.id); } @Post('/refund-charges') async refundCharges( @GetUserFromRequest() user: User, @GetOrgFromRequest() org: Organization, @Body() body: { chargeIds: string[] } ) { if (!user.isSuperAdmin) { throw new HttpException('Unauthorized', 400); } return this._stripeService.refundCharges(org.id, body.chargeIds); } @Post('/cancel-subscription') async cancelSubscription( @GetUserFromRequest() user: User, @GetOrgFromRequest() org: Organization ) { if (!user.isSuperAdmin) { throw new HttpException('Unauthorized', 400); } return this._stripeService.cancelSubscription(org.id); } @Get('/chatbase-refund/preview') chatbaseRefundPreview(@GetOrgFromRequest() org: Organization) { return this._stripeService.chatbaseRefundPreview(org.id); } @Post('/chatbase-refund') async chatbaseRefund( @GetUserFromRequest() user: User, @GetOrgFromRequest() org: Organization ) { const refund = await this._stripeService.chatbaseRefund(org.id); if (refund.refunded) { await this._notificationService.sendEmail( process.env.EMAIL_FROM_ADDRESS, 'Refund issued from Chatbase', `Organization ${org.name} received a refund of ${refund.amount} ${refund.currency} and their subscription was cancelled`, user.email ); } return refund; } @Post('/add-subscription') async addSubscription( @Body() body: { subscription: string }, @GetUserFromRequest() user: User, @GetOrgFromRequest() org: Organization ) { if (!user.isSuperAdmin) { throw new Error('Unauthorized'); } await this._subscriptionService.addSubscription( org.id, user.id, body.subscription ); } }