diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts index b5019ad40..a821f3708 100644 --- a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts +++ b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts @@ -35,6 +35,8 @@ import { InvoiceGLEntriesSubscriber } from './subscribers/InvoiceGLEntriesSubscr import { SaleInvoiceGLEntries } from './ledger/InvoiceGLEntries'; import { LedgerModule } from '../Ledger/Ledger.module'; import { AccountsModule } from '../Accounts/Accounts.module'; +import SaleInvoiceWriteoffSubscriber from './subscribers/SaleInvoiceWriteoffSubscriber'; +import { SaleInvoiceWriteoffGLStorage } from './commands/writeoff/SaleInvoiceWriteoffGLStorage'; @Module({ imports: [ @@ -76,6 +78,8 @@ import { AccountsModule } from '../Accounts/Accounts.module'; GetInvoicePaymentsService, SaleInvoiceGLEntries, InvoiceGLEntriesSubscriber, + SaleInvoiceWriteoffGLStorage, + SaleInvoiceWriteoffSubscriber ], }) export class SaleInvoicesModule {} diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoiceWriteoffGLEntries.ts b/packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoiceWriteoffGLEntries.ts deleted file mode 100644 index ee4ad9782..000000000 --- a/packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoiceWriteoffGLEntries.ts +++ /dev/null @@ -1,104 +0,0 @@ -// import { Service } from 'typedi'; -// import { ISaleInvoice, AccountNormal, ILedgerEntry, ILedger } from '@/interfaces'; -// import Ledger from '@/services/Accounting/Ledger'; - -// @Service() -// export class SaleInvoiceWriteoffGLEntries { -// /** -// * Retrieves the invoice write-off common GL entry. -// * @param {ISaleInvoice} saleInvoice -// */ -// private getInvoiceWriteoffGLCommonEntry = (saleInvoice: ISaleInvoice) => { -// return { -// date: saleInvoice.invoiceDate, - -// currencyCode: saleInvoice.currencyCode, -// exchangeRate: saleInvoice.exchangeRate, - -// transactionId: saleInvoice.id, -// transactionType: 'InvoiceWriteOff', -// transactionNumber: saleInvoice.invoiceNo, - -// referenceNo: saleInvoice.referenceNo, -// branchId: saleInvoice.branchId, -// }; -// }; - -// /** -// * Retrieves the invoice write-off receiveable GL entry. -// * @param {number} ARAccountId -// * @param {ISaleInvoice} saleInvoice -// * @returns {ILedgerEntry} -// */ -// private getInvoiceWriteoffGLReceivableEntry = ( -// ARAccountId: number, -// saleInvoice: ISaleInvoice -// ): ILedgerEntry => { -// const commontEntry = this.getInvoiceWriteoffGLCommonEntry(saleInvoice); - -// return { -// ...commontEntry, -// credit: saleInvoice.localWrittenoffAmount, -// accountId: ARAccountId, -// contactId: saleInvoice.customerId, -// debit: 0, -// index: 1, -// indexGroup: 300, -// accountNormal: saleInvoice.writtenoffExpenseAccount.accountNormal, -// }; -// }; - -// /** -// * Retrieves the invoice write-off expense GL entry. -// * @param {ISaleInvoice} saleInvoice -// * @returns {ILedgerEntry} -// */ -// private getInvoiceWriteoffGLExpenseEntry = ( -// saleInvoice: ISaleInvoice -// ): ILedgerEntry => { -// const commontEntry = this.getInvoiceWriteoffGLCommonEntry(saleInvoice); - -// return { -// ...commontEntry, -// debit: saleInvoice.localWrittenoffAmount, -// accountId: saleInvoice.writtenoffExpenseAccountId, -// credit: 0, -// index: 2, -// indexGroup: 300, -// accountNormal: AccountNormal.DEBIT, -// }; -// }; - -// /** -// * Retrieves the invoice write-off GL entries. -// * @param {number} ARAccountId -// * @param {ISaleInvoice} saleInvoice -// * @returns {ILedgerEntry[]} -// */ -// public getInvoiceWriteoffGLEntries = ( -// ARAccountId: number, -// saleInvoice: ISaleInvoice -// ): ILedgerEntry[] => { -// const creditEntry = this.getInvoiceWriteoffGLExpenseEntry(saleInvoice); -// const debitEntry = this.getInvoiceWriteoffGLReceivableEntry( -// ARAccountId, -// saleInvoice -// ); -// return [debitEntry, creditEntry]; -// }; - -// /** -// * Retrieves the invoice write-off ledger. -// * @param {number} ARAccountId -// * @param {ISaleInvoice} saleInvoice -// * @returns {Ledger} -// */ -// public getInvoiceWriteoffLedger = ( -// ARAccountId: number, -// saleInvoice: ISaleInvoice -// ): ILedger => { -// const entries = this.getInvoiceWriteoffGLEntries(ARAccountId, saleInvoice); - -// return new Ledger(entries); -// }; -// } diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoiceWriteoffGLStorage.ts b/packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoiceWriteoffGLStorage.ts deleted file mode 100644 index 581cc8e26..000000000 --- a/packages/server-nest/src/modules/SaleInvoices/commands/SaleInvoiceWriteoffGLStorage.ts +++ /dev/null @@ -1,88 +0,0 @@ -// import { Knex } from 'knex'; -// import LedgerStorageService from '@/services/Accounting/LedgerStorageService'; -// import HasTenancyService from '@/services/Tenancy/TenancyService'; -// import { Service, Inject } from 'typedi'; -// import { SaleInvoiceWriteoffGLEntries } from './SaleInvoiceWriteoffGLEntries'; - -// @Service() -// export class SaleInvoiceWriteoffGLStorage { -// @Inject() -// private invoiceWriteoffLedger: SaleInvoiceWriteoffGLEntries; - -// @Inject() -// private ledgerStorage: LedgerStorageService; - -// @Inject() -// private tenancy: HasTenancyService; - -// /** -// * Writes the invoice write-off GL entries. -// * @param {number} tenantId -// * @param {number} saleInvoiceId -// * @param {Knex.Transaction} trx -// * @returns {Promise} -// */ -// public writeInvoiceWriteoffEntries = async ( -// tenantId: number, -// saleInvoiceId: number, -// trx?: Knex.Transaction -// ) => { -// const { SaleInvoice } = this.tenancy.models(tenantId); -// const { accountRepository } = this.tenancy.repositories(tenantId); - -// // Retrieves the sale invoice. -// const saleInvoice = await SaleInvoice.query(trx) -// .findById(saleInvoiceId) -// .withGraphFetched('writtenoffExpenseAccount'); - -// // Find or create the A/R account. -// const ARAccount = await accountRepository.findOrCreateAccountReceivable( -// saleInvoice.currencyCode, -// {}, -// trx -// ); -// // Retrieves the invoice write-off ledger. -// const ledger = this.invoiceWriteoffLedger.getInvoiceWriteoffLedger( -// ARAccount.id, -// saleInvoice -// ); -// return this.ledgerStorage.commit(tenantId, ledger, trx); -// }; - -// /** -// * Rewrites the invoice write-off GL entries. -// * @param {number} tenantId -// * @param {number} saleInvoiceId -// * @param {Knex.Transactio} actiontrx -// * @returns {Promise} -// */ -// public rewriteInvoiceWriteoffEntries = async ( -// tenantId: number, -// saleInvoiceId: number, -// trx?: Knex.Transaction -// ) => { -// await this.revertInvoiceWriteoffEntries(tenantId, saleInvoiceId, trx); - -// await this.writeInvoiceWriteoffEntries(tenantId, saleInvoiceId, trx); -// }; - -// /** -// * Reverts the invoice write-off GL entries. -// * @param {number} tenantId -// * @param {number} saleInvoiceId -// * @param {Knex.Transaction} trx -// * @returns {Promise} -// */ -// public revertInvoiceWriteoffEntries = async ( -// tenantId: number, -// saleInvoiceId: number, -// trx?: Knex.Transaction -// ) => { -// await this.ledgerStorage.deleteByReference( -// tenantId, -// saleInvoiceId, -// 'InvoiceWriteOff', -// trx -// ); -// }; -// } diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/writeoff/SaleInvoiceWriteoffGL.ts b/packages/server-nest/src/modules/SaleInvoices/commands/writeoff/SaleInvoiceWriteoffGL.ts new file mode 100644 index 000000000..1cba043d2 --- /dev/null +++ b/packages/server-nest/src/modules/SaleInvoices/commands/writeoff/SaleInvoiceWriteoffGL.ts @@ -0,0 +1,111 @@ +import { SaleInvoice } from '../../models/SaleInvoice'; +import { ILedger } from '@/modules/Ledger/types/Ledger.types'; +import { ILedgerEntry } from '@/modules/Ledger/types/Ledger.types'; +import { AccountNormal } from '@/interfaces/Account'; +import { Ledger } from '@/modules/Ledger/Ledger'; + +export class SaleInvoiceWriteoffGL { + private saleInvoiceModel: SaleInvoice; + private ARAccountId: number; + + /** + * Sets the sale invoice model. + * @param {SaleInvoice} saleInvoiceModel - + */ + constructor(saleInvoiceModel: SaleInvoice) { + this.saleInvoiceModel = saleInvoiceModel; + } + + /** + * Sets the A/R account ID. + * @param {number} ARAccountId - + */ + setARAccountId(ARAccountId: number) { + this.ARAccountId = ARAccountId; + return this; + } + + /** + * Retrieves the invoice write-off common GL entry. + * @param {ISaleInvoice} saleInvoice + */ + private get invoiceWriteoffGLCommonEntry() { + return { + date: this.saleInvoiceModel.invoiceDate, + + currencyCode: this.saleInvoiceModel.currencyCode, + exchangeRate: this.saleInvoiceModel.exchangeRate, + + transactionId: this.saleInvoiceModel.id, + transactionType: 'InvoiceWriteOff', + transactionNumber: this.saleInvoiceModel.invoiceNo, + + referenceNo: this.saleInvoiceModel.referenceNo, + branchId: this.saleInvoiceModel.branchId, + }; + } + + /** + * Retrieves the invoice write-off receiveable GL entry. + * @param {number} ARAccountId + * @param {ISaleInvoice} saleInvoice + * @returns {ILedgerEntry} + */ + private get invoiceWriteoffGLReceivableEntry(): ILedgerEntry { + const commontEntry = this.invoiceWriteoffGLCommonEntry; + + return { + ...commontEntry, + credit: this.saleInvoiceModel.localWrittenoffAmount, + accountId: this.ARAccountId, + contactId: this.saleInvoiceModel.customerId, + debit: 0, + index: 1, + indexGroup: 300, + accountNormal: + this.saleInvoiceModel.writtenoffExpenseAccount.accountNormal, + }; + } + + /** + * Retrieves the invoice write-off expense GL entry. + * @param {ISaleInvoice} saleInvoice + * @returns {ILedgerEntry} + */ + private get invoiceWriteoffGLExpenseEntry(): ILedgerEntry { + const commontEntry = this.invoiceWriteoffGLCommonEntry; + + return { + ...commontEntry, + debit: this.saleInvoiceModel.writtenoffAmount, + accountId: this.saleInvoiceModel.writtenoffExpenseAccountId, + credit: 0, + index: 2, + indexGroup: 300, + accountNormal: AccountNormal.DEBIT, + }; + } + + /** + * Retrieves the invoice write-off GL entries. + * @returns {ILedgerEntry[]} + */ + public getInvoiceWriteoffGLEntries(): ILedgerEntry[] { + const creditEntry = this.invoiceWriteoffGLExpenseEntry; + const debitEntry = this.invoiceWriteoffGLReceivableEntry; + + return [debitEntry, creditEntry]; + } + + /** + * Retrieves the invoice write-off ledger. + * @param {number} ARAccountId + * @param {ISaleInvoice} saleInvoice + * @returns {Ledger} + */ + public getInvoiceWriteoffLedger(): ILedger { + const entries = this.getInvoiceWriteoffGLEntries(); + + return new Ledger(entries); + } +} diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/writeoff/SaleInvoiceWriteoffGLStorage.ts b/packages/server-nest/src/modules/SaleInvoices/commands/writeoff/SaleInvoiceWriteoffGLStorage.ts new file mode 100644 index 000000000..31eb964da --- /dev/null +++ b/packages/server-nest/src/modules/SaleInvoices/commands/writeoff/SaleInvoiceWriteoffGLStorage.ts @@ -0,0 +1,87 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { Account } from '@/modules/Accounts/models/Account.model'; +import { AccountRepository } from '@/modules/Accounts/repositories/Account.repository'; +import { LedgerStorageService } from '@/modules/Ledger/LedgerStorage.service'; +import { SaleInvoice } from '../../models/SaleInvoice'; +import { SaleInvoiceWriteoffGL } from './SaleInvoiceWriteoffGL'; + +@Injectable() +export class SaleInvoiceWriteoffGLStorage { + /** + * @param {LedgerStorageService} ledgerStorage - Ledger storage service. + * @param {AccountRepository} accountRepository - Account repository. + * @param {Account} accountModel - Account model. + * @param {SaleInvoice} saleInvoiceModel - Sale invoice model. + */ + constructor( + private readonly ledgerStorage: LedgerStorageService, + private readonly accountRepository: AccountRepository, + + @Inject(Account.name) private readonly accountModel: typeof Account, + @Inject(SaleInvoice.name) + private readonly saleInvoiceModel: typeof SaleInvoice, + ) {} + + /** + * Writes the invoice write-off GL entries. + * @param {number} saleInvoiceId - Sale invoice id. + * @param {Knex.Transaction} trx - Knex transaction. + * @returns {Promise} + */ + public async writeInvoiceWriteoffEntries( + saleInvoiceId: number, + trx?: Knex.Transaction, + ) { + // Retrieves the sale invoice. + const saleInvoice = await this.saleInvoiceModel + .query(trx) + .findById(saleInvoiceId) + .withGraphFetched('writtenoffExpenseAccount'); + + // Find or create the A/R account. + const ARAccount = + await this.accountRepository.findOrCreateAccountReceivable( + saleInvoice.currencyCode, + {}, + trx, + ); + const ledger = new SaleInvoiceWriteoffGL(saleInvoice) + .setARAccountId(ARAccount.id) + .getInvoiceWriteoffLedger(); + + return this.ledgerStorage.commit(ledger, trx); + } + + /** + * Rewrites the invoice write-off GL entries. + * @param {number} saleInvoiceId - Sale invoice id. + * @param {Knex.Transaction} trx - Knex transaction. + * @returns {Promise} + */ + public async rewriteInvoiceWriteoffEntries( + saleInvoiceId: number, + trx?: Knex.Transaction, + ) { + await this.revertInvoiceWriteoffEntries(saleInvoiceId, trx); + + await this.writeInvoiceWriteoffEntries(saleInvoiceId, trx); + } + + /** + * Reverts the invoice write-off GL entries. + * @param {number} saleInvoiceId - Sale invoice id. + * @param {Knex.Transaction} trx - Knex transaction. + * @returns {Promise} + */ + public revertInvoiceWriteoffEntries = async ( + saleInvoiceId: number, + trx?: Knex.Transaction, + ) => { + await this.ledgerStorage.deleteByReference( + saleInvoiceId, + 'InvoiceWriteOff', + trx, + ); + }; +} diff --git a/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts b/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts index 8fa493c54..78fbce8f1 100644 --- a/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts +++ b/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts @@ -15,6 +15,7 @@ import { TaxRateTransaction } from '@/modules/TaxRates/models/TaxRateTransaction import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry'; import { Document } from '@/modules/ChromiumlyTenancy/models/Document'; import { DiscountType } from '@/common/types/Discount'; +import { Account } from '@/modules/Accounts/models/Account.model'; export class SaleInvoice extends BaseModel { public taxAmountWithheld: number; @@ -51,9 +52,10 @@ export class SaleInvoice extends BaseModel { public branchId: number; public warehouseId: number; - public taxes: TaxRateTransaction[]; - public entries: ItemEntry[]; - public attachments: Document[]; + public taxes!: TaxRateTransaction[]; + public entries!: ItemEntry[]; + public attachments!: Document[]; + public writtenoffExpenseAccount!: Account; /** * Table name diff --git a/packages/server-nest/src/modules/SaleInvoices/subscribers/SaleInvoiceWriteoffSubscriber.ts b/packages/server-nest/src/modules/SaleInvoices/subscribers/SaleInvoiceWriteoffSubscriber.ts index d42855c1b..ee48546f6 100644 --- a/packages/server-nest/src/modules/SaleInvoices/subscribers/SaleInvoiceWriteoffSubscriber.ts +++ b/packages/server-nest/src/modules/SaleInvoices/subscribers/SaleInvoiceWriteoffSubscriber.ts @@ -1,58 +1,37 @@ -// import { Inject, Service } from 'typedi'; -// import events from '@/subscribers/events'; -// import { -// ISaleInvoiceWriteoffCreatePayload, -// ISaleInvoiceWrittenOffCanceledPayload, -// } from '@/interfaces'; -// import { SaleInvoiceWriteoffGLStorage } from './SaleInvoiceWriteoffGLStorage'; +import { Injectable } from '@nestjs/common'; +import { OnEvent } from '@nestjs/event-emitter'; +import { + ISaleInvoiceWriteoffCreatePayload, + ISaleInvoiceWrittenOffCanceledPayload, +} from '../SaleInvoice.types'; +import { SaleInvoiceWriteoffGLStorage } from '../commands/writeoff/SaleInvoiceWriteoffGLStorage'; +import { events } from '@/common/events/events'; -// @Service() -// export default class SaleInvoiceWriteoffSubscriber { -// @Inject() -// writeGLStorage: SaleInvoiceWriteoffGLStorage; +@Injectable() +export default class SaleInvoiceWriteoffSubscriber { + constructor(private readonly writeGLStorage: SaleInvoiceWriteoffGLStorage) {} -// /** -// * Attaches events. -// */ -// public attach(bus) { -// bus.subscribe( -// events.saleInvoice.onWrittenoff, -// this.writeJournalEntriesOnceWriteoffCreate -// ); -// bus.subscribe( -// events.saleInvoice.onWrittenoffCanceled, -// this.revertJournalEntriesOnce -// ); -// } -// /** -// * Write the written-off sale invoice journal entries. -// * @param {ISaleInvoiceWriteoffCreatePayload} -// */ -// private writeJournalEntriesOnceWriteoffCreate = async ({ -// tenantId, -// saleInvoice, -// trx, -// }: ISaleInvoiceWriteoffCreatePayload) => { -// await this.writeGLStorage.writeInvoiceWriteoffEntries( -// tenantId, -// saleInvoice.id, -// trx -// ); -// }; + /** + * Write the written-off sale invoice journal entries. + * @param {ISaleInvoiceWriteoffCreatePayload} + */ + @OnEvent(events.saleInvoice.onWrittenoff) + public async writeJournalEntriesOnceWriteoffCreate({ + saleInvoice, + trx, + }: ISaleInvoiceWriteoffCreatePayload) { + await this.writeGLStorage.writeInvoiceWriteoffEntries(saleInvoice.id, trx); + } -// /** -// * Reverts the written-of sale invoice jounral entries. -// * @param {ISaleInvoiceWrittenOffCanceledPayload} -// */ -// private revertJournalEntriesOnce = async ({ -// tenantId, -// saleInvoice, -// trx, -// }: ISaleInvoiceWrittenOffCanceledPayload) => { -// await this.writeGLStorage.revertInvoiceWriteoffEntries( -// tenantId, -// saleInvoice.id, -// trx -// ); -// }; -// } + /** + * Reverts the written-of sale invoice jounral entries. + * @param {ISaleInvoiceWrittenOffCanceledPayload} + */ + @OnEvent(events.saleInvoice.onWrittenoffCanceled) + public async revertJournalEntriesOnce({ + saleInvoice, + trx, + }: ISaleInvoiceWrittenOffCanceledPayload) { + await this.writeGLStorage.revertInvoiceWriteoffEntries(saleInvoice.id, trx); + } +}