From 0e89a389d640a05dc91e1ffe0074472c87d99af3 Mon Sep 17 00:00:00 2001 From: Stephen Morgan Date: Fri, 12 Jun 2020 14:28:32 +1000 Subject: [PATCH] lib: multiBalanceReport: Split displayedAccounts, calculateReportQuery into separate functions. --- .../Hledger/Reports/MultiBalanceReport.hs | 101 ++++++++++-------- 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/hledger-lib/Hledger/Reports/MultiBalanceReport.hs b/hledger-lib/Hledger/Reports/MultiBalanceReport.hs index 996c81eda..f29555fe6 100644 --- a/hledger-lib/Hledger/Reports/MultiBalanceReport.hs +++ b/hledger-lib/Hledger/Reports/MultiBalanceReport.hs @@ -93,36 +93,13 @@ multiBalanceReport today ropts j = multiBalanceReportWith :: ReportOpts -> Query -> Journal -> PriceOracle -> MultiBalanceReport multiBalanceReportWith ropts@ReportOpts{..} q j priceoracle = report where - ---------------------------------------------------------------------- - -- 1. Queries, report/column dates. + -- Queries, report/column dates. + reportspan = dbg "reportspan" $ calculateReportSpan ropts q j + reportq = dbg "reportq" $ makeReportQuery ropts reportspan q - depthq = dbg "depthq" $ filterQuery queryIsDepth q - depth = queryDepth depthq - -- The date span specified by -b/-e/-p options and query args if any. - requestedspan = dbg "requestedspan" $ queryDateSpan date2_ q - -- If the requested span is open-ended, close it using the journal's end dates. - -- This can still be the null (open) span if the journal is empty. - requestedspan' = dbg "requestedspan'" $ requestedspan `spanDefaultsFrom` journalDateSpan date2_ j - -- The list of interval spans enclosing the requested span. - -- This list can be empty if the journal was empty, - -- or if hledger-ui has added its special date:-tomorrow to the query - -- and all txns are in the future. - intervalspans = dbg "intervalspans" $ splitSpan interval_ requestedspan' - -- The requested span enlarged to enclose a whole number of intervals. - -- This can be the null span if there were no intervals. - reportspan = dbg "reportspan" $ DateSpan (maybe Nothing spanStart $ headMay intervalspans) - (maybe Nothing spanEnd $ lastMay intervalspans) - -- The user's query with no depth limit, and expanded to the report span - -- if there is one (otherwise any date queries are left as-is, which - -- handles the hledger-ui+future txns case above). - reportq = dbg "reportq" $ makeReportQuery ropts reportspan q - - -- The matched accounts with a starting balance. All of these shold 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. startbals = dbg' "startbals" $ startingBalances ropts reportq j reportspan - -- 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. - startaccts = dbg'' "startaccts" $ HM.keys startbals -- Postings matching the query within the report period. ps :: [(Posting, Day)] = dbg'' "ps" $ getPostings ropts reportq j @@ -141,16 +118,7 @@ multiBalanceReportWith ropts@ReportOpts{..} q j priceoracle = report accumvalued = dbg'' "accumvalued" $ accumValueAmounts ropts j priceoracle startbals acctchanges -- All account names that will be displayed, possibly depth-clipped. - displayaccts :: [ClippedAccountName] = - dbg'' "displayaccts" $ - (if tree_ ropts then expandAccountNames else id) $ - nub $ map (clipOrEllipsifyAccountName depth) $ - if empty_ || balancetype_ == HistoricalBalance - then nubSort $ startaccts ++ allpostedaccts - else allpostedaccts - where - allpostedaccts :: [AccountName] = - dbg'' "allpostedaccts" . sort . accountNamesFromPostings $ map fst ps + displayaccts = dbg'' "displayaccts" $ displayedAccounts ropts q startbals ps -- All the rows of the report. rows = dbg'' "rows" $ buildReportRows ropts reportq accumvalued @@ -166,6 +134,39 @@ multiBalanceReportWith ropts@ReportOpts{..} q j priceoracle = report PeriodicReport colspans sortedrows totalsrow +-- | Calculate the span of the report to be generated. +calculateReportSpan :: ReportOpts -> Query -> Journal -> DateSpan +calculateReportSpan ropts q j = reportspan + where + -- The date span specified by -b/-e/-p options and query args if any. + requestedspan = dbg "requestedspan" $ queryDateSpan (date2_ ropts) q + -- If the requested span is open-ended, close it using the journal's end dates. + -- This can still be the null (open) span if the journal is empty. + requestedspan' = dbg "requestedspan'" $ + requestedspan `spanDefaultsFrom` journalDateSpan (date2_ ropts) j + -- The list of interval spans enclosing the requested span. + -- This list can be empty if the journal was empty, + -- or if hledger-ui has added its special date:-tomorrow to the query + -- and all txns are in the future. + intervalspans = dbg "intervalspans" $ splitSpan (interval_ ropts) requestedspan' + -- The requested span enlarged to enclose a whole number of intervals. + -- This can be the null span if there were no intervals. + reportspan = DateSpan (spanStart =<< headMay intervalspans) + (spanEnd =<< lastMay intervalspans) + +-- | Remove any date queries and insert queries from the report span. +-- The user's query expanded to the report span +-- if there is one (otherwise any date queries are left as-is, which +-- handles the hledger-ui+future txns case above). +makeReportQuery :: ReportOpts -> DateSpan -> Query -> Query +makeReportQuery ropts reportspan q + | reportspan == nulldatespan = q + | otherwise = And [dateless q, reportspandatesq] + where + reportspandatesq = dbg "reportspandatesq" $ dateqcons reportspan + dateless = dbg "dateless" . filterQuery (not . queryIsDateOrDate2) + dateqcons = if date2_ ropts then Date2 else Date + -- | Calculate starting balances, if needed for -H -- -- Balances at report start date, from all earlier postings which otherwise match the query. @@ -212,16 +213,6 @@ getPostings ropts q = PrimaryDate -> postingDate SecondaryDate -> postingDate2 --- | Remove any date queries and insert queries from the report span. -makeReportQuery :: ReportOpts -> DateSpan -> Query -> Query -makeReportQuery ropts reportspan q - | reportspan == nulldatespan = q - | otherwise = And [dateless q, reportspandatesq] - where - reportspandatesq = dbg "reportspandatesq" $ dateqcons reportspan - dateless = dbg "dateless" . filterQuery (not . queryIsDateOrDate2) - dateqcons = if date2_ ropts then Date2 else Date - -- | Calculate the DateSpans to be used for the columns of the report. calculateColSpans :: ReportOpts -> DateSpan -> [Day] -> [DateSpan] calculateColSpans ropts reportspan days = @@ -320,6 +311,22 @@ buildReportRows ropts q acctvalues = , empty_ ropts || queryDepth q == 0 || any (not . mixedAmountLooksZero) rowbals -- TODO: Remove this eventually, to be handled elswhere ] +-- | Calculate accounts which are to be displayed in the report +displayedAccounts :: ReportOpts -> Query + -> HashMap AccountName MixedAmount + -> [(Posting, Day)] + -> [AccountName] +displayedAccounts ropts q startbals ps = + (if tree_ ropts then expandAccountNames else id) $ + nub $ map (clipOrEllipsifyAccountName depth) $ + if empty_ ropts || balancetype_ ropts == HistoricalBalance + then nubSort $ (HM.keys startbals) ++ allpostedaccts + else allpostedaccts + where + allpostedaccts :: [AccountName] = + dbg'' "allpostedaccts" . sort . accountNamesFromPostings $ map fst ps + depth = queryDepth q + -- | Sort the rows by amount or by account declaration order. This is a bit tricky. -- TODO: is it always ok to sort report rows after report has been generated, as a separate step ? sortRows :: ReportOpts -> Journal -> [MultiBalanceReportRow] -> [MultiBalanceReportRow]