From 8726543e34315f388003717667a216c99939c88a Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Wed, 16 Sep 2026 23:24:02 -0400 Subject: [PATCH] Show the implied price on every ledger line, not just the totals Price was blanked on the bridge lines and on the excluded row, so a ledger that had both measures on every line showed a price on two of them. Baseline sat there as 2,242,180.67 over 8,111,717.10 with the column empty. A bridge line's price is the implied price of that initiative's own contribution -- Scale #116 above works out to 0.2397 against a current 0.2735 -- which is the number that says whether the initiative was a price move or a volume move. That is the same question the plug toggle asks about the edit, answered for the adjustments already made. A line with no units is left blank, since its price is undefined rather than zero -- the "price" bridge line in that example moved dollars alone. The price column's hint said "holds units", which stopped being true when plug arrived: it holds units under plug = price and moves them under plug = volume. It now just says what the column is. Co-Authored-By: Claude Opus 5 (1M context) --- ui/src/components/OperationPanel.jsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ui/src/components/OperationPanel.jsx b/ui/src/components/OperationPanel.jsx index 8dcb1aa..b36b337 100644 --- a/ui/src/components/OperationPanel.jsx +++ b/ui/src/components/OperationPanel.jsx @@ -277,11 +277,17 @@ function ScaleLedger({ currentTotals, scaleInputs, setScaleInputs, scalePlug, se return grand[key] } + // Every line that has both measures has a price -- a bridge line's is the + // implied price of that initiative's own contribution, which is the number + // that says whether it was a price move or a volume move. Only a line with no + // units has nothing to show, since the price is undefined rather than zero. + const priceOf = (row) => (row && row.units) ? row.value / row.units : null + // measure columns, in ledger order const measures = [ valueCol && { key: 'value', label: valueCol, current: total.value, dp: 2 }, unitsCol && { key: 'units', label: unitsCol, current: total.units, dp: 2 }, - (valueCol && unitsCol) && { key: 'price', label: 'price', current: curPrice, dp: 4, hint: 'holds units' }, + (valueCol && unitsCol) && { key: 'price', label: 'price', current: curPrice, dp: 4, hint: 'value / units' }, ].filter(Boolean) const derived = Object.fromEntries( @@ -383,7 +389,7 @@ function ScaleLedger({ currentTotals, scaleInputs, setScaleInputs, scalePlug, se {measures.map(m => ( - {m.key === 'price' ? '' : fmtNum(e[m.key], m.dp)} + {m.key === 'price' ? fmtNum(priceOf(e), m.dp) : fmtNum(e[m.key], m.dp)} ))} @@ -409,7 +415,7 @@ function ScaleLedger({ currentTotals, scaleInputs, setScaleInputs, scalePlug, se {measures.map(m => ( - {m.key === 'price' ? '' : fmtNum(excl[m.key], m.dp)} + {m.key === 'price' ? fmtNum(priceOf(excl), m.dp) : fmtNum(excl[m.key], m.dp)} ))}