From 015b764d00531a6eed3fea9465e4ec3d3b52ab47 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Fri, 13 Jan 2017 17:25:44 +0200 Subject: [PATCH] Preserve implicit amounts and prices the way user wrote them in output of print command (#471) * Remember original postings during infer and pivot This includes such functions like: - inferFromAssignment - inferBalancingAmount - inferBalancingPrices - pivotPosting * Use original postings for hledger print - Introduce "--explicit" option for "print" command which brings back old behavior when every inferred number being printed. - Make "print" by default print original postings without inferred amounts. But use effective account name to have effect from aliases. - Instruct shell tests with an new expected output or to use --explicit option when inferred amounts are checked. Resolves simonmichael/hledger#442 --- hledger-lib/Hledger/Data/Journal.hs | 2 +- hledger-lib/Hledger/Data/Posting.hs | 5 + hledger-lib/Hledger/Data/Transaction.hs | 4 +- hledger-lib/Hledger/Data/Types.hs | 5 +- hledger/Hledger/Cli/Print.hs | 20 +++- hledger/Hledger/Cli/Utils.hs | 2 +- tests/bin/rewrite.test | 15 +-- tests/cli/multiple-files.test | 8 +- tests/i18n/unicode-print.test | 2 +- tests/i18n/wide-char-layout.test | 6 +- tests/journal/comments.test | 6 +- tests/journal/commodities.test | 4 +- tests/journal/dates.test | 2 +- tests/journal/default-commodity.test | 6 +- tests/journal/parens-in-account-name.test | 2 +- tests/journal/precision.test | 6 +- tests/journal/transaction-prices.test | 10 +- tests/misc/account-aliases.test | 8 +- tests/misc/amount-rendering.test | 5 +- tests/misc/query-status.test | 6 +- tests/print/explicit.test | 114 ++++++++++++++++++++++ tests/print/long-account-name.test | 2 +- tests/print/query-desc.test | 2 +- 23 files changed, 190 insertions(+), 52 deletions(-) create mode 100644 tests/print/explicit.test diff --git a/hledger-lib/Hledger/Data/Journal.hs b/hledger-lib/Hledger/Data/Journal.hs index 97ad60592..96f195f52 100644 --- a/hledger-lib/Hledger/Data/Journal.hs +++ b/hledger-lib/Hledger/Data/Journal.hs @@ -657,7 +657,7 @@ checkInferAndRegisterAmounts (Right oldTx) = do where inferFromAssignment :: Posting -> CurrentBalancesModifier s Posting inferFromAssignment p = maybe (return p) - (fmap (\a -> p { pamount = a }) . setBalance (paccount p)) + (fmap (\a -> p { pamount = a, porigin = Just $ originalPosting p }) . setBalance (paccount p)) $ pbalanceassertion p -- | Adds a posting's amonut to the posting's account balance and diff --git a/hledger-lib/Hledger/Data/Posting.hs b/hledger-lib/Hledger/Data/Posting.hs index a54ba5737..d320c0c64 100644 --- a/hledger-lib/Hledger/Data/Posting.hs +++ b/hledger-lib/Hledger/Data/Posting.hs @@ -15,6 +15,7 @@ module Hledger.Data.Posting ( posting, post, -- * operations + originalPosting, postingStatus, isReal, isVirtual, @@ -83,12 +84,16 @@ nullposting = Posting ,ptags=[] ,pbalanceassertion=Nothing ,ptransaction=Nothing + ,porigin=Nothing } posting = nullposting post :: AccountName -> Amount -> Posting post acct amt = posting {paccount=acct, pamount=Mixed [amt]} +originalPosting :: Posting -> Posting +originalPosting p = fromMaybe p $ porigin p + -- XXX once rendered user output, but just for debugging now; clean up showPosting :: Posting -> String showPosting p@Posting{paccount=a,pamount=amt,ptype=t} = diff --git a/hledger-lib/Hledger/Data/Transaction.hs b/hledger-lib/Hledger/Data/Transaction.hs index 731692f03..8a50ccd89 100644 --- a/hledger-lib/Hledger/Data/Transaction.hs +++ b/hledger-lib/Hledger/Data/Transaction.hs @@ -402,7 +402,7 @@ inferBalancingAmount update t@Transaction{tpostings=ps} inferamount p@Posting{ptype=BalancedVirtualPosting} | not (hasAmount p) = updateAmount p bvsum inferamount p = return p - updateAmount p amt = update (paccount p) amt' >> return p { pamount=amt' } + updateAmount p amt = update (paccount p) amt' >> return p { pamount=amt', porigin=Just $ originalPosting p } where amt' = normaliseMixedAmount $ costOfMixedAmount (-amt) -- | Infer prices for this transaction's posting amounts, if needed to make @@ -467,7 +467,7 @@ priceInferrerFor t pt = inferprice inferprice p@Posting{pamount=Mixed [a]} | caninferprices && ptype p == pt && acommodity a == fromcommodity - = p{pamount=Mixed [a{aprice=conversionprice}]} + = p{pamount=Mixed [a{aprice=conversionprice}], porigin=Just $ originalPosting p} where fromcommodity = head $ filter (`elem` sumcommodities) pcommodities -- these heads are ugly but should be safe conversionprice diff --git a/hledger-lib/Hledger/Data/Types.hs b/hledger-lib/Hledger/Data/Types.hs index 6e7d21161..d479b8a54 100644 --- a/hledger-lib/Hledger/Data/Types.hs +++ b/hledger-lib/Hledger/Data/Types.hs @@ -199,8 +199,9 @@ data Posting = Posting { ptype :: PostingType, ptags :: [Tag], -- ^ tag names and values, extracted from the comment pbalanceassertion :: Maybe Amount, -- ^ optional: the expected balance in this commodity in the account after this posting - ptransaction :: Maybe Transaction -- ^ this posting's parent transaction (co-recursive types). + ptransaction :: Maybe Transaction, -- ^ this posting's parent transaction (co-recursive types). -- Tying this knot gets tedious, Maybe makes it easier/optional. + porigin :: Maybe Posting -- ^ original posting if this one is result of any transformations (one level only) } deriving (Typeable,Data,Generic) instance NFData Posting @@ -208,7 +209,7 @@ instance NFData Posting -- The equality test for postings ignores the parent transaction's -- identity, to avoid infinite loops. instance Eq Posting where - (==) (Posting a1 b1 c1 d1 e1 f1 g1 h1 i1 _) (Posting a2 b2 c2 d2 e2 f2 g2 h2 i2 _) = a1==a2 && b1==b2 && c1==c2 && d1==d2 && e1==e2 && f1==f2 && g1==g2 && h1==h2 && i1==i2 + (==) (Posting a1 b1 c1 d1 e1 f1 g1 h1 i1 _ _) (Posting a2 b2 c2 d2 e2 f2 g2 h2 i2 _ _) = a1==a2 && b1==b2 && c1==c2 && d1==d2 && e1==e2 && f1==f2 && g1==g2 && h1==h2 && i1==i2 -- | The position of parse errors (eg), like parsec's SourcePos but generic. -- File name, 1-based line number and 1-based column number. diff --git a/hledger/Hledger/Cli/Print.hs b/hledger/Hledger/Cli/Print.hs index 1a9a02092..68fb4f6dc 100644 --- a/hledger/Hledger/Cli/Print.hs +++ b/hledger/Hledger/Cli/Print.hs @@ -34,7 +34,9 @@ printmode = (defCommandMode $ ["print"] ++ aliases) { in flagReq ["match","m"] (\s opts -> Right $ setopt "match" s opts) matcharg ("show the transaction whose description is most similar to "++matcharg - ++ ", and is most recent") + ++ ", and is most recent"), + flagNone ["explicit","x"] (setboolopt "explicit") + "make output more explicit than original transactions" ] ++ outputflags ,groupHidden = [] @@ -43,6 +45,17 @@ printmode = (defCommandMode $ ["print"] ++ aliases) { } where aliases = [] +showTransaction' :: CliOpts -> Transaction -> String +showTransaction' opts + | boolopt "explicit" $ rawopts_ opts = showTransactionUnelided + | otherwise = showTransactionUnelided . originalTransaction + +originalTransaction :: Transaction -> Transaction +originalTransaction t = t { tpostings = map originalPosting' $ tpostings t } where + -- We don't want plain original postings because print wouldn't issue alias + -- directives. Thus we are going to print effective account name. + originalPosting' p = (originalPosting p) { paccount = paccount p } + -- | Print journal transactions in standard format. print' :: CliOpts -> Journal -> IO () print' opts j = do @@ -57,12 +70,15 @@ printEntries opts@CliOpts{reportopts_=ropts} j = do fmt = outputFormatFromOpts opts (render, ropts') = case fmt of "csv" -> ((++"\n") . printCSV . entriesReportAsCsv, ropts{accountlistmode_=ALFlat}) - _ -> (entriesReportAsText, ropts) + _ -> (entriesReportAsText' opts, ropts) writeOutput opts $ render $ entriesReport ropts' q j entriesReportAsText :: EntriesReport -> String entriesReportAsText items = concatMap showTransactionUnelided items +entriesReportAsText' :: CliOpts -> EntriesReport -> String +entriesReportAsText' = concatMap . showTransaction' + -- XXX -- tests_showTransactions = [ -- "showTransactions" ~: do diff --git a/hledger/Hledger/Cli/Utils.hs b/hledger/Hledger/Cli/Utils.hs index 059b4c4c0..b61b692cc 100644 --- a/hledger/Hledger/Cli/Utils.hs +++ b/hledger/Hledger/Cli/Utils.hs @@ -91,7 +91,7 @@ pivot tag j = j{jtxns = map pivotTrans . jtxns $ j} where pivotTrans t = t{tpostings = map pivotPosting . tpostings $ t} pivotPosting p - | Just (_ , value) <- tagTuple = p{paccount = joinAccountNames tag value} + | Just (_ , value) <- tagTuple = p{paccount = joinAccountNames tag value, porigin = Just $ originalPosting p} | _ <- tagTuple = p where tagTuple = find ((tag ==) . fst) . ptags $ p diff --git a/tests/bin/rewrite.test b/tests/bin/rewrite.test index 62f24dbc9..2f7ba3d27 100644 --- a/tests/bin/rewrite.test +++ b/tests/bin/rewrite.test @@ -13,13 +13,14 @@ runghc ../../bin/hledger-rewrite.hs -f- ^income --add-posting '(liabilities:tax) >>> 2016/01/01 paycheck income:remuneration $-100 - assets:bank $100 + assets:bank (liabilities:tax) $-33 2016/01/01 withdraw assets:cash $20 - assets:bank $-20 + assets:bank +>>>2 >>>=0 # Duplicate posting for budgeting (from documentation) @@ -35,13 +36,14 @@ runghc ../../bin/hledger-rewrite.hs -f- expenses:gifts --add-posting '(budget:gi >>> 2016/01/01 withdraw assets:cash $20 - assets:bank $-20 + assets:bank 2016/01/01 gift assets:cash $-15 - expenses:gifts $15 + expenses:gifts (budget:gifts) $-15 +>>>2 >>>=0 # Add absolute bank processing fee @@ -62,14 +64,15 @@ runghc ../../bin/hledger-rewrite.hs -f- assets:bank and 'amt:<0' --add-posting ' >>> 2016/01/01 withdraw assets:cash $20 - assets:bank $-20 + assets:bank expenses:fee $5 assets:bank $-5 2016/01/02 withdraw - assets:cash $30 + assets:cash assets:bank $-30 expenses:fee $5 assets:bank $-5 +>>>2 >>>=0 diff --git a/tests/cli/multiple-files.test b/tests/cli/multiple-files.test index 8ec765f90..a7a03d0fc 100644 --- a/tests/cli/multiple-files.test +++ b/tests/cli/multiple-files.test @@ -25,15 +25,15 @@ hledger print -f personal.journal -f business.journal -f alias.journal -f person >>> 2014/01/01 expenses:office supplies $1 - assets:business checking $-1 + assets:business checking 2014/01/02 expenses:food $1 - assets:cash $-1 + assets:cash 2014/01/02 expenses:food $1 - assets:cash $-1 + assets:cash >>>2 >>>=0 @@ -47,7 +47,7 @@ hledger print -f personal.journal -f ../journal/a.timeclock -f ../journal/b.time >>> 2014/01/02 expenses:food $1 - assets:cash $-1 + assets:cash 2016/01/01 * 12:00-16:00 (a:aa) 4.00h diff --git a/tests/i18n/unicode-print.test b/tests/i18n/unicode-print.test index be4ad952e..8e3f83f0d 100644 --- a/tests/i18n/unicode-print.test +++ b/tests/i18n/unicode-print.test @@ -6,6 +6,6 @@ hledger -f - print >>> 2009/01/01 проверка счёт:первый 1 - счёт:второй -1 + счёт:второй >>>=0 diff --git a/tests/i18n/wide-char-layout.test b/tests/i18n/wide-char-layout.test index f410ba60d..4e5c055b7 100644 --- a/tests/i18n/wide-char-layout.test +++ b/tests/i18n/wide-char-layout.test @@ -21,11 +21,11 @@ hledger -f - print >>> 2014/01/01 transaction 1 㐀 㐃㐃1 @ 2 㐂㐂㐂㐂㐂㐂㐂㐂㐂㐂㐂 - 㐀:㐁 -2 㐂㐂㐂㐂㐂㐂㐂㐂㐂㐂㐂 ; 㐃㐃-1 + 㐀:㐁 ; 㐃㐃-1 2014/01/02 transaction 2 - 㐀:㐁:㐂 USD 1 @@ EUR 1 - 㐀:㐁:㐂:㐃 EUR -1 + 㐀:㐁:㐂 USD 1 + 㐀:㐁:㐂:㐃 EUR -1 2014/01/03 transaction 3 㐀:㐁:㐂:㐃:㐄 1 diff --git a/tests/journal/comments.test b/tests/journal/comments.test index 73e0378e2..88d06c8f9 100644 --- a/tests/journal/comments.test +++ b/tests/journal/comments.test @@ -13,7 +13,7 @@ hledger -f - print ; transaction comment 1 ; transaction comment 2 a 1 - b -1 + b >>>=0 @@ -27,7 +27,7 @@ hledger -f - print >>> 2009/01/01 x a 1 - b -1 + b >>>=0 @@ -51,7 +51,7 @@ hledger -f - print ; transaction new line comment a 1 ; posting 1 same line comment ; posting 1 new line comment - b -1 + b ; posting 2 new line comment >>>2 diff --git a/tests/journal/commodities.test b/tests/journal/commodities.test index 71264ded7..604324d74 100644 --- a/tests/journal/commodities.test +++ b/tests/journal/commodities.test @@ -8,7 +8,7 @@ hledger -f- print >>>2 /unexpected/ >>>= 1 # 2. with quotes, ok; quotes appear in print output -hledger -f- print +hledger -f- print --explicit <<< 2010-04-05 x a 10 "DE 0002 635307" @@ -34,7 +34,7 @@ hledger -f- balance >>>=0 # 4. autobalance with prices -hledger -f- print +hledger -f- print --explicit <<< 2016/1/1 saving-card $-105 diff --git a/tests/journal/dates.test b/tests/journal/dates.test index 2a2196821..8b5c5cd24 100644 --- a/tests/journal/dates.test +++ b/tests/journal/dates.test @@ -24,7 +24,7 @@ hledger -f- print >>> 2000/02/29 x a 1 - b -1 + b >>>= 0 # 4. 29th feb on non-leap year should fail diff --git a/tests/journal/default-commodity.test b/tests/journal/default-commodity.test index 6458ed822..56d39d64c 100644 --- a/tests/journal/default-commodity.test +++ b/tests/journal/default-commodity.test @@ -12,7 +12,7 @@ hledger -f- print >>> 2010/01/01 a 1000 - b -1000 + b >>>=0 @@ -26,7 +26,7 @@ D £1000.00 >>> 2010/01/01 a £1000.00 - b £-1000.00 + b >>>=0 @@ -40,7 +40,7 @@ D $1,000 >>> 2010/01/01 a $1000,000 - b $-1000,000 + b >>>=0 diff --git a/tests/journal/parens-in-account-name.test b/tests/journal/parens-in-account-name.test index d9a036584..3db01ad32 100644 --- a/tests/journal/parens-in-account-name.test +++ b/tests/journal/parens-in-account-name.test @@ -8,6 +8,6 @@ hledger -f - print 2009/01/01 x a 2 b (b) b -1 - c -1 + c >>>=0 diff --git a/tests/journal/precision.test b/tests/journal/precision.test index 67f48a111..28dcdd4bf 100644 --- a/tests/journal/precision.test +++ b/tests/journal/precision.test @@ -32,7 +32,7 @@ hledger -f - print # 2. and here the price should be printed with its original precision, not # the canonical display precision -hledger -f - print +hledger -f - print --explicit <<< 2010/1/1 a $0.00 @@ -130,7 +130,7 @@ D $1000.0 # the max precisions of the commodities being converted (#262). # Here the (irrational) price should be displayed with just precision 4 # (C's precision 2 + D's precision 2). -hledger -f- print +hledger -f- print --explicit <<< 2015/1/1 c C 10.00 @@ -147,7 +147,7 @@ hledger -f- print ## 8. Here the price should be displayed with precision 7 # (E's precision 4 + F's precision 3). -hledger -f- print +hledger -f- print --explicit <<< 2015/1/1 e E 10.0000 diff --git a/tests/journal/transaction-prices.test b/tests/journal/transaction-prices.test index e5681d21e..980a1fb94 100644 --- a/tests/journal/transaction-prices.test +++ b/tests/journal/transaction-prices.test @@ -1,6 +1,6 @@ # price-related tests # 1. print a transaction with an explicit unit price -hledger -f- print +hledger -f- print --explicit <<< 2011/01/01 expenses:foreign currency €100 @ $1.35 @@ -13,7 +13,7 @@ hledger -f- print >>>=0 # 2. -B/--cost converts to the price's commodity ("cost") -hledger -f- print --cost +hledger -f- print --explicit --cost <<< 2011/01/01 expenses:foreign currency €100 @ $1.35 @@ -26,7 +26,7 @@ hledger -f- print --cost >>>=0 # 3. print a transaction with a total price -hledger -f - print +hledger -f - print --explicit <<< 2011/01/01 expenses:foreign currency €100 @@ $135 @@ -40,7 +40,7 @@ hledger -f - print # 4. when the balance has exactly two commodities, both unpriced, infer an # implicit conversion price for the first one in terms of the second. -hledger -f - print +hledger -f - print --explicit <<< 2011/01/01 expenses:foreign currency €100 @@ -61,7 +61,7 @@ hledger -f - print >>>=0 ## 5. another, from ledger tests. Just one posting to price so uses @@. -hledger -f - print +hledger -f - print --explicit <<< 2002/09/30 * 1a1a6305d06ce4b284dba0d267c23f69d70c20be c56a21d23a6535184e7152ee138c28974f14280c 866.231000 GGGGG diff --git a/tests/misc/account-aliases.test b/tests/misc/account-aliases.test index 51e8d238e..5d17d4076 100644 --- a/tests/misc/account-aliases.test +++ b/tests/misc/account-aliases.test @@ -73,12 +73,12 @@ alias /A (.)/=\1 2011/01/01 b b 1 b b 2 - c -3 + c 2011/01/01 b 1 b 2 - c -3 + c >>>=0 @@ -98,7 +98,7 @@ hledger -f- print --alias '/A (.)/=a' --alias /a/=b 2011/01/01 b 1 b 2 - c -3 + c >>>=0 @@ -117,7 +117,7 @@ alias E=F >>> 2011/01/01 [E:x] 1 - [x:A:x] -1 + [x:A:x] >>>2 >>>=0 diff --git a/tests/misc/amount-rendering.test b/tests/misc/amount-rendering.test index b5b06d89c..4395d126e 100644 --- a/tests/misc/amount-rendering.test +++ b/tests/misc/amount-rendering.test @@ -1,6 +1,6 @@ # amount layout tests, using default vertical layout # 1. print -hledger -f - print +hledger -f - print --explicit <<< 2010/1/1 a EUR 1 ; a euro @@ -47,8 +47,7 @@ hledger -f - balance >>>=0 # 4. a single-commodity zero amount's commodity/decimal places/price is preserved, when possible -# -hledger -f- print --empty +hledger -f- print --explicit --empty <<< 2010/3/1 x a $0.00 @ 3EUR diff --git a/tests/misc/query-status.test b/tests/misc/query-status.test index 5f85f66c6..ff4ee9c48 100644 --- a/tests/misc/query-status.test +++ b/tests/misc/query-status.test @@ -17,11 +17,11 @@ hledger -f- print --cleared >>> 2010/01/02 * x a 1 - b -1 + b 2010/01/03 * a 1 - b -1 + b >>>=0 @@ -42,7 +42,7 @@ hledger -f- print --uncleared >>> 2010/01/01 x a 1 - b -1 + b >>>=0 diff --git a/tests/print/explicit.test b/tests/print/explicit.test new file mode 100644 index 000000000..a2aca8adc --- /dev/null +++ b/tests/print/explicit.test @@ -0,0 +1,114 @@ +# Tests of --explicit option effect + +# 1. implicit transaction balance w/o --explict +hledger -f - print +<<< +2017/1/1 + expenses $5 + assets +>>> +2017/01/01 + expenses $5 + assets + +>>>2 +>>>=0 + +# 2. implicit transaction balance w/ --explict +hledger -f - print --explicit +<<< +2017/1/1 + expenses $5 + assets +>>> +2017/01/01 + expenses $5 + assets $-5 + +>>>2 +>>>=0 + +# 3. implicit commodity price w/o --explict +hledger -f - print +<<< +2017/1/1 + expenses 4 EUR + assets $-5 +>>> +2017/01/01 + expenses 4 EUR + assets $-5 + +>>>2 +>>>=0 + +# 4. implicit commodity price w/ --explict +hledger -f - print --explicit +<<< +2017/1/1 + expenses 4 EUR + assets $-5 +>>> +2017/01/01 + expenses 4 EUR @@ $5 + assets $-5 + +>>>2 +>>>=0 + +# 5. implicit account balance w/o --explict +hledger -f - print +<<< +2017/1/1 + assets = $100 + equity +>>> +2017/01/01 + assets = $100 + equity + +>>>2 +>>>=0 + +# 6. implicit account balance w/ --explict +hledger -f - print --explicit +<<< +2017/1/1 + assets = $100 + equity +>>> +2017/01/01 + assets $100 = $100 + equity $-100 + +>>>2 +>>>=0 + +# 7. default commodity always applied because print do not issue appropriate directive +hledger -f - print +<<< +D 1000.00 EUR +2017/1/1 + expenses 100 + assets +>>> +2017/01/01 + expenses 100.00 EUR + assets + +>>>2 +>>>=0 + +# 8. option --explicit implies effect of --empty +hledger -f - print --explicit +<<< +2017/1/1 + assets $0 + equity +>>> +2017/01/01 + assets 0 + equity 0 + +>>>2 +>>>=0 diff --git a/tests/print/long-account-name.test b/tests/print/long-account-name.test index 875cf4606..eb69235f7 100644 --- a/tests/print/long-account-name.test +++ b/tests/print/long-account-name.test @@ -6,6 +6,6 @@ hledger -f - print >>> 2009/01/01 x aaaaabbbbbcccccdddddeeeeefffffggggghhhhh 1 - b -1 + b >>>=0 diff --git a/tests/print/query-desc.test b/tests/print/query-desc.test index 793d95e8b..9fc44557a 100644 --- a/tests/print/query-desc.test +++ b/tests/print/query-desc.test @@ -11,6 +11,6 @@ hledger -f - print desc:x >>> 2009/01/01 x a 1 - b -1 + b >>>=0