From 7bcd578c1129ab5b7b3c3870b278c01e0e90fa66 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 15 Jan 2025 15:28:39 +0200 Subject: [PATCH] refactor --- .../commands/BillInventoryTransactions.ts | 31 +- .../CreditNotesInventoryTransactions.ts | 5 +- .../src/modules/InventoryCost/Inventory.ts | 538 +++++++----------- .../InventoryCost/InventoryAverageCost.ts | 454 +++++++-------- .../InventoryCost/InventoryCostApplication.ts | 16 +- .../InventoryCost/InventoryCostLotTracker.ts | 536 ++++++++--------- .../InventoryCost/InventoryCosts.service.ts | 258 ++++----- .../src/modules/InventoryCost/utils.ts | 43 +- .../inventory/InvoiceInventoryTransactions.ts | 4 +- .../VendorCreditInventoryTransactions.ts | 4 +- .../src/modules/Vendors/Vendors.module.ts | 5 +- 11 files changed, 894 insertions(+), 1000 deletions(-) diff --git a/packages/server-nest/src/modules/Bills/commands/BillInventoryTransactions.ts b/packages/server-nest/src/modules/Bills/commands/BillInventoryTransactions.ts index 6ddeee4f9..a4c621f12 100644 --- a/packages/server-nest/src/modules/Bills/commands/BillInventoryTransactions.ts +++ b/packages/server-nest/src/modules/Bills/commands/BillInventoryTransactions.ts @@ -1,16 +1,16 @@ import { Knex } from 'knex'; import { Bill } from '../models/Bill'; -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service'; -import { InventoryService } from '@/modules/InventoryCost/Inventory'; - +import { InventoryTransactionsService } from '@/modules/InventoryCost/InventoryTransactions.service'; @Injectable() export class BillInventoryTransactions { constructor( private readonly itemsEntriesService: ItemsEntriesService, - private readonly inventoryService: InventoryService, + private readonly inventoryTransactionsService: InventoryTransactionsService, - private readonly bill: typeof Bill + @Inject(Bill.name) + private readonly bill: typeof Bill, ) {} /** @@ -21,19 +21,18 @@ export class BillInventoryTransactions { public async recordInventoryTransactions( billId: number, override?: boolean, - trx?: Knex.Transaction + trx?: Knex.Transaction, ): Promise { // Retireve bill with assocaited entries and allocated cost entries. - - const bill = await this.bill.query(trx) + + const bill = await this.bill + .query(trx) .findById(billId) .withGraphFetched('entries.allocatedCostEntries'); // Loads the inventory items entries of the given sale invoice. const inventoryEntries = - await this.itemsEntriesService.filterInventoryEntries( - bill.entries - ); + await this.itemsEntriesService.filterInventoryEntries(bill.entries); const transaction = { transactionId: bill.id, transactionType: 'Bill', @@ -46,10 +45,10 @@ export class BillInventoryTransactions { warehouseId: bill.warehouseId, }; - await this.inventoryService.recordInventoryTransactionsFromItemsEntries( + await this.inventoryTransactionsService.recordInventoryTransactionsFromItemsEntries( transaction, override, - trx + trx, ); } @@ -61,13 +60,13 @@ export class BillInventoryTransactions { */ public async revertInventoryTransactions( billId: number, - trx?: Knex.Transaction + trx?: Knex.Transaction, ) { // Deletes the inventory transactions by the given reference id and type. - await this.inventoryService.deleteInventoryTransactions( + await this.inventoryTransactionsService.deleteInventoryTransactions( billId, 'Bill', - trx + trx, ); } } diff --git a/packages/server-nest/src/modules/CreditNotes/commands/CreditNotesInventoryTransactions.ts b/packages/server-nest/src/modules/CreditNotes/commands/CreditNotesInventoryTransactions.ts index 9d64d6706..fb6c3be2c 100644 --- a/packages/server-nest/src/modules/CreditNotes/commands/CreditNotesInventoryTransactions.ts +++ b/packages/server-nest/src/modules/CreditNotes/commands/CreditNotesInventoryTransactions.ts @@ -1,13 +1,12 @@ import { Injectable } from '@nestjs/common'; - -import { InventoryService } from '@/modules/InventoryCost/Inventory'; +import { InventoryTransactionsService } from '@/modules/InventoryCost/InventoryTransactions.service'; import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service'; import { CreditNote } from '../models/CreditNote'; import { Knex } from 'knex'; @Injectable() export class CreditNoteInventoryTransactions { constructor( - private readonly inventoryService: InventoryService, + private readonly inventoryService: InventoryTransactionsService, private readonly itemsEntriesService: ItemsEntriesService, ) {} diff --git a/packages/server-nest/src/modules/InventoryCost/Inventory.ts b/packages/server-nest/src/modules/InventoryCost/Inventory.ts index 0c8d48361..d1e2a26fa 100644 --- a/packages/server-nest/src/modules/InventoryCost/Inventory.ts +++ b/packages/server-nest/src/modules/InventoryCost/Inventory.ts @@ -1,362 +1,214 @@ -import { pick } from 'lodash'; -import { Inject, Injectable } from '@nestjs/common'; -import { EventEmitter2 } from '@nestjs/event-emitter'; -import { Knex } from 'knex'; -import { - IInventoryLotCost, - IInventoryTransaction, - TInventoryTransactionDirection, - IItemEntry, - IItemEntryTransactionType, - IInventoryTransactionsCreatedPayload, - IInventoryTransactionsDeletedPayload, - IInventoryItemCostScheduledPayload, -} from '@/interfaces'; -import { InventoryAverageCostMethod } from './InventoryAverageCost'; -import { InventoryCostLotTracker } from './InventoryCostLotTracker'; -import { ItemsEntriesService } from '../Items/ItemsEntries.service'; -import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service'; -import { Item } from '../Items/models/Item'; -import { SETTINGS_PROVIDER } from '../Settings/Settings.types'; -import { SettingsStore } from '../Settings/SettingsStore'; -import { events } from '@/common/events/events'; -import { InventoryTransaction } from './models/InventoryTransaction'; -import InventoryCostMethod from './InventoryCostMethod'; +// import { pick } from 'lodash'; +// import { Inject, Injectable } from '@nestjs/common'; +// import { EventEmitter2 } from '@nestjs/event-emitter'; +// import { Knex } from 'knex'; +// import { +// IInventoryLotCost, +// IInventoryTransaction, +// TInventoryTransactionDirection, +// IItemEntry, +// IItemEntryTransactionType, +// IInventoryTransactionsCreatedPayload, +// IInventoryTransactionsDeletedPayload, +// IInventoryItemCostScheduledPayload, +// } from '@/interfaces'; +// import { InventoryAverageCostMethod } from './InventoryAverageCost'; +// import { InventoryCostLotTracker } from './InventoryCostLotTracker'; +// import { ItemsEntriesService } from '../Items/ItemsEntries.service'; +// import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service'; +// import { Item } from '../Items/models/Item'; +// import { SETTINGS_PROVIDER } from '../Settings/Settings.types'; +// import { SettingsStore } from '../Settings/SettingsStore'; +// import { events } from '@/common/events/events'; +// import { InventoryTransaction } from './models/InventoryTransaction'; +// import InventoryCostMethod from './InventoryCostMethod'; -@Injectable() -export class InventoryService { - constructor( - private readonly eventEmitter: EventEmitter2, - private readonly uow: UnitOfWork, +// @Injectable() +// export class InventoryService { +// constructor( +// private readonly eventEmitter: EventEmitter2, +// private readonly uow: UnitOfWork, - @Inject(InventoryTransaction.name) - private readonly inventoryTransactionModel: typeof InventoryTransaction, +// @Inject(InventoryTransaction.name) +// private readonly inventoryTransactionModel: typeof InventoryTransaction, - @Inject(InventoryCostLotTracker.name) - private readonly inventoryCostLotTracker: typeof InventoryCostLotTracker, +// @Inject(InventoryCostLotTracker.name) +// private readonly inventoryCostLotTracker: typeof InventoryCostLotTracker, - @Inject(SETTINGS_PROVIDER) - private readonly settings: SettingsStore, - ) {} +// @Inject(SETTINGS_PROVIDER) +// private readonly settings: SettingsStore, +// ) {} - /** - * Transforms the items entries to inventory transactions. - */ - transformItemEntriesToInventory(transaction: { - transactionId: number; - transactionType: IItemEntryTransactionType; - transactionNumber?: string; +// /** +// * Transforms the items entries to inventory transactions. +// */ +// transformItemEntriesToInventory(transaction: { +// transactionId: number; +// transactionType: IItemEntryTransactionType; +// transactionNumber?: string; - exchangeRate?: number; +// exchangeRate?: number; - warehouseId: number | null; +// warehouseId: number | null; - date: Date | string; - direction: TInventoryTransactionDirection; - entries: IItemEntry[]; - createdAt: Date; - }): IInventoryTransaction[] { - const exchangeRate = transaction.exchangeRate || 1; +// date: Date | string; +// direction: TInventoryTransactionDirection; +// entries: IItemEntry[]; +// createdAt: Date; +// }): IInventoryTransaction[] { +// const exchangeRate = transaction.exchangeRate || 1; - return transaction.entries.map((entry: IItemEntry) => ({ - ...pick(entry, ['itemId', 'quantity']), - rate: entry.rate * exchangeRate, - transactionType: transaction.transactionType, - transactionId: transaction.transactionId, - direction: transaction.direction, - date: transaction.date, - entryId: entry.id, - createdAt: transaction.createdAt, - costAccountId: entry.costAccountId, +// return transaction.entries.map((entry: IItemEntry) => ({ +// ...pick(entry, ['itemId', 'quantity']), +// rate: entry.rate * exchangeRate, +// transactionType: transaction.transactionType, +// transactionId: transaction.transactionId, +// direction: transaction.direction, +// date: transaction.date, +// entryId: entry.id, +// createdAt: transaction.createdAt, +// costAccountId: entry.costAccountId, - warehouseId: entry.warehouseId || transaction.warehouseId, - meta: { - transactionNumber: transaction.transactionNumber, - description: entry.description, - }, - })); - } +// warehouseId: entry.warehouseId || transaction.warehouseId, +// meta: { +// transactionNumber: transaction.transactionNumber, +// description: entry.description, +// }, +// })); +// } - async computeItemCost(fromDate: Date, itemId: number) { - return this.uow.withTransaction((trx: Knex.Transaction) => { - return this.computeInventoryItemCost(fromDate, itemId); - }); - } +// async computeItemCost(fromDate: Date, itemId: number) { +// return this.uow.withTransaction((trx: Knex.Transaction) => { +// return this.computeInventoryItemCost(fromDate, itemId); +// }); +// } - /** - * Computes the given item cost and records the inventory lots transactions - * and journal entries based on the cost method FIFO, LIFO or average cost rate. - * @param {Date} fromDate - From date. - * @param {number} itemId - Item id. - */ - async computeInventoryItemCost( - fromDate: Date, - itemId: number, - trx?: Knex.Transaction, - ) { - // Fetches the item with associated item category. - const item = await Item.query().findById(itemId); +// /** +// * Computes the given item cost and records the inventory lots transactions +// * and journal entries based on the cost method FIFO, LIFO or average cost rate. +// * @param {Date} fromDate - From date. +// * @param {number} itemId - Item id. +// */ +// async computeInventoryItemCost( +// fromDate: Date, +// itemId: number, +// trx?: Knex.Transaction, +// ) { +// // Fetches the item with associated item category. +// const item = await Item.query().findById(itemId); - // Cannot continue if the given item was not inventory item. - if (item.type !== 'inventory') { - throw new Error('You could not compute item cost has no inventory type.'); - } - let costMethodComputer: InventoryCostMethod; +// // Cannot continue if the given item was not inventory item. +// if (item.type !== 'inventory') { +// throw new Error('You could not compute item cost has no inventory type.'); +// } +// let costMethodComputer: InventoryCostMethod; - // Switch between methods based on the item cost method. - switch ('AVG') { - case 'FIFO': - case 'LIFO': - costMethodComputer = new InventoryCostLotTracker( - tenantId, - fromDate, - itemId, - ); - break; - case 'AVG': - costMethodComputer = new InventoryAverageCostMethod( - fromDate, - itemId, - trx, - ); - break; - } - return costMethodComputer.computeItemCost(); - } +// // Switch between methods based on the item cost method. +// switch ('AVG') { +// case 'FIFO': +// case 'LIFO': +// costMethodComputer = new InventoryCostLotTracker( +// tenantId, +// fromDate, +// itemId, +// ); +// break; +// case 'AVG': +// costMethodComputer = new InventoryAverageCostMethod( +// fromDate, +// itemId, +// trx, +// ); +// break; +// } +// return costMethodComputer.computeItemCost(); +// } - /** - * Schedule item cost compute job. - * @param {number} tenantId - * @param {number} itemId - * @param {Date} startingDate - */ - async scheduleComputeItemCost( - tenantId: number, - itemId: number, - startingDate: Date | string, - ) { - const agenda = Container.get('agenda'); +// /** +// * Schedule item cost compute job. +// * @param {number} tenantId +// * @param {number} itemId +// * @param {Date} startingDate +// */ +// async scheduleComputeItemCost( +// tenantId: number, +// itemId: number, +// startingDate: Date | string, +// ) { +// const agenda = Container.get('agenda'); - const commonJobsQuery = { - name: 'compute-item-cost', - lastRunAt: { $exists: false }, - 'data.tenantId': tenantId, - 'data.itemId': itemId, - }; - // Cancel any `compute-item-cost` in the queue has upper starting date - // with the same given item. - await agenda.cancel({ - ...commonJobsQuery, - 'data.startingDate': { $lte: startingDate }, - }); - // Retrieve any `compute-item-cost` in the queue has lower starting date - // with the same given item. - const dependsJobs = await agenda.jobs({ - ...commonJobsQuery, - 'data.startingDate': { $gte: startingDate }, - }); - // If the depends jobs cleared. - if (dependsJobs.length === 0) { - await agenda.schedule( - config.scheduleComputeItemCost, - 'compute-item-cost', - { - startingDate, - itemId, - tenantId, - }, - ); - // Triggers `onComputeItemCostJobScheduled` event. - await this.eventPublisher.emitAsync( - events.inventory.onComputeItemCostJobScheduled, - { - startingDate, - itemId, - tenantId, - } as IInventoryItemCostScheduledPayload, - ); - } else { - // Re-schedule the jobs that have higher date from current moment. - await Promise.all( - dependsJobs.map((job) => - job.schedule(config.scheduleComputeItemCost).save(), - ), - ); - } - } +// const commonJobsQuery = { +// name: 'compute-item-cost', +// lastRunAt: { $exists: false }, +// 'data.tenantId': tenantId, +// 'data.itemId': itemId, +// }; +// // Cancel any `compute-item-cost` in the queue has upper starting date +// // with the same given item. +// await agenda.cancel({ +// ...commonJobsQuery, +// 'data.startingDate': { $lte: startingDate }, +// }); +// // Retrieve any `compute-item-cost` in the queue has lower starting date +// // with the same given item. +// const dependsJobs = await agenda.jobs({ +// ...commonJobsQuery, +// 'data.startingDate': { $gte: startingDate }, +// }); +// // If the depends jobs cleared. +// if (dependsJobs.length === 0) { +// await agenda.schedule( +// config.scheduleComputeItemCost, +// 'compute-item-cost', +// { +// startingDate, +// itemId, +// tenantId, +// }, +// ); +// // Triggers `onComputeItemCostJobScheduled` event. +// await this.eventPublisher.emitAsync( +// events.inventory.onComputeItemCostJobScheduled, +// { +// startingDate, +// itemId, +// tenantId, +// } as IInventoryItemCostScheduledPayload, +// ); +// } else { +// // Re-schedule the jobs that have higher date from current moment. +// await Promise.all( +// dependsJobs.map((job) => +// job.schedule(config.scheduleComputeItemCost).save(), +// ), +// ); +// } +// } - /** - * Records the inventory transactions. - * @param {number} tenantId - Tenant id. - * @param {Bill} bill - Bill model object. - * @param {number} billId - Bill id. - * @return {Promise} - */ - async recordInventoryTransactions( - transactions: IInventoryTransaction[], - override: boolean = false, - trx?: Knex.Transaction, - ): Promise { - const bulkInsertOpers = []; - transactions.forEach((transaction: IInventoryTransaction) => { - const oper = this.recordInventoryTransaction(transaction, override, trx); - bulkInsertOpers.push(oper); - }); - const inventoryTransactions = await Promise.all(bulkInsertOpers); +// /** +// * Mark item cost computing is running. +// * @param {boolean} isRunning - +// */ +// async markItemsCostComputeRunning(isRunning: boolean = true) { +// this.settings.set({ +// key: 'cost_compute_running', +// group: 'inventory', +// value: isRunning, +// }); +// await this.settings.save(); +// } - // Triggers `onInventoryTransactionsCreated` event. - await this.eventEmitter.emitAsync( - events.inventory.onInventoryTransactionsCreated, - { - inventoryTransactions, - trx, - } as IInventoryTransactionsCreatedPayload, - ); - } - - /** - * Writes the inventory transactiosn on the storage from the given - * inventory transactions entries. - * - * @param {number} tenantId - - * @param {IInventoryTransaction} inventoryEntry - - * @param {boolean} deleteOld - - */ - async recordInventoryTransaction( - inventoryEntry: IInventoryTransaction, - deleteOld: boolean = false, - trx: Knex.Transaction, - ): Promise { - if (deleteOld) { - await this.deleteInventoryTransactions( - inventoryEntry.transactionId, - inventoryEntry.transactionType, - trx, - ); - } - return this.inventoryTransactionModel.query(trx).insertGraph({ - ...inventoryEntry, - }); - } - - /** - * Records the inventory transactions from items entries that have (inventory) type. - * - * @param {number} tenantId - * @param {number} transactionId - * @param {string} transactionType - * @param {Date|string} transactionDate - * @param {boolean} override - */ - async recordInventoryTransactionsFromItemsEntries( - transaction: { - transactionId: number; - transactionType: IItemEntryTransactionType; - exchangeRate: number; - - date: Date | string; - direction: TInventoryTransactionDirection; - entries: IItemEntry[]; - createdAt: Date | string; - - warehouseId: number; - }, - override: boolean = false, - trx?: Knex.Transaction, - ): Promise { - // Can't continue if there is no entries has inventory items in the invoice. - if (transaction.entries.length <= 0) { - return; - } - // Inventory transactions. - const inventoryTranscations = - this.transformItemEntriesToInventory(transaction); - - // Records the inventory transactions of the given sale invoice. - await this.recordInventoryTransactions( - inventoryTranscations, - override, - trx, - ); - } - - /** - * Deletes the given inventory transactions. - * @param {number} tenantId - Tenant id. - * @param {string} transactionType - * @param {number} transactionId - * @return {Promise<{ - * oldInventoryTransactions: IInventoryTransaction[] - * }>} - */ - async deleteInventoryTransactions( - transactionId: number, - transactionType: string, - trx?: Knex.Transaction, - ): Promise<{ oldInventoryTransactions: InventoryTransaction[] }> { - // Retrieve the inventory transactions of the given sale invoice. - const oldInventoryTransactions = await this.inventoryTransactionModel - .query(trx) - .where({ transactionId, transactionType }); - - // Deletes the inventory transactions by the given transaction type and id. - await this.inventoryTransactionModel - .query(trx) - .where({ transactionType, transactionId }) - .delete(); - - // Triggers `onInventoryTransactionsDeleted` event. - await this.eventEmitter.emitAsync( - events.inventory.onInventoryTransactionsDeleted, - { - oldInventoryTransactions, - transactionId, - transactionType, - trx, - } as IInventoryTransactionsDeletedPayload, - ); - return { oldInventoryTransactions }; - } - - /** - * Records the inventory cost lot transaction. - * @param {number} tenantId - * @param {IInventoryLotCost} inventoryLotEntry - * @return {Promise} - */ - async recordInventoryCostLotTransaction( - tenantId: number, - inventoryLotEntry: IInventoryLotCost, - ): Promise { - return this.inventoryCostLotTracker.query().insert({ - ...inventoryLotEntry, - }); - } - - /** - * Mark item cost computing is running. - * @param {boolean} isRunning - - */ - async markItemsCostComputeRunning(isRunning: boolean = true) { - this.settings.set({ - key: 'cost_compute_running', - group: 'inventory', - value: isRunning, - }); - await this.settings.save(); - } - - /** - * Checks if the items cost compute is running. - * @returns {boolean} - */ - isItemsCostComputeRunning() { - return ( - this.settings.get({ - key: 'cost_compute_running', - group: 'inventory', - }) ?? false - ); - } -} +// /** +// * Checks if the items cost compute is running. +// * @returns {boolean} +// */ +// isItemsCostComputeRunning() { +// return ( +// this.settings.get({ +// key: 'cost_compute_running', +// group: 'inventory', +// }) ?? false +// ); +// } +// } diff --git a/packages/server-nest/src/modules/InventoryCost/InventoryAverageCost.ts b/packages/server-nest/src/modules/InventoryCost/InventoryAverageCost.ts index e8524a370..2386bdb7d 100644 --- a/packages/server-nest/src/modules/InventoryCost/InventoryAverageCost.ts +++ b/packages/server-nest/src/modules/InventoryCost/InventoryAverageCost.ts @@ -1,254 +1,254 @@ -import { pick } from 'lodash'; -import { Knex } from 'knex'; -import InventoryCostMethod from './InventoryCostMethod'; -import { InventoryTransaction } from './models/InventoryTransaction'; +// import { pick } from 'lodash'; +// import { Knex } from 'knex'; +// import InventoryCostMethod from './InventoryCostMethod'; +// import { InventoryTransaction } from './models/InventoryTransaction'; -export class InventoryAverageCostMethod extends InventoryCostMethod { - startingDate: Date; - itemId: number; - costTransactions: any[]; - trx: Knex.Transaction; +// export class InventoryAverageCostMethod extends InventoryCostMethod { +// startingDate: Date; +// itemId: number; +// costTransactions: any[]; +// trx: Knex.Transaction; - /** - * Constructor method. - * @param {number} tenantId - The given tenant id. - * @param {Date} startingDate - - * @param {number} itemId - The given inventory item id. - */ - constructor( - tenantId: number, - startingDate: Date, - itemId: number, - trx?: Knex.Transaction, - ) { - super(tenantId, startingDate, itemId); +// /** +// * Constructor method. +// * @param {number} tenantId - The given tenant id. +// * @param {Date} startingDate - +// * @param {number} itemId - The given inventory item id. +// */ +// constructor( +// tenantId: number, +// startingDate: Date, +// itemId: number, +// trx?: Knex.Transaction, +// ) { +// super(tenantId, startingDate, itemId); - this.trx = trx; - this.startingDate = startingDate; - this.itemId = itemId; - this.costTransactions = []; - } +// this.trx = trx; +// this.startingDate = startingDate; +// this.itemId = itemId; +// this.costTransactions = []; +// } - /** - * Computes items costs from the given date using average cost method. - * ---------- - * - Calculate the items average cost in the given date. - * - Remove the journal entries that associated to the inventory transacions - * after the given date. - * - Re-compute the inventory transactions and re-write the journal entries - * after the given date. - * ---------- - * @async - * @param {Date} startingDate - * @param {number} referenceId - * @param {string} referenceType - */ - public async computeItemCost() { - const { InventoryTransaction } = this.tenantModels; - const { averageCost, openingQuantity, openingCost } = - await this.getOpeningAverageCost(this.startingDate, this.itemId); +// /** +// * Computes items costs from the given date using average cost method. +// * ---------- +// * - Calculate the items average cost in the given date. +// * - Remove the journal entries that associated to the inventory transacions +// * after the given date. +// * - Re-compute the inventory transactions and re-write the journal entries +// * after the given date. +// * ---------- +// * @async +// * @param {Date} startingDate +// * @param {number} referenceId +// * @param {string} referenceType +// */ +// public async computeItemCost() { +// const { InventoryTransaction } = this.tenantModels; +// const { averageCost, openingQuantity, openingCost } = +// await this.getOpeningAverageCost(this.startingDate, this.itemId); - const afterInvTransactions = - await InventoryTransaction.query() - .modify('filterDateRange', this.startingDate) - .orderBy('date', 'ASC') - .orderByRaw("FIELD(direction, 'IN', 'OUT')") - .orderBy('createdAt', 'ASC') - .where('item_id', this.itemId) - .withGraphFetched('item'); +// const afterInvTransactions = +// await InventoryTransaction.query() +// .modify('filterDateRange', this.startingDate) +// .orderBy('date', 'ASC') +// .orderByRaw("FIELD(direction, 'IN', 'OUT')") +// .orderBy('createdAt', 'ASC') +// .where('item_id', this.itemId) +// .withGraphFetched('item'); - // Tracking inventroy transactions and retrieve cost transactions based on - // average rate cost method. - const costTransactions = this.trackingCostTransactions( - afterInvTransactions, - openingQuantity, - openingCost, - ); - // Revert the inveout out lots transactions - await this.revertTheInventoryOutLotTrans(); +// // Tracking inventroy transactions and retrieve cost transactions based on +// // average rate cost method. +// const costTransactions = this.trackingCostTransactions( +// afterInvTransactions, +// openingQuantity, +// openingCost, +// ); +// // Revert the inveout out lots transactions +// await this.revertTheInventoryOutLotTrans(); - // Store inventory lots cost transactions. - await this.storeInventoryLotsCost(costTransactions); - } +// // Store inventory lots cost transactions. +// await this.storeInventoryLotsCost(costTransactions); +// } - /** - * Get items Average cost from specific date from inventory transactions. - * @async - * @param {Date} closingDate - * @return {number} - */ - public async getOpeningAverageCost(closingDate: Date, itemId: number) { - const { InventoryCostLotTracker } = this.tenantModels; +// /** +// * Get items Average cost from specific date from inventory transactions. +// * @async +// * @param {Date} closingDate +// * @return {number} +// */ +// public async getOpeningAverageCost(closingDate: Date, itemId: number) { +// const { InventoryCostLotTracker } = this.tenantModels; - const commonBuilder = (builder: any) => { - if (closingDate) { - builder.where('date', '<', closingDate); - } - builder.where('item_id', itemId); - builder.sum('rate as rate'); - builder.sum('quantity as quantity'); - builder.sum('cost as cost'); - builder.first(); - }; - // Calculates the total inventory total quantity and rate `IN` transactions. - const inInvSumationOper: Promise = InventoryCostLotTracker.query() - .onBuild(commonBuilder) - .where('direction', 'IN'); +// const commonBuilder = (builder: any) => { +// if (closingDate) { +// builder.where('date', '<', closingDate); +// } +// builder.where('item_id', itemId); +// builder.sum('rate as rate'); +// builder.sum('quantity as quantity'); +// builder.sum('cost as cost'); +// builder.first(); +// }; +// // Calculates the total inventory total quantity and rate `IN` transactions. +// const inInvSumationOper: Promise = InventoryCostLotTracker.query() +// .onBuild(commonBuilder) +// .where('direction', 'IN'); - // Calculates the total inventory total quantity and rate `OUT` transactions. - const outInvSumationOper: Promise = InventoryCostLotTracker.query() - .onBuild(commonBuilder) - .where('direction', 'OUT'); +// // Calculates the total inventory total quantity and rate `OUT` transactions. +// const outInvSumationOper: Promise = InventoryCostLotTracker.query() +// .onBuild(commonBuilder) +// .where('direction', 'OUT'); - const [inInvSumation, outInvSumation] = await Promise.all([ - inInvSumationOper, - outInvSumationOper, - ]); - return this.computeItemAverageCost( - inInvSumation?.cost || 0, - inInvSumation?.quantity || 0, - outInvSumation?.cost || 0, - outInvSumation?.quantity || 0, - ); - } +// const [inInvSumation, outInvSumation] = await Promise.all([ +// inInvSumationOper, +// outInvSumationOper, +// ]); +// return this.computeItemAverageCost( +// inInvSumation?.cost || 0, +// inInvSumation?.quantity || 0, +// outInvSumation?.cost || 0, +// outInvSumation?.quantity || 0, +// ); +// } - /** - * Computes the item average cost. - * @static - * @param {number} quantityIn - * @param {number} rateIn - * @param {number} quantityOut - * @param {number} rateOut - */ - public computeItemAverageCost( - totalCostIn: number, - totalQuantityIn: number, +// /** +// * Computes the item average cost. +// * @static +// * @param {number} quantityIn +// * @param {number} rateIn +// * @param {number} quantityOut +// * @param {number} rateOut +// */ +// public computeItemAverageCost( +// totalCostIn: number, +// totalQuantityIn: number, - totalCostOut: number, - totalQuantityOut: number, - ) { - const openingCost = totalCostIn - totalCostOut; - const openingQuantity = totalQuantityIn - totalQuantityOut; +// totalCostOut: number, +// totalQuantityOut: number, +// ) { +// const openingCost = totalCostIn - totalCostOut; +// const openingQuantity = totalQuantityIn - totalQuantityOut; - const averageCost = openingQuantity ? openingCost / openingQuantity : 0; +// const averageCost = openingQuantity ? openingCost / openingQuantity : 0; - return { averageCost, openingCost, openingQuantity }; - } +// return { averageCost, openingCost, openingQuantity }; +// } - private getCost(rate: number, quantity: number) { - return quantity ? rate * quantity : rate; - } +// private getCost(rate: number, quantity: number) { +// return quantity ? rate * quantity : rate; +// } - /** - * Records the journal entries from specific item inventory transactions. - * @param {IInventoryTransaction[]} invTransactions - * @param {number} openingAverageCost - * @param {string} referenceType - * @param {number} referenceId - * @param {JournalCommand} journalCommands - */ - public trackingCostTransactions( - invTransactions: InventoryTransaction[], - openingQuantity: number = 0, - openingCost: number = 0, - ) { - const costTransactions: any[] = []; +// /** +// * Records the journal entries from specific item inventory transactions. +// * @param {IInventoryTransaction[]} invTransactions +// * @param {number} openingAverageCost +// * @param {string} referenceType +// * @param {number} referenceId +// * @param {JournalCommand} journalCommands +// */ +// public trackingCostTransactions( +// invTransactions: InventoryTransaction[], +// openingQuantity: number = 0, +// openingCost: number = 0, +// ) { +// const costTransactions: any[] = []; - // Cumulative item quantity and cost. This will decrement after - // each out transactions depends on its quantity and cost. - let accQuantity: number = openingQuantity; - let accCost: number = openingCost; +// // Cumulative item quantity and cost. This will decrement after +// // each out transactions depends on its quantity and cost. +// let accQuantity: number = openingQuantity; +// let accCost: number = openingCost; - invTransactions.forEach((invTransaction: InventoryTransaction) => { - const commonEntry = { - invTransId: invTransaction.id, - ...pick(invTransaction, [ - 'date', - 'direction', - 'itemId', - 'quantity', - 'rate', - 'entryId', - 'transactionId', - 'transactionType', - 'createdAt', - 'costAccountId', - 'branchId', - 'warehouseId', - ]), - inventoryTransactionId: invTransaction.id, - }; - switch (invTransaction.direction) { - case 'IN': - const inCost = this.getCost( - invTransaction.rate, - invTransaction.quantity, - ); - // Increases the quantity and cost in `IN` inventory transactions. - accQuantity += invTransaction.quantity; - accCost += inCost; +// invTransactions.forEach((invTransaction: InventoryTransaction) => { +// const commonEntry = { +// invTransId: invTransaction.id, +// ...pick(invTransaction, [ +// 'date', +// 'direction', +// 'itemId', +// 'quantity', +// 'rate', +// 'entryId', +// 'transactionId', +// 'transactionType', +// 'createdAt', +// 'costAccountId', +// 'branchId', +// 'warehouseId', +// ]), +// inventoryTransactionId: invTransaction.id, +// }; +// switch (invTransaction.direction) { +// case 'IN': +// const inCost = this.getCost( +// invTransaction.rate, +// invTransaction.quantity, +// ); +// // Increases the quantity and cost in `IN` inventory transactions. +// accQuantity += invTransaction.quantity; +// accCost += inCost; - costTransactions.push({ - ...commonEntry, - cost: inCost, - }); - break; - case 'OUT': - // Average cost = Total cost / Total quantity - const averageCost = accQuantity ? accCost / accQuantity : 0; +// costTransactions.push({ +// ...commonEntry, +// cost: inCost, +// }); +// break; +// case 'OUT': +// // Average cost = Total cost / Total quantity +// const averageCost = accQuantity ? accCost / accQuantity : 0; - const quantity = - accQuantity > 0 - ? Math.min(invTransaction.quantity, accQuantity) - : invTransaction.quantity; +// const quantity = +// accQuantity > 0 +// ? Math.min(invTransaction.quantity, accQuantity) +// : invTransaction.quantity; - // Cost = the transaction quantity * Average cost. - const cost = this.getCost(averageCost, quantity); +// // Cost = the transaction quantity * Average cost. +// const cost = this.getCost(averageCost, quantity); - // Revenue = transaction quanity * rate. - // const revenue = quantity * invTransaction.rate; - costTransactions.push({ - ...commonEntry, - quantity, - cost, - }); - accQuantity = Math.max(accQuantity - quantity, 0); - accCost = Math.max(accCost - cost, 0); +// // Revenue = transaction quanity * rate. +// // const revenue = quantity * invTransaction.rate; +// costTransactions.push({ +// ...commonEntry, +// quantity, +// cost, +// }); +// accQuantity = Math.max(accQuantity - quantity, 0); +// accCost = Math.max(accCost - cost, 0); - if (invTransaction.quantity > quantity) { - const remainingQuantity = Math.max( - invTransaction.quantity - quantity, - 0, - ); - const remainingIncome = remainingQuantity * invTransaction.rate; +// if (invTransaction.quantity > quantity) { +// const remainingQuantity = Math.max( +// invTransaction.quantity - quantity, +// 0, +// ); +// const remainingIncome = remainingQuantity * invTransaction.rate; - costTransactions.push({ - ...commonEntry, - quantity: remainingQuantity, - cost: 0, - }); - accQuantity = Math.max(accQuantity - remainingQuantity, 0); - accCost = Math.max(accCost - remainingIncome, 0); - } - break; - } - }); - return costTransactions; - } +// costTransactions.push({ +// ...commonEntry, +// quantity: remainingQuantity, +// cost: 0, +// }); +// accQuantity = Math.max(accQuantity - remainingQuantity, 0); +// accCost = Math.max(accCost - remainingIncome, 0); +// } +// break; +// } +// }); +// return costTransactions; +// } - /** - * Reverts the inventory lots `OUT` transactions. - * @param {Date} openingDate - Opening date. - * @param {number} itemId - Item id. - * @returns {Promise} - */ - async revertTheInventoryOutLotTrans(): Promise { - const { InventoryCostLotTracker } = this.tenantModels; +// /** +// * Reverts the inventory lots `OUT` transactions. +// * @param {Date} openingDate - Opening date. +// * @param {number} itemId - Item id. +// * @returns {Promise} +// */ +// async revertTheInventoryOutLotTrans(): Promise { +// const { InventoryCostLotTracker } = this.tenantModels; - await InventoryCostLotTracker.query(this.trx) - .modify('filterDateRange', this.startingDate) - .orderBy('date', 'DESC') - .where('item_id', this.itemId) - .delete(); - } -} +// await InventoryCostLotTracker.query(this.trx) +// .modify('filterDateRange', this.startingDate) +// .orderBy('date', 'DESC') +// .where('item_id', this.itemId) +// .delete(); +// } +// } diff --git a/packages/server-nest/src/modules/InventoryCost/InventoryCostApplication.ts b/packages/server-nest/src/modules/InventoryCost/InventoryCostApplication.ts index f262b929d..bc7cc74f9 100644 --- a/packages/server-nest/src/modules/InventoryCost/InventoryCostApplication.ts +++ b/packages/server-nest/src/modules/InventoryCost/InventoryCostApplication.ts @@ -1,11 +1,11 @@ import { Injectable } from '@nestjs/common'; -import { InventoryItemCostService } from './InventoryCosts.service'; +// import { InventoryItemCostService } from './InventoryCosts.service'; import { IInventoryItemCostMeta } from './types/InventoryCost.types'; @Injectable() export class InventoryCostApplication { constructor( - private readonly inventoryCost: InventoryItemCostService, + // private readonly inventoryCost: InventoryItemCostService, ) {} /** @@ -17,11 +17,11 @@ export class InventoryCostApplication { public getItemsInventoryValuationList = async ( itemsId: number[], date: Date - ): Promise => { - const itemsMap = await this.inventoryCost.getItemsInventoryValuation( - itemsId, - date - ); - return [...itemsMap.values()]; + ): Promise => { + // const itemsMap = await this.inventoryCost.getItemsInventoryValuation( + // itemsId, + // date + // ); + // return [...itemsMap.values()]; }; } diff --git a/packages/server-nest/src/modules/InventoryCost/InventoryCostLotTracker.ts b/packages/server-nest/src/modules/InventoryCost/InventoryCostLotTracker.ts index 349321c68..5df269782 100644 --- a/packages/server-nest/src/modules/InventoryCost/InventoryCostLotTracker.ts +++ b/packages/server-nest/src/modules/InventoryCost/InventoryCostLotTracker.ts @@ -1,302 +1,302 @@ -import { pick, chain } from 'lodash'; -import moment from 'moment'; -import { IInventoryLotCost, IInventoryTransaction } from "interfaces"; -import InventoryCostMethod from '@/services/Inventory/InventoryCostMethod'; +// import { pick, chain } from 'lodash'; +// import moment from 'moment'; +// import { IInventoryLotCost, IInventoryTransaction } from "interfaces"; +// import InventoryCostMethod from '@/services/Inventory/InventoryCostMethod'; -type TCostMethod = 'FIFO' | 'LIFO'; +// type TCostMethod = 'FIFO' | 'LIFO'; -export class InventoryCostLotTracker extends InventoryCostMethod { - startingDate: Date; - itemId: number; - costMethod: TCostMethod; - itemsById: Map; - inventoryINTrans: any; - inventoryByItem: any; - costLotsTransactions: IInventoryLotCost[]; - inTransactions: any[]; - outTransactions: IInventoryTransaction[]; - revertJEntriesTransactions: IInventoryTransaction[]; +// export class InventoryCostLotTracker extends InventoryCostMethod { +// startingDate: Date; +// itemId: number; +// costMethod: TCostMethod; +// itemsById: Map; +// inventoryINTrans: any; +// inventoryByItem: any; +// costLotsTransactions: IInventoryLotCost[]; +// inTransactions: any[]; +// outTransactions: IInventoryTransaction[]; +// revertJEntriesTransactions: IInventoryTransaction[]; - /** - * Constructor method. - * @param {Date} startingDate - - * @param {number} itemId - - * @param {string} costMethod - - */ - constructor( - tenantId: number, - startingDate: Date, - itemId: number, - costMethod: TCostMethod = 'FIFO' - ) { - super(tenantId, startingDate, itemId); +// /** +// * Constructor method. +// * @param {Date} startingDate - +// * @param {number} itemId - +// * @param {string} costMethod - +// */ +// constructor( +// tenantId: number, +// startingDate: Date, +// itemId: number, +// costMethod: TCostMethod = 'FIFO' +// ) { +// super(tenantId, startingDate, itemId); - this.startingDate = startingDate; - this.itemId = itemId; - this.costMethod = costMethod; +// this.startingDate = startingDate; +// this.itemId = itemId; +// this.costMethod = costMethod; - // Collect cost lots transactions to insert them to the storage in bulk. - this.costLotsTransactions= []; - // Collect inventory transactions by item id. - this.inventoryByItem = {}; - // Collection `IN` inventory tranaction by transaction id. - this.inventoryINTrans = {}; - // Collects `IN` transactions. - this.inTransactions = []; - // Collects `OUT` transactions. - this.outTransactions = []; - } +// // Collect cost lots transactions to insert them to the storage in bulk. +// this.costLotsTransactions= []; +// // Collect inventory transactions by item id. +// this.inventoryByItem = {}; +// // Collection `IN` inventory tranaction by transaction id. +// this.inventoryINTrans = {}; +// // Collects `IN` transactions. +// this.inTransactions = []; +// // Collects `OUT` transactions. +// this.outTransactions = []; +// } - /** - * Computes items costs from the given date using FIFO or LIFO cost method. - * -------- - * - Revert the inventory lots after the given date. - * - Remove all the journal entries from the inventory transactions - * after the given date. - * - Re-tracking the inventory lots from inventory transactions. - * - Re-write the journal entries from the given inventory transactions. - * @async - * @return {void} - */ - public async computeItemCost(): Promise { - await this.revertInventoryLots(this.startingDate); - await this.fetchInvINTransactions(); - await this.fetchInvOUTTransactions(); - await this.fetchRevertInvJReferenceIds(); - await this.fetchItemsMapped(); +// /** +// * Computes items costs from the given date using FIFO or LIFO cost method. +// * -------- +// * - Revert the inventory lots after the given date. +// * - Remove all the journal entries from the inventory transactions +// * after the given date. +// * - Re-tracking the inventory lots from inventory transactions. +// * - Re-write the journal entries from the given inventory transactions. +// * @async +// * @return {void} +// */ +// public async computeItemCost(): Promise { +// await this.revertInventoryLots(this.startingDate); +// await this.fetchInvINTransactions(); +// await this.fetchInvOUTTransactions(); +// await this.fetchRevertInvJReferenceIds(); +// await this.fetchItemsMapped(); - this.trackingInventoryINLots(this.inTransactions); - this.trackingInventoryOUTLots(this.outTransactions); +// this.trackingInventoryINLots(this.inTransactions); +// this.trackingInventoryOUTLots(this.outTransactions); - // Re-tracking the inventory `IN` and `OUT` lots costs. - const storedTrackedInvLotsOper = this.storeInventoryLotsCost( - this.costLotsTransactions, - ); - return Promise.all([ - storedTrackedInvLotsOper, - ]); - } +// // Re-tracking the inventory `IN` and `OUT` lots costs. +// const storedTrackedInvLotsOper = this.storeInventoryLotsCost( +// this.costLotsTransactions, +// ); +// return Promise.all([ +// storedTrackedInvLotsOper, +// ]); +// } - /** - * Fetched inventory transactions that has date from the starting date and - * fetches available IN LOTs transactions that has remaining bigger than zero. - * @private - */ - private async fetchInvINTransactions() { - const { InventoryTransaction, InventoryLotCostTracker } = this.tenantModels; +// /** +// * Fetched inventory transactions that has date from the starting date and +// * fetches available IN LOTs transactions that has remaining bigger than zero. +// * @private +// */ +// private async fetchInvINTransactions() { +// const { InventoryTransaction, InventoryLotCostTracker } = this.tenantModels; - const commonBuilder = (builder: any) => { - builder.orderBy('date', (this.costMethod === 'LIFO') ? 'DESC': 'ASC'); - builder.where('item_id', this.itemId); - }; - const afterInvTransactions: IInventoryTransaction[] = - await InventoryTransaction.query() - .modify('filterDateRange', this.startingDate) - .orderByRaw("FIELD(direction, 'IN', 'OUT')") - .onBuild(commonBuilder) - .orderBy('lot_number', (this.costMethod === 'LIFO') ? 'DESC' : 'ASC') - .withGraphFetched('item'); +// const commonBuilder = (builder: any) => { +// builder.orderBy('date', (this.costMethod === 'LIFO') ? 'DESC': 'ASC'); +// builder.where('item_id', this.itemId); +// }; +// const afterInvTransactions: IInventoryTransaction[] = +// await InventoryTransaction.query() +// .modify('filterDateRange', this.startingDate) +// .orderByRaw("FIELD(direction, 'IN', 'OUT')") +// .onBuild(commonBuilder) +// .orderBy('lot_number', (this.costMethod === 'LIFO') ? 'DESC' : 'ASC') +// .withGraphFetched('item'); - const availableINLots: IInventoryLotCost[] = - await InventoryLotCostTracker.query() - .modify('filterDateRange', null, this.startingDate) - .orderBy('date', 'ASC') - .where('direction', 'IN') - .orderBy('lot_number', 'ASC') - .onBuild(commonBuilder) - .whereNot('remaining', 0); +// const availableINLots: IInventoryLotCost[] = +// await InventoryLotCostTracker.query() +// .modify('filterDateRange', null, this.startingDate) +// .orderBy('date', 'ASC') +// .where('direction', 'IN') +// .orderBy('lot_number', 'ASC') +// .onBuild(commonBuilder) +// .whereNot('remaining', 0); - this.inTransactions = [ - ...availableINLots.map((trans) => ({ lotTransId: trans.id, ...trans })), - ...afterInvTransactions.map((trans) => ({ invTransId: trans.id, ...trans })), - ]; - } +// this.inTransactions = [ +// ...availableINLots.map((trans) => ({ lotTransId: trans.id, ...trans })), +// ...afterInvTransactions.map((trans) => ({ invTransId: trans.id, ...trans })), +// ]; +// } - /** - * Fetches inventory OUT transactions that has date from the starting date. - * @private - */ - private async fetchInvOUTTransactions() { - const { InventoryTransaction } = this.tenantModels; +// /** +// * Fetches inventory OUT transactions that has date from the starting date. +// * @private +// */ +// private async fetchInvOUTTransactions() { +// const { InventoryTransaction } = this.tenantModels; - const afterOUTTransactions: IInventoryTransaction[] = - await InventoryTransaction.query() - .modify('filterDateRange', this.startingDate) - .orderBy('date', 'ASC') - .orderBy('lot_number', 'ASC') - .where('item_id', this.itemId) - .where('direction', 'OUT') - .withGraphFetched('item'); +// const afterOUTTransactions: IInventoryTransaction[] = +// await InventoryTransaction.query() +// .modify('filterDateRange', this.startingDate) +// .orderBy('date', 'ASC') +// .orderBy('lot_number', 'ASC') +// .where('item_id', this.itemId) +// .where('direction', 'OUT') +// .withGraphFetched('item'); - this.outTransactions = [ ...afterOUTTransactions ]; - } +// this.outTransactions = [ ...afterOUTTransactions ]; +// } - private async fetchItemsMapped() { - const itemsIds = chain(this.inTransactions).map((e) => e.itemId).uniq().value(); - const { Item } = this.tenantModels; - const storedItems = await Item.query() - .where('type', 'inventory') - .whereIn('id', itemsIds); +// private async fetchItemsMapped() { +// const itemsIds = chain(this.inTransactions).map((e) => e.itemId).uniq().value(); +// const { Item } = this.tenantModels; +// const storedItems = await Item.query() +// .where('type', 'inventory') +// .whereIn('id', itemsIds); - this.itemsById = new Map(storedItems.map((item: any) => [item.id, item])); - } +// this.itemsById = new Map(storedItems.map((item: any) => [item.id, item])); +// } - /** - * Fetch the inventory transactions that should revert its journal entries. - * @private - */ - private async fetchRevertInvJReferenceIds() { - const { InventoryTransaction } = this.tenantModels; - const revertJEntriesTransactions: IInventoryTransaction[] = - await InventoryTransaction.query() - .select(['transactionId', 'transactionType']) - .modify('filterDateRange', this.startingDate) - .where('direction', 'OUT') - .where('item_id', this.itemId); +// /** +// * Fetch the inventory transactions that should revert its journal entries. +// * @private +// */ +// private async fetchRevertInvJReferenceIds() { +// const { InventoryTransaction } = this.tenantModels; +// const revertJEntriesTransactions: IInventoryTransaction[] = +// await InventoryTransaction.query() +// .select(['transactionId', 'transactionType']) +// .modify('filterDateRange', this.startingDate) +// .where('direction', 'OUT') +// .where('item_id', this.itemId); - this.revertJEntriesTransactions = revertJEntriesTransactions; - } +// this.revertJEntriesTransactions = revertJEntriesTransactions; +// } - /** - * Revert the inventory lots to the given date by removing the inventory lots - * transactions after the given date and increment the remaining that - * associate to lot number. - * @async - * @return {Promise} - */ - public async revertInventoryLots(startingDate: Date) { - const { InventoryLotCostTracker } = this.tenantModels; - const asyncOpers: any[] = []; - const inventoryLotsTrans = await InventoryLotCostTracker.query() - .modify('filterDateRange', this.startingDate) - .orderBy('date', 'DESC') - .where('item_id', this.itemId) - .where('direction', 'OUT'); +// /** +// * Revert the inventory lots to the given date by removing the inventory lots +// * transactions after the given date and increment the remaining that +// * associate to lot number. +// * @async +// * @return {Promise} +// */ +// public async revertInventoryLots(startingDate: Date) { +// const { InventoryLotCostTracker } = this.tenantModels; +// const asyncOpers: any[] = []; +// const inventoryLotsTrans = await InventoryLotCostTracker.query() +// .modify('filterDateRange', this.startingDate) +// .orderBy('date', 'DESC') +// .where('item_id', this.itemId) +// .where('direction', 'OUT'); - const deleteInvLotsTrans = InventoryLotCostTracker.query() - .modify('filterDateRange', this.startingDate) - .where('item_id', this.itemId) - .delete(); +// const deleteInvLotsTrans = InventoryLotCostTracker.query() +// .modify('filterDateRange', this.startingDate) +// .where('item_id', this.itemId) +// .delete(); - inventoryLotsTrans.forEach((inventoryLot: IInventoryLotCost) => { - if (!inventoryLot.lotNumber) { return; } +// inventoryLotsTrans.forEach((inventoryLot: IInventoryLotCost) => { +// if (!inventoryLot.lotNumber) { return; } - const incrementOper = InventoryLotCostTracker.query() - .where('lot_number', inventoryLot.lotNumber) - .where('direction', 'IN') - .increment('remaining', inventoryLot.quantity); +// const incrementOper = InventoryLotCostTracker.query() +// .where('lot_number', inventoryLot.lotNumber) +// .where('direction', 'IN') +// .increment('remaining', inventoryLot.quantity); - asyncOpers.push(incrementOper); - }); - return Promise.all([deleteInvLotsTrans, ...asyncOpers]); - } +// asyncOpers.push(incrementOper); +// }); +// return Promise.all([deleteInvLotsTrans, ...asyncOpers]); +// } - /** - * Tracking inventory `IN` lots transactions. - * @public - * @param {IInventoryTransaction[]} inventoryTransactions - - * @return {void} - */ - public trackingInventoryINLots( - inventoryTransactions: IInventoryTransaction[], - ) { - inventoryTransactions.forEach((transaction: IInventoryTransaction) => { - const { itemId, id } = transaction; - (this.inventoryByItem[itemId] || (this.inventoryByItem[itemId] = [])); +// /** +// * Tracking inventory `IN` lots transactions. +// * @public +// * @param {IInventoryTransaction[]} inventoryTransactions - +// * @return {void} +// */ +// public trackingInventoryINLots( +// inventoryTransactions: IInventoryTransaction[], +// ) { +// inventoryTransactions.forEach((transaction: IInventoryTransaction) => { +// const { itemId, id } = transaction; +// (this.inventoryByItem[itemId] || (this.inventoryByItem[itemId] = [])); - const commonLotTransaction: IInventoryLotCost = { - ...pick(transaction, [ - 'date', 'rate', 'itemId', 'quantity', 'invTransId', 'lotTransId', - 'direction', 'transactionType', 'transactionId', 'lotNumber', 'remaining' - ]), - }; - this.inventoryByItem[itemId].push(id); - this.inventoryINTrans[id] = { - ...commonLotTransaction, - decrement: 0, - remaining: commonLotTransaction.remaining || commonLotTransaction.quantity, - }; - this.costLotsTransactions.push(this.inventoryINTrans[id]); - }); - } +// const commonLotTransaction: IInventoryLotCost = { +// ...pick(transaction, [ +// 'date', 'rate', 'itemId', 'quantity', 'invTransId', 'lotTransId', +// 'direction', 'transactionType', 'transactionId', 'lotNumber', 'remaining' +// ]), +// }; +// this.inventoryByItem[itemId].push(id); +// this.inventoryINTrans[id] = { +// ...commonLotTransaction, +// decrement: 0, +// remaining: commonLotTransaction.remaining || commonLotTransaction.quantity, +// }; +// this.costLotsTransactions.push(this.inventoryINTrans[id]); +// }); +// } - /** - * Tracking inventory `OUT` lots transactions. - * @public - * @param {IInventoryTransaction[]} inventoryTransactions - - * @return {void} - */ - public trackingInventoryOUTLots( - inventoryTransactions: IInventoryTransaction[], - ) { - inventoryTransactions.forEach((transaction: IInventoryTransaction) => { - const { itemId, id } = transaction; - (this.inventoryByItem[itemId] || (this.inventoryByItem[itemId] = [])); +// /** +// * Tracking inventory `OUT` lots transactions. +// * @public +// * @param {IInventoryTransaction[]} inventoryTransactions - +// * @return {void} +// */ +// public trackingInventoryOUTLots( +// inventoryTransactions: IInventoryTransaction[], +// ) { +// inventoryTransactions.forEach((transaction: IInventoryTransaction) => { +// const { itemId, id } = transaction; +// (this.inventoryByItem[itemId] || (this.inventoryByItem[itemId] = [])); - const commonLotTransaction: IInventoryLotCost = { - ...pick(transaction, [ - 'date', 'rate', 'itemId', 'quantity', 'invTransId', 'lotTransId', 'entryId', - 'direction', 'transactionType', 'transactionId', 'lotNumber', 'remaining' - ]), - }; - let invRemaining = transaction.quantity; - const idsShouldDel: number[] = []; +// const commonLotTransaction: IInventoryLotCost = { +// ...pick(transaction, [ +// 'date', 'rate', 'itemId', 'quantity', 'invTransId', 'lotTransId', 'entryId', +// 'direction', 'transactionType', 'transactionId', 'lotNumber', 'remaining' +// ]), +// }; +// let invRemaining = transaction.quantity; +// const idsShouldDel: number[] = []; - this.inventoryByItem?.[itemId]?.some((_invTransactionId: number) => { - const _invINTransaction = this.inventoryINTrans[_invTransactionId]; +// this.inventoryByItem?.[itemId]?.some((_invTransactionId: number) => { +// const _invINTransaction = this.inventoryINTrans[_invTransactionId]; - // Can't continue if the IN transaction remaining equals zero. - if (invRemaining <= 0) { return true; } +// // Can't continue if the IN transaction remaining equals zero. +// if (invRemaining <= 0) { return true; } - // Can't continue if the IN transaction date is after the current transaction date. - if (moment(_invINTransaction.date).isAfter(transaction.date)) { - return true; - } - // Detarmines the 'OUT' lot tranasctions whether bigger than 'IN' remaining transaction. - const biggerThanRemaining = (_invINTransaction.remaining - transaction.quantity) > 0; - const decrement = (biggerThanRemaining) ? transaction.quantity : _invINTransaction.remaining; - const maxDecrement = Math.min(decrement, invRemaining); - const cost = maxDecrement * _invINTransaction.rate; +// // Can't continue if the IN transaction date is after the current transaction date. +// if (moment(_invINTransaction.date).isAfter(transaction.date)) { +// return true; +// } +// // Detarmines the 'OUT' lot tranasctions whether bigger than 'IN' remaining transaction. +// const biggerThanRemaining = (_invINTransaction.remaining - transaction.quantity) > 0; +// const decrement = (biggerThanRemaining) ? transaction.quantity : _invINTransaction.remaining; +// const maxDecrement = Math.min(decrement, invRemaining); +// const cost = maxDecrement * _invINTransaction.rate; - _invINTransaction.decrement += maxDecrement; - _invINTransaction.remaining = Math.max( - _invINTransaction.remaining - maxDecrement, - 0, - ); - invRemaining = Math.max(invRemaining - maxDecrement, 0); +// _invINTransaction.decrement += maxDecrement; +// _invINTransaction.remaining = Math.max( +// _invINTransaction.remaining - maxDecrement, +// 0, +// ); +// invRemaining = Math.max(invRemaining - maxDecrement, 0); - this.costLotsTransactions.push({ - ...commonLotTransaction, - cost, - quantity: maxDecrement, - lotNumber: _invINTransaction.lotNumber, - }); - // Pop the 'IN' lots that has zero remaining. - if (_invINTransaction.remaining === 0) { - idsShouldDel.push(_invTransactionId); - } - return false; - }); - if (invRemaining > 0) { - this.costLotsTransactions.push({ - ...commonLotTransaction, - quantity: invRemaining, - }); - } - this.removeInventoryItems(itemId, idsShouldDel); - }); - } +// this.costLotsTransactions.push({ +// ...commonLotTransaction, +// cost, +// quantity: maxDecrement, +// lotNumber: _invINTransaction.lotNumber, +// }); +// // Pop the 'IN' lots that has zero remaining. +// if (_invINTransaction.remaining === 0) { +// idsShouldDel.push(_invTransactionId); +// } +// return false; +// }); +// if (invRemaining > 0) { +// this.costLotsTransactions.push({ +// ...commonLotTransaction, +// quantity: invRemaining, +// }); +// } +// this.removeInventoryItems(itemId, idsShouldDel); +// }); +// } - /** - * Remove inventory transactions for specific item id. - * @private - * @param {number} itemId - * @param {number[]} idsShouldDel - * @return {void} - */ - private removeInventoryItems(itemId: number, idsShouldDel: number[]) { - // Remove the IN transactions that has zero remaining amount. - this.inventoryByItem[itemId] = this.inventoryByItem?.[itemId] - ?.filter((transId: number) => idsShouldDel.indexOf(transId) === -1); - } -} \ No newline at end of file +// /** +// * Remove inventory transactions for specific item id. +// * @private +// * @param {number} itemId +// * @param {number[]} idsShouldDel +// * @return {void} +// */ +// private removeInventoryItems(itemId: number, idsShouldDel: number[]) { +// // Remove the IN transactions that has zero remaining amount. +// this.inventoryByItem[itemId] = this.inventoryByItem?.[itemId] +// ?.filter((transId: number) => idsShouldDel.indexOf(transId) === -1); +// } +// } \ No newline at end of file diff --git a/packages/server-nest/src/modules/InventoryCost/InventoryCosts.service.ts b/packages/server-nest/src/modules/InventoryCost/InventoryCosts.service.ts index a0fc9a674..c83a8f1cb 100644 --- a/packages/server-nest/src/modules/InventoryCost/InventoryCosts.service.ts +++ b/packages/server-nest/src/modules/InventoryCost/InventoryCosts.service.ts @@ -1,149 +1,149 @@ -import { keyBy, get } from 'lodash'; -import { Knex } from 'knex'; -import * as R from 'ramda'; -import { IInventoryItemCostMeta } from './types/InventoryCost.types'; -import { Inject, Injectable } from '@nestjs/common'; -import { InventoryTransaction } from './models/InventoryTransaction'; -import { InventoryCostLotTracker } from './models/InventoryCostLotTracker'; -import { Item } from '../Items/models/Item'; +// import { keyBy, get } from 'lodash'; +// import { Knex } from 'knex'; +// import * as R from 'ramda'; +// import { IInventoryItemCostMeta } from './types/InventoryCost.types'; +// import { Inject, Injectable } from '@nestjs/common'; +// import { InventoryTransaction } from './models/InventoryTransaction'; +// import { InventoryCostLotTracker } from './models/InventoryCostLotTracker'; +// import { Item } from '../Items/models/Item'; -@Injectable() -export class InventoryItemCostService { - constructor( - @Inject(InventoryTransaction.name) - private readonly inventoryTransactionModel: typeof InventoryTransaction, +// @Injectable() +// export class InventoryItemCostService { +// constructor( +// @Inject(InventoryTransaction.name) +// private readonly inventoryTransactionModel: typeof InventoryTransaction, - @Inject(InventoryCostLotTracker.name) - private readonly inventoryCostLotTrackerModel: typeof InventoryCostLotTracker, +// @Inject(InventoryCostLotTracker.name) +// private readonly inventoryCostLotTrackerModel: typeof InventoryCostLotTracker, - @Inject(Item.name) - private readonly itemModel: typeof Item, - ) {} +// @Inject(Item.name) +// private readonly itemModel: typeof Item, +// ) {} - /** - * Common query of items inventory valuation. - * @param {number[]} itemsIds - - * @param {Date} date - - * @param {Knex.QueryBuilder} builder - - */ - private itemsInventoryValuationCommonQuery = R.curry( - (itemsIds: number[], date: Date, builder: Knex.QueryBuilder) => { - if (date) { - builder.where('date', '<', date); - } - builder.whereIn('item_id', itemsIds); - builder.sum('rate as rate'); - builder.sum('quantity as quantity'); - builder.sum('cost as cost'); +// /** +// * Common query of items inventory valuation. +// * @param {number[]} itemsIds - +// * @param {Date} date - +// * @param {Knex.QueryBuilder} builder - +// */ +// private itemsInventoryValuationCommonQuery = R.curry( +// (itemsIds: number[], date: Date, builder: Knex.QueryBuilder) => { +// if (date) { +// builder.where('date', '<', date); +// } +// builder.whereIn('item_id', itemsIds); +// builder.sum('rate as rate'); +// builder.sum('quantity as quantity'); +// builder.sum('cost as cost'); - builder.groupBy('item_id'); - builder.select(['item_id']); - } - ); +// builder.groupBy('item_id'); +// builder.select(['item_id']); +// } +// ); - /** - * - * @param {} INValuationMap - - * @param {} OUTValuationMap - - * @param {number} itemId - */ - private getItemInventoryMeta = R.curry( - ( - INValuationMap, - OUTValuationMap, - itemId: number - ): IInventoryItemCostMeta => { - const INCost = get(INValuationMap, `[${itemId}].cost`, 0); - const INQuantity = get(INValuationMap, `[${itemId}].quantity`, 0); +// /** +// * +// * @param {} INValuationMap - +// * @param {} OUTValuationMap - +// * @param {number} itemId +// */ +// private getItemInventoryMeta = R.curry( +// ( +// INValuationMap, +// OUTValuationMap, +// itemId: number +// ): IInventoryItemCostMeta => { +// const INCost = get(INValuationMap, `[${itemId}].cost`, 0); +// const INQuantity = get(INValuationMap, `[${itemId}].quantity`, 0); - const OUTCost = get(OUTValuationMap, `[${itemId}].cost`, 0); - const OUTQuantity = get(OUTValuationMap, `[${itemId}].quantity`, 0); +// const OUTCost = get(OUTValuationMap, `[${itemId}].cost`, 0); +// const OUTQuantity = get(OUTValuationMap, `[${itemId}].quantity`, 0); - const valuation = INCost - OUTCost; - const quantity = INQuantity - OUTQuantity; - const average = quantity ? valuation / quantity : 0; +// const valuation = INCost - OUTCost; +// const quantity = INQuantity - OUTQuantity; +// const average = quantity ? valuation / quantity : 0; - return { itemId, valuation, quantity, average }; - } - ); +// return { itemId, valuation, quantity, average }; +// } +// ); - /** - * - * @param {number} tenantId - * @param {number} itemsId - * @param {Date} date - * @returns - */ - private getItemsInventoryINAndOutAggregated = ( - itemsId: number[], - date: Date - ): Promise => { +// /** +// * +// * @param {number} tenantId +// * @param {number} itemsId +// * @param {Date} date +// * @returns +// */ +// private getItemsInventoryINAndOutAggregated = ( +// itemsId: number[], +// date: Date +// ): Promise => { - const commonBuilder = this.itemsInventoryValuationCommonQuery( - itemsId, - date - ); - const INValuationOper = this.inventoryCostLotTrackerModel.query() - .onBuild(commonBuilder) - .where('direction', 'IN'); +// const commonBuilder = this.itemsInventoryValuationCommonQuery( +// itemsId, +// date +// ); +// const INValuationOper = this.inventoryCostLotTrackerModel.query() +// .onBuild(commonBuilder) +// .where('direction', 'IN'); - const OUTValuationOper = this.inventoryCostLotTrackerModel.query() - .onBuild(commonBuilder) - .where('direction', 'OUT'); +// const OUTValuationOper = this.inventoryCostLotTrackerModel.query() +// .onBuild(commonBuilder) +// .where('direction', 'OUT'); - return Promise.all([OUTValuationOper, INValuationOper]); - }; +// return Promise.all([OUTValuationOper, INValuationOper]); +// }; - /** - * - * @param {number} tenantId - - * @param {number[]} itemsIds - - * @param {Date} date - - */ - private getItemsInventoryInOutMap = async ( - itemsId: number[], - date: Date - ) => { - const [OUTValuation, INValuation] = - await this.getItemsInventoryINAndOutAggregated(itemsId, date); +// /** +// * +// * @param {number} tenantId - +// * @param {number[]} itemsIds - +// * @param {Date} date - +// */ +// private getItemsInventoryInOutMap = async ( +// itemsId: number[], +// date: Date +// ) => { +// const [OUTValuation, INValuation] = +// await this.getItemsInventoryINAndOutAggregated(itemsId, date); - const OUTValuationMap = keyBy(OUTValuation, 'itemId'); - const INValuationMap = keyBy(INValuation, 'itemId'); +// const OUTValuationMap = keyBy(OUTValuation, 'itemId'); +// const INValuationMap = keyBy(INValuation, 'itemId'); - return [OUTValuationMap, INValuationMap]; - }; +// return [OUTValuationMap, INValuationMap]; +// }; - /** - * - * @param {number} tenantId - * @param {number} itemId - * @param {Date} date - * @returns {Promise>} - */ - public getItemsInventoryValuation = async ( - itemsId: number[], - date: Date - ): Promise> => { - // Retrieves the inventory items. - const items = await this.itemModel.query() - .whereIn('id', itemsId) - .where('type', 'inventory'); +// /** +// * +// * @param {number} tenantId +// * @param {number} itemId +// * @param {Date} date +// * @returns {Promise>} +// */ +// public getItemsInventoryValuation = async ( +// itemsId: number[], +// date: Date +// ): Promise> => { +// // Retrieves the inventory items. +// const items = await this.itemModel.query() +// .whereIn('id', itemsId) +// .where('type', 'inventory'); - // Retrieves the inventory items ids. - const inventoryItemsIds: number[] = items.map((item) => item.id); +// // Retrieves the inventory items ids. +// const inventoryItemsIds: number[] = items.map((item) => item.id); - // Retreives the items inventory IN/OUT map. - const [OUTValuationMap, INValuationMap] = - await this.getItemsInventoryInOutMap(itemsId, date); +// // Retreives the items inventory IN/OUT map. +// const [OUTValuationMap, INValuationMap] = +// await this.getItemsInventoryInOutMap(itemsId, date); - const getItemValuation = this.getItemInventoryMeta( - INValuationMap, - OUTValuationMap - ); - const itemsValuations = inventoryItemsIds.map(getItemValuation); - const itemsValuationsMap = new Map( - itemsValuations.map((i) => [i.itemId, i]) - ); - return itemsValuationsMap; - }; -} +// const getItemValuation = this.getItemInventoryMeta( +// INValuationMap, +// OUTValuationMap +// ); +// const itemsValuations = inventoryItemsIds.map(getItemValuation); +// const itemsValuationsMap = new Map( +// itemsValuations.map((i) => [i.itemId, i]) +// ); +// return itemsValuationsMap; +// }; +// } diff --git a/packages/server-nest/src/modules/InventoryCost/utils.ts b/packages/server-nest/src/modules/InventoryCost/utils.ts index f961694b1..156ac55aa 100644 --- a/packages/server-nest/src/modules/InventoryCost/utils.ts +++ b/packages/server-nest/src/modules/InventoryCost/utils.ts @@ -1,4 +1,7 @@ import { chain } from 'lodash'; +import { pick } from 'lodash'; +import { IItemEntryTransactionType } from '../TransactionItemEntry/ItemEntry.types'; +import { TInventoryTransactionDirection } from './types/InventoryCost.types'; /** * Grpups by transaction type and id the inventory transactions. @@ -6,10 +9,48 @@ import { chain } from 'lodash'; * @returns */ export function groupInventoryTransactionsByTypeId( - transactions: { transactionType: string; transactionId: number }[] + transactions: { transactionType: string; transactionId: number }[], ): { transactionType: string; transactionId: number }[][] { return chain(transactions) .groupBy((t) => `${t.transactionType}-${t.transactionId}`) .values() .value(); } + +/** + * Transforms the items entries to inventory transactions. + */ +export function transformItemEntriesToInventory(transaction: { + transactionId: number; + transactionType: IItemEntryTransactionType; + transactionNumber?: string; + + exchangeRate?: number; + + warehouseId: number | null; + + date: Date | string; + direction: TInventoryTransactionDirection; + entries: IItemEntry[]; + createdAt: Date; +}): IInventoryTransaction[] { + const exchangeRate = transaction.exchangeRate || 1; + + return transaction.entries.map((entry: IItemEntry) => ({ + ...pick(entry, ['itemId', 'quantity']), + rate: entry.rate * exchangeRate, + transactionType: transaction.transactionType, + transactionId: transaction.transactionId, + direction: transaction.direction, + date: transaction.date, + entryId: entry.id, + createdAt: transaction.createdAt, + costAccountId: entry.costAccountId, + + warehouseId: entry.warehouseId || transaction.warehouseId, + meta: { + transactionNumber: transaction.transactionNumber, + description: entry.description, + }, + })); +} diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/inventory/InvoiceInventoryTransactions.ts b/packages/server-nest/src/modules/SaleInvoices/commands/inventory/InvoiceInventoryTransactions.ts index a5c75e1ff..b322fb477 100644 --- a/packages/server-nest/src/modules/SaleInvoices/commands/inventory/InvoiceInventoryTransactions.ts +++ b/packages/server-nest/src/modules/SaleInvoices/commands/inventory/InvoiceInventoryTransactions.ts @@ -1,4 +1,4 @@ -import { InventoryService } from '@/modules/InventoryCost/Inventory'; +import { InventoryTransactionsService } from '@/modules/InventoryCost/InventoryTransactions.service'; import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service'; import { Injectable } from '@nestjs/common'; import { Knex } from 'knex'; @@ -8,7 +8,7 @@ import { SaleInvoice } from '../../models/SaleInvoice'; export class InvoiceInventoryTransactions { constructor( private readonly itemsEntriesService: ItemsEntriesService, - private readonly inventoryService: InventoryService, + private readonly inventoryService: InventoryTransactionsService, ) {} /** diff --git a/packages/server-nest/src/modules/VendorCredit/commands/VendorCreditInventoryTransactions.ts b/packages/server-nest/src/modules/VendorCredit/commands/VendorCreditInventoryTransactions.ts index 5527fcb61..c92ec751d 100644 --- a/packages/server-nest/src/modules/VendorCredit/commands/VendorCreditInventoryTransactions.ts +++ b/packages/server-nest/src/modules/VendorCredit/commands/VendorCreditInventoryTransactions.ts @@ -1,13 +1,13 @@ import { Knex } from 'knex'; import { Injectable } from '@nestjs/common'; import { VendorCredit } from '../models/VendorCredit'; -import { InventoryService } from '@/modules/InventoryCost/Inventory'; +import { InventoryTransactionsService } from '@/modules/InventoryCost/InventoryTransactions.service'; import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service'; @Injectable() export class VendorCreditInventoryTransactions { constructor( - private readonly inventoryService: InventoryService, + private readonly inventoryService: InventoryTransactionsService, private readonly itemsEntriesService: ItemsEntriesService ) {} diff --git a/packages/server-nest/src/modules/Vendors/Vendors.module.ts b/packages/server-nest/src/modules/Vendors/Vendors.module.ts index e49c879c2..456fbe87e 100644 --- a/packages/server-nest/src/modules/Vendors/Vendors.module.ts +++ b/packages/server-nest/src/modules/Vendors/Vendors.module.ts @@ -12,9 +12,11 @@ import { VendorValidators } from './commands/VendorValidators'; import { VendorsApplication } from './VendorsApplication.service'; import { TenancyContext } from '../Tenancy/TenancyContext.service'; import { VendorsController } from './Vendors.controller'; +import { GetVendorsService } from './queries/GetVendors.service'; +import { DynamicListModule } from '../DynamicListing/DynamicList.module'; @Module({ - imports: [TenancyDatabaseModule], + imports: [TenancyDatabaseModule, DynamicListModule], controllers: [VendorsController], providers: [ ActivateVendorService, @@ -23,6 +25,7 @@ import { VendorsController } from './Vendors.controller'; EditVendorService, EditOpeningBalanceVendorService, GetVendorService, + GetVendorsService, VendorValidators, DeleteVendorService, VendorsApplication,