refactor: migrate ledger subscribers to nestjs

This commit is contained in:
Ahmed Bouhuolia
2024-12-31 23:51:24 +02:00
parent a819d6c1ba
commit 3ad34ba56f
21 changed files with 779 additions and 611 deletions

View File

@@ -18,8 +18,8 @@ import { TemplateInjectableModule } from '../TemplateInjectable/TemplateInjectab
import { GetCreditNote } from './queries/GetCreditNote.service';
import { CreditNoteBrandingTemplate } from './queries/CreditNoteBrandingTemplate.service';
import { AutoIncrementOrdersModule } from '../AutoIncrementOrders/AutoIncrementOrders.module';
import CreditNoteGLEntries from './commands/CreditNoteGLEntries';
import CreditNoteGLEntriesSubscriber from './subscribers/CreditNoteGLEntriesSubscriber';
import { CreditNoteGLEntries } from './commands/CreditNoteGLEntries';
import { CreditNoteGLEntriesSubscriber } from './subscribers/CreditNoteGLEntriesSubscriber';
@Module({
imports: [
@@ -29,7 +29,7 @@ import CreditNoteGLEntriesSubscriber from './subscribers/CreditNoteGLEntriesSubs
PdfTemplatesModule,
ChromiumlyTenancyModule,
TemplateInjectableModule,
AutoIncrementOrdersModule
AutoIncrementOrdersModule,
],
providers: [
CreateCreditNoteService,
@@ -44,12 +44,12 @@ import CreditNoteGLEntriesSubscriber from './subscribers/CreditNoteGLEntriesSubs
CreditNoteApplication,
CreditNoteBrandingTemplate,
CreditNoteGLEntries,
CreditNoteGLEntriesSubscriber
CreditNoteGLEntriesSubscriber,
],
exports: [
CreateCreditNoteService,
GetCreditNote,
CommandCreditNoteDTOTransform,
CommandCreditNoteDTOTransform,
EditCreditNoteService,
OpenCreditNoteService,
DeleteCreditNoteService,
@@ -57,7 +57,7 @@ import CreditNoteGLEntriesSubscriber from './subscribers/CreditNoteGLEntriesSubs
CreditNoteAutoIncrementService,
GetCreditNoteState,
CreditNoteApplication,
CreditNoteBrandingTemplate
CreditNoteBrandingTemplate,
],
controllers: [CreditNotesController],
})

View File

@@ -0,0 +1,186 @@
import { ILedgerEntry } from '@/modules/Ledger/types/Ledger.types';
import { CreditNote } from '../models/CreditNote';
import { AccountNormal } from '@/interfaces/Account';
import { Ledger } from '@/modules/Ledger/Ledger';
import { ItemEntry } from '@/modules/Items/models/ItemEntry';
export class CreditNoteGL {
creditNoteModel: CreditNote;
ARAccountId: number;
discountAccountId: number;
adjustmentAccountId: number;
/**
* @param {CreditNote} creditNoteModel - Credit note model.
*/
constructor(creditNoteModel: CreditNote) {
this.creditNoteModel = creditNoteModel;
}
/**
* Sets the A/R account id.
* @param {number} ARAccountId - A/R account id.
*/
public setARAccountId(ARAccountId: number) {
this.ARAccountId = ARAccountId;
return this;
}
/**
* Sets the discount account id.
* @param {number} discountAccountId - Discount account id.
*/
public setDiscountAccountId(discountAccountId: number) {
this.discountAccountId = discountAccountId;
return this;
}
/**
* Sets the adjustment account id.
* @param {number} adjustmentAccountId - Adjustment account id.
*/
public setAdjustmentAccountId(adjustmentAccountId: number) {
this.adjustmentAccountId = adjustmentAccountId;
return this;
}
/**
* Retrieve the credit note common entry.
* @returns {ICreditNoteGLCommonEntry}
*/
private get creditNoteCommonEntry() {
return {
date: this.creditNoteModel.creditNoteDate,
userId: this.creditNoteModel.userId,
currencyCode: this.creditNoteModel.currencyCode,
exchangeRate: this.creditNoteModel.exchangeRate,
transactionType: 'CreditNote',
transactionId: this.creditNoteModel.id,
transactionNumber: this.creditNoteModel.creditNoteNumber,
referenceNumber: this.creditNoteModel.referenceNo,
createdAt: this.creditNoteModel.createdAt,
indexGroup: 10,
credit: 0,
debit: 0,
branchId: this.creditNoteModel.branchId,
};
}
/**
* Retrieves the creidt note A/R entry.
* @param {ICreditNote} creditNote -
* @param {number} ARAccountId -
* @returns {ILedgerEntry}
*/
private get creditNoteAREntry() {
const commonEntry = this.creditNoteCommonEntry;
return {
...commonEntry,
credit: this.creditNoteModel.totalLocal,
accountId: this.ARAccountId,
contactId: this.creditNoteModel.customerId,
index: 1,
accountNormal: AccountNormal.DEBIT,
};
}
/**
* Retrieve the credit note item entry.
* @param {ItemEntry} entry
* @param {number} index
* @returns {ILedgerEntry}
*/
private getCreditNoteItemEntry(
entry: ItemEntry,
index: number,
): ILedgerEntry {
const commonEntry = this.creditNoteCommonEntry;
const totalLocal =
entry.totalExcludingTax * this.creditNoteModel.exchangeRate;
return {
...commonEntry,
debit: totalLocal,
accountId: entry.sellAccountId || entry.item.sellAccountId,
note: entry.description,
index: index + 2,
itemId: entry.itemId,
itemQuantity: entry.quantity,
accountNormal: AccountNormal.CREDIT,
};
}
/**
* Retrieves the credit note discount entry.
* @param {ICreditNote} creditNote
* @param {number} discountAccountId
* @returns {ILedgerEntry}
*/
private get discountEntry(): ILedgerEntry {
const commonEntry = this.creditNoteCommonEntry;
return {
...commonEntry,
credit: this.creditNoteModel.discountAmountLocal,
accountId: this.discountAccountId,
accountNormal: AccountNormal.CREDIT,
index: 1,
};
}
/**
* Retrieves the credit note adjustment entry.
* @param {ICreditNote} creditNote
* @param {number} adjustmentAccountId
* @returns {ILedgerEntry}
*/
private get adjustmentEntry(): ILedgerEntry {
const commonEntry = this.creditNoteCommonEntry;
const adjustmentAmount = Math.abs(this.creditNoteModel.adjustmentLocal);
return {
...commonEntry,
credit: this.creditNoteModel.adjustmentLocal < 0 ? adjustmentAmount : 0,
debit: this.creditNoteModel.adjustmentLocal > 0 ? adjustmentAmount : 0,
accountId: this.adjustmentAccountId,
accountNormal: AccountNormal.CREDIT,
index: 1,
};
}
/**
* Retrieve the credit note GL entries.
* @param {ICreditNote} creditNote - Credit note.
* @param {IAccount} receivableAccount - Receviable account.
* @returns {ILedgerEntry[]} - Ledger entries.
*/
public getCreditNoteGLEntries(): ILedgerEntry[] {
const AREntry = this.creditNoteAREntry;
const getItemEntry = this.getCreditNoteItemEntry;
const itemsEntries = this.creditNoteModel.entries.map(getItemEntry);
const discountEntry = this.discountEntry;
const adjustmentEntry = this.adjustmentEntry;
return [AREntry, discountEntry, adjustmentEntry, ...itemsEntries];
}
/**
* Retrieves the credit note GL.
* @param {ICreditNote} creditNote
* @param {number} receivableAccount
* @returns {Ledger}
*/
public getCreditNoteLedger(): Ledger {
const ledgerEntries = this.getCreditNoteGLEntries();
return new Ledger(ledgerEntries);
}
}

View File

@@ -1,137 +1,75 @@
import { Inject, Service } from 'typedi';
import { Knex } from 'knex';
import * as R from 'ramda';
import {
AccountNormal,
IItemEntry,
ILedgerEntry,
ICreditNote,
ILedger,
ICreditNoteGLCommonEntry,
} from '@/interfaces';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import Ledger from '@/services/Accounting/Ledger';
import LedgerStorageService from '@/services/Accounting/LedgerStorageService';
import { SaleReceipt } from '@/models';
import { CreditNoteGL } from './CreditNoteGL';
import { Inject, Injectable } from '@nestjs/common';
import { LedgerStorageService } from '@/modules/Ledger/LedgerStorage.service';
import { CreditNote } from '../models/CreditNote';
import { AccountRepository } from '@/modules/Accounts/repositories/Account.repository';
@Service()
export default class CreditNoteGLEntries {
@Inject()
private tenancy: HasTenancyService;
@Injectable()
export class CreditNoteGLEntries {
constructor(
private readonly ledgerStorage: LedgerStorageService,
private readonly accountRepository: AccountRepository,
@Inject()
private ledgerStorage: LedgerStorageService;
/**
* Retrieves the credit note GL.
* @param {ICreditNote} creditNote
* @param {number} receivableAccount
* @returns {Ledger}
*/
private getCreditNoteGLedger = (
creditNote: ICreditNote,
receivableAccount: number,
discountAccount: number,
adjustmentAccount: number
): Ledger => {
const ledgerEntries = this.getCreditNoteGLEntries(
creditNote,
receivableAccount,
discountAccount,
adjustmentAccount
);
return new Ledger(ledgerEntries);
};
/**
* Saves credit note GL entries.
* @param {number} tenantId -
* @param {ICreditNote} creditNote - Credit note model.
* @param {number} payableAccount - Payable account id.
* @param {Knex.Transaction} trx
*/
public saveCreditNoteGLEntries = async (
tenantId: number,
creditNote: ICreditNote,
payableAccount: number,
discountAccount: number,
adjustmentAccount: number,
trx?: Knex.Transaction
): Promise<void> => {
const ledger = this.getCreditNoteGLedger(
creditNote,
payableAccount,
discountAccount,
adjustmentAccount
);
await this.ledgerStorage.commit(tenantId, ledger, trx);
};
@Inject(CreditNote.name)
private readonly creditNoteModel: typeof CreditNote,
) {}
/**
* Reverts the credit note associated GL entries.
* @param {number} tenantId
* @param {number} vendorCreditId
* @param {number} creditNoteId - Credit note id.
* @param {Knex.Transaction} trx
*/
public revertVendorCreditGLEntries = async (
creditNoteId: number,
trx?: Knex.Transaction
trx?: Knex.Transaction,
): Promise<void> => {
await this.ledgerStorage.deleteByReference(
creditNoteId,
'CreditNote',
trx
);
await this.ledgerStorage.deleteByReference(creditNoteId, 'CreditNote', trx);
};
/**
* Writes vendor credit associated GL entries.
* @param {number} tenantId - Tenant id.
* @param {number} creditNoteId - Credit note id.
* @param {Knex.Transaction} trx - Knex transactions.
*/
public createVendorCreditGLEntries = async (
creditNoteId: number,
trx?: Knex.Transaction
trx?: Knex.Transaction,
): Promise<void> => {
const { CreditNote } = this.tenancy.models(tenantId);
const { accountRepository } = this.tenancy.repositories(tenantId);
// Retrieve the credit note with associated entries and items.
const creditNoteWithItems = await CreditNote.query(trx)
.findById(creditNoteId)
.withGraphFetched('entries.item');
// Retreive the the `accounts receivable` account based on the given currency.
const ARAccount = await accountRepository.findOrCreateAccountReceivable(
creditNoteWithItems.currencyCode
);
const discountAccount = await accountRepository.findOrCreateDiscountAccount(
{}
);
const ARAccount =
await this.accountRepository.findOrCreateAccountReceivable(
creditNoteWithItems.currencyCode,
);
const discountAccount =
await this.accountRepository.findOrCreateDiscountAccount({});
const adjustmentAccount =
await accountRepository.findOrCreateOtherChargesAccount({});
await this.accountRepository.findOrCreateOtherChargesAccount({});
const creditNoteLedger = new CreditNoteGL(creditNoteWithItems)
.setARAccountId(ARAccount.id)
.setDiscountAccountId(discountAccount.id)
.setAdjustmentAccountId(adjustmentAccount.id)
.getCreditNoteLedger();
// Saves the credit note GL entries.
await this.saveCreditNoteGLEntries(
tenantId,
creditNoteWithItems,
ARAccount.id,
discountAccount.id,
adjustmentAccount.id,
trx
);
await this.ledgerStorage.commit(creditNoteLedger, trx);
};
/**
* Edits vendor credit associated GL entries.
* @param {number} tenantId
* @param {number} creditNoteId
* @param {number} creditNoteId - Credit note id.
* @param {Knex.Transaction} trx
*/
public editVendorCreditGLEntries = async (
creditNoteId: number,
trx?: Knex.Transaction
trx?: Knex.Transaction,
): Promise<void> => {
// Reverts vendor credit GL entries.
await this.revertVendorCreditGLEntries(creditNoteId, trx);
@@ -139,155 +77,4 @@ export default class CreditNoteGLEntries {
// Creates vendor credit Gl entries.
await this.createVendorCreditGLEntries(creditNoteId, trx);
};
/**
* Retrieve the credit note common entry.
* @param {ICreditNote} creditNote -
* @returns {ICreditNoteGLCommonEntry}
*/
private getCreditNoteCommonEntry = (
creditNote: ICreditNote
): ICreditNoteGLCommonEntry => {
return {
date: creditNote.creditNoteDate,
userId: creditNote.userId,
currencyCode: creditNote.currencyCode,
exchangeRate: creditNote.exchangeRate,
transactionType: 'CreditNote',
transactionId: creditNote.id,
transactionNumber: creditNote.creditNoteNumber,
referenceNumber: creditNote.referenceNo,
createdAt: creditNote.createdAt,
indexGroup: 10,
credit: 0,
debit: 0,
branchId: creditNote.branchId,
};
};
/**
* Retrieves the creidt note A/R entry.
* @param {ICreditNote} creditNote -
* @param {number} ARAccountId -
* @returns {ILedgerEntry}
*/
private getCreditNoteAREntry = (
creditNote: ICreditNote,
ARAccountId: number
): ILedgerEntry => {
const commonEntry = this.getCreditNoteCommonEntry(creditNote);
return {
...commonEntry,
credit: creditNote.totalLocal,
accountId: ARAccountId,
contactId: creditNote.customerId,
index: 1,
accountNormal: AccountNormal.DEBIT,
};
};
/**
* Retrieve the credit note item entry.
* @param {ICreditNote} creditNote
* @param {IItemEntry} entry
* @param {number} index
* @returns {ILedgerEntry}
*/
private getCreditNoteItemEntry = R.curry(
(
creditNote: ICreditNote,
entry: IItemEntry,
index: number
): ILedgerEntry => {
const commonEntry = this.getCreditNoteCommonEntry(creditNote);
const totalLocal = entry.totalExcludingTax * creditNote.exchangeRate;
return {
...commonEntry,
debit: totalLocal,
accountId: entry.sellAccountId || entry.item.sellAccountId,
note: entry.description,
index: index + 2,
itemId: entry.itemId,
itemQuantity: entry.quantity,
accountNormal: AccountNormal.CREDIT,
};
}
);
/**
* Retrieves the credit note discount entry.
* @param {ICreditNote} creditNote
* @param {number} discountAccountId
* @returns {ILedgerEntry}
*/
private getDiscountEntry = (
creditNote: ICreditNote,
discountAccountId: number
): ILedgerEntry => {
const commonEntry = this.getCreditNoteCommonEntry(creditNote);
return {
...commonEntry,
credit: creditNote.discountAmountLocal,
accountId: discountAccountId,
index: 1,
accountNormal: AccountNormal.CREDIT,
};
};
/**
* Retrieves the credit note adjustment entry.
* @param {ICreditNote} creditNote
* @param {number} adjustmentAccountId
* @returns {ILedgerEntry}
*/
private getAdjustmentEntry = (
creditNote: ICreditNote,
adjustmentAccountId: number
): ILedgerEntry => {
const commonEntry = this.getCreditNoteCommonEntry(creditNote);
const adjustmentAmount = Math.abs(creditNote.adjustmentLocal);
return {
...commonEntry,
credit: creditNote.adjustmentLocal < 0 ? adjustmentAmount : 0,
debit: creditNote.adjustmentLocal > 0 ? adjustmentAmount : 0,
accountId: adjustmentAccountId,
accountNormal: AccountNormal.CREDIT,
index: 1,
};
};
/**
* Retrieve the credit note GL entries.
* @param {ICreditNote} creditNote - Credit note.
* @param {IAccount} receivableAccount - Receviable account.
* @returns {ILedgerEntry[]} - Ledger entries.
*/
public getCreditNoteGLEntries = (
creditNote: ICreditNote,
ARAccountId: number,
discountAccountId: number,
adjustmentAccountId: number
): ILedgerEntry[] => {
const AREntry = this.getCreditNoteAREntry(creditNote, ARAccountId);
const getItemEntry = this.getCreditNoteItemEntry(creditNote);
const itemsEntries = creditNote.entries.map(getItemEntry);
const discountEntry = this.getDiscountEntry(creditNote, discountAccountId);
const adjustmentEntry = this.getAdjustmentEntry(
creditNote,
adjustmentAccountId
);
return [AREntry, discountEntry, adjustmentEntry, ...itemsEntries];
};
}

View File

@@ -24,6 +24,7 @@ export class CreditNote extends BaseModel {
public invoicesAmount: number;
public creditNoteDate: Date;
public creditNoteNumber: string;
public referenceNo: string;
public currencyCode: string;
public customerId: number;

View File

@@ -4,13 +4,13 @@ import {
ICreditNoteEditedPayload,
ICreditNoteOpenedPayload,
} from '../types/CreditNotes.types';
import CreditNoteGLEntries from '../commands/CreditNoteGLEntries';
import { CreditNoteGLEntries } from '../commands/CreditNoteGLEntries';
import { OnEvent } from '@nestjs/event-emitter';
import { Injectable } from '@nestjs/common';
import { events } from '@/common/events/events';
@Injectable()
export default class CreditNoteGLEntriesSubscriber {
export class CreditNoteGLEntriesSubscriber {
constructor(private readonly creditNoteGLEntries: CreditNoteGLEntries) {}
/**