The KPI payload has carried income, expenses and net per month since the aggregates RPC, but after the Recharts trend chart was dropped only the net column was rendered (the bars pane). A fiscal year's month-by-month sums were therefore fetched and never shown (#2196). - New components/kpi/KPIMonthsTable.tsx: full-width dry table (Manad, Intakter, Kostnader, Resultat) with the period totals as the last row, rendered between the panes and the cost story. Rows and totals come from the pure helper components/kpi/months-table.ts. - New preference showMonthlyTable (default true) on KPIPreferences: filled by mergeWithDefaults on read, accepted by the preferences route, sent whole by the dialog, required by readPreferencesBody. A boolean, not a KPI_DEFINITIONS id: stored kpiOrder arrays would hide a new id for every existing company. - One Switch row in the Anpassa dialog after the KPI list. - Reuses the orphaned kpi.trend_* keys; adds months_col_month, months_total and the two settings keys in sv and en. - Tests: helper rows/totals/inactive flags, defaults + merge, route accepts false and rejects a string; fixtures updated for the new field. Closes #2196 Claude-Session: https://claude.ai/code/session_0179bdetHyofL6ATfQxB5wP5 Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
import { roundOre } from '@/lib/money'
|
|
import type { KPIReport } from '@/types'
|
|
|
|
/**
|
|
* Rows for the month-by-month table under Nyckeltal (#2196): the report's
|
|
* `months` (one per month of the fiscal period, zero-filled) plus the
|
|
* period totals the panes already show, so the table foots to the same
|
|
* figures. Pure so the shape is testable without rendering.
|
|
*/
|
|
export interface MonthsTableRow {
|
|
label: string
|
|
income: number
|
|
expenses: number
|
|
net: number
|
|
/** No movement at all: ahead of the last booking or before the first one. */
|
|
inactive: boolean
|
|
}
|
|
|
|
export interface MonthsTable {
|
|
rows: MonthsTableRow[]
|
|
total: { income: number; expenses: number; net: number }
|
|
}
|
|
|
|
export function monthsTableRows(report: Pick<KPIReport, 'months' | 'totalRevenue' | 'totalExpenses' | 'netResult'>): MonthsTable {
|
|
const rows = report.months.map((m) => ({
|
|
label: m.label,
|
|
income: m.income,
|
|
expenses: m.expenses,
|
|
net: m.net,
|
|
inactive: m.income === 0 && m.expenses === 0 && m.net === 0,
|
|
}))
|
|
// The report totals are the numbers the panes print; the months sum to the
|
|
// same values since #2201 (reversed originals counted in both), so the
|
|
// footer reads the totals rather than re-adding the rows.
|
|
return {
|
|
rows,
|
|
total: {
|
|
income: roundOre(report.totalRevenue),
|
|
expenses: roundOre(report.totalExpenses),
|
|
net: roundOre(report.netResult),
|
|
},
|
|
}
|
|
}
|