import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core"; import * as domain from "../domain/journalEntry"; import type { Transaction } from "../generated/kysely-tailordb"; import { JournalEntryNotFoundError } from "../lib/errors.generated"; import { createAccountingPeriodRepository, type AccountingPeriodRepository, } from "../repository/accountingPeriodRepository"; import { createJournalEntryRepository, type JournalEntryRepository, } from "../repository/journalEntryRepository"; export interface ReverseJournalEntryInput { id: string; reversalPeriodId?: string; } export async function run( db: Transaction, input: ReverseJournalEntryInput, _ctx: CommandContext, journalEntryRepositoryFactory: ( db: Transaction, ) => JournalEntryRepository = createJournalEntryRepository, accountingPeriodRepositoryFactory: ( db: Transaction, ) => AccountingPeriodRepository = createAccountingPeriodRepository, ) { const journalEntryRepository = journalEntryRepositoryFactory(db); const accountingPeriodRepository = accountingPeriodRepositoryFactory(db); const entry = await journalEntryRepository.findById(input.id, { forUpdate: true }); if (!entry) return err(new JournalEntryNotFoundError(input.id)); const valid = domain.validateReversal(entry, false); if (!valid.ok) return valid; const existingReversal = await journalEntryRepository.findReversal(entry.id); const allowed = domain.validateReversal(entry, !!existingReversal); if (!allowed.ok) return allowed; const lines = await journalEntryRepository.findLines(entry.id); const targetPeriodId = input.reversalPeriodId ?? entry.accountingPeriodId; const period = await accountingPeriodRepository.findById(targetPeriodId); const reversal = domain.reverse( entry, lines, targetPeriodId, period, !!existingReversal, new Date(), ); if (!reversal.ok) return reversal; const { journalEntry: reversalEntry, journalLines: reversalJournalLines } = await journalEntryRepository.insert(reversal.value.header, reversal.value.lines); return ok({ reversalEntry, reversalJournalLines, originalEntry: entry }); }