From e98af39e278cf1c54ec31138efefff7e909ead26 Mon Sep 17 00:00:00 2001 From: Simon Michael Date: Wed, 15 Jan 2025 13:22:49 -1000 Subject: [PATCH] imp:pivot: support pivoting on amount (quantity) or cost --- hledger-lib/Hledger/Data/Journal.hs | 33 +++++++++++---------- hledger/hledger.m4.md | 11 +++---- hledger/test/pivot.test | 45 ++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 28 deletions(-) diff --git a/hledger-lib/Hledger/Data/Journal.hs b/hledger-lib/Hledger/Data/Journal.hs index ca85d6584..8e34088b9 100644 --- a/hledger-lib/Hledger/Data/Journal.hs +++ b/hledger-lib/Hledger/Data/Journal.hs @@ -1164,24 +1164,27 @@ pivotAccount :: Text -> Posting -> Text pivotAccount fieldortagname p = T.intercalate ":" [pivotComponent x p | x <- T.splitOn ":" fieldortagname] --- | Get the value of the given field or tag for this posting, otherwise the empty string. +-- | Get the value of the given field or tag for this posting. -- "comm" and "cur" are accepted as synonyms meaning the commodity symbol. --- We currently don't handle pivoting of a posting with more than one commodity symbol; in that case we return "". +-- 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. pivotComponent :: Text -> Posting -> Text pivotComponent fieldortagname p - | fieldortagname == "acct" = paccount p - | fieldortagname `elem` ["cur","comm"] = - case map acommodity $ amounts $ pamount p of - [s] -> s - _ -> "" - | Just t <- ptransaction p, fieldortagname == "code" = tcode t - | Just t <- ptransaction p, fieldortagname == "desc" = tdescription t - | Just t <- ptransaction p, fieldortagname == "description" = tdescription t -- backward compatible with 1.30 and older - | Just t <- ptransaction p, fieldortagname == "payee" = transactionPayee t - | Just t <- ptransaction p, fieldortagname == "note" = transactionNote t - | Just t <- ptransaction p, fieldortagname == "status" = T.pack . show . tstatus $ t - | Just (_, value) <- postingFindTag fieldortagname p = value - | otherwise = "" + | 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 + | fieldortagname == "note", Just t <- ptransaction p = transactionNote t + | fieldortagname == "status", Just t <- ptransaction p = T.pack . show . tstatus $ t + | fieldortagname == "acct" = paccount 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 $ showAmountCost a; _ -> unknown + | Just (_, tagvalue) <- postingFindTag fieldortagname p = tagvalue + | otherwise = unknown + where + descnames = ["desc", "description"] -- allow "description" for hledger <=1.30 compat + commnames = ["cur","comm"] -- allow either; cur is the query prefix, comm is more consistent + unknown = "" postingFindTag :: TagName -> Posting -> Maybe (TagName, TagValue) postingFindTag tagname p = find ((tagname==) . fst) $ postingAllTags p diff --git a/hledger/hledger.m4.md b/hledger/hledger.m4.md index 927d0bdf6..9c6f8c1a3 100644 --- a/hledger/hledger.m4.md +++ b/hledger/hledger.m4.md @@ -5377,18 +5377,19 @@ Normally, hledger groups amounts and displays their totals by account (name). With `--pivot PIVOTEXPR`, some other field's (or multiple fields') value is used as a synthetic account name, causing different grouping and display. PIVOTEXPR can be -- any of these standard transaction or posting fields (their value is substituted): `status`, `code`, `desc`, `payee`, `note`, `acct`, `comm`/`cur` +- any of these standard transaction or posting fields (their value is substituted): `status`, `code`, `desc`, `payee`, `note`, `acct`, `comm`/`cur`, `amt`, `cost` - or a tag name - or any combination of these, colon-separated. Some special cases: -- Colons, in PIVOTEXPR or in a pivoted tag value, will appear in the generated account name, influencing the account tree. -- When an unrecognised tag name or field is provided, its pivoted value will be "". -- When a posting has multiple commodities, the pivoted value of "comm"/"cur" will be "". +- Colons appearing in PIVOTEXPR or in a pivoted tag value will generate account hierarchy. - When pivoting a posting has multiple values for a tag, the pivoted value of that tag will be the first value. +- When a posting has multiple commodities, the pivoted value of "comm"/"cur" will be "". + Also when an unrecognised tag name or field is provided, its pivoted value will be "". + (If this causes confusing output, consider excluding those postings from the report.) -For example: +Examples: ```journal 2016/02/16 Yearly Dues Payment diff --git a/hledger/test/pivot.test b/hledger/test/pivot.test index fcbd0497a..e34b53b28 100644 --- a/hledger/test/pivot.test +++ b/hledger/test/pivot.test @@ -158,23 +158,52 @@ Balance changes in 2025: || -1 A, -2 B # ** 14. When commodities are being converted, the original commodity is shown. +< +2025-01-01 + expenses 1 A @ $10 + expenses 2 B @ $100 + assets + $ hledger -f- bal -Y expenses --pivot=comm -B Balance changes in 2025, converted to cost: || 2025 ===++====== - A || $1 - B || $2 + A || $10 + B || $200 ---++------ - || $3 + || $210 # ** 15. The "" bucket looks a bit strange in this case.. $ hledger -f- bal -Y assets --pivot=comm -B Balance changes in 2025, converted to cost: - || 2025 -===++====== - $ || $-3 ----++------ - || $-3 + || 2025 +===++======= + $ || $-210 +---++------- + || $-210 +# ** 16. Pivot on amount. +$ hledger -f- bal -Y --pivot=amt +Balance changes in 2025: + + || 2025 +======++================= + -210 || $-210 + 1 || 1 A + 2 || 2 B +------++----------------- + || $-210, 1 A, 2 B + +# ** 17. Pivot on cost. +$ hledger -f- bal -Y --pivot=cost +Balance changes in 2025: + + || 2025 +=========++================= + || $-210 + @ $10 || 1 A + @ $100 || 2 B +---------++----------------- + || $-210, 1 A, 2 B