reg: support --value-at in register reports; cleanups, tests

This commit is contained in:
Simon Michael 2019-04-26 11:46:19 -07:00
parent 7306e61646
commit 696e3098c8
6 changed files with 164 additions and 63 deletions

View File

@ -44,15 +44,14 @@ entriesReport opts q j =
-- | Convert all the posting amounts in an EntriesReport to their
-- default valuation commodities. This means using the Journal's most
-- recent applicable market prices before the valuation date.
-- The valuation date is set with --value-date and can be:
-- a custom date;
-- the posting date;
-- the last day in the report period, or in the journal if no period
-- (or the posting date, if journal is empty - shouldn't happen);
-- or today's date (gives an error if today_ is not set in ReportOpts).
-- The valuation date is set with --value-at and can be:
-- each posting's date,
-- the last day in the report period (or in the journal if no period,
-- or the posting dates if journal is empty - shouldn't happen),
-- or today's date (gives an error if today_ is not set in ReportOpts),
-- or a specified date.
erValue :: ReportOpts -> Journal -> EntriesReport -> EntriesReport
erValue ropts@ReportOpts{..} j ts =
map txnvalue ts
erValue ropts@ReportOpts{..} j ts = map txnvalue ts
where
txnvalue t@Transaction{..} = t{tpostings=map postingvalue tpostings}
postingvalue p@Posting{..} = p{pamount=mixedAmountValue prices d pamount}
@ -78,7 +77,7 @@ erValue ropts@ReportOpts{..} j ts =
AtPeriod -> fromMaybe (postingDate p) mperiodorjournallastday
AtNow -> case today_ of
Just d -> d
Nothing -> error' "ReportOpts today_ is unset so could not satisfy --value-at=now"
Nothing -> error' "erValue: ReportOpts today_ is unset so could not satisfy --value-at=now"
AtDate d -> d
tests_EntriesReport = tests "EntriesReport" [

View File

@ -275,11 +275,11 @@ multiBalanceReportSpan (MultiBalanceReport (colspans, _, _)) = DateSpan (spanSta
-- | Convert all the posting amounts in a MultiBalanceReport to their
-- default valuation commodities. This means using the Journal's most
-- recent applicable market prices before the valuation date.
-- The valuation date is set with --value-date and can be:
-- the posting date,
-- the last day in the report subperiod,
-- today's date (gives an error if today_ is not set in ReportOpts),
-- or a custom date.
-- The valuation date is set with --value-at and can be:
-- each posting's date,
-- or the last day in the report subperiod,
-- or today's date (gives an error if today_ is not set in ReportOpts),
-- or a specified date.
mbrValue :: ReportOpts -> Journal -> MultiBalanceReport -> MultiBalanceReport
mbrValue ReportOpts{..} Journal{..} (MultiBalanceReport (spans, rows, (coltotals, rowtotaltotal, rowavgtotal))) =
MultiBalanceReport (
@ -299,11 +299,11 @@ mbrValue ReportOpts{..} Journal{..} (MultiBalanceReport (spans, rows, (coltotals
-- & reversed for quick lookup of the latest price.
prices = reverse $ sortOn mpdate jmarketprices
d = case value_at_ of
AtTransaction -> error' "sorry, --value-at=transaction is not yet supported with multicolumn balance reports" -- XXX
AtTransaction -> error' "sorry, --value-at=transaction is not yet supported with balance reports" -- XXX
AtPeriod -> periodend
AtNow -> case today_ of
Just d -> d
Nothing -> error' "ReportOpts today_ is unset so could not satisfy --value-at=now"
Nothing -> error' "mbrValue: ReportOpts today_ is unset so could not satisfy --value-at=now"
AtDate d -> d
-- | Generates a simple non-columnar BalanceReport, but using multiBalanceReport,

View File

@ -1,10 +1,16 @@
{-# LANGUAGE RecordWildCards, DeriveDataTypeable, FlexibleInstances, TupleSections, OverloadedStrings #-}
{-|
Postings report, used by the register command.
-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
module Hledger.Reports.PostingsReport (
PostingsReport,
PostingsReportItem,
@ -228,22 +234,44 @@ negatePostingAmount p = p { pamount = negate $ pamount p }
-- | Convert all the posting amounts in a PostingsReport to their
-- default valuation commodities. This means using the Journal's most
-- recent applicable market prices before the valuation date.
-- The valuation date is the specified report end date if any,
-- otherwise the current date, otherwise the journal's end date.
-- The valuation date is set with --value-at and can be:
-- each posting's date,
-- the last day in the report period (or in the journal if no period,
-- or the posting dates if journal is empty - shouldn't happen),
-- or today's date (gives an error if today_ is not set in ReportOpts),
-- or a specified date.
prValue :: ReportOpts -> Journal -> PostingsReport -> PostingsReport
prValue ropts j r =
let mvaluationdate = periodEnd (period_ ropts) <|> today_ ropts <|> journalEndDate False j
in case mvaluationdate of
Nothing -> r
Just d -> r'
prValue ropts@ReportOpts{..} j@Journal{..} (totallabel, items) = (totallabel, items')
where
items' = [ (md, md2, desc, p{pamount=val $ pamount p}, val tot)
| (md, md2, desc, p, tot) <- items
, let val = mixedAmountValue prices (valuationdate $ postingDate p)
]
valuationdate pdate =
case value_at_ of
AtTransaction | interval_ /= NoInterval -> error' "sorry, --value-at=transaction is not yet supported with periodic register reports" -- XXX
AtPeriod | interval_ /= NoInterval -> error' "sorry, --value-at=transaction is not yet supported with periodic register reports" -- XXX
AtTransaction -> pdate
AtPeriod -> fromMaybe pdate mperiodorjournallastday
AtNow -> case today_ of
Just d -> d
Nothing -> error' "prValue: ReportOpts today_ is unset so could not satisfy --value-at=now"
AtDate d -> d
where
-- 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
(label,items) = r
r' = (label, [(md,md2,desc,valueposting p, mixedAmountValue prices d amt) | (md,md2,desc,p,amt) <- items])
valueposting p@Posting{..} = p{pamount=mixedAmountValue prices d pamount}
mperiodorjournallastday = mperiodlastday <|> journalEndDate False j
-- Get the last day of the report period.
-- Will be Nothing if no report period is specified, or also
-- if ReportOpts does not have today_ set, since we need that
-- to get the report period robustly.
mperiodlastday :: Maybe Day = do
t <- today_
let q = queryFromOpts t ropts
qend <- queryEndDate False q
return $ addDays (-1) qend
-- prices are in parse order - sort into date then parse order,
-- & reversed for quick lookup of the latest price.
prices = reverse $ sortOn mpdate jmarketprices
-- tests

View File

@ -94,6 +94,7 @@ data ReportOpts = ReportOpts {
today_ :: Maybe Day -- ^ The current date. A late addition to ReportOpts.
-- Optional, but when set it may affect some reports:
-- Reports use it when picking a -V valuation date.
-- This is not great, adds indeterminacy.
,period_ :: Period
,interval_ :: Interval
,statuses_ :: [Status] -- ^ Zero, one, or two statuses to be matched

View File

@ -502,10 +502,12 @@ The precise effect of the keywords is command-specific, but here is their genera
- `--value-at=transaction` (or `t`)
: Use the prices as of each transaction date (more precisely, each [posting date](/journal.html#posting-dates)).
: (Currently not supported with: balance commands, periodic register reports.)
- `--value-at=period` (or `p`)
: Use the prices as of the last day of the report period (or each subperiod).
: When no report period is specified, this will be the journal's last transaction date.
: (Currently not supported with: periodic register reports.)
- `--value-at=now` (or `n`)
: Use the prices as of today's date when the report is generated. This is the default.
@ -514,11 +516,6 @@ The precise effect of the keywords is command-specific, but here is their genera
: Use the prices as of the given date (8 digits with `-` or `/` or `.` separators).
: Eg `--value-at=2019-04-25`.
Currently `--value-at` affects only some commands
([print](/hledger.html#print),
[multicolumn balance reports](/hledger.html#balance)),
and some of the keywords may not be supported by certain commands.
Here are some examples to show its effect:
```journal

View File

@ -28,8 +28,24 @@ $ hledger -f- bal -N -V
$135.00 expenses:foreign
# 3. Market prices in the future (later than today's date) are always ignored. #453, #683
# XXX not working right now
# 3. The location of price directives does not matter.
# If multiple directives have the same date, the last parsed is used.
<
3000/01/01
(a) $100
P 2000/1/1 $ €1.35
3000/03/03
(b) $100
P 2000/1/1 $ €1.30
$ hledger -f- bal -N -V a
€130.00 a
# 4. Market prices in the future (later than today's date) are ignored by default. #453, #683
<
P 2000/1/1 $ €1.20
P 3000/1/1 $ €1.30
@ -41,37 +57,16 @@ $ hledger -f- bal -N -V
€120.00 a
# 4. The market prices in effect at the report end date are used.
# The location of price directives does not matter.
# If multiple directives have the same date, the last parsed is used.
<
P 3000/3/1 $ €1.40
3000/01/01
(a) $100
3000/03/03
(b) $100
P 2000/1/1 $ €1.20
P 3000/1/1 $ €1.35
P 3000/1/1 $ €1.30
$ hledger -f- bal -N -V a -e 3000/2
€130.00 a
# 5. Again, this time there are prices later than the journal data and
# an explicit report end date brings them into play.
# 5. Market prices in the future are still ignored by default even
# with an explicit future report end date, unlike hledger 1.14-.
<
P 3000/1/1 $ €1.10
P 3000/2/1 $ €1.30
3000/01/01
(a) $100
$ hledger -f- bal -N -V a -e 3000/2
€130.00 a
$ hledger -f- bal -N -V -e 3000/2
$100 a
# 6. Market prices interact with D directives and with amount style canonicalisation. #131
@ -210,7 +205,7 @@ Balance changes in 2000q1:
# 15. multicolumn balance report valued at transaction is not supported
$ hledger -f- bal -M --value-at=transaction
>2 /--value-at=transaction is not yet supported with multicolumn balance reports/
>2 /not yet supported with balance reports/
>=1
# 16. multicolumn balance report valued at period end
@ -243,3 +238,84 @@ Balance changes in 2000q1:
---++---------------
|| 1 B 1 B 1 B
# 19. single column balance report with default value
$ hledger -f- bal -V
12 B a
--------------------
12 B
# 20. single column balance report valued at transaction is not supported
$ hledger -f- bal --value-at=transaction
>2 /not yet supported with balance reports/
>=1
# 21. single column balance report valued at period end
$ hledger -f- bal --value-at=period
9 B a
--------------------
9 B
# 22. single column balance report valued at today
$ hledger -f- bal --value-at=now
12 B a
--------------------
12 B
# 23. single column balance report valued at other date
$ hledger -f- bal --value-at=2000-01-15
3 B a
--------------------
3 B
# 24. register report with default value
$ hledger -f- reg -V
2000/01/01 (a) 4 B 4 B
2000/02/01 (a) 4 B 8 B
2000/03/01 (a) 4 B 12 B
# 25. register report valued at transaction
$ hledger -f- reg --value-at=transaction
2000/01/01 (a) 1 B 1 B
2000/02/01 (a) 2 B 4 B
2000/03/01 (a) 3 B 9 B
# 26. register report valued at period end
$ hledger -f- reg --value-at=period
2000/01/01 (a) 3 B 3 B
2000/02/01 (a) 3 B 6 B
2000/03/01 (a) 3 B 9 B
# 27. register report valued at today
$ hledger -f- reg --value-at=now
2000/01/01 (a) 4 B 4 B
2000/02/01 (a) 4 B 8 B
2000/03/01 (a) 4 B 12 B
# 28. register report valued at other date
$ hledger -f- reg --value-at=2000-01-15
2000/01/01 (a) 1 B 1 B
2000/02/01 (a) 1 B 2 B
2000/03/01 (a) 1 B 3 B
# 29. periodic register report with default value
$ hledger -f- reg -V -Q
2000q1 a 12 B 12 B
# 30. periodic register report valued at transaction
$ hledger -f- reg --value-at=transaction -Q
>2 /not yet supported with periodic register reports/
>=1
# 31. periodic register report valued at period end
$ hledger -f- reg --value-at=period -Q
>2 /not yet supported with periodic register reports/
>=1
# 32. periodic register report valued at today
$ hledger -f- reg --value-at=now -Q
2000q1 a 12 B 12 B
# 33. periodic register report valued at other date
$ hledger -f- reg --value-at=2000-01-15 -Q
2000q1 a 3 B 3 B