mirror of
https://github.com/standardnotes/server
synced 2026-07-14 09:01:33 -04:00
119 lines
4.3 KiB
TypeScript
119 lines
4.3 KiB
TypeScript
import { inject, injectable } from 'inversify'
|
|
|
|
import TYPES from '../../../Bootstrap/Types'
|
|
import { UniqueEntityId } from '../../Core/UniqueEntityId'
|
|
import { MonthlyRevenue } from '../../Revenue/MonthlyRevenue'
|
|
import { RevenueModification } from '../../Revenue/RevenueModification'
|
|
import { RevenueModificationRepositoryInterface } from '../../Revenue/RevenueModificationRepositoryInterface'
|
|
import { Subscription } from '../../Subscription/Subscription'
|
|
import { User } from '../../User/User'
|
|
import { Result } from '../../Core/Result'
|
|
import { DomainUseCaseInterface } from '../DomainUseCaseInterface'
|
|
import { SaveRevenueModificationDTO } from './SaveRevenueModificationDTO'
|
|
import { TimerInterface } from '@standardnotes/time'
|
|
import { SubscriptionEventType } from '../../Subscription/SubscriptionEventType'
|
|
|
|
@injectable()
|
|
export class SaveRevenueModification implements DomainUseCaseInterface<RevenueModification> {
|
|
constructor(
|
|
@inject(TYPES.RevenueModificationRepository)
|
|
private revenueModificationRepository: RevenueModificationRepositoryInterface,
|
|
@inject(TYPES.Timer) private timer: TimerInterface,
|
|
) {}
|
|
|
|
async execute(dto: SaveRevenueModificationDTO): Promise<Result<RevenueModification>> {
|
|
const userOrError = User.create(
|
|
{
|
|
email: dto.userEmail,
|
|
},
|
|
new UniqueEntityId(dto.userUuid.value),
|
|
)
|
|
if (userOrError.isFailed()) {
|
|
return Result.fail<RevenueModification>(userOrError.getError())
|
|
}
|
|
const user = userOrError.getValue()
|
|
|
|
const subscriptionOrError = Subscription.create(
|
|
{
|
|
isFirstSubscriptionForUser: dto.newSubscriber,
|
|
payedAmount: dto.payedAmount,
|
|
planName: dto.planName,
|
|
billingFrequency: dto.billingFrequency,
|
|
},
|
|
new UniqueEntityId(dto.subscriptionId),
|
|
)
|
|
if (subscriptionOrError.isFailed()) {
|
|
return Result.fail<RevenueModification>(subscriptionOrError.getError())
|
|
}
|
|
const subscription = subscriptionOrError.getValue()
|
|
|
|
const previousMonthlyRevenueOrError = MonthlyRevenue.create(0)
|
|
if (previousMonthlyRevenueOrError.isFailed()) {
|
|
return Result.fail<RevenueModification>(previousMonthlyRevenueOrError.getError())
|
|
}
|
|
let previousMonthlyRevenue = previousMonthlyRevenueOrError.getValue()
|
|
|
|
const previousRevenueModification = await this.revenueModificationRepository.findLastByUserUuid(dto.userUuid)
|
|
if (previousRevenueModification !== null) {
|
|
previousMonthlyRevenue = previousRevenueModification.props.newMonthlyRevenue
|
|
}
|
|
const newMonthlyRevenueOrError = this.calculateNewMonthlyRevenue(
|
|
subscription,
|
|
previousMonthlyRevenue,
|
|
dto.eventType,
|
|
)
|
|
if (newMonthlyRevenueOrError.isFailed()) {
|
|
return Result.fail<RevenueModification>(newMonthlyRevenueOrError.getError())
|
|
}
|
|
const newMonthlyRevenue = newMonthlyRevenueOrError.getValue()
|
|
|
|
const revenueModificationOrError = RevenueModification.create({
|
|
eventType: dto.eventType,
|
|
subscription,
|
|
user,
|
|
previousMonthlyRevenue,
|
|
newMonthlyRevenue,
|
|
createdAt: this.timer.getTimestampInMicroseconds(),
|
|
})
|
|
|
|
if (revenueModificationOrError.isFailed()) {
|
|
return Result.fail<RevenueModification>(revenueModificationOrError.getError())
|
|
}
|
|
const revenueModification = revenueModificationOrError.getValue()
|
|
|
|
await this.revenueModificationRepository.save(revenueModification)
|
|
|
|
return Result.ok<RevenueModification>(revenueModification)
|
|
}
|
|
|
|
private calculateNewMonthlyRevenue(
|
|
subscription: Subscription,
|
|
previousMonthlyRevenue: MonthlyRevenue,
|
|
eventType: SubscriptionEventType,
|
|
): Result<MonthlyRevenue> {
|
|
let revenue = 0
|
|
switch (eventType.value) {
|
|
case 'SUBSCRIPTION_PURCHASED':
|
|
case 'SUBSCRIPTION_RENEWED':
|
|
case 'SUBSCRIPTION_DATA_MIGRATED':
|
|
revenue = subscription.props.payedAmount / subscription.props.billingFrequency
|
|
break
|
|
case 'SUBSCRIPTION_EXPIRED':
|
|
case 'SUBSCRIPTION_REFUNDED':
|
|
revenue = 0
|
|
break
|
|
case 'SUBSCRIPTION_CANCELLED':
|
|
revenue = previousMonthlyRevenue.value
|
|
break
|
|
}
|
|
|
|
const monthlyRevenueOrError = MonthlyRevenue.create(revenue)
|
|
|
|
if (monthlyRevenueOrError.isFailed()) {
|
|
return Result.fail<MonthlyRevenue>(monthlyRevenueOrError.getError())
|
|
}
|
|
|
|
return Result.ok<MonthlyRevenue>(monthlyRevenueOrError.getValue())
|
|
}
|
|
}
|