2
0
mirror of https://github.com/frappe/books.git synced 2024-12-23 19:39:07 +00:00
books/reports/inventory/helpers.ts
2023-01-05 11:14:05 +05:30

200 lines
4.4 KiB
TypeScript

import { Fyo } from 'fyo';
import { StockQueue } from 'models/inventory/stockQueue';
import { ValuationMethod } from 'models/inventory/types';
import { ModelNameEnum } from 'models/types';
import { safeParseFloat, safeParseInt } from 'utils/index';
import {
ComputedStockLedgerEntry,
RawStockLedgerEntry,
StockBalanceEntry,
} from './types';
type Item = string;
type Location = string;
export async function getRawStockLedgerEntries(fyo: Fyo) {
const fieldnames = [
'name',
'date',
'item',
'rate',
'quantity',
'location',
'referenceName',
'referenceType',
];
return (await fyo.db.getAllRaw(ModelNameEnum.StockLedgerEntry, {
fields: fieldnames,
orderBy: ['date', 'created', 'name'],
order: 'asc',
})) as RawStockLedgerEntry[];
}
export function getStockLedgerEntries(
rawSLEs: RawStockLedgerEntry[],
valuationMethod: ValuationMethod
): ComputedStockLedgerEntry[] {
const computedSLEs: ComputedStockLedgerEntry[] = [];
const stockQueues: Record<Item, Record<Location, StockQueue>> = {};
for (const sle of rawSLEs) {
const name = safeParseInt(sle.name);
const date = new Date(sle.date);
const rate = safeParseFloat(sle.rate);
const { item, location, quantity, referenceName, referenceType } = sle;
if (quantity === 0) {
continue;
}
stockQueues[item] ??= {};
stockQueues[item][location] ??= new StockQueue();
const q = stockQueues[item][location];
const initialValue = q.value;
let incomingRate: number | null;
if (quantity > 0) {
incomingRate = q.inward(rate, quantity);
} else {
incomingRate = q.outward(-quantity);
}
if (incomingRate === null) {
continue;
}
const balanceQuantity = q.quantity;
let valuationRate = q.fifo;
if (valuationMethod === ValuationMethod.MovingAverage) {
valuationRate = q.movingAverage;
}
const balanceValue = q.value;
const valueChange = balanceValue - initialValue;
const csle: ComputedStockLedgerEntry = {
name,
date,
item,
location,
quantity,
balanceQuantity,
incomingRate,
valuationRate,
balanceValue,
valueChange,
referenceName,
referenceType,
};
computedSLEs.push(csle);
}
return computedSLEs;
}
export function getStockBalanceEntries(
computedSLEs: ComputedStockLedgerEntry[],
filters: {
item?: string;
location?: string;
fromDate?: string;
toDate?: string;
}
): StockBalanceEntry[] {
const sbeMap: Record<Item, Record<Location, StockBalanceEntry>> = {};
const fromDate = filters.fromDate ? Date.parse(filters.fromDate) : null;
const toDate = filters.toDate ? Date.parse(filters.toDate) : null;
for (const sle of computedSLEs) {
if (filters.item && sle.item !== filters.item) {
continue;
}
if (filters.location && sle.location !== filters.location) {
continue;
}
sbeMap[sle.item] ??= {};
sbeMap[sle.item][sle.location] ??= getSBE(sle.item, sle.location);
const date = sle.date.valueOf();
if (fromDate && date < fromDate) {
const sbe = sbeMap[sle.item][sle.location]!;
updateOpeningBalances(sbe, sle);
continue;
}
if (toDate && date > toDate) {
continue;
}
const sbe = sbeMap[sle.item][sle.location]!;
updateCurrentBalances(sbe, sle);
}
return Object.values(sbeMap)
.map((sbes) => Object.values(sbes))
.flat();
}
function getSBE(item: string, location: string): StockBalanceEntry {
return {
name: 0,
item,
location,
balanceQuantity: 0,
balanceValue: 0,
openingQuantity: 0,
openingValue: 0,
incomingQuantity: 0,
incomingValue: 0,
outgoingQuantity: 0,
outgoingValue: 0,
valuationRate: 0,
};
}
function updateOpeningBalances(
sbe: StockBalanceEntry,
sle: ComputedStockLedgerEntry
) {
sbe.openingQuantity += sle.quantity;
sbe.openingValue += sle.valueChange;
sbe.balanceQuantity += sle.quantity;
sbe.balanceValue += sle.valueChange;
}
function updateCurrentBalances(
sbe: StockBalanceEntry,
sle: ComputedStockLedgerEntry
) {
sbe.balanceQuantity += sle.quantity;
sbe.balanceValue += sle.valueChange;
if (sle.quantity > 0) {
sbe.incomingQuantity += sle.quantity;
sbe.incomingValue += sle.valueChange;
} else {
sbe.outgoingQuantity -= sle.quantity;
sbe.outgoingValue -= sle.valueChange;
}
sbe.valuationRate = sle.valuationRate;
}