Net sales: use forecast (otb + pickup) instead of otb-only for future dates

The forecasting API's total.otb is booked-to-date only; total.forecast adds
expected pickup and equals otb for past dates anyway. Using otb-only for
future days understated expected net sales in the current-week/month
forecast sections. Relabelled "(OTB)" cards to "(Forecast)" to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-23 17:39:10 +00:00
parent 320a0ce1ec
commit 69b4c50e14
3 changed files with 10 additions and 9 deletions

View file

@ -40,13 +40,14 @@ export async function netSalesRoutes(fastify) {
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 ?? [])) {
// forecast = otb + expected pickup for future dates; equals otb for past dates
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),
net_sales: parseFloat(d.total?.forecast ?? d.total?.otb ?? 0),
py_sales: parseFloat(d.total?.prior_final ?? 0),
accom: parseFloat(d.accom?.forecast ?? d.accom?.otb ?? 0),
dry: parseFloat(d.dry?.forecast ?? d.dry?.otb ?? 0),
wet: parseFloat(d.wet?.forecast ?? d.wet?.otb ?? 0),
is_past: d.is_past ?? true,
})
}

View file

@ -303,14 +303,14 @@ export default function Monthly() {
)}
</div>
<div className="summary-card">
<div className="label">% Net Sales (OTB)</div>
<div className="label">% Net Sales (Forecast)</div>
<div className="value">{pctSalesFull != null ? `${pctSalesFull.toFixed(1)}%` : '—'}</div>
{pyWagesFull != null && pySalesFull > 0 && (
<div className="sub">PY {((pyWagesFull / pySalesFull) * 100).toFixed(1)}%</div>
)}
</div>
<div className="summary-card">
<div className="label">Net Sales (OTB)</div>
<div className="label">Net Sales (Forecast)</div>
<div className="value">{fmtMoney(netSalesFull)}</div>
{pySalesFull > 0 && <div className="sub">PY {fmtMoney(pySalesFull)}{pyPct(netSalesFull, pySalesFull)}</div>}
</div>

View file

@ -272,11 +272,11 @@ export default function Weekly() {
</div>
</div>
<div className="summary-card">
<div className="label">% Net Sales (OTB)</div>
<div className="label">% Net Sales (Forecast)</div>
<div className="value">{pctSalesFull != null ? `${pctSalesFull.toFixed(1)}%` : '—'}</div>
</div>
<div className="summary-card">
<div className="label">Net Sales (OTB)</div>
<div className="label">Net Sales (Forecast)</div>
<div className="value">{fmtMoney(netSalesFull)}</div>
{pySalesFull > 0 && <div className="sub">PY {fmtMoney(pySalesFull)}{pyPct(netSalesFull, pySalesFull)}</div>}
</div>