refactor: The expense G/L writer

This commit is contained in:
Ahmed Bouhuolia
2024-09-04 21:10:13 +02:00
parent 3795322a65
commit d3d2112b8a
4 changed files with 164 additions and 118 deletions

View File

@@ -0,0 +1,113 @@
import * as R from 'ramda';
import {
AccountNormal,
IExpenseCategory,
ILedger,
ILedgerEntry,
} from '@/interfaces';
import Ledger from '../Accounting/Ledger';
export class ExpenseGL {
private expense: any;
/**
* Constructor method.
*/
constructor(expense: any) {
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,
transactionType: 'Expense',
transactionId: this.expense.id,
date: this.expense.paymentDate,
userId: this.expense.userId,
debit: 0,
credit: 0,
branchId: this.expense.branchId,
};
};
/**
* Retrieves the expense GL payment entry.
* @param {IExpense} expense
* @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,
};
};
/**
* 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;
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();
const paymentEntry = this.getExpenseGLPaymentEntry();
const categoryEntries = this.expense.categories.map(getCategoryEntry);
return [paymentEntry, ...categoryEntries];
};
/**
* Retrieves the given expense ledger.
* @param {IExpense} expense
* @returns {ILedger}
*/
public getExpenseLedger = (): ILedger => {
const entries = this.getExpenseGLEntries();
console.log(entries, 'entries');
return new Ledger(entries);
};
}

View File

@@ -1,106 +0,0 @@
import * as R from 'ramda';
import { Service } from 'typedi';
import {
AccountNormal,
IExpense,
IExpenseCategory,
ILedger,
ILedgerEntry,
} from '@/interfaces';
import Ledger from '@/services/Accounting/Ledger';
@Service()
export class ExpenseGLEntries {
/**
* Retrieves the expense GL common entry.
* @param {IExpense} expense
* @returns
*/
private getExpenseGLCommonEntry = (expense: IExpense) => {
return {
currencyCode: expense.currencyCode,
exchangeRate: expense.exchangeRate,
transactionType: 'Expense',
transactionId: expense.id,
date: expense.paymentDate,
userId: expense.userId,
debit: 0,
credit: 0,
branchId: expense.branchId,
};
};
/**
* Retrieves the expense GL payment entry.
* @param {IExpense} expense
* @returns {ILedgerEntry}
*/
private getExpenseGLPaymentEntry = (expense: IExpense): ILedgerEntry => {
const commonEntry = this.getExpenseGLCommonEntry(expense);
return {
...commonEntry,
credit: expense.localAmount,
accountId: expense.paymentAccountId,
accountNormal: AccountNormal.DEBIT,
index: 1,
};
};
/**
* Retrieves the expense GL category entry.
* @param {IExpense} expense -
* @param {IExpenseCategory} expenseCategory -
* @param {number} index
* @returns {ILedgerEntry}
*/
private getExpenseGLCategoryEntry = R.curry(
(
expense: IExpense,
category: IExpenseCategory,
index: number
): ILedgerEntry => {
const commonEntry = this.getExpenseGLCommonEntry(expense);
const localAmount = category.amount * expense.exchangeRate;
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 = (expense: IExpense): ILedgerEntry[] => {
const getCategoryEntry = this.getExpenseGLCategoryEntry(expense);
const paymentEntry = this.getExpenseGLPaymentEntry(expense);
const categoryEntries = expense.categories.map(getCategoryEntry);
return [paymentEntry, ...categoryEntries];
};
/**
* Retrieves the given expense ledger.
* @param {IExpense} expense
* @returns {ILedger}
*/
public getExpenseLedger = (expense: IExpense): ILedger => {
const entries = this.getExpenseGLEntries(expense);
return new Ledger(entries);
};
}

View File

@@ -0,0 +1,45 @@
import { Knex } from 'knex';
import { Inject, Service } from 'typedi';
import { IExpense, ILedger } from '@/interfaces';
import { ExpenseGL } from './ExpenseGL';
import HasTenancyService from '../Tenancy/TenancyService';
@Service()
export class ExpenseGLEntries {
@Inject()
private tenancy: HasTenancyService;
/**
* Retrieves the expense G/L of the given id.
* @param {number} tenantId
* @param {number} expenseId
* @param {Knex.Transaction} trx
* @returns {Promise<ILedger>}
*/
public getExpenseLedgerById = async (
tenantId: number,
expenseId: number,
trx?: Knex.Transaction
): Promise<ILedger> => {
const { Expense } = await this.tenancy.models(tenantId);
const expense = await Expense.query(trx)
.findById(expenseId)
.withGraphFetched('categories')
.withGraphFetched('paymentAccount')
.throwIfNotFound();
return this.getExpenseLedger(expense);
};
/**
* Retrieves the given expense ledger.
* @param {IExpense} expense
* @returns {ILedger}
*/
public getExpenseLedger = (expense: IExpense): ILedger => {
const expenseGL = new ExpenseGL(expense);
return expenseGL.getExpenseLedger();
};
}

View File

@@ -2,7 +2,7 @@ import { Knex } from 'knex';
import { Service, Inject } from 'typedi';
import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { ExpenseGLEntries } from './ExpenseGLEntries';
import { ExpenseGLEntries } from './ExpenseGLEntriesService';
@Service()
export class ExpenseGLEntriesStorage {
@@ -12,9 +12,6 @@ export class ExpenseGLEntriesStorage {
@Inject()
private ledgerStorage: LedgerStorageService;
@Inject()
private tenancy: HasTenancyService;
/**
* Writes the expense GL entries.
* @param {number} tenantId
@@ -26,15 +23,12 @@ export class ExpenseGLEntriesStorage {
expenseId: number,
trx?: Knex.Transaction
) => {
const { Expense } = await this.tenancy.models(tenantId);
const expense = await Expense.query(trx)
.findById(expenseId)
.withGraphFetched('categories');
// Retrieves the given expense ledger.
const expenseLedger = this.expenseGLEntries.getExpenseLedger(expense);
const expenseLedger = await this.expenseGLEntries.getExpenseLedgerById(
tenantId,
expenseId,
trx
);
// Commits the expense ledger entries.
await this.ledgerStorage.commit(tenantId, expenseLedger, trx);
};