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

@@ -0,0 +1,45 @@
import { Inject, Service } from 'typedi';
import { castArray, first, uniq } from 'lodash';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
import { GetAutofillCategorizeTransctionTransformer } from './GetAutofillCategorizeTransactionTransformer';
@Service()
export class GetAutofillCategorizeTransaction {
@Inject()
private tenancy: HasTenancyService;
@Inject()
private transformer: TransformerInjectable;
/**
* Retrieves the autofill values of categorize transactions form.
* @param {number} tenantId - Tenant id.
* @param {Array<number> | number} uncategorizeTransactionsId - Uncategorized transactions ids.
*/
public async getAutofillCategorizeTransaction(
tenantId: number,
uncategorizeTransactionsId: Array<number> | number
) {
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
const uncategorizeTransactionsIds = uniq(
castArray(uncategorizeTransactionsId)
);
const uncategorizedTransactions =
await UncategorizedCashflowTransaction.query()
.whereIn('id', uncategorizeTransactionsIds)
.withGraphFetched('recognizedTransaction.assignAccount')
.withGraphFetched('recognizedTransaction.bankRule')
.throwIfNotFound();
return this.transformer.transform(
tenantId,
{},
new GetAutofillCategorizeTransctionTransformer(),
{
uncategorizedTransactions,
firstUncategorizedTransaction: first(uncategorizedTransactions),
}
);
}
}

View File

@@ -0,0 +1,174 @@
import { Transformer } from '@/lib/Transformer/Transformer';
import { sumBy } from 'lodash';
export class GetAutofillCategorizeTransctionTransformer extends Transformer {
/**
* Included attributes to the object.
* @returns {Array}
*/
public includeAttributes = (): string[] => {
return [
'amount',
'formattedAmount',
'isRecognized',
'date',
'formattedDate',
'creditAccountId',
'debitAccountId',
'referenceNo',
'transactionType',
'recognizedByRuleId',
'recognizedByRuleName',
'isWithdrawalTransaction',
'isDepositTransaction',
];
};
/**
* Detarmines whether the transaction is recognized.
* @returns {boolean}
*/
public isRecognized() {
return !!this.options.firstUncategorizedTransaction?.recognizedTransaction;
}
/**
* Retrieves the total amount of uncategorized transactions.
* @returns {number}
*/
public amount() {
return sumBy(this.options.uncategorizedTransactions, 'amount');
}
/**
* Retrieves the formatted total amount of uncategorized transactions.
* @returns {string}
*/
public formattedAmount() {
return this.formatNumber(this.amount(), {
currencyCode: 'USD',
money: true,
});
}
/**
* Detarmines whether the transaction is deposit.
* @returns {boolean}
*/
public isDepositTransaction() {
const amount = this.amount();
return amount > 0;
}
/**
* Detarmines whether the transaction is withdrawal.
* @returns {boolean}
*/
public isWithdrawalTransaction() {
const amount = this.amount();
return amount < 0;
}
/**
*
* @param {string}
*/
public date() {
return this.options.firstUncategorizedTransaction?.date || null;
}
/**
* Retrieves the formatted date of uncategorized transaction.
* @returns {string}
*/
public formattedDate() {
return this.formatDate(this.date());
}
/**
*
* @param {string}
*/
public referenceNo() {
return this.options.firstUncategorizedTransaction?.referenceNo || null;
}
/**
*
* @returns {number}
*/
public creditAccountId() {
return (
this.options.firstUncategorizedTransaction?.recognizedTransaction
?.assignedAccountId || null
);
}
/**
*
* @returns {number}
*/
public debitAccountId() {
return this.options.firstUncategorizedTransaction?.accountId || null;
}
/**
*
* @returns {string}
*/
public transactionType() {
const assignCategory =
this.options.firstUncategorizedTransaction?.recognizedTransaction
?.assignCategory || null;
return assignCategory || this.isDepositTransaction()
? 'other_income'
: 'other_expense';
}
/**
*
* @returns {string}
*/
public payee() {
return (
this.options.firstUncategorizedTransaction?.recognizedTransaction
?.assignedPayee || null
);
}
/**
*
* @returns {string}
*/
public memo() {
return (
this.options.firstUncategorizedTransaction?.recognizedTransaction
?.assignedMemo || null
);
}
/**
* Retrieves the rule id the transaction recongized by.
* @returns {string}
*/
public recognizedByRuleId() {
return (
this.options.firstUncategorizedTransaction?.recognizedTransaction
?.bankRuleId || null
);
}
/**
* Retrieves the rule name the transaction recongized by.
* @returns {string}
*/
public recognizedByRuleName() {
return (
this.options.firstUncategorizedTransaction?.recognizedTransaction
?.bankRule?.name || null
);
}
}

View File

@@ -1,8 +1,8 @@
import { Knex } from 'knex';
import { Inject, Service } from 'typedi';
import UncategorizedCashflowTransaction from '@/models/UncategorizedCashflowTransaction';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { transformToMapBy } from '@/utils';
import { Inject, Service } from 'typedi';
import { PromisePool } from '@supercharge/promise-pool';
import { BankRule } from '@/models/BankRule';
import { bankRulesMatchTransaction } from './_utils';