lib,cli: Strip prices in MultiBalanceReport and PostingsReport whenever
we know we won't need them. Knowing whether we need them is accomplished by pulling the "show-costs" option used by the Close command up into ReportOpts.
This commit is contained in:
		
							parent
							
								
									b7a2479186
								
							
						
					
					
						commit
						f6feef7f80
					
				| @ -558,14 +558,22 @@ cumulativeSum value start = snd . M.mapAccumWithKey accumValued start | ||||
| postingAndAccountValuations :: ReportSpec -> Journal -> PriceOracle | ||||
|                             -> (DateSpan -> Posting -> Posting, DateSpan -> Account -> Account) | ||||
| postingAndAccountValuations ReportSpec{rsToday=today, rsOpts=ropts} j priceoracle = case value_ ropts of | ||||
|     Just (AtEnd _) -> (const id, avalue' (cost_ ropts) (value_ ropts)) | ||||
|     _              -> (pvalue' (cost_ ropts) (value_ ropts), const id) | ||||
|     -- If we're doing AtEnd valuation, we may need to value the same posting at different dates | ||||
|     -- (for example, when preparing a ValueChange report). So we should only convert to cost and | ||||
|     -- maybe strip prices from the Posting, and should do valuation on the Accounts. | ||||
|     Just v@(AtEnd _) -> (pvalue Nothing, avalue v) | ||||
|     -- Otherwise, all costing and valuation should be done on the Postings. | ||||
|     _                -> (pvalue (value_ ropts), const id) | ||||
|   where | ||||
|     avalue' c v span a = a{aibalance = value (aibalance a), aebalance = value (aebalance a)} | ||||
|       where value = mixedAmountApplyCostValuation priceoracle styles (end span) today (error "multiBalanceReport: did not expect amount valuation to be called ") c v  -- PARTIAL: should not happen | ||||
|     pvalue' c v span = postingApplyCostValuation priceoracle styles (end span) today c v | ||||
|     end = fromMaybe (error "multiBalanceReport: expected all spans to have an end date")  -- XXX should not happen | ||||
|         . fmap (addDays (-1)) . spanEnd | ||||
|     -- For a Posting: convert to cost, apply valuation, then strip prices if we don't need them (See issue #1507). | ||||
|     pvalue v span = maybeStripPrices . postingApplyCostValuation priceoracle styles (end span) today (cost_ ropts) v | ||||
|     -- For an Account: Apply valuation to both the inclusive and exclusive balances. | ||||
|     avalue v span a = a{aibalance = value (aibalance a), aebalance = value (aebalance a)} | ||||
|       where value = mixedAmountApplyValuation priceoracle styles (end span) today (error "multiBalanceReport: did not expect amount valuation to be called ") v  -- PARTIAL: should not happen | ||||
| 
 | ||||
|     maybeStripPrices = if show_costs_ ropts then id else postingStripPrices | ||||
|     end = maybe (error "multiBalanceReport: expected all spans to have an end date")  -- PARTIAL: should not happen | ||||
|             (addDays (-1)) . spanEnd | ||||
|     styles = journalCommodityStyles j | ||||
| 
 | ||||
| -- tests | ||||
|  | ||||
| @ -91,8 +91,9 @@ postingsReport rspec@ReportSpec{rsOpts=ropts@ReportOpts{..}} j = items | ||||
|             fromMaybe (error' "postingsReport: expected a non-empty journal") $  -- PARTIAL: shouldn't happen | ||||
|             reportPeriodOrJournalLastDay rspec j | ||||
| 
 | ||||
|       -- Posting report does not use prices after valuation, so remove them. | ||||
|       displaypsnoprices = map (\(p,md) -> (postingStripPrices p, md)) displayps | ||||
|       -- Strip prices from postings if we won't need them. | ||||
|       displaypsnoprices = map (\(p,md) -> (maybeStripPrices p, md)) displayps | ||||
|         where maybeStripPrices = if show_costs_ then id else postingStripPrices | ||||
| 
 | ||||
|       -- Posting report items ready for display. | ||||
|       items = | ||||
|  | ||||
| @ -119,6 +119,7 @@ data ReportOpts = ReportOpts { | ||||
|     ,drop_           :: Int | ||||
|     ,row_total_      :: Bool | ||||
|     ,no_total_       :: Bool | ||||
|     ,show_costs_     :: Bool  -- ^ Whether to show costs for reports which normally don't show them | ||||
|     ,pretty_tables_  :: Bool | ||||
|     ,sort_amount_    :: Bool | ||||
|     ,percent_        :: Bool | ||||
| @ -166,6 +167,7 @@ defreportopts = ReportOpts | ||||
|     , drop_            = 0 | ||||
|     , row_total_       = False | ||||
|     , no_total_        = False | ||||
|     , show_costs_      = False | ||||
|     , pretty_tables_   = False | ||||
|     , sort_amount_     = False | ||||
|     , percent_         = False | ||||
| @ -215,6 +217,7 @@ rawOptsToReportOpts rawopts = do | ||||
|           ,drop_        = posintopt "drop" rawopts | ||||
|           ,row_total_   = boolopt "row-total" rawopts | ||||
|           ,no_total_    = boolopt "no-total" rawopts | ||||
|           ,show_costs_  = boolopt "show-costs" rawopts | ||||
|           ,sort_amount_ = boolopt "sort-amount" rawopts | ||||
|           ,percent_     = boolopt "percent" rawopts | ||||
|           ,invert_      = boolopt "invert" rawopts | ||||
|  | ||||
| @ -388,11 +388,11 @@ balance opts@CliOpts{reportspec_=rspec} j = case reporttype_ of | ||||
| balanceReportAsCsv :: ReportOpts -> BalanceReport -> CSV | ||||
| balanceReportAsCsv opts (items, total) = | ||||
|   ["account","balance"] : | ||||
|   [[accountNameDrop (drop_ opts) a, wbToText $ showMixedAmountB oneLine b] | (a, _, _, b) <- items] | ||||
|   [[accountNameDrop (drop_ opts) a, wbToText $ showMixedAmountB (balanceOpts False opts) b] | (a, _, _, b) <- items] | ||||
|   ++ | ||||
|   if no_total_ opts | ||||
|   then [] | ||||
|   else [["total", wbToText $ showMixedAmountB oneLine total]] | ||||
|   else [["total", wbToText $ showMixedAmountB (balanceOpts False opts) total]] | ||||
| 
 | ||||
| -- | Render a single-column balance report as plain text. | ||||
| balanceReportAsText :: ReportOpts -> BalanceReport -> TB.Builder | ||||
| @ -461,12 +461,12 @@ renderComponent topaligned opts (acctname, depth, total) (FormatField ljust mmin | ||||
|     DepthSpacerField -> Cell align [WideBuilder (TB.fromText $ T.replicate d " ") d] | ||||
|                         where d = maybe id min mmax $ depth * fromMaybe 1 mmin | ||||
|     AccountField     -> textCell align $ formatText ljust mmin mmax acctname | ||||
|     TotalField       -> Cell align . pure $ showamt total | ||||
|     TotalField       -> Cell align . pure $ showMixedAmountB dopts total | ||||
|     _                -> Cell align [mempty] | ||||
|   where | ||||
|     align = if topaligned then (if ljust then TopLeft    else TopRight) | ||||
|                           else (if ljust then BottomLeft else BottomRight) | ||||
|     showamt = showMixedAmountB noPrice{displayColour=color_ opts, displayMinWidth=mmin, displayMaxWidth=mmax} | ||||
|     dopts = (balanceOpts True opts){displayOneLine=False, displayMinWidth=mmin, displayMaxWidth=mmax} | ||||
| 
 | ||||
| -- rendering multi-column balance reports | ||||
| 
 | ||||
| @ -482,7 +482,7 @@ multiBalanceReportAsCsv opts@ReportOpts{average_, row_total_} | ||||
|    ++ ["average" | average_] | ||||
|   ) : | ||||
|   [displayName a : | ||||
|    map (wbToText . showMixedAmountB oneLine) | ||||
|    map (wbToText . showMixedAmountB (balanceOpts False opts)) | ||||
|    (amts | ||||
|     ++ [rowtot | row_total_] | ||||
|     ++ [rowavg | average_]) | ||||
| @ -491,7 +491,7 @@ multiBalanceReportAsCsv opts@ReportOpts{average_, row_total_} | ||||
|   if no_total_ opts | ||||
|   then [] | ||||
|   else ["total" : | ||||
|         map (wbToText . showMixedAmountB oneLine) ( | ||||
|         map (wbToText . showMixedAmountB (balanceOpts False opts)) ( | ||||
|           coltotals | ||||
|           ++ [tot | row_total_] | ||||
|           ++ [avg | average_] | ||||
| @ -656,13 +656,19 @@ balanceReportAsTable opts@ReportOpts{average_, row_total_, balancetype_} | ||||
| -- console output. Amounts with more than two commodities will be elided | ||||
| -- unless --no-elide is used. | ||||
| balanceReportTableAsText :: ReportOpts -> Table T.Text T.Text MixedAmount -> TB.Builder | ||||
| balanceReportTableAsText ReportOpts{..} = | ||||
| balanceReportTableAsText ropts@ReportOpts{..} = | ||||
|     Tab.renderTableB def{tableBorders=False, prettyTable=pretty_tables_} | ||||
|         (Tab.textCell TopLeft) (Tab.textCell TopRight) showamt | ||||
|   where | ||||
|     showamt = Cell TopRight . pure . showMixedAmountB oneLine{displayColour=color_, displayMaxWidth=mmax} | ||||
|     mmax = if no_elide_ then Nothing else Just 32 | ||||
|         (Tab.textCell TopLeft) (Tab.textCell TopRight) $ | ||||
|         Cell TopRight . pure . showMixedAmountB (balanceOpts True ropts) | ||||
| 
 | ||||
| -- | Amount display options to use for balance reports | ||||
| balanceOpts :: Bool -> ReportOpts -> AmountDisplayOpts | ||||
| balanceOpts isTable ReportOpts{..} = oneLine | ||||
|     { displayColour   = isTable && color_ | ||||
|     , displayMaxWidth = if isTable && not no_elide_ then Just 32 else Nothing | ||||
|     , displayPrice    = True  -- multiBalanceReport strips prices from Amounts if they are not being used, | ||||
|                               -- so we can display prices here without fear. | ||||
|     } | ||||
| 
 | ||||
| tests_Balance = tests "Balance" [ | ||||
| 
 | ||||
|  | ||||
| @ -82,14 +82,9 @@ close CliOpts{rawopts_=rawopts, reportspec_=rspec} j = do | ||||
|     -- should we show the amount(s) on the equity posting(s) ? | ||||
|     explicit = boolopt "explicit" rawopts | ||||
| 
 | ||||
|     -- should we preserve cost information ? | ||||
|     normalise = case boolopt "show-costs" rawopts of | ||||
|                   True  -> normaliseMixedAmount | ||||
|                   False -> normaliseMixedAmount . mixedAmountStripPrices | ||||
| 
 | ||||
|     -- the balances to close | ||||
|     (acctbals,_) = balanceReport rspec_ j | ||||
|     totalamt = maSum $ map (\(_,_,_,b) -> normalise b) acctbals | ||||
|     totalamt = maSum $ map (\(_,_,_,b) -> b) acctbals | ||||
| 
 | ||||
|     -- since balance assertion amounts are required to be exact, the | ||||
|     -- amounts in opening/closing transactions should be too (#941, #1137) | ||||
| @ -117,13 +112,13 @@ close CliOpts{rawopts_=rawopts, reportspec_=rspec} j = do | ||||
| 
 | ||||
|         | -- get the balances for each commodity and transaction price | ||||
|           (a,_,_,mb) <- acctbals | ||||
|         , let bs = amounts $ normalise mb | ||||
|         , let bs = amounts $ normaliseMixedAmount mb | ||||
|           -- mark the last balance in each commodity with True | ||||
|         , let bs' = concat [reverse $ zip (reverse bs) (True : repeat False) | ||||
|                            | bs <- groupBy ((==) `on` acommodity) bs] | ||||
|         , (b, islast) <- bs' | ||||
|         ] | ||||
|        | ||||
| 
 | ||||
|       -- or a final multicommodity posting transferring all balances to equity | ||||
|       -- (print will show this as multiple single-commodity postings) | ||||
|       ++ [posting{paccount=closingacct, pamount=if explicit then mapMixedAmount precise totalamt else missingmixedamt} | not interleaved] | ||||
| @ -143,7 +138,7 @@ close CliOpts{rawopts_=rawopts, reportspec_=rspec} j = do | ||||
|         ++ [posting{paccount=openingacct, pamount=Mixed [precise $ negate b]} | interleaved] | ||||
| 
 | ||||
|         | (a,_,_,mb) <- acctbals | ||||
|         , let bs = amounts $ normalise mb | ||||
|         , let bs = amounts $ normaliseMixedAmount mb | ||||
|           -- mark the last balance in each commodity with the unpriced sum in that commodity (for a balance assertion) | ||||
|         , let bs' = concat [reverse $ zip (reverse bs) (Just commoditysum : repeat Nothing) | ||||
|                            | bs <- groupBy ((==) `on` acommodity) bs | ||||
|  | ||||
| @ -93,8 +93,9 @@ postingsReportItemAsCsvRecord (_, _, _, p, b) = [idx,date,code,desc,acct,amt,bal | ||||
|                              BalancedVirtualPosting -> wrap "[" "]" | ||||
|                              VirtualPosting -> wrap "(" ")" | ||||
|                              _ -> id | ||||
|     amt = wbToText . showMixedAmountB oneLine $ pamount p | ||||
|     bal = wbToText $ showMixedAmountB oneLine b | ||||
|     -- Since postingsReport strips prices from all Amounts when not used, we can display prices. | ||||
|     amt = wbToText . showMixedAmountB oneLine{displayPrice=True} $ pamount p | ||||
|     bal = wbToText $ showMixedAmountB oneLine{displayPrice=True} b | ||||
| 
 | ||||
| -- | Render a register report as plain text suitable for console output. | ||||
| postingsReportAsText :: CliOpts -> PostingsReport -> TL.Text | ||||
| @ -107,7 +108,8 @@ postingsReportAsText opts items = TB.toLazyText $ foldMap first3 linesWithWidths | ||||
|     -- balwidth = maximum $ 12 : map third3 linesWithWidths | ||||
|     amtwidth = maximumStrict $ 12 : widths (map itemamt items) | ||||
|     balwidth = maximumStrict $ 12 : widths (map itembal items) | ||||
|     widths = map wbWidth . concatMap (showAmountsLinesB noPrice) | ||||
|     -- Since postingsReport strips prices from all Amounts when not used, we can display prices. | ||||
|     widths = map wbWidth . concatMap (showAmountsLinesB oneLine{displayPrice=True}) | ||||
|     itemamt (_,_,_,Posting{pamount=a},_) = amounts a | ||||
|     itembal (_,_,_,_,a) = amounts a | ||||
| 
 | ||||
| @ -190,7 +192,9 @@ postingsReportItemAsText opts preferredamtwidth preferredbalwidth (mdate, mendda | ||||
|             _                      -> (id,acctwidth) | ||||
|     amt = showAmountsLinesB dopts . (\x -> if null x then [nullamt] else x) . amounts $ pamount p | ||||
|     bal = showAmountsLinesB dopts $ amounts b | ||||
|     dopts = noPrice{displayColour=color_ . rsOpts $ reportspec_ opts} | ||||
|     -- Since postingsReport strips prices from all Amounts when not used, we can display prices. | ||||
|     dopts = oneLine{displayColour=color_, displayPrice=True} | ||||
|       where ReportOpts{..} = rsOpts $ reportspec_ opts | ||||
|     -- Since this will usually be called with the knot tied between this(amt|bal)width and | ||||
|     -- preferred(amt|bal)width, make sure the former do not depend on the latter to avoid loops. | ||||
|     thisamtwidth = maximumDef 0 $ map wbWidth amt | ||||
|  | ||||
| @ -210,7 +210,19 @@ hledger -f - balance --no-total -E | ||||
|                  -1Y  b | ||||
| >>>= 0 | ||||
| 
 | ||||
| # 18. the above with -B | ||||
| # 18. Without -E, a should be hidden because its balance is zero, even though it has a non-zero cost. | ||||
| hledger -f - balance --no-total | ||||
| <<< | ||||
| 1/1 | ||||
|     a   1X @@ 1Y | ||||
|     a   1X @@ 1Y | ||||
|     a  -2X @@ 1Y | ||||
|     b | ||||
| >>> | ||||
|                  -1Y  b | ||||
| >>>= 0 | ||||
| 
 | ||||
| # 19. the above with -B | ||||
| hledger -f - balance --no-total -E -B | ||||
| <<< | ||||
| 1/1 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user