import { ok, err } from "@tailor-platform/erp-kit/core"; import { uoMCategoryLifecycle } from "../db/uoMCategory.lifecycle.generated"; import type { Transaction } from "../generated/kysely-tailordb"; import { CategoryHasActiveUnitsError, UomCategoryNotFoundError } from "../lib/errors.generated"; export interface DeactivateCategoryInput { categoryId: string; } /** * Function: deactivateCategory * * Disables a UoM category from being used in new product assignments * while preserving historical data. All units must be deactivated first. */ export async function run(db: Transaction, input: DeactivateCategoryInput) { // 1. Find category by ID const uoMCategory = await db .selectFrom("UoMCategory") .selectAll() .where("id", "=", input.categoryId) .forUpdate() .executeTakeFirst(); // 2. If not found, throw error if (!uoMCategory) { return err(new UomCategoryNotFoundError(input.categoryId)); } // Active units must be deactivated before their category const activeUnits = await db .selectFrom("Unit") .selectAll() .where("categoryId", "=", input.categoryId) .where("status", "=", "ACTIVE") .execute(); if (activeUnits.length > 0) { return err(new CategoryHasActiveUnitsError(input.categoryId)); } // 3. If already inactive, return category (idempotent) const nextStatus = uoMCategoryLifecycle.tryTransition(uoMCategory.status, "deactivate"); if (!nextStatus) { return ok({ uoMCategory }); } // 4. Update status to INACTIVE const updatedCategory = await db .updateTable("UoMCategory") .set({ status: nextStatus, }) .where("id", "=", input.categoryId) .returningAll() .executeTakeFirstOrThrow(); // 5. Return updated category return ok({ uoMCategory: updatedCategory }); }