imp:end value reports: future P directives don't influence report end/valuation date [#2445]
In end-value reports with unspecified end date, a market price later than the latest transaction can extend the default report end date and valuation date. Now, only market prices on or before "today" can do this; market price declarations dated in the future will be ignored. Report span and valuation date calculations have been clarified.
This commit is contained in:
parent
4e52c7bd76
commit
c930fd0952
@ -665,11 +665,17 @@ journalApplyValuationFromOptsWith rspec@ReportSpec{_rsReportOpts=ropts} j priceo
|
||||
CalcGain -> id
|
||||
_ -> journalToCost costop where costop = fromMaybe NoConversionOp $ conversionop_ ropts
|
||||
|
||||
-- Find the end of the period containing this posting
|
||||
-- Find the "end" valuation date for this posting.
|
||||
-- With a report interval, this is the last day of the report subperiod containing this posting;
|
||||
-- with no interval it's the last date of the overall report period
|
||||
-- (which for an end value report may have been extended to include the latest non-future P directive).
|
||||
-- To get the period's last day, we subtract one from the (exclusive) period end date.
|
||||
postingperiodend = addDays (-1) . fromMaybe err . mPeriodEnd . postingDateOrDate2 (whichDate ropts)
|
||||
mPeriodEnd = case interval_ ropts of
|
||||
NoInterval -> const . spanEnd . fst $ reportSpan j rspec
|
||||
_ -> spanEnd <=< latestSpanContaining (historical : spans)
|
||||
where
|
||||
mPeriodEnd = case interval_ ropts of
|
||||
NoInterval -> const . spanEnd . fst $ reportSpan j rspec
|
||||
_ -> spanEnd <=< latestSpanContaining (historical : spans)
|
||||
|
||||
historical = DateSpan Nothing $ (fmap Exact . spanStart) =<< headMay spans
|
||||
spans = snd $ reportSpanBothDates j rspec
|
||||
styles = journalCommodityStyles j
|
||||
@ -766,48 +772,59 @@ sortKeysDescription = "date, desc, account, amount, absamount" -- 'description'
|
||||
|
||||
-- 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
|
||||
-- and the journal is empty, returns the null date span.
|
||||
-- Also return the intervals if they are requested.
|
||||
-- | The effective report span is the start and end dates requested by options or queries.
|
||||
-- If the start date is unspecified, the earliest transaction or posting date is used.
|
||||
-- If the end date is unspecified, the latest transaction or posting date
|
||||
-- (or non-future market price date, when doing an end value report) is used.
|
||||
-- If none of these things are present, the null date span is returned.
|
||||
-- The report sub-periods caused by a report interval, if any, are also returned.
|
||||
reportSpan :: Journal -> ReportSpec -> (DateSpan, [DateSpan])
|
||||
reportSpan = reportSpanHelper False
|
||||
-- Note: In end value reports, the report end date and valuation date are the same.
|
||||
-- If valuation date ever needs to be different, journalApplyValuationFromOptsWith is the place.
|
||||
|
||||
-- | Like reportSpan, but uses both primary and secondary dates when calculating
|
||||
-- the span.
|
||||
-- | Like reportSpan, but considers both primary and secondary dates, not just one or the other.
|
||||
reportSpanBothDates :: Journal -> ReportSpec -> (DateSpan, [DateSpan])
|
||||
reportSpanBothDates = reportSpanHelper True
|
||||
|
||||
-- | A helper for reportSpan, which takes a Bool indicating whether to use both
|
||||
-- primary and secondary dates.
|
||||
reportSpanHelper :: Bool -> Journal -> ReportSpec -> (DateSpan, [DateSpan])
|
||||
reportSpanHelper bothdates j ReportSpec{_rsQuery=query, _rsReportOpts=ropts} =
|
||||
(reportspan, if not (null intervalspans) then intervalspans else [reportspan])
|
||||
reportSpanHelper bothdates j ReportSpec{_rsQuery=query, _rsReportOpts=ropts, _rsDay=today} =
|
||||
(enlargedreportspan, if not (null intervalspans) then intervalspans else [enlargedreportspan])
|
||||
where
|
||||
-- The date span specified by -b/-e/-p options and query args if any.
|
||||
requestedspan = dbg3 "requestedspan" $ if bothdates then queryDateSpan' query else queryDateSpan (date2_ ropts) query
|
||||
-- If we are requesting period-end valuation, the journal date span should
|
||||
-- include price directives after the last transaction
|
||||
journalspan = dbg3 "journalspan" $ if bothdates then journalDateSpanBothDates j else journalDateSpan (date2_ ropts) j
|
||||
pricespan = dbg3 "pricespan" . DateSpan Nothing $ case value_ ropts of
|
||||
Just (AtEnd _) -> fmap (Exact . addDays 1) . maximumMay . map pddate $ jpricedirectives j
|
||||
_ -> Nothing
|
||||
-- If the requested span has open ends, fill those with the journal's start and/or end dates, if possible.
|
||||
requestedspan' = dbg3 "requestedspan'" $ requestedspan `spanValidDefaultsFrom` (journalspan `spanExtend` pricespan)
|
||||
requestedspan = dbg3 "requestedspan" $
|
||||
if bothdates then queryDateSpan' query else queryDateSpan (date2_ ropts) query
|
||||
|
||||
-- If the requested span has open ends, fill them with defaults.
|
||||
reportspan = dbg3 "reportspan" $ requestedspan `spanValidDefaultsFrom` txnsorpricespan
|
||||
where
|
||||
txnsorpricespan = dbg3 "txnsorpricespan" $ DateSpan mfirsttxn mlatesttxnorprice
|
||||
where
|
||||
DateSpan mfirsttxn mlasttxn = dbg3 "txnsspan" $
|
||||
if bothdates then journalDateSpanBothDates j else journalDateSpan (date2_ ropts) j
|
||||
mlatesttxnorprice =
|
||||
case value_ ropts of
|
||||
Just (AtEnd _) -> mlasttxn `max` mlatestnonfutureprice
|
||||
_ -> mlasttxn
|
||||
where
|
||||
mlatestnonfutureprice = dbg3 "latestnonfutureprice" $ -- #2445
|
||||
fmap (Exact . addDays 1) . maximumMay . filter (not . (> today)) . map pddate $ jpricedirectives 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 = dbg3 "intervalspans" $ splitSpan adjust (interval_ ropts) requestedspan'
|
||||
intervalspans = dbg3 "intervalspans" $ splitSpan adjust (interval_ ropts) reportspan
|
||||
where
|
||||
-- When calculating report periods, we will adjust the start date back to the nearest interval boundary
|
||||
-- unless a start date was specified explicitly.
|
||||
adjust = isNothing $ spanStart requestedspan
|
||||
|
||||
-- The requested span enlarged to enclose a whole number of intervals.
|
||||
-- This can be the null span if there were no intervals.
|
||||
reportspan = dbg3 "reportspan" $ DateSpan (fmap Exact . spanStart =<< headMay intervalspans)
|
||||
(fmap Exact . spanEnd =<< lastMay intervalspans)
|
||||
enlargedreportspan = dbg3 "enlargedreportspan" $
|
||||
DateSpan (fmap Exact . spanStart =<< headMay intervalspans)
|
||||
(fmap Exact . spanEnd =<< lastMay intervalspans)
|
||||
|
||||
reportStartDate :: Journal -> ReportSpec -> Maybe Day
|
||||
reportStartDate j = spanStart . fst . reportSpan j
|
||||
|
||||
@ -6154,8 +6154,8 @@ hledger will use the prices on a particular valuation date (or on more than one
|
||||
By default hledger uses "end" dates for valuation. More specifically:
|
||||
|
||||
- For single period reports (including normal print and register reports):
|
||||
- If an explicit [report end date](#report-start-end-date) is specified, that is used
|
||||
- Otherwise the latest transaction date or P directive date is used (even if it's in the future)
|
||||
- If an explicit [report end date](#report-start-end-date) is specified, that is used.
|
||||
- Otherwise the latest transaction date or non-future P directive date is used.
|
||||
|
||||
- For [multiperiod reports](#report-intervals), each period is valued on its last day.
|
||||
|
||||
|
||||
@ -126,6 +126,7 @@ P 2000/01/15 A 5 B
|
||||
P 2000/02/01 A 2 B
|
||||
P 2000/03/01 A 3 B
|
||||
P 2000/04/01 A 4 B
|
||||
P 3000/01/01 A 9 B
|
||||
|
||||
2000/01/01
|
||||
(a) 1 A @ 6 B
|
||||
@ -215,6 +216,20 @@ $ hledger -f- print --value=now
|
||||
|
||||
>=0
|
||||
|
||||
# ** 15. print value using prices on default end date, which is the later of
|
||||
# txn dates and market price dates, excluding future market prices in the future.
|
||||
$ hledger -f- print -V --today=2025-09-01
|
||||
2000-01-01
|
||||
(a) 4 B
|
||||
|
||||
2000-02-01
|
||||
(a) 4 B
|
||||
|
||||
2000-03-01
|
||||
(a) 4 B
|
||||
|
||||
>=0
|
||||
|
||||
# ** register
|
||||
|
||||
# ** 15. register report valued at cost.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user