|
- /** Keys used to pick one inventory row when an item has multiple stock-UOM buckets. */
- export type InventoryBucketPick = {
- itemId?: number | null;
- itemCode?: string | null;
- itemName?: string | null;
- uomId?: number | null;
- stockUomId?: number | null;
- uom?: string | null;
- shortUom?: string | null;
- stockUom?: string | null;
- };
-
- export type InventoryBucketRow = {
- itemId?: number | null;
- itemCode?: string | null;
- itemName?: string | null;
- stockUomId?: number | null;
- uomCode?: string | null;
- uomUdfudesc?: string | null;
- uomShortDesc?: string | null;
- availableQty?: number | null;
- onHandQty?: number | null;
- unavailableQty?: number | null;
- };
-
- const norm = (s?: string | null) => (s ?? "").trim().toLowerCase();
-
- /** Available = onHand − unavailable. Do not treat 0 as missing (`||` is wrong). */
- export function inventoryAvailableQty(inv: InventoryBucketRow): number {
- if (inv.availableQty != null && !Number.isNaN(Number(inv.availableQty))) {
- return Number(inv.availableQty);
- }
- return Number(inv.onHandQty ?? 0) - Number(inv.unavailableQty ?? 0);
- }
-
- function itemMatches(inv: InventoryBucketRow, pick: InventoryBucketPick): boolean {
- if (pick.itemId != null && inv.itemId != null) {
- return Number(inv.itemId) === Number(pick.itemId);
- }
- if (pick.itemCode && inv.itemCode) {
- return inv.itemCode === pick.itemCode;
- }
- if (pick.itemName && inv.itemName) {
- return inv.itemName === pick.itemName;
- }
- return false;
- }
-
- function uomMatches(inv: InventoryBucketRow, pick: InventoryBucketPick): boolean {
- const pickUomId = pick.stockUomId ?? pick.uomId;
- if (pickUomId != null && inv.stockUomId != null) {
- return Number(inv.stockUomId) === Number(pickUomId);
- }
- const labels = [pick.uom, pick.shortUom, pick.stockUom].map(norm).filter(Boolean);
- if (labels.length === 0) return true;
- const invLabels = [inv.uomUdfudesc, inv.uomShortDesc, inv.uomCode].map(norm);
- return labels.some((l) => invLabels.includes(l));
- }
-
- export function matchInventoryBucket(
- inventories: InventoryBucketRow[],
- pick: InventoryBucketPick,
- ): InventoryBucketRow | undefined {
- const itemHits = inventories.filter((inv) => itemMatches(inv, pick));
- if (itemHits.length === 0) return undefined;
- const hasUomPick =
- pick.stockUomId != null ||
- pick.uomId != null ||
- [pick.uom, pick.shortUom, pick.stockUom].some((s) => Boolean(norm(s)));
- if (hasUomPick) {
- return itemHits.find((inv) => uomMatches(inv, pick));
- }
- return itemHits[0];
- }
-
- export function getStockAvailableFromInventories(
- inventories: InventoryBucketRow[],
- pick: InventoryBucketPick,
- ): number {
- const inv = matchInventoryBucket(inventories, pick);
- return inv ? inventoryAvailableQty(inv) : 0;
- }
|