From 92e3e17214974e21d90a37e43427ea3681b5cf79 Mon Sep 17 00:00:00 2001 From: savanto Date: Mon, 30 Jun 2025 16:12:44 -0500 Subject: [PATCH] imp: pivot: Tag name shadowing field name takes precedence (#2169) Tags shadowing field names (eg. `payee`) take precedence during pivoting. For example, before this change, ``` 2025-01-01 CustA asset $100 ; payee:CustA asset $200 ; payee:CustB revenue ``` we expect `bal asset --pivot=payee` to produce: ``` $300 CustA -------------------- $300 ``` But after this change, we expect: ``` $100 CustA $200 CustB -------------------- $300 ``` More specific tags take precedence over less specific tags (ie. posting tags take precedence over transaction tags): ``` 2025-01-01 CustA ; payee:CustB asset $100 ; payee:CustA asset $200 ; payee:CustB revenue ``` still results in ``` $100 CustA $200 CustB -------------------- $300 ``` --- hledger-lib/Hledger/Data/Journal.hs | 3 ++- hledger/test/pivot.test | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/hledger-lib/Hledger/Data/Journal.hs b/hledger-lib/Hledger/Data/Journal.hs index 2d05de1139e..eb676b55f9a 100644 --- a/hledger-lib/Hledger/Data/Journal.hs +++ b/hledger-lib/Hledger/Data/Journal.hs @@ -1145,8 +1145,10 @@ pivotAccount fieldortagname p = -- "comm" and "cur" are accepted as synonyms meaning the commodity symbol. -- Pivoting on an unknown field or tag, or on commodity when there are multiple commodities, returns "". -- Pivoting on a tag when there are multiple values for that tag, returns the first value. +-- Pivoting on a tag name that shadows a field name gives precedence to the tag value. pivotComponent :: Text -> Posting -> Text pivotComponent fieldortagname p + | Just (_, tagvalue) <- postingFindTag fieldortagname p = tagvalue | fieldortagname == "code", Just t <- ptransaction p = tcode t | fieldortagname `elem` descnames, Just t <- ptransaction p = tdescription t | fieldortagname == "payee", Just t <- ptransaction p = transactionPayee t @@ -1156,7 +1158,6 @@ pivotComponent fieldortagname p | fieldortagname `elem` commnames = case map acommodity $ amounts $ pamount p of [s] -> s; _ -> unknown | fieldortagname == "amt" = case amounts $ pamount p of [a] -> T.pack $ show $ aquantity a; _ -> unknown | fieldortagname == "cost" = case amounts $ pamount p of [a@Amount{acost=Just _}] -> T.pack $ lstrip $ showAmountCost a; _ -> unknown - | Just (_, tagvalue) <- postingFindTag fieldortagname p = tagvalue | otherwise = unknown where descnames = ["desc", "description"] -- allow "description" for hledger <=1.30 compat diff --git a/hledger/test/pivot.test b/hledger/test/pivot.test index e4dae385bbe..0a422bf76ab 100644 --- a/hledger/test/pivot.test +++ b/hledger/test/pivot.test @@ -207,3 +207,28 @@ Balance changes in 2025: @ $100 || 2 B --------++----------------- || $-210, 1 A, 2 B + +# ** 18. When tag shadows field, tag takes precedence. +< +2025-01-01 CustA ; payee:CustB + asset $100 + asset $200 + revenue $-300 + +$ hledger -f- bal asset --pivot=payee + $300 CustB +-------------------- + $300 + +# ** 19. More specific tag takes precedence over less specific (ie. posting tag precedes transaction tag). +< +2025-01-01 CustA ; payee:CustB + asset $100 ; payee:CustA + asset $200 ; payee:CustB + revenue $-300 + +$ hledger -f- bal asset --pivot=payee + $100 CustA + $200 CustB +-------------------- + $300