imp: bal: budget goals now respect -H (#1879)
This commit is contained in:
parent
3e60e784f3
commit
42bcbad2fd
@ -76,7 +76,7 @@ module Hledger.Data.Dates (
|
|||||||
daysInSpan,
|
daysInSpan,
|
||||||
|
|
||||||
tests_Dates
|
tests_Dates
|
||||||
)
|
, intervalStartBefore)
|
||||||
where
|
where
|
||||||
|
|
||||||
import qualified Control.Monad.Fail as Fail (MonadFail, fail)
|
import qualified Control.Monad.Fail as Fail (MonadFail, fail)
|
||||||
@ -548,6 +548,13 @@ prevyear = startofyear . addGregorianYearsClip (-1)
|
|||||||
nextyear = startofyear . addGregorianYearsClip 1
|
nextyear = startofyear . addGregorianYearsClip 1
|
||||||
startofyear day = fromGregorian y 1 1 where (y,_,_) = toGregorian day
|
startofyear day = fromGregorian y 1 1 where (y,_,_) = toGregorian day
|
||||||
|
|
||||||
|
-- Get the natural start for the given interval that falls on or before the given day.
|
||||||
|
intervalStartBefore :: Interval -> Day -> Day
|
||||||
|
intervalStartBefore int d =
|
||||||
|
case splitSpan int (DateSpan (Just d) (Just $ addDays 1 d)) of
|
||||||
|
(DateSpan (Just start) _:_) -> start
|
||||||
|
_ -> d
|
||||||
|
|
||||||
-- | For given date d find year-long interval that starts on given
|
-- | For given date d find year-long interval that starts on given
|
||||||
-- MM/DD of year and covers it.
|
-- MM/DD of year and covers it.
|
||||||
-- The given MM and DD should be basically valid (1-12 & 1-31),
|
-- The given MM and DD should be basically valid (1-12 & 1-31),
|
||||||
|
|||||||
@ -73,7 +73,9 @@ instance Show PeriodicTransaction where
|
|||||||
|
|
||||||
--nullperiodictransaction is defined in Types.hs
|
--nullperiodictransaction is defined in Types.hs
|
||||||
|
|
||||||
-- | Generate transactions from 'PeriodicTransaction' within a 'DateSpan'
|
-- | Generate transactions from 'PeriodicTransaction' within a 'DateSpan'.
|
||||||
|
-- This should be a closed span with both start and end dates specified;
|
||||||
|
-- an open ended span will generate no transactions.
|
||||||
--
|
--
|
||||||
-- Note that new transactions require 'txnTieKnot' post-processing.
|
-- Note that new transactions require 'txnTieKnot' post-processing.
|
||||||
-- The new transactions will have three tags added:
|
-- The new transactions will have three tags added:
|
||||||
|
|||||||
@ -28,7 +28,7 @@ import Data.HashMap.Strict (HashMap)
|
|||||||
import qualified Data.HashMap.Strict as HM
|
import qualified Data.HashMap.Strict as HM
|
||||||
import Data.List (find, partition, transpose, foldl')
|
import Data.List (find, partition, transpose, foldl')
|
||||||
import Data.List.Extra (nubSort)
|
import Data.List.Extra (nubSort)
|
||||||
import Data.Maybe (fromMaybe, catMaybes)
|
import Data.Maybe (fromMaybe, catMaybes, isJust)
|
||||||
import Data.Map (Map)
|
import Data.Map (Map)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
@ -36,6 +36,7 @@ import Data.Text (Text)
|
|||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Lazy as TL
|
import qualified Data.Text.Lazy as TL
|
||||||
import qualified Data.Text.Lazy.Builder as TB
|
import qualified Data.Text.Lazy.Builder as TB
|
||||||
|
import Safe (maximumDef, minimumDef)
|
||||||
--import System.Console.CmdArgs.Explicit as C
|
--import System.Console.CmdArgs.Explicit as C
|
||||||
--import Lucid as L
|
--import Lucid as L
|
||||||
import qualified Text.Tabular.AsciiWide as Tab
|
import qualified Text.Tabular.AsciiWide as Tab
|
||||||
@ -96,27 +97,47 @@ budgetReport rspec bopts reportspan j = dbg4 "sortedbudgetreport" budgetreport
|
|||||||
| otherwise = budgetgoalreport
|
| otherwise = budgetgoalreport
|
||||||
budgetreport = combineBudgetAndActual ropts j budgetgoalreport' actualreport
|
budgetreport = combineBudgetAndActual ropts j budgetgoalreport' actualreport
|
||||||
|
|
||||||
-- | Use all periodic transactions in the journal to generate
|
-- | Use all (or all matched by --budget's argument) periodic transactions in the journal
|
||||||
-- budget goal transactions in the specified date span.
|
-- to generate budget goal transactions in the specified date span (and before, to support
|
||||||
-- Budget goal transactions are similar to forecast transactions except
|
-- --historical. The precise start date is the natural start date of the largest interval
|
||||||
-- their purpose and effect is to define balance change goals, per account and period,
|
-- of the active periodic transaction rules that is on or before the earlier of journal start date,
|
||||||
-- for BudgetReport.
|
-- report start date.)
|
||||||
|
-- Budget goal transactions are similar to forecast transactions except their purpose
|
||||||
|
-- and effect is to define balance change goals, per account and period, for BudgetReport.
|
||||||
|
--
|
||||||
journalAddBudgetGoalTransactions :: BalancingOpts -> ReportOpts -> DateSpan -> Journal -> Journal
|
journalAddBudgetGoalTransactions :: BalancingOpts -> ReportOpts -> DateSpan -> Journal -> Journal
|
||||||
journalAddBudgetGoalTransactions bopts ropts reportspan j =
|
journalAddBudgetGoalTransactions bopts ropts reportspan j =
|
||||||
either error' id $ journalBalanceTransactions bopts j{ jtxns = budgetts } -- PARTIAL:
|
either error' id $ journalBalanceTransactions bopts j{ jtxns = budgetts } -- PARTIAL:
|
||||||
where
|
where
|
||||||
budgetspan = dbg3 "budget span" $ reportspan
|
budgetspan = dbg3 "budget span" $ DateSpan mbudgetgoalsstartdate (spanEnd reportspan)
|
||||||
pat = fromMaybe "" $ dbg3 "budget pattern" $ T.toLower <$> budgetpat_ ropts
|
where
|
||||||
|
mbudgetgoalsstartdate =
|
||||||
|
-- We want to also generate budget goal txns before the report start date, in case -H is used.
|
||||||
|
-- What should the actual starting date for goal txns be ? This gets a little tricky: consider a
|
||||||
|
-- journal with a "~ monthly" periodic transaction rule, where the first transaction is on 1/5.
|
||||||
|
-- Users will certainly expect a budget goal for january, but "~ monthly" generates transactions
|
||||||
|
-- on the first of month, and starting from 1/5 would exclude 1/1.
|
||||||
|
-- Hopefully the following procedure will produce intuitive behaviour in general:
|
||||||
|
-- from the earlier of the journal start date and the report start date,
|
||||||
|
-- move backward to the nearest natural start date of the largest period seen among the
|
||||||
|
-- active periodic transactions (so here: monthly, 1/5 -> 1/1).
|
||||||
|
case minimumDef Nothing $ filter isJust [journalStartDate False j, spanStart reportspan] of
|
||||||
|
Nothing -> Nothing
|
||||||
|
Just d -> Just $ intervalStartBefore biggestinterval d
|
||||||
|
where
|
||||||
|
biggestinterval = maximumDef (Days 1) $ map ptinterval budgetpts
|
||||||
|
|
||||||
-- select periodic transactions matching a pattern
|
-- select periodic transactions matching a pattern
|
||||||
-- (the argument of the (final) --budget option).
|
-- (the argument of the (final) --budget option).
|
||||||
-- XXX two limitations/wishes, requiring more extensive type changes:
|
-- XXX two limitations/wishes, requiring more extensive type changes:
|
||||||
-- - give an error if pat is non-null and matches no periodic txns
|
-- - give an error if pat is non-null and matches no periodic txns
|
||||||
-- - allow a regexp or a full hledger query, not just a substring
|
-- - allow a regexp or a full hledger query, not just a substring
|
||||||
|
pat = fromMaybe "" $ dbg3 "budget pattern" $ T.toLower <$> budgetpat_ ropts
|
||||||
|
budgetpts = [pt | pt <- jperiodictxns j, pat `T.isInfixOf` T.toLower (ptdescription pt)]
|
||||||
budgetts =
|
budgetts =
|
||||||
dbg5 "budget goal txns" $
|
dbg5 "budget goal txns" $
|
||||||
[makeBudgetTxn t
|
[makeBudgetTxn t
|
||||||
| pt <- jperiodictxns j
|
| pt <- budgetpts
|
||||||
, pat `T.isInfixOf` T.toLower (ptdescription pt)
|
|
||||||
, t <- runPeriodicTransaction pt budgetspan
|
, t <- runPeriodicTransaction pt budgetspan
|
||||||
]
|
]
|
||||||
makeBudgetTxn t = txnTieKnot $ t { tdescription = T.pack "Budget transaction" }
|
makeBudgetTxn t = txnTieKnot $ t { tdescription = T.pack "Budget transaction" }
|
||||||
|
|||||||
@ -635,3 +635,33 @@ $ hledger -f- bal --budget=weekly -p 2021-01
|
|||||||
$ hledger -f- bal --budget=monthly -p 2021-01
|
$ hledger -f- bal --budget=monthly -p 2021-01
|
||||||
> !/aaa/
|
> !/aaa/
|
||||||
>=
|
>=
|
||||||
|
|
||||||
|
# 33. Cumulative budget report.
|
||||||
|
<
|
||||||
|
~ monthly
|
||||||
|
(a) 10
|
||||||
|
|
||||||
|
2022-01-05
|
||||||
|
(a) 10
|
||||||
|
|
||||||
|
2022-02-03
|
||||||
|
(a) 5
|
||||||
|
|
||||||
|
$ hledger -f- bal --budget -M --cumulative
|
||||||
|
Budget performance in 2022-01-01..2022-02-28:
|
||||||
|
|
||||||
|
|| 2022-01-31 2022-02-28
|
||||||
|
===++=================================
|
||||||
|
a || 10 [100% of 10] 15 [75% of 20]
|
||||||
|
---++---------------------------------
|
||||||
|
|| 10 [100% of 10] 15 [75% of 20]
|
||||||
|
|
||||||
|
# 34. Historical budget report.
|
||||||
|
$ hledger -f- bal --budget -M --historical -b 2022-02-01
|
||||||
|
Budget performance in 2022-02:
|
||||||
|
|
||||||
|
|| 2022-02-28
|
||||||
|
===++================
|
||||||
|
a || 15 [75% of 20]
|
||||||
|
---++----------------
|
||||||
|
|| 15 [75% of 20]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user