import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/core"; import type { WorkCenterOverheadAbsorptionMethod } from "../generated/enums"; import type { Transaction, Updateable } from "../generated/kysely-tailordb"; import { WorkCenterNotFoundError, InvalidCapacityError, InvalidRateError, OverheadCurrencyRequiredError, } from "../lib/errors.generated"; export type UpdateWorkCenterInput = ( | { id: string } | { companyId: string; siteId: string; code: string } ) & { capacityAssumptions?: number; laborRate?: number | null; machineRate?: number | null; calendarReference?: string | null; overheadAbsorptionMethod?: WorkCenterOverheadAbsorptionMethod | null; overheadAbsorptionCurrency?: string | null; }; /** * Function: updateWorkCenter * * Revises mutable work-center master data such as capacity, calendar, * rate assumptions, and overhead policy. Only DRAFT or ACTIVE work centers * may be updated. */ export async function run>( db: Transaction, input: UpdateWorkCenterInput & Omit, "status">, _ctx: CommandContext, ) { const { capacityAssumptions, laborRate, machineRate, calendarReference, overheadAbsorptionMethod, overheadAbsorptionCurrency, ...customFields } = input; delete (customFields as Record).id; delete (customFields as Record).companyId; delete (customFields as Record).siteId; delete (customFields as Record).code; // 1. Check work center exists let workCenterQuery = db.selectFrom("WorkCenter").selectAll(); if ("id" in input) { workCenterQuery = workCenterQuery.where("id", "=", (input as { id: string }).id); } else { const lookup = input as { companyId: string; siteId: string; code: string }; workCenterQuery = workCenterQuery .where("companyId", "=", lookup.companyId) .where("siteId", "=", lookup.siteId) .where("code", "=", lookup.code); } const workCenter = await workCenterQuery.forUpdate().executeTakeFirst(); if (!workCenter) { const key = "id" in input ? (input as { id: string }).id : `${(input as { companyId: string; siteId: string; code: string }).companyId}:${(input as { companyId: string; siteId: string; code: string }).siteId}:${(input as { companyId: string; siteId: string; code: string }).code}`; return err(new WorkCenterNotFoundError(key)); } // 2. Only DRAFT or ACTIVE allowed if (workCenter.status !== "DRAFT" && workCenter.status !== "ACTIVE") { return err(new WorkCenterNotFoundError(workCenter.id)); } // 3. Validate capacity if provided if (capacityAssumptions != null && capacityAssumptions <= 0) { return err(new InvalidCapacityError(workCenter.id)); } // 4. Validate rates if provided if (laborRate != null && laborRate < 0) { return err(new InvalidRateError(workCenter.id)); } if (machineRate != null && machineRate < 0) { return err(new InvalidRateError(workCenter.id)); } // Resolve the effective overhead method after update const effectiveMethod = overheadAbsorptionMethod !== undefined ? overheadAbsorptionMethod : workCenter.overheadAbsorptionMethod; const effectiveCurrency = overheadAbsorptionCurrency !== undefined ? overheadAbsorptionCurrency : workCenter.overheadAbsorptionCurrency; // 5. Overhead currency required for FIXED_AMOUNT_PER_GOOD_UNIT if (effectiveMethod === "FIXED_AMOUNT_PER_GOOD_UNIT" && !effectiveCurrency) { return err(new OverheadCurrencyRequiredError(workCenter.id)); } // 6. Build update set const updateSet: Updateable<"WorkCenter"> = { ...(customFields as Updateable<"WorkCenter">), }; if (capacityAssumptions !== undefined) updateSet.capacityAssumptions = capacityAssumptions; if (laborRate !== undefined) updateSet.laborRate = laborRate; if (machineRate !== undefined) updateSet.machineRate = machineRate; if (calendarReference !== undefined) updateSet.calendarReference = calendarReference; if (overheadAbsorptionMethod !== undefined) updateSet.overheadAbsorptionMethod = overheadAbsorptionMethod; if (overheadAbsorptionCurrency !== undefined) updateSet.overheadAbsorptionCurrency = overheadAbsorptionCurrency; if (Object.keys(updateSet).length === 0) { return ok({ workCenter }); } // 7. Persist changes const updated = await db .updateTable("WorkCenter") .set(updateSet) .where("id", "=", workCenter.id) .returningAll() .executeTakeFirstOrThrow(); return ok({ workCenter: updated }); }