Files
speckle-server/packages/server/modules/workspaces/services/cost.ts
T
2024-08-29 15:20:51 +02:00

147 lines
3.7 KiB
TypeScript

import { CountWorkspaceRoleWithOptionalProjectRole } from '@/modules/workspaces/domain/operations'
import { Roles, throwUncoveredError } from '@speckle/shared'
type KnownWorkspaceCostItemNames =
| 'workspace admin'
| 'workspace member'
| 'read/write guest'
| 'read only guest'
type KnownCurrencies = 'GBP'
type WorkspaceCostItem = {
name: KnownWorkspaceCostItemNames
description: string
count: number
cost: number
}
const getWorkspaceCostItemCost = ({
name
}: {
name: KnownWorkspaceCostItemNames
currency?: KnownCurrencies
}): number => {
switch (name) {
case 'workspace admin':
return 70
case 'workspace member':
return 50
case 'read/write guest':
return 10
case 'read only guest':
return 0
default:
throwUncoveredError(name)
}
}
type GetWorkspaceCostItems = (args: {
workspaceId: string
}) => Promise<WorkspaceCostItem[]>
export const getWorkspaceCostItemsFactory =
({
countRole
}: {
countRole: CountWorkspaceRoleWithOptionalProjectRole
}): GetWorkspaceCostItems =>
async ({ workspaceId }) => {
const [adminCount, memberCount, writeGuestCount, readGuestCount] =
await Promise.all([
countRole({ workspaceId, workspaceRole: Roles.Workspace.Admin }),
countRole({ workspaceId, workspaceRole: Roles.Workspace.Member }),
countRole({
workspaceId,
workspaceRole: Roles.Workspace.Guest,
projectRole: Roles.Stream.Contributor
}),
countRole({
workspaceId,
workspaceRole: Roles.Workspace.Guest,
projectRole: Roles.Stream.Reviewer
})
])
const workspaceCostItems: WorkspaceCostItem[] = []
if (adminCount)
workspaceCostItems.push({
name: 'workspace admin',
description: 'Workspace administrator with all the powers',
count: adminCount,
cost: getWorkspaceCostItemCost({ name: 'workspace admin' })
})
if (memberCount)
workspaceCostItems.push({
name: 'workspace member',
description: 'General workspace member',
count: memberCount,
cost: getWorkspaceCostItemCost({ name: 'workspace member' })
})
if (writeGuestCount)
workspaceCostItems.push({
name: 'read/write guest',
description: 'Workspace guest with write access to minimum 1 workspace project',
count: writeGuestCount,
cost: getWorkspaceCostItemCost({ name: 'read/write guest' })
})
if (readGuestCount)
workspaceCostItems.push({
name: 'read only guest',
description: 'Workspace guest with only read access to some workspace projects',
count: readGuestCount,
cost: getWorkspaceCostItemCost({ name: 'read only guest' })
})
return workspaceCostItems
}
type WorkspaceDiscount = {
name: string
amount: number
}
type WorkspaceCost = {
subTotal: number
currency: KnownCurrencies
items: WorkspaceCostItem[]
total: number
discount?: WorkspaceDiscount
}
export const calculateWorkspaceTotalCost = ({
subTotal,
discount
}: Pick<WorkspaceCost, 'subTotal' | 'discount'>) => {
if (!discount) {
return subTotal
}
return subTotal * discount?.amount
}
export const getWorkspaceCostFactory =
({
getWorkspaceCostItems,
discount
}: {
getWorkspaceCostItems: GetWorkspaceCostItems
discount?: WorkspaceDiscount
}) =>
async ({ workspaceId }: { workspaceId: string }): Promise<WorkspaceCost> => {
const items = await getWorkspaceCostItems({ workspaceId })
const subTotal = items.reduce((acc, { cost, count }) => acc + cost * count, 0)
return {
currency: 'GBP',
items,
subTotal,
discount,
total: calculateWorkspaceTotalCost({
subTotal,
discount
})
}
}