Files
speckle-server/packages/server/modules/gatekeeper/services/workspacePlans.ts
T
Gergő Jedlicska 72ecb9197b feat(gatekeeper): intoduce the enterprise plan (#4882)
* feat(gatekeeper): intoduce the enterprise plan

* chore(server): remove more "magic strings"

* test(shared): fix plan tests with enterprise case

* Small change to format plan name

---------

Co-authored-by: Mike Tasset <mike.tasset@gmail.com>
2025-06-05 11:07:59 +02:00

93 lines
2.8 KiB
TypeScript

import {
GetWorkspacePlan,
UpsertWorkspacePlan
} from '@/modules/gatekeeper/domain/billing'
import { InvalidWorkspacePlanStatus } from '@/modules/gatekeeper/errors/billing'
import { EventBusEmit } from '@/modules/shared/services/eventBus'
import { GetWorkspace } from '@/modules/workspaces/domain/operations'
import { WorkspaceNotFoundError } from '@/modules/workspaces/errors/workspace'
import { throwUncoveredError, WorkspacePlan, WorkspacePlans } from '@speckle/shared'
export const updateWorkspacePlanFactory =
({
getWorkspace,
upsertWorkspacePlan,
getWorkspacePlan,
emitEvent
}: {
getWorkspace: GetWorkspace
// im using the generic function here, cause the service is
// responsible for protecting the permutations
upsertWorkspacePlan: UpsertWorkspacePlan
getWorkspacePlan: GetWorkspacePlan
emitEvent: EventBusEmit
}) =>
async ({
workspaceId,
name,
status
}: Pick<WorkspacePlan, 'workspaceId' | 'name' | 'status'>): Promise<void> => {
const workspace = await getWorkspace({
workspaceId
})
if (!workspace) throw new WorkspaceNotFoundError()
const previousPlan = await getWorkspacePlan({ workspaceId })
const createdAt = new Date()
const updatedAt = new Date()
switch (name) {
case WorkspacePlans.Team:
case WorkspacePlans.TeamUnlimited:
case WorkspacePlans.Pro:
case WorkspacePlans.ProUnlimited:
switch (status) {
case 'valid':
case 'cancelationScheduled':
case 'canceled':
case 'paymentFailed':
await upsertWorkspacePlan({
workspacePlan: { workspaceId, status, name, createdAt, updatedAt }
})
break
default:
throwUncoveredError(status)
}
break
case WorkspacePlans.Free:
case WorkspacePlans.Academia:
case WorkspacePlans.Unlimited:
case WorkspacePlans.Enterprise:
case WorkspacePlans.TeamUnlimitedInvoiced:
case WorkspacePlans.ProUnlimitedInvoiced:
switch (status) {
case 'valid':
await upsertWorkspacePlan({
workspacePlan: { workspaceId, status, name, createdAt, updatedAt }
})
break
case 'cancelationScheduled':
case 'canceled':
case 'paymentFailed':
throw new InvalidWorkspacePlanStatus()
default:
throwUncoveredError(status)
}
break
default:
throwUncoveredError(name)
}
await emitEvent({
eventName: 'gatekeeper.workspace-plan-updated',
payload: {
workspacePlan: {
name,
status,
workspaceId
},
...(previousPlan && {
previousPlan: { name: previousPlan.name }
})
}
})
}