mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 06:10:31 +00:00
feat: getting matched transactiosn from multi uncategorized transactions
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { Service, Inject } from 'typedi';
|
import { Service, Inject } from 'typedi';
|
||||||
import { Router, Request, Response, NextFunction } from 'express';
|
import { Router, Request, Response, NextFunction } from 'express';
|
||||||
import { param } from 'express-validator';
|
import { param, query } from 'express-validator';
|
||||||
import BaseController from '../BaseController';
|
import BaseController from '../BaseController';
|
||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
import CheckPolicies from '@/api/middleware/CheckPolicies';
|
||||||
@@ -24,7 +24,12 @@ export default class GetCashflowAccounts extends BaseController {
|
|||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
'/transactions/:transactionId/matches',
|
'/transactions/matches',
|
||||||
|
[
|
||||||
|
query('uncategorizeTransactionsIds').exists().isArray({ min: 1 }),
|
||||||
|
query('uncategorizeTransactionsIds.*').exists().isNumeric().toInt(),
|
||||||
|
],
|
||||||
|
this.validationResult,
|
||||||
this.getMatchedTransactions.bind(this)
|
this.getMatchedTransactions.bind(this)
|
||||||
);
|
);
|
||||||
router.get(
|
router.get(
|
||||||
@@ -76,14 +81,15 @@ export default class GetCashflowAccounts extends BaseController {
|
|||||||
next: NextFunction
|
next: NextFunction
|
||||||
) {
|
) {
|
||||||
const { tenantId } = req;
|
const { tenantId } = req;
|
||||||
const { transactionId } = req.params;
|
const uncategorizeTransactionsIds: Array<number> =
|
||||||
|
req.query.uncategorizeTransactionsIds;
|
||||||
const filter = this.matchedQueryData(req) as GetMatchedTransactionsFilter;
|
const filter = this.matchedQueryData(req) as GetMatchedTransactionsFilter;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data =
|
const data =
|
||||||
await this.bankTransactionsMatchingApp.getMatchedTransactions(
|
await this.bankTransactionsMatchingApp.getMatchedTransactions(
|
||||||
tenantId,
|
tenantId,
|
||||||
transactionId,
|
uncategorizeTransactionsIds,
|
||||||
filter
|
filter
|
||||||
);
|
);
|
||||||
return res.status(200).send(data);
|
return res.status(200).send(data);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { first, sumBy } from 'lodash';
|
||||||
import { PromisePool } from '@supercharge/promise-pool';
|
import { PromisePool } from '@supercharge/promise-pool';
|
||||||
import { GetMatchedTransactionsFilter, MatchedTransactionsPOJO } from './types';
|
import { GetMatchedTransactionsFilter, MatchedTransactionsPOJO } from './types';
|
||||||
import { GetMatchedTransactionsByExpenses } from './GetMatchedTransactionsByExpenses';
|
import { GetMatchedTransactionsByExpenses } from './GetMatchedTransactionsByExpenses';
|
||||||
@@ -47,19 +48,20 @@ export class GetMatchedTransactions {
|
|||||||
/**
|
/**
|
||||||
* Retrieves the matched transactions.
|
* Retrieves the matched transactions.
|
||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
|
* @param {Array<number>} uncategorizedTransactionIds - Uncategorized transactions ids.
|
||||||
* @param {GetMatchedTransactionsFilter} filter -
|
* @param {GetMatchedTransactionsFilter} filter -
|
||||||
* @returns {Promise<MatchedTransactionsPOJO>}
|
* @returns {Promise<MatchedTransactionsPOJO>}
|
||||||
*/
|
*/
|
||||||
public async getMatchedTransactions(
|
public async getMatchedTransactions(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
uncategorizedTransactionId: number,
|
uncategorizedTransactionIds: Array<number>,
|
||||||
filter: GetMatchedTransactionsFilter
|
filter: GetMatchedTransactionsFilter
|
||||||
): Promise<MatchedTransactionsPOJO> {
|
): Promise<MatchedTransactionsPOJO> {
|
||||||
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
|
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
const uncategorizedTransaction =
|
const uncategorizedTransactions =
|
||||||
await UncategorizedCashflowTransaction.query()
|
await UncategorizedCashflowTransaction.query()
|
||||||
.findById(uncategorizedTransactionId)
|
.whereIn('id', uncategorizedTransactionIds)
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
const filtered = filter.transactionType
|
const filtered = filter.transactionType
|
||||||
@@ -71,9 +73,8 @@ export class GetMatchedTransactions {
|
|||||||
.process(async ({ type, service }) => {
|
.process(async ({ type, service }) => {
|
||||||
return service.getMatchedTransactions(tenantId, filter);
|
return service.getMatchedTransactions(tenantId, filter);
|
||||||
});
|
});
|
||||||
|
|
||||||
const { perfectMatches, possibleMatches } = this.groupMatchedResults(
|
const { perfectMatches, possibleMatches } = this.groupMatchedResults(
|
||||||
uncategorizedTransaction,
|
uncategorizedTransactions,
|
||||||
matchedTransactions
|
matchedTransactions
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
@@ -90,20 +91,20 @@ export class GetMatchedTransactions {
|
|||||||
* @returns {MatchedTransactionsPOJO}
|
* @returns {MatchedTransactionsPOJO}
|
||||||
*/
|
*/
|
||||||
private groupMatchedResults(
|
private groupMatchedResults(
|
||||||
uncategorizedTransaction,
|
uncategorizedTransactions: Array<any>,
|
||||||
matchedTransactions
|
matchedTransactions
|
||||||
): MatchedTransactionsPOJO {
|
): MatchedTransactionsPOJO {
|
||||||
const results = R.compose(R.flatten)(matchedTransactions?.results);
|
const results = R.compose(R.flatten)(matchedTransactions?.results);
|
||||||
|
|
||||||
|
const firstUncategorized = first(uncategorizedTransactions);
|
||||||
|
const amount = sumBy(uncategorizedTransactions, 'amount');
|
||||||
|
const date = firstUncategorized.date;
|
||||||
|
|
||||||
// Sort the results based on amount, date, and transaction type
|
// Sort the results based on amount, date, and transaction type
|
||||||
const closestResullts = sortClosestMatchTransactions(
|
const closestResullts = sortClosestMatchTransactions(amount, date, results);
|
||||||
uncategorizedTransaction,
|
|
||||||
results
|
|
||||||
);
|
|
||||||
const perfectMatches = R.filter(
|
const perfectMatches = R.filter(
|
||||||
(match) =>
|
(match) =>
|
||||||
match.amount === uncategorizedTransaction.amount &&
|
match.amount === amount && moment(match.date).isSame(date, 'day'),
|
||||||
moment(match.date).isSame(uncategorizedTransaction.date, 'day'),
|
|
||||||
closestResullts
|
closestResullts
|
||||||
);
|
);
|
||||||
const possibleMatches = R.difference(closestResullts, perfectMatches);
|
const possibleMatches = R.difference(closestResullts, perfectMatches);
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ export class MatchBankTransactionsApplication {
|
|||||||
*/
|
*/
|
||||||
public getMatchedTransactions(
|
public getMatchedTransactions(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
uncategorizedTransactionId: number,
|
uncategorizedTransactionsIds: Array<number>,
|
||||||
filter: GetMatchedTransactionsFilter
|
filter: GetMatchedTransactionsFilter
|
||||||
) {
|
) {
|
||||||
return this.getMatchedTransactionsService.getMatchedTransactions(
|
return this.getMatchedTransactionsService.getMatchedTransactions(
|
||||||
tenantId,
|
tenantId,
|
||||||
uncategorizedTransactionId,
|
uncategorizedTransactionsIds,
|
||||||
filter
|
filter
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { MatchTransactionsTypes } from './MatchTransactionsTypes';
|
|||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import {
|
import {
|
||||||
sumMatchTranasctions,
|
sumMatchTranasctions,
|
||||||
|
sumUncategorizedTransactions,
|
||||||
validateUncategorizedTransactionsExcluded,
|
validateUncategorizedTransactionsExcluded,
|
||||||
validateUncategorizedTransactionsNotMatched,
|
validateUncategorizedTransactionsNotMatched,
|
||||||
} from './_utils';
|
} from './_utils';
|
||||||
@@ -95,11 +96,14 @@ export class MatchBankTransactions {
|
|||||||
const totalMatchedTranasctions = sumMatchTranasctions(
|
const totalMatchedTranasctions = sumMatchTranasctions(
|
||||||
validatationResult.results
|
validatationResult.results
|
||||||
);
|
);
|
||||||
|
const totalUncategorizedTransactions = sumUncategorizedTransactions(
|
||||||
|
uncategorizedTransactions
|
||||||
|
);
|
||||||
// Validates the total given matching transcations whether is not equal
|
// Validates the total given matching transcations whether is not equal
|
||||||
// uncategorized transaction amount.
|
// uncategorized transaction amount.
|
||||||
// if (totalMatchedTranasctions !== uncategorizedTransaction.amount) {
|
if (totalUncategorizedTransactions === totalMatchedTranasctions) {
|
||||||
// throw new ServiceError(ERRORS.TOTAL_MATCHING_TRANSACTIONS_INVALID);
|
throw new ServiceError(ERRORS.TOTAL_MATCHING_TRANSACTIONS_INVALID);
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user