import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/core"; import type { Transaction, Updateable } from "../generated/kysely-tailordb"; import { CompanyNotFoundError, InvalidLegalNameError, CurrencyNotFoundError, CurrencyImmutableError, } from "../lib/errors.generated"; import type { PrimitivesQueries } from "../module"; export type UpdateCompanyInput = { companyId: string; legalName?: string; taxId?: string | null; registrationNumber?: string | null; baseCurrencyId?: string | null; street?: string | null; city?: string | null; state?: string | null; postalCode?: string | null; country?: string | null; }; /** * Function: updateCompany * * Modifies an existing company's attributes. Legal name validation applies when * provided. Base currency can only be changed while the company is in DRAFT status. */ export async function run>( db: Transaction, input: UpdateCompanyInput & Omit, "status">, ctx: CommandContext, primitivesQueries?: Pick, ) { const { companyId, legalName, taxId, registrationNumber, baseCurrencyId, street, city, state, postalCode, country, ...customFields } = input; // 1. Find company by id with forUpdate const existing = await db .selectFrom("Company") .selectAll() .where("id", "=", companyId) .forUpdate() .executeTakeFirst(); if (!existing) { return err(new CompanyNotFoundError(companyId)); } // 2. If legalName provided and empty, error if (legalName?.trim() === "") { return err(new InvalidLegalNameError(legalName)); } // 3. If baseCurrencyId provided, company must be DRAFT and currency must be valid if (baseCurrencyId !== undefined) { if (existing.status !== "DRAFT") { return err(new CurrencyImmutableError(companyId)); } if (baseCurrencyId !== null && primitivesQueries) { const { currency } = (await primitivesQueries.getCurrency(db, { id: baseCurrencyId }, ctx)) .value; if (currency?.status !== "ACTIVE") { return err(new CurrencyNotFoundError(baseCurrencyId)); } } } // 4. Build update object from provided fields — strip reserved model columns from customFields const RESERVED_KEYS = new Set([ "id", "status", "legalName", "taxId", "registrationNumber", "baseCurrencyId", "street", "city", "state", "postalCode", "country", "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<"Company"> = { ...(safeCustomFields as Updateable<"Company">), }; if (legalName !== undefined) updateData.legalName = legalName; if (taxId !== undefined) updateData.taxId = taxId; if (registrationNumber !== undefined) updateData.registrationNumber = registrationNumber; if (baseCurrencyId !== undefined) updateData.baseCurrencyId = baseCurrencyId; if (street !== undefined) updateData.street = street; if (city !== undefined) updateData.city = city; if (state !== undefined) updateData.state = state; if (postalCode !== undefined) updateData.postalCode = postalCode; if (country !== undefined) updateData.country = country; if (Object.keys(updateData).length === 0) { return ok({ company: existing }); } const company = await db .updateTable("Company") .set(updateData) .where("id", "=", companyId) .returningAll() .executeTakeFirstOrThrow(); return ok({ company }); }