mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 15:20:34 +00:00
feat: validate the matched linked transacation on deleting.
This commit is contained in:
@@ -23,11 +23,9 @@ export class BankTransactionsMatchingController extends BaseController {
|
|||||||
'/:transactionId',
|
'/:transactionId',
|
||||||
[
|
[
|
||||||
param('transactionId').exists(),
|
param('transactionId').exists(),
|
||||||
|
|
||||||
body('matchedTransactions').isArray({ min: 1 }),
|
body('matchedTransactions').isArray({ min: 1 }),
|
||||||
body('matchedTransactions.*.reference_type').exists(),
|
body('matchedTransactions.*.reference_type').exists(),
|
||||||
body('matchedTransactions.*.reference_id').isNumeric().toInt(),
|
body('matchedTransactions.*.reference_id').isNumeric().toInt(),
|
||||||
body('matchedTransactions.*.amount').exists().isNumeric().toFloat(),
|
|
||||||
],
|
],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
this.matchBankTransaction.bind(this)
|
this.matchBankTransaction.bind(this)
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ export class BankingRulesController extends BaseController {
|
|||||||
body('assign_account_id').isInt({ min: 0 }),
|
body('assign_account_id').isInt({ min: 0 }),
|
||||||
body('assign_payee').isString().optional({ nullable: true }),
|
body('assign_payee').isString().optional({ nullable: true }),
|
||||||
body('assign_memo').isString().optional({ nullable: true }),
|
body('assign_memo').isString().optional({ nullable: true }),
|
||||||
|
|
||||||
|
body('recognition').isBoolean().toBoolean().optional({ nullable: true }),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ exports.up = function (knex) {
|
|||||||
return knex.schema.createTable('recognized_bank_transactions', (table) => {
|
return knex.schema.createTable('recognized_bank_transactions', (table) => {
|
||||||
table.increments('id');
|
table.increments('id');
|
||||||
table
|
table
|
||||||
.integer('cashflow_transaction_id')
|
.integer('uncategorized_transaction_id')
|
||||||
.unsigned()
|
.unsigned()
|
||||||
.references('id')
|
.references('id')
|
||||||
.inTable('uncategorized_cashflow_transactions');
|
.inTable('uncategorized_cashflow_transactions');
|
||||||
|
|||||||
@@ -103,6 +103,11 @@ import { AttachmentsOnCreditNote } from '@/services/Attachments/events/Attachmen
|
|||||||
import { AttachmentsOnBillPayments } from '@/services/Attachments/events/AttachmentsOnPaymentsMade';
|
import { AttachmentsOnBillPayments } from '@/services/Attachments/events/AttachmentsOnPaymentsMade';
|
||||||
import { AttachmentsOnSaleEstimates } from '@/services/Attachments/events/AttachmentsOnSaleEstimates';
|
import { AttachmentsOnSaleEstimates } from '@/services/Attachments/events/AttachmentsOnSaleEstimates';
|
||||||
import { TriggerRecognizedTransactions } from '@/services/Banking/RegonizeTranasctions/events/TriggerRecognizedTransactions';
|
import { TriggerRecognizedTransactions } from '@/services/Banking/RegonizeTranasctions/events/TriggerRecognizedTransactions';
|
||||||
|
import { ValidateMatchingOnExpenseDelete } from '@/services/Banking/Matching/events/ValidateMatchingOnExpenseDelete';
|
||||||
|
import { ValidateMatchingOnManualJournalDelete } from '@/services/Banking/Matching/events/ValidateMatchingOnManualJournalDelete';
|
||||||
|
import { ValidateMatchingOnPaymentReceivedDelete } from '@/services/Banking/Matching/events/ValidateMatchingOnPaymentReceivedDelete';
|
||||||
|
import { ValidateMatchingOnPaymentMadeDelete } from '@/services/Banking/Matching/events/ValidateMatchingOnPaymentMadeDelete';
|
||||||
|
import { ValidateMatchingOnCashflowDelete } from '@/services/Banking/Matching/events/ValidateMatchingOnCashflowDelete';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return new EventPublisher();
|
return new EventPublisher();
|
||||||
@@ -250,5 +255,12 @@ export const susbcribers = () => {
|
|||||||
|
|
||||||
// Bank Rules
|
// Bank Rules
|
||||||
TriggerRecognizedTransactions,
|
TriggerRecognizedTransactions,
|
||||||
|
|
||||||
|
// Validate matching
|
||||||
|
ValidateMatchingOnCashflowDelete,
|
||||||
|
ValidateMatchingOnExpenseDelete,
|
||||||
|
ValidateMatchingOnManualJournalDelete,
|
||||||
|
ValidateMatchingOnPaymentReceivedDelete,
|
||||||
|
ValidateMatchingOnPaymentMadeDelete,
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -127,8 +127,8 @@ export default class UncategorizedCashflowTransaction extends mixin(
|
|||||||
/**
|
/**
|
||||||
* Uncategorized transaction may has association to matched transaction.
|
* Uncategorized transaction may has association to matched transaction.
|
||||||
*/
|
*/
|
||||||
matchedBankTransaction: {
|
matchedBankTransactions: {
|
||||||
relation: Model.BelongsToOneRelation,
|
relation: Model.HasManyRelation,
|
||||||
modelClass: MatchedBankTransaction,
|
modelClass: MatchedBankTransaction,
|
||||||
join: {
|
join: {
|
||||||
from: 'uncategorized_cashflow_transactions.id',
|
from: 'uncategorized_cashflow_transactions.id',
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByTy
|
|||||||
* Retrieves the matched transactions.
|
* Retrieves the matched transactions.
|
||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
* @param {GetMatchedTransactionsFilter} filter -
|
* @param {GetMatchedTransactionsFilter} filter -
|
||||||
|
* @returns {Promise<MatchedTransactionsPOJO>}
|
||||||
*/
|
*/
|
||||||
public async getMatchedTransactions(
|
public async getMatchedTransactions(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
@@ -38,10 +39,10 @@ export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByTy
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Retrieves the matched transaction.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {number} transactionId
|
* @param {number} transactionId
|
||||||
* @returns
|
* @returns {Promise<MatchedTransactionPOJO>}
|
||||||
*/
|
*/
|
||||||
public async getMatchedTransaction(
|
public async getMatchedTransaction(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
@@ -49,8 +50,6 @@ export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByTy
|
|||||||
): Promise<MatchedTransactionPOJO> {
|
): Promise<MatchedTransactionPOJO> {
|
||||||
const { SaleInvoice } = this.tenancy.models(tenantId);
|
const { SaleInvoice } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
console.log(transactionId);
|
|
||||||
|
|
||||||
const invoice = await SaleInvoice.query().findById(transactionId);
|
const invoice = await SaleInvoice.query().findById(transactionId);
|
||||||
|
|
||||||
return this.transformer.transform(
|
return this.transformer.transform(
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { sumBy } from 'lodash';
|
import { isEmpty, sumBy } from 'lodash';
|
||||||
|
import { Knex } from 'knex';
|
||||||
|
import { Inject, Service } from 'typedi';
|
||||||
import { PromisePool } from '@supercharge/promise-pool';
|
import { PromisePool } from '@supercharge/promise-pool';
|
||||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import UnitOfWork from '@/services/UnitOfWork';
|
import UnitOfWork from '@/services/UnitOfWork';
|
||||||
import events from '@/subscribers/events';
|
import events from '@/subscribers/events';
|
||||||
import { Knex } from 'knex';
|
|
||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import {
|
import {
|
||||||
ERRORS,
|
ERRORS,
|
||||||
IBankTransactionMatchedEventPayload,
|
IBankTransactionMatchedEventPayload,
|
||||||
@@ -34,6 +34,7 @@ export class MatchBankTransactions {
|
|||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {number} uncategorizedTransactionId
|
* @param {number} uncategorizedTransactionId
|
||||||
* @param {IMatchTransactionsDTO} matchTransactionsDTO
|
* @param {IMatchTransactionsDTO} matchTransactionsDTO
|
||||||
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async validate(
|
async validate(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
@@ -43,11 +44,21 @@ export class MatchBankTransactions {
|
|||||||
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
|
const { UncategorizedCashflowTransaction } = this.tenancy.models(tenantId);
|
||||||
const { matchedTransactions } = matchTransactionsDTO;
|
const { matchedTransactions } = matchTransactionsDTO;
|
||||||
|
|
||||||
|
// Validates the uncategorized transaction existance.
|
||||||
const uncategorizedTransaction =
|
const uncategorizedTransaction =
|
||||||
await UncategorizedCashflowTransaction.query()
|
await UncategorizedCashflowTransaction.query()
|
||||||
.findById(uncategorizedTransactionId)
|
.findById(uncategorizedTransactionId)
|
||||||
|
.withGraphFetched('matchedBankTransactions')
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
|
// Validates the uncategorized transaction is not already matched.
|
||||||
|
if (!isEmpty(uncategorizedTransaction.matchedBankTransactions)) {
|
||||||
|
throw new ServiceError(ERRORS.TRANSACTION_ALREADY_MATCHED);
|
||||||
|
}
|
||||||
|
// Validate the uncategorized transaction is not excluded.
|
||||||
|
if (uncategorizedTransaction.excluded) {
|
||||||
|
throw new ServiceError(ERRORS.CANNOT_MATCH_EXCLUDED_TRANSACTION);
|
||||||
|
}
|
||||||
// Validates the given matched transaction.
|
// Validates the given matched transaction.
|
||||||
const validateMatchedTransaction = async (matchedTransaction) => {
|
const validateMatchedTransaction = async (matchedTransaction) => {
|
||||||
const getMatchedTransactionsService =
|
const getMatchedTransactionsService =
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
import UnitOfWork from '@/services/UnitOfWork';
|
import UnitOfWork from '@/services/UnitOfWork';
|
||||||
import events from '@/subscribers/events';
|
import events from '@/subscribers/events';
|
||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import { IBankTransactionUnmatchingEventPayload } from './types';
|
import { IBankTransactionUnmatchingEventPayload } from './types';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
@@ -16,10 +16,16 @@ export class UnmatchMatchedBankTransaction {
|
|||||||
@Inject()
|
@Inject()
|
||||||
private eventPublisher: EventPublisher;
|
private eventPublisher: EventPublisher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmatch the matched the given uncategorized bank transaction.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number} uncategorizedTransactionId
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
public unmatchMatchedTransaction(
|
public unmatchMatchedTransaction(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
uncategorizedTransactionId: number
|
uncategorizedTransactionId: number
|
||||||
) {
|
): Promise<void> {
|
||||||
const { MatchedBankTransaction } = this.tenancy.models(tenantId);
|
const { MatchedBankTransaction } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
return this.uow.withTransaction(tenantId, async (trx) => {
|
return this.uow.withTransaction(tenantId, async (trx) => {
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { ServiceError } from '@/exceptions';
|
||||||
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { ERRORS } from './types';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ValidateTransactionMatched {
|
||||||
|
@Inject()
|
||||||
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {string} referenceType
|
||||||
|
* @param {number} referenceId
|
||||||
|
*/
|
||||||
|
public async validateTransactionNoMatchLinking(
|
||||||
|
tenantId: number,
|
||||||
|
referenceType: string,
|
||||||
|
referenceId: number
|
||||||
|
) {
|
||||||
|
const { MatchedBankTransaction } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const foundMatchedTransaction =
|
||||||
|
await MatchedBankTransaction.query().findOne({
|
||||||
|
referenceType,
|
||||||
|
referenceId,
|
||||||
|
});
|
||||||
|
if (foundMatchedTransaction) {
|
||||||
|
throw new ServiceError(ERRORS.CANNOT_DELETE_TRANSACTION_MATCHED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { IManualJournalDeletingPayload } from '@/interfaces';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import { ValidateTransactionMatched } from '../ValidateTransactionsMatched';
|
||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ValidateMatchingOnCashflowDelete {
|
||||||
|
@Inject()
|
||||||
|
private validateNoMatchingLinkedService: ValidateTransactionMatched;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.cashflow.onTransactionDeleting,
|
||||||
|
this.validateMatchingOnCashflowDelete.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IManualJournalDeletingPayload}
|
||||||
|
*/
|
||||||
|
public async validateMatchingOnCashflowDelete({
|
||||||
|
tenantId,
|
||||||
|
oldManualJournal,
|
||||||
|
trx,
|
||||||
|
}: IManualJournalDeletingPayload) {
|
||||||
|
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
||||||
|
tenantId,
|
||||||
|
'ManualJournal',
|
||||||
|
oldManualJournal.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { IExpenseEventDeletePayload } from '@/interfaces';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import { ValidateTransactionMatched } from '../ValidateTransactionsMatched';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ValidateMatchingOnExpenseDelete {
|
||||||
|
@Inject()
|
||||||
|
private validateNoMatchingLinkedService: ValidateTransactionMatched;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.expenses.onDeleting,
|
||||||
|
this.validateMatchingOnExpenseDelete.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IExpenseEventDeletePayload}
|
||||||
|
*/
|
||||||
|
public async validateMatchingOnExpenseDelete({
|
||||||
|
tenantId,
|
||||||
|
oldExpense,
|
||||||
|
trx,
|
||||||
|
}: IExpenseEventDeletePayload) {
|
||||||
|
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
||||||
|
tenantId,
|
||||||
|
'Expense',
|
||||||
|
oldExpense.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { IManualJournalDeletingPayload } from '@/interfaces';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import { ValidateTransactionMatched } from '../ValidateTransactionsMatched';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ValidateMatchingOnManualJournalDelete {
|
||||||
|
@Inject()
|
||||||
|
private validateNoMatchingLinkedService: ValidateTransactionMatched;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.manualJournals.onDeleting,
|
||||||
|
this.validateMatchingOnManualJournalDelete.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IManualJournalDeletingPayload}
|
||||||
|
*/
|
||||||
|
public async validateMatchingOnManualJournalDelete({
|
||||||
|
tenantId,
|
||||||
|
oldManualJournal,
|
||||||
|
trx,
|
||||||
|
}: IManualJournalDeletingPayload) {
|
||||||
|
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
||||||
|
tenantId,
|
||||||
|
'ManualJournal',
|
||||||
|
oldManualJournal.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import {
|
||||||
|
IBillPaymentEventDeletedPayload,
|
||||||
|
IPaymentReceiveDeletedPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { ValidateTransactionMatched } from '../ValidateTransactionsMatched';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ValidateMatchingOnPaymentMadeDelete {
|
||||||
|
@Inject()
|
||||||
|
private validateNoMatchingLinkedService: ValidateTransactionMatched;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.billPayment.onDeleting,
|
||||||
|
this.validateMatchingOnPaymentMadeDelete.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IPaymentReceiveDeletedPayload}
|
||||||
|
*/
|
||||||
|
public async validateMatchingOnPaymentMadeDelete({
|
||||||
|
tenantId,
|
||||||
|
oldBillPayment,
|
||||||
|
trx,
|
||||||
|
}: IBillPaymentEventDeletedPayload) {
|
||||||
|
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
||||||
|
tenantId,
|
||||||
|
'PaymentMade',
|
||||||
|
oldBillPayment.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { IPaymentReceiveDeletedPayload } from '@/interfaces';
|
||||||
|
import { ValidateTransactionMatched } from '../ValidateTransactionsMatched';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ValidateMatchingOnPaymentReceivedDelete {
|
||||||
|
@Inject()
|
||||||
|
private validateNoMatchingLinkedService: ValidateTransactionMatched;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor method.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.paymentReceive.onDeleting,
|
||||||
|
this.validateMatchingOnPaymentReceivedDelete.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IPaymentReceiveDeletedPayload}
|
||||||
|
*/
|
||||||
|
public async validateMatchingOnPaymentReceivedDelete({
|
||||||
|
tenantId,
|
||||||
|
oldPaymentReceive,
|
||||||
|
trx,
|
||||||
|
}: IPaymentReceiveDeletedPayload) {
|
||||||
|
await this.validateNoMatchingLinkedService.validateTransactionNoMatchLinking(
|
||||||
|
tenantId,
|
||||||
|
'PaymentReceive',
|
||||||
|
oldPaymentReceive.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,6 +56,8 @@ export const ERRORS = {
|
|||||||
'RESOURCE_TYPE_MATCHING_TRANSACTION_INVALID',
|
'RESOURCE_TYPE_MATCHING_TRANSACTION_INVALID',
|
||||||
RESOURCE_ID_MATCHING_TRANSACTION_INVALID:
|
RESOURCE_ID_MATCHING_TRANSACTION_INVALID:
|
||||||
'RESOURCE_ID_MATCHING_TRANSACTION_INVALID',
|
'RESOURCE_ID_MATCHING_TRANSACTION_INVALID',
|
||||||
|
|
||||||
TOTAL_MATCHING_TRANSACTIONS_INVALID: 'TOTAL_MATCHING_TRANSACTIONS_INVALID',
|
TOTAL_MATCHING_TRANSACTIONS_INVALID: 'TOTAL_MATCHING_TRANSACTIONS_INVALID',
|
||||||
|
TRANSACTION_ALREADY_MATCHED: 'TRANSACTION_ALREADY_MATCHED',
|
||||||
|
CANNOT_MATCH_EXCLUDED_TRANSACTION: 'CANNOT_MATCH_EXCLUDED_TRANSACTION',
|
||||||
|
CANNOT_DELETE_TRANSACTION_MATCHED: 'CANNOT_DELETE_TRANSACTION_MATCHED'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export class RecognizeTranasctionsService {
|
|||||||
trx
|
trx
|
||||||
).insert({
|
).insert({
|
||||||
bankRuleId: bankRule.id,
|
bankRuleId: bankRule.id,
|
||||||
cashflowTransactionId: transaction.id,
|
uncategorizedTransactionId: transaction.id,
|
||||||
assignedCategory: bankRule.assignCategory,
|
assignedCategory: bankRule.assignCategory,
|
||||||
assignedAccountId: bankRule.assignAccountId,
|
assignedAccountId: bankRule.assignAccountId,
|
||||||
assignedPayee: bankRule.assignPayee,
|
assignedPayee: bankRule.assignPayee,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Inject, Service } from 'typedi';
|
|||||||
import events from '@/subscribers/events';
|
import events from '@/subscribers/events';
|
||||||
import {
|
import {
|
||||||
IBankRuleEventCreatedPayload,
|
IBankRuleEventCreatedPayload,
|
||||||
|
IBankRuleEventDeletedPayload,
|
||||||
IBankRuleEventEditedPayload,
|
IBankRuleEventEditedPayload,
|
||||||
} from '../../Rules/types';
|
} from '../../Rules/types';
|
||||||
|
|
||||||
@@ -20,17 +21,55 @@ export class TriggerRecognizedTransactions {
|
|||||||
);
|
);
|
||||||
bus.subscribe(
|
bus.subscribe(
|
||||||
events.bankRules.onEdited,
|
events.bankRules.onEdited,
|
||||||
this.recognizedTransactionsOnRuleCreated.bind(this)
|
this.recognizedTransactionsOnRuleEdited.bind(this)
|
||||||
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.bankRules.onDeleted,
|
||||||
|
this.recognizedTransactionsOnRuleDeleted.bind(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers the recognize uncategorized transactions job.
|
* Triggers the recognize uncategorized transactions job on rule created.
|
||||||
* @param {IBankRuleEventEditedPayload | IBankRuleEventCreatedPayload} payload -
|
* @param {IBankRuleEventCreatedPayload} payload -
|
||||||
*/
|
*/
|
||||||
private async recognizedTransactionsOnRuleCreated({
|
private async recognizedTransactionsOnRuleCreated({
|
||||||
tenantId,
|
tenantId,
|
||||||
}: IBankRuleEventEditedPayload | IBankRuleEventCreatedPayload) {
|
createRuleDTO,
|
||||||
|
}: IBankRuleEventCreatedPayload) {
|
||||||
|
const payload = { tenantId };
|
||||||
|
|
||||||
|
// Cannot run recognition if the option is not enabled.
|
||||||
|
if (createRuleDTO.recognition) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.agenda.now('recognize-uncategorized-transactions-job', payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers the recognize uncategorized transactions job on rule edited.
|
||||||
|
* @param {IBankRuleEventEditedPayload} payload -
|
||||||
|
*/
|
||||||
|
private async recognizedTransactionsOnRuleEdited({
|
||||||
|
tenantId,
|
||||||
|
editRuleDTO,
|
||||||
|
}: IBankRuleEventEditedPayload) {
|
||||||
|
const payload = { tenantId };
|
||||||
|
|
||||||
|
// Cannot run recognition if the option is not enabled.
|
||||||
|
if (!editRuleDTO.recognition) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.agenda.now('recognize-uncategorized-transactions-job', payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers the recognize uncategorized transactions job on rule deleted.
|
||||||
|
* @param {IBankRuleEventDeletedPayload} payload -
|
||||||
|
*/
|
||||||
|
private async recognizedTransactionsOnRuleDeleted({
|
||||||
|
tenantId,
|
||||||
|
}: IBankRuleEventDeletedPayload) {
|
||||||
const payload = { tenantId };
|
const payload = { tenantId };
|
||||||
await this.agenda.now('recognize-uncategorized-transactions-job', payload);
|
await this.agenda.now('recognize-uncategorized-transactions-job', payload);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ export interface IBankRuleCommonDTO {
|
|||||||
assignAccountId: number;
|
assignAccountId: number;
|
||||||
assignPayee?: string;
|
assignPayee?: string;
|
||||||
assignMemo?: string;
|
assignMemo?: string;
|
||||||
|
|
||||||
|
recognition?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICreateBankRuleDTO extends IBankRuleCommonDTO {}
|
export interface ICreateBankRuleDTO extends IBankRuleCommonDTO {}
|
||||||
|
|||||||
Reference in New Issue
Block a user