"Fill F&B from last 7 days" only drew from the current month's elapsed days, so early in a month (e.g. the 3rd) it only had 1-2 actual days to repeat instead of a true trailing 7-day window. Add a dedicated last7-fnb endpoint that fetches a real 7-day window ending yesterday, reaching back into the prior month when needed.
88 lines
3.5 KiB
TypeScript
88 lines
3.5 KiB
TypeScript
import type { ReportMeta, ReportResult, WorksheetData, ForecastReportData, WeeklyActualData } from './types'
|
|
|
|
const BASE = '/reports/api'
|
|
|
|
async function request<T>(path: string, opts: RequestInit = {}): Promise<T> {
|
|
const res = await fetch(`${BASE}${path}`, {
|
|
credentials: 'include',
|
|
headers: { 'Content-Type': 'application/json', ...opts.headers },
|
|
...opts,
|
|
})
|
|
if (res.status === 401) {
|
|
;(window.top ?? window).location.href = '/login'
|
|
throw new Error('Unauthenticated')
|
|
}
|
|
if (!res.ok) {
|
|
const err = await res.json().catch(() => ({ error: res.statusText }))
|
|
throw new Error((err as { error?: string }).error || `Request failed: ${res.status}`)
|
|
}
|
|
return res.json()
|
|
}
|
|
|
|
export function fetchReports(): Promise<ReportMeta[]> {
|
|
return request('/reports')
|
|
}
|
|
|
|
export function runReport(id: string, dateFrom: string, dateTo: string): Promise<ReportResult> {
|
|
return request(`/reports/${encodeURIComponent(id)}/run`, {
|
|
method: 'POST',
|
|
body: JSON.stringify({ dateFrom, dateTo }),
|
|
})
|
|
}
|
|
|
|
// ── Weekly Actuals API ──────────────────────────────────────────────────────
|
|
|
|
export function getWeeklyActual(weekEnding: string): Promise<WeeklyActualData> {
|
|
return request<WeeklyActualData>(`/weekly-actual/${weekEnding}`)
|
|
}
|
|
|
|
// ── Directors Forecast API ──────────────────────────────────────────────────
|
|
|
|
export function dfGetWorksheet(year: number, month: number, dowAlign = true): Promise<WorksheetData> {
|
|
return request<WorksheetData>(`/directors-forecast/worksheet/${year}/${month}?dow_align=${dowAlign}`)
|
|
}
|
|
|
|
export function dfSaveWorksheet(year: number, month: number, data: { pickup_avg_rate: number; overrides: object[] }): Promise<{ ok: boolean }> {
|
|
return request<{ ok: boolean }>(`/directors-forecast/worksheet/${year}/${month}`, {
|
|
method: 'PUT', body: JSON.stringify(data),
|
|
})
|
|
}
|
|
|
|
export function dfGetReport(year: number, month: number, dowAlign = true): Promise<ForecastReportData> {
|
|
return request<ForecastReportData>(`/directors-forecast/report/${year}/${month}?dow_align=${dowAlign}`)
|
|
}
|
|
|
|
export type Last7FnBDay = {
|
|
date: string
|
|
actual_dry: number | null
|
|
actual_wet: number | null
|
|
forecast_dry: number | null
|
|
forecast_wet: number | null
|
|
}
|
|
|
|
export function dfGetLast7Fnb(): Promise<{ days: Last7FnBDay[] }> {
|
|
return request<{ days: Last7FnBDay[] }>('/directors-forecast/last7-fnb')
|
|
}
|
|
|
|
export function dfSaveSnapshot(year: number, month: number, data: object) {
|
|
return request(`/directors-forecast/report/${year}/${month}/snapshot`, {
|
|
method: 'POST', body: JSON.stringify(data),
|
|
})
|
|
}
|
|
|
|
export function dfDeleteSnapshot(year: number, month: number, id: number) {
|
|
return request(`/directors-forecast/report/${year}/${month}/snapshot/${id}`, {
|
|
method: 'DELETE',
|
|
})
|
|
}
|
|
|
|
// ── Settings ──────────────────────────────────────────────────────────────────
|
|
export type AppSetting = { key: string; value: string; updated_at: string }
|
|
|
|
export function getSettings(): Promise<{ settings: AppSetting[] }> {
|
|
return request('/settings')
|
|
}
|
|
|
|
export function saveSettings(settings: { key: string; value: string }[]): Promise<{ ok: boolean }> {
|
|
return request('/settings', { method: 'PUT', body: JSON.stringify({ settings }) })
|
|
}
|