Feature/pivot implicit tags (#460)

* Add implicit tags code/desc/payee for --pivot

Additionally allow using of transaction inherited tags.

* Use original posting in query by account name

To be able to query on individual postings and by account name it is
useful to have access to original account name (before pivot).
Especially this is useful when all postings within transaction gets
the same pivot name due.
As a side effect we'll match by alias.

Note: to query on amt it usually expected to see matches with inferred
amounts.
This commit is contained in:
Mykola Orliuk 2017-01-13 18:02:11 +02:00 committed by Simon Michael
parent 2f5b96b4ae
commit 76867c98a3
6 changed files with 154 additions and 2 deletions

View File

@ -25,6 +25,7 @@ module Hledger.Data.Posting (
hasAmount,
postingAllTags,
transactionAllTags,
postingAllImplicitTags,
relatedPostings,
removePrices,
-- * date operations
@ -168,6 +169,18 @@ postingStatus Posting{pstatus=s, ptransaction=mt}
Nothing -> Uncleared
| otherwise = s
-- | Implicit tags for this transaction.
transactionImplicitTags :: Transaction -> [Tag]
transactionImplicitTags t = filter (not . T.null . snd) [("code", tcode t)
,("desc", tdescription t)
,("payee", tdescription t)
]
-- | Tags for this posting including implicit and any inherited from its parent transaction.
postingAllImplicitTags :: Posting -> [Tag]
postingAllImplicitTags p = ptags p ++ maybe [] transactionTags (ptransaction p)
where transactionTags t = ttags t ++ transactionImplicitTags t
-- | Tags for this posting including any inherited from its parent transaction.
postingAllTags :: Posting -> [Tag]
postingAllTags p = ptags p ++ maybe [] ttags (ptransaction p)

View File

@ -659,6 +659,8 @@ compareAmount ord q Amount{aquantity=aq} = case ord of Lt -> aq < q
AbsEq -> abs aq == abs q
-- | Does the match expression match this posting ?
--
-- Note that for account match we try both original and effective account
matchesPosting :: Query -> Posting -> Bool
matchesPosting (Not q) p = not $ q `matchesPosting` p
matchesPosting (Any) _ = True
@ -667,7 +669,8 @@ matchesPosting (Or qs) p = any (`matchesPosting` p) qs
matchesPosting (And qs) p = all (`matchesPosting` p) qs
matchesPosting (Code r) p = regexMatchesCI r $ maybe "" (T.unpack . tcode) $ ptransaction p
matchesPosting (Desc r) p = regexMatchesCI r $ maybe "" (T.unpack . tdescription) $ ptransaction p
matchesPosting (Acct r) p = regexMatchesCI r $ T.unpack $ paccount p -- XXX pack
matchesPosting (Acct r) p = matchesPosting p || matchesPosting (originalPosting p)
where matchesPosting p = regexMatchesCI r $ T.unpack $ paccount p -- XXX pack
matchesPosting (Date span) p = span `spanContainsDate` postingDate p
matchesPosting (Date2 span) p = span `spanContainsDate` postingDate2 p
matchesPosting (Status Uncleared) p = postingStatus p /= Cleared

View File

@ -93,7 +93,7 @@ pivot tag j = j{jtxns = map pivotTrans . jtxns $ j}
pivotPosting p
| Just (_ , value) <- tagTuple = p{paccount = joinAccountNames tag value, porigin = Just $ originalPosting p}
| _ <- tagTuple = p
where tagTuple = find ((tag ==) . fst) . ptags $ p
where tagTuple = find ((tag ==) . fst) . postingAllImplicitTags $ p
-- | Apply the anonymisation transformation on a journal, if option is present
anonymiseByOpts :: CliOpts -> Journal -> Journal

View File

@ -93,3 +93,42 @@ hledger -f - register tag:foo=bar
>>>2
>>>=0
# 5. look for transactions without tags
hledger -f - print not:tag:.
<<<
2010/01/01 desc
a 1
b -1
2010/01/02
; foo:some tag
c 2
d -2
2010/01/03
e 3
f -3
2010/01/04 (code)
g 4
h -4
>>>
2010/01/01 desc
a 1
b -1
2010/01/03
e 3
f -3
2010/01/04 (code)
g 4
h -4
>>>=0
# 6. query is not affected by implicit tags
hledger -f ../../examples/sample.journal reg tag:d
>>>
>>>2
>>>=0

View File

@ -121,3 +121,16 @@ alias E=F
>>>2
>>>=0
# query will search both origin and substitution in alias
hledger -f- reg '^a$' '^b$'
<<<
alias a = b
1/1
a 1
b -1
>>>
2017/01/01 b 1 1
b -1 0
>>>2
>>>=0

View File

@ -38,3 +38,87 @@ hledger -f- --pivot budget bal --no-total
2 EUR assets:bank account
-2 EUR budget:Freifunk
>>>=0
# query on account will find either effective name or original one
hledger -f- --pivot TAG reg '^Account2$' '^TAG:fun$' not:hidden
<<<
2016/02/16 Test Transaction
Account1 2 EUR
; TAG: fun
Account2 -1 EUR
; TAG: value
Account2 -1 EUR
; TAG: hidden
>>>
2016/02/16 Test Transaction TAG:fun 2 EUR 2 EUR
TAG:value -1 EUR 1 EUR
>>>=0
# pivot for implicit tag desc (technical sample)
hledger -f- --pivot desc reg -M
<<<
2016/02/16 Freifunk
assets:bank account 2 EUR ; date:03/01
income:donations -2 EUR
>>>
2016/02 desc:Freifunk -2 EUR -2 EUR
2016/03 desc:Freifunk 2 EUR 0
>>>=0
# pivot for implicit tag code (technical sample)
hledger -f- --pivot code reg -M
<<<
2016/02/16 (Freifunk) Donation Freifunk
assets:bank account 2 EUR ; date:03/01
income:donations -2 EUR
>>>
2016/02 code:Freifunk -2 EUR -2 EUR
2016/03 code:Freifunk 2 EUR 0
>>>=0
# use of pivot with code-based budgeting
hledger -f- --pivot code reg ^income
<<<
2016/02/16 (Freifunk) Donation Freifunk
assets:bank account 2 EUR
income:donations -2 EUR
>>>
2016/02/16 Donation Freifunk code:Freifunk -2 EUR -2 EUR
>>>=0
# get expenses balance by description/payee
hledger -f- --pivot desc bal --no-total --flat ^expense
<<<
2016/02/16 (1138) Auchan
assets:bank account
expense:snacks 2 EUR
expense:grocery 20 EUR
2016/02/16 StarBars
assets:bank account
expense:coffee 5 EUR
>>>
22 EUR desc:Auchan
5 EUR desc:StarBars
>>>=0
# get daily expenses by description/payee
hledger -f- --pivot desc reg -D ^expense
<<<
2016/02/16 (1138) Auchan
assets:bank account
expense:snacks 2 EUR
expense:grocery 20 EUR
2016/02/16 StarBars
assets:bank account
expense:coffee 5 EUR
2016/02/17 (1139) Auchan
assets:bank account
expense:grocery 30 EUR
>>>
2016/02/16 desc:Auchan 22 EUR 22 EUR
desc:StarBars 5 EUR 27 EUR
2016/02/17 desc:Auchan 30 EUR 57 EUR
>>>=0