@@ -23,8 +23,9 @@ module Hledger.Data.Journal (
23
23
addTransaction ,
24
24
journalBalanceTransactions ,
25
25
journalInferMarketPricesFromTransactions ,
26
+ journalInferCommodityStyles ,
26
27
journalApplyCommodityStyles ,
27
- commodityStylesFromAmounts ,
28
+ journalInferAndApplyCommodityStyles ,
28
29
journalCommodityStyles ,
29
30
journalToCost ,
30
31
journalReverse ,
@@ -78,7 +79,6 @@ module Hledger.Data.Journal (
78
79
journalEquityAccountQuery ,
79
80
journalCashAccountQuery ,
80
81
-- * Misc
81
- canonicalStyleFrom ,
82
82
nulljournal ,
83
83
journalCheckBalanceAssertions ,
84
84
journalNumberAndTieTransactions ,
@@ -87,7 +87,7 @@ module Hledger.Data.Journal (
87
87
journalApplyAliases ,
88
88
-- * Tests
89
89
samplejournal ,
90
- tests_Journal ,
90
+ tests_Journal
91
91
)
92
92
where
93
93
@@ -101,7 +101,7 @@ import Data.Function ((&))
101
101
import qualified Data.HashTable.Class as H (toList )
102
102
import qualified Data.HashTable.ST.Cuckoo as H
103
103
import Data.List (find , sortOn )
104
- import Data.List.Extra (groupSort , nubSort )
104
+ import Data.List.Extra (nubSort )
105
105
import qualified Data.Map as M
106
106
import Data.Maybe (catMaybes , fromJust , fromMaybe , isJust , mapMaybe )
107
107
#if !(MIN_VERSION_base(4,11,0))
@@ -627,7 +627,8 @@ journalModifyTransactions d j =
627
627
-- | Check any balance assertions in the journal and return an error message
628
628
-- if any of them fail (or if the transaction balancing they require fails).
629
629
journalCheckBalanceAssertions :: Journal -> Maybe String
630
- journalCheckBalanceAssertions = either Just (const Nothing ) . journalBalanceTransactions True
630
+ journalCheckBalanceAssertions = either Just (const Nothing ) . journalBalanceTransactions False True
631
+ -- TODO: not using global display styles here, do we need to for BC ?
631
632
632
633
-- "Transaction balancing", including: inferring missing amounts,
633
634
-- applying balance assignments, checking transaction balancedness,
@@ -722,18 +723,20 @@ updateTransactionB t = withRunningBalance $ \BalancingState{bsTransactions} ->
722
723
-- and (optional) all balance assertions pass. Or return an error message
723
724
-- (just the first error encountered).
724
725
--
725
- -- Assumes journalInferCommodityStyles has been called, since those
726
- -- affect transaction balancing.
726
+ -- Assumes the journal amounts' display styles still have the original number
727
+ -- of decimal places that was parsed (ie, display styles have not yet been normalised),
728
+ -- since this affects transaction balancing.
727
729
--
728
730
-- This does multiple things at once because amount inferring, balance
729
731
-- assignments, balance assertions and posting dates are interdependent.
730
- journalBalanceTransactions :: Bool -> Journal -> Either String Journal
731
- journalBalanceTransactions assrt j' =
732
+ --
733
+ journalBalanceTransactions :: Bool -> Bool -> Journal -> Either String Journal
734
+ journalBalanceTransactions usedisplaystyles assrt j' =
732
735
let
733
736
-- ensure transactions are numbered, so we can store them by number
734
737
j@ Journal {jtxns= ts} = journalNumberTransactions j'
735
738
-- display precisions used in balanced checking
736
- styles = Just $ journalCommodityStyles j
739
+ styles = if usedisplaystyles then Just $ journalCommodityStyles j else Nothing
737
740
-- balance assignments will not be allowed on these
738
741
txnmodifieraccts = S. fromList $ map paccount $ concatMap tmpostingrules $ jtxnmodifiers j
739
742
in
@@ -965,25 +968,66 @@ checkBalanceAssignmentUnassignableAccountB p = do
965
968
966
969
--
967
970
971
+ -- | Get an ordered list of amounts in this journal which can
972
+ -- influence canonical amount display styles. Those are, in
973
+ -- the following order:
974
+ --
975
+ -- * amounts in market price (P) directives (in parse order)
976
+ -- * posting amounts in transactions (in parse order)
977
+ -- * the amount in the final default commodity (D) directive
978
+ --
979
+ -- Transaction price amounts (posting amounts' aprice field) are not included.
980
+ --
981
+ journalStyleInfluencingAmounts :: Journal -> [Amount ]
982
+ journalStyleInfluencingAmounts j =
983
+ dbg7 " journalStyleInfluencingAmounts" $
984
+ catMaybes $ concat [
985
+ [mdefaultcommodityamt]
986
+ ,map (Just . pdamount) $ jpricedirectives j
987
+ ,map Just $ concatMap amounts $ map pamount $ journalPostings j
988
+ ]
989
+ where
990
+ -- D's amount style isn't actually stored as an amount, make it into one
991
+ mdefaultcommodityamt =
992
+ case jparsedefaultcommodity j of
993
+ Just (symbol,style) -> Just nullamt{acommodity= symbol,astyle= style}
994
+ Nothing -> Nothing
995
+
996
+ -- | Infer commodity display styles for each commodity (see commodityStylesFromAmounts)
997
+ -- based on the amounts in this journal (see journalStyleInfluencingAmounts),
998
+ -- and save those inferred styles in the journal.
999
+ -- Can return an error message eg if inconsistent number formats are found.
1000
+ journalInferCommodityStyles :: Journal -> Either String Journal
1001
+ journalInferCommodityStyles j =
1002
+ case commodityStylesFromAmounts $ journalStyleInfluencingAmounts j of
1003
+ Left e -> Left e
1004
+ Right cs -> Right j{jinferredcommodities = dbg7 " journalInferCommodityStyles" cs}
1005
+
1006
+ -- | Apply the given commodity display styles to the posting amounts in this journal.
1007
+ journalApplyCommodityStyles :: M. Map CommoditySymbol AmountStyle -> Journal -> Journal
1008
+ journalApplyCommodityStyles styles j@ Journal {jtxns= ts, jpricedirectives= pds} =
1009
+ j {jtxns= map fixtransaction ts
1010
+ ,jpricedirectives= map fixpricedirective pds
1011
+ }
1012
+ where
1013
+ fixtransaction t@ Transaction {tpostings= ps} = t{tpostings= map fixposting ps}
1014
+ fixposting p = p{pamount= styleMixedAmount styles $ pamount p
1015
+ ,pbalanceassertion= fixbalanceassertion <$> pbalanceassertion p}
1016
+ -- balance assertion/assignment amounts, and price amounts, are always displayed
1017
+ -- (eg by print) at full precision
1018
+ fixbalanceassertion ba = ba{baamount= styleAmountExceptPrecision styles $ baamount ba}
1019
+ fixpricedirective pd@ PriceDirective {pdamount= a} = pd{pdamount= styleAmountExceptPrecision styles a}
1020
+
968
1021
-- | Choose and apply a consistent display style to the posting
969
1022
-- amounts in each commodity (see journalCommodityStyles).
970
1023
-- Can return an error message eg if inconsistent number formats are found.
971
- journalApplyCommodityStyles :: Journal -> Either String Journal
972
- journalApplyCommodityStyles j @ Journal {jtxns = ts, jpricedirectives = pds} =
1024
+ journalInferAndApplyCommodityStyles :: Journal -> Either String Journal
1025
+ journalInferAndApplyCommodityStyles j =
973
1026
case journalInferCommodityStyles j of
974
1027
Left e -> Left e
975
- Right j' -> Right j' '
1028
+ Right j' -> Right $ journalApplyCommodityStyles allstyles j '
976
1029
where
977
- styles = journalCommodityStyles j'
978
- j'' = j'{jtxns= map fixtransaction ts
979
- ,jpricedirectives= map fixpricedirective pds
980
- }
981
- fixtransaction t@ Transaction {tpostings= ps} = t{tpostings= map fixposting ps}
982
- fixposting p = p{pamount= styleMixedAmount styles $ pamount p
983
- ,pbalanceassertion= fixbalanceassertion <$> pbalanceassertion p}
984
- -- balance assertion amounts are always displayed (by print) at full precision, per docs
985
- fixbalanceassertion ba = ba{baamount= styleAmountExceptPrecision styles $ baamount ba}
986
- fixpricedirective pd@ PriceDirective {pdamount= a} = pd{pdamount= styleAmountExceptPrecision styles a}
1030
+ allstyles = journalCommodityStyles j'
987
1031
988
1032
-- | Get the canonical amount styles for this journal, whether (in order of precedence):
989
1033
-- set globally in InputOpts,
@@ -1002,18 +1046,6 @@ journalCommodityStyles j =
1002
1046
defaultcommoditystyle = M. fromList $ catMaybes [jparsedefaultcommodity j]
1003
1047
inferredstyles = jinferredcommodities j
1004
1048
1005
- -- | Collect and save inferred amount styles for each commodity based on
1006
- -- the posting amounts in that commodity (excluding price amounts), ie:
1007
- -- "the format of the first amount, adjusted to the highest precision of all amounts".
1008
- -- Can return an error message eg if inconsistent number formats are found.
1009
- journalInferCommodityStyles :: Journal -> Either String Journal
1010
- journalInferCommodityStyles j =
1011
- case
1012
- commodityStylesFromAmounts $ journalStyleInfluencingAmounts j
1013
- of
1014
- Left e -> Left e
1015
- Right cs -> Right j{jinferredcommodities = dbg7 " journalInferCommodityStyles" cs}
1016
-
1017
1049
-- -- | Apply this journal's historical price records to unpriced amounts where possible.
1018
1050
-- journalApplyPriceDirectives :: Journal -> Journal
1019
1051
-- journalApplyPriceDirectives j@Journal{jtxns=ts} = j{jtxns=map fixtransaction ts}
@@ -1242,7 +1274,7 @@ journalApplyAliases aliases j =
1242
1274
-- liabilities:debts $1
1243
1275
-- assets:bank:checking
1244
1276
--
1245
- Right samplejournal = journalBalanceTransactions False $
1277
+ Right samplejournal = journalBalanceTransactions False False $
1246
1278
nulljournal
1247
1279
{jtxns = [
1248
1280
txnTieKnot $ Transaction {
@@ -1385,7 +1417,7 @@ tests_Journal = tests "Journal" [
1385
1417
,tests " journalBalanceTransactions" [
1386
1418
1387
1419
test " balance-assignment" $ do
1388
- let ej = journalBalanceTransactions True $
1420
+ let ej = journalBalanceTransactions False True $
1389
1421
-- 2019/01/01
1390
1422
-- (a) = 1
1391
1423
nulljournal{ jtxns = [
@@ -1396,7 +1428,7 @@ tests_Journal = tests "Journal" [
1396
1428
(jtxns j & head & tpostings & head & pamount) @?= Mixed [num 1 ]
1397
1429
1398
1430
,test " same-day-1" $ do
1399
- assertRight $ journalBalanceTransactions True $
1431
+ assertRight $ journalBalanceTransactions False True $
1400
1432
-- 2019/01/01
1401
1433
-- (a) = 1
1402
1434
-- 2019/01/01
@@ -1407,7 +1439,7 @@ tests_Journal = tests "Journal" [
1407
1439
]}
1408
1440
1409
1441
,test " same-day-2" $ do
1410
- assertRight $ journalBalanceTransactions True $
1442
+ assertRight $ journalBalanceTransactions False True $
1411
1443
-- 2019/01/01
1412
1444
-- (a) 2 = 2
1413
1445
-- 2019/01/01
@@ -1425,7 +1457,7 @@ tests_Journal = tests "Journal" [
1425
1457
]}
1426
1458
1427
1459
,test " out-of-order" $ do
1428
- assertRight $ journalBalanceTransactions True $
1460
+ assertRight $ journalBalanceTransactions False True $
1429
1461
-- 2019/1/2
1430
1462
-- (a) 1 = 2
1431
1463
-- 2019/1/1
0 commit comments