import { err, ok } from "@tailor-platform/erp-kit/core"; import { Decimal } from "decimal.js"; import type { Transaction } from "../generated/kysely-tailordb"; import { OutgoingPaymentTargetIneligibleError } from "../lib/errors.generated"; export type OutgoingPaymentSettlementTargetInput = { accountPayableDueScheduleLineId: string; }; export type OutgoingPaymentIdentity = { companyId: string; supplierAccountId: string; currencyId: string; }; export type OutgoingPaymentSettlementTargetDocument = OutgoingPaymentIdentity & { documentType: string; status: string; }; export type OutgoingPaymentSettlementDocumentType = "INVOICE" | "CREDIT_MEMO"; export function isOutgoingPaymentSettlementTargetEligible( document: OutgoingPaymentSettlementTargetDocument, payment: OutgoingPaymentIdentity, ) { return ( (document.documentType === "INVOICE" || document.documentType === "CREDIT_MEMO") && document.status === "POSTED" && document.companyId === payment.companyId && document.supplierAccountId === payment.supplierAccountId && document.currencyId === payment.currencyId ); } export function toSignedSettlementAmount( documentType: OutgoingPaymentSettlementDocumentType, settledAmount: string, ) { const amount = new Decimal(settledAmount); return documentType === "CREDIT_MEMO" ? amount.negated() : amount; } export async function validateOutgoingPaymentSettlementTargets( db: Transaction, payment: OutgoingPaymentIdentity, settlements: OutgoingPaymentSettlementTargetInput[], ) { if (settlements.length === 0) return ok({}); const dueScheduleLineIds = settlements.map( (settlement) => settlement.accountPayableDueScheduleLineId, ); const targets = await db .selectFrom("AccountPayableDueScheduleLine as dueSchedule") .innerJoin( "AccountPayableDocument as document", "document.id", "dueSchedule.accountPayableDocumentId", ) .select([ "dueSchedule.id as dueScheduleLineId", "document.id as accountPayableDocumentId", "document.documentType as documentType", "document.status as status", "document.companyId as companyId", "document.supplierAccountId as supplierAccountId", "document.currencyId as currencyId", ]) .where("dueSchedule.id", "in", dueScheduleLineIds) .execute(); const targetByDueScheduleLineId = new Map( targets.map((target) => [target.dueScheduleLineId, target]), ); for (const dueScheduleLineId of dueScheduleLineIds) { const target = targetByDueScheduleLineId.get(dueScheduleLineId); if (!target || !isOutgoingPaymentSettlementTargetEligible(target, payment)) { return err(new OutgoingPaymentTargetIneligibleError(dueScheduleLineId)); } } return ok({}); }