Skip to content

Commit

Permalink
fix: bank transactions report
Browse files Browse the repository at this point in the history
  • Loading branch information
abouolia committed Jul 7, 2024
1 parent b7487f1 commit 9a5befb
Show file tree
Hide file tree
Showing 28 changed files with 560 additions and 158 deletions.
2 changes: 2 additions & 0 deletions packages/server/src/interfaces/Account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ export interface IAccountTransaction {
referenceId: number;

referenceNumber?: string;

transactionNumber?: string;
transactionType?: string;

note?: string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ export interface ICashflowAccountTransaction {

date: Date;
formattedDate: string;

status: string;
formattedStatus: string;

uncategorizedTransactionId: number;
}
2 changes: 2 additions & 0 deletions packages/server/src/interfaces/Ledger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export interface ILedgerEntry {
date: Date | string;

transactionType: string;
transactionSubType: string;

transactionId: number;

transactionNumber?: string;
Expand Down
2 changes: 2 additions & 0 deletions packages/server/src/loaders/eventEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ import { ValidateMatchingOnCashflowDelete } from '@/services/Banking/Matching/ev
import { RecognizeSyncedBankTranasctions } from '@/services/Banking/Plaid/subscribers/RecognizeSyncedBankTransactions';
import { UnlinkBankRuleOnDeleteBankRule } from '@/services/Banking/Rules/events/UnlinkBankRuleOnDeleteBankRule';
import { DecrementUncategorizedTransactionOnMatching } from '@/services/Banking/Matching/events/DecrementUncategorizedTransactionsOnMatch';
import { DecrementUncategorizedTransactionOnExclude } from '@/services/Banking/Exclude/events/DecrementUncategorizedTransactionOnExclude';

export default () => {
return new EventPublisher();
Expand Down Expand Up @@ -260,6 +261,7 @@ export const susbcribers = () => {
TriggerRecognizedTransactions,
UnlinkBankRuleOnDeleteBankRule,
DecrementUncategorizedTransactionOnMatching,
DecrementUncategorizedTransactionOnExclude,

// Validate matching
ValidateMatchingOnCashflowDelete,
Expand Down
19 changes: 18 additions & 1 deletion packages/server/src/models/CashflowTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import {
getCashflowAccountTransactionsTypes,
getCashflowTransactionType,
} from '@/services/Cashflow/utils';
import AccountTransaction from './AccountTransaction';
import { CASHFLOW_DIRECTION } from '@/services/Cashflow/constants';
import { getTransactionTypeLabel } from '@/utils/transactions-types';

export default class CashflowTransaction extends TenantModel {
transactionType: string;
amount: number;
Expand Down Expand Up @@ -100,9 +100,26 @@ export default class CashflowTransaction extends TenantModel {
*/
static get modifiers() {
return {
/**
* Filter the published transactions.
*/
published(query) {
query.whereNot('published_at', null);
},

/**
* Filter the not categorized transactions.
*/
notCategorized(query) {
query.whereNull('cashflowTransactions.uncategorizedTransactionId');
},

/**
* Filter the categorized transactions.
*/
categorized(query) {
query.whereNotNull('cashflowTransactions.uncategorizedTransactionId');
},
};
}

Expand Down
2 changes: 2 additions & 0 deletions packages/server/src/services/Accounting/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const transformLedgerEntryToTransaction = (
referenceId: entry.transactionId,

transactionNumber: entry.transactionNumber,
transactionType: entry.transactionSubType,

referenceNumber: entry.referenceNumber,

note: entry.note,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ export class GetBankAccountSummary {
Account,
UncategorizedCashflowTransaction,
RecognizedBankTransaction,
MatchedBankTransaction,
} = this.tenancy.models(tenantId);

await initialize(knex, [
UncategorizedCashflowTransaction,
RecognizedBankTransaction,
MatchedBankTransaction,
]);
const bankAccount = await Account.query()
.findById(bankAccountId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import HasTenancyService from '@/services/Tenancy/TenancyService';
import UnitOfWork from '@/services/UnitOfWork';
import { Inject, Service } from 'typedi';
import { validateTransactionNotCategorized } from './utils';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import events from '@/subscribers/events';
import {
IBankTransactionUnexcludedEventPayload,
IBankTransactionUnexcludingEventPayload,
} from './_types';

@Service()
export class ExcludeBankTransaction {
Expand All @@ -11,6 +17,9 @@ export class ExcludeBankTransaction {
@Inject()
private uow: UnitOfWork;

@Inject()
private eventPublisher: EventPublisher;

/**
* Marks the given bank transaction as excluded.
* @param {number} tenantId
Expand All @@ -31,11 +40,23 @@ export class ExcludeBankTransaction {
validateTransactionNotCategorized(oldUncategorizedTransaction);

return this.uow.withTransaction(tenantId, async (trx) => {
await this.eventPublisher.emitAsync(events.bankTransactions.onExcluding, {
tenantId,
uncategorizedTransactionId,
trx,
} as IBankTransactionUnexcludingEventPayload);

await UncategorizedCashflowTransaction.query(trx)
.findById(uncategorizedTransactionId)
.patch({
excludedAt: new Date(),
});

await this.eventPublisher.emitAsync(events.bankTransactions.onExcluded, {
tenantId,
uncategorizedTransactionId,
trx,
} as IBankTransactionUnexcludedEventPayload);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import HasTenancyService from '@/services/Tenancy/TenancyService';
import UnitOfWork from '@/services/UnitOfWork';
import { Inject, Service } from 'typedi';
import { validateTransactionNotCategorized } from './utils';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import events from '@/subscribers/events';
import {
IBankTransactionExcludedEventPayload,
IBankTransactionExcludingEventPayload,
} from './_types';

@Service()
export class UnexcludeBankTransaction {
Expand All @@ -11,6 +17,9 @@ export class UnexcludeBankTransaction {
@Inject()
private uow: UnitOfWork;

@Inject()
private eventPublisher: EventPublisher;

/**
* Marks the given bank transaction as excluded.
* @param {number} tenantId
Expand All @@ -31,11 +40,21 @@ export class UnexcludeBankTransaction {
validateTransactionNotCategorized(oldUncategorizedTransaction);

return this.uow.withTransaction(tenantId, async (trx) => {
await this.eventPublisher.emitAsync(events.bankTransactions.onExcluding, {
tenantId,
uncategorizedTransactionId,
} as IBankTransactionExcludingEventPayload);

await UncategorizedCashflowTransaction.query(trx)
.findById(uncategorizedTransactionId)
.patch({
excludedAt: null,
});

await this.eventPublisher.emitAsync(events.bankTransactions.onExcluded, {
tenantId,
uncategorizedTransactionId,
} as IBankTransactionExcludedEventPayload);
});
}
}
26 changes: 25 additions & 1 deletion packages/server/src/services/Banking/Exclude/_types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
import { Knex } from "knex";

export interface ExcludedBankTransactionsQuery {
page?: number;
pageSize?: number;
accountId?: number;
}
}

export interface IBankTransactionUnexcludingEventPayload {
tenantId: number;
uncategorizedTransactionId: number;
trx?: Knex.Transaction
}

export interface IBankTransactionUnexcludedEventPayload {
tenantId: number;
uncategorizedTransactionId: number;
trx?: Knex.Transaction
}

export interface IBankTransactionExcludingEventPayload {
tenantId: number;
uncategorizedTransactionId: number;
trx?: Knex.Transaction
}
export interface IBankTransactionExcludedEventPayload {
tenantId: number;
uncategorizedTransactionId: number;
trx?: Knex.Transaction
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Inject, Service } from 'typedi';
import events from '@/subscribers/events';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import {
IBankTransactionExcludedEventPayload,
IBankTransactionUnexcludedEventPayload,
} from '../_types';

@Service()
export class DecrementUncategorizedTransactionOnExclude {
@Inject()
private tenancy: HasTenancyService;
/**
* Constructor method.
*/
public attach(bus) {
bus.subscribe(
events.bankTransactions.onExcluded,
this.decrementUnCategorizedTransactionsOnExclude.bind(this)
);
bus.subscribe(
events.bankTransactions.onUnexcluded,
this.incrementUnCategorizedTransactionsOnUnexclude.bind(this)
);
}

/**
* Validates the cashflow transaction whether matched with bank transaction on deleting.
* @param {IManualJournalDeletingPayload}
*/
public async decrementUnCategorizedTransactionsOnExclude({
tenantId,
uncategorizedTransactionId,
trx,
}: IBankTransactionExcludedEventPayload) {
const { UncategorizedCashflowTransaction, Account } =
this.tenancy.models(tenantId);

const transaction = await UncategorizedCashflowTransaction.query(
trx
).findById(uncategorizedTransactionId);

await Account.query(trx)
.findById(transaction.accountId)
.decrement('uncategorizedTransactions', 1);
}

/**
* Validates the cashflow transaction whether matched with bank transaction on deleting.
* @param {IManualJournalDeletingPayload}
*/
public async incrementUnCategorizedTransactionsOnUnexclude({
tenantId,
uncategorizedTransactionId,
trx,
}: IBankTransactionUnexcludedEventPayload) {
const { UncategorizedCashflowTransaction, Account } =
this.tenancy.models(tenantId);

const transaction = await UncategorizedCashflowTransaction.query().findById(
uncategorizedTransactionId
);
//
await Account.query(trx)
.findById(transaction.accountId)
.increment('uncategorizedTransactions', 1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export class GetMatchedTransactionsByCashflow extends GetMatchedTransactionsByTy
q.withGraphJoined('matchedBankTransaction');
q.whereNull('matchedBankTransaction.id');

// Not categorized.
q.modify('notCategorized');

// Published.
q.modify('published');

Expand Down Expand Up @@ -69,6 +72,8 @@ export class GetMatchedTransactionsByCashflow extends GetMatchedTransactionsByTy
.findById(transactionId)
.withGraphJoined('matchedBankTransaction')
.whereNull('matchedBankTransaction.id')
.modify('notCategorized')
.modify('published')
.throwIfNotFound();

return this.transformer.transform(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export class DecrementUncategorizedTransactionOnMatching {
public async decrementUnCategorizedTransactionsOnMatching({
tenantId,
uncategorizedTransactionId,
matchTransactionsDTO,
trx,
}: IBankTransactionMatchedEventPayload) {
const { UncategorizedCashflowTransaction, Account } =
Expand Down Expand Up @@ -64,6 +63,6 @@ export class DecrementUncategorizedTransactionOnMatching {
//
await Account.query(trx)
.findById(transaction.accountId)
.decrement('uncategorizedTransactions', 1);
.increment('uncategorizedTransactions', 1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ export default class CashflowTransactionJournalEntries {
currencyCode: transaction.currencyCode,
exchangeRate: transaction.exchangeRate,

transactionType: transformCashflowTransactionType(
transaction.transactionType
),
transactionType: 'CashflowTransaction',
transactionId: transaction.id,
transactionNumber: transaction.transactionNumber,
transactionSubType: transformCashflowTransactionType(
transaction.transactionType
),
referenceNumber: transaction.referenceNo,

note: transaction.description,
Expand Down Expand Up @@ -161,12 +162,10 @@ export default class CashflowTransactionJournalEntries {
cashflowTransactionId: number,
trx?: Knex.Transaction
): Promise<void> => {
const transactionTypes = getCashflowAccountTransactionsTypes();

await this.ledgerStorage.deleteByReference(
tenantId,
cashflowTransactionId,
transactionTypes,
'CashflowTransaction',
trx
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export default class NewCashflowTransactionService {
...fromDTO,
transactionNumber,
currencyCode: cashflowAccount.currencyCode,
exchangeRate: fromDTO?.exchangeRate || 1,
transactionType: transformCashflowTransactionType(
fromDTO.transactionType
),
Expand Down
Loading

0 comments on commit 9a5befb

Please sign in to comment.