import { ok, err } from "@tailor-platform/erp-kit/core"; import type { Transaction } from "../generated/kysely-tailordb"; import { DuplicateCategoryNameError } from "../lib/errors.generated"; interface CreateCategoryInput> { name: string; description?: string; referenceUnit: { name: string; symbol: string; roundingPrecision: number; } & UnitCF; } /** * Function: createCategory * * Establishes a new unit of measure category that groups related units. * Creates the category with a reference unit that has conversion factor 1.0. */ export async function run< CatCF extends Record, UnitCF extends Record, >(db: Transaction, input: CreateCategoryInput & CatCF) { const { name, description, referenceUnit, ...categoryCustomFields } = input; const { name: unitName, symbol, roundingPrecision, ...unitCustomFields } = referenceUnit; // 1. Check if category name already exists const existingCategory = await db .selectFrom("UoMCategory") .selectAll() .where("name", "=", name) .forUpdate() .executeTakeFirst(); if (existingCategory) { return err(new DuplicateCategoryNameError(name)); } // 2. Create category without reference unit first const category = await db .insertInto("UoMCategory") .values({ ...(categoryCustomFields as Record), name, description: description ?? null, referenceUnitId: null, status: "ACTIVE" as const, }) .returningAll() .executeTakeFirstOrThrow(); // 3. Create reference unit with conversion factor 1.0 const createdReferenceUnit = await db .insertInto("Unit") .values({ ...(unitCustomFields as Record), name: unitName, symbol, categoryId: category.id, conversionFactor: 1.0, roundingPrecision, status: "ACTIVE" as const, }) .returningAll() .executeTakeFirstOrThrow(); // 4. Update category with reference unit ID const updatedCategory = await db .updateTable("UoMCategory") .set({ referenceUnitId: createdReferenceUnit.id, }) .where("id", "=", category.id) .returningAll() .executeTakeFirstOrThrow(); return ok({ uoMCategory: updatedCategory, referenceUnit: createdReferenceUnit }); }