inventory.stock-turnover@1.0.0
impl/typescript.ts
1,527 bytes · the TypeScript implementation · view raw
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { roundDiv } from "./math_round_div.ts"; ← from math.round-div ^1.0.0 · built alongside by fune
import { type Money, assertSameCurrency, money } from "./money_amount.ts"; ← from money.amount ^1.0.0 · built alongside by fune
import { type StockTurnover } from "./inventory_stock_turnover_types.ts";
function notNegative(name: string, amount: Money): void {
if (amount.minor < 0) throw new RangeError(`${name} must not be negative, received ${amount.minor}`);
}
/**
* Turns, days inventory outstanding and days of cover. Each is one exact
* division rounded half-up, then made a float, so every language agrees.
*/
export function stockTurnover(openingStock: Money, closingStock: Money, costOfSales: Money, periodDays: number): StockTurnover {
assertSameCurrency(openingStock, closingStock);
assertSameCurrency(openingStock, costOfSales);
notNegative("openingStock", openingStock);
notNegative("closingStock", closingStock);
notNegative("costOfSales", costOfSales);
if (!Number.isInteger(periodDays) || periodDays < 1) {
throw new RangeError(`periodDays must be a whole number of days, at least 1, received ${periodDays}`);
}
const both = openingStock.minor + closingStock.minor;
const cogs = costOfSales.minor;
return {
averageStock: money(roundDiv(both, 2, "half-up"), openingStock.currency),
turns: both === 0 ? null : roundDiv(cogs * 200, both, "half-up") / 100,
daysInventoryOutstanding: cogs === 0 ? null : roundDiv(both * periodDays * 10, cogs * 2, "half-up") / 10,
daysOfCover: cogs === 0 ? null : roundDiv(closingStock.minor * periodDays * 10, cogs, "half-up") / 10,
};
}