import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core"; import { Decimal } from "decimal.js"; import type { Transaction } from "../generated/kysely-tailordb"; import { ApSupplierAccountNotFoundError, ApInvalidSupplierAccountError, CompanyNotFoundError, InvalidToleranceValueError, InvoiceToleranceConfigAlreadyExistsError, } from "../lib/errors.generated"; import type { BusinessPartnerQueries, OrganizationQueries } from "../module"; export interface CreateInvoiceToleranceConfigInput { companyId: string; supplierAccountId: string; quantityAbsoluteTolerance?: string | null; quantityPercentageTolerance?: string | null; unitPriceAbsoluteTolerance?: string | null; unitPricePercentageTolerance?: string | null; } const toleranceFields = [ "quantityAbsoluteTolerance", "quantityPercentageTolerance", "unitPriceAbsoluteTolerance", "unitPricePercentageTolerance", ] as const; function validateToleranceValues(input: CreateInvoiceToleranceConfigInput) { for (const field of toleranceFields) { const value = input[field]; if (value != null && new Decimal(value).lt(0)) { return err(new InvalidToleranceValueError(field)); } } return ok({}); } export async function run( db: Transaction, input: CreateInvoiceToleranceConfigInput & F, ctx: CommandContext, organizationQueries: Pick, supplierAccountQueries: Pick, ) { const { companyId, supplierAccountId, quantityAbsoluteTolerance, quantityPercentageTolerance, unitPriceAbsoluteTolerance, unitPricePercentageTolerance, ...customFields } = input; const { company } = (await organizationQueries.getCompany(db, { id: companyId }, ctx)).value; if (!company) return err(new CompanyNotFoundError(companyId)); const { account: supplier } = ( await supplierAccountQueries.getSupplierAccount(db, { supplierAccountId }, ctx) ).value; if (!supplier) return err(new ApSupplierAccountNotFoundError(supplierAccountId)); if (supplier.companyId !== companyId || supplier.accountStatus !== "ACTIVE") return err(new ApInvalidSupplierAccountError(supplierAccountId)); const toleranceResult = validateToleranceValues(input); if (!toleranceResult.ok) return toleranceResult; const existing = await db .selectFrom("InvoiceToleranceConfig") .selectAll() .where("companyId", "=", companyId) .where("supplierAccountId", "=", supplierAccountId) .executeTakeFirst(); if (existing) { return err(new InvoiceToleranceConfigAlreadyExistsError(`${companyId}:${supplierAccountId}`)); } const invoiceToleranceConfig = await db .insertInto("InvoiceToleranceConfig") .values({ ...(customFields as Record), companyId, supplierAccountId, quantityAbsoluteTolerance: quantityAbsoluteTolerance ?? null, quantityPercentageTolerance: quantityPercentageTolerance ?? null, unitPriceAbsoluteTolerance: unitPriceAbsoluteTolerance ?? null, unitPricePercentageTolerance: unitPricePercentageTolerance ?? null, }) .returningAll() .executeTakeFirstOrThrow(); return ok({ invoiceToleranceConfig }); }