All files / src/api/analytics stock.ts

100% Statements 77/77
88.23% Branches 15/17
100% Functions 3/3
100% Lines 77/77

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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 771x 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 1x 1x 1x 3x 3x 3x 3x 1x 3x 3x 1x 1x 1x 1x 1x 1x 3x 1x 1x 3x 3x 3x 3x 1x 2x 2x 2x 1x 1x 1x 1x 3x 1x 1x 3x 3x 3x 3x 1x 1x 1x 1x 1x 1x 3x 1x 1x
/**
* @file stock.ts
* @module api/analytics/stock
*
* @summary
* Stock value time series and monthly movement endpoints.
* Functions are resilient and return `[]` on any error to keep charts rendering.
* @enterprise
* - Resilient data fetching with graceful error handling
* - TypeDoc documentation for stock analytics functions
*/
import http from '../httpClient';
import { asNumber, paramClean } from './util';
import type { AnalyticsParams } from './validation';
import type { StockValuePoint, MonthlyMovement, StockPerSupplierPoint } from './types';
 
// Backend DTO shims (tolerant, local to this module)
type BackendStockValueDTO = { date?: string; totalValue?: unknown };
type BackendMonthlyMovementDTO = { month?: string; stockIn?: unknown; stockOut?: unknown };
 
 
/** Fetch total inventory value over time. 
 * Returns array of {date, totalValue}. Empty array on errors.
 * @example
 * ```typescript
 * const points = await getStockValueOverTime({
 *   from: '2025-09-01',
 *   to: '2025-11-30',
 *   supplierId: 'SUP-001'
 * });
 * return <LineChart data={points} />;
 * ```
*/
export async function getStockValueOverTime(p?: AnalyticsParams): Promise<StockValuePoint[]> {
    try {
        const { data } = await http.get<unknown>('/api/analytics/stock-value', { params: paramClean(p) });
        if (!Array.isArray(data)) return [];
        const rows = (data as BackendStockValueDTO[]).map((d) => ({
            date: String(d.date ?? ''),
            totalValue: asNumber(d.totalValue),
        }));
        rows.sort((a, b) => a.date.localeCompare(b.date));
        return rows;
    } catch {
        return [];
    }
}
 
/** Fetch monthly stock movement (in/out). */
export async function getMonthlyStockMovement(p?: AnalyticsParams): Promise<MonthlyMovement[]> {
    try {
        const { data } = await http.get<unknown>('/api/analytics/monthly-stock-movement', { params: paramClean(p) });
        if (!Array.isArray(data)) return [];
        return (data as BackendMonthlyMovementDTO[]).map((d) => ({
            month: String(d.month ?? ''),
            stockIn: asNumber(d.stockIn),
            stockOut: asNumber(d.stockOut),
        }));
    } catch {
        return [];
    }
}
 
/** Fetch a current snapshot of totals per supplier. (No date filters.) */
export async function getStockPerSupplier(): Promise<StockPerSupplierPoint[]> {
    try {
        const { data } = await http.get<unknown>('/api/analytics/stock-per-supplier');
        if (!Array.isArray(data)) return [];
        return (data as Array<{ supplierName?: string; totalQuantity?: unknown }>)
        .map((d) => ({ supplierName: String(d.supplierName ?? ''), totalQuantity: asNumber(d.totalQuantity) }))
        .filter((r) => r.supplierName);
    } catch {
        return [];
    }
}
 
export type { StockValuePoint, MonthlyMovement } from './types';