58 lines
2.3 KiB
JavaScript
58 lines
2.3 KiB
JavaScript
import { requireAuth, requireCap } from '../auth.js'
|
|
import { getConfig } from '../db.js'
|
|
|
|
async function fcFetch(path) {
|
|
const apiKey = await getConfig('forecasting_api_key')
|
|
const baseUrl = (await getConfig('forecasting_url')) || 'http://10.10.10.113:3080'
|
|
if (!apiKey) throw new Error('Forecasting API key not configured — add it in Settings')
|
|
const res = await fetch(`${baseUrl}/forecasting/api/public${path}`, {
|
|
headers: { 'X-API-Key': apiKey },
|
|
signal: AbortSignal.timeout(15000),
|
|
})
|
|
if (!res.ok) throw new Error(`Forecasting API ${res.status} — ${path}`)
|
|
return res.json()
|
|
}
|
|
|
|
function daysBetween(from, to) {
|
|
const a = new Date(from + 'T00:00:00')
|
|
const b = new Date(to + 'T00:00:00')
|
|
return Math.max(1, Math.ceil((b - a) / 86_400_000) + 1)
|
|
}
|
|
|
|
export async function netSalesRoutes(fastify) {
|
|
fastify.addHook('preHandler', requireAuth)
|
|
|
|
// Returns daily net sales and prior-year net sales for a date range.
|
|
fastify.get('/api/net-sales', { preHandler: requireCap('view') }, async (request, reply) => {
|
|
const { from, to } = request.query
|
|
if (!from || !to) return reply.status(400).send({ error: 'from and to required' })
|
|
|
|
const MAX_DAYS = 365
|
|
const totalDays = daysBetween(from, to)
|
|
const allDays = []
|
|
|
|
// Batch into ≤365-day chunks if range exceeds API limit
|
|
let batchStart = new Date(from + 'T00:00:00')
|
|
const end = new Date(to + 'T00:00:00')
|
|
while (batchStart <= end) {
|
|
const remaining = Math.ceil((end - batchStart) / 86_400_000) + 1
|
|
const batchDays = Math.min(remaining, MAX_DAYS)
|
|
const startStr = batchStart.toISOString().slice(0, 10)
|
|
const data = await fcFetch(`/forecast/revenue?start_date=${startStr}&days=${batchDays}&type=all&dow_align=true`)
|
|
for (const d of (data?.data ?? [])) {
|
|
allDays.push({
|
|
date: d.date,
|
|
net_sales: parseFloat(d.total?.otb ?? 0),
|
|
py_sales: parseFloat(d.total?.prior_final ?? 0),
|
|
accom: parseFloat(d.accom?.otb ?? 0),
|
|
dry: parseFloat(d.dry?.otb ?? 0),
|
|
wet: parseFloat(d.wet?.otb ?? 0),
|
|
is_past: d.is_past ?? true,
|
|
})
|
|
}
|
|
batchStart.setDate(batchStart.getDate() + batchDays)
|
|
}
|
|
|
|
return { days: allDays }
|
|
})
|
|
}
|