Merge pull request #914 from simonmichael/rule-tags
tags for matching rule-generated txns and postings
This commit is contained in:
		
							parent
							
								
									a5cae2a859
								
							
						
					
					
						commit
						35799142dd
					
				| @ -21,7 +21,7 @@ import Text.Printf | |||||||
| import Hledger.Data.Types | import Hledger.Data.Types | ||||||
| import Hledger.Data.Dates | import Hledger.Data.Dates | ||||||
| import Hledger.Data.Amount | import Hledger.Data.Amount | ||||||
| import Hledger.Data.Posting (post) | import Hledger.Data.Posting (post, commentAddTagNextLine) | ||||||
| import Hledger.Data.Transaction | import Hledger.Data.Transaction | ||||||
| import Hledger.Utils.UTF8IOCompat (error') | import Hledger.Utils.UTF8IOCompat (error') | ||||||
| -- import Hledger.Utils.Debug | -- import Hledger.Utils.Debug | ||||||
| @ -69,6 +69,10 @@ instance Show PeriodicTransaction where | |||||||
| -- | Generate transactions from 'PeriodicTransaction' within a 'DateSpan' | -- | Generate transactions from 'PeriodicTransaction' within a 'DateSpan' | ||||||
| -- | -- | ||||||
| -- Note that new transactions require 'txnTieKnot' post-processing. | -- Note that new transactions require 'txnTieKnot' post-processing. | ||||||
|  | -- The new transactions will have three tags added:  | ||||||
|  | -- - a recur:PERIODICEXPR tag whose value is the generating periodic expression | ||||||
|  | -- - a generated-transaction: tag | ||||||
|  | -- - a hidden _generated-transaction: tag which does not appear in the comment.  | ||||||
| -- | -- | ||||||
| -- >>> _ptgen "monthly from 2017/1 to 2017/4" | -- >>> _ptgen "monthly from 2017/1 to 2017/4" | ||||||
| -- 2017/01/01 | -- 2017/01/01 | ||||||
| @ -204,10 +208,14 @@ runPeriodicTransaction PeriodicTransaction{..} requestedspan = | |||||||
|            tstatus      = ptstatus |            tstatus      = ptstatus | ||||||
|           ,tcode        = ptcode |           ,tcode        = ptcode | ||||||
|           ,tdescription = ptdescription |           ,tdescription = ptdescription | ||||||
|           ,tcomment     = (if T.null ptcomment then "\n" else ptcomment) <> "recur: " <> ptperiodexpr |           ,tcomment     = ptcomment | ||||||
|           ,ttags        = ("recur", ptperiodexpr) : pttags |                           `commentAddTagNextLine` ("generated-transaction",period) | ||||||
|  |           ,ttags        = ("_generated-transaction",period) : | ||||||
|  |                           ("generated-transaction" ,period) : | ||||||
|  |                           pttags | ||||||
|           ,tpostings    = ptpostings |           ,tpostings    = ptpostings | ||||||
|           } |           } | ||||||
|  |     period = "~ " <> ptperiodexpr | ||||||
| 
 | 
 | ||||||
| -- | Check that this date span begins at a boundary of this interval, | -- | Check that this date span begins at a boundary of this interval, | ||||||
| -- or return an explanatory error message including the provided period expression | -- or return an explanatory error message including the provided period expression | ||||||
|  | |||||||
| @ -54,6 +54,10 @@ module Hledger.Data.Posting ( | |||||||
|   concatAccountNames, |   concatAccountNames, | ||||||
|   accountNameApplyAliases, |   accountNameApplyAliases, | ||||||
|   accountNameApplyAliasesMemo, |   accountNameApplyAliasesMemo, | ||||||
|  |   -- * comment/tag operations | ||||||
|  |   commentJoin, | ||||||
|  |   commentAddTag, | ||||||
|  |   commentAddTagNextLine, | ||||||
|   -- * arithmetic |   -- * arithmetic | ||||||
|   sumPostings, |   sumPostings, | ||||||
|   -- * rendering |   -- * rendering | ||||||
| @ -356,6 +360,29 @@ postingValueAtDate prices styles mc d p = postingTransformAmount (mixedAmountVal | |||||||
| postingTransformAmount :: (MixedAmount -> MixedAmount) -> Posting -> Posting | postingTransformAmount :: (MixedAmount -> MixedAmount) -> Posting -> Posting | ||||||
| postingTransformAmount f p@Posting{pamount=a} = p{pamount=f a} | postingTransformAmount f p@Posting{pamount=a} = p{pamount=f a} | ||||||
| 
 | 
 | ||||||
|  | -- | Join two parts of a comment, eg a tag and another tag, or a tag | ||||||
|  | -- and a non-tag, on a single line. Interpolates a comma and space | ||||||
|  | -- unless one of the parts is empty. | ||||||
|  | commentJoin :: Text -> Text -> Text | ||||||
|  | commentJoin c1 c2 | ||||||
|  |   | T.null c1 = c2 | ||||||
|  |   | T.null c2 = c1 | ||||||
|  |   | otherwise = c1 <> ", " <> c2 | ||||||
|  | 
 | ||||||
|  | -- | Add a tag to a comment, comma-separated from any prior content. | ||||||
|  | commentAddTag :: Text -> Tag -> Text | ||||||
|  | commentAddTag c (t,v) | ||||||
|  |   | T.null c' = tag | ||||||
|  |   | otherwise = c' `commentJoin` tag | ||||||
|  |   where | ||||||
|  |     c'  = textchomp c | ||||||
|  |     tag = t <> ":" <> v | ||||||
|  | 
 | ||||||
|  | -- | Add a tag on its own line to a comment, preserving any prior content. | ||||||
|  | commentAddTagNextLine :: Text -> Tag -> Text | ||||||
|  | commentAddTagNextLine cmt (t,v) = | ||||||
|  |   cmt <> if "\n" `T.isSuffixOf` cmt then "" else "\n" <> t <> ":" <> v  | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| -- tests | -- tests | ||||||
| 
 | 
 | ||||||
| @ -387,5 +414,14 @@ tests_Posting = tests "Posting" [ | |||||||
|     ,concatAccountNames ["a","(b)","[c:d]"] `is` "(a:b:c:d)" |     ,concatAccountNames ["a","(b)","[c:d]"] `is` "(a:b:c:d)" | ||||||
|   ] |   ] | ||||||
| 
 | 
 | ||||||
|  |  ,tests "commentAddTag" [ | ||||||
|  |     commentAddTag "" ("a","") `is` "a:" | ||||||
|  |    ,commentAddTag "[1/2]" ("a","") `is` "[1/2], a:" | ||||||
|  |   ] | ||||||
|  | 
 | ||||||
|  |  ,tests "commentAddTagNextLine" [ | ||||||
|  |     commentAddTagNextLine "" ("a","") `is` "\na:" | ||||||
|  |    ,commentAddTagNextLine "[1/2]" ("a","") `is` "[1/2]\na:" | ||||||
|  |   ] | ||||||
|  ] |  ] | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ module Hledger.Data.TransactionModifier ( | |||||||
| ) | ) | ||||||
| where | where | ||||||
| 
 | 
 | ||||||
|  | import Control.Applicative ((<|>)) | ||||||
| import Data.Maybe | import Data.Maybe | ||||||
| #if !(MIN_VERSION_base(4,11,0)) | #if !(MIN_VERSION_base(4,11,0)) | ||||||
| import Data.Monoid ((<>)) | import Data.Monoid ((<>)) | ||||||
| @ -23,6 +24,7 @@ import Hledger.Data.Dates | |||||||
| import Hledger.Data.Amount | import Hledger.Data.Amount | ||||||
| import Hledger.Data.Transaction | import Hledger.Data.Transaction | ||||||
| import Hledger.Query | import Hledger.Query | ||||||
|  | import Hledger.Data.Posting (commentJoin, commentAddTag) | ||||||
| import Hledger.Utils.UTF8IOCompat (error') | import Hledger.Utils.UTF8IOCompat (error') | ||||||
| import Hledger.Utils.Debug | import Hledger.Utils.Debug | ||||||
| 
 | 
 | ||||||
| @ -36,7 +38,15 @@ import Hledger.Utils.Debug | |||||||
| modifyTransactions :: [TransactionModifier] -> [Transaction] -> [Transaction] | modifyTransactions :: [TransactionModifier] -> [Transaction] -> [Transaction] | ||||||
| modifyTransactions tmods = map applymods | modifyTransactions tmods = map applymods | ||||||
|   where |   where | ||||||
|     applymods = foldr (flip (.) . transactionModifierToFunction) id tmods |     applymods t = taggedt' | ||||||
|  |       where | ||||||
|  |         t' = foldr (flip (.) . transactionModifierToFunction) id tmods t | ||||||
|  |         taggedt' | ||||||
|  |           -- PERF: compares txns to see if any modifier had an effect, inefficient ? | ||||||
|  |           | t' /= t   = t'{tcomment = tcomment t' `commentAddTag` ("modified","") | ||||||
|  |                           ,ttags    = ("modified","") : ttags t' | ||||||
|  |                           } | ||||||
|  |           | otherwise = t' | ||||||
| 
 | 
 | ||||||
| -- | Converts a 'TransactionModifier' to a 'Transaction'-transforming function, | -- | Converts a 'TransactionModifier' to a 'Transaction'-transforming function, | ||||||
| -- which applies the modification(s) specified by the TransactionModifier. | -- which applies the modification(s) specified by the TransactionModifier. | ||||||
| @ -61,10 +71,10 @@ modifyTransactions tmods = map applymods | |||||||
| -- | -- | ||||||
| transactionModifierToFunction :: TransactionModifier -> (Transaction -> Transaction) | transactionModifierToFunction :: TransactionModifier -> (Transaction -> Transaction) | ||||||
| transactionModifierToFunction mt = | transactionModifierToFunction mt = | ||||||
|   \t@(tpostings -> ps) -> txnTieKnot t{ tpostings=generatePostings ps } -- TODO add modifier txn comment/tags ? |   \t@(tpostings -> ps) -> txnTieKnot t{ tpostings=generatePostings ps } | ||||||
|   where |   where | ||||||
|     q = simplifyQuery $ tmParseQuery mt (error' "a transaction modifier's query cannot depend on current date") |     q = simplifyQuery $ tmParseQuery mt (error' "a transaction modifier's query cannot depend on current date") | ||||||
|     mods = map tmPostingRuleToFunction $ tmpostingrules mt |     mods = map (tmPostingRuleToFunction (tmquerytxt mt)) $ tmpostingrules mt | ||||||
|     generatePostings ps = [p' | p <- ps |     generatePostings ps = [p' | p <- ps | ||||||
|                               , p' <- if q `matchesPosting` p then p:[ m p | m <- mods] else [p]] |                               , p' <- if q `matchesPosting` p then p:[ m p | m <- mods] else [p]] | ||||||
| 
 | 
 | ||||||
| @ -86,14 +96,23 @@ tmParseQuery mt = fst . flip parseQuery (tmquerytxt mt) | |||||||
| -- which will be used to make a new posting based on the old one (an "automated posting"). | -- which will be used to make a new posting based on the old one (an "automated posting"). | ||||||
| -- The new posting's amount can optionally be the old posting's amount multiplied by a constant. | -- The new posting's amount can optionally be the old posting's amount multiplied by a constant. | ||||||
| -- If the old posting had a total-priced amount, the new posting's multiplied amount will be unit-priced. | -- If the old posting had a total-priced amount, the new posting's multiplied amount will be unit-priced. | ||||||
| tmPostingRuleToFunction :: TMPostingRule -> (Posting -> Posting) | -- The new posting will have two tags added: a normal generated-posting: tag which also appears in the comment, | ||||||
| tmPostingRuleToFunction pr = | -- and a hidden _generated-posting: tag which does not. | ||||||
|  | -- The TransactionModifier's query text is also provided, and saved | ||||||
|  | -- as the tags' value. | ||||||
|  | tmPostingRuleToFunction :: T.Text -> TMPostingRule -> (Posting -> Posting) | ||||||
|  | tmPostingRuleToFunction querytxt pr = | ||||||
|   \p -> renderPostingCommentDates $ pr |   \p -> renderPostingCommentDates $ pr | ||||||
|       { pdate = pdate p |       { pdate    = pdate  pr <|> pdate  p | ||||||
|       , pdate2 = pdate2 p |       , pdate2   = pdate2 pr <|> pdate2 p | ||||||
|       , pamount = amount' p |       , pamount  = amount' p | ||||||
|  |       , pcomment = pcomment pr `commentAddTag` ("generated-posting",qry) | ||||||
|  |       , ptags    = ("generated-posting", qry) : | ||||||
|  |                    ("_generated-posting",qry) : | ||||||
|  |                    ptags pr | ||||||
|       } |       } | ||||||
|   where |   where | ||||||
|  |     qry = "= " <> querytxt | ||||||
|     amount' = case postingRuleMultiplier pr of |     amount' = case postingRuleMultiplier pr of | ||||||
|         Nothing -> const $ pamount pr |         Nothing -> const $ pamount pr | ||||||
|         Just n  -> \p -> |         Just n  -> \p -> | ||||||
| @ -123,7 +142,7 @@ postingRuleMultiplier p = | |||||||
| renderPostingCommentDates :: Posting -> Posting | renderPostingCommentDates :: Posting -> Posting | ||||||
| renderPostingCommentDates p = p { pcomment = comment' } | renderPostingCommentDates p = p { pcomment = comment' } | ||||||
|     where |     where | ||||||
|         datesComment = T.concat $ catMaybes [T.pack . showDate <$> pdate p, ("=" <>) . T.pack . showDate <$> pdate2 p] |         dates = T.concat $ catMaybes [T.pack . showDate <$> pdate p, ("=" <>) . T.pack . showDate <$> pdate2 p] | ||||||
|         comment' |         comment' | ||||||
|             | T.null datesComment = pcomment p |             | T.null dates = pcomment p | ||||||
|             | otherwise = T.intercalate "\n" $ filter (not . T.null) [T.strip $ pcomment p, "[" <> datesComment <> "]"] |             | otherwise    = ("[" <> dates <> "]") `commentJoin` pcomment p | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ module Hledger.Utils.Text | |||||||
|   textstrip, |   textstrip, | ||||||
|   textlstrip, |   textlstrip, | ||||||
|   textrstrip, |   textrstrip, | ||||||
|  -- chomp, |   textchomp, | ||||||
|  -- elideLeft, |  -- elideLeft, | ||||||
|   textElideRight, |   textElideRight, | ||||||
|  -- formatString, |  -- formatString, | ||||||
| @ -90,9 +90,9 @@ textlstrip = T.dropWhile (`elem` (" \t" :: String)) :: Text -> Text -- XXX isSpa | |||||||
| textrstrip = T.reverse . textlstrip . T.reverse | textrstrip = T.reverse . textlstrip . T.reverse | ||||||
| textrstrip :: Text -> Text | textrstrip :: Text -> Text | ||||||
| 
 | 
 | ||||||
| -- -- | Remove trailing newlines/carriage returns. | -- | Remove trailing newlines/carriage returns (and other whitespace). | ||||||
| -- chomp :: String -> String | textchomp :: Text -> Text | ||||||
| -- chomp = reverse . dropWhile (`elem` "\r\n") . reverse | textchomp = T.stripEnd | ||||||
| 
 | 
 | ||||||
| -- stripbrackets :: String -> String | -- stripbrackets :: String -> String | ||||||
| -- stripbrackets = dropWhile (`elem` "([") . reverse . dropWhile (`elem` "])") . reverse :: String -> String | -- stripbrackets = dropWhile (`elem` "([") . reverse . dropWhile (`elem` "])") . reverse :: String -> String | ||||||
|  | |||||||
| @ -1201,8 +1201,16 @@ can not accidentally alter their meaning, as in this example: | |||||||
| With the `--forecast` flag, each periodic transaction rule generates | With the `--forecast` flag, each periodic transaction rule generates | ||||||
| future transactions recurring at the specified interval. | future transactions recurring at the specified interval. | ||||||
| These are not saved in the journal, but appear in all reports. | These are not saved in the journal, but appear in all reports. | ||||||
| They will look like normal transactions, but with an extra | They will look like normal transactions, but with an extra [tag](manual.html#tags-1): | ||||||
| [tag](manual.html#tags-1) named `recur`, whose value is the generating period expression. |   | ||||||
|  | - `generated-transaction:~ PERIODICEXPR`  - shows that this was generated by a periodic transaction rule, and the period | ||||||
|  | 
 | ||||||
|  | There is also a hidden tag, with an underscore prefix, which does not appear in hledger's output: | ||||||
|  | 
 | ||||||
|  | - `_generated-transaction:~ PERIODICEXPR` | ||||||
|  | 
 | ||||||
|  | This can be used to match transactions generated "just now", | ||||||
|  | rather than generated in the past and saved to the journal. | ||||||
| 
 | 
 | ||||||
| Forecast transactions start on the first occurrence, and end on the last occurrence, | Forecast transactions start on the first occurrence, and end on the last occurrence, | ||||||
| of their interval within the forecast period. The forecast period: | of their interval within the forecast period. The forecast period: | ||||||
| @ -1251,11 +1259,11 @@ and | |||||||
| 
 | 
 | ||||||
| ## Auto postings / transaction modifiers | ## Auto postings / transaction modifiers | ||||||
| 
 | 
 | ||||||
| Transaction modifier rules describe changes to be applied automatically to certain matched transactions. | Transaction modifier rules, AKA auto posting rules, describe changes to be applied automatically to certain matched transactions. | ||||||
| Currently just one kind of change is possible - adding extra postings, which we call "automated postings" or just "auto postings". | Currently just one kind of change is possible - adding extra postings, which we call "automated postings" or just "auto postings". | ||||||
| These rules become active when you use the `--auto` flag. | These rules become active when you use the `--auto` flag. | ||||||
| 
 | 
 | ||||||
| A transaction modifier, AKA auto posting rule, looks much like a normal transaction | A transaction modifier rule looks much like a normal transaction | ||||||
| except the first line is an equals sign followed by a [query](manual.html#queries) that matches certain postings | except the first line is an equals sign followed by a [query](manual.html#queries) that matches certain postings | ||||||
| (mnemonic: `=` suggests matching). | (mnemonic: `=` suggests matching). | ||||||
| And each "posting" is actually a posting-generating rule: | And each "posting" is actually a posting-generating rule: | ||||||
| @ -1309,6 +1317,12 @@ $ hledger print --auto | |||||||
|     assets:checking            $20 |     assets:checking            $20 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | ### Auto postings and dates | ||||||
|  | 
 | ||||||
|  | A [posting date](#posting-dates) (or secondary date) in the matched posting, | ||||||
|  | or (taking precedence) a posting date in the auto posting rule itself, | ||||||
|  | will also be used in the generated posting. | ||||||
|  | 
 | ||||||
| ### Auto postings and transaction balancing / inferred amounts / balance assertions | ### Auto postings and transaction balancing / inferred amounts / balance assertions | ||||||
| 
 | 
 | ||||||
| Currently, transaction modifiers are applied / auto postings are added: | Currently, transaction modifiers are applied / auto postings are added: | ||||||
| @ -1321,6 +1335,22 @@ after auto postings are added. This changed in hledger 1.12+; see | |||||||
| [#893](https://github.com/simonmichael/hledger/issues/893) for | [#893](https://github.com/simonmichael/hledger/issues/893) for | ||||||
| background. | background. | ||||||
| 
 | 
 | ||||||
|  | ### Auto posting tags | ||||||
|  | 
 | ||||||
|  | Postings added by transaction modifiers will have some extra [tags](#tags-1):   | ||||||
|  | 
 | ||||||
|  | - `generated-posting:= QUERY`  - shows this was generated by an auto posting rule, and the query | ||||||
|  | - `_generated-posting:= QUERY` - a hidden tag, which does not appear in hledger's output. | ||||||
|  |                                      This can be used to match postings generated "just now", | ||||||
|  |                                      rather than generated in the past and saved to the journal. | ||||||
|  | 
 | ||||||
|  | Also, any transaction that has been changed by transaction modifier rules will have these tags added: | ||||||
|  | 
 | ||||||
|  | - `modified:` - this transaction was modified | ||||||
|  | - `_modified:` - a hidden tag not appearing in the comment; this transaction was modified "just now". | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| # EDITOR SUPPORT | # EDITOR SUPPORT | ||||||
| 
 | 
 | ||||||
| Helper modes exist for popular text editors, which make working with | Helper modes exist for popular text editors, which make working with | ||||||
|  | |||||||
| @ -51,7 +51,7 @@ hledger print -b 2016-11 -e 2017-02 -f - --forecast | |||||||
|     assets:cash |     assets:cash | ||||||
| 
 | 
 | ||||||
| 2017/01/01 * marked cleared, and with a description | 2017/01/01 * marked cleared, and with a description | ||||||
|     ; recur: monthly from 2016/1 |     ; generated-transaction:~ monthly from 2016/1 | ||||||
|     income                    $-1000 |     income                    $-1000 | ||||||
|     expenses:food                $20 |     expenses:food                $20 | ||||||
|     expenses:leisure             $15 |     expenses:leisure             $15 | ||||||
| @ -118,7 +118,7 @@ Y 2000 | |||||||
| 
 | 
 | ||||||
| >>> | >>> | ||||||
| 2000/02/01 forecast | 2000/02/01 forecast | ||||||
|     ; recur: 2/1 |     ; generated-transaction:~ 2/1 | ||||||
| 
 | 
 | ||||||
| >>>2 | >>>2 | ||||||
| >>>=0 | >>>=0 | ||||||
| @ -135,7 +135,7 @@ Y 2000 | |||||||
| 
 | 
 | ||||||
| >>> | >>> | ||||||
| 2000/01/15 forecast | 2000/01/15 forecast | ||||||
|     ; recur: 15 |     ; generated-transaction:~ 15 | ||||||
| 
 | 
 | ||||||
| >>>2 | >>>2 | ||||||
| >>>=0 | >>>=0 | ||||||
| @ -152,7 +152,7 @@ Y 2000 | |||||||
| 
 | 
 | ||||||
| >>> | >>> | ||||||
| 2000/02/01 forecast | 2000/02/01 forecast | ||||||
|     ; recur: next month |     ; generated-transaction:~ next month | ||||||
| 
 | 
 | ||||||
| >>>2 | >>>2 | ||||||
| >>>=0 | >>>=0 | ||||||
|  | |||||||
| @ -15,11 +15,11 @@ | |||||||
| 
 | 
 | ||||||
| # 1. print | # 1. print | ||||||
| $ hledger print -f- --auto | $ hledger print -f- --auto | ||||||
| 2016/01/01 paycheck | 2016/01/01 paycheck  ; modified: | ||||||
|     income:remuneration           $-100 |     income:remuneration           $-100 | ||||||
|     (liabilities:tax)              $-33  ; income tax |     (liabilities:tax)              $-33  ; income tax, generated-posting:= ^income | ||||||
|     income:donations               $-15 |     income:donations               $-15 | ||||||
|     (liabilities:tax)               $-5  ; income tax |     (liabilities:tax)               $-5  ; income tax, generated-posting:= ^income | ||||||
|     assets:bank |     assets:bank | ||||||
| 
 | 
 | ||||||
| 2016/01/01 withdraw | 2016/01/01 withdraw | ||||||
| @ -80,10 +80,10 @@ $ hledger register -f- --auto | |||||||
| 
 | 
 | ||||||
| # 5. | # 5. | ||||||
| $ hledger print -f- --auto | $ hledger print -f- --auto | ||||||
| 2018/10/07 * MARKET | 2018/10/07 * MARKET  ; modified: | ||||||
|     expenses:groceries:food |     expenses:groceries:food | ||||||
|     [budget:groceries]                 $-20 |     [budget:groceries]                 $-20  ; generated-posting:= ^expenses:groceries | ||||||
|     [assets:bank:checking]              $20 |     [assets:bank:checking]              $20  ; generated-posting:= ^expenses:groceries | ||||||
|     assets:bank:checking               $-20 |     assets:bank:checking               $-20 | ||||||
| 
 | 
 | ||||||
| >= | >= | ||||||
| @ -99,10 +99,10 @@ $ hledger print -f- --auto | |||||||
| 
 | 
 | ||||||
| # 6. | # 6. | ||||||
| $ hledger -f- print --auto -x | $ hledger -f- print --auto -x | ||||||
| 2018/01/01 | 2018/01/01  ; modified: | ||||||
|     (assets:billable:client1)     0.50h @ $90 |     (assets:billable:client1)     0.50h @ $90 | ||||||
|     assets:receivable:client1    50.00h @ $90 |     assets:receivable:client1    50.00h @ $90  ; generated-posting:= assets:billable:client1 | ||||||
|     revenues:client1                   $-4500 |     revenues:client1                   $-4500  ; generated-posting:= assets:billable:client1 | ||||||
| 
 | 
 | ||||||
| >= | >= | ||||||
| 
 | 
 | ||||||
| @ -117,10 +117,10 @@ $ hledger -f- print --auto -x | |||||||
| 
 | 
 | ||||||
| # 7. | # 7. | ||||||
| $ hledger -f- print --auto -x | $ hledger -f- print --auto -x | ||||||
| 2018/01/01 | 2018/01/01  ; modified: | ||||||
|     (assets:billable:client1)           0.50h |     (assets:billable:client1)           0.50h | ||||||
|     assets:receivable:client1             $50 |     assets:receivable:client1             $50  ; generated-posting:= assets:billable:client1 | ||||||
|     revenues:client1                     $-50 |     revenues:client1                     $-50  ; generated-posting:= assets:billable:client1 | ||||||
| 
 | 
 | ||||||
| >= | >= | ||||||
| 
 | 
 | ||||||
| @ -135,10 +135,10 @@ $ hledger -f- print --auto -x | |||||||
| 
 | 
 | ||||||
| # 8. | # 8. | ||||||
| $ hledger -f- print --auto -x | $ hledger -f- print --auto -x | ||||||
| 2018/01/01 | 2018/01/01  ; modified: | ||||||
|     (assets:billable:client1)                       0.50h @ $90 |     (assets:billable:client1)                       0.50h @ $90 | ||||||
|     assets:receivable:client1    0.50 "Client1 Hours" @ $100.00 |     assets:receivable:client1    0.50 "Client1 Hours" @ $100.00  ; generated-posting:= assets:billable:client1 | ||||||
|     revenues:client1                                    $-50.00 |     revenues:client1                                    $-50.00  ; generated-posting:= assets:billable:client1 | ||||||
| 
 | 
 | ||||||
| >= | >= | ||||||
| 
 | 
 | ||||||
| @ -180,11 +180,11 @@ $ hledger print -f- --auto | |||||||
| 
 | 
 | ||||||
| # 10. | # 10. | ||||||
| $ hledger -f- print --auto | $ hledger -f- print --auto | ||||||
| 2018/01/01 | 2018/01/01  ; modified: | ||||||
|     Expenses:Joint:Widgets     $100.00 @ £0.50 |     Expenses:Joint:Widgets     $100.00 @ £0.50 | ||||||
|     Expenses:Joint            $-100.00 @ £0.50 |     Expenses:Joint            $-100.00 @ £0.50  ; generated-posting:= ^Expenses:Joint | ||||||
|     Liabilities:Joint:Bob       $50.00 @ £0.50 |     Liabilities:Joint:Bob       $50.00 @ £0.50  ; generated-posting:= ^Expenses:Joint | ||||||
|     Liabilities:Joint:Bill      $50.00 @ £0.50 |     Liabilities:Joint:Bill      $50.00 @ £0.50  ; generated-posting:= ^Expenses:Joint | ||||||
|     Assets:Joint:Bank                  £-50.00 |     Assets:Joint:Bank                  £-50.00 | ||||||
| 
 | 
 | ||||||
| >=0 | >=0 | ||||||
| @ -202,11 +202,11 @@ $ hledger -f- print --auto | |||||||
| 
 | 
 | ||||||
| # 11. | # 11. | ||||||
| $ hledger -f- print --auto | $ hledger -f- print --auto | ||||||
| 2018/01/01 | 2018/01/01  ; modified: | ||||||
|     Expenses:Joint:Widgets     $100.00 @@ £50 |     Expenses:Joint:Widgets     $100.00 @@ £50 | ||||||
|     Expenses:Joint            $-100.00 @@ £50 |     Expenses:Joint            $-100.00 @@ £50  ; generated-posting:= ^Expenses:Joint | ||||||
|     Liabilities:Joint:Bob       $50.00 @@ £25 |     Liabilities:Joint:Bob       $50.00 @@ £25  ; generated-posting:= ^Expenses:Joint | ||||||
|     Liabilities:Joint:Bill      $50.00 @@ £25 |     Liabilities:Joint:Bill      $50.00 @@ £25  ; generated-posting:= ^Expenses:Joint | ||||||
|     Assets:Joint:Bank                 £-50.00 |     Assets:Joint:Bank                 £-50.00 | ||||||
| 
 | 
 | ||||||
| >=0 | >=0 | ||||||
| @ -231,11 +231,11 @@ $ hledger -f- print --auto | |||||||
| 
 | 
 | ||||||
| # 12. | # 12. | ||||||
| $ hledger -f- print --auto | $ hledger -f- print --auto | ||||||
| 2018/01/01 | 2018/01/01  ; modified: | ||||||
|     Expenses:Joint:Widgets            $100.00 |     Expenses:Joint:Widgets            $100.00 | ||||||
|     Expenses:Joint            $-100.00 @@ £50 |     Expenses:Joint            $-100.00 @@ £50  ; generated-posting:= ^Expenses:Joint | ||||||
|     Liabilities:Joint:Bob       $50.00 @@ £25 |     Liabilities:Joint:Bob       $50.00 @@ £25  ; generated-posting:= ^Expenses:Joint | ||||||
|     Liabilities:Joint:Bill      $50.00 @@ £25 |     Liabilities:Joint:Bill      $50.00 @@ £25  ; generated-posting:= ^Expenses:Joint | ||||||
|     Assets:Joint:Bank                 £-50.00 |     Assets:Joint:Bank                 £-50.00 | ||||||
| 
 | 
 | ||||||
| >=0 | >=0 | ||||||
| @ -264,11 +264,11 @@ $ hledger print -f- --auto --forecast -b 2016-01 -e 2016-03 | |||||||
|     assets:bank |     assets:bank | ||||||
| 
 | 
 | ||||||
| 2016/02/01 paycheck | 2016/02/01 paycheck | ||||||
|     ; recur: monthly from 2016-01 |     ; generated-transaction:~ monthly from 2016-01, modified: | ||||||
|     income:remuneration           $-100 |     income:remuneration           $-100 | ||||||
|     (liabilities:tax)              $-33  ; income tax |     (liabilities:tax)              $-33  ; income tax, generated-posting:= ^income | ||||||
|     income:donations               $-15 |     income:donations               $-15 | ||||||
|     (liabilities:tax)               $-5  ; income tax |     (liabilities:tax)               $-5  ; income tax, generated-posting:= ^income | ||||||
|     assets:bank |     assets:bank | ||||||
| 
 | 
 | ||||||
| >= | >= | ||||||
| @ -280,7 +280,7 @@ $ hledger print -f- --forecast -b 2016-01 -e 2016-03 | |||||||
|     assets:bank |     assets:bank | ||||||
| 
 | 
 | ||||||
| 2016/02/01 paycheck | 2016/02/01 paycheck | ||||||
|     ; recur: monthly from 2016-01 |     ; generated-transaction:~ monthly from 2016-01 | ||||||
|     income:remuneration           $-100 |     income:remuneration           $-100 | ||||||
|     income:donations               $-15 |     income:donations               $-15 | ||||||
|     assets:bank |     assets:bank | ||||||
|  | |||||||
| @ -85,9 +85,9 @@ D $1000. | |||||||
|   (a)  €1 |   (a)  €1 | ||||||
| 
 | 
 | ||||||
| >>> | >>> | ||||||
| 2018/01/01 | 2018/01/01  ; modified: | ||||||
|     (a)              €1 |     (a)              €1 | ||||||
|     (b)              €2 |     (b)              €2  ; generated-posting:= a | ||||||
| 
 | 
 | ||||||
| >>>= | >>>= | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| # Add proportional income tax (from documentation) | # 1. Add proportional income tax (from documentation) | ||||||
| hledger rewrite -f- ^income --add-posting '(liabilities:tax)  *.33  ; income tax' | hledger rewrite -f- ^income --add-posting '(liabilities:tax)  *.33  ; income tax' | ||||||
| <<< | <<< | ||||||
| 2016/1/1 paycheck | 2016/1/1 paycheck | ||||||
| @ -10,11 +10,11 @@ hledger rewrite -f- ^income --add-posting '(liabilities:tax)  *.33  ; income tax | |||||||
|     assets:cash             $20 |     assets:cash             $20 | ||||||
|     assets:bank |     assets:bank | ||||||
| >>> | >>> | ||||||
| 2016/01/01 paycheck | 2016/01/01 paycheck  ; modified: | ||||||
|     income:remuneration           $-100 |     income:remuneration           $-100 | ||||||
|     (liabilities:tax)              $-33  ; income tax |     (liabilities:tax)              $-33  ; income tax, generated-posting:= ^income | ||||||
|     income:donations               $-15 |     income:donations               $-15 | ||||||
|     (liabilities:tax)               $-5  ; income tax |     (liabilities:tax)               $-5  ; income tax, generated-posting:= ^income | ||||||
|     assets:bank |     assets:bank | ||||||
| 
 | 
 | ||||||
| 2016/01/01 withdraw | 2016/01/01 withdraw | ||||||
| @ -24,7 +24,8 @@ hledger rewrite -f- ^income --add-posting '(liabilities:tax)  *.33  ; income tax | |||||||
| >>>2 | >>>2 | ||||||
| >>>=0 | >>>=0 | ||||||
| 
 | 
 | ||||||
| # Duplicate posting for budgeting (from documentation) | # 2. Duplicate posting for budgeting (from documentation). | ||||||
|  | # It uses same date as the matched posting. | ||||||
| hledger rewrite -f- expenses:gifts --add-posting '(budget:gifts)  *-1' | hledger rewrite -f- expenses:gifts --add-posting '(budget:gifts)  *-1' | ||||||
| <<< | <<< | ||||||
| 2016/1/1 withdraw | 2016/1/1 withdraw | ||||||
| @ -39,15 +40,15 @@ hledger rewrite -f- expenses:gifts --add-posting '(budget:gifts)  *-1' | |||||||
|     assets:cash             $20 |     assets:cash             $20 | ||||||
|     assets:bank |     assets:bank | ||||||
| 
 | 
 | ||||||
| 2016/01/01 gift | 2016/01/01 gift  ; modified: | ||||||
|     assets:cash               $-15 |     assets:cash               $-15 | ||||||
|     expenses:gifts      ; [1/2] |     expenses:gifts      ; [1/2] | ||||||
|     (budget:gifts)            $-15  ; [2016/01/02] |     (budget:gifts)            $-15  ; [2016/01/02], generated-posting:= expenses:gifts | ||||||
| 
 | 
 | ||||||
| >>>2 | >>>2 | ||||||
| >>>=0 | >>>=0 | ||||||
| 
 | 
 | ||||||
| # Add postings in another commodity | # 3. Add postings in another commodity | ||||||
| hledger rewrite -f- | hledger rewrite -f- | ||||||
| <<< | <<< | ||||||
| 2017/04/24 * 09:00-09:25 | 2017/04/24 * 09:00-09:25 | ||||||
| @ -66,23 +67,23 @@ hledger rewrite -f- | |||||||
| = ^assets:unbilled:client2 | = ^assets:unbilled:client2 | ||||||
|   (assets:to bill:client2)   *150.00 CAD |   (assets:to bill:client2)   *150.00 CAD | ||||||
| >>> | >>> | ||||||
| 2017/04/24 * 09:00-09:25 | 2017/04/24 * 09:00-09:25  ; modified: | ||||||
|     (assets:unbilled:client1)           0.42h |     (assets:unbilled:client1)           0.42h | ||||||
|     (assets:to bill:client1)        42.00 CAD |     (assets:to bill:client1)        42.00 CAD  ; generated-posting:= ^assets:unbilled:client1 | ||||||
| 
 | 
 | ||||||
| 2017/04/25 * 10:00-11:15 | 2017/04/25 * 10:00-11:15  ; modified: | ||||||
|     (assets:unbilled:client1)           1.25h |     (assets:unbilled:client1)           1.25h | ||||||
|     (assets:to bill:client1)       125.00 CAD |     (assets:to bill:client1)       125.00 CAD  ; generated-posting:= ^assets:unbilled:client1 | ||||||
| 
 | 
 | ||||||
| 2017/04/25 * 14:00-15:32 | 2017/04/25 * 14:00-15:32  ; modified: | ||||||
|     (assets:unbilled:client2)           1.54h |     (assets:unbilled:client2)           1.54h | ||||||
|     (assets:to bill:client2)       231.00 CAD |     (assets:to bill:client2)       231.00 CAD  ; generated-posting:= ^assets:unbilled:client2 | ||||||
| 
 | 
 | ||||||
| >>>2 | >>>2 | ||||||
| >>>=0 | >>>=0 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Add postings with prices | # 4. Add postings with prices | ||||||
| hledger rewrite -f- -B | hledger rewrite -f- -B | ||||||
| <<< | <<< | ||||||
| 2017/04/24 * 09:00-09:25 | 2017/04/24 * 09:00-09:25 | ||||||
| @ -103,25 +104,26 @@ hledger rewrite -f- -B | |||||||
|   assets:to bill:client2   *1.00 hours @ $150.00 |   assets:to bill:client2   *1.00 hours @ $150.00 | ||||||
|   income:consulting:client2 |   income:consulting:client2 | ||||||
| >>> | >>> | ||||||
| 2017/04/24 * 09:00-09:25 | 2017/04/24 * 09:00-09:25  ; modified: | ||||||
|     (assets:unbilled:client1)           0.42h |     (assets:unbilled:client1)           0.42h | ||||||
|     assets:to bill:client1             $42.00 |     assets:to bill:client1             $42.00  ; generated-posting:= ^assets:unbilled:client1 | ||||||
|     income:consulting:client1 |     income:consulting:client1      ; generated-posting:= ^assets:unbilled:client1 | ||||||
| 
 | 
 | ||||||
| 2017/04/25 * 10:00-11:15 | 2017/04/25 * 10:00-11:15  ; modified: | ||||||
|     (assets:unbilled:client1)           1.25h |     (assets:unbilled:client1)           1.25h | ||||||
|     assets:to bill:client1            $125.00 |     assets:to bill:client1            $125.00  ; generated-posting:= ^assets:unbilled:client1 | ||||||
|     income:consulting:client1 |     income:consulting:client1      ; generated-posting:= ^assets:unbilled:client1 | ||||||
| 
 | 
 | ||||||
| 2017/04/25 * 14:00-15:32 | 2017/04/25 * 14:00-15:32  ; modified: | ||||||
|     (assets:unbilled:client2)           1.54h |     (assets:unbilled:client2)           1.54h | ||||||
|     assets:to bill:client2            $231.00 |     assets:to bill:client2            $231.00  ; generated-posting:= ^assets:unbilled:client2 | ||||||
|     income:consulting:client2 |     income:consulting:client2      ; generated-posting:= ^assets:unbilled:client2 | ||||||
| 
 | 
 | ||||||
| >>>2 | >>>2 | ||||||
| >>>=0 | >>>=0 | ||||||
| 
 | 
 | ||||||
| # Add absolute bank processing fee | # 5. Add absolute bank processing fee | ||||||
|  | # XXX is "and" really processed here ? | ||||||
| hledger rewrite -f- assets:bank and 'amt:<0' --add-posting 'expenses:fee  $5'  --add-posting 'assets:bank  $-5' | hledger rewrite -f- assets:bank and 'amt:<0' --add-posting 'expenses:fee  $5'  --add-posting 'assets:bank  $-5' | ||||||
| <<< | <<< | ||||||
| 2016/1/1 withdraw | 2016/1/1 withdraw | ||||||
| @ -137,22 +139,22 @@ hledger rewrite -f- assets:bank and 'amt:<0' --add-posting 'expenses:fee  $5'  - | |||||||
| #     income:remuneration     $-100 | #     income:remuneration     $-100 | ||||||
| #     assets:bank | #     assets:bank | ||||||
| >>> | >>> | ||||||
| 2016/01/01 withdraw | 2016/01/01 withdraw  ; modified: | ||||||
|     assets:cash              $20 |     assets:cash              $20 | ||||||
|     assets:bank |     assets:bank | ||||||
|     expenses:fee              $5 |     expenses:fee              $5  ; generated-posting:= assets:bank and amt:<0 | ||||||
|     assets:bank              $-5 |     assets:bank              $-5  ; generated-posting:= assets:bank and amt:<0 | ||||||
| 
 | 
 | ||||||
| 2016/01/02 withdraw | 2016/01/02 withdraw  ; modified: | ||||||
|     assets:cash |     assets:cash | ||||||
|     assets:bank             $-30 |     assets:bank             $-30 | ||||||
|     expenses:fee              $5 |     expenses:fee              $5  ; generated-posting:= assets:bank and amt:<0 | ||||||
|     assets:bank              $-5 |     assets:bank              $-5  ; generated-posting:= assets:bank and amt:<0 | ||||||
| 
 | 
 | ||||||
| >>>2 | >>>2 | ||||||
| >>>=0 | >>>=0 | ||||||
| 
 | 
 | ||||||
| # Rewrite rule within journal | # 6. Rewrite rule within journal | ||||||
| hledger rewrite -f- date:2017/1  --add-posting 'Here comes Santa  $0' | hledger rewrite -f- date:2017/1  --add-posting 'Here comes Santa  $0' | ||||||
| <<< | <<< | ||||||
| = ^assets:bank$ date:2017/1 amt:<0 | = ^assets:bank$ date:2017/1 amt:<0 | ||||||
| @ -186,32 +188,32 @@ hledger rewrite -f- date:2017/1  --add-posting 'Here comes Santa  $0' | |||||||
| = ^expenses not:housing not:grocery not:food | = ^expenses not:housing not:grocery not:food | ||||||
|     (budget:misc)  *-1 |     (budget:misc)  *-1 | ||||||
| >>> | >>> | ||||||
| 2016/12/31 | 2016/12/31  ; modified: | ||||||
|     expenses:housing         $600.00 |     expenses:housing         $600.00 | ||||||
|     (budget:housing)        $-600.00 |     (budget:housing)        $-600.00  ; generated-posting:= ^expenses:housing | ||||||
|     assets:cash |     assets:cash | ||||||
| 
 | 
 | ||||||
| 2017/01/01 | 2017/01/01  ; modified: | ||||||
|     expenses:food             $20.00 |     expenses:food             $20.00 | ||||||
|     (budget:food)            $-20.00 |     (budget:food)            $-20.00  ; generated-posting:= ^expenses:grocery ^expenses:food | ||||||
|     Here comes Santa               0 |     Here comes Santa               0  ; generated-posting:= date:2017/1 | ||||||
|     expenses:leisure          $15.00 |     expenses:leisure          $15.00 | ||||||
|     (budget:misc)            $-15.00 |     (budget:misc)            $-15.00  ; generated-posting:= ^expenses not:housing not:grocery not:food | ||||||
|     Here comes Santa               0 |     Here comes Santa               0  ; generated-posting:= date:2017/1 | ||||||
|     expenses:grocery          $30.00 |     expenses:grocery          $30.00 | ||||||
|     (budget:food)            $-30.00 |     (budget:food)            $-30.00  ; generated-posting:= ^expenses:grocery ^expenses:food | ||||||
|     Here comes Santa               0 |     Here comes Santa               0  ; generated-posting:= date:2017/1 | ||||||
|     assets:cash |     assets:cash | ||||||
|     Here comes Santa               0 |     Here comes Santa               0  ; generated-posting:= date:2017/1 | ||||||
| 
 | 
 | ||||||
| 2017/01/02 | 2017/01/02  ; modified: | ||||||
|     assets:cash              $200.00 |     assets:cash              $200.00 | ||||||
|     Here comes Santa               0 |     Here comes Santa               0  ; generated-posting:= date:2017/1 | ||||||
|     assets:bank |     assets:bank | ||||||
|     assets:bank               $-1.60 |     assets:bank               $-1.60  ; generated-posting:= ^assets:bank$ date:2017/1 amt:<0 | ||||||
|     expenses:fee               $1.60  ; cash withdraw fee |     expenses:fee               $1.60  ; cash withdraw fee, generated-posting:= ^assets:bank$ date:2017/1 amt:<0 | ||||||
|     (budget:misc)             $-1.60 |     (budget:misc)             $-1.60  ; generated-posting:= ^expenses not:housing not:grocery not:food | ||||||
|     Here comes Santa               0 |     Here comes Santa               0  ; generated-posting:= date:2017/1 | ||||||
| 
 | 
 | ||||||
| 2017/02/01 | 2017/02/01 | ||||||
|     assets:cash         $100.00 |     assets:cash         $100.00 | ||||||
| @ -220,7 +222,7 @@ hledger rewrite -f- date:2017/1  --add-posting 'Here comes Santa  $0' | |||||||
| >>>2 | >>>2 | ||||||
| >>>=0 | >>>=0 | ||||||
| 
 | 
 | ||||||
| # Rewrite using diff output | # 7. Rewrite using diff output | ||||||
| hledger rewrite --diff -f- assets:bank and 'amt:<0' --add-posting 'expenses:fee  $5'  --add-posting 'assets:bank  $-5' | hledger rewrite --diff -f- assets:bank and 'amt:<0' --add-posting 'expenses:fee  $5'  --add-posting 'assets:bank  $-5' | ||||||
| <<< | <<< | ||||||
| 2016/01/01 withdraw | 2016/01/01 withdraw | ||||||
| @ -234,16 +236,18 @@ hledger rewrite --diff -f- assets:bank and 'amt:<0' --add-posting 'expenses:fee | |||||||
| --- - | --- - | ||||||
| +++ - | +++ - | ||||||
| @@ -1,3 +1,5 @@ | @@ -1,3 +1,5 @@ | ||||||
|  2016/01/01 withdraw | -2016/01/01 withdraw | ||||||
|  | +2016/01/01 withdraw  ; modified: | ||||||
|      assets:cash              $20 |      assets:cash              $20 | ||||||
|      assets:bank |      assets:bank | ||||||
| +    expenses:fee              $5 | +    expenses:fee              $5  ; generated-posting:= assets:bank and amt:<0 | ||||||
| +    assets:bank              $-5 | +    assets:bank              $-5  ; generated-posting:= assets:bank and amt:<0 | ||||||
| @@ -5,3 +7,5 @@ | @@ -5,3 +7,5 @@ | ||||||
|  2016/01/02 withdraw | -2016/01/02 withdraw | ||||||
|  | +2016/01/02 withdraw  ; modified: | ||||||
|      assets:cash |      assets:cash | ||||||
|      assets:bank             $-30 |      assets:bank             $-30 | ||||||
| +    expenses:fee              $5 | +    expenses:fee              $5  ; generated-posting:= assets:bank and amt:<0 | ||||||
| +    assets:bank              $-5 | +    assets:bank              $-5  ; generated-posting:= assets:bank and amt:<0 | ||||||
| >>>2 | >>>2 | ||||||
| >>>=0 | >>>=0 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user