lib,cli: Extend AtThen valuation to all report types.
Also adds a postingDate argument to amountApplyValuation, and re-orders the ValuationType and (Transaction/Posting) arguments to (transaction/posting)ApplyValuation, to be consistent with amountApplyValuation.
This commit is contained in:
		
							parent
							
								
									3d7d5c0db7
								
							
						
					
					
						commit
						83110e8820
					
				| @ -334,28 +334,14 @@ aliasReplace (RegexAlias re repl) a = | |||||||
| -- provided price oracle, commodity styles, reference dates, and | -- provided price oracle, commodity styles, reference dates, and | ||||||
| -- whether this is for a multiperiod report or not. See | -- whether this is for a multiperiod report or not. See | ||||||
| -- amountApplyValuation. | -- amountApplyValuation. | ||||||
| postingApplyValuation :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Day -> Day -> Posting -> ValuationType -> Posting | postingApplyValuation :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Day -> Day -> ValuationType -> Posting -> Posting | ||||||
| postingApplyValuation priceoracle styles periodlast today p v = | postingApplyValuation priceoracle styles periodlast today v p = | ||||||
|   case v of |     postingTransformAmount (mixedAmountApplyValuation priceoracle styles periodlast today (postingDate p) v) p | ||||||
|     AtCost    Nothing -> postingToCost styles p |  | ||||||
|     AtCost    mc      -> postingValueAtDate priceoracle styles mc periodlast $ postingToCost styles p |  | ||||||
|     AtThen    mc      -> postingValueAtDate priceoracle styles mc (postingDate p) p |  | ||||||
|     AtEnd     mc      -> postingValueAtDate priceoracle styles mc periodlast p |  | ||||||
|     AtNow     mc      -> postingValueAtDate priceoracle styles mc today p |  | ||||||
|     AtDate d  mc      -> postingValueAtDate priceoracle styles mc d p |  | ||||||
| 
 | 
 | ||||||
| -- | Convert this posting's amount to cost, and apply the appropriate amount styles. | -- | Convert this posting's amount to cost, and apply the appropriate amount styles. | ||||||
| postingToCost :: M.Map CommoditySymbol AmountStyle -> Posting -> Posting | postingToCost :: M.Map CommoditySymbol AmountStyle -> Posting -> Posting | ||||||
| postingToCost styles p@Posting{pamount=a} = p{pamount=styleMixedAmount styles $ mixedAmountCost a} | postingToCost styles p@Posting{pamount=a} = p{pamount=styleMixedAmount styles $ mixedAmountCost a} | ||||||
| 
 | 
 | ||||||
| -- | Convert this posting's amount to market value in the given commodity, |  | ||||||
| -- or the default valuation commodity, at the given valuation date, |  | ||||||
| -- using the given market price oracle. |  | ||||||
| -- When market prices available on that date are not sufficient to |  | ||||||
| -- calculate the value, amounts are left unchanged. |  | ||||||
| postingValueAtDate :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Maybe CommoditySymbol -> Day -> Posting -> Posting |  | ||||||
| postingValueAtDate priceoracle styles mc d p = postingTransformAmount (mixedAmountValueAtDate priceoracle styles mc d) p |  | ||||||
| 
 |  | ||||||
| -- | Apply a transform function to this posting's amount. | -- | Apply a transform function to this posting's amount. | ||||||
| postingTransformAmount :: (MixedAmount -> MixedAmount) -> Posting -> Posting | postingTransformAmount :: (MixedAmount -> MixedAmount) -> Posting -> Posting | ||||||
| postingTransformAmount f p@Posting{pamount=a} = p{pamount=f a} | postingTransformAmount f p@Posting{pamount=a} = p{pamount=f a} | ||||||
|  | |||||||
| @ -594,9 +594,9 @@ transactionTransformPostings f t@Transaction{tpostings=ps} = t{tpostings=map f p | |||||||
| -- the provided price oracle, commodity styles, reference dates, and | -- the provided price oracle, commodity styles, reference dates, and | ||||||
| -- whether this is for a multiperiod report or not. See | -- whether this is for a multiperiod report or not. See | ||||||
| -- amountApplyValuation. | -- amountApplyValuation. | ||||||
| transactionApplyValuation :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Day -> Day -> Transaction -> ValuationType -> Transaction | transactionApplyValuation :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Day -> Day -> ValuationType -> Transaction -> Transaction | ||||||
| transactionApplyValuation priceoracle styles periodlast today t v = | transactionApplyValuation priceoracle styles periodlast today v = | ||||||
|   transactionTransformPostings (\p -> postingApplyValuation priceoracle styles periodlast today p v) t |   transactionTransformPostings (postingApplyValuation priceoracle styles periodlast today v) | ||||||
| 
 | 
 | ||||||
| -- | Convert this transaction's amounts to cost, and apply the appropriate amount styles. | -- | Convert this transaction's amounts to cost, and apply the appropriate amount styles. | ||||||
| transactionToCost :: M.Map CommoditySymbol AmountStyle -> Transaction -> Transaction | transactionToCost :: M.Map CommoditySymbol AmountStyle -> Transaction -> Transaction | ||||||
|  | |||||||
| @ -16,7 +16,6 @@ module Hledger.Data.Valuation ( | |||||||
|    ValuationType(..) |    ValuationType(..) | ||||||
|   ,PriceOracle |   ,PriceOracle | ||||||
|   ,journalPriceOracle |   ,journalPriceOracle | ||||||
|   ,unsupportedValueThenError |  | ||||||
|   -- ,amountApplyValuation |   -- ,amountApplyValuation | ||||||
|   -- ,amountValueAtDate |   -- ,amountValueAtDate | ||||||
|   ,mixedAmountApplyValuation |   ,mixedAmountApplyValuation | ||||||
| @ -98,9 +97,9 @@ priceDirectiveToMarketPrice PriceDirective{..} = | |||||||
| -- provided price oracle, commodity styles, reference dates, and | -- provided price oracle, commodity styles, reference dates, and | ||||||
| -- whether this is for a multiperiod report or not. | -- whether this is for a multiperiod report or not. | ||||||
| -- See amountApplyValuation. | -- See amountApplyValuation. | ||||||
| mixedAmountApplyValuation :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Day -> Day -> ValuationType -> MixedAmount -> MixedAmount | mixedAmountApplyValuation :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Day -> Day -> Day -> ValuationType -> MixedAmount -> MixedAmount | ||||||
| mixedAmountApplyValuation priceoracle styles periodlast today v (Mixed as) = | mixedAmountApplyValuation priceoracle styles periodlast today postingdate v = | ||||||
|   Mixed $ map (amountApplyValuation priceoracle styles periodlast today v) as |   mapMixedAmount (amountApplyValuation priceoracle styles periodlast today postingdate v) | ||||||
| 
 | 
 | ||||||
| -- | Apply a specified valuation to this amount, using the provided | -- | Apply a specified valuation to this amount, using the provided | ||||||
| -- price oracle, reference dates, and whether this is for a | -- price oracle, reference dates, and whether this is for a | ||||||
| @ -126,35 +125,27 @@ mixedAmountApplyValuation priceoracle styles periodlast today v (Mixed as) = | |||||||
| -- - the provided "today" date - (--value=now, or -V/X with no report | -- - the provided "today" date - (--value=now, or -V/X with no report | ||||||
| --   end date). | --   end date). | ||||||
| --  | --  | ||||||
| -- Note --value=then is not supported by this function, and will cause an error; |  | ||||||
| -- use postingApplyValuation for that. |  | ||||||
| --  |  | ||||||
| -- This is all a bit complicated. See the reference doc at | -- This is all a bit complicated. See the reference doc at | ||||||
| -- https://hledger.org/hledger.html#effect-of-valuation-on-reports | -- https://hledger.org/hledger.html#effect-of-valuation-on-reports | ||||||
| -- (hledger_options.m4.md "Effect of valuation on reports"), and #1083. | -- (hledger_options.m4.md "Effect of valuation on reports"), and #1083. | ||||||
| -- | -- | ||||||
| amountApplyValuation :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Day -> Day -> ValuationType -> Amount -> Amount | amountApplyValuation :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Day -> Day -> Day -> ValuationType -> Amount -> Amount | ||||||
| amountApplyValuation priceoracle styles periodlast today v a = | amountApplyValuation priceoracle styles periodlast today postingdate v a = | ||||||
|   case v of |   case v of | ||||||
|     AtCost    Nothing -> styleAmount styles $ amountCost a |     AtCost    Nothing -> styleAmount styles $ amountCost a | ||||||
|     AtCost    mc      -> amountValueAtDate priceoracle styles mc periodlast $ styleAmount styles $ amountCost a |     AtCost    mc      -> amountValueAtDate priceoracle styles mc periodlast . styleAmount styles $ amountCost a | ||||||
|     AtThen    _mc     -> error' unsupportedValueThenError  -- PARTIAL: |     AtThen    mc      -> amountValueAtDate priceoracle styles mc postingdate a | ||||||
|                       -- amountValueAtDate priceoracle styles mc periodlast a  -- posting date unknown, handle like AtEnd |  | ||||||
|     AtEnd     mc      -> amountValueAtDate priceoracle styles mc periodlast a |     AtEnd     mc      -> amountValueAtDate priceoracle styles mc periodlast a | ||||||
|     AtNow     mc      -> amountValueAtDate priceoracle styles mc today a |     AtNow     mc      -> amountValueAtDate priceoracle styles mc today a | ||||||
|     AtDate d  mc      -> amountValueAtDate priceoracle styles mc d a |     AtDate d  mc      -> amountValueAtDate priceoracle styles mc d a | ||||||
| 
 | 
 | ||||||
| -- | Standard error message for a report not supporting --value=then. |  | ||||||
| unsupportedValueThenError :: String |  | ||||||
| unsupportedValueThenError = "Sorry, --value=then is not yet supported for this kind of report." |  | ||||||
| 
 |  | ||||||
| -- | Find the market value of each component amount in the given | -- | Find the market value of each component amount in the given | ||||||
| -- commodity, or its default valuation commodity, at the given | -- commodity, or its default valuation commodity, at the given | ||||||
| -- valuation date, using the given market price oracle. | -- valuation date, using the given market price oracle. | ||||||
| -- When market prices available on that date are not sufficient to | -- When market prices available on that date are not sufficient to | ||||||
| -- calculate the value, amounts are left unchanged. | -- calculate the value, amounts are left unchanged. | ||||||
| mixedAmountValueAtDate :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Maybe CommoditySymbol -> Day -> MixedAmount -> MixedAmount | mixedAmountValueAtDate :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Maybe CommoditySymbol -> Day -> MixedAmount -> MixedAmount | ||||||
| mixedAmountValueAtDate priceoracle styles mc d (Mixed as) = Mixed $ map (amountValueAtDate priceoracle styles mc d) as | mixedAmountValueAtDate priceoracle styles mc d = mapMixedAmount (amountValueAtDate priceoracle styles mc d) | ||||||
| 
 | 
 | ||||||
| -- | Find the market value of this amount in the given valuation | -- | Find the market value of this amount in the given valuation | ||||||
| -- commodity if any, otherwise the default valuation commodity, at the | -- commodity if any, otherwise the default valuation commodity, at the | ||||||
|  | |||||||
| @ -111,9 +111,7 @@ accountTransactionsReport rspec@ReportSpec{rsOpts=ropts} j reportq thisacctq = i | |||||||
|     periodlast = |     periodlast = | ||||||
|       fromMaybe (error' "journalApplyValuation: expected a non-empty journal") $ -- XXX shouldn't happen |       fromMaybe (error' "journalApplyValuation: expected a non-empty journal") $ -- XXX shouldn't happen | ||||||
|       reportPeriodOrJournalLastDay rspec j |       reportPeriodOrJournalLastDay rspec j | ||||||
|     tval = case value_ ropts of |     tval = maybe id (transactionApplyValuation prices styles periodlast (rsToday rspec)) $ value_ ropts | ||||||
|              Just v  -> \t -> transactionApplyValuation prices styles periodlast (rsToday rspec) t v |  | ||||||
|              Nothing -> id |  | ||||||
|     ts4 = |     ts4 = | ||||||
|       ptraceAtWith 5 (("ts4:\n"++).pshowTransactions) $ |       ptraceAtWith 5 (("ts4:\n"++).pshowTransactions) $ | ||||||
|       map tval ts3 |       map tval ts3 | ||||||
|  | |||||||
| @ -228,7 +228,7 @@ budgetReportAsText ropts@ReportOpts{..} budgetr = TB.toLazyText $ | |||||||
|     title = "Budget performance in " <> showDateSpan (periodicReportSpan budgetr) |     title = "Budget performance in " <> showDateSpan (periodicReportSpan budgetr) | ||||||
|            <> (case value_ of |            <> (case value_ of | ||||||
|                  Just (AtCost _mc)   -> ", valued at cost" |                  Just (AtCost _mc)   -> ", valued at cost" | ||||||
|                  Just (AtThen _mc)   -> error' unsupportedValueThenError  -- PARTIAL: |                  Just (AtThen _mc)   -> ", valued at posting date" | ||||||
|                  Just (AtEnd _mc)    -> ", valued at period ends" |                  Just (AtEnd _mc)    -> ", valued at period ends" | ||||||
|                  Just (AtNow _mc)    -> ", current value" |                  Just (AtNow _mc)    -> ", current value" | ||||||
|                  Just (AtDate d _mc) -> ", valued at " <> showDate d |                  Just (AtDate d _mc) -> ", valued at " <> showDate d | ||||||
|  | |||||||
| @ -40,8 +40,8 @@ entriesReport rspec@ReportSpec{rsOpts=ropts@ReportOpts{..}} j@Journal{..} = | |||||||
|     -- We may be converting posting amounts to value, per hledger_options.m4.md "Effect of --value on reports". |     -- We may be converting posting amounts to value, per hledger_options.m4.md "Effect of --value on reports". | ||||||
|     tvalue t@Transaction{..} = t{tpostings=map pvalue tpostings} |     tvalue t@Transaction{..} = t{tpostings=map pvalue tpostings} | ||||||
|       where |       where | ||||||
|         pvalue p = maybe p |         pvalue = maybe id | ||||||
|           (postingApplyValuation (journalPriceOracle infer_value_ j) (journalCommodityStyles j) periodlast (rsToday rspec) p) |           (postingApplyValuation (journalPriceOracle infer_value_ j) (journalCommodityStyles j) periodlast (rsToday rspec)) | ||||||
|           value_ |           value_ | ||||||
|           where |           where | ||||||
|             periodlast  = fromMaybe (rsToday rspec) $ reportPeriodOrJournalLastDay rspec j |             periodlast  = fromMaybe (rsToday rspec) $ reportPeriodOrJournalLastDay rspec j | ||||||
|  | |||||||
| @ -114,20 +114,17 @@ multiBalanceReportWith rspec' j priceoracle = report | |||||||
|     -- Queries, report/column dates. |     -- Queries, report/column dates. | ||||||
|     reportspan = dbg3 "reportspan" $ calculateReportSpan rspec' j |     reportspan = dbg3 "reportspan" $ calculateReportSpan rspec' j | ||||||
|     rspec      = dbg3 "reportopts" $ makeReportQuery rspec' reportspan |     rspec      = dbg3 "reportopts" $ makeReportQuery rspec' reportspan | ||||||
|     valuation  = makeValuation rspec' j priceoracle  -- Must use rspec' instead of rspec, |  | ||||||
|                                                      -- so the reportspan isn't used for valuation |  | ||||||
| 
 | 
 | ||||||
|     -- Group postings into their columns. |     -- Group postings into their columns. | ||||||
|     colps    = dbg5 "colps"  $ getPostingsByColumn rspec j reportspan |     colps    = dbg5 "colps"  $ getPostingsByColumn rspec j reportspan | ||||||
|     colspans = dbg3 "colspans" $ M.keys colps |  | ||||||
| 
 | 
 | ||||||
|     -- The matched accounts with a starting balance. All of these should appear |     -- The matched accounts with a starting balance. All of these should appear | ||||||
|     -- in the report, even if they have no postings during the report period. |     -- in the report, even if they have no postings during the report period. | ||||||
|     startbals = dbg5 "startbals" $ startingBalances rspec j reportspan |     startbals = dbg5 "startbals" $ startingBalances rspec j priceoracle reportspan | ||||||
| 
 | 
 | ||||||
|     -- Generate and postprocess the report, negating balances and taking percentages if needed |     -- Generate and postprocess the report, negating balances and taking percentages if needed | ||||||
|     report = dbg4 "multiBalanceReportWith" $ |     report = dbg4 "multiBalanceReportWith" $ | ||||||
|       generateMultiBalanceReport rspec j valuation colspans colps startbals |       generateMultiBalanceReport rspec j priceoracle colps startbals | ||||||
| 
 | 
 | ||||||
| -- | Generate a compound balance report from a list of CBCSubreportSpec. This | -- | Generate a compound balance report from a list of CBCSubreportSpec. This | ||||||
| -- shares postings between the subreports. | -- shares postings between the subreports. | ||||||
| @ -145,16 +142,13 @@ compoundBalanceReportWith rspec' j priceoracle subreportspecs = cbr | |||||||
|     -- Queries, report/column dates. |     -- Queries, report/column dates. | ||||||
|     reportspan = dbg3 "reportspan" $ calculateReportSpan rspec' j |     reportspan = dbg3 "reportspan" $ calculateReportSpan rspec' j | ||||||
|     rspec      = dbg3 "reportopts" $ makeReportQuery rspec' reportspan |     rspec      = dbg3 "reportopts" $ makeReportQuery rspec' reportspan | ||||||
|     valuation  = makeValuation rspec' j priceoracle  -- Must use rspec' instead of rspec, |  | ||||||
|                                                      -- so the reportspan isn't used for valuation |  | ||||||
| 
 | 
 | ||||||
|     -- Group postings into their columns. |     -- Group postings into their columns. | ||||||
|     colps    = dbg5 "colps"  $ getPostingsByColumn rspec j reportspan |     colps    = dbg5 "colps"  $ getPostingsByColumn rspec j reportspan | ||||||
|     colspans = dbg3 "colspans" $ M.keys colps |  | ||||||
| 
 | 
 | ||||||
|     -- The matched accounts with a starting balance. All of these should appear |     -- The matched accounts with a starting balance. All of these should appear | ||||||
|     -- in the report, even if they have no postings during the report period. |     -- in the report, even if they have no postings during the report period. | ||||||
|     startbals = dbg5 "startbals" $ startingBalances rspec j reportspan |     startbals = dbg5 "startbals" $ startingBalances rspec j priceoracle reportspan | ||||||
| 
 | 
 | ||||||
|     subreports = map generateSubreport subreportspecs |     subreports = map generateSubreport subreportspecs | ||||||
|       where |       where | ||||||
| @ -162,7 +156,7 @@ compoundBalanceReportWith rspec' j priceoracle subreportspecs = cbr | |||||||
|             ( cbcsubreporttitle |             ( cbcsubreporttitle | ||||||
|             -- Postprocess the report, negating balances and taking percentages if needed |             -- Postprocess the report, negating balances and taking percentages if needed | ||||||
|             , cbcsubreporttransform $ |             , cbcsubreporttransform $ | ||||||
|                 generateMultiBalanceReport rspec{rsOpts=ropts} j valuation colspans colps' startbals' |                 generateMultiBalanceReport rspec{rsOpts=ropts} j priceoracle colps' startbals' | ||||||
|             , cbcsubreportincreasestotal |             , cbcsubreportincreasestotal | ||||||
|             ) |             ) | ||||||
|           where |           where | ||||||
| @ -183,7 +177,7 @@ compoundBalanceReportWith rspec' j priceoracle subreportspecs = cbr | |||||||
|         subreportTotal (_, sr, increasestotal) = |         subreportTotal (_, sr, increasestotal) = | ||||||
|             (if increasestotal then id else fmap negate) $ prTotals sr |             (if increasestotal then id else fmap negate) $ prTotals sr | ||||||
| 
 | 
 | ||||||
|     cbr = CompoundPeriodicReport "" colspans subreports overalltotals |     cbr = CompoundPeriodicReport "" (M.keys colps) subreports overalltotals | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| -- | Calculate starting balances, if needed for -H | -- | Calculate starting balances, if needed for -H | ||||||
| @ -193,14 +187,18 @@ compoundBalanceReportWith rspec' j priceoracle subreportspecs = cbr | |||||||
| -- TODO: Do we want to check whether to bother calculating these? isHistorical | -- TODO: Do we want to check whether to bother calculating these? isHistorical | ||||||
| -- and startDate is not nothing, otherwise mempty? This currently gives a | -- and startDate is not nothing, otherwise mempty? This currently gives a | ||||||
| -- failure with some totals which are supposed to be 0 being blank. | -- failure with some totals which are supposed to be 0 being blank. | ||||||
| startingBalances :: ReportSpec -> Journal -> DateSpan -> HashMap AccountName Account | startingBalances :: ReportSpec -> Journal -> PriceOracle -> DateSpan -> HashMap AccountName Account | ||||||
| startingBalances rspec@ReportSpec{rsQuery=query,rsOpts=ropts} j reportspan = | startingBalances rspec@ReportSpec{rsQuery=query,rsOpts=ropts} j priceoracle reportspan = | ||||||
|     acctChangesFromPostings rspec' . map fst $ getPostings rspec' j |     fmap (M.findWithDefault nullacct precedingspan) acctmap | ||||||
|   where |   where | ||||||
|  |     acctmap = calculateReportMatrix rspec' j priceoracle mempty | ||||||
|  |             . M.singleton precedingspan . map fst $ getPostings rspec' j | ||||||
|  | 
 | ||||||
|     rspec' = rspec{rsQuery=startbalq,rsOpts=ropts'} |     rspec' = rspec{rsQuery=startbalq,rsOpts=ropts'} | ||||||
|     ropts' = case accountlistmode_ ropts of |     -- If we're re-valuing every period, we need to have the unvalued start | ||||||
|         ALTree -> ropts{period_=precedingperiod, no_elide_=True} |     -- balance, so we can do it ourselves later. | ||||||
|         ALFlat -> ropts{period_=precedingperiod} |     ropts' = if changingValuation ropts then ropts''{value_=Nothing} else ropts'' | ||||||
|  |       where ropts'' = ropts{period_=precedingperiod, no_elide_=accountlistmode_ ropts == ALTree} | ||||||
| 
 | 
 | ||||||
|     -- q projected back before the report start date. |     -- q projected back before the report start date. | ||||||
|     -- When there's no report start date, in case there are future txns (the hledger-ui case above), |     -- When there's no report start date, in case there are future txns (the hledger-ui case above), | ||||||
| @ -249,14 +247,6 @@ makeReportQuery rspec reportspan | |||||||
|     dateless         = dbg3 "dateless" . filterQuery (not . queryIsDateOrDate2) |     dateless         = dbg3 "dateless" . filterQuery (not . queryIsDateOrDate2) | ||||||
|     dateqcons        = if date2_ (rsOpts rspec) then Date2 else Date |     dateqcons        = if date2_ (rsOpts rspec) then Date2 else Date | ||||||
| 
 | 
 | ||||||
| -- | Make a valuation function for valuating MixedAmounts and a given Day |  | ||||||
| makeValuation :: ReportSpec -> Journal -> PriceOracle -> (Day -> MixedAmount -> MixedAmount) |  | ||||||
| makeValuation rspec j priceoracle day = case value_ (rsOpts rspec) of |  | ||||||
|     Nothing -> id |  | ||||||
|     Just v  -> mixedAmountApplyValuation priceoracle styles day (rsToday rspec) v |  | ||||||
|   where |  | ||||||
|     styles = journalCommodityStyles j |  | ||||||
| 
 |  | ||||||
| -- | Group postings, grouped by their column | -- | Group postings, grouped by their column | ||||||
| getPostingsByColumn :: ReportSpec -> Journal -> DateSpan -> Map DateSpan [Posting] | getPostingsByColumn :: ReportSpec -> Journal -> DateSpan -> Map DateSpan [Posting] | ||||||
| getPostingsByColumn rspec j reportspan = columns | getPostingsByColumn rspec j reportspan = columns | ||||||
| @ -265,7 +255,7 @@ getPostingsByColumn rspec j reportspan = columns | |||||||
|     ps :: [(Posting, Day)] = dbg5 "getPostingsByColumn" $ getPostings rspec j |     ps :: [(Posting, Day)] = dbg5 "getPostingsByColumn" $ getPostings rspec j | ||||||
| 
 | 
 | ||||||
|     -- The date spans to be included as report columns. |     -- The date spans to be included as report columns. | ||||||
|     colspans = dbg3 "displayspan" $ splitSpan (interval_ $ rsOpts rspec) reportspan |     colspans = dbg3 "colspans" $ splitSpan (interval_ $ rsOpts rspec) reportspan | ||||||
|     addPosting (p, d) = maybe id (M.adjust (p:)) $ latestSpanContaining colspans d |     addPosting (p, d) = maybe id (M.adjust (p:)) $ latestSpanContaining colspans d | ||||||
|     emptyMap = M.fromList . zip colspans $ repeat [] |     emptyMap = M.fromList . zip colspans $ repeat [] | ||||||
| 
 | 
 | ||||||
| @ -292,22 +282,6 @@ getPostings ReportSpec{rsQuery=query,rsOpts=ropts} = | |||||||
|         SecondaryDate -> postingDate2 |         SecondaryDate -> postingDate2 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| -- | Gather the account balance changes into a regular matrix |  | ||||||
| -- including the accounts from all columns. |  | ||||||
| calculateAccountChanges :: ReportSpec -> [DateSpan] -> Map DateSpan [Posting] |  | ||||||
|                         -> HashMap ClippedAccountName (Map DateSpan Account) |  | ||||||
| calculateAccountChanges rspec colspans colps |  | ||||||
|     | queryDepth (rsQuery rspec) == Just 0 = acctchanges <> elided |  | ||||||
|     | otherwise = acctchanges |  | ||||||
|   where |  | ||||||
|     -- Transpose to get each account's balance changes across all columns. |  | ||||||
|     acctchanges = transposeMap colacctchanges |  | ||||||
| 
 |  | ||||||
|     colacctchanges :: Map DateSpan (HashMap ClippedAccountName Account) = |  | ||||||
|       dbg5 "colacctchanges" $ fmap (acctChangesFromPostings rspec) colps |  | ||||||
| 
 |  | ||||||
|     elided = HM.singleton "..." $ M.fromList [(span, nullacct) | span <- colspans] |  | ||||||
| 
 |  | ||||||
| -- | Given a set of postings, eg for a single report column, gather | -- | Given a set of postings, eg for a single report column, gather | ||||||
| -- the accounts that have postings and calculate the change amount for | -- the accounts that have postings and calculate the change amount for | ||||||
| -- each. Accounts and amounts will be depth-clipped appropriately if | -- each. Accounts and amounts will be depth-clipped appropriately if | ||||||
| @ -323,16 +297,17 @@ acctChangesFromPostings ReportSpec{rsQuery=query,rsOpts=ropts} ps = | |||||||
|                       filter ((0<) . anumpostings) |                       filter ((0<) . anumpostings) | ||||||
|     depthq = dbg3 "depthq" $ filterQuery queryIsDepth query |     depthq = dbg3 "depthq" $ filterQuery queryIsDepth query | ||||||
| 
 | 
 | ||||||
| -- | Accumulate and value amounts, as specified by the report options. | -- | Gather the account balance changes into a regular matrix, then | ||||||
|  | -- accumulate and value amounts, as specified by the report options. | ||||||
| -- | -- | ||||||
| -- Makes sure all report columns have an entry. | -- Makes sure all report columns have an entry. | ||||||
| accumValueAmounts :: ReportOpts -> (Day -> MixedAmount -> MixedAmount) -> [DateSpan] | calculateReportMatrix :: ReportSpec -> Journal -> PriceOracle | ||||||
|                   -> HashMap ClippedAccountName Account |                       -> HashMap ClippedAccountName Account | ||||||
|                   -> HashMap ClippedAccountName (Map DateSpan Account) |                       -> Map DateSpan [Posting] | ||||||
|                   -> HashMap ClippedAccountName (Map DateSpan Account) |                       -> HashMap ClippedAccountName (Map DateSpan Account) | ||||||
| accumValueAmounts ropts valuation colspans startbals acctchanges =  -- PARTIAL: | calculateReportMatrix rspec@ReportSpec{rsOpts=ropts} j priceoracle startbals colps =  -- PARTIAL: | ||||||
|     -- Ensure all columns have entries, including those with starting balances |     -- Ensure all columns have entries, including those with starting balances | ||||||
|     HM.mapWithKey rowbals $ ((<>zeros) <$> acctchanges) <> (zeros <$ startbals) |     HM.mapWithKey rowbals allchanges | ||||||
|   where |   where | ||||||
|     -- The valued row amounts to be displayed: per-period changes, |     -- The valued row amounts to be displayed: per-period changes, | ||||||
|     -- zero-based cumulative totals, or |     -- zero-based cumulative totals, or | ||||||
| @ -342,71 +317,47 @@ accumValueAmounts ropts valuation colspans startbals acctchanges =  -- PARTIAL: | |||||||
|         CumulativeChange  -> cumulative |         CumulativeChange  -> cumulative | ||||||
|         HistoricalBalance -> historical |         HistoricalBalance -> historical | ||||||
|       where |       where | ||||||
|         historical = cumulativeSum startingBalance |         historical                           = cumulativeSum avalue startingBalance changes | ||||||
|         cumulative | fixedValuationDate = cumulativeSum nullacct |         cumulative | changingValuation ropts = fmap (`subtractAcct` valuedStart) historical | ||||||
|                    | otherwise          = fmap (`subtractAcct` valuedStart) historical |                    | otherwise               = cumulativeSum avalue nullacct changes | ||||||
|         changeamts | fixedValuationDate = M.mapWithKey valueAcct changes |         changeamts | changingValuation ropts = periodChanges valuedStart historical | ||||||
|                    | otherwise          = M.fromDistinctAscList . zip dates $ |                    | otherwise               = changes | ||||||
|                                             zipWith subtractAcct histamts (valuedStart:histamts) |  | ||||||
|           where (dates, histamts) = unzip $ M.toAscList historical |  | ||||||
| 
 |  | ||||||
|         cumulativeSum start = snd $ M.mapAccumWithKey accumValued start changes |  | ||||||
|           where accumValued startAmt date newAmt = (s, valueAcct date s) |  | ||||||
|                   where s = sumAcct startAmt newAmt |  | ||||||
| 
 |  | ||||||
|         -- Whether the market price is measured at the same date for all report |  | ||||||
|         -- periods, and we can therefore use the simpler calculations for |  | ||||||
|         -- cumulative and change reports. |  | ||||||
|         fixedValuationDate = case value_ ropts of |  | ||||||
|             Just (AtCost (Just _)) -> singleperiod |  | ||||||
|             Just (AtEnd  _)        -> singleperiod |  | ||||||
|             _                      -> True |  | ||||||
|           where singleperiod = interval_ ropts == NoInterval |  | ||||||
| 
 | 
 | ||||||
|         startingBalance = HM.lookupDefault nullacct name startbals |         startingBalance = HM.lookupDefault nullacct name startbals | ||||||
|         valuedStart = valueAcct (DateSpan Nothing historicalDate) startingBalance |         valuedStart = avalue (DateSpan Nothing historicalDate) startingBalance | ||||||
| 
 | 
 | ||||||
|     -- Add the values of two accounts. Should be right-biased, since it's used |     -- Transpose to get each account's balance changes across all columns, then | ||||||
|     -- in scanl, so other properties (such as anumpostings) stay in the right place |     -- pad with zeros | ||||||
|     sumAcct Account{aibalance=i1,aebalance=e1} a@Account{aibalance=i2,aebalance=e2} = |     allchanges     = ((<>zeros) <$> acctchanges) <> (zeros <$ startbals) | ||||||
|         a{aibalance = i1 + i2, aebalance = e1 + e2} |     acctchanges    = dbg5 "acctchanges" . addElided $ transposeMap colacctchanges | ||||||
|  |     colacctchanges = dbg5 "colacctchanges" $ fmap (acctChangesFromPostings rspec) valuedps | ||||||
|  |     valuedps = M.mapWithKey (\colspan -> map (pvalue colspan)) colps | ||||||
| 
 | 
 | ||||||
|     -- Subtract the values in one account from another. Should be left-biased. |     (pvalue, avalue) = postingAndAccountValuations rspec j priceoracle | ||||||
|     subtractAcct a@Account{aibalance=i1,aebalance=e1} Account{aibalance=i2,aebalance=e2} = |     addElided = if queryDepth (rsQuery rspec) == Just 0 then HM.insert "..." zeros else id | ||||||
|         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 |  | ||||||
| 
 |  | ||||||
|     zeros = M.fromList [(span, nullacct) | span <- colspans] |  | ||||||
|     historicalDate = minimumMay $ mapMaybe spanStart colspans |     historicalDate = minimumMay $ mapMaybe spanStart colspans | ||||||
|  |     zeros = M.fromList [(span, nullacct) | span <- colspans] | ||||||
|  |     colspans = M.keys colps | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| -- | Lay out a set of postings grouped by date span into a regular matrix with rows | -- | Lay out a set of postings grouped by date span into a regular matrix with rows | ||||||
| -- given by AccountName and columns by DateSpan, then generate a MultiBalanceReport | -- given by AccountName and columns by DateSpan, then generate a MultiBalanceReport | ||||||
| -- from the columns. | -- from the columns. | ||||||
| generateMultiBalanceReport :: ReportSpec -> Journal -> (Day -> MixedAmount -> MixedAmount) -> [DateSpan] | generateMultiBalanceReport :: ReportSpec -> Journal -> PriceOracle | ||||||
|                            -> Map DateSpan [Posting] -> HashMap AccountName Account |                            -> Map DateSpan [Posting] -> HashMap AccountName Account | ||||||
|                            -> MultiBalanceReport |                            -> MultiBalanceReport | ||||||
| generateMultiBalanceReport rspec@ReportSpec{rsOpts=ropts} j valuation colspans colps startbals = | generateMultiBalanceReport rspec@ReportSpec{rsOpts=ropts} j priceoracle colps startbals = | ||||||
|     report |     report | ||||||
|   where |   where | ||||||
|     -- Each account's balance changes across all columns. |  | ||||||
|     acctchanges = dbg5 "acctchanges" $ calculateAccountChanges rspec colspans colps |  | ||||||
| 
 |  | ||||||
|     -- Process changes into normal, cumulative, or historical amounts, plus value them |     -- Process changes into normal, cumulative, or historical amounts, plus value them | ||||||
|     accumvalued = accumValueAmounts ropts valuation colspans startbals acctchanges |     matrix = calculateReportMatrix rspec j priceoracle startbals colps | ||||||
| 
 | 
 | ||||||
|     -- All account names that will be displayed, possibly depth-clipped. |     -- All account names that will be displayed, possibly depth-clipped. | ||||||
|     displaynames = dbg5 "displaynames" $ displayedAccounts rspec accumvalued |     displaynames = dbg5 "displaynames" $ displayedAccounts rspec matrix | ||||||
| 
 | 
 | ||||||
|     -- All the rows of the report. |     -- All the rows of the report. | ||||||
|     rows = dbg5 "rows" |     rows = dbg5 "rows" . (if invert_ ropts then map (fmap negate) else id)  -- Negate amounts if applicable | ||||||
|              . (if invert_ ropts then map (fmap negate) else id)  -- Negate amounts if applicable |              $ buildReportRows ropts displaynames matrix | ||||||
|              $ buildReportRows ropts displaynames accumvalued |  | ||||||
| 
 | 
 | ||||||
|     -- Calculate column totals |     -- Calculate column totals | ||||||
|     totalsrow = dbg5 "totalsrow" $ calculateTotalsRow ropts rows |     totalsrow = dbg5 "totalsrow" $ calculateTotalsRow ropts rows | ||||||
| @ -415,7 +366,7 @@ generateMultiBalanceReport rspec@ReportSpec{rsOpts=ropts} j valuation colspans c | |||||||
|     sortedrows = dbg5 "sortedrows" $ sortRows ropts j rows |     sortedrows = dbg5 "sortedrows" $ sortRows ropts j rows | ||||||
| 
 | 
 | ||||||
|     -- Take percentages if needed |     -- Take percentages if needed | ||||||
|     report = reportPercent ropts $ PeriodicReport colspans sortedrows totalsrow |     report = reportPercent ropts $ PeriodicReport (M.keys colps) sortedrows totalsrow | ||||||
| 
 | 
 | ||||||
| -- | Build the report rows. | -- | Build the report rows. | ||||||
| -- One row per account, with account name info, row amounts, row total and row average. | -- One row per account, with account name info, row amounts, row total and row average. | ||||||
| @ -565,7 +516,7 @@ reportPercent ropts report@(PeriodicReport spans rows totalrow) | |||||||
| -- Makes sure that all DateSpans are present in all rows. | -- Makes sure that all DateSpans are present in all rows. | ||||||
| transposeMap :: Map DateSpan (HashMap AccountName a) | transposeMap :: Map DateSpan (HashMap AccountName a) | ||||||
|              -> HashMap AccountName (Map DateSpan a) |              -> HashMap AccountName (Map DateSpan a) | ||||||
| transposeMap xs = M.foldrWithKey addSpan mempty xs | transposeMap = M.foldrWithKey addSpan mempty | ||||||
|   where |   where | ||||||
|     addSpan span acctmap seen = HM.foldrWithKey (addAcctSpan span) seen acctmap |     addSpan span acctmap seen = HM.foldrWithKey (addAcctSpan span) seen acctmap | ||||||
| 
 | 
 | ||||||
| @ -598,6 +549,54 @@ perdivide a b = fromMaybe (error' errmsg) $ do  -- PARTIAL: | |||||||
|     return $ mixed [per $ if aquantity b' == 0 then 0 else aquantity a' / abs (aquantity b') * 100] |     return $ mixed [per $ if aquantity b' == 0 then 0 else aquantity a' / abs (aquantity b') * 100] | ||||||
|   where errmsg = "Cannot calculate percentages if accounts have different commodities (Hint: Try --cost, -V or similar flags.)" |   where errmsg = "Cannot calculate percentages if accounts have different commodities (Hint: Try --cost, -V or similar flags.)" | ||||||
| 
 | 
 | ||||||
|  | -- 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 -> Account -> Account | ||||||
|  | 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 :: Account -> Account -> Account | ||||||
|  | subtractAcct a@Account{aibalance=i1,aebalance=e1} Account{aibalance=i2,aebalance=e2} = | ||||||
|  |     a{aibalance = i1 - i2, aebalance = e1 - e2} | ||||||
|  | 
 | ||||||
|  | -- | Whether the market price for postings might change when reported in | ||||||
|  | -- different report periods. | ||||||
|  | changingValuation :: ReportOpts -> Bool | ||||||
|  | changingValuation ropts = case value_ ropts of | ||||||
|  |     Just (AtCost (Just _)) -> multiperiod | ||||||
|  |     Just (AtEnd  _)        -> multiperiod | ||||||
|  |     _                      -> False | ||||||
|  |   where multiperiod = interval_ ropts /= NoInterval | ||||||
|  | 
 | ||||||
|  | -- | Extract period changes from a cumulative list | ||||||
|  | periodChanges :: Account -> Map k Account -> Map k Account | ||||||
|  | periodChanges start amtmap = | ||||||
|  |     M.fromDistinctAscList . zip dates $ zipWith subtractAcct amts (start:amts) | ||||||
|  |   where (dates, amts) = unzip $ M.toAscList amtmap | ||||||
|  | 
 | ||||||
|  | -- | Calculate a cumulative sum from a list of period changes and a valuation | ||||||
|  | -- function. | ||||||
|  | cumulativeSum :: (DateSpan -> Account -> Account) -> Account -> Map DateSpan Account -> Map DateSpan Account | ||||||
|  | cumulativeSum value start = snd . M.mapAccumWithKey accumValued start | ||||||
|  |   where accumValued startAmt date newAmt = let s = sumAcct startAmt newAmt in (s, value date s) | ||||||
|  | 
 | ||||||
|  | -- | Calculate the Posting and Account valuation functions required by this | ||||||
|  | -- MultiBalanceReport. | ||||||
|  | postingAndAccountValuations :: ReportSpec -> Journal -> PriceOracle | ||||||
|  |                             -> (DateSpan -> Posting -> Posting, DateSpan -> Account -> Account) | ||||||
|  | postingAndAccountValuations rspec@ReportSpec{rsOpts=ropts} j priceoracle = | ||||||
|  |   case value_ ropts of | ||||||
|  |     Nothing -> (const id, const id) | ||||||
|  |     Just v  -> if changingValuation ropts then (const id, avalue' v) else (pvalue' v, const id) | ||||||
|  |   where | ||||||
|  |     avalue' v span a = a{aibalance = value (aibalance a), aebalance = value (aebalance a)} | ||||||
|  |       where value = mixedAmountApplyValuation priceoracle styles (end span) (rsToday rspec) (error "multiBalanceReport: did not expect amount valuation to be called ") v  -- PARTIAL: should not happen | ||||||
|  |     pvalue' v span = postingApplyValuation priceoracle styles (end span) (rsToday rspec) v | ||||||
|  |     end = fromMaybe (error "multiBalanceReport: expected all spans to have an end date")  -- XXX should not happen | ||||||
|  |         . fmap (addDays (-1)) . spanEnd | ||||||
|  |     styles = journalCommodityStyles j | ||||||
|  | 
 | ||||||
| -- tests | -- tests | ||||||
| 
 | 
 | ||||||
| tests_MultiBalanceReport = tests "MultiBalanceReport" [ | tests_MultiBalanceReport = tests "MultiBalanceReport" [ | ||||||
|  | |||||||
| @ -75,17 +75,18 @@ postingsReport rspec@ReportSpec{rsOpts=ropts@ReportOpts{..}} j = items | |||||||
|       -- postings to be included in the report, and similarly-matched postings before the report start date |       -- postings to be included in the report, and similarly-matched postings before the report start date | ||||||
|       (precedingps, reportps) = matchedPostingsBeforeAndDuring rspec j reportspan |       (precedingps, reportps) = matchedPostingsBeforeAndDuring rspec j reportspan | ||||||
| 
 | 
 | ||||||
|  |       -- We may be converting posting amounts to value, per hledger_options.m4.md "Effect of --value on reports". | ||||||
|  |       pvalue periodlast = maybe id (postingApplyValuation priceoracle styles periodlast (rsToday rspec)) value_ | ||||||
|  | 
 | ||||||
|       -- Postings, or summary postings with their subperiod's end date, to be displayed. |       -- Postings, or summary postings with their subperiod's end date, to be displayed. | ||||||
|       displayps :: [(Posting, Maybe Day)] |       displayps :: [(Posting, Maybe Day)] | ||||||
|         | multiperiod = |         | multiperiod = | ||||||
|             let summaryps = summarisePostingsByInterval interval_ whichdate mdepth showempty reportspan reportps |             let summaryps = summarisePostingsByInterval interval_ whichdate mdepth showempty reportspan reportps | ||||||
|             in [(pvalue p lastday, Just periodend) | (p, periodend) <- summaryps, let lastday = addDays (-1) periodend] |             in [(pvalue lastday p, Just periodend) | (p, periodend) <- summaryps, let lastday = addDays (-1) periodend] | ||||||
|         | otherwise = |         | otherwise = | ||||||
|             [(pvalue p reportorjournallast, Nothing) | p <- reportps] |             [(pvalue reportorjournallast p, Nothing) | p <- reportps] | ||||||
|         where |         where | ||||||
|           showempty = empty_ || average_ |           showempty = empty_ || average_ | ||||||
|           -- We may be converting posting amounts to value, per hledger_options.m4.md "Effect of --value on reports". |  | ||||||
|           pvalue p periodlast = maybe p (postingApplyValuation priceoracle styles periodlast (rsToday rspec) p) value_ |  | ||||||
|           reportorjournallast = |           reportorjournallast = | ||||||
|             fromMaybe (error' "postingsReport: expected a non-empty journal") $  -- PARTIAL: shouldn't happen |             fromMaybe (error' "postingsReport: expected a non-empty journal") $  -- PARTIAL: shouldn't happen | ||||||
|             reportPeriodOrJournalLastDay rspec j |             reportPeriodOrJournalLastDay rspec j | ||||||
| @ -100,19 +101,16 @@ postingsReport rspec@ReportSpec{rsOpts=ropts@ReportOpts{..}} j = items | |||||||
|           -- of --value on reports". |           -- of --value on reports". | ||||||
|           -- XXX balance report doesn't value starting balance.. should this ? |           -- XXX balance report doesn't value starting balance.. should this ? | ||||||
|           historical = balancetype_ == HistoricalBalance |           historical = balancetype_ == HistoricalBalance | ||||||
|           startbal | average_  = if historical then bvalue precedingavg else 0 |           startbal | average_  = if historical then precedingavg else 0 | ||||||
|                    | otherwise = if historical then bvalue precedingsum else 0 |                    | otherwise = if historical then precedingsum else 0 | ||||||
|             where |             where | ||||||
|               precedingsum = sumPostings precedingps |               precedingsum = sumPostings $ map (pvalue daybeforereportstart) precedingps | ||||||
|               precedingavg | null precedingps = 0 |               precedingavg | null precedingps = 0 | ||||||
|                            | otherwise        = divideMixedAmount (fromIntegral $ length precedingps) precedingsum |                            | otherwise        = divideMixedAmount (fromIntegral $ length precedingps) precedingsum | ||||||
|               bvalue = maybe id (mixedAmountApplyValuation priceoracle styles daybeforereportstart $ rsToday rspec) value_ |               daybeforereportstart = | ||||||
|                   -- XXX constrain valuation type to AtDate daybeforereportstart here ? |                 maybe (error' "postingsReport: expected a non-empty journal")  -- PARTIAL: shouldn't happen | ||||||
|                 where |                 (addDays (-1)) | ||||||
|                   daybeforereportstart = |                 $ reportPeriodOrJournalStart rspec j | ||||||
|                     maybe (error' "postingsReport: expected a non-empty journal")  -- PARTIAL: shouldn't happen |  | ||||||
|                     (addDays (-1)) |  | ||||||
|                     $ reportPeriodOrJournalStart rspec j |  | ||||||
| 
 | 
 | ||||||
|           runningcalc = registerRunningCalculationFn ropts |           runningcalc = registerRunningCalculationFn ropts | ||||||
|           startnum = if historical then length precedingps + 1 else 1 |           startnum = if historical then length precedingps + 1 else 1 | ||||||
|  | |||||||
| @ -81,8 +81,7 @@ tsDraw UIState{aopts=UIOpts{cliopts_=copts@CliOpts{reportspec_=rspec@ReportSpec{ | |||||||
| 
 | 
 | ||||||
|       render . defaultLayout toplabel bottomlabel . str |       render . defaultLayout toplabel bottomlabel . str | ||||||
|         . T.unpack . showTransactionOneLineAmounts |         . T.unpack . showTransactionOneLineAmounts | ||||||
|         . maybe t (transactionApplyValuation prices styles periodlast (rsToday rspec) t) |         $ maybe id (transactionApplyValuation prices styles periodlast (rsToday rspec)) (value_ ropts) t | ||||||
|         $ value_ ropts |  | ||||||
|         -- (if real_ ropts then filterTransactionPostings (Real True) else id) -- filter postings by --real |         -- (if real_ ropts then filterTransactionPostings (Real True) else id) -- filter postings by --real | ||||||
|       where |       where | ||||||
|         toplabel = |         toplabel = | ||||||
|  | |||||||
| @ -577,7 +577,7 @@ multiBalanceReportAsText ropts@ReportOpts{..} r = TB.toLazyText $ | |||||||
|         HistoricalBalance                -> "Ending balances (historical)" |         HistoricalBalance                -> "Ending balances (historical)" | ||||||
|     valuationdesc = case value_ of |     valuationdesc = case value_ of | ||||||
|         Just (AtCost _mc)    -> ", valued at cost" |         Just (AtCost _mc)    -> ", valued at cost" | ||||||
|         Just (AtThen _mc)    -> error' unsupportedValueThenError  -- TODO -- ", valued at period ends"  -- handled like AtEnd for now  -- PARTIAL: |         Just (AtThen _mc)    -> ", valued at posting date" | ||||||
|         Just (AtEnd _mc) | changingValuation -> "" |         Just (AtEnd _mc) | changingValuation -> "" | ||||||
|         Just (AtEnd _mc)     -> ", valued at period ends" |         Just (AtEnd _mc)     -> ", valued at period ends" | ||||||
|         Just (AtNow _mc)     -> ", current value" |         Just (AtNow _mc)     -> ", current value" | ||||||
|  | |||||||
| @ -141,7 +141,7 @@ compoundBalanceCommand CompoundBalanceCommandSpec{..} opts@CliOpts{reportspec_=r | |||||||
| 
 | 
 | ||||||
|         valuationdesc = case value_ of |         valuationdesc = case value_ of | ||||||
|           Just (AtCost _mc)       -> ", valued at cost" |           Just (AtCost _mc)       -> ", valued at cost" | ||||||
|           Just (AtThen _mc)       -> error' unsupportedValueThenError  -- TODO |           Just (AtThen _mc)       -> ", valued at posting date" | ||||||
|           Just (AtEnd _mc) | changingValuation -> "" |           Just (AtEnd _mc) | changingValuation -> "" | ||||||
|           Just (AtEnd _mc)        -> ", valued at period ends" |           Just (AtEnd _mc)        -> ", valued at period ends" | ||||||
|           Just (AtNow _mc)        -> ", current value" |           Just (AtNow _mc)        -> ", current value" | ||||||
|  | |||||||
| @ -569,8 +569,7 @@ Budget performance in 2000-01-01..2000-04-30, valued at 2000-01-15: | |||||||
| ---++---------------------------------------------------------------------------------------------------------------- | ---++---------------------------------------------------------------------------------------------------------------- | ||||||
|    || 5 B [50% of 10 B]  5 B [50% of 10 B]  5 B [50% of 10 B]  0 [0% of 10 B]  15 B [38% of 40 B]  4 B [38% of 10 B]  |    || 5 B [50% of 10 B]  5 B [50% of 10 B]  5 B [50% of 10 B]  0 [0% of 10 B]  15 B [38% of 40 B]  4 B [38% of 10 B]  | ||||||
| 
 | 
 | ||||||
| # 50. --value=then with --historical. How is the starting total valued ? | # 50. --value=then with --historical. The starting total is valued individually for each posting at its posting time. | ||||||
| # Currently not supported. |  | ||||||
| < | < | ||||||
| P 2020-01-01 A 1 B | P 2020-01-01 A 1 B | ||||||
| P 2020-02-01 A 2 B | P 2020-02-01 A 2 B | ||||||
| @ -590,8 +589,9 @@ P 2020-04-01 A 4 B | |||||||
|    (a)  1 A |    (a)  1 A | ||||||
| 
 | 
 | ||||||
| $ hledger -f- reg --value=then -b 2020-03 -H | $ hledger -f- reg --value=then -b 2020-03 -H | ||||||
| >2 /not yet supported/ | 2020-03-01                      (a)                            3 B           6 B | ||||||
| >=1 | 2020-04-01                      (a)                            4 B          10 B | ||||||
|  | >=0 | ||||||
| 
 | 
 | ||||||
| # 51. --value=then with a report interval. How are the summary amounts valued ? | # 51. --value=then with a report interval. How are the summary amounts valued ? | ||||||
| # Currently each interval's unvalued sum is valued on its first day. | # Currently each interval's unvalued sum is valued on its first day. | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user