diff --git a/frontend/src/pages/Monthly.tsx b/frontend/src/pages/Monthly.tsx
index 709f646..f232613 100644
--- a/frontend/src/pages/Monthly.tsx
+++ b/frontend/src/pages/Monthly.tsx
@@ -153,9 +153,10 @@ export default function Monthly() {
}
}).sort((a, b) => b.forecast_eom - a.forecast_eom)
- const totalActual = deptSummary.reduce((s, d) => s + d.actual_mtd, 0)
- const totalForecast = deptSummary.reduce((s, d) => s + d.forecast_eom, 0)
- const pyTotalWages = pyDepts.reduce((s, d) => s + d.cost, 0)
+ const totalActual = deptSummary.reduce((s, d) => s + d.actual_mtd, 0)
+ const totalForecast = deptSummary.reduce((s, d) => s + d.forecast_eom, 0)
+ const pyTotalWages = pyDepts.reduce((s, d) => s + d.cost, 0)
+ const pyTotalWagesFull = pyDepts.reduce((s, d) => s + d.costFull, 0)
// MTD row: pro-rata budget to yesterday
const yDay = isCurrentMonth ? parseInt(yesterdayStr.slice(8)) : dim
@@ -349,6 +350,7 @@ export default function Monthly() {
{isCurrentMonth ? 'Actual MTD' : 'Actual'} |
{isCurrentMonth && Forecast → EOM | }
% of Total |
+ vs PY |
Budget |
% Budget |
Variance |
@@ -364,6 +366,10 @@ export default function Monthly() {
const dp = depBudg != null && depBudg > 0 ? (displayCost / depBudg) * 100 : null
const dv = depBudg != null ? displayCost - depBudg : null
const depOfTotal = totalDisplay > 0 ? (displayCost / totalDisplay) * 100 : null
+ // PY: compare actual_mtd vs PY MTD for current month; actual vs PY full for past months
+ const pyDept = pyDepts.find(p => p.id === dep.department_id)
+ const pyCost = pyDept ? (isCurrentMonth ? pyDept.cost : pyDept.costFull) : null
+ const pyDelta = pyCost != null && pyCost > 0 ? ((dep.actual_mtd - pyCost) / pyCost) * 100 : null
return (
setModal({ deptId: dep.department_id, deptName: dep.department_name })}>
@@ -376,6 +382,11 @@ export default function Monthly() {
|
{depOfTotal != null ? `${depOfTotal.toFixed(1)}%` : '—'}
|
+
+ {pyDelta != null
+ ? 0 ? 'variance-over' : 'variance-under'}>{pyDelta > 0 ? '+' : ''}{pyDelta.toFixed(1)}%
+ : '—'}
+ |
{depBudg != null ? fmtMoney(depBudg) : '—'} |
{dp != null ? {fmtDelta(dp)} : '—'}
@@ -391,6 +402,14 @@ export default function Monthly() {
| {fmtMoney(totalActual)} |
{isCurrentMonth && {fmtMoney(totalForecast)} | }
100% |
+
+ {(() => {
+ const pyBase = isCurrentMonth ? pyTotalWages : pyTotalWagesFull
+ if (pyBase <= 0) return '—'
+ const d = ((totalActual - pyBase) / pyBase) * 100
+ return 0 ? 'variance-over' : 'variance-under'}>{d > 0 ? '+' : ''}{d.toFixed(1)}%
+ })()}
+ |
{budget != null ? fmtMoney(budget) : '—'} |
{pctBudgFull != null ? {fmtDelta(pctBudgFull)} : '—'}
|