reg: support --value-at with -H (#329)

This commit is contained in:
Simon Michael 2019-05-05 17:47:38 -07:00
parent 4c56baf842
commit ad00da244b
3 changed files with 109 additions and 26 deletions

View File

@ -71,13 +71,26 @@ postingsReport ropts@ReportOpts{..} q j =
-- postings to be included in the report, and similarly-matched postings before the report start date
(precedingps, reportps) = matchedPostingsBeforeAndDuring ropts q j reportspan
-- We may be converting amounts to value, according to --value-at, as follows:
-- (keep synced with hledger_options.m4.md)
-- register -M --value-at
-- transaction: convert each summary posting to value at posting date ; convert -H starting balance to value at day before report start
-- period: convert each summary posting to value at period end ; convert -H starting balance to value at day before report start
-- date: convert each summary posting to value at date ; convert -H starting balance to value at date
-- register --value-at
-- transaction: convert each posting to value at posting date ; convert -H starting balance to value at day before report start
-- period: convert each posting to value at report end ; convert -H starting balance to value at day before report start
-- date: convert each posting to value at date ; convert -H starting balance to value at date
-- in all cases, the running total/average is calculated from the above numbers.
-- "Day before report start" is a bit arbitrary.
mvalueat = if value_ then Just value_at_ else Nothing
today = fromMaybe (error' "postingsReport: ReportOpts today_ is unset so could not satisfy --value-at=now") today_
-- Postings or summary pseudo postings to be displayed.
-- If --value-at is present, we'll need to convert them to value as of various dates.
displayps =
let
multiperiod = interval_ /= NoInterval
mvalueat = if value_ then Just value_at_ else Nothing
today = fromMaybe (error' "postingsReport: ReportOpts today_ is unset so could not satisfy --value-at=now") today_
in
if multiperiod then
let
@ -86,6 +99,7 @@ postingsReport ropts@ReportOpts{..} q j =
in case mvalueat of
Nothing -> [(p , periodend) | (p,periodend) <- summaryps]
Just AtTransaction -> [(postingValueAtDate j (postingDate p) p , periodend) | (p,periodend) <- summaryps]
-- ^ XXX shouldn't this value the individual ps at postingdate before summarising
Just AtPeriod -> [(postingValueAtDate j periodlastday p , periodend) | (p,periodend) <- summaryps
,let periodlastday = maybe
(error' "postingsReport: expected a subperiod end date") -- XXX shouldn't happen
@ -105,8 +119,10 @@ postingsReport ropts@ReportOpts{..} q j =
Just AtNow -> [(postingValueAtDate j today p , Nothing) | p <- reportps]
Just (AtDate d) -> [(postingValueAtDate j d p , Nothing) | p <- reportps]
-- For -H: postings preceding the report period, to calculate the initial running total/average.
-- posting report items ready for display
items = dbg1 "postingsReport items" $ postingsReportItems displayps (nullposting,Nothing) whichdate depth startbal runningcalc startnum
items = dbg1 "postingsReport items" $ postingsReportItems displayps (nullposting,Nothing) whichdate depth valuedstartbal runningcalc startnum
where
historical = balancetype_ == HistoricalBalance
precedingsum = sumPostings precedingps
@ -114,6 +130,25 @@ postingsReport ropts@ReportOpts{..} q j =
| otherwise = divideMixedAmount (fromIntegral $ length precedingps) precedingsum
startbal | average_ = if historical then precedingavg else 0
| otherwise = if historical then precedingsum else 0
-- For --value-at: convert the initial running total/average to value.
-- For --value-at=transaction, we don't bother valuing each
-- preceding posting at posting date - how useful would that
-- be ? Just value the initial sum/average at report start date.
valuedstartbal = case mvalueat of
Nothing -> startbal
Just AtTransaction -> mixedAmountValue prices daybeforereportstart startbal
Just AtPeriod -> mixedAmountValue prices daybeforereportstart startbal
Just AtNow -> mixedAmountValue prices today startbal
Just (AtDate d) -> mixedAmountValue prices d startbal
where
daybeforereportstart = maybe
(error' "postingsReport: expected a non-empty journal") -- XXX shouldn't happen
(addDays (-1))
$ reportPeriodOrJournalStart ropts j
-- prices are in parse order - sort into date then parse order,
-- & reversed for quick lookup of the latest price.
prices = reverse $ sortOn mpdate $ jmarketprices j
startnum = if historical then length precedingps + 1 else 1
runningcalc = registerRunningCalculationFn ropts

View File

@ -33,6 +33,8 @@ module Hledger.Reports.ReportOptions (
specifiedStartEndDates,
specifiedStartDate,
specifiedEndDate,
reportPeriodStart,
reportPeriodOrJournalStart,
reportPeriodLastDay,
reportPeriodOrJournalLastDay,
@ -431,6 +433,8 @@ queryOptsFromOpts d ReportOpts{..} = flagsqopts ++ argsqopts
flagsqopts = []
argsqopts = snd $ parseQuery d (T.pack query_)
-- Report dates.
-- | The effective report span is the start and end dates specified by
-- options or queries, or otherwise the earliest and latest transaction or
-- posting dates in the journal. If no dates are specified by options/queries
@ -470,10 +474,32 @@ specifiedStartDate ropts = fst <$> specifiedStartEndDates ropts
specifiedEndDate :: ReportOpts -> IO (Maybe Day)
specifiedEndDate ropts = snd <$> specifiedStartEndDates ropts
-- Get the last day of the overall report period.
-- Some pure alternatives to the above. XXX review/clean up
-- Get the report's start date.
-- If no report period is specified, will be Nothing.
-- Will also be Nothing if ReportOpts does not have today_ set,
-- since we need that to get the report period robustly.
-- since we need that to get the report period robustly
-- (unlike reportStartDate, which looks up the date with IO.)
reportPeriodStart :: ReportOpts -> Maybe Day
reportPeriodStart ropts@ReportOpts{..} = do
t <- today_
queryStartDate False $ queryFromOpts t ropts
-- Get the report's start date, or if no report period is specified,
-- the journal's start date (the earliest posting date). If there's no
-- report period and nothing in the journal, will be Nothing.
reportPeriodOrJournalStart :: ReportOpts -> Journal -> Maybe Day
reportPeriodOrJournalStart ropts@ReportOpts{..} j =
reportPeriodStart ropts <|> journalStartDate False j
-- Get the last day of the overall report period.
-- This the inclusive end date (one day before the
-- more commonly used, exclusive, report end date).
-- If no report period is specified, will be Nothing.
-- Will also be Nothing if ReportOpts does not have today_ set,
-- since we need that to get the report period robustly
-- (unlike reportEndDate, which looks up the date with IO.)
reportPeriodLastDay :: ReportOpts -> Maybe Day
reportPeriodLastDay ropts@ReportOpts{..} = do
t <- today_
@ -481,10 +507,10 @@ reportPeriodLastDay ropts@ReportOpts{..} = do
qend <- queryEndDate False q
return $ addDays (-1) qend
-- Get the last day of the overall report period,
-- or if no report period is specified, the last day of the journal
-- (ie the latest posting date).
-- If there's no report period and nothing in the journal, will be Nothing.
-- Get the last day of the overall report period, or if no report
-- period is specified, the last day of the journal (ie the latest
-- posting date). If there's no report period and nothing in the
-- journal, will be Nothing.
reportPeriodOrJournalLastDay :: ReportOpts -> Journal -> Maybe Day
reportPeriodOrJournalLastDay ropts@ReportOpts{..} j =
reportPeriodLastDay ropts <|> journalEndDate False j

View File

@ -231,33 +231,55 @@ $ hledger -f- reg -V
2000/02/01 (a) 4 B 8 B
2000/03/01 (a) 4 B 12 B
# register with -H (starting balance)
# 19. register with starting balance, valued at transaction.
# Shows the running total of the posting amount values (not the values of the running total).
# The starting balance is 1 A, valued at 2000/1/31 (day before report start), which is 5 B.
$ hledger -f- reg --value-at=transaction -b 200002 -H
2000/02/01 (a) 2 B 7 B
2000/03/01 (a) 3 B 10 B
# 20. register with starting balance, valued at period end.
# That is unspecified so the last posting date is used, ie 2000/3/1, so the price is 3 B.
# Starting balance is 5 B as above.
$ hledger -f- reg --value-at=period -b 200002 -H
2000/02/01 (a) 3 B 8 B
2000/03/01 (a) 3 B 11 B
# 21. register with starting balance, valued at specified date (when the price is 5 B).
# Starting balance is 5 B as above.
$ hledger -f- reg --value-at=2000-01-15 -b 200002 -H
2000/02/01 (a) 5 B 10 B
2000/03/01 (a) 5 B 15 B
# register, periodic
# 19. periodic register report valued at transaction
# 22. periodic register report valued at transaction
$ hledger -f- reg --value-at=transaction -M
2000/01 a 1 B 1 B
2000/02 a 2 B 3 B
2000/03 a 3 B 6 B
# 20. periodic register report valued at period end
# 23. periodic register report valued at period end
$ hledger -f- reg --value-at=period -M
2000/01 a 5 B 5 B
2000/02 a 2 B 7 B
2000/03 a 3 B 10 B
# 21. periodic register report valued at specified date
# 24. periodic register report valued at specified date
$ hledger -f- reg --value-at=2000-01-15 -M
2000/01 a 5 B 5 B
2000/02 a 5 B 10 B
2000/03 a 5 B 15 B
# 22. periodic register report valued today
# 25. periodic register report valued today
$ hledger -f- reg --value-at=now -M
2000/01 a 4 B 4 B
2000/02 a 4 B 8 B
2000/03 a 4 B 12 B
# 23. periodic register report valued at default date (same as above)
# 26. periodic register report valued at default date (same as above)
$ hledger -f- reg -V -M
2000/01 a 4 B 4 B
2000/02 a 4 B 8 B
@ -265,31 +287,31 @@ $ hledger -f- reg -V -M
# balance
# 24. single column balance report valued at transaction
# 27. single column balance report valued at transaction
$ hledger -f- bal --value-at=transaction
6 B a
--------------------
6 B
# 25. single column balance report valued at period end
# 28. single column balance report valued at period end
$ hledger -f- bal --value-at=period
9 B a
--------------------
9 B
# 26. single column balance report valued at specified date
# 29. single column balance report valued at specified date
$ hledger -f- bal --value-at=2000-01-15
15 B a
--------------------
15 B
# 27. single column balance report valued today
# 30. single column balance report valued today
$ hledger -f- bal --value-at=now
12 B a
--------------------
12 B
# 28. single column balance report valued at default date (same as above)
# 31. single column balance report valued at default date (same as above)
$ hledger -f- bal -V
12 B a
--------------------
@ -297,7 +319,7 @@ $ hledger -f- bal -V
# balance, periodic
# 29. multicolumn balance report valued at transaction
# 32. multicolumn balance report valued at transaction
$ hledger -f- bal -MTA --value-at=transaction
Balance changes in 2000q1:
@ -307,7 +329,7 @@ Balance changes in 2000q1:
---++---------------------------------
|| 1 B 2 B 3 B 6 B 2 B
# 30. multicolumn balance report valued at period end
# 33. multicolumn balance report valued at period end
$ hledger -f- bal -M --value-at=period
Balance changes in 2000q1:
@ -317,7 +339,7 @@ Balance changes in 2000q1:
---++---------------
|| 5 B 2 B 3 B
# 31. multicolumn balance report valued at period end with -T or -A
# 34. multicolumn balance report valued at period end with -T or -A
$ hledger -f- bal -M --value-at=period -TA
Balance changes in 2000q1:
@ -329,7 +351,7 @@ Balance changes in 2000q1:
# >2 /not yet supported/
# >=1
# 32. multicolumn balance report valued at other date
# 35. multicolumn balance report valued at other date
$ hledger -f- bal -MTA --value-at=2000-01-15
Balance changes in 2000q1:
@ -339,7 +361,7 @@ Balance changes in 2000q1:
---++---------------------------------
|| 5 B 5 B 5 B 15 B 5 B
# 33. multicolumn balance report valued today (with today >= 2000-04-01)
# 36. multicolumn balance report valued today (with today >= 2000-04-01)
$ hledger -f- bal -M --value-at=now
Balance changes in 2000q1:
@ -349,7 +371,7 @@ Balance changes in 2000q1:
---++---------------
|| 4 B 4 B 4 B
# 34. multicolumn balance report valued at default date (same as above)
# 37. multicolumn balance report valued at default date (same as above)
$ hledger -f- bal -M -V
Balance changes in 2000q1: