lib,ui: Do all cost conversion and price stripping in journalSelectingAmountFromOpts.

This commit is contained in:
Stephen Morgan 2021-05-07 20:20:47 +10:00
parent 0078f1a520
commit 53611be6e9
6 changed files with 54 additions and 59 deletions

View File

@ -84,45 +84,35 @@ accountTransactionsReport rspec@ReportSpec{rsOpts=ropts} j reportq thisacctq = i
where where
-- a depth limit should not affect the account transactions report -- a depth limit should not affect the account transactions report
-- seems unnecessary for some reason XXX -- seems unnecessary for some reason XXX
reportq' = -- filterQuery (not . queryIsDepth) reportq' = reportq -- filterQuery (not . queryIsDepth)
reportq symq = filterQuery queryIsSym reportq'
realq = filterQuery queryIsReal reportq'
-- get all transactions statusq = filterQuery queryIsStatus reportq'
ts1 = prices = journalPriceOracle (infer_value_ ropts) j
-- ptraceAtWith 5 (("ts1:\n"++).pshowTransactions) $ styles = journalCommodityStyles j
jtxns j
-- apply any cur:SYM filters in reportq'
symq = filterQuery queryIsSym reportq'
ts2 =
ptraceAtWith 5 (("ts2:\n"++).pshowTransactions) $
(if queryIsNull symq then id else map (filterTransactionAmounts symq)) ts1
-- keep just the transactions affecting this account (via possibly realness or status-filtered postings)
realq = filterQuery queryIsReal reportq'
statusq = filterQuery queryIsStatus reportq'
ts3 =
traceAt 3 ("thisacctq: "++show thisacctq) $
ptraceAtWith 5 (("ts3:\n"++).pshowTransactions) $
filter (matchesTransaction thisacctq . filterTransactionPostings (And [realq, statusq])) ts2
-- maybe convert these transactions to cost or value
-- PARTIAL:
prices = journalPriceOracle (infer_value_ ropts) j
styles = journalCommodityStyles j
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 = transactionApplyCostValuation prices styles periodlast (rsToday rspec) (cost_ ropts) $ value_ ropts pvalue = maybe id (postingApplyValuation prices styles periodlast (rsToday rspec)) $ value_ ropts
ts4 =
ptraceAtWith 5 (("ts4:\n"++).pshowTransactions) $
map tval ts3
-- sort by the transaction's register date, for accurate starting balance -- sort by the transaction's register date, for accurate starting balance
-- these are not yet filtered by tdate, we want to search them all for priorps -- these are not yet filtered by tdate, we want to search them all for priorps
ts5 = transactions =
ptraceAtWith 5 (("ts5:\n"++).pshowTransactions) $ ptraceAtWith 5 (("ts5:\n"++).pshowTransactions)
sortBy (comparing (transactionRegisterDate reportq' thisacctq)) ts4 . sortBy (comparing (transactionRegisterDate reportq' thisacctq))
. jtxns
-- maybe convert these transactions to cost or value
. ptraceAtWith 5 (("ts4:\n"++).pshowTransactions.jtxns)
. journalMapPostings pvalue
. journalSelectingAmountFromOpts ropts
-- keep just the transactions affecting this account (via possibly realness or status-filtered postings)
. traceAt 3 ("thisacctq: "++show thisacctq)
. ptraceAtWith 5 (("ts3:\n"++).pshowTransactions.jtxns)
. filterJournalTransactions thisacctq
. filterJournalPostings (And [realq, statusq])
-- apply any cur:SYM filters in reportq'
. ptraceAtWith 5 (("ts2:\n"++).pshowTransactions.jtxns)
$ (if queryIsNull symq then id else filterJournalAmounts symq) j
startbal startbal
| balancetype_ ropts == HistoricalBalance = sumPostings priorps | balancetype_ ropts == HistoricalBalance = sumPostings priorps
@ -132,7 +122,7 @@ accountTransactionsReport rspec@ReportSpec{rsOpts=ropts} j reportq thisacctq = i
filter (matchesPosting filter (matchesPosting
(dbg5 "priorq" $ (dbg5 "priorq" $
And [thisacctq, tostartdateq, datelessreportq])) And [thisacctq, tostartdateq, datelessreportq]))
$ transactionsPostings ts5 $ transactionsPostings transactions
tostartdateq = tostartdateq =
case mstartdate of case mstartdate of
Just _ -> Date (DateSpan Nothing mstartdate) Just _ -> Date (DateSpan Nothing mstartdate)
@ -149,7 +139,7 @@ accountTransactionsReport rspec@ReportSpec{rsOpts=ropts} j reportq thisacctq = i
items = reverse $ items = reverse $
accountTransactionsReportItems reportq' thisacctq startbal maNegate $ accountTransactionsReportItems reportq' thisacctq startbal maNegate $
(if filtertxns then filter (reportq' `matchesTransaction`) else id) $ (if filtertxns then filter (reportq' `matchesTransaction`) else id) $
ts5 transactions
pshowTransactions :: [Transaction] -> String pshowTransactions :: [Transaction] -> String
pshowTransactions = pshow . map (\t -> unwords [show $ tdate t, T.unpack $ tdescription t]) pshowTransactions = pshow . map (\t -> unwords [show $ tdate t, T.unpack $ tdescription t])

View File

@ -33,15 +33,18 @@ type EntriesReportItem = Transaction
-- | Select transactions for an entries report. -- | Select transactions for an entries report.
entriesReport :: ReportSpec -> Journal -> EntriesReport entriesReport :: ReportSpec -> Journal -> EntriesReport
entriesReport rspec@ReportSpec{rsOpts=ropts@ReportOpts{..}} j@Journal{..} = entriesReport rspec@ReportSpec{rsOpts=ropts@ReportOpts{..}} j =
sortBy (comparing getdate) $ filter (rsQuery rspec `matchesTransaction`) $ map tvalue jtxns sortBy (comparing getdate) . jtxns . filterJournalTransactions (rsQuery rspec)
. journalMapPostings pvalue
$ journalSelectingAmountFromOpts ropts{show_costs_=True} j
where where
getdate = transactionDateFn ropts getdate = transactionDateFn ropts
-- 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} pvalue = maybe id (postingApplyValuation priceoracle styles periodlast (rsToday rspec)) value_
where where
pvalue = postingApplyCostValuation (journalPriceOracle infer_value_ j) (journalCommodityStyles j) periodlast (rsToday rspec) cost_ value_ priceoracle = journalPriceOracle infer_value_ j
where periodlast = fromMaybe (rsToday rspec) $ reportPeriodOrJournalLastDay rspec j styles = journalCommodityStyles j
periodlast = fromMaybe (rsToday rspec) $ reportPeriodOrJournalLastDay rspec j
tests_EntriesReport = tests "EntriesReport" [ tests_EntriesReport = tests "EntriesReport" [
tests "entriesReport" [ tests "entriesReport" [

View File

@ -248,8 +248,9 @@ getPostings :: ReportSpec -> Journal -> [(Posting, Day)]
getPostings ReportSpec{rsQuery=query,rsOpts=ropts} = getPostings ReportSpec{rsQuery=query,rsOpts=ropts} =
map (\p -> (p, date p)) . map (\p -> (p, date p)) .
journalPostings . journalPostings .
filterJournalAmounts symq . -- remove amount parts excluded by cur: filterJournalAmounts symq . -- remove amount parts excluded by cur:
filterJournalPostings reportq -- remove postings not matched by (adjusted) query filterJournalPostings reportq . -- remove postings not matched by (adjusted) query
journalSelectingAmountFromOpts ropts
where where
symq = dbg3 "symq" . filterQuery queryIsSym $ dbg3 "requested q" query symq = dbg3 "symq" . filterQuery queryIsSym $ dbg3 "requested q" query
-- The user's query with no depth limit, and expanded to the report span -- The user's query with no depth limit, and expanded to the report span
@ -553,25 +554,24 @@ cumulativeSum :: (DateSpan -> Account -> Account) -> Account -> Map DateSpan Acc
cumulativeSum value start = snd . M.mapAccumWithKey accumValued start cumulativeSum value start = snd . M.mapAccumWithKey accumValued start
where accumValued startAmt date newAmt = let s = sumAcct startAmt newAmt in (s, value date s) 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 -- | Calculate the Posting and Account valuation functions required by this MultiBalanceReport.
-- MultiBalanceReport.
postingAndAccountValuations :: ReportSpec -> Journal -> PriceOracle postingAndAccountValuations :: ReportSpec -> Journal -> PriceOracle
-> (DateSpan -> Posting -> Posting, DateSpan -> Account -> Account) -> (DateSpan -> Posting -> Posting, DateSpan -> Account -> Account)
postingAndAccountValuations ReportSpec{rsToday=today, rsOpts=ropts} j priceoracle = case value_ ropts of postingAndAccountValuations ReportSpec{rsToday=today, rsOpts=ropts} j priceoracle = case value_ ropts of
-- If we're doing no valuation, just return the identity functions.
Nothing -> (const id, const id)
-- If we're doing AtEnd valuation, we may need to value the same posting at different dates -- 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 -- (for example, when preparing a ValueChange report). So we should do valuation on the Accounts.
-- maybe strip prices from the Posting, and should do valuation on the Accounts. Just v@(AtEnd _) -> (const id, avalue v)
Just v@(AtEnd _) -> (pvalue Nothing, avalue v) -- Otherwise, all valuation should be done on the Postings.
-- Otherwise, all costing and valuation should be done on the Postings. Just v -> (pvalue v, const id)
_ -> (pvalue (value_ ropts), const id)
where where
-- For a Posting: convert to cost, apply valuation, then strip prices if we don't need them (See issue #1507). -- 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 pvalue v span = postingApplyValuation priceoracle styles (end span) today v
-- For an Account: Apply valuation to both the inclusive and exclusive balances. -- 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)} 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 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 end = maybe (error "multiBalanceReport: expected all spans to have an end date") -- PARTIAL: should not happen
(addDays (-1)) . spanEnd (addDays (-1)) . spanEnd
styles = journalCommodityStyles j styles = journalCommodityStyles j

View File

@ -76,9 +76,7 @@ postingsReport rspec@ReportSpec{rsOpts=ropts@ReportOpts{..}} j = items
(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". -- We may be converting posting amounts to value, per hledger_options.m4.md "Effect of --value on reports".
-- Strip prices from postings if we won't need them. pvalue periodlast = maybe id (postingApplyValuation priceoracle styles periodlast (rsToday rspec)) value_
pvalue periodlast = maybeStripPrices . postingApplyCostValuation priceoracle styles periodlast (rsToday rspec) cost_ value_
where maybeStripPrices = if show_costs_ then id else postingStripPrices
-- 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)]

View File

@ -488,13 +488,14 @@ flat_ = not . tree_
-- depthFromOpts :: ReportOpts -> Int -- depthFromOpts :: ReportOpts -> Int
-- depthFromOpts opts = min (fromMaybe 99999 $ depth_ opts) (queryDepth $ queryFromOpts nulldate opts) -- depthFromOpts opts = min (fromMaybe 99999 $ depth_ opts) (queryDepth $ queryFromOpts nulldate opts)
-- | Convert this journal's postings' amounts to cost using their -- | Convert this journal's postings' amounts to cost using their transaction prices,
-- transaction prices, if specified by options (-B/--cost). -- if specified by options (-B/--cost). Strip prices if not needed.
-- Maybe soon superseded by newer valuation code.
journalSelectingAmountFromOpts :: ReportOpts -> Journal -> Journal journalSelectingAmountFromOpts :: ReportOpts -> Journal -> Journal
journalSelectingAmountFromOpts opts = case cost_ opts of journalSelectingAmountFromOpts ropts = maybeStripPrices . case cost_ ropts of
Cost -> journalToCost Cost -> journalToCost
NoCost -> id NoCost -> id
where
maybeStripPrices = if show_costs_ ropts then id else journalMapPostingAmounts mixedAmountStripPrices
-- | Convert report options to a query, ignoring any non-flag command line arguments. -- | Convert report options to a query, ignoring any non-flag command line arguments.
queryFromFlags :: ReportOpts -> Query queryFromFlags :: ReportOpts -> Query

View File

@ -83,7 +83,10 @@ 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
$ transactionApplyCostValuation prices styles periodlast (rsToday rspec) (cost_ ropts) (value_ ropts) t . maybe id (transactionApplyValuation prices styles periodlast (rsToday rspec)) (value_ ropts)
$ case cost_ ropts of
Cost -> transactionToCost styles t
NoCost -> t
-- (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 =