mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 05:40:31 +00:00
fix: Date format in sales/purchases APIs.
fix: Algorithm FIFO cost calculate method.
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import {
|
||||
InventoryTransaction,
|
||||
Item
|
||||
Item,
|
||||
Option,
|
||||
} from '@/models';
|
||||
import InventoryAverageCost from '@/services/Inventory/InventoryAverageCost';
|
||||
import InventoryCostLotTracker from '@/services/Inventory/InventoryCostLotTracker';
|
||||
import { option } from 'commander';
|
||||
|
||||
type TCostMethod = 'FIFO' | 'LIFO' | 'AVG';
|
||||
|
||||
@@ -38,10 +40,7 @@ export default class InventoryService {
|
||||
*/
|
||||
static async recordInventoryTransactions(
|
||||
entries: [],
|
||||
date: Date,
|
||||
transactionType: string,
|
||||
transactionId: number,
|
||||
direction: string,
|
||||
deleteOld: boolean,
|
||||
) {
|
||||
const storedOpers: any = [];
|
||||
const entriesItemsIds = entries.map((e: any) => e.item_id);
|
||||
@@ -56,19 +55,22 @@ export default class InventoryService {
|
||||
const inventoryEntries = entries.filter(
|
||||
(entry: any) => inventoryItemsIds.indexOf(entry.item_id) !== -1
|
||||
);
|
||||
inventoryEntries.forEach((entry: any) => {
|
||||
inventoryEntries.forEach(async (entry: any) => {
|
||||
if (deleteOld) {
|
||||
await this.deleteInventoryTransactions(
|
||||
entry.transactionId,
|
||||
entry.transactionType,
|
||||
);
|
||||
}
|
||||
const oper = InventoryTransaction.tenant().query().insert({
|
||||
date,
|
||||
direction,
|
||||
item_id: entry.item_id,
|
||||
quantity: entry.quantity,
|
||||
rate: entry.rate,
|
||||
transaction_type: transactionType,
|
||||
transaction_id: transactionId,
|
||||
...entry,
|
||||
lotNumber: entry.lotNumber,
|
||||
});
|
||||
storedOpers.push(oper);
|
||||
});
|
||||
return Promise.all(storedOpers);
|
||||
});
|
||||
return Promise.all([
|
||||
...storedOpers,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,4 +92,24 @@ export default class InventoryService {
|
||||
revertInventoryLotsCost(fromDate?: Date) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the lot number after the increment.
|
||||
*/
|
||||
static async nextLotNumber() {
|
||||
const LOT_NUMBER_KEY = 'lot_number_increment';
|
||||
const effectRows = await Option.tenant().query()
|
||||
.where('key', LOT_NUMBER_KEY)
|
||||
.increment('value', 1);
|
||||
|
||||
if (effectRows) {
|
||||
await Option.tenant().query()
|
||||
.insert({
|
||||
key: LOT_NUMBER_KEY,
|
||||
value: 1,
|
||||
});
|
||||
}
|
||||
const options = await Option.tenant().query();
|
||||
return options.getMeta(LOT_NUMBER_KEY, 1);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { omit, pick, chain } from 'lodash';
|
||||
import uniqid from 'uniqid';
|
||||
import {
|
||||
InventoryTransaction,
|
||||
InventoryLotCostTracker,
|
||||
@@ -62,6 +61,7 @@ export default class InventoryCostLotTracker implements IInventoryCostMethod {
|
||||
.query()
|
||||
.where('date', '>=', this.startingDate)
|
||||
.orderBy('date', 'ASC')
|
||||
.orderBy('lot_number', 'ASC')
|
||||
.where('item_id', this.itemId)
|
||||
.withGraphFetched('item');
|
||||
|
||||
@@ -70,6 +70,7 @@ export default class InventoryCostLotTracker implements IInventoryCostMethod {
|
||||
.query()
|
||||
.where('date', '<', this.startingDate)
|
||||
.orderBy('date', 'ASC')
|
||||
.orderBy('lot_number', 'ASC')
|
||||
.where('item_id', this.itemId)
|
||||
.where('direction', 'IN')
|
||||
.whereNot('remaining', 0);
|
||||
@@ -267,17 +268,16 @@ export default class InventoryCostLotTracker implements IInventoryCostMethod {
|
||||
...commonLotTransaction,
|
||||
decrement: 0,
|
||||
remaining: commonLotTransaction.remaining || commonLotTransaction.quantity,
|
||||
lotNumber: commonLotTransaction.lotNumber || uniqid.time(),
|
||||
};
|
||||
costLotsTransactions.push(inventoryINTrans[id]);
|
||||
|
||||
// Record inventory 'OUT' cost lots from 'IN' transactions.
|
||||
} else if (transaction.direction === 'OUT') {
|
||||
let invRemaining = transaction.quantity;
|
||||
const idsShouldDel: number[] = [];
|
||||
|
||||
inventoryByItem?.[itemId]?.some((
|
||||
_invTransactionId: number,
|
||||
index: number,
|
||||
) => {
|
||||
const _invINTransaction = inventoryINTrans[_invTransactionId];
|
||||
if (invRemaining <= 0) { return true; }
|
||||
@@ -285,22 +285,23 @@ export default class InventoryCostLotTracker implements IInventoryCostMethod {
|
||||
// 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);
|
||||
|
||||
_invINTransaction.decrement += decrement;
|
||||
_invINTransaction.decrement += maxDecrement;
|
||||
_invINTransaction.remaining = Math.max(
|
||||
_invINTransaction.remaining - decrement,
|
||||
_invINTransaction.remaining - maxDecrement,
|
||||
0,
|
||||
);
|
||||
invRemaining = Math.max(invRemaining - decrement, 0);
|
||||
invRemaining = Math.max(invRemaining - maxDecrement, 0);
|
||||
|
||||
costLotsTransactions.push({
|
||||
...commonLotTransaction,
|
||||
quantity: decrement,
|
||||
quantity: maxDecrement,
|
||||
lotNumber: _invINTransaction.lotNumber,
|
||||
});
|
||||
// Pop the 'IN' lots that has zero remaining.
|
||||
if (_invINTransaction.remaining === 0) {
|
||||
inventoryByItem?.[itemId].splice(index, 1);
|
||||
idsShouldDel.push(_invTransactionId);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@@ -310,6 +311,9 @@ export default class InventoryCostLotTracker implements IInventoryCostMethod {
|
||||
quantity: invRemaining,
|
||||
});
|
||||
}
|
||||
// Remove the IN transactions that has zero remaining amount.
|
||||
inventoryByItem[itemId] = inventoryByItem?.[itemId]
|
||||
?.filter((transId: number) => idsShouldDel.indexOf(transId) === -1);
|
||||
}
|
||||
});
|
||||
return costLotsTransactions;
|
||||
|
||||
Reference in New Issue
Block a user