import type { Prisma, PrismaClient } from "@capakraken/db"; import { CreateOrgUnitSchema, UpdateOrgUnitSchema, type OrgUnitTree } from "@capakraken/shared"; import { TRPCError } from "@trpc/server"; import { z } from "zod"; type OrgUnitDb = Pick; type OrgUnitListInput = { level?: number | undefined; parentId?: string | undefined; isActive?: boolean | undefined; }; type OrgUnitTreeNode = { id: string; name: string; shortName: string | null; level: number; parentId: string | null; sortOrder: number; isActive: boolean; createdAt: Date; updatedAt: Date; }; type ParentOrgUnitRecord = { level: number; }; type CreateOrgUnitInput = z.infer; type UpdateOrgUnitInput = z.infer; export function buildOrgUnitListWhere( input: OrgUnitListInput, ): Prisma.OrgUnitWhereInput { return { ...(input.level !== undefined ? { level: input.level } : {}), ...(input.parentId !== undefined ? { parentId: input.parentId } : {}), ...(input.isActive !== undefined ? { isActive: input.isActive } : {}), }; } export function buildOrgUnitTree( flatItems: OrgUnitTreeNode[], parentId: string | null = null, ): OrgUnitTree[] { return flatItems .filter((item) => item.parentId === parentId) .sort((a, b) => a.sortOrder - b.sortOrder || a.name.localeCompare(b.name)) .map((item) => ({ ...item, children: buildOrgUnitTree(flatItems, item.id), })); } export async function findOrgUnitByIdentifier( db: OrgUnitDb, identifier: string, extraArgs: Record, ): Promise { const normalizedIdentifier = identifier.trim(); let unit = await db.orgUnit.findUnique({ where: { id: normalizedIdentifier }, ...extraArgs, }) as TOrgUnit | null; if (!unit) { unit = await db.orgUnit.findFirst({ where: { name: { equals: normalizedIdentifier, mode: "insensitive" } }, ...extraArgs, }) as TOrgUnit | null; } if (!unit) { unit = await db.orgUnit.findFirst({ where: { shortName: { equals: normalizedIdentifier, mode: "insensitive" } }, ...extraArgs, }) as TOrgUnit | null; } if (!unit) { unit = await db.orgUnit.findFirst({ where: { OR: [ { name: { contains: normalizedIdentifier, mode: "insensitive" } }, { shortName: { contains: normalizedIdentifier, mode: "insensitive" } }, ], }, ...extraArgs, }) as TOrgUnit | null; } if (!unit) { throw new TRPCError({ code: "NOT_FOUND", message: `Org unit not found: ${normalizedIdentifier}`, }); } return unit; } export function assertOrgUnitParentLevel( parent: ParentOrgUnitRecord, childLevel: number, ): void { if (parent.level >= childLevel) { throw new TRPCError({ code: "BAD_REQUEST", message: `Child level (${childLevel}) must be greater than parent level (${parent.level})`, }); } } export function buildOrgUnitCreateData( input: CreateOrgUnitInput, ): Prisma.OrgUnitUncheckedCreateInput { return { name: input.name, ...(input.shortName !== undefined ? { shortName: input.shortName } : {}), level: input.level, ...(input.parentId ? { parentId: input.parentId } : {}), sortOrder: input.sortOrder, }; } export function buildOrgUnitUpdateData( input: UpdateOrgUnitInput, ): Prisma.OrgUnitUncheckedUpdateInput { return { ...(input.name !== undefined ? { name: input.name } : {}), ...(input.shortName !== undefined ? { shortName: input.shortName } : {}), ...(input.sortOrder !== undefined ? { sortOrder: input.sortOrder } : {}), ...(input.isActive !== undefined ? { isActive: input.isActive } : {}), ...(input.parentId !== undefined ? { parentId: input.parentId } : {}), }; }