mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 05:40:31 +00:00
feat: average rate cost method.
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
import { Container, Service, Inject } from 'typedi';
|
||||
import { IInventoryTransaction, IItem } from 'interfaces'
|
||||
import { pick } from 'lodash';
|
||||
import {
|
||||
EventDispatcher,
|
||||
EventDispatcherInterface,
|
||||
} from 'decorators/eventDispatcher';
|
||||
import { IInventoryTransaction, IItem, IItemEntry } from 'interfaces'
|
||||
import InventoryAverageCost from 'services/Inventory/InventoryAverageCost';
|
||||
import InventoryCostLotTracker from 'services/Inventory/InventoryCostLotTracker';
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import events from 'subscribers/events';
|
||||
|
||||
type TCostMethod = 'FIFO' | 'LIFO' | 'AVG';
|
||||
|
||||
@@ -11,6 +17,31 @@ export default class InventoryService {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
@EventDispatcher()
|
||||
eventDispatcher: EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* Transforms the items entries to inventory transactions.
|
||||
*/
|
||||
transformItemEntriesToInventory(
|
||||
itemEntries: IItemEntry[],
|
||||
transactionType: string,
|
||||
transactionId: number,
|
||||
direction: 'IN'|'OUT',
|
||||
date: Date|string,
|
||||
lotNumber: number,
|
||||
) {
|
||||
return itemEntries.map((entry: IItemEntry) => ({
|
||||
...pick(entry, ['itemId', 'quantity', 'rate']),
|
||||
lotNumber,
|
||||
transactionType,
|
||||
transactionId,
|
||||
direction,
|
||||
date,
|
||||
entryId: entry.id,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -21,25 +52,23 @@ export default class InventoryService {
|
||||
async computeItemCost(tenantId: number, fromDate: Date, itemId: number) {
|
||||
const { Item } = this.tenancy.models(tenantId);
|
||||
|
||||
const item = await Item.query()
|
||||
.findById(itemId)
|
||||
.withGraphFetched('category');
|
||||
// Fetches the item with assocaited 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.');
|
||||
}
|
||||
const costMethod: TCostMethod = item.category.costMethod;
|
||||
let costMethodComputer: IInventoryCostMethod;
|
||||
|
||||
// Switch between methods based on the item cost method.
|
||||
switch(costMethod) {
|
||||
switch('AVG') {
|
||||
case 'FIFO':
|
||||
case 'LIFO':
|
||||
costMethodComputer = new InventoryCostLotTracker(fromDate, itemId);
|
||||
costMethodComputer = new InventoryCostLotTracker(tenantId, fromDate, itemId);
|
||||
break;
|
||||
case 'AVG':
|
||||
costMethodComputer = new InventoryAverageCost(fromDate, itemId);
|
||||
costMethodComputer = new InventoryAverageCost(tenantId, fromDate, itemId);
|
||||
break;
|
||||
}
|
||||
return costMethodComputer.computeItemCost();
|
||||
@@ -54,9 +83,36 @@ export default class InventoryService {
|
||||
async scheduleComputeItemCost(tenantId: number, itemId: number, startingDate: Date|string) {
|
||||
const agenda = Container.get('agenda');
|
||||
|
||||
return agenda.schedule('in 3 seconds', 'compute-item-cost', {
|
||||
startingDate, itemId, tenantId,
|
||||
// Cancel any `compute-item-cost` in the queue has upper starting date
|
||||
// with the same given item.
|
||||
await agenda.cancel({
|
||||
name: 'compute-item-cost',
|
||||
nextRunAt: { $ne: null },
|
||||
'data.tenantId': tenantId,
|
||||
'data.itemId': itemId,
|
||||
'data.startingDate': { "$gt": startingDate }
|
||||
});
|
||||
|
||||
// Retrieve any `compute-item-cost` in the queue has lower starting date
|
||||
// with the same given item.
|
||||
const dependsJobs = await agenda.jobs({
|
||||
name: 'compute-item-cost',
|
||||
nextRunAt: { $ne: null },
|
||||
'data.tenantId': tenantId,
|
||||
'data.itemId': itemId,
|
||||
'data.startingDate': { "$lte": startingDate }
|
||||
});
|
||||
if (dependsJobs.length === 0) {
|
||||
await agenda.schedule('in 30 seconds', 'compute-item-cost', {
|
||||
startingDate, itemId, tenantId,
|
||||
});
|
||||
|
||||
// Triggers `onComputeItemCostJobScheduled` event.
|
||||
await this.eventDispatcher.dispatch(
|
||||
events.inventory.onComputeItemCostJobScheduled,
|
||||
{ startingDate, itemId, tenantId },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,24 +124,11 @@ export default class InventoryService {
|
||||
*/
|
||||
async recordInventoryTransactions(
|
||||
tenantId: number,
|
||||
entries: IInventoryTransaction[],
|
||||
inventoryEntries: IInventoryTransaction[],
|
||||
deleteOld: boolean,
|
||||
): Promise<void> {
|
||||
const { InventoryTransaction, Item } = this.tenancy.models(tenantId);
|
||||
|
||||
// Mapping the inventory entries items ids.
|
||||
const entriesItemsIds = entries.map((e: any) => e.itemId);
|
||||
const inventoryItems = await Item.query()
|
||||
.whereIn('id', entriesItemsIds)
|
||||
.where('type', 'inventory');
|
||||
|
||||
// Mapping the inventory items ids.
|
||||
const inventoryItemsIds = inventoryItems.map((i: IItem) => i.id);
|
||||
|
||||
// Filter the bill entries that have inventory items.
|
||||
const inventoryEntries = entries.filter(
|
||||
(entry: IInventoryTransaction) => inventoryItemsIds.indexOf(entry.itemId) !== -1
|
||||
);
|
||||
inventoryEntries.forEach(async (entry: any) => {
|
||||
if (deleteOld) {
|
||||
await this.deleteInventoryTransactions(
|
||||
@@ -108,14 +151,14 @@ export default class InventoryService {
|
||||
* @param {number} transactionId
|
||||
* @return {Promise}
|
||||
*/
|
||||
deleteInventoryTransactions(
|
||||
async deleteInventoryTransactions(
|
||||
tenantId: number,
|
||||
transactionId: number,
|
||||
transactionType: string,
|
||||
) {
|
||||
): Promise<void> {
|
||||
const { InventoryTransaction } = this.tenancy.models(tenantId);
|
||||
|
||||
return InventoryTransaction.query()
|
||||
await InventoryTransaction.query()
|
||||
.where('transaction_type', transactionType)
|
||||
.where('transaction_id', transactionId)
|
||||
.delete();
|
||||
@@ -125,22 +168,37 @@ export default class InventoryService {
|
||||
* Retrieve the lot number after the increment.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
*/
|
||||
async nextLotNumber(tenantId: number) {
|
||||
const { Option } = this.tenancy.models(tenantId);
|
||||
getNextLotNumber(tenantId: number) {
|
||||
const settings = this.tenancy.settings(tenantId);
|
||||
|
||||
const LOT_NUMBER_KEY = 'lot_number_increment';
|
||||
const effectRows = await Option.query()
|
||||
.where('key', LOT_NUMBER_KEY)
|
||||
.increment('value', 1);
|
||||
const storedLotNumber = settings.find({ key: LOT_NUMBER_KEY });
|
||||
|
||||
if (effectRows === 0) {
|
||||
await Option.query()
|
||||
.insert({
|
||||
key: LOT_NUMBER_KEY,
|
||||
value: 1,
|
||||
});
|
||||
return (storedLotNumber && storedLotNumber.value) ?
|
||||
parseInt(storedLotNumber.value, 10) : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the next inventory LOT number.
|
||||
* @param {number} tenantId
|
||||
* @return {Promise<number>}
|
||||
*/
|
||||
async incrementNextLotNumber(tenantId: number) {
|
||||
const settings = this.tenancy.settings(tenantId);
|
||||
|
||||
const LOT_NUMBER_KEY = 'lot_number_increment';
|
||||
const storedLotNumber = settings.find({ key: LOT_NUMBER_KEY });
|
||||
|
||||
let lotNumber = 1;
|
||||
|
||||
if (storedLotNumber && storedLotNumber.value) {
|
||||
lotNumber = parseInt(storedLotNumber.value, 10);
|
||||
lotNumber += 1;
|
||||
}
|
||||
const options = await Option.query();
|
||||
return options.getMeta(LOT_NUMBER_KEY, 1);
|
||||
settings.set({ key: LOT_NUMBER_KEY }, lotNumber);
|
||||
|
||||
await settings.save();
|
||||
|
||||
return lotNumber;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
import { pick } from 'lodash';
|
||||
import { raw } from 'objection';
|
||||
import { IInventoryTransaction } from 'interfaces';
|
||||
import InventoryCostMethod from 'services/Inventory/InventoryCostMethod';
|
||||
|
||||
export default class InventoryAverageCostMethod extends InventoryCostMethod implements IInventoryCostMethod {
|
||||
export default class InventoryAverageCostMethod
|
||||
extends InventoryCostMethod
|
||||
implements IInventoryCostMethod {
|
||||
startingDate: Date;
|
||||
itemId: number;
|
||||
costTransactions: any[];
|
||||
@@ -13,13 +16,9 @@ export default class InventoryAverageCostMethod extends InventoryCostMethod impl
|
||||
* @param {Date} startingDate -
|
||||
* @param {number} itemId - The given inventory item id.
|
||||
*/
|
||||
constructor(
|
||||
tenantId: number,
|
||||
startingDate: Date,
|
||||
itemId: number,
|
||||
) {
|
||||
super();
|
||||
|
||||
constructor(tenantId: number, startingDate: Date, itemId: number) {
|
||||
super(tenantId, startingDate, itemId);
|
||||
|
||||
this.startingDate = startingDate;
|
||||
this.itemId = itemId;
|
||||
this.costTransactions = [];
|
||||
@@ -27,154 +26,216 @@ export default class InventoryAverageCostMethod extends InventoryCostMethod impl
|
||||
|
||||
/**
|
||||
* 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
|
||||
* - 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
|
||||
* - Re-compute the inventory transactions and re-write the journal entries
|
||||
* after the given date.
|
||||
* ----------
|
||||
* @asycn
|
||||
* @param {Date} startingDate
|
||||
* @param {number} referenceId
|
||||
* @param {string} referenceType
|
||||
* @async
|
||||
* @param {Date} startingDate
|
||||
* @param {number} referenceId
|
||||
* @param {string} referenceType
|
||||
*/
|
||||
public async computeItemCost() {
|
||||
const { InventoryTransaction } = this.tenantModels;
|
||||
const openingAvgCost = await this.getOpeningAvaregeCost(this.startingDate, this.itemId);
|
||||
const {
|
||||
averageCost,
|
||||
openingQuantity,
|
||||
openingCost,
|
||||
} = await this.getOpeningAvaregeCost(this.startingDate, this.itemId);
|
||||
|
||||
const afterInvTransactions: IInventoryTransaction[] = await InventoryTransaction.query()
|
||||
.modify('filterDateRange', this.startingDate)
|
||||
.modify('filterDateRange', this.startingDate)
|
||||
.orderBy('date', 'ASC')
|
||||
.orderByRaw("FIELD(direction, 'IN', 'OUT')")
|
||||
.orderBy('lot_number', 'ASC')
|
||||
.where('item_id', this.itemId)
|
||||
.withGraphFetched('item');
|
||||
|
||||
// Tracking inventroy transactions and retrieve cost transactions
|
||||
// based on average rate cost method.
|
||||
|
||||
// Tracking inventroy transactions and retrieve cost transactions based on
|
||||
// average rate cost method.
|
||||
const costTransactions = this.trackingCostTransactions(
|
||||
afterInvTransactions,
|
||||
openingAvgCost,
|
||||
openingQuantity,
|
||||
openingCost
|
||||
);
|
||||
// Revert the inveout out lots transactions
|
||||
await this.revertTheInventoryOutLotTrans();
|
||||
|
||||
// Store inventory lots cost transactions.
|
||||
await this.storeInventoryLotsCost(costTransactions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get items Avarege cost from specific date from inventory transactions.
|
||||
* @static
|
||||
* @param {Date} startingDate
|
||||
* @async
|
||||
* @param {Date} closingDate
|
||||
* @return {number}
|
||||
*/
|
||||
public async getOpeningAvaregeCost(startingDate: Date, itemId: number) {
|
||||
const { InventoryTransaction } = this.tenantModels;
|
||||
public async getOpeningAvaregeCost(closingDate: Date, itemId: number) {
|
||||
const { InventoryCostLotTracker } = this.tenantModels;
|
||||
|
||||
const commonBuilder = (builder: any) => {
|
||||
if (startingDate) {
|
||||
builder.where('date', '<', startingDate);
|
||||
if (closingDate) {
|
||||
builder.where('date', '<', closingDate);
|
||||
}
|
||||
builder.where('item_id', itemId);
|
||||
builder.groupBy('rate');
|
||||
builder.groupBy('quantity');
|
||||
builder.groupBy('item_id');
|
||||
builder.groupBy('direction');
|
||||
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.
|
||||
|
||||
// @todo total `IN` transactions.
|
||||
const inInvSumationOper: Promise<any> = InventoryTransaction.query()
|
||||
const inInvSumationOper: Promise<any> = InventoryCostLotTracker.query()
|
||||
.onBuild(commonBuilder)
|
||||
.where('direction', 'IN')
|
||||
.first();
|
||||
.where('direction', 'IN');
|
||||
|
||||
// Calculates the total inventory total quantity and rate `OUT` transactions.
|
||||
// @todo total `OUT` transactions.
|
||||
const outInvSumationOper: Promise<any> = InventoryTransaction.query()
|
||||
const outInvSumationOper: Promise<any> = InventoryCostLotTracker.query()
|
||||
.onBuild(commonBuilder)
|
||||
.where('direction', 'OUT')
|
||||
.first();
|
||||
.where('direction', 'OUT');
|
||||
|
||||
const [inInvSumation, outInvSumation] = await Promise.all([
|
||||
inInvSumationOper,
|
||||
outInvSumationOper,
|
||||
]);
|
||||
return this.computeItemAverageCost(
|
||||
inInvSumation?.quantity || 0,
|
||||
inInvSumation?.rate || 0,
|
||||
outInvSumation?.quantity || 0,
|
||||
outInvSumation?.rate || 0
|
||||
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
|
||||
* @static
|
||||
* @param {number} quantityIn
|
||||
* @param {number} rateIn
|
||||
* @param {number} quantityOut
|
||||
* @param {number} rateOut
|
||||
*/
|
||||
public computeItemAverageCost(
|
||||
quantityIn: number,
|
||||
rateIn: number,
|
||||
totalCostIn: number,
|
||||
totalQuantityIn: number,
|
||||
|
||||
quantityOut: number,
|
||||
rateOut: number,
|
||||
totalCostOut: number,
|
||||
totalQuantityOut: number
|
||||
) {
|
||||
const totalQuantity = (quantityIn - quantityOut);
|
||||
const totalRate = (rateIn - rateOut);
|
||||
const averageCost = (totalRate) ? (totalQuantity / totalRate) : totalQuantity;
|
||||
const openingCost = totalCostIn - totalCostOut;
|
||||
const openingQuantity = totalQuantityIn - totalQuantityOut;
|
||||
|
||||
return averageCost;
|
||||
const averageCost = openingQuantity ? openingCost / openingQuantity : 0;
|
||||
|
||||
return { averageCost, openingCost, openingQuantity };
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the journal entries from specific item inventory transactions.
|
||||
* @param {IInventoryTransaction[]} invTransactions
|
||||
* @param {number} openingAverageCost
|
||||
* @param {string} referenceType
|
||||
* @param {number} referenceId
|
||||
* @param {JournalCommand} journalCommands
|
||||
* @param {IInventoryTransaction[]} invTransactions
|
||||
* @param {number} openingAverageCost
|
||||
* @param {string} referenceType
|
||||
* @param {number} referenceId
|
||||
* @param {JournalCommand} journalCommands
|
||||
*/
|
||||
public trackingCostTransactions(
|
||||
invTransactions: IInventoryTransaction[],
|
||||
openingAverageCost: number,
|
||||
openingQuantity: number = 0,
|
||||
openingCost: number = 0
|
||||
) {
|
||||
const costTransactions: any[] = [];
|
||||
let accQuantity: number = 0;
|
||||
let accCost: number = 0;
|
||||
|
||||
// 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: IInventoryTransaction) => {
|
||||
const commonEntry = {
|
||||
invTransId: invTransaction.id,
|
||||
...pick(invTransaction, ['date', 'direction', 'itemId', 'quantity', 'rate', 'entryId',
|
||||
'transactionId', 'transactionType']),
|
||||
...pick(invTransaction, [
|
||||
'date',
|
||||
'direction',
|
||||
'itemId',
|
||||
'quantity',
|
||||
'rate',
|
||||
'entryId',
|
||||
'transactionId',
|
||||
'transactionType',
|
||||
'lotNumber',
|
||||
]),
|
||||
};
|
||||
switch(invTransaction.direction) {
|
||||
switch (invTransaction.direction) {
|
||||
case 'IN':
|
||||
const inCost = invTransaction.rate * invTransaction.quantity;
|
||||
|
||||
// Increases the quantity and cost in `IN` inventory transactions.
|
||||
accQuantity += invTransaction.quantity;
|
||||
accCost += invTransaction.rate * invTransaction.quantity;
|
||||
accCost += inCost;
|
||||
|
||||
costTransactions.push({
|
||||
...commonEntry,
|
||||
cost: inCost,
|
||||
});
|
||||
break;
|
||||
case 'OUT':
|
||||
const transactionAvgCost = accCost ? (accCost / accQuantity) : 0;
|
||||
const averageCost = transactionAvgCost;
|
||||
const cost = (invTransaction.quantity * averageCost);
|
||||
const income = (invTransaction.quantity * invTransaction.rate);
|
||||
// Average cost = Total cost / Total quantity
|
||||
const averageCost = accQuantity ? accCost / accQuantity : 0;
|
||||
|
||||
accQuantity -= invTransaction.quantity;
|
||||
accCost -= income;
|
||||
const quantity =
|
||||
accQuantity > 0
|
||||
? Math.min(invTransaction.quantity, accQuantity)
|
||||
: invTransaction.quantity;
|
||||
|
||||
// Cost = the transaction quantity * Average cost.
|
||||
const cost = quantity * averageCost;
|
||||
|
||||
// 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()
|
||||
.modify('filterDateRange', this.startingDate)
|
||||
.orderBy('date', 'DESC')
|
||||
.where('item_id', this.itemId)
|
||||
.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ export default class InventoryCostLotTracker extends InventoryCostMethod impleme
|
||||
itemId: number,
|
||||
costMethod: TCostMethod = 'FIFO'
|
||||
) {
|
||||
super();
|
||||
super(tenantId, startingDate, itemId);
|
||||
|
||||
this.startingDate = startingDate;
|
||||
this.itemId = itemId;
|
||||
@@ -129,7 +129,7 @@ export default class InventoryCostLotTracker extends InventoryCostMethod impleme
|
||||
.withGraphFetched('item');
|
||||
|
||||
this.outTransactions = [ ...afterOUTTransactions ];
|
||||
}
|
||||
}
|
||||
|
||||
private async fetchItemsMapped() {
|
||||
const itemsIds = chain(this.inTransactions).map((e) => e.itemId).uniq().value();
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { omit } from 'lodash';
|
||||
import { Inject } from 'typedi';
|
||||
import { Container } from 'typedi';
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import { IInventoryLotCost } from 'interfaces';
|
||||
|
||||
export default class InventoryCostMethod {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
tenantModels: any;
|
||||
|
||||
@@ -13,27 +12,29 @@ export default class InventoryCostMethod {
|
||||
* @param {number} tenantId - The given tenant id.
|
||||
*/
|
||||
constructor(tenantId: number, startingDate: Date, itemId: number) {
|
||||
this.tenantModels = this.tenantModels.models(tenantId);
|
||||
const tenancyService = Container.get(TenancyService);
|
||||
|
||||
this.tenantModels = tenancyService.models(tenantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the inventory lots costs transactions in bulk.
|
||||
* @param {IInventoryLotCost[]} costLotsTransactions
|
||||
* @param {IInventoryLotCost[]} costLotsTransactions
|
||||
* @return {Promise[]}
|
||||
*/
|
||||
public storeInventoryLotsCost(costLotsTransactions: IInventoryLotCost[]): Promise<object> {
|
||||
const { InventoryLotCostTracker } = this.tenantModels;
|
||||
const { InventoryCostLotTracker } = this.tenantModels;
|
||||
const opers: any = [];
|
||||
|
||||
costLotsTransactions.forEach((transaction: IInventoryLotCost) => {
|
||||
costLotsTransactions.forEach((transaction: any) => {
|
||||
if (transaction.lotTransId && transaction.decrement) {
|
||||
const decrementOper = InventoryLotCostTracker.query()
|
||||
const decrementOper = InventoryCostLotTracker.query()
|
||||
.where('id', transaction.lotTransId)
|
||||
.decrement('remaining', transaction.decrement);
|
||||
opers.push(decrementOper);
|
||||
|
||||
} else if(!transaction.lotTransId) {
|
||||
const operation = InventoryLotCostTracker.query()
|
||||
const operation = InventoryCostLotTracker.query()
|
||||
.insert({
|
||||
...omit(transaction, ['decrement', 'invTransId', 'lotTransId']),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user