diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index d7bfd01b8d..f2f0246b01 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -139,6 +139,7 @@ model Bundle { state String @default("Active") // Active, Inactive limitCountPerUser Int // limit count of application per user could create subscriptionOptions BundleSubscriptionOption[] + maxRenewalTime Int // in seconds resource BundleResource diff --git a/server/src/initializer/initializer.service.ts b/server/src/initializer/initializer.service.ts index 919e8cab63..85a8b493c6 100644 --- a/server/src/initializer/initializer.service.ts +++ b/server/src/initializer/initializer.service.ts @@ -82,6 +82,7 @@ export class InitializerService { displayName: 'Standard', limitCountPerUser: 10, priority: 0, + maxRenewalTime: 3600 * 24 * 365 * 10, resource: { limitCPU: 1 * CPU_UNIT, limitMemory: 512, @@ -105,11 +106,25 @@ export class InitializerService { subscriptionOptions: [ { name: 'monthly', - displayName: 'Monthly', + displayName: '1 Month', duration: 31 * 24 * 3600, price: 0, specialPrice: 0, }, + { + name: 'half-yearly', + displayName: '6 Months', + duration: 6 * 31 * 24 * 3600, + price: 0, + specialPrice: 0, + }, + { + name: 'yearly', + displayName: '12 Months', + duration: 12 * 31 * 24 * 3600, + price: 0, + specialPrice: 0, + }, ], region: { connect: { diff --git a/server/src/subscription/subscription.controller.ts b/server/src/subscription/subscription.controller.ts index a9d23ff413..fdc00d7b2a 100644 --- a/server/src/subscription/subscription.controller.ts +++ b/server/src/subscription/subscription.controller.ts @@ -98,7 +98,7 @@ export class SubscriptionController { // check account balance const account = await this.accountService.findOne(user.id) const balance = account?.balance || 0 - const priceAmount = option.specialPrice || option.price + const priceAmount = option.specialPrice if (balance < priceAmount) { return ResponseUtil.error( `account balance is not enough, need ${priceAmount} but only ${account.balance}`, @@ -170,14 +170,28 @@ export class SubscriptionController { if (!option) { return ResponseUtil.error(`duration not supported in bundle`) } - const priceAmount = option.specialPrice || option.price + const priceAmount = option.specialPrice + + // check max renewal time + const MAX_RENEWAL_AT = Date.now() + bundle.maxRenewalTime * 1000 + const newExpiredAt = subscription.expiredAt.getTime() + duration * 1000 + if (newExpiredAt > MAX_RENEWAL_AT) { + return ResponseUtil.error( + `max renewal time is ${MAX_RENEWAL_AT} for bundle ${bundle.name}`, + ) + } + + // check account balance + const account = await this.accountService.findOne(user.id) + const balance = account?.balance || 0 + if (balance < priceAmount) { + return ResponseUtil.error( + `account balance is not enough, need ${priceAmount} but only ${account.balance}`, + ) + } // renew subscription - const res = await this.subscriptService.renew( - subscription, - duration, - priceAmount, - ) + const res = await this.subscriptService.renew(subscription, option) return ResponseUtil.ok(res) } diff --git a/server/src/subscription/subscription.service.ts b/server/src/subscription/subscription.service.ts index ac6532a661..729efa6622 100644 --- a/server/src/subscription/subscription.service.ts +++ b/server/src/subscription/subscription.service.ts @@ -53,7 +53,7 @@ export class SubscriptionService { data: { subscriptionId: subscription.id, duration: option.duration, - amount: option.price, + amount: option.specialPrice, phase: SubscriptionRenewalPhase.Pending, lockedAt: TASK_LOCK_INIT_TIME, createdBy: userid, @@ -106,17 +106,13 @@ export class SubscriptionService { /** * Renew a subscription by creating a subscription renewal */ - async renew( - subscription: Subscription, - duration: number, - priceAmount: number, - ) { + async renew(subscription: Subscription, option: BundleSubscriptionOption) { // create subscription renewal const res = await this.prisma.subscriptionRenewal.create({ data: { subscriptionId: subscription.id, - duration: duration, - amount: priceAmount, + duration: option.duration, + amount: option.specialPrice, phase: SubscriptionRenewalPhase.Pending, lockedAt: TASK_LOCK_INIT_TIME, createdBy: subscription.createdBy,