From 35a83fbd8c69ba228c6b9e9e62b72211b727f57e Mon Sep 17 00:00:00 2001 From: Stephen Morgan Date: Mon, 26 Oct 2020 23:47:50 +1100 Subject: [PATCH] lib: For MultiBalanceReport, report change in valuation rather than valuation of change. --- .../Hledger/Reports/MultiBalanceReport.hs | 47 ++++++++++++++----- tests/journal/valuation.test | 40 ++++++++-------- 2 files changed, 55 insertions(+), 32 deletions(-) diff --git a/hledger-lib/Hledger/Reports/MultiBalanceReport.hs b/hledger-lib/Hledger/Reports/MultiBalanceReport.hs index 9c7d35080..7c49cdf22 100644 --- a/hledger-lib/Hledger/Reports/MultiBalanceReport.hs +++ b/hledger-lib/Hledger/Reports/MultiBalanceReport.hs @@ -51,7 +51,7 @@ import Data.Semigroup ((<>)) #endif import Data.Semigroup (sconcat) import Data.Time.Calendar (Day, addDays, fromGregorian) -import Safe (headMay, lastDef, lastMay) +import Safe (headMay, lastDef, lastMay, minimumMay) import Hledger.Data import Hledger.Query @@ -339,34 +339,57 @@ accumValueAmounts :: ReportOpts -> (Day -> MixedAmount -> MixedAmount) -> [DateS -> HashMap ClippedAccountName (Map DateSpan Account) -> HashMap ClippedAccountName (Map DateSpan Account) accumValueAmounts ropts valuation colspans startbals acctchanges = -- PARTIAL: - HM.mapWithKey processRow $ acctchanges <> (mempty <$ startbals) + HM.mapWithKey rowbals $ acctchanges <> (mempty <$ startbals) where - -- Must accumulate before valuing, since valuation can change without any - -- postings. Make sure every column has an entry. - processRow name changes = M.mapWithKey valueAcct . rowbals name $ changes <> zeros - -- The row amounts to be displayed: per-period changes, -- zero-based cumulative totals, or -- starting-balance-based historical balances. - rowbals name changes = dbg'' "rowbals" $ case balancetype_ ropts of - PeriodChange -> changes - CumulativeChange -> snd $ M.mapAccum f nullacct changes - HistoricalBalance -> snd $ M.mapAccum f (startingBalanceFor name) changes - where f a b = let s = sumAcct a b in (s, s) + rowbals name changes' = dbg'' "rowbals" $ case balancetype_ ropts of + HistoricalBalance -> historical + CumulativeChange -> cumulative + PeriodChange -> changeamts + where + -- Calculate the valued historical balance in each column, ensuring every + -- columns has an entry. + historical = cumulativeSum startingBalance + -- If no valuation can sum the changes directly, otherwise need to + -- subtract the valued starting amount from the historical sum + cumulative = case value_ ropts of + Nothing -> cumulativeSum nullacct + Just _ -> fmap (`subtractAcct` valuedStart) historical + -- If no valuation can use the change list directly, otherwise need to + -- calculate the incremental differences in the historical sum + changeamts = case value_ ropts of + Nothing -> changes + Just _ -> let (dates, histamts) = unzip $ M.toAscList historical + in M.fromDistinctAscList . zip dates $ + zipWith subtractAcct histamts (valuedStart:histamts) + + cumulativeSum start = snd $ M.mapAccumWithKey accumValued start changes + where accumValued startAmt date newAmt = (s, valueAcct date s) + where s = sumAcct startAmt newAmt + + changes = changes' <> zeros + startingBalance = HM.lookupDefault nullacct name startbals + valuedStart = valueAcct (DateSpan Nothing historicalDate) startingBalance -- Add the values of two accounts. Should be right-biased, since it's used -- in scanl, so other properties (such as anumpostings) stay in the right place sumAcct Account{aibalance=i1,aebalance=e1} a@Account{aibalance=i2,aebalance=e2} = a{aibalance = i1 + i2, aebalance = e1 + e2} + -- Subtract the values in one account from another. Should be left-biased. + subtractAcct a@Account{aibalance=i1,aebalance=e1} Account{aibalance=i2,aebalance=e2} = + a{aibalance = i1 - i2, aebalance = e1 - e2} + -- We may be converting amounts to value, per hledger_options.m4.md "Effect of --value on reports". valueAcct (DateSpan _ (Just end)) acct = acct{aibalance = value (aibalance acct), aebalance = value (aebalance acct)} where value = valuation (addDays (-1) end) valueAcct _ _ = error "multiBalanceReport: expected all spans to have an end date" -- XXX should not happen - startingBalanceFor a = HM.lookupDefault nullacct a startbals zeros = M.fromList [(span, nullacct) | span <- colspans] + historicalDate = minimumMay $ mapMaybe spanStart colspans -- | Lay out a set of postings grouped by date span into a regular matrix with rows diff --git a/tests/journal/valuation.test b/tests/journal/valuation.test index 05c9bab3c..3e0248cca 100644 --- a/tests/journal/valuation.test +++ b/tests/journal/valuation.test @@ -379,21 +379,21 @@ Balance changes in 2000Q1, valued at cost: $ hledger -f- bal -M --value=end Balance changes in 2000Q1, valued at period ends: - || Jan Feb Mar -===++=============== - a || 5 B 2 B 3 B ----++--------------- - || 5 B 2 B 3 B + || Jan Feb Mar +===++================ + a || 5 B -1 B 5 B +---++---------------- + || 5 B -1 B 5 B # 36. multicolumn balance report valued at period end with -T or -A $ hledger -f- bal -MTA --value=end Balance changes in 2000Q1, valued at period ends: - || Jan Feb Mar Total Average -===++================================= - a || 5 B 2 B 3 B 10 B 3 B ----++--------------------------------- - || 5 B 2 B 3 B 10 B 3 B + || Jan Feb Mar Total Average +===++================================== + a || 5 B -1 B 5 B 9 B 3 B +---++---------------------------------- + || 5 B -1 B 5 B 9 B 3 B # 37. multicolumn balance report valued at other date $ hledger -f- bal -MTA --value=2000-01-15 @@ -419,11 +419,11 @@ Balance changes in 2000Q1, current value: $ hledger -f- bal -M -V Balance changes in 2000Q1, valued at period ends: - || Jan Feb Mar -===++=============== - a || 5 B 2 B 3 B ----++--------------- - || 5 B 2 B 3 B + || Jan Feb Mar +===++================ + a || 5 B -1 B 5 B +---++---------------- + || 5 B -1 B 5 B # balance, periodic, with -H (starting balance and accumulating across periods) @@ -551,11 +551,11 @@ Budget performance in 2000Q1, valued at cost: $ hledger -f- bal -MTA --budget --value=e Budget performance in 2000Q1, valued at period ends: - || Jan Feb Mar Total Average -===++============================================================================================= - a || 5 B [50% of 10 B] 2 B [50% of 4 B] 3 B [50% of 6 B] 10 B [50% of 20 B] 3 B [50% of 7 B] ----++--------------------------------------------------------------------------------------------- - || 5 B [50% of 10 B] 2 B [50% of 4 B] 3 B [50% of 6 B] 10 B [50% of 20 B] 3 B [50% of 7 B] + || Jan Feb Mar Total Average +===++=============================================================================================== + a || 5 B [50% of 10 B] -1 B [50% of -2 B] 5 B [50% of 10 B] 9 B [50% of 18 B] 3 B [50% of 6 B] +---++----------------------------------------------------------------------------------------------- + || 5 B [50% of 10 B] -1 B [50% of -2 B] 5 B [50% of 10 B] 9 B [50% of 18 B] 3 B [50% of 6 B] # 49. budget report, valued at other date. $ hledger -f- bal -MTA --budget --value=2000-01-15