import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/core"; import type { WorkCenterOverheadAbsorptionMethod } from "../generated/enums"; import type { Transaction } from "../generated/kysely-tailordb"; import { InvalidScopeError, DuplicateWorkCenterCodeError, InvalidCapacityError, InvalidRateError, OverheadCurrencyRequiredError, } from "../lib/errors.generated"; export interface CreateWorkCenterInput { code: string; companyId: string; siteId?: string | null; capacityAssumptions: number; laborRate?: number | null; machineRate?: number | null; calendarReference?: string | null; overheadAbsorptionMethod?: WorkCenterOverheadAbsorptionMethod | null; overheadAbsorptionCurrency?: string | null; } /** * Function: createWorkCenter * * Creates a new work center in DRAFT status with scope, capacity assumptions, * rate context, and optional overhead-absorption policy. */ export async function run>( db: Transaction, input: CreateWorkCenterInput & CF, _ctx: CommandContext, ) { const { code, companyId, siteId, capacityAssumptions, laborRate, machineRate, calendarReference, overheadAbsorptionMethod, overheadAbsorptionCurrency, ...customFields } = input; // 1. Validate scope — company is always required if (!companyId) { return err(new InvalidScopeError(code)); } // 2. Validate capacity > 0 if (capacityAssumptions <= 0) { return err(new InvalidCapacityError(code)); } // 3. Validate rates >= 0 if (laborRate != null && laborRate < 0) { return err(new InvalidRateError(code)); } if (machineRate != null && machineRate < 0) { return err(new InvalidRateError(code)); } // 4. Overhead currency required for FIXED_AMOUNT_PER_GOOD_UNIT if (overheadAbsorptionMethod === "FIXED_AMOUNT_PER_GOOD_UNIT" && !overheadAbsorptionCurrency) { return err(new OverheadCurrencyRequiredError(code)); } // 5. Check code uniqueness within company+site scope let existingQuery = db .selectFrom("WorkCenter") .selectAll() .where("code", "=", code) .where("companyId", "=", companyId); if (siteId) { existingQuery = existingQuery.where("siteId", "=", siteId); } const existing = await existingQuery.forUpdate().executeTakeFirst(); if (existing) { return err(new DuplicateWorkCenterCodeError(code)); } // 6. Create work center in DRAFT status const workCenter = await db .insertInto("WorkCenter") .values({ ...(customFields as Record), code, companyId, siteId: siteId ?? null, capacityAssumptions, laborRate: laborRate ?? null, machineRate: machineRate ?? null, calendarReference: calendarReference ?? null, overheadAbsorptionMethod: overheadAbsorptionMethod ?? null, overheadAbsorptionCurrency: overheadAbsorptionCurrency ?? null, status: "DRAFT", }) .returningAll() .executeTakeFirstOrThrow(); return ok({ workCenter }); }