Files
speckle-server/packages/server/modules/gatekeeper/services/subscriptions.ts
T

81 lines
2.5 KiB
TypeScript

import {
GetWorkspacePlan,
GetWorkspaceSubscriptionBySubscriptionId,
PaidWorkspacePlanStatuses,
SubscriptionData,
UpsertPaidWorkspacePlan,
UpsertWorkspaceSubscription
} from '@/modules/gatekeeper/domain/billing'
import {
WorkspacePlanMismatchError,
WorkspacePlanNotFoundError,
WorkspaceSubscriptionNotFoundError
} from '@/modules/gatekeeper/errors/billing'
import { throwUncoveredError } from '@speckle/shared'
export const handleSubscriptionUpdateFactory =
({
upsertPaidWorkspacePlan,
getWorkspacePlan,
getWorkspaceSubscriptionBySubscriptionId,
upsertWorkspaceSubscription
}: {
getWorkspacePlan: GetWorkspacePlan
upsertPaidWorkspacePlan: UpsertPaidWorkspacePlan
getWorkspaceSubscriptionBySubscriptionId: GetWorkspaceSubscriptionBySubscriptionId
upsertWorkspaceSubscription: UpsertWorkspaceSubscription
}) =>
async ({ subscriptionData }: { subscriptionData: SubscriptionData }) => {
// we're only handling marking the sub scheduled for cancelation right now
const subscription = await getWorkspaceSubscriptionBySubscriptionId({
subscriptionId: subscriptionData.subscriptionId
})
if (!subscription) throw new WorkspaceSubscriptionNotFoundError()
const workspacePlan = await getWorkspacePlan({
workspaceId: subscription.workspaceId
})
if (!workspacePlan) throw new WorkspacePlanNotFoundError()
let status: PaidWorkspacePlanStatuses | undefined = undefined
if (
subscriptionData.status === 'active' &&
subscriptionData.cancelAt &&
subscriptionData.cancelAt > new Date()
) {
status = 'cancelationScheduled'
} else if (
subscriptionData.status === 'active' &&
subscriptionData.cancelAt === null
) {
status = 'valid'
} else if (subscriptionData.status === 'past_due') {
status = 'paymentFailed'
} else if (subscriptionData.status === 'canceled') {
status = 'canceled'
}
if (status) {
switch (workspacePlan.name) {
case 'team':
case 'pro':
case 'business':
break
case 'unlimited':
case 'academia':
throw new WorkspacePlanMismatchError()
default:
throwUncoveredError(workspacePlan)
}
await upsertPaidWorkspacePlan({
workspacePlan: { ...workspacePlan, status }
})
// if there is a status in the sub, we recognize, we need to update our state
await upsertWorkspaceSubscription({
workspaceSubscription: { ...subscription, subscriptionData }
})
}
}