imp:pivot: support pivoting on amount (quantity) or cost

This commit is contained in:
Simon Michael 2025-01-15 13:22:49 -10:00
parent e7e0b5c868
commit e98af39e27
3 changed files with 61 additions and 28 deletions

View File

@ -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

View File

@ -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

View File

@ -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