All files / src/api/analytics lowStock.ts

100% Statements 61/61
91.66% Branches 11/12
100% Functions 1/1
100% Lines 61/61

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 611x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 6x 6x 5x 5x 5x 5x 4x 4x 4x 4x 6x 2x 4x 4x 4x 4x 5x 5x 5x 5x 4x 4x 4x 4x 4x 4x 4x 6x 1x 1x 6x
/**
* @file lowStock.ts
* @module api/analytics/lowStock
*
* @summary
* Low-stock table: tolerant parsing + severity sorting.
* Fetches and normalizes low-stock item data for a given supplier.
* @enterprise
* - Robust data parsing with flexible field recognition
* - Severity-based sorting for actionable insights
* - TypeDoc documentation for low-stock analytics function
*/
 
import http from '../httpClient';
import { isArrayOfRecords, isRecord, pickNumber, pickString, paramClean } from './util';
import type { AnalyticsParams } from './validation';
import type { LowStockRow } from './types';
 
 
/** Fetch low-stock rows for a given supplier, optionally bounded by dates. 
 * Returns array of {itemName, quantity, minimumQuantity}. Empty array on errors.
 * @example
 * ```typescript
 * const lowStockItems = await getLowStockItems('SUP-001', {
 *  from: '2025-09-01',
 * to: '2025-11-30'
 * });
 * return <AlertTable data={lowStockItems} />;
 * ```
*/
export async function getLowStockItems(supplierId: string, p?: AnalyticsParams): Promise<LowStockRow[]> {
    if (!supplierId) return [];
    try {
        const { data } = await http.get<unknown>('/api/analytics/low-stock-items', {
            params: { supplierId, ...paramClean(p) },
        });
        
        
        // Accept either a direct array or an envelope with `.items` array.
        let rawList: Array<Record<string, unknown>> = [];
        if (isArrayOfRecords(data)) rawList = data;
        else if (isRecord(data) && isArrayOfRecords((data as Record<string, unknown>).items as unknown)) rawList = (data as Record<string, unknown>).items as Array<Record<string, unknown>>;
        
        // Parse rows with tolerant field picking
        const rows: LowStockRow[] = rawList
        .map((rec) => {
            const itemName = pickString(rec, ['itemName', 'name']);
            const quantity = pickNumber(rec, ['quantity', 'qty', 'currentQty']);
            const minimumQuantity = pickNumber(rec, ['minimumQuantity', 'minQuantity', 'minQty', 'minimum']);
            return itemName ? { itemName, quantity, minimumQuantity } : null;
        })
        .filter((x): x is LowStockRow => x !== null);
        
        
        // Sort by severity (deficit descending)
        rows.sort((a, b) => (b.minimumQuantity - b.quantity) - (a.minimumQuantity - a.quantity));
        return rows;
    } catch {
        return [];
    }
}