feat(nestjs): migrate to NestJS

This commit is contained in:
Ahmed Bouhuolia
2025-04-07 11:51:24 +02:00
parent f068218a16
commit 55fcc908ef
3779 changed files with 631 additions and 195332 deletions

View File

@@ -0,0 +1,211 @@
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 { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
import { Ledger } from '@/modules/Ledger/Ledger';
import { SaleInvoice } from '../models/SaleInvoice';
export class InvoiceGL {
private saleInvoice: SaleInvoice;
private ARAccountId: number;
private taxPayableAccountId: number;
private discountAccountId: number;
private otherChargesAccountId: number;
/**
* Constructor method.
* @param {SaleInvoice} saleInvoice - Sale invoice.
*/
constructor(saleInvoice: SaleInvoice) {
this.saleInvoice = saleInvoice;
}
/**
* Set the receivable account id.
* @param {number} ARAccountId - Receivable account id.
*/
setARAccountId(ARAccountId: number) {
this.ARAccountId = ARAccountId;
}
/**
* Set the tax payable account id.
* @param {number} taxPayableAccountId - Tax payable account id.
*/
setTaxPayableAccountId(taxPayableAccountId: number) {
this.taxPayableAccountId = taxPayableAccountId;
}
/**
* Set the discount account id.
* @param {number} discountAccountId - Discount account id.
*/
setDiscountAccountId(discountAccountId: number) {
this.discountAccountId = discountAccountId;
}
/**
* Set the other charges account id.
* @param {number} otherChargesAccountId - Other charges account id.
*/
setOtherChargesAccountId(otherChargesAccountId: number) {
this.otherChargesAccountId = otherChargesAccountId;
}
/**
* Retrieves the invoice GL common entry.
*/
private get invoiceGLCommonEntry() {
return {
credit: 0,
debit: 0,
currencyCode: this.saleInvoice.currencyCode,
exchangeRate: this.saleInvoice.exchangeRate,
transactionType: 'SaleInvoice',
transactionId: this.saleInvoice.id,
date: this.saleInvoice.invoiceDate,
userId: this.saleInvoice.userId,
transactionNumber: this.saleInvoice.invoiceNo,
referenceNumber: this.saleInvoice.referenceNo,
createdAt: this.saleInvoice.createdAt,
indexGroup: 10,
branchId: this.saleInvoice.branchId,
};
}
/**
* Retrieve receivable entry of the invoice.
* @returns {ILedgerEntry}
*/
public get invoiceReceivableEntry(): ILedgerEntry {
const commonEntry = this.invoiceGLCommonEntry;
return {
...commonEntry,
debit: this.saleInvoice.totalLocal,
accountId: this.ARAccountId,
contactId: this.saleInvoice.customerId,
accountNormal: AccountNormal.DEBIT,
index: 1,
};
}
/**
* Retrieve item income entry of the invoice.
* @param {ItemEntry} entry - Item entry.
* @param {number} index - Index.
* @returns {ILedgerEntry}
*/
private getInvoiceItemEntry = R.curry(
(entry: ItemEntry, index: number): ILedgerEntry => {
const commonEntry = this.invoiceGLCommonEntry;
const localAmount =
entry.totalExcludingTax * this.saleInvoice.exchangeRate;
return {
...commonEntry,
credit: localAmount,
accountId: entry.sellAccountId,
note: entry.description,
index: index + 2,
itemId: entry.itemId,
accountNormal: AccountNormal.CREDIT,
taxRateId: entry.taxRateId,
taxRate: entry.taxRate,
};
},
);
/**
* Retreives the GL entry of tax payable.
* @param {ItemEntry} entry - Item entry.
* @param {number} index - Index.
* @returns {ILedgerEntry}
*/
private getInvoiceTaxEntry(entry: ItemEntry, index: number): ILedgerEntry {
const commonEntry = this.invoiceGLCommonEntry;
return {
...commonEntry,
credit: entry.taxAmount,
accountId: this.taxPayableAccountId,
index: index + 1,
indexGroup: 30,
accountNormal: AccountNormal.CREDIT,
taxRateId: entry.taxRateId,
taxRate: entry.taxRate,
};
}
/**
* Retrieves the invoice discount GL entry.
* @returns {ILedgerEntry}
*/
private get invoiceDiscountEntry(): ILedgerEntry {
const commonEntry = this.invoiceGLCommonEntry;
return {
...commonEntry,
debit: this.saleInvoice.discountAmountLocal,
accountId: this.discountAccountId,
accountNormal: AccountNormal.CREDIT,
index: 1,
} as ILedgerEntry;
};
/**
* Retrieves the invoice adjustment GL entry.
* @returns {ILedgerEntry}
*/
private get adjustmentEntry(): ILedgerEntry {
const commonEntry = this.invoiceGLCommonEntry;
const adjustmentAmount = Math.abs(this.saleInvoice.adjustmentLocal);
return {
...commonEntry,
debit: this.saleInvoice.adjustmentLocal < 0 ? adjustmentAmount : 0,
credit: this.saleInvoice.adjustmentLocal > 0 ? adjustmentAmount : 0,
accountId: this.otherChargesAccountId,
accountNormal: AccountNormal.CREDIT,
index: 1,
};
};
/**
* Retrieves the invoice GL entries.
* @returns {ILedgerEntry[]}
*/
public getInvoiceGLEntries = (): ILedgerEntry[] => {
const creditEntries = this.saleInvoice.entries.map(
(entry, index) => this.getInvoiceItemEntry(entry, index),
);
const taxEntries = this.saleInvoice.entries
.filter((entry) => entry.taxAmount > 0)
.map((entry, index) => this.getInvoiceTaxEntry(entry, index));
return [
this.invoiceReceivableEntry,
...creditEntries,
...taxEntries,
this.invoiceDiscountEntry,
this.adjustmentEntry,
];
};
/**
* Retrieves the invoice ledger.
* @returns {ILedger}
*/
public getInvoiceLedger = (): ILedger => {
const entries = this.getInvoiceGLEntries();
return new Ledger(entries);
};
}

View File

@@ -0,0 +1,96 @@
import { Knex } from 'knex';
import { Inject, Injectable } from '@nestjs/common';
import { LedgerStorageService } from '../../Ledger/LedgerStorage.service';
import { SaleInvoice } from '../models/SaleInvoice';
import { AccountRepository } from '../../Accounts/repositories/Account.repository';
import { InvoiceGL } from './InvoiceGL';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
@Injectable()
export class SaleInvoiceGLEntries {
constructor(
private readonly ledegrRepository: LedgerStorageService,
private readonly accountRepository: AccountRepository,
@Inject(SaleInvoice.name)
private readonly saleInvoiceModel: TenantModelProxy<typeof SaleInvoice>,
) {}
/**
* Writes a sale invoice GL entries.
* @param {number} saleInvoiceId - Sale invoice id.
* @param {Knex.Transaction} trx
*/
public writeInvoiceGLEntries = async (
saleInvoiceId: number,
trx?: Knex.Transaction,
) => {
const saleInvoice = await this.saleInvoiceModel()
.query(trx)
.findById(saleInvoiceId)
.withGraphFetched('entries.item');
// Find or create the A/R account.
const ARAccount =
await this.accountRepository.findOrCreateAccountReceivable(
saleInvoice.currencyCode,
{},
trx,
);
// Find or create tax payable account.
const taxPayableAccount =
await this.accountRepository.findOrCreateTaxPayable({}, trx);
// Find or create the discount expense account.
const discountAccount =
await this.accountRepository.findOrCreateDiscountAccount({}, trx);
// Find or create the other charges account.
const otherChargesAccount =
await this.accountRepository.findOrCreateOtherChargesAccount({}, trx);
// Retrieves the ledger of the invoice.
const invoiceGL = new InvoiceGL(saleInvoice);
invoiceGL.setARAccountId(ARAccount.id);
invoiceGL.setTaxPayableAccountId(taxPayableAccount.id);
invoiceGL.setDiscountAccountId(discountAccount.id);
invoiceGL.setOtherChargesAccountId(otherChargesAccount.id);
const ledger = invoiceGL.getInvoiceLedger();
// Commits the ledger entries to the storage as UOW.
await this.ledegrRepository.commit(ledger, trx);
};
/**
* Rewrites the given invoice GL entries.
* @param {number} tenantId
* @param {number} saleInvoiceId
* @param {Knex.Transaction} trx
*/
public rewritesInvoiceGLEntries = async (
saleInvoiceId: number,
trx?: Knex.Transaction,
) => {
// Reverts the invoice GL entries.
await this.revertInvoiceGLEntries(saleInvoiceId, trx);
// Writes the invoice GL entries.
await this.writeInvoiceGLEntries(saleInvoiceId, trx);
};
/**
* Reverts the given invoice GL entries.
* @param {number} saleInvoiceId - Sale invoice id.
* @param {Knex.Transaction} trx
*/
public revertInvoiceGLEntries = async (
saleInvoiceId: number,
trx?: Knex.Transaction,
) => {
await this.ledegrRepository.deleteByReference(
saleInvoiceId,
'SaleInvoice',
trx,
);
};
}