mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 20:30:33 +00:00
refactor: inventory cost to nestjs
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
"@types/ramda": "^0.30.2",
|
||||
"accounting": "^0.4.1",
|
||||
"async": "^3.2.0",
|
||||
"async-mutex": "^0.5.0",
|
||||
"axios": "^1.6.0",
|
||||
"bluebird": "^3.7.2",
|
||||
"bull": "^4.16.3",
|
||||
|
||||
5
packages/server-nest/src/common/config/inventory.ts
Normal file
5
packages/server-nest/src/common/config/inventory.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { registerAs } from "@nestjs/config";
|
||||
|
||||
export default registerAs('inventory', () => ({
|
||||
scheduleComputeItemCost: process.env.INVENTORY_SCHEDULE_COMPUTE_ITEM_COST,
|
||||
}));
|
||||
@@ -3,7 +3,7 @@ import { Knex } from 'knex';
|
||||
import { Bill } from '../models/Bill';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/InventoryTransactions.service';
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/commands/InventoryTransactions.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
|
||||
@@ -51,22 +51,22 @@ import { FeaturesModule } from '../Features/Features.module';
|
||||
BranchCommandValidator,
|
||||
BranchTransactionDTOTransformer,
|
||||
ManualJournalBranchesDTOTransformer,
|
||||
// BillBranchValidateSubscriber,
|
||||
// CreditNoteBranchValidateSubscriber,
|
||||
// CreditNoteRefundBranchValidateSubscriber,
|
||||
// ContactBranchValidateSubscriber,
|
||||
// ExpenseBranchValidateSubscriber,
|
||||
// InventoryAdjustmentBranchValidateSubscriber,
|
||||
// ManualJournalBranchValidateSubscriber,
|
||||
// PaymentMadeBranchValidateSubscriber,
|
||||
// PaymentReceiveBranchValidateSubscriber,
|
||||
// SaleEstimateBranchValidateSubscriber,
|
||||
// SaleReceiptBranchValidateSubscriber,
|
||||
// VendorCreditBranchValidateSubscriber,
|
||||
// ValidateBranchExistance,
|
||||
// ManualJournalBranchesValidator,
|
||||
// CashflowTransactionsActivateBranches,
|
||||
// ExpensesActivateBranches
|
||||
BillBranchValidateSubscriber,
|
||||
CreditNoteBranchValidateSubscriber,
|
||||
CreditNoteRefundBranchValidateSubscriber,
|
||||
ContactBranchValidateSubscriber,
|
||||
ExpenseBranchValidateSubscriber,
|
||||
InventoryAdjustmentBranchValidateSubscriber,
|
||||
ManualJournalBranchValidateSubscriber,
|
||||
PaymentMadeBranchValidateSubscriber,
|
||||
PaymentReceiveBranchValidateSubscriber,
|
||||
SaleEstimateBranchValidateSubscriber,
|
||||
SaleReceiptBranchValidateSubscriber,
|
||||
VendorCreditBranchValidateSubscriber,
|
||||
ValidateBranchExistance,
|
||||
ManualJournalBranchesValidator,
|
||||
CashflowTransactionsActivateBranches,
|
||||
ExpensesActivateBranches
|
||||
],
|
||||
exports: [
|
||||
BranchesSettingsService,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { BankTransaction } from '@/modules/BankingTransactions/models/BankTransaction';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CashflowTransactionsActivateBranches {
|
||||
constructor(
|
||||
@Inject(BankTransaction.name)
|
||||
private readonly bankTransaction: TenantModelProxy<typeof BankTransaction>,
|
||||
) {}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { Expense } from '@/modules/Expenses/models/Expense.model';
|
||||
|
||||
@Injectable()
|
||||
export class ExpensesActivateBranches {
|
||||
constructor(
|
||||
@Inject(Expense.name)
|
||||
private readonly expenseModel: TenantModelProxy<typeof Expense>,
|
||||
) {}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/InventoryTransactions.service';
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/commands/InventoryTransactions.service';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
import { CreditNote } from '../models/CreditNote';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Injectable } from "@nestjs/common";
|
||||
import { Knex } from "knex";
|
||||
import { InventoryAdjustment } from "../models/InventoryAdjustment";
|
||||
import { InventoryTransaction } from "@/modules/InventoryCost/models/InventoryTransaction";
|
||||
import { InventoryTransactionsService } from "@/modules/InventoryCost/InventoryTransactions.service";
|
||||
import { InventoryTransactionsService } from "@/modules/InventoryCost/commands/InventoryTransactions.service";
|
||||
|
||||
@Injectable()
|
||||
export class InventoryAdjustmentInventoryTransactions {
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
// 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,
|
||||
|
||||
// @Inject(InventoryTransaction.name)
|
||||
// private readonly inventoryTransactionModel: typeof InventoryTransaction,
|
||||
|
||||
// @Inject(InventoryCostLotTracker.name)
|
||||
// private readonly inventoryCostLotTracker: typeof InventoryCostLotTracker,
|
||||
|
||||
// @Inject(SETTINGS_PROVIDER)
|
||||
// private readonly settings: SettingsStore,
|
||||
// ) {}
|
||||
|
||||
// /**
|
||||
// * Transforms the items entries to inventory transactions.
|
||||
// */
|
||||
// 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,
|
||||
// },
|
||||
// }));
|
||||
// }
|
||||
|
||||
// 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);
|
||||
|
||||
// // 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();
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 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(),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// /**
|
||||
// * 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
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
@@ -1,254 +0,0 @@
|
||||
// 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;
|
||||
|
||||
// /**
|
||||
// * 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 = [];
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 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');
|
||||
|
||||
// // 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);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 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<any> = InventoryCostLotTracker.query()
|
||||
// .onBuild(commonBuilder)
|
||||
// .where('direction', 'IN');
|
||||
|
||||
// // Calculates the total inventory total quantity and rate `OUT` transactions.
|
||||
// const outInvSumationOper: Promise<any> = 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,
|
||||
// );
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 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;
|
||||
|
||||
// const averageCost = openingQuantity ? openingCost / openingQuantity : 0;
|
||||
|
||||
// return { averageCost, openingCost, openingQuantity };
|
||||
// }
|
||||
|
||||
// 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[] = [];
|
||||
|
||||
// // 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// // 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);
|
||||
|
||||
// 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;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Reverts the inventory lots `OUT` transactions.
|
||||
// * @param {Date} openingDate - Opening date.
|
||||
// * @param {number} itemId - Item id.
|
||||
// * @returns {Promise<void>}
|
||||
// */
|
||||
// async revertTheInventoryOutLotTrans(): Promise<void> {
|
||||
// const { InventoryCostLotTracker } = this.tenantModels;
|
||||
|
||||
// await InventoryCostLotTracker.query(this.trx)
|
||||
// .modify('filterDateRange', this.startingDate)
|
||||
// .orderBy('date', 'DESC')
|
||||
// .where('item_id', this.itemId)
|
||||
// .delete();
|
||||
// }
|
||||
// }
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { InventoryCostGLStorage } from './InventoryCostGLStorage.service';
|
||||
import { InventoryCostGLStorage } from './commands/InventoryCostGLStorage.service';
|
||||
import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module';
|
||||
import { InventoryCostLotTracker } from './models/InventoryCostLotTracker';
|
||||
import { InventoryTransaction } from './models/InventoryTransaction';
|
||||
import { InventoryCostGLBeforeWriteSubscriber } from './subscribers/InventoryCostGLBeforeWriteSubscriber';
|
||||
import { InventoryItemsQuantitySyncService } from './InventoryItemsQuantitySync.service';
|
||||
import { InventoryCostMethod } from './InventoryCostMethod';
|
||||
import { InventoryTransactionsService } from './InventoryTransactions.service';
|
||||
import { InventoryItemsQuantitySyncService } from './commands/InventoryItemsQuantitySync.service';
|
||||
import { InventoryTransactionsService } from './commands/InventoryTransactions.service';
|
||||
import { LedgerModule } from '../Ledger/Ledger.module';
|
||||
import { InventoryComputeCostService } from './commands/InventoryComputeCost.service';
|
||||
|
||||
const models = [
|
||||
RegisterTenancyModel(InventoryCostLotTracker),
|
||||
@@ -20,8 +20,8 @@ const models = [
|
||||
InventoryCostGLBeforeWriteSubscriber,
|
||||
InventoryCostGLStorage,
|
||||
InventoryItemsQuantitySyncService,
|
||||
InventoryCostMethod,
|
||||
InventoryTransactionsService,
|
||||
InventoryComputeCostService,
|
||||
],
|
||||
exports: [...models, InventoryTransactionsService],
|
||||
})
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
// import { InventoryItemCostService } from './InventoryCosts.service';
|
||||
import { IInventoryItemCostMeta } from './types/InventoryCost.types';
|
||||
import { InventoryItemCostService } from './commands/InventoryCosts.service';
|
||||
|
||||
@Injectable()
|
||||
export class InventoryCostApplication {
|
||||
constructor(
|
||||
// private readonly inventoryCost: InventoryItemCostService,
|
||||
) {}
|
||||
constructor(private readonly inventoryCost: InventoryItemCostService) {}
|
||||
|
||||
/**
|
||||
* Computes the item cost.
|
||||
* @param {Date} fromDate - From date.
|
||||
* @param {number} itemId - Item id.
|
||||
* @returns {Promise<Map<number, IInventoryItemCostMeta>>}
|
||||
*/
|
||||
computeItemCost(fromDate: Date, itemId: number) {
|
||||
return this.inventoryCost.getItemsInventoryValuation([itemId], fromDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the items inventory valuation list.
|
||||
@@ -14,14 +21,14 @@ export class InventoryCostApplication {
|
||||
* @param {Date} date
|
||||
* @returns {Promise<IInventoryItemCostMeta[]>}
|
||||
*/
|
||||
public getItemsInventoryValuationList = async (
|
||||
async getItemsInventoryValuation(
|
||||
itemsId: number[],
|
||||
date: Date
|
||||
): Promise<any> => {
|
||||
// const itemsMap = await this.inventoryCost.getItemsInventoryValuation(
|
||||
// itemsId,
|
||||
// date
|
||||
// );
|
||||
// return [...itemsMap.values()];
|
||||
};
|
||||
date: Date,
|
||||
): Promise<any> {
|
||||
const itemsMap = await this.inventoryCost.getItemsInventoryValuation(
|
||||
itemsId,
|
||||
date,
|
||||
);
|
||||
return [...itemsMap.values()];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,302 +0,0 @@
|
||||
// import { pick, chain } from 'lodash';
|
||||
// import moment from 'moment';
|
||||
// import { IInventoryLotCost, IInventoryTransaction } from "interfaces";
|
||||
// import InventoryCostMethod from '@/services/Inventory/InventoryCostMethod';
|
||||
|
||||
// type TCostMethod = 'FIFO' | 'LIFO';
|
||||
|
||||
// export class InventoryCostLotTracker extends InventoryCostMethod {
|
||||
// startingDate: Date;
|
||||
// itemId: number;
|
||||
// costMethod: TCostMethod;
|
||||
// itemsById: Map<number, any>;
|
||||
// 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);
|
||||
|
||||
// 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 = [];
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 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<any> {
|
||||
// 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);
|
||||
|
||||
// // 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;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
|
||||
// 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 ];
|
||||
// }
|
||||
|
||||
// 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]));
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 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;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 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();
|
||||
|
||||
// inventoryLotsTrans.forEach((inventoryLot: IInventoryLotCost) => {
|
||||
// if (!inventoryLot.lotNumber) { return; }
|
||||
|
||||
// const incrementOper = InventoryLotCostTracker.query()
|
||||
// .where('lot_number', inventoryLot.lotNumber)
|
||||
// .where('direction', 'IN')
|
||||
// .increment('remaining', inventoryLot.quantity);
|
||||
|
||||
// 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] = []));
|
||||
|
||||
// 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] = []));
|
||||
|
||||
// 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];
|
||||
|
||||
// // 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;
|
||||
|
||||
// _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);
|
||||
// });
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 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);
|
||||
// }
|
||||
// }
|
||||
@@ -1,149 +0,0 @@
|
||||
// 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,
|
||||
|
||||
// @Inject(InventoryCostLotTracker.name)
|
||||
// private readonly inventoryCostLotTrackerModel: typeof InventoryCostLotTracker,
|
||||
|
||||
// @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');
|
||||
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
|
||||
// return { itemId, valuation, quantity, average };
|
||||
// }
|
||||
// );
|
||||
|
||||
// /**
|
||||
// *
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} itemsId
|
||||
// * @param {Date} date
|
||||
// * @returns
|
||||
// */
|
||||
// private getItemsInventoryINAndOutAggregated = (
|
||||
// itemsId: number[],
|
||||
// date: Date
|
||||
// ): Promise<any> => {
|
||||
|
||||
// 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');
|
||||
|
||||
// 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);
|
||||
|
||||
// const OUTValuationMap = keyBy(OUTValuation, 'itemId');
|
||||
// const INValuationMap = keyBy(INValuation, 'itemId');
|
||||
|
||||
// return [OUTValuationMap, INValuationMap];
|
||||
// };
|
||||
|
||||
// /**
|
||||
// *
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} itemId
|
||||
// * @param {Date} date
|
||||
// * @returns {Promise<Map<number, IInventoryItemCostMeta>>}
|
||||
// */
|
||||
// public getItemsInventoryValuation = async (
|
||||
// itemsId: number[],
|
||||
// date: Date
|
||||
// ): Promise<Map<number, IInventoryItemCostMeta>> => {
|
||||
// // 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);
|
||||
|
||||
// // 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;
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,97 @@
|
||||
import { pick } from 'lodash';
|
||||
import { Knex } from 'knex';
|
||||
import { InventoryTransaction } from '../models/InventoryTransaction';
|
||||
import { InventoryItemOpeningAvgCostService } from './InventoryItemOpeningAvgCost.service';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { InventoryAverageCostMethod } from './InventoryAverageCostMethod';
|
||||
import { StoreInventoryLotsCostService } from './StoreInventortyLotsCost.service';
|
||||
import { TenantModelProxy } from '../../System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class InventoryAverageCostMethodService {
|
||||
constructor(
|
||||
private readonly itemOpeningAvgCostService: InventoryItemOpeningAvgCostService,
|
||||
private readonly storeInventoryLotsCostService: StoreInventoryLotsCostService,
|
||||
|
||||
@Inject(InventoryTransaction.name)
|
||||
private readonly inventoryTransactionModel: TenantModelProxy<
|
||||
typeof InventoryTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieves the inventory cost lots.
|
||||
* @param {Date} startingDate
|
||||
* @param {number} itemId
|
||||
* @param {number} openingQuantity
|
||||
* @param {number} openingCost
|
||||
* @returns {Promise<any[]>}
|
||||
*/
|
||||
async getInventoryCostLots(
|
||||
startingDate: Date,
|
||||
itemId: number,
|
||||
openingQuantity: number,
|
||||
openingCost: number,
|
||||
) {
|
||||
const afterInvTransactions = await this.inventoryTransactionModel()
|
||||
.query()
|
||||
.modify('filterDateRange', startingDate)
|
||||
.orderBy('date', 'ASC')
|
||||
.orderByRaw("FIELD(direction, 'IN', 'OUT')")
|
||||
.orderBy('createdAt', 'ASC')
|
||||
.where('item_id', itemId)
|
||||
.withGraphFetched('item');
|
||||
|
||||
const avgCostTracker = new InventoryAverageCostMethod();
|
||||
|
||||
// Tracking inventroy transactions and retrieve cost transactions based on
|
||||
// average rate cost method.
|
||||
return avgCostTracker.trackingCostTransactions(
|
||||
afterInvTransactions,
|
||||
openingQuantity,
|
||||
openingCost,
|
||||
);
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
* ----------
|
||||
* @param {Date} startingDate
|
||||
* @param {number} itemId
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public async computeItemCost(
|
||||
startingDate: Date,
|
||||
itemId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
const { openingQuantity, openingCost } =
|
||||
await this.itemOpeningAvgCostService.getOpeningAverageCost(
|
||||
startingDate,
|
||||
itemId,
|
||||
);
|
||||
// Retrieves the new calculated inventory cost lots.
|
||||
const inventoryCostLots = await this.getInventoryCostLots(
|
||||
startingDate,
|
||||
itemId,
|
||||
openingQuantity,
|
||||
openingCost,
|
||||
);
|
||||
// Revert the inveout out lots transactions
|
||||
await this.storeInventoryLotsCostService.revertInventoryCostLotTransactions(
|
||||
startingDate,
|
||||
itemId,
|
||||
trx,
|
||||
);
|
||||
// Store inventory lots cost transactions.
|
||||
await this.storeInventoryLotsCostService.storeInventoryLotsCost(
|
||||
inventoryCostLots,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import { pick } from 'lodash';
|
||||
import { Knex } from 'knex';
|
||||
import { InventoryTransaction } from '../models/InventoryTransaction';
|
||||
|
||||
export class InventoryAverageCostMethod {
|
||||
/**
|
||||
* Constructor method.
|
||||
* @param {number} tenantId - The given tenant id.
|
||||
* @param {Date} startingDate -
|
||||
* @param {number} itemId - The given inventory item id.
|
||||
*/
|
||||
constructor() {}
|
||||
|
||||
/**
|
||||
* Computes the cost of the given rate and quantity.
|
||||
* @param {number} rate - The given rate.
|
||||
* @param {number} quantity - The given quantity.
|
||||
* @returns {number}
|
||||
*/
|
||||
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[] = [];
|
||||
|
||||
// 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;
|
||||
|
||||
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;
|
||||
|
||||
// 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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
import { pick } from 'lodash';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
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 { InventoryTransaction } from '../models/InventoryTransaction';
|
||||
import { IItemEntryTransactionType } from '../../TransactionItemEntry/ItemEntry.types';
|
||||
import { ModelObject } from 'objection';
|
||||
import { ItemEntry } from '../../TransactionItemEntry/models/ItemEntry';
|
||||
import { TInventoryTransactionDirection } from '../types/InventoryCost.types';
|
||||
import { InventoryAverageCostMethodService } from './InventoryAverageCostMethod.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class InventoryComputeCostService {
|
||||
constructor(
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly inventoryAverageCostMethod: InventoryAverageCostMethodService,
|
||||
|
||||
@Inject(Item.name)
|
||||
private readonly itemModel: TenantModelProxy<typeof Item>,
|
||||
|
||||
@Inject(SETTINGS_PROVIDER)
|
||||
private readonly settingsStore: () => SettingsStore,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Compute item cost.
|
||||
* @param {Date} fromDate - From date.
|
||||
* @param {number} itemId - Item id.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async computeItemCost(fromDate: Date, itemId: number) {
|
||||
return this.uow.withTransaction((trx: Knex.Transaction) => {
|
||||
return this.computeInventoryItemCost(fromDate, itemId, trx);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param {Knex.Transaction} trx - Knex transaction.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async computeInventoryItemCost(
|
||||
fromDate: Date,
|
||||
itemId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
// Fetches the item with associated item category.
|
||||
const item = await this.itemModel().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.');
|
||||
}
|
||||
return this.inventoryAverageCostMethod.computeItemCost(
|
||||
fromDate,
|
||||
itemId,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(
|
||||
// this.config.get('inventory.scheduleComputeItemCost'),
|
||||
// 'compute-item-cost',
|
||||
// {
|
||||
// startingDate,
|
||||
// itemId,
|
||||
// tenantId,
|
||||
// },
|
||||
// );
|
||||
// // Triggers `onComputeItemCostJobScheduled` event.
|
||||
// await this.eventEmitter.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(this.config.get('inventory.scheduleComputeItemCost'))
|
||||
// .save(),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark item cost computing is running.
|
||||
* @param {boolean} isRunning -
|
||||
*/
|
||||
async markItemsCostComputeRunning(isRunning: boolean = true) {
|
||||
const settings = await this.settingsStore();
|
||||
|
||||
settings.set({
|
||||
key: 'cost_compute_running',
|
||||
group: 'inventory',
|
||||
value: isRunning,
|
||||
});
|
||||
await settings.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the items cost compute is running.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
async isItemsCostComputeRunning() {
|
||||
const settings = await this.settingsStore();
|
||||
|
||||
return (
|
||||
settings.get({
|
||||
key: 'cost_compute_running',
|
||||
group: 'inventory',
|
||||
}) ?? false
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { LedgerStorageService } from '../Ledger/LedgerStorage.service';
|
||||
import { Ledger } from '../Ledger/Ledger';
|
||||
import { AccountTransaction } from '../Accounts/models/AccountTransaction.model';
|
||||
import { LedgerStorageService } from '../../Ledger/LedgerStorage.service';
|
||||
import { Ledger } from '../../Ledger/Ledger';
|
||||
import { AccountTransaction } from '../../Accounts/models/AccountTransaction.model';
|
||||
import { TenantModelProxy } from '../../System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class InventoryCostGLStorage {
|
||||
@@ -10,7 +11,9 @@ export class InventoryCostGLStorage {
|
||||
private readonly ledgerStorage: LedgerStorageService,
|
||||
|
||||
@Inject(AccountTransaction.name)
|
||||
private readonly accountTransactionModel: typeof AccountTransaction,
|
||||
private readonly accountTransactionModel: TenantModelProxy<
|
||||
typeof AccountTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -23,7 +26,7 @@ export class InventoryCostGLStorage {
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> {
|
||||
// Retrieve transactions from specific date range and costable transactions only.
|
||||
const transactions = await this.accountTransactionModel
|
||||
const transactions = await this.accountTransactionModel()
|
||||
.query()
|
||||
.where('costable', true)
|
||||
.modify('filterDateRange', startingDate)
|
||||
@@ -0,0 +1,135 @@
|
||||
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,
|
||||
|
||||
@Inject(InventoryCostLotTracker.name)
|
||||
private readonly inventoryCostLotTrackerModel: typeof InventoryCostLotTracker,
|
||||
|
||||
@Inject(Item.name)
|
||||
private readonly itemModel: typeof Item,
|
||||
) {}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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 valuation = INCost - OUTCost;
|
||||
const quantity = INQuantity - OUTQuantity;
|
||||
const average = quantity ? valuation / quantity : 0;
|
||||
|
||||
return { itemId, valuation, quantity, average };
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} tenantId
|
||||
* @param {number} itemsId
|
||||
* @param {Date} date
|
||||
* @returns
|
||||
*/
|
||||
private getItemsInventoryINAndOutAggregated = (
|
||||
itemsId: number[],
|
||||
date: Date,
|
||||
): Promise<any> => {
|
||||
const commonBuilder = (builder: Knex.QueryBuilder) => {
|
||||
if (date) {
|
||||
builder.where('date', '<', date);
|
||||
}
|
||||
builder.whereIn('item_id', itemsId);
|
||||
builder.sum('rate as rate');
|
||||
builder.sum('quantity as quantity');
|
||||
builder.sum('cost as cost');
|
||||
|
||||
builder.groupBy('item_id');
|
||||
builder.select(['item_id']);
|
||||
};
|
||||
const INValuationOper = this.inventoryCostLotTrackerModel
|
||||
.query()
|
||||
.onBuild(commonBuilder)
|
||||
.where('direction', 'IN');
|
||||
|
||||
const OUTValuationOper = this.inventoryCostLotTrackerModel
|
||||
.query()
|
||||
.onBuild(commonBuilder)
|
||||
.where('direction', 'OUT');
|
||||
|
||||
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);
|
||||
|
||||
const OUTValuationMap = keyBy(OUTValuation, 'itemId');
|
||||
const INValuationMap = keyBy(INValuation, 'itemId');
|
||||
|
||||
return [OUTValuationMap, INValuationMap];
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} tenantId
|
||||
* @param {number} itemId
|
||||
* @param {Date} date
|
||||
* @returns {Promise<Map<number, IInventoryItemCostMeta>>}
|
||||
*/
|
||||
public getItemsInventoryValuation = async (
|
||||
itemsId: number[],
|
||||
date: Date,
|
||||
): Promise<Map<number, IInventoryItemCostMeta>> => {
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { TenantModelProxy } from '../../System/models/TenantBaseModel';
|
||||
import { InventoryCostLotTracker } from '../models/InventoryCostLotTracker';
|
||||
|
||||
@Injectable()
|
||||
export class InventoryItemOpeningAvgCostService {
|
||||
constructor(
|
||||
private readonly inventoryCostLotTrackerModel: TenantModelProxy<
|
||||
typeof InventoryCostLotTracker
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Get items Average cost from specific date from inventory transactions.
|
||||
* @param {Date} closingDate - Closing date.
|
||||
* @param {number} itemId - Item id.
|
||||
* @return {Promise<{
|
||||
* averageCost: number,
|
||||
* openingCost: number,
|
||||
* openingQuantity: number,
|
||||
* }>}
|
||||
*/
|
||||
public async getOpeningAverageCost(closingDate: Date, itemId: number) {
|
||||
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 = this.inventoryCostLotTrackerModel()
|
||||
.query()
|
||||
.onBuild(commonBuilder)
|
||||
.where('direction', 'IN');
|
||||
|
||||
// Calculates the total inventory total quantity and rate `OUT` transactions.
|
||||
const outInvSumationOper = this.inventoryCostLotTrackerModel()
|
||||
.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,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
const averageCost = openingQuantity ? openingCost / openingQuantity : 0;
|
||||
|
||||
return { averageCost, openingCost, openingQuantity };
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { toSafeInteger } from 'lodash';
|
||||
import { IItemsQuantityChanges } from './types/InventoryCost.types';
|
||||
import { IItemsQuantityChanges } from '../types/InventoryCost.types';
|
||||
import { Knex } from 'knex';
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { Item } from '../Items/models/Item';
|
||||
import { Item } from '../../Items/models/Item';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InventoryTransaction } from './models/InventoryTransaction';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
import { InventoryTransaction } from '../models/InventoryTransaction';
|
||||
import { TenantModelProxy } from '../../System/models/TenantBaseModel';
|
||||
|
||||
/**
|
||||
* Syncs the inventory transactions with inventory items quantity.
|
||||
@@ -5,14 +5,14 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
IInventoryTransactionsDeletedPayload,
|
||||
TInventoryTransactionDirection,
|
||||
} from './types/InventoryCost.types';
|
||||
import { InventoryCostLotTracker } from './models/InventoryCostLotTracker';
|
||||
import { InventoryTransaction } from './models/InventoryTransaction';
|
||||
} from '../types/InventoryCost.types';
|
||||
import { InventoryCostLotTracker } from '../models/InventoryCostLotTracker';
|
||||
import { InventoryTransaction } from '../models/InventoryTransaction';
|
||||
import { events } from '@/common/events/events';
|
||||
import { IInventoryTransactionsCreatedPayload } from './types/InventoryCost.types';
|
||||
import { transformItemEntriesToInventory } from './utils';
|
||||
import { IItemEntryTransactionType } from '../TransactionItemEntry/ItemEntry.types';
|
||||
import { ItemEntry } from '../TransactionItemEntry/models/ItemEntry';
|
||||
import { IInventoryTransactionsCreatedPayload } from '../types/InventoryCost.types';
|
||||
import { transformItemEntriesToInventory } from '../utils';
|
||||
import { IItemEntryTransactionType } from '../../TransactionItemEntry/ItemEntry.types';
|
||||
import { ItemEntry } from '../../TransactionItemEntry/models/ItemEntry';
|
||||
|
||||
export class InventoryTransactionsService {
|
||||
constructor(
|
||||
@@ -82,7 +82,6 @@ export class InventoryTransactionsService {
|
||||
|
||||
/**
|
||||
* Records the inventory transactions from items entries that have (inventory) type.
|
||||
*
|
||||
* @param {number} tenantId
|
||||
* @param {number} transactionId
|
||||
* @param {string} transactionType
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { omit } from 'lodash';
|
||||
import { InventoryCostLotTracker } from './models/InventoryCostLotTracker';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
import { InventoryCostLotTracker } from '../models/InventoryCostLotTracker';
|
||||
import { TenantModelProxy } from '../../System/models/TenantBaseModel';
|
||||
|
||||
export class InventoryCostMethod {
|
||||
@Injectable()
|
||||
export class StoreInventoryLotsCostService {
|
||||
constructor(
|
||||
@Inject(InventoryCostLotTracker.name)
|
||||
private readonly inventoryCostLotTracker: TenantModelProxy<
|
||||
@@ -20,7 +21,7 @@ export class InventoryCostMethod {
|
||||
*/
|
||||
public storeInventoryLotsCost(
|
||||
costLotsTransactions: InventoryCostLotTracker[],
|
||||
trx: Knex.Transaction,
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<object> {
|
||||
const opers: any = [];
|
||||
|
||||
@@ -43,4 +44,24 @@ export class InventoryCostMethod {
|
||||
});
|
||||
return Promise.all(opers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts the inventory lots `OUT` transactions.
|
||||
* @param {Date} startingDate - Starting date.
|
||||
* @param {number} itemId - Item id.
|
||||
* @param {Knex.Transaction} trx - Knex transaction.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async revertInventoryCostLotTransactions(
|
||||
startingDate: Date,
|
||||
itemId: number,
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> {
|
||||
await this.inventoryCostLotTracker()
|
||||
.query(trx)
|
||||
.modify('filterDateRange', startingDate)
|
||||
.orderBy('date', 'DESC')
|
||||
.where('item_id', itemId)
|
||||
.delete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { JOB_REF, Processor } from '@nestjs/bullmq';
|
||||
import { Inject, Scope } from '@nestjs/common';
|
||||
import { Job } from 'bullmq';
|
||||
import { ClsService } from 'nestjs-cls';
|
||||
import { TenantJobPayload } from '@/interfaces/Tenant';
|
||||
import { InventoryComputeCostService } from '../commands/InventoryComputeCost.service';
|
||||
|
||||
interface ComputeItemCostJobPayload extends TenantJobPayload {
|
||||
itemId: number;
|
||||
startingDate: Date;
|
||||
}
|
||||
|
||||
@Processor({
|
||||
name: 'compute-item-cost',
|
||||
scope: Scope.REQUEST,
|
||||
})
|
||||
export class ComputeItemCostProcessor {
|
||||
constructor(
|
||||
private readonly inventoryComputeCostService: InventoryComputeCostService,
|
||||
private readonly clsService: ClsService,
|
||||
|
||||
@Inject(JOB_REF)
|
||||
private readonly jobRef: Job<ComputeItemCostJobPayload>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Handle compute item cost job.
|
||||
*/
|
||||
async handleComputeItemCost() {
|
||||
const { itemId, startingDate, organizationId, userId } = this.jobRef.data;
|
||||
|
||||
this.clsService.set('organizationId', organizationId);
|
||||
this.clsService.set('userId', userId);
|
||||
|
||||
await this.inventoryComputeCostService.computeItemCost(
|
||||
startingDate,
|
||||
itemId,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { IInventoryCostLotsGLEntriesWriteEvent } from '../types/InventoryCost.types';
|
||||
import { InventoryCostGLStorage } from '../InventoryCostGLStorage.service';
|
||||
import { InventoryCostGLStorage } from '../commands/InventoryCostGLStorage.service';
|
||||
|
||||
@Injectable()
|
||||
export class InventoryCostGLBeforeWriteSubscriber {
|
||||
@@ -21,7 +21,7 @@ export class InventoryCostGLBeforeWriteSubscriber {
|
||||
}: IInventoryCostLotsGLEntriesWriteEvent) {
|
||||
await this.inventoryCostGLStorage.revertInventoryCostGLEntries(
|
||||
startingDate,
|
||||
trx
|
||||
trx,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ItemEntry } from '../TransactionItemEntry/models/ItemEntry';
|
||||
import { ServiceError } from './ServiceError';
|
||||
import { IItemEntryDTO } from '../TransactionItemEntry/ItemEntry.types';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
import { entriesAmountDiff } from '@/utils/entries-amount-diff';
|
||||
|
||||
const ERRORS = {
|
||||
ITEMS_NOT_FOUND: 'ITEMS_NOT_FOUND',
|
||||
@@ -176,21 +177,21 @@ export class ItemsEntriesService {
|
||||
): Promise<void> {
|
||||
const opers = [];
|
||||
|
||||
// const diffEntries = entriesAmountDiff(
|
||||
// entries,
|
||||
// oldEntries,
|
||||
// 'quantity',
|
||||
// 'itemId',
|
||||
// );
|
||||
// diffEntries.forEach((entry: ItemEntry) => {
|
||||
// const changeQuantityOper = this.itemRepository.changeNumber(
|
||||
// { id: entry.itemId, type: 'inventory' },
|
||||
// 'quantityOnHand',
|
||||
// entry.quantity,
|
||||
// );
|
||||
// opers.push(changeQuantityOper);
|
||||
// });
|
||||
// await Promise.all(opers);
|
||||
const diffEntries = entriesAmountDiff(
|
||||
entries,
|
||||
oldEntries,
|
||||
'quantity',
|
||||
'itemId',
|
||||
);
|
||||
diffEntries.forEach((entry: ItemEntry) => {
|
||||
const changeQuantityOper = this.itemModel()
|
||||
.query()
|
||||
.where({ id: entry.itemId, type: 'inventory' })
|
||||
.modify('quantityOnHand', entry.quantity);
|
||||
|
||||
opers.push(changeQuantityOper);
|
||||
});
|
||||
await Promise.all(opers);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,6 +22,8 @@ export class Item extends TenantBaseModel{
|
||||
public readonly landedCost: boolean;
|
||||
public readonly note: string;
|
||||
public readonly userId: number;
|
||||
public readonly sellTaxRateId: number;
|
||||
public readonly purchaseTaxRateId: number;
|
||||
|
||||
public readonly warehouse!: Warehouse;
|
||||
|
||||
|
||||
@@ -1,161 +1,149 @@
|
||||
// import { Mutex } from 'async-mutex';
|
||||
// import { Container, Service, Inject } from 'typedi';
|
||||
// import { chain } from 'lodash';
|
||||
// import moment from 'moment';
|
||||
// import { Knex } from 'knex';
|
||||
// import InventoryService from '@/services/Inventory/Inventory';
|
||||
// import {
|
||||
// IInventoryCostLotsGLEntriesWriteEvent,
|
||||
// IInventoryTransaction,
|
||||
// } from '@/interfaces';
|
||||
// import UnitOfWork from '@/services/UnitOfWork';
|
||||
// import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
// import events from '@/subscribers/events';
|
||||
import { Mutex } from 'async-mutex';
|
||||
import { chain } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { Knex } from 'knex';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { ModelObject } from 'objection';
|
||||
import { InventoryTransaction } from '../InventoryCost/models/InventoryTransaction';
|
||||
import { IInventoryCostLotsGLEntriesWriteEvent } from '../InventoryCost/types/InventoryCost.types';
|
||||
|
||||
// @Service()
|
||||
// export class SaleInvoicesCost {
|
||||
// @Inject()
|
||||
// private inventoryService: InventoryService;
|
||||
@Injectable()
|
||||
export class SaleInvoicesCost {
|
||||
constructor(
|
||||
private readonly inventoryService: InventoryService,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
) {}
|
||||
|
||||
// @Inject()
|
||||
// private uow: UnitOfWork;
|
||||
/**
|
||||
* Schedule sale invoice re-compute based on the item
|
||||
* cost method and starting date.
|
||||
* @param {number[]} itemIds - Inventory items ids.
|
||||
* @param {Date} startingDate - Starting compute cost date.
|
||||
* @return {Promise<Agenda>}
|
||||
*/
|
||||
async scheduleComputeCostByItemsIds(
|
||||
inventoryItemsIds: number[],
|
||||
startingDate: Date,
|
||||
): Promise<void> {
|
||||
const mutex = new Mutex();
|
||||
const asyncOpers = inventoryItemsIds.map(
|
||||
async (inventoryItemId: number) => {
|
||||
// @todo refactor the lock acquire to be distrbuted using Redis
|
||||
// and run the cost schedule job after running invoice transaction.
|
||||
const release = await mutex.acquire();
|
||||
|
||||
// @Inject()
|
||||
// private eventPublisher: EventPublisher;
|
||||
try {
|
||||
await this.inventoryService.scheduleComputeItemCost(
|
||||
inventoryItemId,
|
||||
startingDate,
|
||||
);
|
||||
} finally {
|
||||
release();
|
||||
}
|
||||
},
|
||||
);
|
||||
await Promise.all(asyncOpers);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Schedule sale invoice re-compute based on the item
|
||||
// * cost method and starting date.
|
||||
// * @param {number[]} itemIds - Inventory items ids.
|
||||
// * @param {Date} startingDate - Starting compute cost date.
|
||||
// * @return {Promise<Agenda>}
|
||||
// */
|
||||
// async scheduleComputeCostByItemsIds(
|
||||
// tenantId: number,
|
||||
// inventoryItemsIds: number[],
|
||||
// startingDate: Date
|
||||
// ): Promise<void> {
|
||||
// const mutex = new Mutex();
|
||||
/**
|
||||
* Retrieve the max dated inventory transactions in the transactions that
|
||||
* have the same item id.
|
||||
* @param {ModelObject<InventoryTransaction>[]} inventoryTransactions
|
||||
* @return {ModelObject<InventoryTransaction>[]}
|
||||
*/
|
||||
getMaxDateInventoryTransactions(
|
||||
inventoryTransactions: ModelObject<InventoryTransaction>[],
|
||||
): ModelObject<InventoryTransaction>[] {
|
||||
return chain(inventoryTransactions)
|
||||
.reduce((acc: any, transaction) => {
|
||||
const compatatorDate = acc[transaction.itemId];
|
||||
|
||||
// const asyncOpers = inventoryItemsIds.map(
|
||||
// async (inventoryItemId: number) => {
|
||||
// // @todo refactor the lock acquire to be distrbuted using Redis
|
||||
// // and run the cost schedule job after running invoice transaction.
|
||||
// const release = await mutex.acquire();
|
||||
if (
|
||||
!compatatorDate ||
|
||||
moment(compatatorDate.date).isBefore(transaction.date)
|
||||
) {
|
||||
return {
|
||||
...acc,
|
||||
[transaction.itemId]: {
|
||||
...transaction,
|
||||
},
|
||||
};
|
||||
}
|
||||
return acc;
|
||||
}, {})
|
||||
.values()
|
||||
.value();
|
||||
}
|
||||
|
||||
// try {
|
||||
// await this.inventoryService.scheduleComputeItemCost(
|
||||
// tenantId,
|
||||
// inventoryItemId,
|
||||
// startingDate
|
||||
// );
|
||||
// } finally {
|
||||
// release();
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
// await Promise.all(asyncOpers);
|
||||
// }
|
||||
/**
|
||||
* Computes items costs by the given inventory transaction.
|
||||
* @param {number} tenantId
|
||||
* @param {IInventoryTransaction[]} inventoryTransactions
|
||||
*/
|
||||
async computeItemsCostByInventoryTransactions(
|
||||
inventoryTransactions: ModelObject<InventoryTransaction>[],
|
||||
) {
|
||||
const mutex = new Mutex();
|
||||
const reducedTransactions = this.getMaxDateInventoryTransactions(
|
||||
inventoryTransactions,
|
||||
);
|
||||
const asyncOpers = reducedTransactions.map(async (transaction) => {
|
||||
const release = await mutex.acquire();
|
||||
|
||||
// /**
|
||||
// * Retrieve the max dated inventory transactions in the transactions that
|
||||
// * have the same item id.
|
||||
// * @param {IInventoryTransaction[]} inventoryTransactions
|
||||
// * @return {IInventoryTransaction[]}
|
||||
// */
|
||||
// getMaxDateInventoryTransactions(
|
||||
// inventoryTransactions: IInventoryTransaction[]
|
||||
// ): IInventoryTransaction[] {
|
||||
// return chain(inventoryTransactions)
|
||||
// .reduce((acc: any, transaction) => {
|
||||
// const compatatorDate = acc[transaction.itemId];
|
||||
try {
|
||||
await this.inventoryService.scheduleComputeItemCost(
|
||||
transaction.itemId,
|
||||
transaction.date,
|
||||
);
|
||||
} finally {
|
||||
release();
|
||||
}
|
||||
});
|
||||
await Promise.all([...asyncOpers]);
|
||||
}
|
||||
|
||||
// if (
|
||||
// !compatatorDate ||
|
||||
// moment(compatatorDate.date).isBefore(transaction.date)
|
||||
// ) {
|
||||
// return {
|
||||
// ...acc,
|
||||
// [transaction.itemId]: {
|
||||
// ...transaction,
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
// return acc;
|
||||
// }, {})
|
||||
// .values()
|
||||
// .value();
|
||||
// }
|
||||
/**
|
||||
* Schedule writing journal entries.
|
||||
* @param {Date} startingDate - Starting date.
|
||||
* @return {Promise<agenda>}
|
||||
*/
|
||||
scheduleWriteJournalEntries(startingDate?: Date) {
|
||||
const agenda = Container.get('agenda');
|
||||
|
||||
// /**
|
||||
// * Computes items costs by the given inventory transaction.
|
||||
// * @param {number} tenantId
|
||||
// * @param {IInventoryTransaction[]} inventoryTransactions
|
||||
// */
|
||||
// async computeItemsCostByInventoryTransactions(
|
||||
// tenantId: number,
|
||||
// inventoryTransactions: IInventoryTransaction[]
|
||||
// ) {
|
||||
// const mutex = new Mutex();
|
||||
// const reducedTransactions = this.getMaxDateInventoryTransactions(
|
||||
// inventoryTransactions
|
||||
// );
|
||||
// const asyncOpers = reducedTransactions.map(async (transaction) => {
|
||||
// const release = await mutex.acquire();
|
||||
return agenda.schedule('in 3 seconds', 'rewrite-invoices-journal-entries', {
|
||||
startingDate,
|
||||
tenantId,
|
||||
});
|
||||
}
|
||||
|
||||
// try {
|
||||
// await this.inventoryService.scheduleComputeItemCost(
|
||||
// tenantId,
|
||||
// transaction.itemId,
|
||||
// transaction.date
|
||||
// );
|
||||
// } finally {
|
||||
// release();
|
||||
// }
|
||||
// });
|
||||
// await Promise.all([...asyncOpers]);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Schedule writing journal entries.
|
||||
// * @param {Date} startingDate
|
||||
// * @return {Promise<agenda>}
|
||||
// */
|
||||
// scheduleWriteJournalEntries(tenantId: number, startingDate?: Date) {
|
||||
// const agenda = Container.get('agenda');
|
||||
|
||||
// return agenda.schedule('in 3 seconds', 'rewrite-invoices-journal-entries', {
|
||||
// startingDate,
|
||||
// tenantId,
|
||||
// });
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Writes cost GL entries from the inventory cost lots.
|
||||
// * @param {number} tenantId -
|
||||
// * @param {Date} startingDate -
|
||||
// * @returns {Promise<void>}
|
||||
// */
|
||||
// public writeCostLotsGLEntries = (tenantId: number, startingDate: Date) => {
|
||||
// return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
|
||||
// // Triggers event `onInventoryCostLotsGLEntriesBeforeWrite`.
|
||||
// await this.eventPublisher.emitAsync(
|
||||
// events.inventory.onCostLotsGLEntriesBeforeWrite,
|
||||
// {
|
||||
// tenantId,
|
||||
// startingDate,
|
||||
// trx,
|
||||
// } as IInventoryCostLotsGLEntriesWriteEvent
|
||||
// );
|
||||
// // Triggers event `onInventoryCostLotsGLEntriesWrite`.
|
||||
// await this.eventPublisher.emitAsync(
|
||||
// events.inventory.onCostLotsGLEntriesWrite,
|
||||
// {
|
||||
// tenantId,
|
||||
// startingDate,
|
||||
// trx,
|
||||
// } as IInventoryCostLotsGLEntriesWriteEvent
|
||||
// );
|
||||
// });
|
||||
// };
|
||||
// }
|
||||
/**
|
||||
* Writes cost GL entries from the inventory cost lots.
|
||||
* @param {number} tenantId -
|
||||
* @param {Date} startingDate -
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public writeCostLotsGLEntries = (startingDate: Date) => {
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers event `onInventoryCostLotsGLEntriesBeforeWrite`.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.inventory.onCostLotsGLEntriesBeforeWrite,
|
||||
{
|
||||
startingDate,
|
||||
trx,
|
||||
} as IInventoryCostLotsGLEntriesWriteEvent,
|
||||
);
|
||||
// Triggers event `onInventoryCostLotsGLEntriesWrite`.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.inventory.onCostLotsGLEntriesWrite,
|
||||
{
|
||||
startingDate,
|
||||
trx,
|
||||
} as IInventoryCostLotsGLEntriesWriteEvent,
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,6 +19,17 @@ import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CreateSaleInvoice {
|
||||
/**
|
||||
* @param {ItemsEntriesService} itemsEntriesService - Items entries service.
|
||||
* @param {CommandSaleInvoiceValidators} validators - Command sale invoice validators.
|
||||
* @param {CommandSaleInvoiceDTOTransformer} transformerDTO - Command sale invoice DTO transformer.
|
||||
* @param {EventEmitter2} eventPublisher - Event emitter.
|
||||
* @param {SaleEstimateValidators} commandEstimateValidators - Command sale estimate validators.
|
||||
* @param {UnitOfWork} uow - Unit of work.
|
||||
* @param {TenantModelProxy<typeof SaleInvoice>} saleInvoiceModel - Sale invoice model.
|
||||
* @param {TenantModelProxy<typeof SaleEstimate>} saleEstimateModel - Sale estimate model.
|
||||
* @param {TenantModelProxy<typeof Customer>} customerModel - Customer model.
|
||||
*/
|
||||
constructor(
|
||||
private readonly itemsEntriesService: ItemsEntriesService,
|
||||
private readonly validators: CommandSaleInvoiceValidators,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/InventoryTransactions.service';
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/commands/InventoryTransactions.service';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import { SaleReceipt } from '../models/SaleReceipt';
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/InventoryTransactions.service';
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/commands/InventoryTransactions.service';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
|
||||
@Injectable()
|
||||
|
||||
@@ -1,55 +1,54 @@
|
||||
// import { Knex } from 'knex';
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import HasTenancyService from '../Tenancy/TenancyService';
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Item } from '../Items/models/Item';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
|
||||
// @Service()
|
||||
// export class SyncItemTaxRateOnEditTaxRate {
|
||||
// @Inject()
|
||||
// private tenancy: HasTenancyService;
|
||||
@Injectable()
|
||||
export class SyncItemTaxRateOnEditTaxRate {
|
||||
constructor(
|
||||
@Inject(Item.name)
|
||||
private readonly itemModel: TenantModelProxy<typeof Item>,
|
||||
) {}
|
||||
|
||||
// /**
|
||||
// * Syncs the new tax rate created to item default sell tax rate.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} itemId
|
||||
// * @param {number} sellTaxRateId
|
||||
// */
|
||||
// public updateItemSellTaxRate = async (
|
||||
// tenantId: number,
|
||||
// oldSellTaxRateId: number,
|
||||
// sellTaxRateId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// const { Item } = this.tenancy.models(tenantId);
|
||||
/**
|
||||
* Syncs the new tax rate created to item default sell tax rate.
|
||||
* @param {number} itemId - Item id.
|
||||
* @param {number} sellTaxRateId - Sell tax rate id.
|
||||
*/
|
||||
public updateItemSellTaxRate = async (
|
||||
oldSellTaxRateId: number,
|
||||
sellTaxRateId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
// Can't continue if the old and new sell tax rate id are equal.
|
||||
if (oldSellTaxRateId === sellTaxRateId) return;
|
||||
|
||||
// // Can't continue if the old and new sell tax rate id are equal.
|
||||
// if (oldSellTaxRateId === sellTaxRateId) return;
|
||||
await this.itemModel()
|
||||
.query()
|
||||
.where('sellTaxRateId', oldSellTaxRateId)
|
||||
.update({
|
||||
sellTaxRateId,
|
||||
});
|
||||
};
|
||||
|
||||
// await Item.query().where('sellTaxRateId', oldSellTaxRateId).update({
|
||||
// sellTaxRateId,
|
||||
// });
|
||||
// };
|
||||
/**
|
||||
* Syncs the new tax rate created to item default purchase tax rate.
|
||||
* @param {number} itemId
|
||||
* @param {number} purchaseTaxRateId
|
||||
*/
|
||||
public updateItemPurchaseTaxRate = async (
|
||||
oldPurchaseTaxRateId: number,
|
||||
purchaseTaxRateId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
// Can't continue if the old and new sell tax rate id are equal.
|
||||
if (oldPurchaseTaxRateId === purchaseTaxRateId) return;
|
||||
|
||||
// /**
|
||||
// * Syncs the new tax rate created to item default purchase tax rate.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} itemId
|
||||
// * @param {number} purchaseTaxRateId
|
||||
// */
|
||||
// public updateItemPurchaseTaxRate = async (
|
||||
// tenantId: number,
|
||||
// oldPurchaseTaxRateId: number,
|
||||
// purchaseTaxRateId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// const { Item } = this.tenancy.models(tenantId);
|
||||
|
||||
// // Can't continue if the old and new sell tax rate id are equal.
|
||||
// if (oldPurchaseTaxRateId === purchaseTaxRateId) return;
|
||||
|
||||
// await Item.query(trx)
|
||||
// .where('purchaseTaxRateId', oldPurchaseTaxRateId)
|
||||
// .update({
|
||||
// purchaseTaxRateId,
|
||||
// });
|
||||
// };
|
||||
// }
|
||||
await this.itemModel()
|
||||
.query(trx)
|
||||
.where('purchaseTaxRateId', oldPurchaseTaxRateId)
|
||||
.update({
|
||||
purchaseTaxRateId,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { SyncItemTaxRateOnEditTaxRate } from './SyncItemTaxRateOnEditTaxRate';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { ITaxRateEditedPayload } from '@/interfaces';
|
||||
// import { runAfterTransaction } from '../UnitOfWork/TransactionsHooks';
|
||||
|
||||
// @Service()
|
||||
// export class SyncItemTaxRateOnEditTaxSubscriber {
|
||||
// @Inject()
|
||||
// private syncItemRateOnEdit: SyncItemTaxRateOnEditTaxRate;
|
||||
|
||||
// /**
|
||||
// * Attaches events with handles.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.taxRates.onEdited,
|
||||
// this.handleSyncNewTaxRateToItemTaxRate
|
||||
// );
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Syncs the new tax rate created to default item tax rates.
|
||||
// * @param {ITaxRateEditedPayload} payload -
|
||||
// */
|
||||
// private handleSyncNewTaxRateToItemTaxRate = async ({
|
||||
// taxRate,
|
||||
// tenantId,
|
||||
// oldTaxRate,
|
||||
// trx,
|
||||
// }: ITaxRateEditedPayload) => {
|
||||
// runAfterTransaction(trx, async () => {
|
||||
// await this.syncItemRateOnEdit.updateItemPurchaseTaxRate(
|
||||
// tenantId,
|
||||
// oldTaxRate.id,
|
||||
// taxRate.id
|
||||
// );
|
||||
// await this.syncItemRateOnEdit.updateItemSellTaxRate(
|
||||
// tenantId,
|
||||
// oldTaxRate.id,
|
||||
// taxRate.id
|
||||
// );
|
||||
// });
|
||||
// };
|
||||
// }
|
||||
@@ -12,6 +12,11 @@ import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
||||
import { TaxRatesApplication } from './TaxRate.application';
|
||||
import { ItemEntriesTaxTransactions } from './ItemEntriesTaxTransactions.service';
|
||||
import { GetTaxRatesService } from './queries/GetTaxRates.service';
|
||||
import { WriteBillTaxTransactionsSubscriber } from './subscribers/WriteBillTaxTransactionsSubscriber';
|
||||
import { WriteInvoiceTaxTransactionsSubscriber } from './subscribers/WriteInvoiceTaxTransactionsSubscriber';
|
||||
import { BillTaxRateValidateSubscriber } from './subscribers/BillTaxRateValidateSubscriber';
|
||||
import { SaleInvoiceTaxRateValidateSubscriber } from './subscribers/SaleInvoiceTaxRateValidateSubscriber';
|
||||
import { SyncItemTaxRateOnEditTaxSubscriber } from './subscribers/SyncItemTaxRateOnEditTaxSubscriber';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
@@ -28,7 +33,12 @@ import { GetTaxRatesService } from './queries/GetTaxRates.service';
|
||||
TransformerInjectable,
|
||||
TenancyContext,
|
||||
TaxRatesApplication,
|
||||
ItemEntriesTaxTransactions
|
||||
ItemEntriesTaxTransactions,
|
||||
WriteBillTaxTransactionsSubscriber,
|
||||
WriteInvoiceTaxTransactionsSubscriber,
|
||||
BillTaxRateValidateSubscriber,
|
||||
SaleInvoiceTaxRateValidateSubscriber,
|
||||
SyncItemTaxRateOnEditTaxSubscriber,
|
||||
],
|
||||
exports: [ItemEntriesTaxTransactions],
|
||||
})
|
||||
|
||||
@@ -1,99 +1,105 @@
|
||||
// import { sumBy, chain, keyBy } from 'lodash';
|
||||
// import { IItemEntry, ITaxTransaction } from '@/interfaces';
|
||||
// import HasTenancyService from '../Tenancy/TenancyService';
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { Knex } from 'knex';
|
||||
import { sumBy, chain, keyBy } from 'lodash';
|
||||
import { Knex } from 'knex';
|
||||
import { SaleInvoice } from '../SaleInvoices/models/SaleInvoice';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
import { TaxRateModel } from './models/TaxRate.model';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { ModelObject } from 'objection';
|
||||
import { ItemEntry } from '../TransactionItemEntry/models/ItemEntry';
|
||||
|
||||
// @Service()
|
||||
// export class WriteTaxTransactionsItemEntries {
|
||||
// @Inject()
|
||||
// private tenancy: HasTenancyService;
|
||||
@Injectable()
|
||||
export class WriteTaxTransactionsItemEntries {
|
||||
constructor(
|
||||
@Inject(SaleInvoice.name)
|
||||
private readonly taxRateTransactionModel: TenantModelProxy<
|
||||
typeof SaleInvoice
|
||||
>,
|
||||
|
||||
// /**
|
||||
// * Writes the tax transactions from the given item entries.
|
||||
// * @param {number} tenantId
|
||||
// * @param {IItemEntry[]} itemEntries
|
||||
// */
|
||||
// public async writeTaxTransactionsFromItemEntries(
|
||||
// tenantId: number,
|
||||
// itemEntries: IItemEntry[],
|
||||
// trx?: Knex.Transaction
|
||||
// ) {
|
||||
// const { TaxRateTransaction, TaxRate } = this.tenancy.models(tenantId);
|
||||
// const aggregatedEntries = this.aggregateItemEntriesByTaxCode(itemEntries);
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: TenantModelProxy<typeof TaxRateModel>,
|
||||
) {}
|
||||
|
||||
// const entriesTaxRateIds = aggregatedEntries.map((entry) => entry.taxRateId);
|
||||
/**
|
||||
* Writes the tax transactions from the given item entries.
|
||||
* @param {number} tenantId
|
||||
* @param {IItemEntry[]} itemEntries
|
||||
*/
|
||||
public async writeTaxTransactionsFromItemEntries(
|
||||
itemEntries: ModelObject<ItemEntry>[],
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
const aggregatedEntries = this.aggregateItemEntriesByTaxCode(itemEntries);
|
||||
const entriesTaxRateIds = aggregatedEntries.map((entry) => entry.taxRateId);
|
||||
|
||||
// const taxRates = await TaxRate.query(trx).whereIn('id', entriesTaxRateIds);
|
||||
// const taxRatesById = keyBy(taxRates, 'id');
|
||||
const taxRates = await this.taxRateModel()
|
||||
.query(trx)
|
||||
.whereIn('id', entriesTaxRateIds);
|
||||
const taxRatesById = keyBy(taxRates, 'id');
|
||||
|
||||
// const taxTransactions = aggregatedEntries.map((entry) => ({
|
||||
// taxRateId: entry.taxRateId,
|
||||
// referenceType: entry.referenceType,
|
||||
// referenceId: entry.referenceId,
|
||||
// rate: entry.taxRate || taxRatesById[entry.taxRateId]?.rate,
|
||||
// })) as ITaxTransaction[];
|
||||
const taxTransactions = aggregatedEntries.map((entry) => ({
|
||||
taxRateId: entry.taxRateId,
|
||||
referenceType: entry.referenceType,
|
||||
referenceId: entry.referenceId,
|
||||
rate: entry.taxRate || taxRatesById[entry.taxRateId]?.rate,
|
||||
}));
|
||||
await this.taxRateTransactionModel()
|
||||
.query(trx)
|
||||
.upsertGraph(taxTransactions);
|
||||
}
|
||||
|
||||
// await TaxRateTransaction.query(trx).upsertGraph(taxTransactions);
|
||||
// }
|
||||
/**
|
||||
* Rewrites the tax rate transactions from the given item entries.
|
||||
* @param {number} tenantId
|
||||
* @param {IItemEntry[]} itemEntries
|
||||
* @param {string} referenceType
|
||||
* @param {number} referenceId
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public async rewriteTaxRateTransactionsFromItemEntries(
|
||||
itemEntries: ModelObject<ItemEntry>[],
|
||||
referenceType: string,
|
||||
referenceId: number,
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
await Promise.all([
|
||||
this.removeTaxTransactionsFromItemEntries(
|
||||
referenceId,
|
||||
referenceType,
|
||||
trx,
|
||||
),
|
||||
this.writeTaxTransactionsFromItemEntries(itemEntries, trx),
|
||||
]);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Rewrites the tax rate transactions from the given item entries.
|
||||
// * @param {number} tenantId
|
||||
// * @param {IItemEntry[]} itemEntries
|
||||
// * @param {string} referenceType
|
||||
// * @param {number} referenceId
|
||||
// * @param {Knex.Transaction} trx
|
||||
// */
|
||||
// public async rewriteTaxRateTransactionsFromItemEntries(
|
||||
// tenantId: number,
|
||||
// itemEntries: IItemEntry[],
|
||||
// referenceType: string,
|
||||
// referenceId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) {
|
||||
// await Promise.all([
|
||||
// this.removeTaxTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// referenceId,
|
||||
// referenceType,
|
||||
// trx
|
||||
// ),
|
||||
// this.writeTaxTransactionsFromItemEntries(tenantId, itemEntries, trx),
|
||||
// ]);
|
||||
// }
|
||||
/**
|
||||
* Aggregates by tax code id and sums the amount.
|
||||
* @param {IItemEntry[]} itemEntries
|
||||
* @returns {IItemEntry[]}
|
||||
*/
|
||||
private aggregateItemEntriesByTaxCode = (
|
||||
itemEntries: ModelObject<ItemEntry>[],
|
||||
): ModelObject<ItemEntry>[] => {
|
||||
return chain(itemEntries.filter((item) => item.taxRateId))
|
||||
.groupBy((item) => item.taxRateId)
|
||||
.values()
|
||||
.map((group) => ({ ...group[0], amount: sumBy(group, 'amount') }))
|
||||
.value();
|
||||
};
|
||||
|
||||
// /**
|
||||
// * Aggregates by tax code id and sums the amount.
|
||||
// * @param {IItemEntry[]} itemEntries
|
||||
// * @returns {IItemEntry[]}
|
||||
// */
|
||||
// private aggregateItemEntriesByTaxCode = (
|
||||
// itemEntries: IItemEntry[]
|
||||
// ): IItemEntry[] => {
|
||||
// return chain(itemEntries.filter((item) => item.taxRateId))
|
||||
// .groupBy((item) => item.taxRateId)
|
||||
// .values()
|
||||
// .map((group) => ({ ...group[0], amount: sumBy(group, 'amount') }))
|
||||
// .value();
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Removes the tax transactions from the given item entries.
|
||||
// * @param {number} tenantId - Tenant id.
|
||||
// * @param {string} referenceType - Reference type.
|
||||
// * @param {number} referenceId - Reference id.
|
||||
// */
|
||||
// public async removeTaxTransactionsFromItemEntries(
|
||||
// tenantId: number,
|
||||
// referenceId: number,
|
||||
// referenceType: string,
|
||||
// trx?: Knex.Transaction
|
||||
// ) {
|
||||
// const { TaxRateTransaction } = this.tenancy.models(tenantId);
|
||||
|
||||
// await TaxRateTransaction.query(trx)
|
||||
// .where({ referenceType, referenceId })
|
||||
// .delete();
|
||||
// }
|
||||
// }
|
||||
/**
|
||||
* Removes the tax transactions from the given item entries.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {string} referenceType - Reference type.
|
||||
* @param {number} referenceId - Reference id.
|
||||
*/
|
||||
public async removeTaxTransactionsFromItemEntries(
|
||||
referenceId: number,
|
||||
referenceType: string,
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
await this.taxRateTransactionModel()
|
||||
.query(trx)
|
||||
.where({ referenceType, referenceId })
|
||||
.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Inject } from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { IItemEntryDTO } from '@/modules/TransactionItemEntry/ItemEntry.types';
|
||||
|
||||
@Injectable()
|
||||
export class CommandTaxRatesValidators {
|
||||
@@ -70,46 +71,46 @@ export class CommandTaxRatesValidators {
|
||||
* @param {IItemEntryDTO[]} itemEntriesDTO
|
||||
* @throws {ServiceError}
|
||||
*/
|
||||
// public async validateItemEntriesTaxCode(itemEntriesDTO: IItemEntryDTO[]) {
|
||||
// const filteredTaxEntries = itemEntriesDTO.filter((e) => e.taxCode);
|
||||
// const taxCodes = filteredTaxEntries.map((e) => e.taxCode);
|
||||
public async validateItemEntriesTaxCode(itemEntriesDTO: IItemEntryDTO[]) {
|
||||
const filteredTaxEntries = itemEntriesDTO.filter((e) => e.taxCode);
|
||||
const taxCodes = filteredTaxEntries.map((e) => e.taxCode);
|
||||
|
||||
// // Can't validate if there is no tax codes.
|
||||
// if (taxCodes.length === 0) return;
|
||||
// Can't validate if there is no tax codes.
|
||||
if (taxCodes.length === 0) return;
|
||||
|
||||
// const foundTaxCodes = await this.taxRateModel
|
||||
// .query()
|
||||
// .whereIn('code', taxCodes);
|
||||
// const foundCodes = foundTaxCodes.map((tax) => tax.code);
|
||||
const foundTaxCodes = await this.taxRateModel()
|
||||
.query()
|
||||
.whereIn('code', taxCodes);
|
||||
const foundCodes = foundTaxCodes.map((tax) => tax.code);
|
||||
|
||||
// const notFoundTaxCodes = difference(taxCodes, foundCodes);
|
||||
const notFoundTaxCodes = difference(taxCodes, foundCodes);
|
||||
|
||||
// if (notFoundTaxCodes.length > 0) {
|
||||
// throw new ServiceError(ERRORS.ITEM_ENTRY_TAX_RATE_CODE_NOT_FOUND);
|
||||
// }
|
||||
// }
|
||||
if (notFoundTaxCodes.length > 0) {
|
||||
throw new ServiceError(ERRORS.ITEM_ENTRY_TAX_RATE_CODE_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the tax rate id of the given item entries DTO.
|
||||
* @param {IItemEntryDTO[]} itemEntriesDTO
|
||||
* @throws {ServiceError}
|
||||
*/
|
||||
// public async validateItemEntriesTaxCodeId(itemEntriesDTO: IItemEntryDTO[]) {
|
||||
// const filteredTaxEntries = itemEntriesDTO.filter((e) => e.taxRateId);
|
||||
// const taxRatesIds = filteredTaxEntries.map((e) => e.taxRateId);
|
||||
public async validateItemEntriesTaxCodeId(itemEntriesDTO: IItemEntryDTO[]) {
|
||||
const filteredTaxEntries = itemEntriesDTO.filter((e) => e.taxRateId);
|
||||
const taxRatesIds = filteredTaxEntries.map((e) => e.taxRateId);
|
||||
|
||||
// // Can't validate if there is no tax codes.
|
||||
// if (taxRatesIds.length === 0) return;
|
||||
// Can't validate if there is no tax codes.
|
||||
if (taxRatesIds.length === 0) return;
|
||||
|
||||
// const foundTaxCodes = await this.taxRateModel
|
||||
// .query()
|
||||
// .whereIn('id', taxRatesIds);
|
||||
// const foundTaxRatesIds = foundTaxCodes.map((tax) => tax.id);
|
||||
const foundTaxCodes = await this.taxRateModel()
|
||||
.query()
|
||||
.whereIn('id', taxRatesIds);
|
||||
const foundTaxRatesIds = foundTaxCodes.map((tax) => tax.id);
|
||||
|
||||
// const notFoundTaxCodes = difference(taxRatesIds, foundTaxRatesIds);
|
||||
const notFoundTaxCodes = difference(taxRatesIds, foundTaxRatesIds);
|
||||
|
||||
// if (notFoundTaxCodes.length > 0) {
|
||||
// throw new ServiceError(ERRORS.ITEM_ENTRY_TAX_RATE_ID_NOT_FOUND);
|
||||
// }
|
||||
// }
|
||||
if (notFoundTaxCodes.length > 0) {
|
||||
throw new ServiceError(ERRORS.ITEM_ENTRY_TAX_RATE_ID_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,13 @@ import { mixin, Model, raw } from 'objection';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
|
||||
export class TaxRateTransaction extends BaseModel {
|
||||
id: number;
|
||||
taxRateId: number;
|
||||
referenceType: string;
|
||||
referenceId: number;
|
||||
rate: number;
|
||||
taxAccountId: number;
|
||||
|
||||
/**
|
||||
* Table name
|
||||
*/
|
||||
|
||||
@@ -1,89 +1,61 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { IBillCreatingPayload, IBillEditingPayload } from '@/interfaces';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { CommandTaxRatesValidators } from '../commands/CommandTaxRatesValidator.service';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { CommandTaxRatesValidators } from '../commands/CommandTaxRatesValidator.service';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { IBillCreatingPayload } from '@/modules/Bills/Bills.types';
|
||||
import { IBillEditingPayload } from '@/modules/Bills/Bills.types';
|
||||
|
||||
// @Service()
|
||||
// export class BillTaxRateValidateSubscriber {
|
||||
// @Inject()
|
||||
// private taxRateDTOValidator: CommandTaxRatesValidators;
|
||||
@Injectable()
|
||||
export class BillTaxRateValidateSubscriber {
|
||||
constructor(
|
||||
private readonly taxRateDTOValidator: CommandTaxRatesValidators,
|
||||
) {}
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.bill.onCreating,
|
||||
// this.validateBillEntriesTaxCodeExistanceOnCreating
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.bill.onCreating,
|
||||
// this.validateBillEntriesTaxIdExistanceOnCreating
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.bill.onEditing,
|
||||
// this.validateBillEntriesTaxCodeExistanceOnEditing
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.bill.onEditing,
|
||||
// this.validateBillEntriesTaxIdExistanceOnEditing
|
||||
// );
|
||||
// return bus;
|
||||
// }
|
||||
/**
|
||||
* Validate bill entries tax rate code existance when creating.
|
||||
* @param {IBillCreatingPayload}
|
||||
*/
|
||||
@OnEvent(events.bill.onCreating)
|
||||
async validateBillEntriesTaxCodeExistanceOnCreating({
|
||||
billDTO,
|
||||
}: IBillCreatingPayload) {
|
||||
await this.taxRateDTOValidator.validateItemEntriesTaxCode(billDTO.entries);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Validate bill entries tax rate code existance when creating.
|
||||
// * @param {IBillCreatingPayload}
|
||||
// */
|
||||
// private validateBillEntriesTaxCodeExistanceOnCreating = async ({
|
||||
// billDTO,
|
||||
// tenantId,
|
||||
// }: IBillCreatingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||
// tenantId,
|
||||
// billDTO.entries
|
||||
// );
|
||||
// };
|
||||
/**
|
||||
* Validate the tax rate id existance when creating.
|
||||
* @param {IBillCreatingPayload}
|
||||
*/
|
||||
@OnEvent(events.bill.onCreating)
|
||||
async validateBillEntriesTaxIdExistanceOnCreating({
|
||||
billDTO,
|
||||
}: IBillCreatingPayload) {
|
||||
await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
billDTO.entries,
|
||||
);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Validate the tax rate id existance when creating.
|
||||
// * @param {IBillCreatingPayload}
|
||||
// */
|
||||
// private validateBillEntriesTaxIdExistanceOnCreating = async ({
|
||||
// billDTO,
|
||||
// tenantId,
|
||||
// }: IBillCreatingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
// tenantId,
|
||||
// billDTO.entries
|
||||
// );
|
||||
// };
|
||||
/**
|
||||
* Validate bill entries tax rate code existance when editing.
|
||||
* @param {IBillEditingPayload}
|
||||
*/
|
||||
@OnEvent(events.bill.onEditing)
|
||||
async validateBillEntriesTaxCodeExistanceOnEditing({
|
||||
billDTO,
|
||||
}: IBillEditingPayload) {
|
||||
await this.taxRateDTOValidator.validateItemEntriesTaxCode(billDTO.entries);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Validate bill entries tax rate code existance when editing.
|
||||
// * @param {IBillEditingPayload}
|
||||
// */
|
||||
// private validateBillEntriesTaxCodeExistanceOnEditing = async ({
|
||||
// tenantId,
|
||||
// billDTO,
|
||||
// }: IBillEditingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||
// tenantId,
|
||||
// billDTO.entries
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Validates the bill entries tax rate id existance when editing.
|
||||
// * @param {ISaleInvoiceEditingPayload} payload -
|
||||
// */
|
||||
// private validateBillEntriesTaxIdExistanceOnEditing = async ({
|
||||
// tenantId,
|
||||
// billDTO,
|
||||
// }: IBillEditingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
// tenantId,
|
||||
// billDTO.entries
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
/**
|
||||
* Validates the bill entries tax rate id existance when editing.
|
||||
* @param {ISaleInvoiceEditingPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.bill.onEditing)
|
||||
async validateBillEntriesTaxIdExistanceOnEditing({
|
||||
billDTO,
|
||||
}: IBillEditingPayload) {
|
||||
await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
billDTO.entries,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,92 +1,67 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import {
|
||||
// ISaleInvoiceCreatingPaylaod,
|
||||
// ISaleInvoiceEditingPayload,
|
||||
// } from '@/interfaces';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { CommandTaxRatesValidators } from '../commands/CommandTaxRatesValidator.service';
|
||||
import { CommandTaxRatesValidators } from '../commands/CommandTaxRatesValidator.service';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
ISaleInvoiceCreatingPaylaod,
|
||||
ISaleInvoiceEditingPayload,
|
||||
} from '@/modules/SaleInvoices/SaleInvoice.types';
|
||||
import { events } from '@/common/events/events';
|
||||
|
||||
// @Service()
|
||||
// export class SaleInvoiceTaxRateValidateSubscriber {
|
||||
// @Inject()
|
||||
// private taxRateDTOValidator: CommandTaxRatesValidators;
|
||||
@Injectable()
|
||||
export class SaleInvoiceTaxRateValidateSubscriber {
|
||||
constructor(
|
||||
private readonly taxRateDTOValidator: CommandTaxRatesValidators,
|
||||
) {}
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onCreating,
|
||||
// this.validateSaleInvoiceEntriesTaxCodeExistanceOnCreating
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onCreating,
|
||||
// this.validateSaleInvoiceEntriesTaxIdExistanceOnCreating
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onEditing,
|
||||
// this.validateSaleInvoiceEntriesTaxCodeExistanceOnEditing
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onEditing,
|
||||
// this.validateSaleInvoiceEntriesTaxIdExistanceOnEditing
|
||||
// );
|
||||
// return bus;
|
||||
// }
|
||||
/**
|
||||
* Validate invoice entries tax rate code existance when creating.
|
||||
* @param {ISaleInvoiceCreatingPaylaod}
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onCreating)
|
||||
async validateSaleInvoiceEntriesTaxCodeExistanceOnCreating({
|
||||
saleInvoiceDTO,
|
||||
}: ISaleInvoiceCreatingPaylaod) {
|
||||
await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||
saleInvoiceDTO.entries,
|
||||
);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Validate invoice entries tax rate code existance when creating.
|
||||
// * @param {ISaleInvoiceCreatingPaylaod}
|
||||
// */
|
||||
// private validateSaleInvoiceEntriesTaxCodeExistanceOnCreating = async ({
|
||||
// saleInvoiceDTO,
|
||||
// tenantId,
|
||||
// }: ISaleInvoiceCreatingPaylaod) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||
// tenantId,
|
||||
// saleInvoiceDTO.entries
|
||||
// );
|
||||
// };
|
||||
/**
|
||||
* Validate the tax rate id existance when creating.
|
||||
* @param {ISaleInvoiceCreatingPaylaod}
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onCreating)
|
||||
async validateSaleInvoiceEntriesTaxIdExistanceOnCreating({
|
||||
saleInvoiceDTO,
|
||||
}: ISaleInvoiceCreatingPaylaod) {
|
||||
await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
saleInvoiceDTO.entries,
|
||||
);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Validate the tax rate id existance when creating.
|
||||
// * @param {ISaleInvoiceCreatingPaylaod}
|
||||
// */
|
||||
// private validateSaleInvoiceEntriesTaxIdExistanceOnCreating = async ({
|
||||
// saleInvoiceDTO,
|
||||
// tenantId,
|
||||
// }: ISaleInvoiceCreatingPaylaod) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
// tenantId,
|
||||
// saleInvoiceDTO.entries
|
||||
// );
|
||||
// };
|
||||
/**
|
||||
* Validate invoice entries tax rate code existance when editing.
|
||||
* @param {ISaleInvoiceEditingPayload}
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onEditing)
|
||||
async validateSaleInvoiceEntriesTaxCodeExistanceOnEditing({
|
||||
saleInvoiceDTO,
|
||||
}: ISaleInvoiceEditingPayload) {
|
||||
await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||
saleInvoiceDTO.entries,
|
||||
);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Validate invoice entries tax rate code existance when editing.
|
||||
// * @param {ISaleInvoiceEditingPayload}
|
||||
// */
|
||||
// private validateSaleInvoiceEntriesTaxCodeExistanceOnEditing = async ({
|
||||
// tenantId,
|
||||
// saleInvoiceDTO,
|
||||
// }: ISaleInvoiceEditingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||
// tenantId,
|
||||
// saleInvoiceDTO.entries
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Validates the invoice entries tax rate id existance when editing.
|
||||
// * @param {ISaleInvoiceEditingPayload} payload -
|
||||
// */
|
||||
// private validateSaleInvoiceEntriesTaxIdExistanceOnEditing = async ({
|
||||
// tenantId,
|
||||
// saleInvoiceDTO,
|
||||
// }: ISaleInvoiceEditingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
// tenantId,
|
||||
// saleInvoiceDTO.entries
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
/**
|
||||
* Validates the invoice entries tax rate id existance when editing.
|
||||
* @param {ISaleInvoiceEditingPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onEditing)
|
||||
async validateSaleInvoiceEntriesTaxIdExistanceOnEditing({
|
||||
saleInvoiceDTO,
|
||||
}: ISaleInvoiceEditingPayload) {
|
||||
await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
saleInvoiceDTO.entries,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ITaxRateEditedPayload } from '../TaxRates.types';
|
||||
import { runAfterTransaction } from '@/modules/Tenancy/TenancyDB/TransactionsHooks';
|
||||
import { events } from '@/common/events/events';
|
||||
import { SyncItemTaxRateOnEditTaxRate } from '../SyncItemTaxRateOnEditTaxRate';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
|
||||
@Injectable()
|
||||
export class SyncItemTaxRateOnEditTaxSubscriber {
|
||||
constructor(
|
||||
private readonly syncItemRateOnEdit: SyncItemTaxRateOnEditTaxRate,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Syncs the new tax rate created to default item tax rates.
|
||||
* @param {ITaxRateEditedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.taxRates.onEdited)
|
||||
async handleSyncNewTaxRateToItemTaxRate({
|
||||
taxRate,
|
||||
oldTaxRate,
|
||||
trx,
|
||||
}: ITaxRateEditedPayload) {
|
||||
runAfterTransaction(trx, async () => {
|
||||
await this.syncItemRateOnEdit.updateItemPurchaseTaxRate(
|
||||
oldTaxRate.id,
|
||||
taxRate.id,
|
||||
);
|
||||
await this.syncItemRateOnEdit.updateItemSellTaxRate(
|
||||
oldTaxRate.id,
|
||||
taxRate.id,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,87 +1,65 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import {
|
||||
// IBIllEventDeletedPayload,
|
||||
// IBillCreatedPayload,
|
||||
// IBillEditedPayload,
|
||||
// ISaleInvoiceCreatedPayload,
|
||||
// ISaleInvoiceDeletedPayload,
|
||||
// ISaleInvoiceEditedPayload,
|
||||
// } from '@/interfaces';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { WriteTaxTransactionsItemEntries } from '../WriteTaxTransactionsItemEntries';
|
||||
import {
|
||||
IBIllEventDeletedPayload,
|
||||
IBillCreatedPayload,
|
||||
IBillEditedPayload,
|
||||
} from '@/modules/Bills/Bills.types';
|
||||
import { WriteTaxTransactionsItemEntries } from '../WriteTaxTransactionsItemEntries';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
|
||||
// @Service()
|
||||
// export class WriteBillTaxTransactionsSubscriber {
|
||||
// @Inject()
|
||||
// private writeTaxTransactions: WriteTaxTransactionsItemEntries;
|
||||
@Injectable()
|
||||
export class WriteBillTaxTransactionsSubscriber {
|
||||
constructor(
|
||||
@Inject()
|
||||
private readonly writeTaxTransactions: WriteTaxTransactionsItemEntries,
|
||||
) {}
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.bill.onCreated,
|
||||
// this.writeInvoiceTaxTransactionsOnCreated
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.bill.onEdited,
|
||||
// this.rewriteInvoiceTaxTransactionsOnEdited
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.bill.onDeleted,
|
||||
// this.removeInvoiceTaxTransactionsOnDeleted
|
||||
// );
|
||||
// return bus;
|
||||
// }
|
||||
/**
|
||||
* Writes the bill tax transactions on invoice created.
|
||||
* @param {ISaleInvoiceCreatingPaylaod}
|
||||
*/
|
||||
@OnEvent(events.bill.onCreated)
|
||||
async writeInvoiceTaxTransactionsOnCreated({
|
||||
bill,
|
||||
trx,
|
||||
}: IBillCreatedPayload) {
|
||||
await this.writeTaxTransactions.writeTaxTransactionsFromItemEntries(
|
||||
bill.entries,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Writes the bill tax transactions on invoice created.
|
||||
// * @param {ISaleInvoiceCreatingPaylaod}
|
||||
// */
|
||||
// private writeInvoiceTaxTransactionsOnCreated = async ({
|
||||
// tenantId,
|
||||
// bill,
|
||||
// trx,
|
||||
// }: IBillCreatedPayload) => {
|
||||
// await this.writeTaxTransactions.writeTaxTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// bill.entries,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
/**
|
||||
* Rewrites the bill tax transactions on invoice edited.
|
||||
* @param {IBillEditedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.bill.onEdited)
|
||||
async rewriteInvoiceTaxTransactionsOnEdited({
|
||||
bill,
|
||||
trx,
|
||||
}: IBillEditedPayload) {
|
||||
await this.writeTaxTransactions.rewriteTaxRateTransactionsFromItemEntries(
|
||||
bill.entries,
|
||||
'Bill',
|
||||
bill.id,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Rewrites the bill tax transactions on invoice edited.
|
||||
// * @param {IBillEditedPayload} payload -
|
||||
// */
|
||||
// private rewriteInvoiceTaxTransactionsOnEdited = async ({
|
||||
// tenantId,
|
||||
// bill,
|
||||
// trx,
|
||||
// }: IBillEditedPayload) => {
|
||||
// await this.writeTaxTransactions.rewriteTaxRateTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// bill.entries,
|
||||
// 'Bill',
|
||||
// bill.id,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Removes the invoice tax transactions on invoice deleted.
|
||||
// * @param {IBIllEventDeletedPayload}
|
||||
// */
|
||||
// private removeInvoiceTaxTransactionsOnDeleted = async ({
|
||||
// tenantId,
|
||||
// oldBill,
|
||||
// trx,
|
||||
// }: IBIllEventDeletedPayload) => {
|
||||
// await this.writeTaxTransactions.removeTaxTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// oldBill.id,
|
||||
// 'Bill',
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
/**
|
||||
* Removes the invoice tax transactions on invoice deleted.
|
||||
* @param {IBIllEventDeletedPayload}
|
||||
*/
|
||||
@OnEvent(events.bill.onDeleted)
|
||||
async removeInvoiceTaxTransactionsOnDeleted({
|
||||
oldBill,
|
||||
trx,
|
||||
}: IBIllEventDeletedPayload) {
|
||||
await this.writeTaxTransactions.removeTaxTransactionsFromItemEntries(
|
||||
oldBill.id,
|
||||
'Bill',
|
||||
trx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +1,64 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import {
|
||||
// ISaleInvoiceCreatedPayload,
|
||||
// ISaleInvoiceDeletedPayload,
|
||||
// ISaleInvoiceEditedPayload,
|
||||
// } from '@/interfaces';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { WriteTaxTransactionsItemEntries } from '../WriteTaxTransactionsItemEntries';
|
||||
import {
|
||||
ISaleInvoiceDeletedPayload,
|
||||
ISaleInvoiceEditedPayload,
|
||||
} from '@/modules/SaleInvoices/SaleInvoice.types';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { WriteTaxTransactionsItemEntries } from '../WriteTaxTransactionsItemEntries';
|
||||
import { events } from '@/common/events/events';
|
||||
import { ISaleInvoiceCreatedPayload } from '@/modules/SaleInvoices/SaleInvoice.types';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
// @Service()
|
||||
// export class WriteInvoiceTaxTransactionsSubscriber {
|
||||
// @Inject()
|
||||
// private writeTaxTransactions: WriteTaxTransactionsItemEntries;
|
||||
@Injectable()
|
||||
export class WriteInvoiceTaxTransactionsSubscriber {
|
||||
constructor(
|
||||
private readonly writeTaxTransactions: WriteTaxTransactionsItemEntries,
|
||||
) {}
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onCreated,
|
||||
// this.writeInvoiceTaxTransactionsOnCreated
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onEdited,
|
||||
// this.rewriteInvoiceTaxTransactionsOnEdited
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onDelete,
|
||||
// this.removeInvoiceTaxTransactionsOnDeleted
|
||||
// );
|
||||
// return bus;
|
||||
// }
|
||||
/**
|
||||
* Writes the invoice tax transactions on invoice created.
|
||||
* @param {ISaleInvoiceCreatingPaylaod}
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onCreated)
|
||||
async writeInvoiceTaxTransactionsOnCreated({
|
||||
saleInvoice,
|
||||
trx,
|
||||
}: ISaleInvoiceCreatedPayload) {
|
||||
await this.writeTaxTransactions.writeTaxTransactionsFromItemEntries(
|
||||
saleInvoice.entries,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Writes the invoice tax transactions on invoice created.
|
||||
// * @param {ISaleInvoiceCreatingPaylaod}
|
||||
// */
|
||||
// private writeInvoiceTaxTransactionsOnCreated = async ({
|
||||
// tenantId,
|
||||
// saleInvoice,
|
||||
// trx
|
||||
// }: ISaleInvoiceCreatedPayload) => {
|
||||
// await this.writeTaxTransactions.writeTaxTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// saleInvoice.entries,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
/**
|
||||
* Rewrites the invoice tax transactions on invoice edited.
|
||||
* @param {ISaleInvoiceEditedPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onEdited)
|
||||
async rewriteInvoiceTaxTransactionsOnEdited({
|
||||
saleInvoice,
|
||||
trx,
|
||||
}: ISaleInvoiceEditedPayload) {
|
||||
await this.writeTaxTransactions.rewriteTaxRateTransactionsFromItemEntries(
|
||||
saleInvoice.entries,
|
||||
'SaleInvoice',
|
||||
saleInvoice.id,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Rewrites the invoice tax transactions on invoice edited.
|
||||
// * @param {ISaleInvoiceEditedPayload} payload -
|
||||
// */
|
||||
// private rewriteInvoiceTaxTransactionsOnEdited = async ({
|
||||
// tenantId,
|
||||
// saleInvoice,
|
||||
// trx,
|
||||
// }: ISaleInvoiceEditedPayload) => {
|
||||
// await this.writeTaxTransactions.rewriteTaxRateTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// saleInvoice.entries,
|
||||
// 'SaleInvoice',
|
||||
// saleInvoice.id,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Removes the invoice tax transactions on invoice deleted.
|
||||
// * @param {ISaleInvoiceEditingPayload}
|
||||
// */
|
||||
// private removeInvoiceTaxTransactionsOnDeleted = async ({
|
||||
// tenantId,
|
||||
// oldSaleInvoice,
|
||||
// trx
|
||||
// }: ISaleInvoiceDeletedPayload) => {
|
||||
// await this.writeTaxTransactions.removeTaxTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// oldSaleInvoice.id,
|
||||
// 'SaleInvoice',
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
/**
|
||||
* Removes the invoice tax transactions on invoice deleted.
|
||||
* @param {ISaleInvoiceEditingPayload}
|
||||
*/
|
||||
@OnEvent(events.saleInvoice.onDelete)
|
||||
async removeInvoiceTaxTransactionsOnDeleted({
|
||||
oldSaleInvoice,
|
||||
trx,
|
||||
}: ISaleInvoiceDeletedPayload) {
|
||||
await this.writeTaxTransactions.removeTaxTransactionsFromItemEntries(
|
||||
oldSaleInvoice.id,
|
||||
'SaleInvoice',
|
||||
trx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { VendorCredit } from '../models/VendorCredit';
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/InventoryTransactions.service';
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/commands/InventoryTransactions.service';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
|
||||
@Injectable()
|
||||
|
||||
125
pnpm-lock.yaml
generated
125
pnpm-lock.yaml
generated
@@ -547,6 +547,9 @@ importers:
|
||||
async:
|
||||
specifier: ^3.2.0
|
||||
version: 3.2.5
|
||||
async-mutex:
|
||||
specifier: ^0.5.0
|
||||
version: 0.5.0
|
||||
axios:
|
||||
specifier: ^1.6.0
|
||||
version: 1.7.7
|
||||
@@ -1650,7 +1653,7 @@ packages:
|
||||
'@smithy/util-middleware': 3.0.0
|
||||
'@smithy/util-retry': 3.0.0
|
||||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/client-sts'
|
||||
- aws-crt
|
||||
@@ -1745,7 +1748,7 @@ packages:
|
||||
'@smithy/util-middleware': 3.0.0
|
||||
'@smithy/util-retry': 3.0.0
|
||||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
dev: false
|
||||
@@ -1760,7 +1763,7 @@ packages:
|
||||
'@smithy/smithy-client': 3.0.1
|
||||
'@smithy/types': 3.0.0
|
||||
fast-xml-parser: 4.2.5
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/credential-provider-cognito-identity@3.583.0:
|
||||
@@ -1840,7 +1843,7 @@ packages:
|
||||
'@smithy/property-provider': 3.0.0
|
||||
'@smithy/shared-ini-file-loader': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/client-sso-oidc'
|
||||
- '@aws-sdk/client-sts'
|
||||
@@ -1927,7 +1930,7 @@ packages:
|
||||
buffer: 5.6.0
|
||||
events: 3.3.0
|
||||
stream-browserify: 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-bucket-endpoint@3.577.0:
|
||||
@@ -1940,7 +1943,7 @@ packages:
|
||||
'@smithy/protocol-http': 4.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-config-provider': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-expect-continue@3.577.0:
|
||||
@@ -1950,7 +1953,7 @@ packages:
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/protocol-http': 4.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-flexible-checksums@3.577.0:
|
||||
@@ -1964,7 +1967,7 @@ packages:
|
||||
'@smithy/protocol-http': 4.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-host-header@3.577.0:
|
||||
@@ -1974,7 +1977,7 @@ packages:
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/protocol-http': 4.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-location-constraint@3.577.0:
|
||||
@@ -1983,7 +1986,7 @@ packages:
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-logger@3.577.0:
|
||||
@@ -1992,7 +1995,7 @@ packages:
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-recursion-detection@3.577.0:
|
||||
@@ -2002,7 +2005,7 @@ packages:
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/protocol-http': 4.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-sdk-s3@3.582.0:
|
||||
@@ -2017,7 +2020,7 @@ packages:
|
||||
'@smithy/smithy-client': 3.0.1
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-config-provider': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-signing@3.577.0:
|
||||
@@ -2030,7 +2033,7 @@ packages:
|
||||
'@smithy/signature-v4': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-middleware': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-ssec@3.577.0:
|
||||
@@ -2039,7 +2042,7 @@ packages:
|
||||
dependencies:
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/middleware-user-agent@3.583.0:
|
||||
@@ -2050,7 +2053,7 @@ packages:
|
||||
'@aws-sdk/util-endpoints': 3.583.0
|
||||
'@smithy/protocol-http': 4.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/region-config-resolver@3.577.0:
|
||||
@@ -2062,7 +2065,7 @@ packages:
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-config-provider': 3.0.0
|
||||
'@smithy/util-middleware': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/s3-request-presigner@3.583.0:
|
||||
@@ -2088,7 +2091,7 @@ packages:
|
||||
'@smithy/protocol-http': 4.0.0
|
||||
'@smithy/signature-v4': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/token-providers@3.577.0(@aws-sdk/client-sso-oidc@3.583.0):
|
||||
@@ -2110,7 +2113,7 @@ packages:
|
||||
engines: {node: '>=16.0.0'}
|
||||
dependencies:
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-arn-parser@3.568.0:
|
||||
@@ -2127,7 +2130,7 @@ packages:
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-endpoints': 2.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-format-url@3.577.0:
|
||||
@@ -2137,7 +2140,7 @@ packages:
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/querystring-builder': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-locate-window@3.568.0:
|
||||
@@ -2153,7 +2156,7 @@ packages:
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/types': 3.0.0
|
||||
bowser: 2.11.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-user-agent-node@3.577.0:
|
||||
@@ -2168,7 +2171,7 @@ packages:
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/node-config-provider': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@aws-sdk/util-utf8-browser@3.259.0:
|
||||
@@ -2182,7 +2185,7 @@ packages:
|
||||
engines: {node: '>=16.0.0'}
|
||||
dependencies:
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@babel/code-frame@7.10.4:
|
||||
@@ -7799,7 +7802,7 @@ packages:
|
||||
hasBin: true
|
||||
dependencies:
|
||||
nx: 19.0.7
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
transitivePeerDependencies:
|
||||
- '@swc-node/register'
|
||||
- '@swc/core'
|
||||
@@ -9571,7 +9574,7 @@ packages:
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-config-provider': 3.0.0
|
||||
'@smithy/util-middleware': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/core@2.0.1:
|
||||
@@ -9585,7 +9588,7 @@ packages:
|
||||
'@smithy/smithy-client': 3.0.1
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-middleware': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/credential-provider-imds@3.0.0:
|
||||
@@ -9614,7 +9617,7 @@ packages:
|
||||
dependencies:
|
||||
'@smithy/eventstream-serde-universal': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/eventstream-serde-config-resolver@3.0.0:
|
||||
@@ -9622,7 +9625,7 @@ packages:
|
||||
engines: {node: '>=16.0.0'}
|
||||
dependencies:
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/eventstream-serde-node@3.0.0:
|
||||
@@ -9631,7 +9634,7 @@ packages:
|
||||
dependencies:
|
||||
'@smithy/eventstream-serde-universal': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/eventstream-serde-universal@3.0.0:
|
||||
@@ -9650,7 +9653,7 @@ packages:
|
||||
'@smithy/querystring-builder': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-base64': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/hash-blob-browser@3.0.0:
|
||||
@@ -9659,7 +9662,7 @@ packages:
|
||||
'@smithy/chunked-blob-reader': 3.0.0
|
||||
'@smithy/chunked-blob-reader-native': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/hash-node@3.0.0:
|
||||
@@ -9669,7 +9672,7 @@ packages:
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-buffer-from': 3.0.0
|
||||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/hash-stream-node@3.0.0:
|
||||
@@ -9678,14 +9681,14 @@ packages:
|
||||
dependencies:
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/invalid-dependency@3.0.0:
|
||||
resolution: {integrity: sha512-F6wBBaEFgJzj0s4KUlliIGPmqXemwP6EavgvDqYwCH40O5Xr2iMHvS8todmGVZtuJCorBkXsYLyTu4PuizVq5g==}
|
||||
dependencies:
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/is-array-buffer@3.0.0:
|
||||
@@ -9700,7 +9703,7 @@ packages:
|
||||
dependencies:
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/middleware-content-length@3.0.0:
|
||||
@@ -9709,7 +9712,7 @@ packages:
|
||||
dependencies:
|
||||
'@smithy/protocol-http': 4.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/middleware-endpoint@3.0.0:
|
||||
@@ -9722,7 +9725,7 @@ packages:
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/url-parser': 3.0.0
|
||||
'@smithy/util-middleware': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/middleware-retry@3.0.1:
|
||||
@@ -9736,7 +9739,7 @@ packages:
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-middleware': 3.0.0
|
||||
'@smithy/util-retry': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
uuid: 9.0.1
|
||||
dev: false
|
||||
|
||||
@@ -9745,7 +9748,7 @@ packages:
|
||||
engines: {node: '>=16.0.0'}
|
||||
dependencies:
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/middleware-stack@3.0.0:
|
||||
@@ -9753,7 +9756,7 @@ packages:
|
||||
engines: {node: '>=16.0.0'}
|
||||
dependencies:
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/node-config-provider@3.0.0:
|
||||
@@ -9763,7 +9766,7 @@ packages:
|
||||
'@smithy/property-provider': 3.0.0
|
||||
'@smithy/shared-ini-file-loader': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/node-http-handler@3.0.0:
|
||||
@@ -9774,7 +9777,7 @@ packages:
|
||||
'@smithy/protocol-http': 4.0.0
|
||||
'@smithy/querystring-builder': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/property-provider@3.0.0:
|
||||
@@ -9790,7 +9793,7 @@ packages:
|
||||
engines: {node: '>=16.0.0'}
|
||||
dependencies:
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/querystring-builder@3.0.0:
|
||||
@@ -9847,14 +9850,14 @@ packages:
|
||||
'@smithy/protocol-http': 4.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
'@smithy/util-stream': 3.0.1
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/types@3.0.0:
|
||||
resolution: {integrity: sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/url-parser@3.0.0:
|
||||
@@ -9862,7 +9865,7 @@ packages:
|
||||
dependencies:
|
||||
'@smithy/querystring-parser': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/util-base64@3.0.0:
|
||||
@@ -9871,20 +9874,20 @@ packages:
|
||||
dependencies:
|
||||
'@smithy/util-buffer-from': 3.0.0
|
||||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/util-body-length-browser@3.0.0:
|
||||
resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/util-body-length-node@3.0.0:
|
||||
resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/util-buffer-from@3.0.0:
|
||||
@@ -9910,7 +9913,7 @@ packages:
|
||||
'@smithy/smithy-client': 3.0.1
|
||||
'@smithy/types': 3.0.0
|
||||
bowser: 2.11.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/util-defaults-mode-node@3.0.1:
|
||||
@@ -9923,7 +9926,7 @@ packages:
|
||||
'@smithy/property-provider': 3.0.0
|
||||
'@smithy/smithy-client': 3.0.1
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/util-endpoints@2.0.0:
|
||||
@@ -9932,7 +9935,7 @@ packages:
|
||||
dependencies:
|
||||
'@smithy/node-config-provider': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/util-hex-encoding@3.0.0:
|
||||
@@ -9956,7 +9959,7 @@ packages:
|
||||
dependencies:
|
||||
'@smithy/service-error-classification': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/util-stream@3.0.1:
|
||||
@@ -9970,7 +9973,7 @@ packages:
|
||||
'@smithy/util-buffer-from': 3.0.0
|
||||
'@smithy/util-hex-encoding': 3.0.0
|
||||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/util-uri-escape@3.0.0:
|
||||
@@ -9985,7 +9988,7 @@ packages:
|
||||
engines: {node: '>=16.0.0'}
|
||||
dependencies:
|
||||
'@smithy/util-buffer-from': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@smithy/util-waiter@3.0.0:
|
||||
@@ -9994,7 +9997,7 @@ packages:
|
||||
dependencies:
|
||||
'@smithy/abort-controller': 3.0.0
|
||||
'@smithy/types': 3.0.0
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/@socket.io/component-emitter@3.1.2:
|
||||
@@ -13600,7 +13603,7 @@ packages:
|
||||
engines: {node: '>=14.15.0'}
|
||||
dependencies:
|
||||
js-yaml: 3.14.1
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: true
|
||||
|
||||
/@zkochan/js-yaml@0.0.7:
|
||||
@@ -14382,7 +14385,7 @@ packages:
|
||||
resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: true
|
||||
|
||||
/ast-types@0.15.2:
|
||||
@@ -19738,7 +19741,7 @@ packages:
|
||||
resolution: {integrity: sha512-iACCiXeMYOvZqlF1kTiYINzgepRBymz1wwjiuup9u9nayhb6g4fSwiyJ/6adli+EPwrWtpgQAh2PoS7HukEGEg==}
|
||||
engines: {node: '>= 10'}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: false
|
||||
|
||||
/file-system-cache@2.3.0:
|
||||
@@ -32615,7 +32618,7 @@ packages:
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
dependencies:
|
||||
'@pkgr/core': 0.1.1
|
||||
tslib: 2.6.2
|
||||
tslib: 2.8.0
|
||||
dev: true
|
||||
|
||||
/tailwindcss@3.4.14(ts-node@10.9.2):
|
||||
|
||||
Reference in New Issue
Block a user