imp:journal: balance transactions with local precisions [#2402]

This commit is contained in:
Simon Michael 2025-06-07 15:23:31 -10:00
parent 82ba831822
commit a9408b8cd5
3 changed files with 33 additions and 7 deletions

View File

@ -34,6 +34,7 @@ import Control.Monad.Reader as R (ReaderT, reader, runReaderT, ask, asks)
import Control.Monad.ST (ST, runST)
import Control.Monad.Trans.Class (lift)
import Data.Array.ST (STArray, getElems, newListArray, writeArray)
import Data.Bifunctor (second)
import Data.Foldable (asum)
import Data.Function ((&))
import Data.Functor ((<&>), void)
@ -49,7 +50,6 @@ import qualified Data.Map as M
import Safe (headErr)
import Text.Printf (printf)
import Hledger.Utils
import Hledger.Data.Types
import Hledger.Data.AccountName (isAccountNamePrefixOf)
import Hledger.Data.Amount
@ -57,7 +57,7 @@ import Hledger.Data.Journal
import Hledger.Data.Posting
import Hledger.Data.Transaction
import Hledger.Data.Errors
import Data.Bifunctor (second)
import Hledger.Utils
data BalancingOpts = BalancingOpts
@ -92,7 +92,8 @@ defbalancingopts = BalancingOpts
-- (using the given display styles if provided)
--
transactionCheckBalanced :: BalancingOpts -> Transaction -> [String]
transactionCheckBalanced BalancingOpts{commodity_styles_} t = errs
-- transactionCheckBalanced BalancingOpts{commodity_styles_=_mstyles} t = errs
transactionCheckBalanced _ t = errs
where
-- get real and balanced virtual postings, to be checked separately
(rps, bvps) = foldr partitionPosting ([], []) $ tpostings t
@ -109,10 +110,9 @@ transactionCheckBalanced BalancingOpts{commodity_styles_} t = errs
| costPostingTagName `elem` map fst (ptags p) = mixedAmountStripCosts $ pamount p
| otherwise = mixedAmountCost $ pamount p
-- transaction balancedness is checked at each commodity's display precision
lookszero = mixedAmountLooksZero . atdisplayprecision
where
atdisplayprecision = maybe id styleAmounts $ commodity_styles_
lookszero = mixedAmountLooksZero .
-- maybe id styleAmounts _mstyles -- when rounded with global/journal precisions
styleAmounts (transactionCommodityStylesWith HardRounding t) -- when rounded with transaction's precisions
-- when there's multiple non-zeros, check they do not all have the same sign
(rsignsok, bvsignsok) = (signsOk rps, signsOk bvps)

View File

@ -33,6 +33,8 @@ module Hledger.Data.Transaction
, transactionMapPostings
, transactionMapPostingAmounts
, transactionAmounts
, transactionCommodityStyles
, transactionCommodityStylesWith
, transactionNegate
, partitionAndCheckConversionPostings
, transactionAddTags
@ -483,6 +485,17 @@ transactionMapPostingAmounts f = transactionMapPostings (postingTransformAmount
transactionAmounts :: Transaction -> [MixedAmount]
transactionAmounts = map pamount . tpostings
-- | Get the canonical amount styles inferred from this transaction's amounts.
transactionCommodityStyles :: Transaction -> M.Map CommoditySymbol AmountStyle
transactionCommodityStyles =
either (const mempty) id . -- ignore style problems, commodityStylesFromAmounts doesn't report them currently
commodityStylesFromAmounts . concatMap (amountsRaw . pamount) . tpostings
-- | Like transactionCommodityStyles, but attach a particular rounding strategy to the styles,
-- affecting how they will affect display precisions when applied.
transactionCommodityStylesWith :: Rounding -> Transaction -> M.Map CommoditySymbol AmountStyle
transactionCommodityStylesWith r = amountStylesSetRounding r . transactionCommodityStyles
-- | Flip the sign of this transaction's posting amounts (and balance assertion amounts).
transactionNegate :: Transaction -> Transaction
transactionNegate = transactionMapPostings postingNegate

View File

@ -188,3 +188,16 @@ $ hledger -f - bal -O csv
"b","1 JPY"
"c","1000 JPY"
"Total:","1002 JPY"
# ** 13. An entry like this, generated by bean-report, did not balance in hledger <=1.43,
# because the P amount influenced the commodity's display (and balancing) precision.
# From 1.44 transaction balancing uses the transaction's local precisions,
# so CNY's precision is 2 and this does balance.
<
P 2025-01-01 USD 7.147224669603524229074889868 CNY
2025-01-01
a -113.50 USD @ 7.147224669603524229074889868 CNY
a 811.21 CNY
$ hledger -f - check