From 5a3462ce483842846fbbb59ad2e2f5865212098b Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Thu, 11 Oct 2018 12:37:56 -0400 Subject: [PATCH] read: Integrate transaction modifiers with journal finalization Currently, automated transactions are added before the journal is finalized. This means that no inferred values will be picked up. We change the procedure, if `auto_` is set, to 1. first run `journalFinalise` without assertion checking (assertions might be wrong until automated transactions), but with reordering 2. Insert transaction modifiers 3. Run `journalFinalise` again, this time with assertion checking as set in the options, and without reordering. If `auto_` is not set, all works as before. Closes: #893 --- hledger-lib/Hledger/Read/Common.hs | 44 ++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/hledger-lib/Hledger/Read/Common.hs b/hledger-lib/Hledger/Read/Common.hs index 2ca8f598f..bf53f5d97 100644 --- a/hledger-lib/Hledger/Read/Common.hs +++ b/hledger-lib/Hledger/Read/Common.hs @@ -256,10 +256,23 @@ parseAndFinaliseJournal parser iopts f txt = do Left e -> throwError $ customErrorBundlePretty e Right pj -> - let pj' = if auto_ iopts then applyTransactionModifiers pj else pj in - case journalFinalise t f txt (not $ ignore_assertions_ iopts) pj' of - Right j -> return j - Left e -> throwError e + -- If we are using automated transactions, we finalize twice: + -- once before and once after. However, if we are running it + -- twice, we don't check assertions the first time (they might + -- be false pending modifiers) and we don't reorder the second + -- time. If we are only running once, we reorder and follow + -- the options for checking assertions. + let runFin :: Bool -> Bool -> (ParsedJournal -> Either String Journal) + runFin reorder ignore = journalFinalise t f txt reorder ignore + fj = if auto_ iopts + then applyTransactionModifiers <$> + runFin True False pj >>= + runFin False (not $ ignore_assertions_ iopts) + else runFin True (not $ ignore_assertions_ iopts) pj + in + case fj of + Right j -> return j + Left e -> throwError e parseAndFinaliseJournal' :: JournalParser IO ParsedJournal -> InputOpts -> FilePath -> Text -> ExceptT String IO Journal @@ -273,11 +286,24 @@ parseAndFinaliseJournal' parser iopts f txt = do case ep of Left e -> throwError $ customErrorBundlePretty e - Right pj -> - let pj' = if auto_ iopts then applyTransactionModifiers pj else pj in - case journalFinalise t f txt (not $ ignore_assertions_ iopts) pj' of - Right j -> return j - Left e -> throwError e + Right pj -> + -- If we are using automated transactions, we finalize twice: + -- once before and once after. However, if we are running it + -- twice, we don't check assertions the first time (they might + -- be false pending modifiers) and we don't reorder the second + -- time. If we are only running once, we reorder and follow the + -- options for checking assertions. + let runFin :: Bool -> Bool -> (ParsedJournal -> Either String Journal) + runFin reorder ignore = journalFinalise t f txt reorder ignore + fj = if auto_ iopts + then applyTransactionModifiers <$> + runFin True False pj >>= + runFin False (not $ ignore_assertions_ iopts) + else runFin True (not $ ignore_assertions_ iopts) pj + in + case fj of + Right j -> return j + Left e -> throwError e setYear :: Year -> JournalParser m () setYear y = modify' (\j -> j{jparsedefaultyear=Just y})