import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/core"; import type { AccountAccountType } from "../generated/enums"; import type { Transaction, Updateable } from "../generated/kysely-tailordb"; import { AccountNotFoundError, NameRequiredError, InvalidAccountCodeError, DuplicateAccountCodeError, } from "../lib/errors.generated"; export type UpdateAccountInput = { id: string; name?: string; code?: string; accountType?: AccountAccountType; }; /** * Function: updateAccount * * Modifies the core fields of an existing GL account. */ export async function run>( db: Transaction, input: UpdateAccountInput & Omit, "status">, _ctx: CommandContext, ) { const { id, name, code, accountType, ...customFields } = input; // 1. Find account with forUpdate const account = await db .selectFrom("Account") .selectAll() .where("id", "=", id) .forUpdate() .executeTakeFirst(); if (!account) { return err(new AccountNotFoundError(id)); } // 2. Validate name if provided if (name?.trim() === "") { return err(new NameRequiredError(id)); } // 3. Validate code if changed if (code !== undefined && code !== account.code) { if (!/^\d+$/.test(code)) { return err(new InvalidAccountCodeError(code)); } const existingAccount = await db .selectFrom("Account") .selectAll() .where("companyId", "=", account.companyId) .where("code", "=", code) .executeTakeFirst(); if (existingAccount && existingAccount.id !== id) { return err(new DuplicateAccountCodeError(code)); } } // 4. Build update data const RESERVED_KEYS = new Set([ "id", "companyId", "name", "code", "accountType", "status", "createdAt", "updatedAt", ]); const safeCustomFields: Record = {}; for (const [key, value] of Object.entries(customFields as Record)) { if (!RESERVED_KEYS.has(key)) { safeCustomFields[key] = value; } } const updateData: Updateable<"Account"> = { ...(safeCustomFields as Updateable<"Account">), }; if (name !== undefined) updateData.name = name; if (code !== undefined) updateData.code = code; if (accountType !== undefined) updateData.accountType = accountType; if (Object.keys(updateData).length === 0) { return ok({ account }); } const updated = await db .updateTable("Account") .set(updateData) .where("id", "=", id) .returningAll() .executeTakeFirstOrThrow(); return ok({ account: updated }); }