import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/core"; import type { Transaction } from "../generated/kysely-tailordb"; import { AccountNotFoundError, DefaultValuationPolicyAlreadyExistsError, ValuationPolicyNotFoundError, } from "../lib/errors.generated"; import type { CoaManagementQueries } from "../module"; export interface UpdateValuationPolicyInput { id: string; name?: string; isDefault?: boolean; inventoryAccountId?: string; accrualAccountId?: string; invoicePriceVarianceAccountId?: string; cogsAccountId?: string; ppvAccountId?: string; adjustmentAccountId?: string; standardCostAdjustmentAccountId?: string; consumedPriceVarianceAccountId?: string; } /** * Function: updateValuationPolicy * * Updates an existing valuation policy's name, default flag, or posting * accounts. */ export async function run( db: Transaction, input: UpdateValuationPolicyInput, ctx: CommandContext, coaManagementQueries: Pick, ) { const { id, ...patch } = input; const existing = await db .selectFrom("ValuationPolicy") .selectAll() .where("id", "=", id) .forUpdate() .executeTakeFirst(); if (!existing) { return err(new ValuationPolicyNotFoundError(id)); } // Updated posting accounts must exist in the company's chart of accounts. const accountIds = [ ...new Set( [ patch.inventoryAccountId, patch.accrualAccountId, patch.invoicePriceVarianceAccountId, patch.cogsAccountId, patch.ppvAccountId, patch.adjustmentAccountId, patch.standardCostAdjustmentAccountId, patch.consumedPriceVarianceAccountId, ].filter((accountId) => accountId !== undefined), ), ]; if (accountIds.length > 0) { const { items } = ( await coaManagementQueries.listAccounts( db, { companyId: existing.companyId, accountIds }, ctx, ) ).value; const foundAccountIds = new Set(items.map((account) => account.id)); for (const accountId of accountIds) { if (!foundAccountIds.has(accountId)) { return err(new AccountNotFoundError(accountId)); } } } if (patch.isDefault) { const existingDefault = await db .selectFrom("ValuationPolicy") .selectAll() .where("defaultCompanyId", "=", existing.companyId) .where("id", "!=", id) .executeTakeFirst(); if (existingDefault) { return err(new DefaultValuationPolicyAlreadyExistsError(existingDefault.id)); } } // Skip an empty patch; kysely can't compile a SET with no columns. if (!Object.values(patch).some((value) => value !== undefined)) { return ok({ valuationPolicy: existing }); } const { isDefault, ...columns } = patch; const updated = await db .updateTable("ValuationPolicy") .set({ ...columns, // Unique defaultCompanyId backstops the check above under concurrency. ...(isDefault !== undefined && { defaultCompanyId: isDefault ? existing.companyId : null, }), }) .where("id", "=", id) .returningAll() .executeTakeFirstOrThrow(); return ok({ valuationPolicy: updated }); }