mirror of
https://github.com/vernu/textbee.git
synced 2026-05-19 05:46:23 -04:00
fix(api): prevent duplicate checkout sessions per user
This commit is contained in:
@@ -33,7 +33,7 @@
|
||||
"@nestjs/schedule": "^4.1.1",
|
||||
"@nestjs/swagger": "^7.4.2",
|
||||
"@nestjs/throttler": "^6.2.1",
|
||||
"@polar-sh/sdk": "^0.32.3",
|
||||
"@polar-sh/sdk": "^0.34.9",
|
||||
"axios": "^1.8.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"bull": "^4.16.5",
|
||||
|
||||
107
api/pnpm-lock.yaml
generated
107
api/pnpm-lock.yaml
generated
@@ -48,8 +48,8 @@ importers:
|
||||
specifier: ^6.2.1
|
||||
version: 6.2.1(@nestjs/common@10.4.5(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.5)(reflect-metadata@0.2.2)
|
||||
'@polar-sh/sdk':
|
||||
specifier: ^0.32.3
|
||||
version: 0.32.3(zod@3.24.1)
|
||||
specifier: ^0.34.9
|
||||
version: 0.34.9
|
||||
axios:
|
||||
specifier: ^1.8.2
|
||||
version: 1.8.2
|
||||
@@ -134,19 +134,19 @@ importers:
|
||||
version: 6.0.2
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^8.10.0
|
||||
version: 8.10.0(@typescript-eslint/parser@8.10.0(eslint@9.13.0)(typescript@5.6.3))(eslint@9.13.0)(typescript@5.6.3)
|
||||
version: 8.10.0(@typescript-eslint/parser@8.10.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^8.10.0
|
||||
version: 8.10.0(eslint@9.13.0)(typescript@5.6.3)
|
||||
version: 8.10.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3)
|
||||
eslint:
|
||||
specifier: ^9.13.0
|
||||
version: 9.13.0
|
||||
version: 9.13.0(jiti@2.4.2)
|
||||
eslint-config-prettier:
|
||||
specifier: ^9.1.0
|
||||
version: 9.1.0(eslint@9.13.0)
|
||||
version: 9.1.0(eslint@9.13.0(jiti@2.4.2))
|
||||
eslint-plugin-prettier:
|
||||
specifier: ^5.2.1
|
||||
version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0))(eslint@9.13.0)(prettier@3.3.3)
|
||||
version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.2)))(eslint@9.13.0(jiti@2.4.2))(prettier@3.3.3)
|
||||
jest:
|
||||
specifier: ^29.7.0
|
||||
version: 29.7.0(@types/node@22.7.7)(ts-node@10.9.2(@types/node@22.7.7)(typescript@5.6.3))
|
||||
@@ -317,6 +317,10 @@ packages:
|
||||
resolution: {integrity: sha512-gYq0xCsqFfQaSL/yT1Gl1vIUjtsg7d7RhnUfsXaHt8xTxOKRTdH9GjbesBjXOzgOvB0W0vfssfreSNGFlOOMJg==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
|
||||
'@aws-sdk/types@3.840.0':
|
||||
resolution: {integrity: sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@aws-sdk/util-endpoints@3.667.0':
|
||||
resolution: {integrity: sha512-X22SYDAuQJWnkF1/q17pkX3nGw5XMD9YEUbmt87vUnRq7iyJ3JOpl6UKOBeUBaL838wA5yzdbinmCITJ/VZ1QA==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
@@ -975,12 +979,11 @@ packages:
|
||||
resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
|
||||
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
||||
|
||||
'@polar-sh/sdk@0.32.3':
|
||||
resolution: {integrity: sha512-AW4CNIVIkLYmCy59ynkxGYz0/1m1w/L7WIC7+m0SW5j+k5HrLgTYK7/7jdwu8biddT5EcQOvmjTnHYtLFFs9sA==}
|
||||
'@polar-sh/sdk@0.34.9':
|
||||
resolution: {integrity: sha512-+kzQ3IlO67+/eSC4kmbZbmqdPjmvAr8zjTsavyx/u5lqwrerutvhpDzCCBQMlFnEVgeXArF+Rf6FQKkqKrgpxA==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@modelcontextprotocol/sdk': ^1.5.0
|
||||
zod: '>= 3'
|
||||
'@modelcontextprotocol/sdk': '>=1.5.0 <1.10.0'
|
||||
peerDependenciesMeta:
|
||||
'@modelcontextprotocol/sdk':
|
||||
optional: true
|
||||
@@ -1122,6 +1125,10 @@ packages:
|
||||
resolution: {integrity: sha512-QN0twHNfe8mNJdH9unwsCK13GURU7oEAZqkBI+rsvpv1jrmserO+WnLE7jidR9W/1dxwZ0u/CB01mV2Gms/K2Q==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
|
||||
'@smithy/types@4.3.1':
|
||||
resolution: {integrity: sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@smithy/url-parser@3.0.7':
|
||||
resolution: {integrity: sha512-70UbSSR8J97c1rHZOWhl+VKiZDqHWxs/iW8ZHrHp5fCCPLSBE7GcUlUvKSle3Ca+J9LLbYCj/A79BxztBvAfpA==}
|
||||
|
||||
@@ -2919,6 +2926,10 @@ packages:
|
||||
node-notifier:
|
||||
optional: true
|
||||
|
||||
jiti@2.4.2:
|
||||
resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
|
||||
hasBin: true
|
||||
|
||||
jose@4.15.9:
|
||||
resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==}
|
||||
|
||||
@@ -4387,8 +4398,8 @@ packages:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
zod@3.24.1:
|
||||
resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==}
|
||||
zod@3.25.76:
|
||||
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
|
||||
|
||||
snapshots:
|
||||
|
||||
@@ -4455,7 +4466,7 @@ snapshots:
|
||||
'@aws-crypto/sha256-js': 5.2.0
|
||||
'@aws-crypto/supports-web-crypto': 5.2.0
|
||||
'@aws-crypto/util': 5.2.0
|
||||
'@aws-sdk/types': 3.667.0
|
||||
'@aws-sdk/types': 3.840.0
|
||||
'@aws-sdk/util-locate-window': 3.568.0
|
||||
'@smithy/util-utf8': 2.3.0
|
||||
tslib: 2.8.1
|
||||
@@ -4464,7 +4475,7 @@ snapshots:
|
||||
'@aws-crypto/sha256-js@5.2.0':
|
||||
dependencies:
|
||||
'@aws-crypto/util': 5.2.0
|
||||
'@aws-sdk/types': 3.667.0
|
||||
'@aws-sdk/types': 3.840.0
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
@@ -4475,7 +4486,7 @@ snapshots:
|
||||
|
||||
'@aws-crypto/util@5.2.0':
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.667.0
|
||||
'@aws-sdk/types': 3.840.0
|
||||
'@smithy/util-utf8': 2.3.0
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
@@ -4871,6 +4882,12 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@aws-sdk/types@3.840.0':
|
||||
dependencies:
|
||||
'@smithy/types': 4.3.1
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@aws-sdk/util-endpoints@3.667.0':
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.667.0
|
||||
@@ -5109,9 +5126,9 @@ snapshots:
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.9
|
||||
|
||||
'@eslint-community/eslint-utils@4.4.0(eslint@9.13.0)':
|
||||
'@eslint-community/eslint-utils@4.4.0(eslint@9.13.0(jiti@2.4.2))':
|
||||
dependencies:
|
||||
eslint: 9.13.0
|
||||
eslint: 9.13.0(jiti@2.4.2)
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
'@eslint-community/regexpp@4.11.1': {}
|
||||
@@ -5725,10 +5742,10 @@ snapshots:
|
||||
|
||||
'@pkgr/core@0.1.1': {}
|
||||
|
||||
'@polar-sh/sdk@0.32.3(zod@3.24.1)':
|
||||
'@polar-sh/sdk@0.34.9':
|
||||
dependencies:
|
||||
standardwebhooks: 1.0.0
|
||||
zod: 3.24.1
|
||||
zod: 3.25.76
|
||||
|
||||
'@protobufjs/aspromise@1.1.2':
|
||||
optional: true
|
||||
@@ -5967,6 +5984,11 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@smithy/types@4.3.1':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@smithy/url-parser@3.0.7':
|
||||
dependencies:
|
||||
'@smithy/querystring-parser': 3.0.7
|
||||
@@ -6292,15 +6314,15 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/yargs-parser': 21.0.3
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.10.0(@typescript-eslint/parser@8.10.0(eslint@9.13.0)(typescript@5.6.3))(eslint@9.13.0)(typescript@5.6.3)':
|
||||
'@typescript-eslint/eslint-plugin@8.10.0(@typescript-eslint/parser@8.10.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.11.1
|
||||
'@typescript-eslint/parser': 8.10.0(eslint@9.13.0)(typescript@5.6.3)
|
||||
'@typescript-eslint/parser': 8.10.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3)
|
||||
'@typescript-eslint/scope-manager': 8.10.0
|
||||
'@typescript-eslint/type-utils': 8.10.0(eslint@9.13.0)(typescript@5.6.3)
|
||||
'@typescript-eslint/utils': 8.10.0(eslint@9.13.0)(typescript@5.6.3)
|
||||
'@typescript-eslint/type-utils': 8.10.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3)
|
||||
'@typescript-eslint/utils': 8.10.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3)
|
||||
'@typescript-eslint/visitor-keys': 8.10.0
|
||||
eslint: 9.13.0
|
||||
eslint: 9.13.0(jiti@2.4.2)
|
||||
graphemer: 1.4.0
|
||||
ignore: 5.3.2
|
||||
natural-compare: 1.4.0
|
||||
@@ -6310,14 +6332,14 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.10.0(eslint@9.13.0)(typescript@5.6.3)':
|
||||
'@typescript-eslint/parser@8.10.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.10.0
|
||||
'@typescript-eslint/types': 8.10.0
|
||||
'@typescript-eslint/typescript-estree': 8.10.0(typescript@5.6.3)
|
||||
'@typescript-eslint/visitor-keys': 8.10.0
|
||||
debug: 4.3.7
|
||||
eslint: 9.13.0
|
||||
eslint: 9.13.0(jiti@2.4.2)
|
||||
optionalDependencies:
|
||||
typescript: 5.6.3
|
||||
transitivePeerDependencies:
|
||||
@@ -6328,10 +6350,10 @@ snapshots:
|
||||
'@typescript-eslint/types': 8.10.0
|
||||
'@typescript-eslint/visitor-keys': 8.10.0
|
||||
|
||||
'@typescript-eslint/type-utils@8.10.0(eslint@9.13.0)(typescript@5.6.3)':
|
||||
'@typescript-eslint/type-utils@8.10.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 8.10.0(typescript@5.6.3)
|
||||
'@typescript-eslint/utils': 8.10.0(eslint@9.13.0)(typescript@5.6.3)
|
||||
'@typescript-eslint/utils': 8.10.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3)
|
||||
debug: 4.3.7
|
||||
ts-api-utils: 1.3.0(typescript@5.6.3)
|
||||
optionalDependencies:
|
||||
@@ -6357,13 +6379,13 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.10.0(eslint@9.13.0)(typescript@5.6.3)':
|
||||
'@typescript-eslint/utils@8.10.0(eslint@9.13.0(jiti@2.4.2))(typescript@5.6.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@9.13.0)
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@9.13.0(jiti@2.4.2))
|
||||
'@typescript-eslint/scope-manager': 8.10.0
|
||||
'@typescript-eslint/types': 8.10.0
|
||||
'@typescript-eslint/typescript-estree': 8.10.0(typescript@5.6.3)
|
||||
eslint: 9.13.0
|
||||
eslint: 9.13.0(jiti@2.4.2)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
@@ -7196,19 +7218,19 @@ snapshots:
|
||||
optionalDependencies:
|
||||
source-map: 0.6.1
|
||||
|
||||
eslint-config-prettier@9.1.0(eslint@9.13.0):
|
||||
eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.2)):
|
||||
dependencies:
|
||||
eslint: 9.13.0
|
||||
eslint: 9.13.0(jiti@2.4.2)
|
||||
|
||||
eslint-plugin-prettier@5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0))(eslint@9.13.0)(prettier@3.3.3):
|
||||
eslint-plugin-prettier@5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.13.0(jiti@2.4.2)))(eslint@9.13.0(jiti@2.4.2))(prettier@3.3.3):
|
||||
dependencies:
|
||||
eslint: 9.13.0
|
||||
eslint: 9.13.0(jiti@2.4.2)
|
||||
prettier: 3.3.3
|
||||
prettier-linter-helpers: 1.0.0
|
||||
synckit: 0.9.2
|
||||
optionalDependencies:
|
||||
'@types/eslint': 9.6.1
|
||||
eslint-config-prettier: 9.1.0(eslint@9.13.0)
|
||||
eslint-config-prettier: 9.1.0(eslint@9.13.0(jiti@2.4.2))
|
||||
|
||||
eslint-scope@5.1.1:
|
||||
dependencies:
|
||||
@@ -7224,9 +7246,9 @@ snapshots:
|
||||
|
||||
eslint-visitor-keys@4.1.0: {}
|
||||
|
||||
eslint@9.13.0:
|
||||
eslint@9.13.0(jiti@2.4.2):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@9.13.0)
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@9.13.0(jiti@2.4.2))
|
||||
'@eslint-community/regexpp': 4.11.1
|
||||
'@eslint/config-array': 0.18.0
|
||||
'@eslint/core': 0.7.0
|
||||
@@ -7261,6 +7283,8 @@ snapshots:
|
||||
natural-compare: 1.4.0
|
||||
optionator: 0.9.4
|
||||
text-table: 0.2.0
|
||||
optionalDependencies:
|
||||
jiti: 2.4.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -8373,6 +8397,9 @@ snapshots:
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
jiti@2.4.2:
|
||||
optional: true
|
||||
|
||||
jose@4.15.9: {}
|
||||
|
||||
js-stringify@1.0.2:
|
||||
@@ -9894,4 +9921,4 @@ snapshots:
|
||||
|
||||
yocto-queue@0.1.0: {}
|
||||
|
||||
zod@3.24.1: {}
|
||||
zod@3.25.76: {}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { UsersModule } from 'src/users/users.module'
|
||||
import { GatewayModule } from 'src/gateway/gateway.module'
|
||||
import { PolarWebhookPayload, PolarWebhookPayloadSchema } from './schemas/polar-webhook-payload.schema'
|
||||
import { Device, DeviceSchema } from '../gateway/schemas/device.schema'
|
||||
import { CheckoutSession, CheckoutSessionSchema } from './schemas/checkout-session.schema'
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -19,6 +20,7 @@ import { Device, DeviceSchema } from '../gateway/schemas/device.schema'
|
||||
{ name: Subscription.name, schema: SubscriptionSchema },
|
||||
{ name: PolarWebhookPayload.name, schema: PolarWebhookPayloadSchema },
|
||||
{ name: Device.name, schema: DeviceSchema },
|
||||
{ name: CheckoutSession.name, schema: CheckoutSessionSchema },
|
||||
]),
|
||||
forwardRef(() => AuthModule),
|
||||
forwardRef(() => UsersModule),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common'
|
||||
import { BadRequestException, HttpException, HttpStatus, Injectable } from '@nestjs/common'
|
||||
import { InjectModel } from '@nestjs/mongoose'
|
||||
import { Model, Types } from 'mongoose'
|
||||
import { Plan, PlanDocument } from './schemas/plan.schema'
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
PolarWebhookPayload,
|
||||
PolarWebhookPayloadDocument,
|
||||
} from './schemas/polar-webhook-payload.schema'
|
||||
import { CheckoutSession, CheckoutSessionDocument } from './schemas/checkout-session.schema'
|
||||
|
||||
@Injectable()
|
||||
export class BillingService {
|
||||
@@ -31,6 +32,8 @@ export class BillingService {
|
||||
@InjectModel(Device.name) private deviceModel: Model<DeviceDocument>,
|
||||
@InjectModel(PolarWebhookPayload.name)
|
||||
private polarWebhookPayloadModel: Model<PolarWebhookPayloadDocument>,
|
||||
@InjectModel(CheckoutSession.name)
|
||||
private checkoutSessionModel: Model<CheckoutSessionDocument>,
|
||||
) {
|
||||
this.polarApi = new Polar({
|
||||
accessToken: process.env.POLAR_ACCESS_TOKEN ?? '',
|
||||
@@ -115,6 +118,15 @@ export class BillingService {
|
||||
}): Promise<CheckoutResponseDTO> {
|
||||
const isYearly = payload.isYearly
|
||||
|
||||
const existingCheckoutSession = await this.checkoutSessionModel.findOne({
|
||||
user: user._id,
|
||||
expiresAt: { $gt: new Date() },
|
||||
})
|
||||
|
||||
if (existingCheckoutSession) {
|
||||
return { redirectUrl: existingCheckoutSession.checkoutUrl }
|
||||
}
|
||||
|
||||
const selectedPlan = await this.planModel.findOne({
|
||||
name: payload.planName,
|
||||
})
|
||||
@@ -123,13 +135,12 @@ export class BillingService {
|
||||
!selectedPlan?.polarMonthlyProductId &&
|
||||
!selectedPlan?.polarYearlyProductId
|
||||
) {
|
||||
throw new Error('Plan cannot be purchased')
|
||||
throw new BadRequestException('Plan cannot be purchased')
|
||||
}
|
||||
|
||||
// const product = await this.polarApi.products.get(selectedPlan.polarProductId)
|
||||
|
||||
const discountId =
|
||||
payload.discountId ?? '48f62ff7-3cd8-46ec-8ca7-2e570dc9c522'
|
||||
const discountId = payload.discountId ?? process.env.POLAR_DEFAULT_DISCOUNT_ID
|
||||
|
||||
try {
|
||||
const checkoutOptions: any = {
|
||||
@@ -146,16 +157,36 @@ export class BillingService {
|
||||
metadata: {
|
||||
userId: user._id?.toString(),
|
||||
},
|
||||
}
|
||||
const discount = await this.polarApi.discounts.get({
|
||||
id: discountId,
|
||||
})
|
||||
if (discount) {
|
||||
checkoutOptions.discountId = discount.id
|
||||
externalCustomerId: user._id?.toString(),
|
||||
}
|
||||
|
||||
try {
|
||||
const discount = await this.polarApi.discounts.get({
|
||||
id: discountId,
|
||||
})
|
||||
if (discount) {
|
||||
checkoutOptions.discountId = discount.id
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('failed to get discount', error)
|
||||
}
|
||||
|
||||
|
||||
const checkout = await this.polarApi.checkouts.create(checkoutOptions)
|
||||
console.log(checkout)
|
||||
|
||||
|
||||
this.checkoutSessionModel.updateOne({
|
||||
user: user._id,
|
||||
},{
|
||||
user: user._id,
|
||||
checkoutSessionId: checkout.id,
|
||||
checkoutUrl: checkout.url,
|
||||
expiresAt: new Date(checkout.expiresAt),
|
||||
payload: checkout,
|
||||
}, { upsert: true }).catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
|
||||
return { redirectUrl: checkout.url }
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
|
||||
27
api/src/billing/schemas/checkout-session.schema.ts
Normal file
27
api/src/billing/schemas/checkout-session.schema.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
|
||||
import { Document, Types } from 'mongoose'
|
||||
import { User } from 'src/users/schemas/user.schema'
|
||||
|
||||
export type CheckoutSessionDocument = CheckoutSession & Document
|
||||
|
||||
@Schema({ timestamps: true })
|
||||
export class CheckoutSession {
|
||||
_id?: Types.ObjectId
|
||||
|
||||
@Prop({ type: Types.ObjectId, ref: User.name, required: true })
|
||||
user: User
|
||||
|
||||
@Prop({ type: String, required: true })
|
||||
checkoutSessionId: string
|
||||
|
||||
@Prop({ type: String, required: true })
|
||||
checkoutUrl: string
|
||||
|
||||
@Prop({ type: Date, required: true })
|
||||
expiresAt: Date
|
||||
|
||||
@Prop({ type: Object, required: true, default: {} })
|
||||
payload: any
|
||||
}
|
||||
|
||||
export const CheckoutSessionSchema = SchemaFactory.createForClass(CheckoutSession)
|
||||
Reference in New Issue
Block a user