Files
speckle-server/packages/server/modules/gatekeeper/services/workspacePlans.ts
T
Gergő Jedlicska a3644a50c5 gergo/web 2931 introduce missing workspace plans (#4323)
* fix(gatekeeper): missing priceId-s should stop the server from booting

* feat(shared): add all new workspace plans

* feat(billing): add new world plans

* feat(ci): use stripe sandbox id-s from test env vars

* chore(ci): remove defunct stripe context

* chore(server-env): fix server env example

* feat(gatekeeper): add missing plans to graphql schema

* test(gatekeeper): update plan upgrade tests to match implementation

* fix(ci): update ci .env source

* fix(ci): we do need some secrets from stripe

* fix(ci): run gql schema introspect with the test env

* fix(frontend): format new plan names

* chore(ci): temp disable gql schema checks

* feat(helm): add unlimited seat prices env vars

* feat(helm): add unlimited seat prices to values

* feat(gatekeeper): do not load priceId-s as a side effect, load with module init
2025-04-07 15:24:57 +02:00

102 lines
3.0 KiB
TypeScript

import { 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 } from '@speckle/shared'
export const updateWorkspacePlanFactory =
({
getWorkspace,
upsertWorkspacePlan,
emitEvent
}: {
getWorkspace: GetWorkspace
// im using the generic function here, cause the service is
// responsible for protecting the permutations
upsertWorkspacePlan: UpsertWorkspacePlan
emitEvent: EventBusEmit
}) =>
async ({
workspaceId,
name,
status
}: Pick<WorkspacePlan, 'workspaceId' | 'name' | 'status'>): Promise<void> => {
const workspace = await getWorkspace({
workspaceId
})
if (!workspace) throw new WorkspaceNotFoundError()
const createdAt = new Date()
switch (name) {
case 'starter':
switch (status) {
case 'trial':
case 'expired':
case 'valid':
case 'cancelationScheduled':
case 'canceled':
case 'paymentFailed':
await upsertWorkspacePlan({
workspacePlan: { workspaceId, status, name, createdAt }
})
break
default:
throwUncoveredError(status)
}
break
case 'business':
case 'plus':
case 'team':
case 'teamUnlimited':
case 'pro':
case 'proUnlimited':
switch (status) {
case 'trial':
case 'expired':
throw new InvalidWorkspacePlanStatus()
case 'valid':
case 'cancelationScheduled':
case 'canceled':
case 'paymentFailed':
await upsertWorkspacePlan({
workspacePlan: { workspaceId, status, name, createdAt }
})
break
default:
throwUncoveredError(status)
}
break
case 'free':
case 'academia':
case 'unlimited':
case 'starterInvoiced':
case 'plusInvoiced':
case 'businessInvoiced':
case 'teamUnlimitedInvoiced':
case 'proUnlimitedInvoiced':
switch (status) {
case 'valid':
await upsertWorkspacePlan({
workspacePlan: { workspaceId, status, name, createdAt }
})
break
case 'cancelationScheduled':
case 'canceled':
case 'expired':
case 'paymentFailed':
case 'trial':
throw new InvalidWorkspacePlanStatus()
default:
throwUncoveredError(status)
}
break
default:
throwUncoveredError(name)
}
await emitEvent({
eventName: 'gatekeeper.workspace-plan-updated',
payload: { workspacePlan: { name, status, workspaceId } }
})
}