refactor: inventory adjustments to GL

This commit is contained in:
Ahmed Bouhuolia
2025-01-07 23:00:21 +02:00
parent 1773df1858
commit fdfb766587
12 changed files with 391 additions and 292 deletions

View File

@@ -17,21 +17,20 @@ import { Item } from '@/modules/Items/models/Item';
import { Account } from '@/modules/Accounts/models/Account.model';
import { BranchTransactionDTOTransformer } from '@/modules/Branches/integrations/BranchTransactionDTOTransform';
import { WarehouseTransactionDTOTransform } from '@/modules/Warehouses/Integrations/WarehouseTransactionDTOTransform';
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
export class CreateQuickInventoryAdjustmentService {
constructor(
@Inject(InventoryAdjustment.name)
private readonly inventoryAdjustmentModel: typeof InventoryAdjustment,
@Inject(InventoryAdjustmentEntry.name)
private readonly inventoryAdjustmentEntryModel: typeof InventoryAdjustmentEntry,
@Inject(Item.name)
private readonly itemModel: typeof Item,
@Inject(Account.name)
private readonly accountModel: typeof Account,
private readonly tenancyContext: TenancyContext,
private readonly eventEmitter: EventEmitter2,
private readonly uow: UnitOfWork,
private readonly warehouseDTOTransform: WarehouseTransactionDTOTransform,
@@ -43,9 +42,10 @@ export class CreateQuickInventoryAdjustmentService {
* @param {IQuickInventoryAdjustmentDTO} adjustmentDTO -
* @return {IInventoryAdjustment}
*/
private transformQuickAdjToModel(
private async transformQuickAdjToModel(
adjustmentDTO: IQuickInventoryAdjustmentDTO,
): InventoryAdjustment {
): Promise<InventoryAdjustment> {
const authorizedUser = await this.tenancyContext.getSystemUser();
const entries = [
{
index: 1,
@@ -104,7 +104,8 @@ export class CreateQuickInventoryAdjustmentService {
// Transform the DTO to inventory adjustment model.
const invAdjustmentObject =
this.transformQuickAdjToModel(quickAdjustmentDTO);
await this.transformQuickAdjToModel(quickAdjustmentDTO);
// Writes inventory adjustment transaction with associated transactions
// under unit-of-work envirment.
return this.uow.withTransaction(async (trx: Knex.Transaction) => {

View File

@@ -18,9 +18,6 @@ export class PublishInventoryAdjustmentService {
@Inject(InventoryAdjustment.name)
private readonly inventoryAdjustmentModel: typeof InventoryAdjustment,
@Inject(InventoryAdjustmentEntry.name)
private readonly inventoryAdjustmentEntryModel: typeof InventoryAdjustmentEntry,
) {}
/**

View File

@@ -0,0 +1,123 @@
import * as R from 'ramda';
import { InventoryAdjustment } from '../../models/InventoryAdjustment';
import { InventoryAdjustmentEntry } from '../../models/InventoryAdjustmentEntry';
import { ILedgerEntry } from '../../../Ledger/types/Ledger.types';
import { AccountNormal } from '@/interfaces/Account';
import { Ledger } from '../../../Ledger/Ledger';
export class InventoryAdjustmentsGL {
private inventoryAdjustment: InventoryAdjustment;
private baseCurrency: string;
constructor(inventoryAdjustmentModel: InventoryAdjustment) {
this.inventoryAdjustment = inventoryAdjustmentModel;
}
setBaseCurrency(baseCurrency: string) {
this.baseCurrency = baseCurrency;
return this;
}
/**
* Retrieves the inventory adjustment common GL entry.
* @returns {ILedgerEntry}
*/
private get adjustmentGLCommonEntry() {
return {
currencyCode: this.baseCurrency,
exchangeRate: 1,
transactionId: this.inventoryAdjustment.id,
transactionType: 'InventoryAdjustment',
referenceNumber: this.inventoryAdjustment.referenceNo,
date: this.inventoryAdjustment.date,
userId: this.inventoryAdjustment.userId,
branchId: this.inventoryAdjustment.branchId,
createdAt: this.inventoryAdjustment.createdAt,
credit: 0,
debit: 0,
};
}
/**
* Retrieve the inventory adjustment inventory GL entry.
* @param {InventoryAdjustmentEntry} entry - Inventory adjustment entry.
* @param {number} index - Entry index.
* @returns {ILedgerEntry}
*/
private getAdjustmentGLInventoryEntry = R.curry(
(entry: InventoryAdjustmentEntry, index: number): ILedgerEntry => {
const commonEntry = this.adjustmentGLCommonEntry;
const amount = entry.cost * entry.quantity;
return {
...commonEntry,
debit: amount,
accountId: entry.item.inventoryAccountId,
accountNormal: AccountNormal.DEBIT,
index,
};
},
);
/**
* Retrieves the inventory adjustment
* @param {IInventoryAdjustment} inventoryAdjustment
* @param {IInventoryAdjustmentEntry} entry
* @returns {ILedgerEntry}
*/
private getAdjustmentGLCostEntry(
entry: InventoryAdjustmentEntry,
index: number,
): ILedgerEntry {
const commonEntry = this.adjustmentGLCommonEntry;
const amount = entry.cost * entry.quantity;
return {
...commonEntry,
accountId: this.inventoryAdjustment.adjustmentAccountId,
accountNormal: AccountNormal.DEBIT,
credit: amount,
index: index + 2,
};
}
/**
* Retrieve the inventory adjustment GL item entry.
* @param {InventoryAdjustmentEntry} entry - Inventory adjustment entry.
* @param {number} index - Entry index.
* @returns {ILedgerEntry[]}
*/
private getAdjustmentGLItemEntry(
entry: InventoryAdjustmentEntry,
index: number,
): ILedgerEntry[] {
const getInventoryEntry = this.getAdjustmentGLInventoryEntry();
const inventoryEntry = getInventoryEntry(entry, index);
const costEntry = this.getAdjustmentGLCostEntry(entry, index);
return [inventoryEntry, costEntry];
}
/**
* Writes increment inventroy adjustment GL entries.
* @param {InventoryAdjustment} inventoryAdjustment -
* @param {JournalPoster} jorunal -
* @returns {ILedgerEntry[]}
*/
public getIncrementAdjustmentGLEntries(): ILedgerEntry[] {
return this.inventoryAdjustment.entries
.map((entry, index) => this.getAdjustmentGLItemEntry(entry, index))
.flat();
}
public getAdjustmentGL(): Ledger {
const entries = this.getIncrementAdjustmentGLEntries();
return new Ledger(entries);
}
}

View File

@@ -0,0 +1,75 @@
import { Knex } from 'knex';
import { Inject } from '@nestjs/common';
import { LedgerStorageService } from '../../../Ledger/LedgerStorage.service';
import { InventoryAdjustment } from '../../models/InventoryAdjustment';
import { TenancyContext } from '../../../Tenancy/TenancyContext.service';
import { InventoryAdjustmentsGL } from './InventoryAdjustmentGL';
export class InventoryAdjustmentsGLEntries {
constructor(
private readonly ledgerStorage: LedgerStorageService,
private readonly tenancyContext: TenancyContext,
@Inject(InventoryAdjustment.name)
private readonly inventoryAdjustment: typeof InventoryAdjustment,
) {}
/**
* Writes inventory increment adjustment GL entries.
* @param {number} inventoryAdjustmentId - Inventory adjustment ID.
* @param {Knex.Transaction} trx - Knex transaction.
*/
public writeAdjustmentGLEntries = async (
inventoryAdjustmentId: number,
trx?: Knex.Transaction,
): Promise<void> => {
// Retrieves the inventory adjustment with associated entries.
const adjustment = await this.inventoryAdjustment.query(trx)
.findById(inventoryAdjustmentId)
.withGraphFetched('entries.item');
const tenantMeta = await this.tenancyContext.getTenantMetadata();
// Retrieves the inventory adjustment GL entries.
const ledger = new InventoryAdjustmentsGL(adjustment)
.setBaseCurrency(tenantMeta.baseCurrency)
.getAdjustmentGL();
// Commits the ledger entries to the storage.
await this.ledgerStorage.commit(ledger, trx);
};
/**
* Reverts the adjustment transactions GL entries.
* @param {number} tenantId
* @param {number} inventoryAdjustmentId
* @returns {Promise<void>}
*/
public revertAdjustmentGLEntries = (
inventoryAdjustmentId: number,
trx?: Knex.Transaction,
): Promise<void> => {
return this.ledgerStorage.deleteByReference(
inventoryAdjustmentId,
'InventoryAdjustment',
trx,
);
};
/**
* Rewrite inventory adjustment GL entries.
* @param {number} tenantId
* @param {number} inventoryAdjustmentId
* @param {Knex.Transaction} trx
*/
public rewriteAdjustmentGLEntries = async (
inventoryAdjustmentId: number,
trx?: Knex.Transaction,
) => {
// Reverts GL entries of the given inventory adjustment.
await this.revertAdjustmentGLEntries(inventoryAdjustmentId, trx);
// Writes GL entries of th egiven inventory adjustment.
await this.writeAdjustmentGLEntries(inventoryAdjustmentId, trx);
};
}