import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core"; import { Decimal } from "decimal.js"; import type { Selectable, Transaction } from "../generated/kysely-tailordb"; import { SalesOrderBillingSyncFailedError } from "../lib/errors.generated"; import type { SalesCommands } from "../module"; type AccountReceivableDocument = Selectable<"AccountReceivableDocument">; type AccountReceivableDocumentLine = Selectable<"AccountReceivableDocumentLine">; export async function syncSalesOrderBillingStatusFromAccountReceivable( db: Transaction, input: { document: AccountReceivableDocument; lines: AccountReceivableDocumentLine[]; }, ctx: CommandContext, salesCommands: Pick, ) { const salesOrderLineIds = [ ...new Set( input.lines.map((line) => line.salesOrderLineId).filter((id): id is string => id !== null), ), ]; if (salesOrderLineIds.length === 0) return ok(undefined); const rows = await db .selectFrom("AccountReceivableDocumentLine as line") .innerJoin( "AccountReceivableDocument as document", "document.id", "line.accountReceivableDocumentId", ) .select([ "line.salesOrderLineId as salesOrderLineId", "line.quantity as quantity", "line.correctionType as correctionType", "document.documentType as documentType", ]) .where("line.salesOrderLineId", "in", salesOrderLineIds) .where("document.status", "in", ["REGISTERED", "POSTED"]) .execute(); const invoicedByLineId = new Map(); for (const row of rows) { if (row.salesOrderLineId === null || row.quantity === null) continue; if (row.correctionType === "PRICE" || row.correctionType === "AMOUNT") continue; const signedQuantity = row.documentType === "CREDIT_MEMO" ? new Decimal(row.quantity).neg() : new Decimal(row.quantity); invoicedByLineId.set( row.salesOrderLineId, (invoicedByLineId.get(row.salesOrderLineId) ?? new Decimal(0)).plus(signedQuantity), ); } const result = await salesCommands.recalculateSalesOrderBillingStatus( db, { lineBillings: salesOrderLineIds.map((salesOrderLineId) => ({ salesOrderLineId, billedQuantity: (invoicedByLineId.get(salesOrderLineId) ?? new Decimal(0)).toString(), })), }, ctx, ); return result.ok ? ok(undefined) : err(new SalesOrderBillingSyncFailedError(input.document.id)); }