mirror of
https://github.com/simonmichael/hledger.git
synced 2024-11-07 21:15:19 +03:00
feat:print: add --round option for more control of precisions (#2085)
This commit is contained in:
parent
c7bcdfcdcf
commit
5a72b9e9ea
@ -324,7 +324,7 @@ journalFinalise iopts@InputOpts{..} f txt pj = do
|
||||
& journalAddFile (f, txt) -- save the main file's info
|
||||
& journalReverse -- convert all lists to the order they were parsed
|
||||
& journalAddAccountTypes -- build a map of all known account types
|
||||
& journalStyleAmounts -- Infer and apply commodity styles - should be done early
|
||||
& journalStyleAmounts -- Infer and apply commodity styles (but don't round) - should be done early
|
||||
<&> journalAddForecast (verbose_tags_) (forecastPeriod iopts pj) -- Add forecast transactions if enabled
|
||||
<&> journalPostingsAddAccountTags -- Add account tags to postings, so they can be matched by auto postings.
|
||||
>>= (if auto_ && not (null $ jtxnmodifiers pj)
|
||||
|
@ -16,7 +16,7 @@ module Hledger.Cli.Commands.Print (
|
||||
where
|
||||
|
||||
|
||||
import Data.List (intersperse)
|
||||
import Data.List (intersperse, intercalate)
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.Lazy as TL
|
||||
import qualified Data.Text.Lazy.Builder as TB
|
||||
@ -28,20 +28,32 @@ import Hledger.Read.CsvUtils (CSV, printCSV)
|
||||
import Hledger.Cli.CliOptions
|
||||
import Hledger.Cli.Utils
|
||||
import System.Exit (exitFailure)
|
||||
import qualified Data.Map as M (map)
|
||||
import Safe (lastMay)
|
||||
|
||||
|
||||
printmode = hledgerCommandMode
|
||||
$(embedFileRelative "Hledger/Cli/Commands/Print.txt")
|
||||
([let arg = "DESC" in
|
||||
flagReq ["match","m"] (\s opts -> Right $ setopt "match" s opts) arg
|
||||
("fuzzy search for one recent transaction with description closest to "++arg)
|
||||
,flagNone ["explicit","x"] (setboolopt "explicit")
|
||||
([flagNone ["explicit","x"] (setboolopt "explicit")
|
||||
"show all amounts explicitly"
|
||||
,flagNone ["show-costs"] (setboolopt "show-costs")
|
||||
"show transaction prices even with conversion postings"
|
||||
,flagReq ["round"] (\s opts -> Right $ setopt "round" s opts) "TYPE" $
|
||||
intercalate "\n"
|
||||
["how much rounding or padding should be done when displaying amounts ?"
|
||||
,"none - show original decimal digits,"
|
||||
," as in journal"
|
||||
,"soft - just add or remove decimal zeros"
|
||||
," to match precision (default)"
|
||||
,"hard - round posting amounts to precision"
|
||||
," (can unbalance transactions)"
|
||||
,"all - also round cost amounts to precision"
|
||||
," (can unbalance transactions)"
|
||||
]
|
||||
,flagNone ["new"] (setboolopt "new")
|
||||
"show only newer-dated transactions added in each file since last run"
|
||||
,let arg = "DESC" in
|
||||
flagReq ["match","m"] (\s opts -> Right $ setopt "match" s opts) arg
|
||||
("fuzzy search for one recent transaction with description closest to "++arg)
|
||||
,outputFormatFlag ["txt","csv","json","sql"]
|
||||
,outputFileFlag
|
||||
])
|
||||
@ -49,6 +61,18 @@ printmode = hledgerCommandMode
|
||||
hiddenflags
|
||||
([], Just $ argsFlag "[QUERY]")
|
||||
|
||||
-- | Get the --round option's value, if any. Can fail with a parse error.
|
||||
roundFromRawOpts :: RawOpts -> Maybe Rounding
|
||||
roundFromRawOpts = lastMay . collectopts roundfromrawopt
|
||||
where
|
||||
roundfromrawopt (n,v)
|
||||
| n=="round", v=="none" = Just NoRounding
|
||||
| n=="round", v=="soft" = Just SoftRounding
|
||||
| n=="round", v=="hard" = Just HardRounding
|
||||
| n=="round", v=="all" = Just AllRounding
|
||||
| n=="round" = error' $ "--round's value should be none, soft, hard or all; got: "++v
|
||||
| otherwise = Nothing
|
||||
|
||||
-- | Print journal transactions in standard format.
|
||||
print' :: CliOpts -> Journal -> IO ()
|
||||
print' opts j = do
|
||||
@ -69,16 +93,22 @@ print' opts j = do
|
||||
Nothing -> putStrLn "no matches found." >> exitFailure
|
||||
|
||||
printEntries :: CliOpts -> Journal -> IO ()
|
||||
printEntries opts@CliOpts{reportspec_=rspec} j =
|
||||
printEntries opts@CliOpts{rawopts_=rawopts, reportspec_=rspec} j =
|
||||
writeOutputLazyText opts $ render $ entriesReport rspec j
|
||||
where
|
||||
stylesnorounding = M.map (amountStyleSetRounding NoRounding) $ journalCommodityStyles j
|
||||
stylessoftrounding = M.map (amountStyleSetRounding SoftRounding) $ journalCommodityStyles j
|
||||
-- print does user-specified rounding or (by default) no rounding, in all output formats
|
||||
styles =
|
||||
case roundFromRawOpts rawopts of
|
||||
Nothing -> styles0
|
||||
Just NoRounding -> styles0
|
||||
Just r -> amountStylesSetRounding r styles0
|
||||
where styles0 = journalCommodityStyles j
|
||||
|
||||
fmt = outputFormatFromOpts opts
|
||||
render | fmt=="txt" = entriesReportAsText opts . styleAmounts stylesnorounding
|
||||
| fmt=="csv" = printCSV . entriesReportAsCsv . styleAmounts stylessoftrounding
|
||||
| fmt=="json" = toJsonText . styleAmounts stylessoftrounding
|
||||
| fmt=="sql" = entriesReportAsSql . styleAmounts stylessoftrounding
|
||||
render | fmt=="txt" = entriesReportAsText opts . styleAmounts styles
|
||||
| fmt=="csv" = printCSV . entriesReportAsCsv . styleAmounts styles
|
||||
| fmt=="json" = toJsonText . styleAmounts styles
|
||||
| fmt=="sql" = entriesReportAsSql . styleAmounts styles
|
||||
| otherwise = error' $ unsupportedOutputFormatError fmt -- PARTIAL:
|
||||
|
||||
entriesReportAsText :: CliOpts -> EntriesReport -> TL.Text
|
||||
|
@ -4,31 +4,19 @@ Show transaction journal entries, sorted by date.
|
||||
|
||||
_FLAGS
|
||||
|
||||
The print command displays full journal entries (transactions) from
|
||||
the journal file, sorted by date
|
||||
The print command displays full journal entries (transactions)
|
||||
from the journal file, sorted by date
|
||||
(or with `--date2`, by [secondary date](#secondary-dates)).
|
||||
|
||||
Amounts are shown mostly normalised to
|
||||
[commodity display style](#commodity-display-styles),
|
||||
eg the placement of commodity symbols will be consistent.
|
||||
All of their decimal places are shown, as in the original journal entry
|
||||
(with one alteration: in some cases trailing zeroes are added.)
|
||||
|
||||
Amounts are shown right-aligned within each transaction (but not across all transactions).
|
||||
|
||||
Directives and inter-transaction comments are not shown, currently.
|
||||
This means the print command is somewhat lossy, and if you are using it to
|
||||
reformat your journal you should take care to also copy over the directives
|
||||
and file-level comments.
|
||||
reformat/regenerate your journal you should take care to also copy over
|
||||
the directives and inter-transaction comments.
|
||||
|
||||
Eg:
|
||||
|
||||
```shell
|
||||
$ hledger print
|
||||
2008/01/01 income
|
||||
assets:bank:checking $1
|
||||
income:salary $-1
|
||||
|
||||
$ hledger print -f examples/sample.journal date:200806
|
||||
2008/06/01 gift
|
||||
assets:bank:checking $1
|
||||
income:gifts $-1
|
||||
@ -42,12 +30,55 @@ $ hledger print
|
||||
expenses:supplies $1
|
||||
assets:cash $-2
|
||||
|
||||
2008/12/31 * pay off
|
||||
liabilities:debts $1
|
||||
assets:bank:checking $-1
|
||||
```
|
||||
|
||||
print's output is usually a valid [hledger journal](https://hledger.org/hledger.html), and you can process it again with a second hledger command. This can be useful for certain kinds of search, eg:
|
||||
### print explicitness
|
||||
|
||||
Normally, whether posting amounts are implicit or explicit is preserved.
|
||||
For example, when an amount is omitted in the journal, it will not appear in the output.
|
||||
Similarly, if a conversion cost is implied but not written, it will not appear in the output.
|
||||
|
||||
You can use the `-x`/`--explicit` flag to force explicit display of all amounts and costs.
|
||||
This can be useful for troubleshooting or for making your journal more readable and
|
||||
robust against data entry errors.
|
||||
`-x` is also implied by using any of `-B`,`-V`,`-X`,`--value`.
|
||||
|
||||
The `-x`/`--explicit` flag will cause any postings with a multi-commodity amount
|
||||
(which can arise when a multi-commodity transaction has an implicit amount)
|
||||
to be split into multiple single-commodity postings,
|
||||
keeping the output parseable.
|
||||
|
||||
|
||||
### print amount style
|
||||
|
||||
Amounts are shown right-aligned within each transaction
|
||||
(but not aligned across all transactions; you can do that with ledger-mode in Emacs).
|
||||
|
||||
Amounts will be (mostly) normalised to their [commodity display style](#commodity-display-styles):
|
||||
their symbol placement, decimal mark, and digit group marks will be made consistent.
|
||||
By default, decimal digits are shown as they are written in the journal.
|
||||
|
||||
With the `--round` option, `print` will try increasingly hard to
|
||||
display decimal digits according to the [commodity display styles](#commodity-display-style):
|
||||
|
||||
- `--round=none` show amounts with original precisions (default)
|
||||
- `--round=soft` add/remove decimal zeros in amounts (except costs)
|
||||
- `--round=hard` round amounts (except costs), possibly hiding significant digits
|
||||
- `--round=all` round all amounts and costs
|
||||
|
||||
`soft` is good for non-lossy cleanup, formatting amounts more
|
||||
consistently where it's safe to do so.
|
||||
|
||||
`hard` and `all` can cause `print` to show invalid unbalanced journal entries;
|
||||
they may be useful eg for journal cleanup, with manual fixups where needed.
|
||||
|
||||
|
||||
### print parseability
|
||||
|
||||
print's output is usually a valid [hledger journal](#journal),
|
||||
and you can process it again with a second hledger command.
|
||||
This can be useful for certain kinds of search
|
||||
(though the same can be achieved with `expr:` queries now):
|
||||
|
||||
```shell
|
||||
# Show running total of food expenses paid from cash.
|
||||
@ -61,31 +92,24 @@ There are some situations where print's output can become unparseable:
|
||||
- [Auto postings](#auto-postings) can generate postings with [too many missing amounts](https://github.com/simonmichael/hledger/issues/1276).
|
||||
- [Account aliases can generate bad account names](#aliases-can-generate-bad-account-names).
|
||||
|
||||
Normally, the journal entry's explicit or implicit amount style is preserved.
|
||||
For example, when an amount is omitted in the journal, it will not appear in the output.
|
||||
Similarly, when a cost is implied but not written, it will not appear in the output.
|
||||
You can use the `-x`/`--explicit` flag to make all amounts and costs explicit,
|
||||
which can be useful for troubleshooting or for making your journal more readable and
|
||||
robust against data entry errors.
|
||||
`-x` is also implied by using any of `-B`,`-V`,`-X`,`--value`.
|
||||
|
||||
Note, `-x`/`--explicit` will cause postings with a multi-commodity amount
|
||||
(these can arise when a multi-commodity transaction has an implicit amount)
|
||||
to be split into multiple single-commodity postings,
|
||||
keeping the output parseable.
|
||||
### print, other features
|
||||
|
||||
With `-B`/`--cost`, amounts with [costs](https://hledger.org/hledger.html#costs)
|
||||
are converted to cost using that price. This can be used for troubleshooting.
|
||||
are shown converted to cost.
|
||||
|
||||
With `-m DESC`/`--match=DESC`, print does a fuzzy search for one recent transaction
|
||||
With `--new`, print shows only transactions it has not seen on a previous run.
|
||||
This uses the same deduplication system as the [`import`](#import) command.
|
||||
(See import's docs for details.)
|
||||
|
||||
With `-m DESC`/`--match=DESC`, print shows one recent transaction
|
||||
whose description is most similar to DESC.
|
||||
DESC should contain at least two characters.
|
||||
If there is no similar-enough match,
|
||||
no transaction will be shown and the program exit code will be non-zero.
|
||||
|
||||
With `--new`, hledger prints only transactions it has not seen on a previous run.
|
||||
This uses the same deduplication system as the [`import`](#import) command.
|
||||
(See import's docs for details.)
|
||||
|
||||
### print output format
|
||||
|
||||
This command also supports the
|
||||
[output destination](hledger.html#output-destination) and
|
||||
|
@ -14,7 +14,7 @@ $ mkdir -p b/c/d ; printf '2010/1/1\n (D) 1\n' >b/c/d/d.journal ; printf '2010
|
||||
|
||||
>= 0
|
||||
|
||||
# 2. including other formats
|
||||
# 2. Including other formats.
|
||||
<
|
||||
2016/1/1
|
||||
(x) 1
|
||||
|
@ -111,7 +111,7 @@ P 2000/1/1 $ €1.20
|
||||
|
||||
$ hledger -f- print -V
|
||||
2000-01-01
|
||||
(a) €120.00 = $100
|
||||
(a) €120 = $100
|
||||
|
||||
>=0
|
||||
|
||||
|
@ -25,7 +25,8 @@ $ hledger -f- reg --output-format=json
|
||||
"ascommodityspaced": true,
|
||||
"asdecimalmark": ".",
|
||||
"asdigitgroups": null,
|
||||
"asprecision": 1
|
||||
"asprecision": 1,
|
||||
"asrounding": "HardRounding"
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -53,7 +54,8 @@ $ hledger -f- reg --output-format=json
|
||||
"ascommodityspaced": true,
|
||||
"asdecimalmark": ".",
|
||||
"asdigitgroups": null,
|
||||
"asprecision": 1
|
||||
"asprecision": 1,
|
||||
"asrounding": "HardRounding"
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -82,7 +84,8 @@ $ hledger -f- bal --output-format=json
|
||||
"ascommodityspaced": true,
|
||||
"asdecimalmark": ".",
|
||||
"asdigitgroups": null,
|
||||
"asprecision": 1
|
||||
"asprecision": 1,
|
||||
"asrounding": "HardRounding"
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -102,7 +105,8 @@ $ hledger -f- bal --output-format=json
|
||||
"ascommodityspaced": true,
|
||||
"asdecimalmark": ".",
|
||||
"asdigitgroups": null,
|
||||
"asprecision": 1
|
||||
"asprecision": 1,
|
||||
"asrounding": "HardRounding"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1,41 +1,95 @@
|
||||
# print amount styling tests
|
||||
#
|
||||
# The amounts are:
|
||||
# amt - the posting amount
|
||||
# cost - the posting amount's cost
|
||||
# bal - the balance assertion amount
|
||||
# balcost - the balance assertion amount's cost
|
||||
# Here's an overview of historical behaviour.
|
||||
# See the tests below for examples.
|
||||
#
|
||||
# Styling includes:
|
||||
# basic - everything except precision
|
||||
# prec - precision (number of decimal places)
|
||||
# print shows four kinds of amount:
|
||||
# amt - posting amount
|
||||
# cost - posting amount's cost
|
||||
# bal - balance assertion/assignment amount
|
||||
# balcost - balance assertion/assignment amount's cost
|
||||
#
|
||||
# Historical behaviour:
|
||||
# | hledger | amt basic | cost basic | bal basic | balcost basic | amt prec | cost prec | bal prec | balcost prec |
|
||||
# | 1.14 | Y | N | N | N | Y | N | N | N |
|
||||
# | 1.22 | Y | N | Y | N | N | N | N | N |
|
||||
# | 1.30 | Y | Y | Y | N | N | N | N | N |
|
||||
# | 1.31 | Y | Y | Y | Y | N | N | N | N |
|
||||
#
|
||||
# In the following,
|
||||
# basic styling will move the commodity symbol to the left
|
||||
# precision styling will hide the decimal place
|
||||
# Which amounts does print do basic styling (eg symbol placement) on ?
|
||||
#
|
||||
# | hledger | amt | cost | bal | balcost |
|
||||
# |-----------|-----|------|-----|---------|
|
||||
# | 1.1-1.14 | Y | N | N | N |
|
||||
# | 1.15-1.22 | Y | N | Y | N |
|
||||
# | 1.23-1.30 | Y | Y | Y | N |
|
||||
# | | | | | |
|
||||
# | 1.31- | Y | Y | Y | Y |
|
||||
#
|
||||
# Which kind of rounding does print do on each amount ?
|
||||
#
|
||||
# | hledger | amt | cost | bal | balcost |
|
||||
# |---------------------|------|------|------|---------|
|
||||
# | 1.0-1.20 | hard | none | none | none |
|
||||
# | 1.21-1.30 | soft | none | none | none |
|
||||
# | 1.31 | none | none | none | none |
|
||||
# | | | | | |
|
||||
# | 1.31.1 | none | none | none | none |
|
||||
# | 1.31.1 --round=soft | soft | none | soft | none |
|
||||
# | 1.31.1 --round=hard | hard | none | hard | none |
|
||||
# | 1.31.1 --round=all | hard | hard | hard | hard |
|
||||
|
||||
# 1. print styles all amounts, but leaves all precisions unchanged, even with -c.
|
||||
|
||||
# Four print style tests. In these, basic styling is applied
|
||||
# to all amounts (the commodity symbol moves to the left),
|
||||
# and precision styling is applied as described below.
|
||||
<
|
||||
commodity A 1000.
|
||||
commodity B 1000.
|
||||
; A and B styles
|
||||
commodity A1000.00
|
||||
commodity B1000.00
|
||||
|
||||
; a amounts have 1 significant digit
|
||||
; b amounts have 1 significant digit and 2 zeros
|
||||
; c amounts have 3 significant digits
|
||||
2023-01-01
|
||||
(a) 1.2 A @ 3.4 B = 1.2 A @ 3.4 B
|
||||
|
||||
$ hledger -f- print -c A1000.00 -c B1000.00
|
||||
(a) 0.1 A @ 0.1 B = 0.1 A @ 0.1 B
|
||||
(b) 0.100 A @ 0.100 B = 0.100 A @ 0.100 B
|
||||
(c) 0.123 A @ 0.123 B = 0.123 A @ 0.123 B
|
||||
|
||||
# 1. By default, print shows all amounts with original precisions
|
||||
# (like 1.31)
|
||||
$ hledger -f- print
|
||||
2023-01-01
|
||||
(a) A1.2 @ B3.4 = A1.2 @ B3.4
|
||||
(a) A0.1 @ B0.1 = A0.1 @ B0.1
|
||||
(b) A0.100 @ B0.100 = A0.100 @ B0.100
|
||||
(c) A0.123 @ B0.123 = A0.123 @ B0.123
|
||||
|
||||
>=
|
||||
|
||||
# 2. Precisions are also preserved when there's an implicit conversion (#2079).
|
||||
# 2. With --round=soft, print adds/removes zeros in non-cost amounts
|
||||
# (like 1.30 but more thorough, also affects balance assertion amounts,
|
||||
# also does basic styling of balance assertion costs)
|
||||
$ hledger -f- print --round=soft
|
||||
2023-01-01
|
||||
(a) A0.10 @ B0.1 = A0.10 @ B0.1
|
||||
(b) A0.10 @ B0.100 = A0.10 @ B0.100
|
||||
(c) A0.123 @ B0.123 = A0.123 @ B0.123
|
||||
|
||||
>=
|
||||
|
||||
# 3. With --round=hard, print rounds non-cost amounts.
|
||||
$ hledger -f- print --round=hard
|
||||
2023-01-01
|
||||
(a) A0.10 @ B0.1 = A0.10 @ B0.1
|
||||
(b) A0.10 @ B0.100 = A0.10 @ B0.100
|
||||
(c) A0.12 @ B0.123 = A0.12 @ B0.123
|
||||
|
||||
>=
|
||||
|
||||
# 4. with --round=all, print rounds all amounts.
|
||||
$ hledger -f- print --round=all
|
||||
2023-01-01
|
||||
(a) A0.10 @ B0.10 = A0.10 @ B0.10
|
||||
(b) A0.10 @ B0.10 = A0.10 @ B0.10
|
||||
(c) A0.12 @ B0.12 = A0.12 @ B0.12
|
||||
|
||||
>=
|
||||
|
||||
# 5. print also preserves precisions when there's an implicit conversion
|
||||
# (unlike 1.30, #2079).
|
||||
<
|
||||
commodity A 1000.
|
||||
|
||||
@ -52,29 +106,7 @@ $ hledger -f- print
|
||||
|
||||
>=
|
||||
|
||||
|
||||
# Maybe later:
|
||||
|
||||
# # 0. With print, -c has extra power: it can increase all amount precisions.
|
||||
# $ hledger -f- print -c A1000.00 -c B1000.00
|
||||
# 2023-01-01
|
||||
# (a) A1.20 @ B3.40 = A1.20 @ B3.40
|
||||
#
|
||||
# >=
|
||||
#
|
||||
# # 0. And -c can decrease trailing decimal zeros. But not significant decimal digits
|
||||
# (because that would change transactions).
|
||||
# <
|
||||
# 2023-01-01
|
||||
# (a) 1.2340 A @ 3.4560 B = 1.234 A @ 3.456 B
|
||||
#
|
||||
# $ hledger -f- print -c A1000. -c B1000.
|
||||
# 2023-01-01
|
||||
# (a) A1.234 @ B3.456 = A1.234 @ B3.456
|
||||
#
|
||||
# >=
|
||||
|
||||
# 3. When showing digit group marks, print always shows a decimal mark as well,
|
||||
# 6. When showing digit group marks, print always shows a decimal mark as well,
|
||||
# even when no decimal digits are shown.
|
||||
<
|
||||
decimal-mark .
|
||||
@ -87,3 +119,25 @@ $ hledger -f- print
|
||||
|
||||
>=
|
||||
|
||||
# 7. print shows zeros with a commodity symbol and decimal digits when possible.
|
||||
# This also means that "multi-commodity zeros" are shown more verbosely.
|
||||
<
|
||||
2023-01-01
|
||||
a A 0.00
|
||||
b B 0.00
|
||||
c
|
||||
|
||||
2023-01-02
|
||||
d
|
||||
|
||||
$ hledger -f- print -x
|
||||
2023-01-01
|
||||
a A 0.00
|
||||
b B 0.00
|
||||
c A 0.00
|
||||
c B 0.00
|
||||
|
||||
2023-01-02
|
||||
d 0
|
||||
|
||||
>=
|
Loading…
Reference in New Issue
Block a user