import { CreateManagementLevelGroupSchema, CreateManagementLevelSchema, UpdateManagementLevelGroupSchema, UpdateManagementLevelSchema, } from "@capakraken/shared"; import { z } from "zod"; import { findUniqueOrThrow } from "../db/helpers.js"; import { createAuditEntry } from "../lib/audit.js"; import type { TRPCContext } from "../trpc.js"; import { assertManagementLevelDeletable, assertManagementLevelGroupNameAvailable, assertManagementLevelNameAvailable, buildManagementLevelCreateData, buildManagementLevelGroupCreateData, buildManagementLevelGroupUpdateData, buildManagementLevelUpdateData, } from "./management-level-support.js"; type ManagementLevelProcedureContext = Pick; function withAuditUser(userId: string | undefined) { return userId ? { userId } : {}; } export const managementLevelGroupIdInputSchema = z.object({ id: z.string() }); export const managementLevelGroupUpdateInputSchema = z.object({ id: z.string(), data: UpdateManagementLevelGroupSchema, }); export const managementLevelIdInputSchema = z.object({ id: z.string() }); export const managementLevelUpdateInputSchema = z.object({ id: z.string(), data: UpdateManagementLevelSchema, }); type ManagementLevelGroupIdInput = z.infer; type ManagementLevelGroupCreateInput = z.infer; type ManagementLevelGroupUpdateInput = z.infer; type ManagementLevelCreateInput = z.infer; type ManagementLevelUpdateInput = z.infer; type ManagementLevelIdInput = z.infer; export async function listManagementLevelGroups( ctx: ManagementLevelProcedureContext, ) { return ctx.db.managementLevelGroup.findMany({ include: { levels: { orderBy: { name: "asc" } } }, orderBy: { sortOrder: "asc" }, }); } export async function getManagementLevelGroupById( ctx: ManagementLevelProcedureContext, input: ManagementLevelGroupIdInput, ) { return findUniqueOrThrow( ctx.db.managementLevelGroup.findUnique({ where: { id: input.id }, include: { levels: { orderBy: { name: "asc" } }, _count: { select: { resources: true } }, }, }), "Management level group", ); } export async function createManagementLevelGroup( ctx: ManagementLevelProcedureContext, input: ManagementLevelGroupCreateInput, ) { await assertManagementLevelGroupNameAvailable(ctx.db, input.name); const created = await ctx.db.managementLevelGroup.create({ data: buildManagementLevelGroupCreateData(input), include: { levels: true }, }); void createAuditEntry({ db: ctx.db, entityType: "ManagementLevelGroup", entityId: created.id, entityName: created.name, action: "CREATE", ...withAuditUser(ctx.dbUser?.id), after: created as unknown as Record, source: "ui", }); return created; } export async function updateManagementLevelGroup( ctx: ManagementLevelProcedureContext, input: ManagementLevelGroupUpdateInput, ) { const existing = await findUniqueOrThrow( ctx.db.managementLevelGroup.findUnique({ where: { id: input.id } }), "Group", ); if (input.data.name && input.data.name !== existing.name) { await assertManagementLevelGroupNameAvailable(ctx.db, input.data.name, existing.id); } const updated = await ctx.db.managementLevelGroup.update({ where: { id: input.id }, data: buildManagementLevelGroupUpdateData(input.data), include: { levels: true }, }); void createAuditEntry({ db: ctx.db, entityType: "ManagementLevelGroup", entityId: updated.id, entityName: updated.name, action: "UPDATE", ...withAuditUser(ctx.dbUser?.id), before: existing as unknown as Record, after: updated as unknown as Record, source: "ui", }); return updated; } export async function createManagementLevel( ctx: ManagementLevelProcedureContext, input: ManagementLevelCreateInput, ) { await findUniqueOrThrow( ctx.db.managementLevelGroup.findUnique({ where: { id: input.groupId } }), "Group", ); await assertManagementLevelNameAvailable(ctx.db, input.name); const created = await ctx.db.managementLevel.create({ data: buildManagementLevelCreateData(input), }); void createAuditEntry({ db: ctx.db, entityType: "ManagementLevel", entityId: created.id, entityName: created.name, action: "CREATE", ...withAuditUser(ctx.dbUser?.id), after: created as unknown as Record, source: "ui", }); return created; } export async function updateManagementLevel( ctx: ManagementLevelProcedureContext, input: ManagementLevelUpdateInput, ) { const existing = await findUniqueOrThrow( ctx.db.managementLevel.findUnique({ where: { id: input.id } }), "Level", ); if (input.data.name && input.data.name !== existing.name) { await assertManagementLevelNameAvailable(ctx.db, input.data.name, existing.id); } const updated = await ctx.db.managementLevel.update({ where: { id: input.id }, data: buildManagementLevelUpdateData(input.data), }); void createAuditEntry({ db: ctx.db, entityType: "ManagementLevel", entityId: updated.id, entityName: updated.name, action: "UPDATE", ...withAuditUser(ctx.dbUser?.id), before: existing as unknown as Record, after: updated as unknown as Record, source: "ui", }); return updated; } export async function deleteManagementLevel( ctx: ManagementLevelProcedureContext, input: ManagementLevelIdInput, ) { const level = await findUniqueOrThrow( ctx.db.managementLevel.findUnique({ where: { id: input.id }, include: { _count: { select: { resources: true } } }, }), "Level", ); assertManagementLevelDeletable(level); await ctx.db.managementLevel.delete({ where: { id: input.id } }); void createAuditEntry({ db: ctx.db, entityType: "ManagementLevel", entityId: level.id, entityName: level.name, action: "DELETE", ...withAuditUser(ctx.dbUser?.id), before: level as unknown as Record, source: "ui", }); return { success: true }; }