budget refactoring, type synonyms

Using "actual" and "budget" terminology. "real" is already used in the
context of real/virtual postings. "actual" should be familiar from
unit testing (expected & actual)..
This commit is contained in:
Simon Michael 2018-03-21 16:31:55 +00:00
parent a56c547bc2
commit 550425810f

View File

@ -250,6 +250,7 @@ module Hledger.Cli.Commands.Balance (
,tests_Hledger_Cli_Commands_Balance ,tests_Hledger_Cli_Commands_Balance
) where ) where
import Data.Decimal
import Data.List (intercalate, nub) import Data.List (intercalate, nub)
import Data.Maybe import Data.Maybe
import qualified Data.Map as Map import qualified Data.Map as Map
@ -629,39 +630,53 @@ multiBalanceReportHtmlFootRow ropts (acct:rest) =
-- | Render a multi-column balance report as plain text suitable for console output. -- | Render a multi-column balance report as plain text suitable for console output.
multiBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> String multiBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> String
multiBalanceReportAsText opts r = multiBalanceReportAsText opts r =
printf "%s in %s:\n\n" typeStr (showDateSpan $ multiBalanceReportSpan r) printf "%s in %s:\n\n" desc (showDateSpan $ multiBalanceReportSpan r)
++ renderBalanceReportTable opts tabl ++ renderBalanceReportTable opts tabl
where where
tabl = balanceReportAsTable opts r tabl = balanceReportAsTable opts r
typeStr :: String desc = case balancetype_ opts of
typeStr = case balancetype_ opts of
PeriodChange -> "Balance changes" PeriodChange -> "Balance changes"
CumulativeChange -> "Ending balances (cumulative)" CumulativeChange -> "Ending balances (cumulative)"
HistoricalBalance -> "Ending balances (historical)" HistoricalBalance -> "Ending balances (historical)"
type ActualAmount = MixedAmount
type BudgetAmount = MixedAmount
type ActualAmountsReport = MultiBalanceReport
type BudgetAmountsReport = MultiBalanceReport
type ActualAmountsTable = Table String String MixedAmount
type BudgetAmountsTable = Table String String MixedAmount
type ActualAndBudgetAmountsTable = Table String String (MixedAmount, Maybe MixedAmount)
type Percentage = Decimal
-- | Given two multi-column balance reports, the first representing a budget -- | Given two multi-column balance reports, the first representing a budget
-- (target change amounts) and the second representing actual change amounts, -- (target change amounts) and the second representing actual change amounts,
-- render a budget report as plain text suitable for console output. -- render a budget report as plain text suitable for console output.
-- The reports should have the same number of columns. -- The reports should have the same number of columns.
multiBalanceReportWithBudgetAsText :: ReportOpts -> MultiBalanceReport -> MultiBalanceReport -> String multiBalanceReportWithBudgetAsText :: ReportOpts -> BudgetAmountsReport -> ActualAmountsReport -> String
multiBalanceReportWithBudgetAsText opts budget r = multiBalanceReportWithBudgetAsText opts budgetr actualr =
printf "%s in %s:\n\n" typeStr (showDateSpan $ multiBalanceReportSpan r) printf "%s in %s:\n\n" desc (showDateSpan $ multiBalanceReportSpan actualr)
++ renderBalanceReportTable' opts showcell tabl ++ renderBalanceReportTable' opts showcell actualandbudgetamts
where where
tabl = combine (balanceReportAsTable opts r) (balanceReportAsTable opts budget) desc :: String
typeStr :: String desc = case balancetype_ opts of
typeStr = case balancetype_ opts of
PeriodChange -> "Balance changes" PeriodChange -> "Balance changes"
CumulativeChange -> "Ending balances (cumulative)" CumulativeChange -> "Ending balances (cumulative)"
HistoricalBalance -> "Ending balances (historical)" HistoricalBalance -> "Ending balances (historical)"
showcell (real, Nothing) = showamt real
showcell (real, Just budget) = actualandbudgetamts :: ActualAndBudgetAmountsTable
case percentage real budget of actualandbudgetamts = combine (balanceReportAsTable opts actualr) (balanceReportAsTable opts budgetr)
Just pct -> printf "%s [%s%% of %s]" (showamt real) (show $ roundTo 0 pct) (showamt budget)
Nothing -> printf "%s [%s]" (showamt real) (showamt budget) showcell :: (ActualAmount, Maybe BudgetAmount) -> String
percentage real budget = showcell (actual, Nothing) = showamt actual
showcell (actual, Just budget) =
case percentage actual budget of
Just pct -> printf "%s [%s%% of %s]" (showamt actual) (show $ roundTo 0 pct) (showamt budget)
Nothing -> printf "%s [%s]" (showamt actual) (showamt budget)
percentage :: ActualAmount -> BudgetAmount -> Maybe Percentage
percentage actual budget =
-- percentage of budget consumed is always computed in the cost basis -- percentage of budget consumed is always computed in the cost basis
case (toCost real, toCost budget) of case (toCost actual, toCost budget) of
(Mixed [a1], Mixed [a2]) (Mixed [a1], Mixed [a2])
| isReallyZeroAmount a1 -> Just 0 -- if there are no postings, we consumed 0% of budget | isReallyZeroAmount a1 -> Just 0 -- if there are no postings, we consumed 0% of budget
| acommodity a1 == acommodity a2 && aquantity a2 /= 0 -> | acommodity a1 == acommodity a2 && aquantity a2 /= 0 ->
@ -669,6 +684,8 @@ multiBalanceReportWithBudgetAsText opts budget r =
_ -> Nothing _ -> Nothing
where where
toCost = normaliseMixedAmount . costOfMixedAmount toCost = normaliseMixedAmount . costOfMixedAmount
showamt :: MixedAmount -> String
showamt | color_ opts = cshowMixedAmountOneLineWithoutPrice showamt | color_ opts = cshowMixedAmountOneLineWithoutPrice
| otherwise = showMixedAmountOneLineWithoutPrice | otherwise = showMixedAmountOneLineWithoutPrice
@ -677,9 +694,10 @@ multiBalanceReportWithBudgetAsText opts budget r =
-- The budget table's row/column titles should be a subset of the actual table's. -- The budget table's row/column titles should be a subset of the actual table's.
-- (This is satisfied by the construction of the budget report and the -- (This is satisfied by the construction of the budget report and the
-- process of rolling up account names.) -- process of rolling up account names.)
combine :: ActualAmountsTable -> BudgetAmountsTable -> ActualAndBudgetAmountsTable
combine (Table l t d) (Table l' t' d') = Table l t combinedRows combine (Table l t d) (Table l' t' d') = Table l t combinedRows
where where
-- For all accounts that are present in the budget, zip real amounts with budget amounts -- For all accounts that are present in the budget, zip actual amounts with budget amounts
combinedRows = [ combineRow row budgetRow combinedRows = [ combineRow row budgetRow
| (acct, row) <- zip (headerContents l) d | (acct, row) <- zip (headerContents l) d
, let budgetRow = , let budgetRow =