Files
dashboard-cpsp/utils/reportTotals.ts
T
2026-08-26 13:46:05 +07:00

113 lines
3.1 KiB
TypeScript

import type {
DashboardReportCountingRow,
DashboardReportFeedInRow,
DashboardReportFeedOutRow,
DashboardReportFeedUseRow,
} from '../types/dashboardReport.ts';
export const REPORT_TOTAL_LABEL = 'Total';
const isPresentNumber = (value: number | null | undefined): value is number =>
typeof value === 'number' && Number.isFinite(value);
function sumPresent(values: Array<number | null | undefined>): number | null {
let total = 0;
let any = false;
for (const value of values) {
if (!isPresentNumber(value)) continue;
total += value;
any = true;
}
return any ? total : null;
}
const sackAccuracy = (manual: number | null, iot: number | null): number | null => {
if (manual != null && iot != null && manual > 0 && iot > 0) {
return Math.round((Math.min(manual, iot) / Math.max(manual, iot)) * 1000) / 10;
}
if (manual === 0 && iot === 0) return 100;
return null;
};
export interface CountingTotalsRow {
label: string;
countBefore: number | null;
mortality: number | null;
harvest: number | null;
harvestWeight: number | null;
countAfter: number | null;
iotCount: number | null;
accuracy: number | null;
}
export interface FeedInTotalsRow {
label: string;
manualIn: number | null;
iotIn: number | null;
accuracy: number | null;
}
export interface FeedUseTotalsRow {
label: string;
manualUse: number | null;
iotUse: number | null;
accuracy: number | null;
}
export interface FeedOutTotalsRow {
label: string;
manualOut: number | null;
iotOut: number | null;
accuracy: number | null;
}
export function countingTotals(rows: DashboardReportCountingRow[]): CountingTotalsRow | null {
if (!rows.length) return null;
return {
label: REPORT_TOTAL_LABEL,
countBefore: null,
mortality: sumPresent(rows.map((row) => row.mortality)),
harvest: sumPresent(rows.map((row) => row.harvest)),
harvestWeight: sumPresent(rows.map((row) => row.harvestWeight)),
countAfter: null,
iotCount: null,
accuracy: null,
};
}
export function feedInTotals(rows: DashboardReportFeedInRow[]): FeedInTotalsRow | null {
if (!rows.length) return null;
const manualIn = sumPresent(rows.map((row) => row.manualIn));
const iotIn = sumPresent(rows.map((row) => row.iotIn));
return {
label: REPORT_TOTAL_LABEL,
manualIn,
iotIn,
accuracy: sackAccuracy(manualIn, iotIn),
};
}
export function feedUseTotals(rows: DashboardReportFeedUseRow[]): FeedUseTotalsRow | null {
if (!rows.length) return null;
const manualUse = sumPresent(rows.map((row) => row.manualUse));
const iotUse = sumPresent(rows.map((row) => row.iotUse));
return {
label: REPORT_TOTAL_LABEL,
manualUse,
iotUse,
accuracy: sackAccuracy(manualUse, iotUse),
};
}
export function feedOutTotals(rows: DashboardReportFeedOutRow[]): FeedOutTotalsRow | null {
if (!rows.length) return null;
const manualOut = sumPresent(rows.map((row) => row.manualOut));
const iotOut = sumPresent(rows.map((row) => row.iotOut));
return {
label: REPORT_TOTAL_LABEL,
manualOut,
iotOut,
accuracy: sackAccuracy(manualOut, iotOut),
};
}