imp:print: zero posting amounts are now shown with commodity & style
print now shows zero posting amounts with their original commodity symbol and the corresponding style (instead of stripping the symbol). If an inferred amount has multiple zeroes in different commodities, a posting is displayed for each of these. Possible breaking changes: showMixedAmountLinesB, showAmountB, showAmountPrice now preserve commodityful zeroes when rendering. This is intended to improve print output, but it seems possible it might also affect balance and register reports, though our tests show no change in those.
This commit is contained in:
parent
35c0fd692c
commit
ff730f775b
@ -102,6 +102,7 @@ module Hledger.Data.Amount (
|
||||
maAddAmounts,
|
||||
amounts,
|
||||
amountsRaw,
|
||||
amountsPreservingZeros,
|
||||
maCommodities,
|
||||
filterMixedAmount,
|
||||
filterMixedAmountByCommodity,
|
||||
@ -170,6 +171,7 @@ import Hledger.Data.Types
|
||||
import Hledger.Utils (colorB, numDigitsInt)
|
||||
import Hledger.Utils.Text (textQuoteIfNeeded)
|
||||
import Text.WideString (WideBuilder(..), wbFromText, wbToText, wbUnpack)
|
||||
import Data.Functor ((<&>))
|
||||
|
||||
|
||||
-- A 'Commodity' is a symbol representing a currency or some other kind of
|
||||
@ -208,10 +210,10 @@ data AmountDisplayOpts = AmountDisplayOpts
|
||||
, displayOrder :: Maybe [CommoditySymbol]
|
||||
} deriving (Show)
|
||||
|
||||
-- | Display Amount and MixedAmount with no colour.
|
||||
-- | By default, display Amount and MixedAmount using @noColour@ amount display options.
|
||||
instance Default AmountDisplayOpts where def = noColour
|
||||
|
||||
-- | Display Amount and MixedAmount with no colour.
|
||||
-- | Display amounts without colour, and with various other defaults.
|
||||
noColour :: AmountDisplayOpts
|
||||
noColour = AmountDisplayOpts { displayPrice = True
|
||||
, displayColour = False
|
||||
@ -406,8 +408,8 @@ amountStripPrices a = a{aprice=Nothing}
|
||||
showAmountPrice :: Amount -> WideBuilder
|
||||
showAmountPrice amt = case aprice amt of
|
||||
Nothing -> mempty
|
||||
Just (UnitPrice pa) -> WideBuilder (TB.fromString " @ ") 3 <> showAmountB noColour pa
|
||||
Just (TotalPrice pa) -> WideBuilder (TB.fromString " @@ ") 4 <> showAmountB noColour (sign pa)
|
||||
Just (UnitPrice pa) -> WideBuilder (TB.fromString " @ ") 3 <> showAmountB noColour{displayZeroCommodity=True} pa
|
||||
Just (TotalPrice pa) -> WideBuilder (TB.fromString " @@ ") 4 <> showAmountB noColour{displayZeroCommodity=True} (sign pa)
|
||||
where sign = if aquantity amt < 0 then negate else id
|
||||
|
||||
showAmountPriceDebug :: Maybe AmountPrice -> String
|
||||
@ -460,14 +462,16 @@ showAmountB :: AmountDisplayOpts -> Amount -> WideBuilder
|
||||
showAmountB _ Amount{acommodity="AUTO"} = mempty
|
||||
showAmountB opts a@Amount{astyle=style} =
|
||||
color $ case ascommodityside style of
|
||||
L -> showC (wbFromText c) space <> quantity' <> price
|
||||
R -> quantity' <> showC space (wbFromText c) <> price
|
||||
L -> showC (wbFromText comm) space <> quantity' <> price
|
||||
R -> quantity' <> showC space (wbFromText comm) <> price
|
||||
where
|
||||
color = if displayColour opts && isNegativeAmount a then colorB Dull Red else id
|
||||
quantity = showamountquantity $ if displayThousandsSep opts then a else a{astyle=(astyle a){asdigitgroups=Nothing}}
|
||||
(quantity',c) | amountLooksZero a && not (displayZeroCommodity opts) = (WideBuilder (TB.singleton '0') 1,"")
|
||||
| otherwise = (quantity, quoteCommoditySymbolIfNeeded $ acommodity a)
|
||||
space = if not (T.null c) && ascommodityspaced style then WideBuilder (TB.singleton ' ') 1 else mempty
|
||||
quantity = showamountquantity $
|
||||
if displayThousandsSep opts then a else a{astyle=(astyle a){asdigitgroups=Nothing}}
|
||||
(quantity', comm)
|
||||
| amountLooksZero a && not (displayZeroCommodity opts) = (WideBuilder (TB.singleton '0') 1, "")
|
||||
| otherwise = (quantity, quoteCommoditySymbolIfNeeded $ acommodity a)
|
||||
space = if not (T.null comm) && ascommodityspaced style then WideBuilder (TB.singleton ' ') 1 else mempty
|
||||
-- concatenate these texts,
|
||||
-- or return the empty text if there's a commodity display order. XXX why ?
|
||||
showC l r = if isJust (displayOrder opts) then mempty else l <> r
|
||||
@ -672,7 +676,8 @@ maIsZero = mixedAmountIsZero
|
||||
maIsNonZero :: MixedAmount -> Bool
|
||||
maIsNonZero = not . mixedAmountIsZero
|
||||
|
||||
-- | Get a mixed amount's component amounts.
|
||||
-- | Get a mixed amount's component amounts, with some cleanups.
|
||||
-- The following descriptions are old and possibly wrong:
|
||||
--
|
||||
-- * amounts in the same commodity are combined unless they have different prices or total prices
|
||||
--
|
||||
@ -686,13 +691,37 @@ maIsNonZero = not . mixedAmountIsZero
|
||||
--
|
||||
amounts :: MixedAmount -> [Amount]
|
||||
amounts (Mixed ma)
|
||||
| isMissingMixedAmount (Mixed ma) = [missingamt] -- missingamt should always be alone, but detect it even if not
|
||||
| isMissingMixedAmount (Mixed ma) = [missingamt]
|
||||
| M.null nonzeros = [newzero]
|
||||
| otherwise = toList nonzeros
|
||||
where
|
||||
newzero = fromMaybe nullamt $ find (not . T.null . acommodity) zeros
|
||||
(zeros, nonzeros) = M.partition amountIsZero ma
|
||||
|
||||
-- | Get a mixed amount's component amounts, with some cleanups.
|
||||
-- This is a new version of @amounts@, with updated descriptions
|
||||
-- and optimised for @print@ to show commodityful zeros.
|
||||
--
|
||||
-- * If it contains the "missing amount" marker, only that is returned
|
||||
-- (discarding any additional amounts).
|
||||
--
|
||||
-- * Or if it contains any non-zero amounts, only those are returned
|
||||
-- (discarding any zeroes).
|
||||
--
|
||||
-- * Or if it contains any zero amounts (possibly more than one,
|
||||
-- possibly in different commodities), all of those are returned.
|
||||
--
|
||||
-- * Otherwise the null amount is returned.
|
||||
--
|
||||
amountsPreservingZeros :: MixedAmount -> [Amount]
|
||||
amountsPreservingZeros (Mixed ma)
|
||||
| isMissingMixedAmount (Mixed ma) = [missingamt]
|
||||
| not $ M.null nonzeros = toList nonzeros
|
||||
| not $ M.null zeros = toList zeros
|
||||
| otherwise = [nullamt]
|
||||
where
|
||||
(zeros, nonzeros) = M.partition amountIsZero ma
|
||||
|
||||
-- | Get a mixed amount's component amounts without normalising zero and missing
|
||||
-- amounts. This is used for JSON serialisation, so the order is important. In
|
||||
-- particular, we want the Amounts given in the order of the MixedAmountKeys,
|
||||
@ -913,11 +942,12 @@ showMixedAmountOneLineB opts@AmountDisplayOpts{displayMaxWidth=mmax,displayMinWi
|
||||
-- Add the elision strings (if any) to each amount
|
||||
withElided = zipWith (\n2 amt -> (amt, elisionDisplay Nothing (wbWidth sep) n2 amt)) [n-1,n-2..0]
|
||||
|
||||
-- Get a mixed amount's component amounts with a bit of cleanup (like @amounts@),
|
||||
-- and if a commodity display order is provided, sort them according to that.
|
||||
-- Get a mixed amount's component amounts with a bit of cleanup,
|
||||
-- optionally preserving multiple zeros in different commodities,
|
||||
-- optionally sorting them according to a commodity display order.
|
||||
orderedAmounts :: AmountDisplayOpts -> MixedAmount -> [Amount]
|
||||
orderedAmounts AmountDisplayOpts{displayOrder=mcommodityorder} =
|
||||
amounts
|
||||
orderedAmounts AmountDisplayOpts{displayZeroCommodity=preservezeros, displayOrder=mcommodityorder} =
|
||||
if preservezeros then amountsPreservingZeros else amounts
|
||||
<&> maybe id (mapM findfirst) mcommodityorder -- maybe sort them (somehow..)
|
||||
where
|
||||
-- Find the first amount with the given commodity, otherwise a null amount in that commodity.
|
||||
|
||||
@ -220,6 +220,9 @@ postingsAsLines onelineamounts ps = concatMap first3 linesWithWidths
|
||||
-- Or if onelineamounts is true, such amounts are shown on one line, comma-separated
|
||||
-- (and the output will not be valid journal syntax).
|
||||
--
|
||||
-- If an amount is zero, any commodity symbol attached to it is shown
|
||||
-- (and the corresponding commodity display style is used).
|
||||
--
|
||||
-- By default, 4 spaces (2 if there's a status flag) are shown between
|
||||
-- account name and start of amount area, which is typically 12 chars wide
|
||||
-- and contains a right-aligned amount (so 10-12 visible spaces between
|
||||
@ -262,7 +265,7 @@ postingAsLines elideamount onelineamounts acctwidth amtwidth p =
|
||||
-- amtwidth at all.
|
||||
shownAmounts
|
||||
| elideamount = [mempty]
|
||||
| otherwise = showMixedAmountLinesB noColour{displayOneLine=onelineamounts} $ pamount p
|
||||
| otherwise = showMixedAmountLinesB noColour{displayZeroCommodity=True, displayOneLine=onelineamounts} $ pamount p
|
||||
thisamtwidth = maximumBound 0 $ map wbWidth shownAmounts
|
||||
|
||||
-- when there is a balance assertion, show it only on the last posting line
|
||||
|
||||
@ -46,8 +46,8 @@ $ hledger -f - balance -N
|
||||
b
|
||||
$ hledger -f- print --explicit --empty
|
||||
2010-03-01 x
|
||||
a 0 @ 3EUR
|
||||
b 0
|
||||
a $0.00 @ 3EUR
|
||||
b 0EUR
|
||||
|
||||
>= 0
|
||||
|
||||
|
||||
@ -1006,8 +1006,8 @@ account1 assets:bank:checking
|
||||
|
||||
$ ./csvtest.sh
|
||||
2020-01-21 Client card point of sale fee
|
||||
assets:bank:checking 0 = $1068.94
|
||||
expenses:unknown 0
|
||||
assets:bank:checking $0 = $1068.94
|
||||
expenses:unknown $0
|
||||
|
||||
>=0
|
||||
|
||||
|
||||
@ -96,8 +96,8 @@ $ hledger -f- print
|
||||
b B 0
|
||||
$ hledger -f- print
|
||||
2020-01-01
|
||||
a 0
|
||||
b 0
|
||||
a A 0
|
||||
b B 0
|
||||
|
||||
>=0
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ $ hledger -f - print
|
||||
a
|
||||
$ hledger -f - print --explicit
|
||||
2010-01-01
|
||||
a 0
|
||||
a $0.00
|
||||
a 1C @ $1.0049
|
||||
a $-1.0049
|
||||
|
||||
|
||||
@ -62,8 +62,8 @@ $ hledger -f- print -x --value=now,Z
|
||||
# and sign are not shown either.
|
||||
$ hledger -f- print -x --value=now,C
|
||||
2019-06-01
|
||||
a 0
|
||||
b 0
|
||||
a C0
|
||||
b C0
|
||||
|
||||
>=
|
||||
# # There's nothing setting C display style, so the default style is used,
|
||||
|
||||
@ -92,8 +92,8 @@ $ hledger -f - print
|
||||
equity
|
||||
$ hledger -f - print --explicit
|
||||
2017-01-01
|
||||
assets 0
|
||||
equity 0
|
||||
assets $0
|
||||
equity $0
|
||||
|
||||
>= 0
|
||||
|
||||
|
||||
@ -1,13 +1,27 @@
|
||||
# test -B and #551
|
||||
#hledger -f- print -B
|
||||
#<<<
|
||||
#2009/1/1
|
||||
# assets:foreign currency €100
|
||||
# assets:cash $-135
|
||||
#>>>
|
||||
#2009/01/01
|
||||
# assets:foreign currency $135
|
||||
# assets:cash $-135
|
||||
#
|
||||
#>>>2
|
||||
#>>>= 0
|
||||
# 1. print preserves the commodity symbol of zero amounts.
|
||||
<
|
||||
2023-01-01
|
||||
(a) 0 A @ 0 B == 0 A @ 0 B
|
||||
|
||||
$ hledger -f- print
|
||||
2023-01-01
|
||||
(a) 0 A @ 0 B == 0 A @ 0 B
|
||||
|
||||
>=
|
||||
|
||||
# 2. The inferred balancing amount for zeros in multiple commodities
|
||||
# is preserved and shown accurately, with a posting for each commodity.
|
||||
<
|
||||
2023-01-01
|
||||
a 0 A
|
||||
b 0 B
|
||||
z
|
||||
|
||||
$ hledger -f- print -x
|
||||
2023-01-01
|
||||
a 0 A
|
||||
b 0 B
|
||||
z 0 A
|
||||
z 0 B
|
||||
|
||||
>=
|
||||
|
||||
@ -178,6 +178,7 @@ $ hledger rewrite -f- assets:bank and 'amt:<0' --add-posting 'expenses:fee $5'
|
||||
; but relative order matters to refer-rewritten transactions
|
||||
= ^expenses not:housing not:grocery not:food
|
||||
(budget:misc) *-1
|
||||
|
||||
$ hledger rewrite -f- date:2017/1 --add-posting 'Here comes Santa $0' --verbose-tags
|
||||
2016-12-31 ; modified:
|
||||
expenses:housing $600.00
|
||||
@ -187,24 +188,24 @@ $ hledger rewrite -f- date:2017/1 --add-posting 'Here comes Santa $0' --verbos
|
||||
2017-01-01 ; modified:
|
||||
expenses:food $20.00
|
||||
(budget:food) $-20.00 ; generated-posting: = ^expenses:grocery ^expenses:food
|
||||
Here comes Santa 0 ; generated-posting: = date:2017/1
|
||||
Here comes Santa $0 ; generated-posting: = date:2017/1
|
||||
expenses:leisure $15.00
|
||||
(budget:misc) $-15.00 ; generated-posting: = ^expenses not:housing not:grocery not:food
|
||||
Here comes Santa 0 ; generated-posting: = date:2017/1
|
||||
Here comes Santa $0 ; generated-posting: = date:2017/1
|
||||
expenses:grocery $30.00
|
||||
(budget:food) $-30.00 ; generated-posting: = ^expenses:grocery ^expenses:food
|
||||
Here comes Santa 0 ; generated-posting: = date:2017/1
|
||||
Here comes Santa $0 ; generated-posting: = date:2017/1
|
||||
assets:cash
|
||||
Here comes Santa 0 ; generated-posting: = date:2017/1
|
||||
Here comes Santa $0 ; generated-posting: = date:2017/1
|
||||
|
||||
2017-01-02 ; modified:
|
||||
assets:cash $200.00
|
||||
Here comes Santa 0 ; generated-posting: = date:2017/1
|
||||
Here comes Santa $0 ; generated-posting: = date:2017/1
|
||||
assets:bank
|
||||
assets:bank $-1.60 ; generated-posting: = ^assets:bank$ date:2017/1 amt:<0
|
||||
expenses:fee $1.60 ; cash withdraw fee, generated-posting: = ^assets:bank$ date:2017/1 amt:<0
|
||||
(budget:misc) $-1.60 ; generated-posting: = ^expenses not:housing not:grocery not:food
|
||||
Here comes Santa 0 ; generated-posting: = date:2017/1
|
||||
Here comes Santa $0 ; generated-posting: = date:2017/1
|
||||
|
||||
2017-02-01
|
||||
assets:cash $100.00
|
||||
|
||||
Loading…
Reference in New Issue
Block a user