feat: wip multi-select transactions to categorization and matching

This commit is contained in:
Ahmed Bouhuolia
2024-08-03 22:01:21 +02:00
parent 5ce11f192f
commit d74337fb94
29 changed files with 476 additions and 155 deletions

View File

@@ -58,14 +58,14 @@ export class CategorizeCashflowTransaction {
// Validates the transaction shouldn't be categorized before.
this.commandValidators.validateTransactionsShouldNotCategorized(
oldIncategorizedTransactions
oldUncategorizedTransactions
);
// 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(
// uncategorizedTransactions,
// categorizeDTO.transactionType
// );
this.commandValidators.validateUncategorizeTransactionType(
oldUncategorizedTransactions,
categorizeDTO.transactionType
);
// Edits the cashflow transaction under UOW env.
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
// Triggers `onTransactionCategorizing` event.
@@ -88,6 +88,7 @@ export class CategorizeCashflowTransaction {
tenantId,
cashflowTransactionDTO
);
// Updates the uncategorized transaction as categorized.
await UncategorizedCashflowTransaction.query(trx)
.whereIn('id', uncategorizedTransactionIds)
@@ -102,7 +103,6 @@ export class CategorizeCashflowTransaction {
'id',
uncategorizedTransactionIds
);
// Triggers `onCashflowTransactionCategorized` event.
await this.eventPublisher.emitAsync(
events.cashflow.onTransactionCategorized,

View File

@@ -1,5 +1,5 @@
import { Service } from 'typedi';
import { includes, camelCase, upperFirst } from 'lodash';
import { includes, camelCase, upperFirst, sumBy } from 'lodash';
import { IAccount, IUncategorizedCashflowTransaction } from '@/interfaces';
import { getCashflowTransactionType } from './utils';
import { ServiceError } from '@/exceptions';
@@ -74,7 +74,9 @@ export class CommandCashflowValidator {
const categorized = cashflowTransactions.filter((t) => t.categorized);
if (categorized?.length > 0) {
throw new ServiceError(ERRORS.TRANSACTION_ALREADY_CATEGORIZED);
throw new ServiceError(ERRORS.TRANSACTION_ALREADY_CATEGORIZED, '', {
ids: categorized.map((t) => t.id),
});
}
}
@@ -85,17 +87,19 @@ export class CommandCashflowValidator {
* @throws {ServiceError(ERRORS.UNCATEGORIZED_TRANSACTION_TYPE_INVALID)}
*/
public validateUncategorizeTransactionType(
uncategorizeTransaction: IUncategorizedCashflowTransaction,
uncategorizeTransactions: Array<IUncategorizedCashflowTransaction>,
transactionType: string
) {
const amount = sumBy(uncategorizeTransactions, 'amount');
const isDepositTransaction = amount > 0;
const isWithdrawalTransaction = amount <= 0;
const type = getCashflowTransactionType(
transactionType as CASHFLOW_TRANSACTION_TYPE
);
if (
(type.direction === CASHFLOW_DIRECTION.IN &&
uncategorizeTransaction.isDepositTransaction) ||
(type.direction === CASHFLOW_DIRECTION.OUT &&
uncategorizeTransaction.isWithdrawalTransaction)
(type.direction === CASHFLOW_DIRECTION.IN && isDepositTransaction) ||
(type.direction === CASHFLOW_DIRECTION.OUT && isWithdrawalTransaction)
) {
return;
}

View File

@@ -34,12 +34,13 @@ export class DecrementUncategorizedTransactionOnCategorize {
*/
public async decrementUnCategorizedTransactionsOnCategorized({
tenantId,
uncategorizedTransaction,
uncategorizedTransactions,
}: ICashflowTransactionCategorizedPayload) {
const { Account } = this.tenancy.models(tenantId);
const accountIds = uncategorizedTransactions.map((a) => a.id);
await Account.query()
.findById(uncategorizedTransaction.accountId)
.whereIn('id', accountIds)
.decrement('uncategorizedTransactions', 1);
}

View File

@@ -1,6 +1,5 @@
import { upperFirst, camelCase, first, sum, sumBy } from 'lodash';
import {
CASHFLOW_DIRECTION,
CASHFLOW_TRANSACTION_TYPE,
CASHFLOW_TRANSACTION_TYPE_META,
ERRORS,
@@ -81,6 +80,8 @@ export const validateUncategorizedTransactionsNotExcluded = (
const excluded = transactions.filter((tran) => tran.excluded);
if (excluded?.length > 0) {
throw new ServiceError(ERRORS.CANNOT_CATEGORIZE_EXCLUDED_TRANSACTION);
throw new ServiceError(ERRORS.CANNOT_CATEGORIZE_EXCLUDED_TRANSACTION, '', {
ids: excluded.map((t) => t.id),
});
}
};