refactor: expense GL to Nestjs

This commit is contained in:
Ahmed Bouhuolia
2024-12-30 22:08:50 +02:00
parent 3191076762
commit 4938db704e
20 changed files with 1344 additions and 274 deletions

View File

@@ -10,6 +10,8 @@ import { ExpenseDTOTransformer } from './commands/CommandExpenseDTO.transformer'
import { CommandExpenseValidator } from './commands/CommandExpenseValidator.service';
import { TenancyContext } from '../Tenancy/TenancyContext.service';
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
import { ExpensesWriteGLSubscriber } from './subscribers/ExpenseGLEntries.subscriber';
import { ExpenseGLEntriesStorageService } from './subscribers/ExpenseGLEntriesStorage.sevice';
@Module({
imports: [],
@@ -24,7 +26,9 @@ import { TransformerInjectable } from '../Transformer/TransformerInjectable.serv
GetExpenseService,
ExpensesApplication,
TenancyContext,
TransformerInjectable
TransformerInjectable,
ExpensesWriteGLSubscriber,
ExpenseGLEntriesStorageService,
],
})
export class ExpensesModule {}

View File

@@ -8,6 +8,8 @@ import { Model, mixin, raw } from 'objection';
// import ModelSearchable from './ModelSearchable';
import moment from 'moment';
import { BaseModel } from '@/models/Model';
import { ExpenseCategory } from './ExpenseCategory.model';
import { Account } from '@/modules/Accounts/models/Account.model';
export class Expense extends BaseModel {
// ModelSetting,
@@ -32,6 +34,9 @@ export class Expense extends BaseModel {
branchId!: number;
createdAt!: Date;
categories!: ExpenseCategory[];
paymentAccount!: Account;
/**
* Table name
*/

View File

@@ -2,8 +2,11 @@ import { Model } from 'objection';
import { BaseModel } from '@/models/Model';
export class ExpenseCategory extends BaseModel {
amount!: number;
allocatedCostAmount!: number;
public amount!: number;
public allocatedCostAmount!: number;
public expenseAccountId!: number;
public projectId!: number;
public description!: string;
/**
* Table name

View File

@@ -1,113 +1,105 @@
// import * as R from 'ramda';
// import {
// AccountNormal,
// IExpenseCategory,
// ILedger,
// ILedgerEntry,
// } from '@/interfaces';
// import Ledger from '../Accounting/Ledger';
import * as R from 'ramda';
import { ILedger } from '@/modules/Ledger/types/Ledger.types';
import { AccountNormal } from '@/modules/Accounts/Accounts.types';
import { ILedgerEntry } from '@/modules/Ledger/types/Ledger.types';
import { ExpenseCategory } from '../models/ExpenseCategory.model';
import { Ledger } from '@/modules/Ledger/Ledger';
import { Expense } from '../models/Expense.model';
// export class ExpenseGL {
// private expense: any;
export class ExpenseGL {
private expense: Expense;
// /**
// * Constructor method.
// */
// constructor(expense: any) {
// this.expense = expense;
// }
/**
* Constructor method.
* @param {Expense} expense - Expense.
*/
constructor(expense: Expense) {
this.expense = expense;
}
// /**
// * Retrieves the expense GL common entry.
// * @param {IExpense} expense
// * @returns {Partial<ILedgerEntry>}
// */
// private getExpenseGLCommonEntry = (): Partial<ILedgerEntry> => {
// return {
// currencyCode: this.expense.currencyCode,
// exchangeRate: this.expense.exchangeRate,
/**
* Retrieves the expense GL common entry.
*/
private getExpenseGLCommonEntry = () => {
return {
currencyCode: this.expense.currencyCode,
exchangeRate: this.expense.exchangeRate,
// transactionType: 'Expense',
// transactionId: this.expense.id,
transactionType: 'Expense',
transactionId: this.expense.id,
// date: this.expense.paymentDate,
// userId: this.expense.userId,
date: this.expense.paymentDate,
userId: this.expense.userId,
// debit: 0,
// credit: 0,
debit: 0,
credit: 0,
// branchId: this.expense.branchId,
// };
// };
branchId: this.expense.branchId,
};
};
// /**
// * Retrieves the expense GL payment entry.
// * @param {IExpense} expense
// * @returns {ILedgerEntry}
// */
// private getExpenseGLPaymentEntry = (): ILedgerEntry => {
// const commonEntry = this.getExpenseGLCommonEntry();
/**
* Retrieves the expense GL payment entry.
* @returns {ILedgerEntry}
*/
private getExpenseGLPaymentEntry = (): ILedgerEntry => {
const commonEntry = this.getExpenseGLCommonEntry();
// return {
// ...commonEntry,
// credit: this.expense.localAmount,
// accountId: this.expense.paymentAccountId,
// accountNormal:
// this.expense?.paymentAccount?.accountNormal === 'debit'
// ? AccountNormal.DEBIT
// : AccountNormal.CREDIT,
// index: 1,
// };
// };
return {
...commonEntry,
credit: this.expense.localAmount,
accountId: this.expense.paymentAccountId,
accountNormal:
this.expense?.paymentAccount?.accountNormal === 'debit'
? AccountNormal.DEBIT
: AccountNormal.CREDIT,
index: 1,
};
};
// /**
// * Retrieves the expense GL category entry.
// * @param {IExpense} expense -
// * @param {IExpenseCategory} expenseCategory -
// * @param {number} index
// * @returns {ILedgerEntry}
// */
// private getExpenseGLCategoryEntry = R.curry(
// (category: IExpenseCategory, index: number): ILedgerEntry => {
// const commonEntry = this.getExpenseGLCommonEntry();
// const localAmount = category.amount * this.expense.exchangeRate;
/**
* Retrieves the expense GL category entry.
* @param {ExpenseCategory} category - Expense category.
* @param {number} index
* @returns {ILedgerEntry}
*/
private getExpenseGLCategoryEntry = R.curry(
(category: ExpenseCategory, index: number): ILedgerEntry => {
const commonEntry = this.getExpenseGLCommonEntry();
const localAmount = category.amount * this.expense.exchangeRate;
// return {
// ...commonEntry,
// accountId: category.expenseAccountId,
// accountNormal: AccountNormal.DEBIT,
// debit: localAmount,
// note: category.description,
// index: index + 2,
// projectId: category.projectId,
// };
// }
// );
return {
...commonEntry,
accountId: category.expenseAccountId,
accountNormal: AccountNormal.DEBIT,
debit: localAmount,
note: category.description,
index: index + 2,
projectId: category.projectId,
};
}
);
// /**
// * Retrieves the expense GL entries.
// * @param {IExpense} expense
// * @returns {ILedgerEntry[]}
// */
// public getExpenseGLEntries = (): ILedgerEntry[] => {
// const getCategoryEntry = this.getExpenseGLCategoryEntry();
/**
* Retrieves the expense GL entries.
* @returns {ILedgerEntry[]}
*/
public getExpenseGLEntries = (): ILedgerEntry[] => {
const getCategoryEntry = this.getExpenseGLCategoryEntry();
// const paymentEntry = this.getExpenseGLPaymentEntry();
// const categoryEntries = this.expense.categories.map(getCategoryEntry);
const paymentEntry = this.getExpenseGLPaymentEntry();
const categoryEntries = this.expense.categories.map(getCategoryEntry);
// return [paymentEntry, ...categoryEntries];
// };
return [paymentEntry, ...categoryEntries];
};
// /**
// * Retrieves the given expense ledger.
// * @param {IExpense} expense
// * @returns {ILedger}
// */
// public getExpenseLedger = (): ILedger => {
// const entries = this.getExpenseGLEntries();
/**
* Retrieves the given expense ledger.
* @returns {ILedger}
*/
public getExpenseLedger = (): ILedger => {
const entries = this.getExpenseGLEntries();
// console.log(entries, 'entries');
// return new Ledger(entries);
// };
// }
return new Ledger(entries);
};
}

View File

@@ -1,42 +1,44 @@
// import { Knex } from 'knex';
// import { ExpenseGL } from './ExpenseGL';
// import { Inject, Injectable } from '@nestjs/common';
// import { Expense } from '../models/Expense.model';
import { Knex } from 'knex';
import { ExpenseGL } from './ExpenseGL';
import { Inject, Injectable } from '@nestjs/common';
import { Expense } from '../models/Expense.model';
import { ILedger } from '@/modules/Ledger/types/Ledger.types';
// @Injectable()
// export class ExpenseGLEntries {
// constructor(
// @Inject(Expense.name)
// private readonly expense: typeof Expense,
// ) {}
// /**
// * Retrieves the expense G/L of the given id.
// * @param {number} expenseId
// * @param {Knex.Transaction} trx
// * @returns {Promise<ILedger>}
// */
// public getExpenseLedgerById = async (
// expenseId: number,
// trx?: Knex.Transaction,
// ): Promise<ILedger> => {
// const expense = await this.expense
// .query(trx)
// .findById(expenseId)
// .withGraphFetched('categories')
// .withGraphFetched('paymentAccount')
// .throwIfNotFound();
@Injectable()
export class ExpenseGLEntriesService {
constructor(
@Inject(Expense.name)
private readonly expense: typeof Expense,
) {}
// return this.getExpenseLedger(expense);
// };
/**
* Retrieves the expense G/L of the given id.
* @param {number} expenseId
* @param {Knex.Transaction} trx
* @returns {Promise<ILedger>}
*/
public getExpenseLedgerById = async (
expenseId: number,
trx?: Knex.Transaction,
): Promise<ILedger> => {
const expense = await this.expense
.query(trx)
.findById(expenseId)
.withGraphFetched('categories')
.withGraphFetched('paymentAccount')
.throwIfNotFound();
// /**
// * Retrieves the given expense ledger.
// * @param {IExpense} expense
// * @returns {ILedger}
// */
// public getExpenseLedger = (expense: Expense): ILedger => {
// const expenseGL = new ExpenseGL(expense);
return this.getExpenseLedger(expense);
};
// return expenseGL.getExpenseLedger();
// };
// }
/**
* Retrieves the given expense ledger.
* @param {IExpense} expense
* @returns {ILedger}
*/
public getExpenseLedger = (expense: Expense): ILedger => {
const expenseGL = new ExpenseGL(expense);
return expenseGL.getExpenseLedger();
};
}

View File

@@ -1,77 +1,79 @@
// import {
// IExpenseCreatedPayload,
// IExpenseEventDeletePayload,
// IExpenseEventEditPayload,
// IExpenseEventPublishedPayload,
// } from '../Expenses.types';
// import { ExpenseGLEntriesStorage } from './ExpenseGLEntriesStorage';
// import { Injectable } from '@nestjs/common';
// import { OnEvent } from '@nestjs/event-emitter';
// import { events } from '@/common/events/events';
import {
IExpenseCreatedPayload,
IExpenseEventDeletePayload,
IExpenseEventEditPayload,
IExpenseEventPublishedPayload,
} from '../Expenses.types';
import { ExpenseGLEntriesStorageService } from './ExpenseGLEntriesStorage.sevice';
import { Injectable } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { events } from '@/common/events/events';
// @Injectable()
// export class ExpensesWriteGLSubscriber {
// /**
// * @param {ExpenseGLEntriesStorage} expenseGLEntries -
// */
// constructor(private readonly expenseGLEntries: ExpenseGLEntriesStorage) {}
@Injectable()
export class ExpensesWriteGLSubscriber {
/**
* @param {ExpenseGLEntriesStorageService} expenseGLEntries -
*/
constructor(
private readonly expenseGLEntries: ExpenseGLEntriesStorageService,
) {}
// /**
// * Handles the writing journal entries once the expense created.
// * @param {IExpenseCreatedPayload} payload -
// */
// @OnEvent(events.expenses.onCreated)
// public async handleWriteGLEntriesOnceCreated({
// expense,
// trx,
// }: IExpenseCreatedPayload) {
// // In case expense published, write journal entries.
// if (!expense.publishedAt) return;
/**
* Handles the writing journal entries once the expense created.
* @param {IExpenseCreatedPayload} payload -
*/
@OnEvent(events.expenses.onCreated)
public async handleWriteGLEntriesOnceCreated({
expense,
trx,
}: IExpenseCreatedPayload) {
// In case expense published, write journal entries.
if (!expense.publishedAt) return;
// await this.expenseGLEntries.writeExpenseGLEntries(expense.id, trx);
// }
await this.expenseGLEntries.writeExpenseGLEntries(expense.id, trx);
}
// /**
// * Handle writing expense journal entries once the expense edited.
// * @param {IExpenseEventEditPayload} payload -
// */
// @OnEvent(events.expenses.onEdited)
// public async handleRewriteGLEntriesOnceEdited({
// expenseId,
// expense,
// authorizedUser,
// trx,
// }: IExpenseEventEditPayload) {
// // Cannot continue if the expense is not published.
// if (!expense.publishedAt) return;
/**
* Handle writing expense journal entries once the expense edited.
* @param {IExpenseEventEditPayload} payload -
*/
@OnEvent(events.expenses.onEdited)
public async handleRewriteGLEntriesOnceEdited({
expenseId,
expense,
authorizedUser,
trx,
}: IExpenseEventEditPayload) {
// Cannot continue if the expense is not published.
if (!expense.publishedAt) return;
// await this.expenseGLEntries.rewriteExpenseGLEntries(expense.id, trx);
// }
await this.expenseGLEntries.rewriteExpenseGLEntries(expense.id, trx);
}
// /**
// * Reverts expense journal entries once the expense deleted.
// * @param {IExpenseEventDeletePayload} payload -
// */
// @OnEvent(events.expenses.onDeleted)
// public async handleRevertGLEntriesOnceDeleted({
// expenseId,
// trx,
// }: IExpenseEventDeletePayload) {
// await this.expenseGLEntries.revertExpenseGLEntries(expenseId, trx);
// }
/**
* Reverts expense journal entries once the expense deleted.
* @param {IExpenseEventDeletePayload} payload -
*/
@OnEvent(events.expenses.onDeleted)
public async handleRevertGLEntriesOnceDeleted({
expenseId,
trx,
}: IExpenseEventDeletePayload) {
await this.expenseGLEntries.revertExpenseGLEntries(expenseId, trx);
}
// /**
// * Handles writing expense journal once the expense publish.
// * @param {IExpenseEventPublishedPayload} payload -
// */
// @OnEvent(events.expenses.onPublished)
// public async handleWriteGLEntriesOncePublished({
// expense,
// trx,
// }: IExpenseEventPublishedPayload) {
// // In case expense published, write journal entries.
// if (!expense.publishedAt) return;
/**
* Handles writing expense journal once the expense publish.
* @param {IExpenseEventPublishedPayload} payload -
*/
@OnEvent(events.expenses.onPublished)
public async handleWriteGLEntriesOncePublished({
expense,
trx,
}: IExpenseEventPublishedPayload) {
// In case expense published, write journal entries.
if (!expense.publishedAt) return;
// await this.expenseGLEntries.rewriteExpenseGLEntries(expense.id, trx);
// }
// }
await this.expenseGLEntries.rewriteExpenseGLEntries(expense.id, trx);
}
}

View File

@@ -0,0 +1,68 @@
import { Knex } from 'knex';
import { Injectable } from '@nestjs/common';
import { ExpenseGLEntriesService } from './ExpenseGLEntries.service';
import { LedgerStorageService } from '@/modules/Ledger/LedgerStorage.service';
@Injectable()
export class ExpenseGLEntriesStorageService {
/**
* @param {ExpenseGLEntriesService} expenseGLEntries - Expense GL entries service.
* @param {LedgerStorageService} ledgerStorage - Ledger storage service.
*/
constructor(
private readonly expenseGLEntries: ExpenseGLEntriesService,
private readonly ledgerStorage: LedgerStorageService,
) {}
/**
* Writes the expense GL entries.
* @param {number} tenantId
* @param {number} expenseId
* @param {Knex.Transaction} trx
*/
public writeExpenseGLEntries = async (
expenseId: number,
trx?: Knex.Transaction,
) => {
// Retrieves the given expense ledger.
const expenseLedger = await this.expenseGLEntries.getExpenseLedgerById(
expenseId,
trx,
);
// Commits the expense ledger entries.
await this.ledgerStorage.commit(expenseLedger, trx);
};
/**
* Reverts the given expense GL entries.
* @param {number} tenantId
* @param {number} expenseId
* @param {Knex.Transaction} trx
*/
public revertExpenseGLEntries = async (
expenseId: number,
trx?: Knex.Transaction,
) => {
await this.ledgerStorage.deleteByReference(
expenseId,
'Expense',
trx,
);
};
/**
* Rewrites the expense GL entries.
* @param {number} expenseId
* @param {Knex.Transaction} trx
*/
public rewriteExpenseGLEntries = async (
expenseId: number,
trx?: Knex.Transaction,
) => {
// Reverts the expense GL entries.
await this.revertExpenseGLEntries(expenseId, trx);
// Writes the expense GL entries.
await this.writeExpenseGLEntries(expenseId, trx);
};
}

View File

@@ -1,67 +0,0 @@
// import { Knex } from 'knex';
// import { ExpenseGLEntries } from './ExpenseGLEntries.service';
// import { Injectable } from '@nestjs/common';
// @Injectable()
// export class ExpenseGLEntriesStorage {
// /**
// * @param {ExpenseGLEntries} expenseGLEntries
// * @param {LedgerStorageService} ledgerStorage
// */
// constructor(
// private readonly expenseGLEntries: ExpenseGLEntries,
// private readonly ledgerStorage: LedgerStorageService,
// ) {}
// /**
// * Writes the expense GL entries.
// * @param {number} tenantId
// * @param {number} expenseId
// * @param {Knex.Transaction} trx
// */
// public writeExpenseGLEntries = async (
// expenseId: number,
// trx?: Knex.Transaction,
// ) => {
// // Retrieves the given expense ledger.
// const expenseLedger = await this.expenseGLEntries.getExpenseLedgerById(
// expenseId,
// trx,
// );
// // Commits the expense ledger entries.
// await this.ledgerStorage.commit(expenseLedger, trx);
// };
// /**
// * Reverts the given expense GL entries.
// * @param {number} tenantId
// * @param {number} expenseId
// * @param {Knex.Transaction} trx
// */
// public revertExpenseGLEntries = async (
// expenseId: number,
// trx?: Knex.Transaction,
// ) => {
// await this.ledgerStorage.deleteByReference(
// expenseId,
// 'Expense',
// trx,
// );
// };
// /**
// * Rewrites the expense GL entries.
// * @param {number} expenseId
// * @param {Knex.Transaction} trx
// */
// public rewriteExpenseGLEntries = async (
// expenseId: number,
// trx?: Knex.Transaction,
// ) => {
// // Reverts the expense GL entries.
// await this.revertExpenseGLEntries(expenseId, trx);
// // Writes the expense GL entries.
// await this.writeExpenseGLEntries(expenseId, trx);
// };
// }