Fair PYTD comparison for current week/month

Weekly: cap pyToStr at elapsed days (not full Mon-Sun), and filter
py_sales to past days only — both give WTD vs WTD. Labels show
'PY WTD' for current week, 'PY' for complete past weeks.

Monthly: pyToStr already capped at same day-of-month; salesTo already
capped at today. Labels now show 'PY MTD' for current month, 'PY' for
complete past months.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-23 10:11:09 +00:00
parent dc1a14a070
commit 44a7caa937
2 changed files with 20 additions and 11 deletions

View file

@ -192,7 +192,7 @@ export default function Monthly() {
<div className="summary-card"> <div className="summary-card">
<div className="label">{isCurrentMonth ? 'Actual MTD' : 'Actual'}</div> <div className="label">{isCurrentMonth ? 'Actual MTD' : 'Actual'}</div>
<div className="value">{fmtMoney(totalActual)}</div> <div className="value">{fmtMoney(totalActual)}</div>
{pyWages != null && <div className="sub">PY {fmtMoney(pyWages)}{pyPct(totalActual, pyWages)}</div>} {pyWages != null && <div className="sub">{isCurrentMonth ? 'PY MTD' : 'PY'} {fmtMoney(pyWages)}{pyPct(totalActual, pyWages)}</div>}
</div> </div>
{isCurrentMonth && ( {isCurrentMonth && (
<div className="summary-card"> <div className="summary-card">
@ -221,7 +221,7 @@ export default function Monthly() {
<div className="summary-card"> <div className="summary-card">
<div className="label">{isCurrentMonth ? 'Net Sales MTD' : 'Net Sales'}</div> <div className="label">{isCurrentMonth ? 'Net Sales MTD' : 'Net Sales'}</div>
<div className="value">{fmtMoney(netSales)}</div> <div className="value">{fmtMoney(netSales)}</div>
{pySales > 0 && <div className="sub">PY {fmtMoney(pySales)}{pyPct(netSales, pySales)}</div>} {pySales > 0 && <div className="sub">{isCurrentMonth ? 'PY MTD' : 'PY'} {fmtMoney(pySales)}{pyPct(netSales, pySales)}</div>}
</div> </div>
<div className="summary-card"> <div className="summary-card">
<div className="label">% Net Sales</div> <div className="label">% Net Sales</div>

View file

@ -44,11 +44,15 @@ function pctClass(pct: number | null): string {
export default function Weekly() { export default function Weekly() {
const [fromStr, setFromStr] = useState<string>(() => mondayOf(new Date())) const [fromStr, setFromStr] = useState<string>(() => mondayOf(new Date()))
const toStr = addDaysStr(fromStr, 6) const toStr = addDaysStr(fromStr, 6)
const todayStr = localStr(new Date()) const todayStr = localStr(new Date())
// Prior-year equivalent week (52 weeks back) const isCurrentWeek = fromStr === mondayOf(new Date())
const pyFromStr = addDaysStr(fromStr, -364) const pyFromStr = addDaysStr(fromStr, -364)
const pyToStr = addDaysStr(toStr, -364) // For current (partial) week cap PY at equivalent elapsed day — fair WTD comparison
const daysElapsed = isCurrentWeek
? Math.round((new Date(todayStr + 'T00:00:00').getTime() - new Date(fromStr + 'T00:00:00').getTime()) / 86_400_000)
: 6
const pyToStr = addDaysStr(fromStr, -364 + daysElapsed)
const [depts, setDepts] = useState<DeptActuals[]>([]) const [depts, setDepts] = useState<DeptActuals[]>([])
const [netSales, setNetSales] = useState(0) const [netSales, setNetSales] = useState(0)
@ -74,7 +78,13 @@ export default function Weekly() {
setShowOncosts(actRes.show_oncosts) setShowOncosts(actRes.show_oncosts)
setDeptPcts(actRes.dept_pcts) setDeptPcts(actRes.dept_pcts)
setNetSales(salesRes.days.reduce((s, d) => s + d.net_sales, 0)) setNetSales(salesRes.days.reduce((s, d) => s + d.net_sales, 0))
setPySales(salesRes.days.reduce((s, d) => s + d.py_sales, 0)) // For current week only sum PY sales for elapsed days (WTD = apples to apples)
const isCurrentWk = fromStr === mondayOf(new Date())
setPySales(
isCurrentWk
? salesRes.days.filter(d => d.date <= todayStr).reduce((s, d) => s + d.py_sales, 0)
: salesRes.days.reduce((s, d) => s + d.py_sales, 0)
)
const pyTotal = pyActRes.departments.reduce( const pyTotal = pyActRes.departments.reduce(
(s, dep) => s + Object.values(dep.days).reduce((ds, d) => ds + d.cost, 0), 0 (s, dep) => s + Object.values(dep.days).reduce((ds, d) => ds + d.cost, 0), 0
@ -109,7 +119,6 @@ export default function Weekly() {
const prev = () => setFromStr(s => addDaysStr(s, -7)) const prev = () => setFromStr(s => addDaysStr(s, -7))
const next = () => setFromStr(s => addDaysStr(s, 7)) const next = () => setFromStr(s => addDaysStr(s, 7))
const isCurrentWeek = fromStr === mondayOf(new Date())
const deptWeekBudget = (deptId: string) => const deptWeekBudget = (deptId: string) =>
budget != null && monthlyBudg != null && (deptPcts[deptId] ?? 0) > 0 budget != null && monthlyBudg != null && (deptPcts[deptId] ?? 0) > 0
@ -154,7 +163,7 @@ export default function Weekly() {
<div className="label">Total Wages</div> <div className="label">Total Wages</div>
<div className="value">{fmtMoney(totalWages)}</div> <div className="value">{fmtMoney(totalWages)}</div>
{pyWages != null {pyWages != null
? <div className="sub">PY {fmtMoney(pyWages)}{pyPct(totalWages, pyWages)}</div> ? <div className="sub">{isCurrentWeek ? 'PY WTD' : 'PY'} {fmtMoney(pyWages)}{pyPct(totalWages, pyWages)}</div>
: <div className="sub">{showOncosts ? 'incl. on-costs' : 'base cost'}</div>} : <div className="sub">{showOncosts ? 'incl. on-costs' : 'base cost'}</div>}
</div> </div>
<div className="summary-card"> <div className="summary-card">
@ -173,7 +182,7 @@ export default function Weekly() {
<div className="summary-card"> <div className="summary-card">
<div className="label">Net Sales</div> <div className="label">Net Sales</div>
<div className="value">{fmtMoney(netSales)}</div> <div className="value">{fmtMoney(netSales)}</div>
{pySales > 0 && <div className="sub">PY {fmtMoney(pySales)}{pyPct(netSales, pySales)}</div>} {pySales > 0 && <div className="sub">{isCurrentWeek ? 'PY WTD' : 'PY'} {fmtMoney(pySales)}{pyPct(netSales, pySales)}</div>}
</div> </div>
<div className="summary-card"> <div className="summary-card">
<div className="label">% of Net Sales</div> <div className="label">% of Net Sales</div>