import { Inject, Service } from 'typedi'; import HasTenancyService from '../Tenancy/TenancyService'; import events from '@/subscribers/events'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import UnitOfWork from '../UnitOfWork'; import { ICashflowTransactionCategorizedPayload, ICashflowTransactionUncategorizingPayload, ICategorizeCashflowTransactioDTO, } from '@/interfaces'; import { Knex } from 'knex'; import { transformCategorizeTransToCashflow } from './utils'; import { CommandCashflowValidator } from './CommandCasflowValidator'; import NewCashflowTransactionService from './NewCashflowTransactionService'; @Service() export class CategorizeCashflowTransaction { @Inject() private tenancy: HasTenancyService; @Inject() private eventPublisher: EventPublisher; @Inject() private uow: UnitOfWork; @Inject() private commandValidators: CommandCashflowValidator; @Inject() private createCashflow: NewCashflowTransactionService; /** * Categorize the given cashflow transaction. * @param {number} tenantId * @param {ICategorizeCashflowTransactioDTO} categorizeDTO */ public async categorize( tenantId: number, uncategorizedTransactionId: number, categorizeDTO: ICategorizeCashflowTransactioDTO ) { const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId); // Retrieves the uncategorized transaction or throw an error. const transaction = await UncategorizedCashflowTransaction.query() .findById(uncategorizedTransactionId) .throwIfNotFound(); // Validates the transaction shouldn't be categorized before. this.commandValidators.validateTransactionShouldNotCategorized(transaction); // Validate the uncateogirzed transaction if it's deposit the transaction direction // should `IN` and the same thing if it's withdrawal the direction should be OUT. this.commandValidators.validateUncategorizeTransactionType( transaction, categorizeDTO.transactionType ); // Edits the cashflow transaction under UOW env. return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => { // Triggers `onTransactionCategorizing` event. await this.eventPublisher.emitAsync( events.cashflow.onTransactionCategorizing, { tenantId, trx, } as ICashflowTransactionUncategorizingPayload ); // Transformes the categorize DTO to the cashflow transaction. const cashflowTransactionDTO = transformCategorizeTransToCashflow( transaction, categorizeDTO ); // Creates a new cashflow transaction. const cashflowTransaction = await this.createCashflow.newCashflowTransaction( tenantId, cashflowTransactionDTO ); // Updates the uncategorized transaction as categorized. await UncategorizedCashflowTransaction.query(trx).patchAndFetchById( uncategorizedTransactionId, { categorized: true, categorizeRefType: 'CashflowTransaction', categorizeRefId: cashflowTransaction.id, } ); // Triggers `onCashflowTransactionCategorized` event. await this.eventPublisher.emitAsync( events.cashflow.onTransactionCategorized, { tenantId, // cashflowTransaction, trx, } as ICashflowTransactionCategorizedPayload ); }); } }