diff --git a/packages/server/src/interfaces/CashFlow.ts b/packages/server/src/interfaces/CashFlow.ts index 9e1d4bfd5..0b3298929 100644 --- a/packages/server/src/interfaces/CashFlow.ts +++ b/packages/server/src/interfaces/CashFlow.ts @@ -285,3 +285,17 @@ export interface IUncategorizedTransactionCreatedEventPayload { createUncategorizedTransactionDTO: CreateUncategorizedTransactionDTO; trx: Knex.Transaction; } + +export interface IPendingTransactionRemovingEventPayload { + tenantId: number; + uncategorizedTransactionId: number; + pendingTransaction: IUncategorizedCashflowTransaction; + trx?: Knex.Transaction; +} + +export interface IPendingTransactionRemovedEventPayload { + tenantId: number; + uncategorizedTransactionId: number; + pendingTransaction: IUncategorizedCashflowTransaction; + trx?: Knex.Transaction; +} diff --git a/packages/server/src/services/Banking/BankAccounts/GetBankAccountSummary.ts b/packages/server/src/services/Banking/BankAccounts/GetBankAccountSummary.ts index 6c66c2a5e..4d7b7885a 100644 --- a/packages/server/src/services/Banking/BankAccounts/GetBankAccountSummary.ts +++ b/packages/server/src/services/Banking/BankAccounts/GetBankAccountSummary.ts @@ -52,6 +52,9 @@ export class GetBankAccountSummary { q.withGraphJoined('matchedBankTransactions'); q.whereNull('matchedBankTransactions.id'); + // Exclude the pending transactions. + q.modify('notPending'); + // Count the results. q.count('uncategorized_cashflow_transactions.id as total'); q.first(); @@ -65,6 +68,9 @@ export class GetBankAccountSummary { q.withGraphJoined('recognizedTransaction'); q.whereNotNull('recognizedTransaction.id'); + // Exclude the pending transactions. + q.modify('notPending'); + // Count the results. q.count('uncategorized_cashflow_transactions.id as total'); q.first(); @@ -75,6 +81,9 @@ export class GetBankAccountSummary { q.where('accountId', bankAccountId); q.modify('excluded'); + // Exclude the pending transactions. + q.modify('notPending'); + // Count the results. q.count('uncategorized_cashflow_transactions.id as total'); q.first(); diff --git a/packages/server/src/services/Cashflow/GetRecongizedTransactions.ts b/packages/server/src/services/Cashflow/GetRecongizedTransactions.ts index 9ba2bd102..e82d0b0c8 100644 --- a/packages/server/src/services/Cashflow/GetRecongizedTransactions.ts +++ b/packages/server/src/services/Cashflow/GetRecongizedTransactions.ts @@ -34,7 +34,9 @@ export class GetRecognizedTransactionsService { q.withGraphFetched('recognizedTransaction.assignAccount'); q.withGraphFetched('recognizedTransaction.bankRule'); q.whereNotNull('recognizedTransactionId'); + q.modify('notExcluded'); + q.modify('notPending'); if (_filter.accountId) { q.where('accountId', _filter.accountId); diff --git a/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts b/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts index 7b3c76774..76625536c 100644 --- a/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts +++ b/packages/server/src/services/Cashflow/GetUncategorizedTransactions.ts @@ -51,7 +51,9 @@ export class GetUncategorizedTransactions { .onBuild((q) => { q.where('accountId', accountId); q.where('categorized', false); + q.modify('notExcluded'); + q.modify('notPending'); q.withGraphFetched('account'); q.withGraphFetched('recognizedTransaction.assignAccount'); diff --git a/packages/server/src/services/Cashflow/RemovePendingUncategorizedTransaction.ts b/packages/server/src/services/Cashflow/RemovePendingUncategorizedTransaction.ts index 15a75ae23..101a914cf 100644 --- a/packages/server/src/services/Cashflow/RemovePendingUncategorizedTransaction.ts +++ b/packages/server/src/services/Cashflow/RemovePendingUncategorizedTransaction.ts @@ -6,6 +6,10 @@ import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import events from '@/subscribers/events'; import { ServiceError } from '@/exceptions'; import { ERRORS } from './constants'; +import { + IPendingTransactionRemovedEventPayload, + IPendingTransactionRemovingEventPayload, +} from '@/interfaces'; @Service() export class RemovePendingUncategorizedTransaction { @@ -42,7 +46,12 @@ export class RemovePendingUncategorizedTransaction { return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => { await this.eventPublisher.emitAsync( events.bankTransactions.onPendingRemoving, - { tenantId, uncategorizedTransactionId, trx } + { + tenantId, + uncategorizedTransactionId, + pendingTransaction, + trx, + } as IPendingTransactionRemovingEventPayload ); // Removes the pending uncategorized transaction. await UncategorizedCashflowTransaction.query(trx) @@ -51,7 +60,12 @@ export class RemovePendingUncategorizedTransaction { await this.eventPublisher.emitAsync( events.bankTransactions.onPendingRemoved, - { tenantId, uncategorizedTransactionId, trx } + { + tenantId, + uncategorizedTransactionId, + pendingTransaction, + trx, + } as IPendingTransactionRemovedEventPayload ); }); } diff --git a/packages/server/src/services/Cashflow/subscribers/DecrementUncategorizedTransactionOnCategorize.ts b/packages/server/src/services/Cashflow/subscribers/DecrementUncategorizedTransactionOnCategorize.ts index a1570a390..bd008967b 100644 --- a/packages/server/src/services/Cashflow/subscribers/DecrementUncategorizedTransactionOnCategorize.ts +++ b/packages/server/src/services/Cashflow/subscribers/DecrementUncategorizedTransactionOnCategorize.ts @@ -1,11 +1,11 @@ import { Inject, Service } from 'typedi'; +import PromisePool from '@supercharge/promise-pool'; import events from '@/subscribers/events'; import HasTenancyService from '@/services/Tenancy/TenancyService'; import { ICashflowTransactionCategorizedPayload, ICashflowTransactionUncategorizedPayload, } from '@/interfaces'; -import PromisePool from '@supercharge/promise-pool'; @Service() export class DecrementUncategorizedTransactionOnCategorize { @@ -36,13 +36,17 @@ export class DecrementUncategorizedTransactionOnCategorize { public async decrementUnCategorizedTransactionsOnCategorized({ tenantId, uncategorizedTransactions, - trx + trx, }: ICashflowTransactionCategorizedPayload) { const { Account } = this.tenancy.models(tenantId); await PromisePool.withConcurrency(1) .for(uncategorizedTransactions) .process(async (uncategorizedTransaction) => { + // Cannot continue if the transaction is still pending. + if (uncategorizedTransaction.isPending) { + return; + } await Account.query(trx) .findById(uncategorizedTransaction.accountId) .decrement('uncategorizedTransactions', 1); @@ -56,13 +60,17 @@ export class DecrementUncategorizedTransactionOnCategorize { public async incrementUnCategorizedTransactionsOnUncategorized({ tenantId, uncategorizedTransactions, - trx + trx, }: ICashflowTransactionUncategorizedPayload) { const { Account } = this.tenancy.models(tenantId); await PromisePool.withConcurrency(1) .for(uncategorizedTransactions) .process(async (uncategorizedTransaction) => { + // Cannot continue if the transaction is still pending. + if (uncategorizedTransaction.isPending) { + return; + } await Account.query(trx) .findById(uncategorizedTransaction.accountId) .increment('uncategorizedTransactions', 1); @@ -82,6 +90,9 @@ export class DecrementUncategorizedTransactionOnCategorize { if (!uncategorizedTransaction.accountId) return; + // Cannot continue if the transaction is still pending. + if (uncategorizedTransaction.isPending) return; + await Account.query(trx) .findById(uncategorizedTransaction.accountId) .increment('uncategorizedTransactions', 1);