dev: balanceTransaction -> balanceSingleTransaction
This commit is contained in:
parent
69b63695fc
commit
b2a0de75e2
@ -16,7 +16,7 @@ module Hledger.Data.Balancing
|
|||||||
, defbalancingopts
|
, defbalancingopts
|
||||||
-- * transaction balancing
|
-- * transaction balancing
|
||||||
, isTransactionBalanced
|
, isTransactionBalanced
|
||||||
, balanceTransaction
|
, balanceSingleTransaction
|
||||||
, balanceTransactionHelper
|
, balanceTransactionHelper
|
||||||
-- * assertion validation
|
-- * assertion validation
|
||||||
, transactionCheckAssertions
|
, transactionCheckAssertions
|
||||||
@ -173,32 +173,21 @@ transactionCheckAssertions bopts j t =
|
|||||||
Right _ -> Right t
|
Right _ -> Right t
|
||||||
Left e -> Left e
|
Left e -> Left e
|
||||||
|
|
||||||
-- | Balance this transaction, ensuring that its postings
|
-- | Balance this isolated transaction, ensuring that its postings
|
||||||
-- (and its balanced virtual postings) sum to 0,
|
-- (and its balanced virtual postings) sum to 0,
|
||||||
-- by inferring a missing amount or conversion price(s) if needed.
|
-- by inferring a missing amount or conversion price(s) if needed.
|
||||||
-- Or if balancing is not possible, because the amounts don't sum to 0 or
|
-- Or if balancing is not possible, because the amounts don't sum to 0 or
|
||||||
-- because there's more than one missing amount, return an error message.
|
-- because there's more than one missing amount, return an error message.
|
||||||
--
|
--
|
||||||
-- Transactions with balance assignments can have more than one
|
-- Note this is not as accurate as @balanceTransactionInJournal@,
|
||||||
-- missing amount; to balance those you should use the more powerful
|
-- which considers the whole journal when calculating balance assignments and balance assertions.
|
||||||
-- journalBalanceTransactions.
|
balanceSingleTransaction :: BalancingOpts -> Transaction -> Either String Transaction
|
||||||
--
|
balanceSingleTransaction bopts = fmap fst . balanceTransactionHelper bopts
|
||||||
-- The "sum to 0" test is done using commodity display precisions,
|
|
||||||
-- if provided, so that the result agrees with the numbers users can see.
|
|
||||||
--
|
|
||||||
balanceTransaction ::
|
|
||||||
BalancingOpts
|
|
||||||
-> Transaction
|
|
||||||
-> Either String Transaction
|
|
||||||
balanceTransaction bopts = fmap fst . balanceTransactionHelper bopts
|
|
||||||
|
|
||||||
-- | Helper used by balanceTransaction and balanceTransactionWithBalanceAssignmentAndCheckAssertionsB;
|
-- | Helper used by balanceSingleTransaction and balanceTransactionWithBalanceAssignmentAndCheckAssertionsB;
|
||||||
-- use one of those instead.
|
-- use one of those instead.
|
||||||
-- It also returns a list of accounts and amounts that were inferred.
|
-- It also returns a list of accounts and amounts that were inferred.
|
||||||
balanceTransactionHelper ::
|
balanceTransactionHelper :: BalancingOpts -> Transaction -> Either String (Transaction, [(AccountName, MixedAmount)])
|
||||||
BalancingOpts
|
|
||||||
-> Transaction
|
|
||||||
-> Either String (Transaction, [(AccountName, MixedAmount)])
|
|
||||||
balanceTransactionHelper bopts t = do
|
balanceTransactionHelper bopts t = do
|
||||||
let lbl = lbl_ "balanceTransactionHelper"
|
let lbl = lbl_ "balanceTransactionHelper"
|
||||||
(t', inferredamtsandaccts) <- t
|
(t', inferredamtsandaccts) <- t
|
||||||
@ -411,7 +400,7 @@ costInferrerFor t pt = maybe id infercost inferFromAndTo
|
|||||||
-- journalBalanceTransactions
|
-- journalBalanceTransactions
|
||||||
-- runST
|
-- runST
|
||||||
-- runExceptT
|
-- runExceptT
|
||||||
-- balanceTransaction (Transaction.hs)
|
-- balanceSingleTransaction (Transaction.hs)
|
||||||
-- balanceTransactionHelper
|
-- balanceTransactionHelper
|
||||||
-- runReaderT
|
-- runReaderT
|
||||||
-- balanceTransactionAndCheckAssertionsB
|
-- balanceTransactionAndCheckAssertionsB
|
||||||
@ -422,7 +411,7 @@ costInferrerFor t pt = maybe id infercost inferFromAndTo
|
|||||||
-- journalCheckBalanceAssertions
|
-- journalCheckBalanceAssertions
|
||||||
-- journalBalanceTransactions
|
-- journalBalanceTransactions
|
||||||
-- transactionWizard, postingsBalanced (Add.hs), tests (Transaction.hs)
|
-- transactionWizard, postingsBalanced (Add.hs), tests (Transaction.hs)
|
||||||
-- balanceTransaction (Transaction.hs) XXX hledger add won't allow balance assignments + missing amount ?
|
-- balanceSingleTransaction (Transaction.hs) XXX hledger add won't allow balance assignments + missing amount ?
|
||||||
|
|
||||||
-- | Monad used for statefully balancing/amount-inferring/assertion-checking
|
-- | Monad used for statefully balancing/amount-inferring/assertion-checking
|
||||||
-- a sequence of transactions.
|
-- a sequence of transactions.
|
||||||
@ -532,7 +521,7 @@ journalBalanceTransactions bopts' j' =
|
|||||||
-- postponing those which do until later. The balanced ones are split into their postings,
|
-- postponing those which do until later. The balanced ones are split into their postings,
|
||||||
-- keeping these and the not-yet-balanced transactions in the same relative order.
|
-- keeping these and the not-yet-balanced transactions in the same relative order.
|
||||||
psandts :: [Either Posting Transaction] <- fmap concat $ forM ts $ \case
|
psandts :: [Either Posting Transaction] <- fmap concat $ forM ts $ \case
|
||||||
t | null $ assignmentPostings t -> case balanceTransaction bopts t of
|
t | null $ assignmentPostings t -> case balanceSingleTransaction bopts t of
|
||||||
Left e -> throwError e
|
Left e -> throwError e
|
||||||
Right t' -> do
|
Right t' -> do
|
||||||
lift $ writeArray balancedtxns (tindex t') t'
|
lift $ writeArray balancedtxns (tindex t') t'
|
||||||
@ -810,10 +799,10 @@ tests_Balancing =
|
|||||||
(fst <$> transactionInferBalancingAmount M.empty nulltransaction{tpostings = ["a" `post` usd (-5), "b" `post` (eur 3 @@ usd 4), "c" `post` missingamt]}) @?=
|
(fst <$> transactionInferBalancingAmount M.empty nulltransaction{tpostings = ["a" `post` usd (-5), "b" `post` (eur 3 @@ usd 4), "c" `post` missingamt]}) @?=
|
||||||
Right nulltransaction{tpostings = ["a" `post` usd (-5), "b" `post` (eur 3 @@ usd 4), "c" `post` usd 1]}
|
Right nulltransaction{tpostings = ["a" `post` usd (-5), "b" `post` (eur 3 @@ usd 4), "c" `post` usd 1]}
|
||||||
|
|
||||||
, testGroup "balanceTransaction" [
|
, testGroup "balanceSingleTransaction" [
|
||||||
testCase "detect unbalanced entry, sign error" $
|
testCase "detect unbalanced entry, sign error" $
|
||||||
assertLeft
|
assertLeft
|
||||||
(balanceTransaction defbalancingopts
|
(balanceSingleTransaction defbalancingopts
|
||||||
(Transaction
|
(Transaction
|
||||||
0
|
0
|
||||||
""
|
""
|
||||||
@ -828,7 +817,7 @@ tests_Balancing =
|
|||||||
[posting {paccount = "a", pamount = mixedAmount (usd 1)}, posting {paccount = "b", pamount = mixedAmount (usd 1)}]))
|
[posting {paccount = "a", pamount = mixedAmount (usd 1)}, posting {paccount = "b", pamount = mixedAmount (usd 1)}]))
|
||||||
,testCase "detect unbalanced entry, multiple missing amounts" $
|
,testCase "detect unbalanced entry, multiple missing amounts" $
|
||||||
assertLeft $
|
assertLeft $
|
||||||
balanceTransaction defbalancingopts
|
balanceSingleTransaction defbalancingopts
|
||||||
(Transaction
|
(Transaction
|
||||||
0
|
0
|
||||||
""
|
""
|
||||||
@ -845,7 +834,7 @@ tests_Balancing =
|
|||||||
])
|
])
|
||||||
,testCase "one missing amount is inferred" $
|
,testCase "one missing amount is inferred" $
|
||||||
(pamount . last . tpostings <$>
|
(pamount . last . tpostings <$>
|
||||||
balanceTransaction defbalancingopts
|
balanceSingleTransaction defbalancingopts
|
||||||
(Transaction
|
(Transaction
|
||||||
0
|
0
|
||||||
""
|
""
|
||||||
@ -861,7 +850,7 @@ tests_Balancing =
|
|||||||
Right (mixedAmount $ usd (-1))
|
Right (mixedAmount $ usd (-1))
|
||||||
,testCase "conversion price is inferred" $
|
,testCase "conversion price is inferred" $
|
||||||
(pamount . headErr . tpostings <$> -- PARTIAL headErr succeeds because non-null postings list
|
(pamount . headErr . tpostings <$> -- PARTIAL headErr succeeds because non-null postings list
|
||||||
balanceTransaction defbalancingopts
|
balanceSingleTransaction defbalancingopts
|
||||||
(Transaction
|
(Transaction
|
||||||
0
|
0
|
||||||
""
|
""
|
||||||
@ -877,9 +866,9 @@ tests_Balancing =
|
|||||||
, posting {paccount = "b", pamount = mixedAmount (eur (-1))}
|
, posting {paccount = "b", pamount = mixedAmount (eur (-1))}
|
||||||
])) @?=
|
])) @?=
|
||||||
Right (mixedAmount $ usd 1.35 @@ eur 1)
|
Right (mixedAmount $ usd 1.35 @@ eur 1)
|
||||||
,testCase "balanceTransaction balances based on cost if there are unit prices" $
|
,testCase "balanceSingleTransaction balances based on cost if there are unit prices" $
|
||||||
assertRight $
|
assertRight $
|
||||||
balanceTransaction defbalancingopts
|
balanceSingleTransaction defbalancingopts
|
||||||
(Transaction
|
(Transaction
|
||||||
0
|
0
|
||||||
""
|
""
|
||||||
@ -894,9 +883,9 @@ tests_Balancing =
|
|||||||
[ posting {paccount = "a", pamount = mixedAmount $ usd 1 `at` eur 2}
|
[ posting {paccount = "a", pamount = mixedAmount $ usd 1 `at` eur 2}
|
||||||
, posting {paccount = "a", pamount = mixedAmount $ usd (-2) `at` eur 1}
|
, posting {paccount = "a", pamount = mixedAmount $ usd (-2) `at` eur 1}
|
||||||
])
|
])
|
||||||
,testCase "balanceTransaction balances based on cost if there are total prices" $
|
,testCase "balanceSingleTransaction balances based on cost if there are total prices" $
|
||||||
assertRight $
|
assertRight $
|
||||||
balanceTransaction defbalancingopts
|
balanceSingleTransaction defbalancingopts
|
||||||
(Transaction
|
(Transaction
|
||||||
0
|
0
|
||||||
""
|
""
|
||||||
|
|||||||
@ -96,7 +96,7 @@ validateTransaction ::
|
|||||||
-> FormResult (Transaction, FilePath)
|
-> FormResult (Transaction, FilePath)
|
||||||
validateTransaction deffile dateRes descRes postingsRes fileRes =
|
validateTransaction deffile dateRes descRes postingsRes fileRes =
|
||||||
case makeTransaction <$> dateRes <*> descRes <*> postingsRes <*> fileRes of
|
case makeTransaction <$> dateRes <*> descRes <*> postingsRes <*> fileRes of
|
||||||
FormSuccess (txn,f) -> case balanceTransaction defbalancingopts txn of
|
FormSuccess (txn,f) -> case balanceSingleTransaction defbalancingopts txn of
|
||||||
Left e -> FormFailure [T.pack e]
|
Left e -> FormFailure [T.pack e]
|
||||||
Right txn' -> FormSuccess (txn',f)
|
Right txn' -> FormSuccess (txn',f)
|
||||||
x -> x
|
x -> x
|
||||||
|
|||||||
@ -346,7 +346,7 @@ descriptionAndCommentWizard PrevInput{..} EntryState{..} = do
|
|||||||
return $ Just (desc, comment)
|
return $ Just (desc, comment)
|
||||||
|
|
||||||
postingsBalanced :: [Posting] -> Bool
|
postingsBalanced :: [Posting] -> Bool
|
||||||
postingsBalanced ps = isRight $ balanceTransaction defbalancingopts nulltransaction{tpostings=ps}
|
postingsBalanced ps = isRight $ balanceSingleTransaction defbalancingopts nulltransaction{tpostings=ps}
|
||||||
|
|
||||||
accountWizard PrevInput{..} EntryState{..} = do
|
accountWizard PrevInput{..} EntryState{..} = do
|
||||||
let pnum = length esPostings + 1
|
let pnum = length esPostings + 1
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user