@@ -23,8 +23,9 @@ module Hledger.Data.Journal (
2323 addTransaction ,
2424 journalBalanceTransactions ,
2525 journalInferMarketPricesFromTransactions ,
26+ journalInferCommodityStyles ,
2627 journalApplyCommodityStyles ,
27- commodityStylesFromAmounts ,
28+ journalInferAndApplyCommodityStyles ,
2829 journalCommodityStyles ,
2930 journalToCost ,
3031 journalReverse ,
@@ -78,7 +79,6 @@ module Hledger.Data.Journal (
7879 journalEquityAccountQuery ,
7980 journalCashAccountQuery ,
8081 -- * Misc
81- canonicalStyleFrom ,
8282 nulljournal ,
8383 journalCheckBalanceAssertions ,
8484 journalNumberAndTieTransactions ,
@@ -87,7 +87,7 @@ module Hledger.Data.Journal (
8787 journalApplyAliases ,
8888 -- * Tests
8989 samplejournal ,
90- tests_Journal ,
90+ tests_Journal
9191)
9292where
9393
@@ -101,7 +101,7 @@ import Data.Function ((&))
101101import qualified Data.HashTable.Class as H (toList )
102102import qualified Data.HashTable.ST.Cuckoo as H
103103import Data.List (find , sortOn )
104- import Data.List.Extra (groupSort , nubSort )
104+ import Data.List.Extra (nubSort )
105105import qualified Data.Map as M
106106import Data.Maybe (catMaybes , fromJust , fromMaybe , isJust , mapMaybe )
107107#if !(MIN_VERSION_base(4,11,0))
@@ -653,7 +653,8 @@ journalModifyTransactions d j =
653653-- | Check any balance assertions in the journal and return an error message
654654-- if any of them fail (or if the transaction balancing they require fails).
655655journalCheckBalanceAssertions :: Journal -> Maybe String
656- journalCheckBalanceAssertions = either Just (const Nothing ) . journalBalanceTransactions True
656+ journalCheckBalanceAssertions = either Just (const Nothing ) . journalBalanceTransactions False True
657+ -- TODO: not using global display styles here, do we need to for BC ?
657658
658659-- "Transaction balancing", including: inferring missing amounts,
659660-- applying balance assignments, checking transaction balancedness,
@@ -748,18 +749,20 @@ updateTransactionB t = withRunningBalance $ \BalancingState{bsTransactions} ->
748749-- and (optional) all balance assertions pass. Or return an error message
749750-- (just the first error encountered).
750751--
751- -- Assumes journalInferCommodityStyles has been called, since those
752- -- affect transaction balancing.
752+ -- Assumes the journal amounts' display styles still have the original number
753+ -- of decimal places that was parsed (ie, display styles have not yet been normalised),
754+ -- since this affects transaction balancing.
753755--
754756-- This does multiple things at once because amount inferring, balance
755757-- assignments, balance assertions and posting dates are interdependent.
756- journalBalanceTransactions :: Bool -> Journal -> Either String Journal
757- journalBalanceTransactions assrt j' =
758+ --
759+ journalBalanceTransactions :: Bool -> Bool -> Journal -> Either String Journal
760+ journalBalanceTransactions usedisplaystyles assrt j' =
758761 let
759762 -- ensure transactions are numbered, so we can store them by number
760763 j@ Journal {jtxns= ts} = journalNumberTransactions j'
761764 -- display precisions used in balanced checking
762- styles = Just $ journalCommodityStyles j
765+ styles = if usedisplaystyles then Just $ journalCommodityStyles j else Nothing
763766 -- balance assignments will not be allowed on these
764767 txnmodifieraccts = S. fromList $ map paccount $ concatMap tmpostingrules $ jtxnmodifiers j
765768 in
@@ -991,25 +994,66 @@ checkBalanceAssignmentUnassignableAccountB p = do
991994
992995--
993996
997+ -- | Get an ordered list of amounts in this journal which can
998+ -- influence canonical amount display styles. Those are, in
999+ -- the following order:
1000+ --
1001+ -- * amounts in market price (P) directives (in parse order)
1002+ -- * posting amounts in transactions (in parse order)
1003+ -- * the amount in the final default commodity (D) directive
1004+ --
1005+ -- Transaction price amounts (posting amounts' aprice field) are not included.
1006+ --
1007+ journalStyleInfluencingAmounts :: Journal -> [Amount ]
1008+ journalStyleInfluencingAmounts j =
1009+ dbg7 " journalStyleInfluencingAmounts" $
1010+ catMaybes $ concat [
1011+ [mdefaultcommodityamt]
1012+ ,map (Just . pdamount) $ jpricedirectives j
1013+ ,map Just $ concatMap amounts $ map pamount $ journalPostings j
1014+ ]
1015+ where
1016+ -- D's amount style isn't actually stored as an amount, make it into one
1017+ mdefaultcommodityamt =
1018+ case jparsedefaultcommodity j of
1019+ Just (symbol,style) -> Just nullamt{acommodity= symbol,astyle= style}
1020+ Nothing -> Nothing
1021+
1022+ -- | Infer commodity display styles for each commodity (see commodityStylesFromAmounts)
1023+ -- based on the amounts in this journal (see journalStyleInfluencingAmounts),
1024+ -- and save those inferred styles in the journal.
1025+ -- Can return an error message eg if inconsistent number formats are found.
1026+ journalInferCommodityStyles :: Journal -> Either String Journal
1027+ journalInferCommodityStyles j =
1028+ case commodityStylesFromAmounts $ journalStyleInfluencingAmounts j of
1029+ Left e -> Left e
1030+ Right cs -> Right j{jinferredcommodities = dbg7 " journalInferCommodityStyles" cs}
1031+
1032+ -- | Apply the given commodity display styles to the posting amounts in this journal.
1033+ journalApplyCommodityStyles :: M. Map CommoditySymbol AmountStyle -> Journal -> Journal
1034+ journalApplyCommodityStyles styles j@ Journal {jtxns= ts, jpricedirectives= pds} =
1035+ j {jtxns= map fixtransaction ts
1036+ ,jpricedirectives= map fixpricedirective pds
1037+ }
1038+ where
1039+ fixtransaction t@ Transaction {tpostings= ps} = t{tpostings= map fixposting ps}
1040+ fixposting p = p{pamount= styleMixedAmount styles $ pamount p
1041+ ,pbalanceassertion= fixbalanceassertion <$> pbalanceassertion p}
1042+ -- balance assertion/assignment amounts, and price amounts, are always displayed
1043+ -- (eg by print) at full precision
1044+ fixbalanceassertion ba = ba{baamount= styleAmountExceptPrecision styles $ baamount ba}
1045+ fixpricedirective pd@ PriceDirective {pdamount= a} = pd{pdamount= styleAmountExceptPrecision styles a}
1046+
9941047-- | Choose and apply a consistent display style to the posting
9951048-- amounts in each commodity (see journalCommodityStyles).
9961049-- Can return an error message eg if inconsistent number formats are found.
997- journalApplyCommodityStyles :: Journal -> Either String Journal
998- journalApplyCommodityStyles j @ Journal {jtxns = ts, jpricedirectives = pds} =
1050+ journalInferAndApplyCommodityStyles :: Journal -> Either String Journal
1051+ journalInferAndApplyCommodityStyles j =
9991052 case journalInferCommodityStyles j of
10001053 Left e -> Left e
1001- Right j' -> Right j' '
1054+ Right j' -> Right $ journalApplyCommodityStyles allstyles j '
10021055 where
1003- styles = journalCommodityStyles j'
1004- j'' = j'{jtxns= map fixtransaction ts
1005- ,jpricedirectives= map fixpricedirective pds
1006- }
1007- fixtransaction t@ Transaction {tpostings= ps} = t{tpostings= map fixposting ps}
1008- fixposting p = p{pamount= styleMixedAmount styles $ pamount p
1009- ,pbalanceassertion= fixbalanceassertion <$> pbalanceassertion p}
1010- -- balance assertion amounts are always displayed (by print) at full precision, per docs
1011- fixbalanceassertion ba = ba{baamount= styleAmountExceptPrecision styles $ baamount ba}
1012- fixpricedirective pd@ PriceDirective {pdamount= a} = pd{pdamount= styleAmountExceptPrecision styles a}
1056+ allstyles = journalCommodityStyles j'
10131057
10141058-- | Get the canonical amount styles for this journal, whether (in order of precedence):
10151059-- set globally in InputOpts,
@@ -1028,18 +1072,6 @@ journalCommodityStyles j =
10281072 defaultcommoditystyle = M. fromList $ catMaybes [jparsedefaultcommodity j]
10291073 inferredstyles = jinferredcommodities j
10301074
1031- -- | Collect and save inferred amount styles for each commodity based on
1032- -- the posting amounts in that commodity (excluding price amounts), ie:
1033- -- "the format of the first amount, adjusted to the highest precision of all amounts".
1034- -- Can return an error message eg if inconsistent number formats are found.
1035- journalInferCommodityStyles :: Journal -> Either String Journal
1036- journalInferCommodityStyles j =
1037- case
1038- commodityStylesFromAmounts $ journalStyleInfluencingAmounts j
1039- of
1040- Left e -> Left e
1041- Right cs -> Right j{jinferredcommodities = dbg7 " journalInferCommodityStyles" cs}
1042-
10431075-- -- | Apply this journal's historical price records to unpriced amounts where possible.
10441076-- journalApplyPriceDirectives :: Journal -> Journal
10451077-- journalApplyPriceDirectives j@Journal{jtxns=ts} = j{jtxns=map fixtransaction ts}
@@ -1268,7 +1300,7 @@ journalApplyAliases aliases j =
12681300-- liabilities:debts $1
12691301-- assets:bank:checking
12701302--
1271- Right samplejournal = journalBalanceTransactions False $
1303+ Right samplejournal = journalBalanceTransactions False False $
12721304 nulljournal
12731305 {jtxns = [
12741306 txnTieKnot $ Transaction {
@@ -1411,7 +1443,7 @@ tests_Journal = tests "Journal" [
14111443 ,tests " journalBalanceTransactions" [
14121444
14131445 test " balance-assignment" $ do
1414- let ej = journalBalanceTransactions True $
1446+ let ej = journalBalanceTransactions False True $
14151447 -- 2019/01/01
14161448 -- (a) = 1
14171449 nulljournal{ jtxns = [
@@ -1422,7 +1454,7 @@ tests_Journal = tests "Journal" [
14221454 (jtxns j & head & tpostings & head & pamount) @?= Mixed [num 1 ]
14231455
14241456 ,test " same-day-1" $ do
1425- assertRight $ journalBalanceTransactions True $
1457+ assertRight $ journalBalanceTransactions False True $
14261458 -- 2019/01/01
14271459 -- (a) = 1
14281460 -- 2019/01/01
@@ -1433,7 +1465,7 @@ tests_Journal = tests "Journal" [
14331465 ]}
14341466
14351467 ,test " same-day-2" $ do
1436- assertRight $ journalBalanceTransactions True $
1468+ assertRight $ journalBalanceTransactions False True $
14371469 -- 2019/01/01
14381470 -- (a) 2 = 2
14391471 -- 2019/01/01
@@ -1451,7 +1483,7 @@ tests_Journal = tests "Journal" [
14511483 ]}
14521484
14531485 ,test " out-of-order" $ do
1454- assertRight $ journalBalanceTransactions True $
1486+ assertRight $ journalBalanceTransactions False True $
14551487 -- 2019/1/2
14561488 -- (a) 1 = 2
14571489 -- 2019/1/1
0 commit comments