|
|
@ -1,8 +1,16 @@ |
|
|
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; |
|
|
|
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; |
|
|
|
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config'; |
|
|
|
import { PropertyService } from '@ghostfolio/api/services/property/property.service'; |
|
|
|
import { |
|
|
|
DEFAULT_LANGUAGE_CODE, |
|
|
|
PROPERTY_STRIPE_CONFIG |
|
|
|
} from '@ghostfolio/common/config'; |
|
|
|
import { parseDate } from '@ghostfolio/common/helper'; |
|
|
|
import { SubscriptionOffer, UserWithSettings } from '@ghostfolio/common/types'; |
|
|
|
import { SubscriptionOffer } from '@ghostfolio/common/interfaces'; |
|
|
|
import { |
|
|
|
SubscriptionOfferKey, |
|
|
|
UserWithSettings |
|
|
|
} from '@ghostfolio/common/types'; |
|
|
|
import { SubscriptionType } from '@ghostfolio/common/types/subscription-type.type'; |
|
|
|
|
|
|
|
import { Injectable, Logger } from '@nestjs/common'; |
|
|
@ -17,7 +25,8 @@ export class SubscriptionService { |
|
|
|
|
|
|
|
public constructor( |
|
|
|
private readonly configurationService: ConfigurationService, |
|
|
|
private readonly prismaService: PrismaService |
|
|
|
private readonly prismaService: PrismaService, |
|
|
|
private readonly propertyService: PropertyService |
|
|
|
) { |
|
|
|
this.stripe = new Stripe( |
|
|
|
this.configurationService.get('STRIPE_SECRET_KEY'), |
|
|
@ -36,6 +45,18 @@ export class SubscriptionService { |
|
|
|
priceId: string; |
|
|
|
user: UserWithSettings; |
|
|
|
}) { |
|
|
|
const subscriptionOffers: { |
|
|
|
[offer in SubscriptionOfferKey]: SubscriptionOffer; |
|
|
|
} = |
|
|
|
((await this.propertyService.getByKey(PROPERTY_STRIPE_CONFIG)) as any) ?? |
|
|
|
{}; |
|
|
|
|
|
|
|
const subscriptionOffer = Object.values(subscriptionOffers).find( |
|
|
|
(subscriptionOffer) => { |
|
|
|
return subscriptionOffer.priceId === priceId; |
|
|
|
} |
|
|
|
); |
|
|
|
|
|
|
|
const checkoutSessionCreateParams: Stripe.Checkout.SessionCreateParams = { |
|
|
|
cancel_url: `${this.configurationService.get('ROOT_URL')}/${ |
|
|
|
user.Settings?.settings?.language ?? DEFAULT_LANGUAGE_CODE |
|
|
@ -47,6 +68,13 @@ export class SubscriptionService { |
|
|
|
quantity: 1 |
|
|
|
} |
|
|
|
], |
|
|
|
locale: |
|
|
|
(user.Settings?.settings |
|
|
|
?.language as Stripe.Checkout.SessionCreateParams.Locale) ?? |
|
|
|
DEFAULT_LANGUAGE_CODE, |
|
|
|
metadata: subscriptionOffer |
|
|
|
? { subscriptionOffer: JSON.stringify(subscriptionOffer) } |
|
|
|
: {}, |
|
|
|
mode: 'payment', |
|
|
|
payment_method_types: ['card'], |
|
|
|
success_url: `${this.configurationService.get( |
|
|
@ -73,17 +101,25 @@ export class SubscriptionService { |
|
|
|
|
|
|
|
public async createSubscription({ |
|
|
|
duration = '1 year', |
|
|
|
durationExtension, |
|
|
|
price, |
|
|
|
userId |
|
|
|
}: { |
|
|
|
duration?: StringValue; |
|
|
|
durationExtension?: StringValue; |
|
|
|
price: number; |
|
|
|
userId: string; |
|
|
|
}) { |
|
|
|
let expiresAt = addMilliseconds(new Date(), ms(duration)); |
|
|
|
|
|
|
|
if (durationExtension) { |
|
|
|
expiresAt = addMilliseconds(expiresAt, ms(durationExtension)); |
|
|
|
} |
|
|
|
|
|
|
|
await this.prismaService.subscription.create({ |
|
|
|
data: { |
|
|
|
expiresAt, |
|
|
|
price, |
|
|
|
expiresAt: addMilliseconds(new Date(), ms(duration)), |
|
|
|
User: { |
|
|
|
connect: { |
|
|
|
id: userId |
|
|
@ -95,10 +131,21 @@ export class SubscriptionService { |
|
|
|
|
|
|
|
public async createSubscriptionViaStripe(aCheckoutSessionId: string) { |
|
|
|
try { |
|
|
|
let durationExtension: StringValue; |
|
|
|
|
|
|
|
const session = |
|
|
|
await this.stripe.checkout.sessions.retrieve(aCheckoutSessionId); |
|
|
|
|
|
|
|
const subscriptionOffer: SubscriptionOffer = JSON.parse( |
|
|
|
session.metadata.subscriptionOffer ?? '{}' |
|
|
|
); |
|
|
|
|
|
|
|
if (subscriptionOffer) { |
|
|
|
durationExtension = subscriptionOffer.durationExtension; |
|
|
|
} |
|
|
|
|
|
|
|
await this.createSubscription({ |
|
|
|
durationExtension, |
|
|
|
price: session.amount_total / 100, |
|
|
|
userId: session.client_reference_id |
|
|
|
}); |
|
|
@ -121,7 +168,7 @@ export class SubscriptionService { |
|
|
|
return new Date(a.expiresAt) > new Date(b.expiresAt) ? a : b; |
|
|
|
}); |
|
|
|
|
|
|
|
let offer: SubscriptionOffer = price ? 'renewal' : 'default'; |
|
|
|
let offer: SubscriptionOfferKey = price ? 'renewal' : 'default'; |
|
|
|
|
|
|
|
if (isBefore(createdAt, parseDate('2023-01-01'))) { |
|
|
|
offer = 'renewal-early-bird-2023'; |
|
|
|