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