hledger-iadd 1.3.13 → 1.3.14
raw patch · 4 files changed
+54/−31 lines, 4 filesdep ~hledger-libPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: hledger-lib
API changes (from Hackage documentation)
+ Model: isSubsetTransaction :: Transaction -> Transaction -> Bool
Files
- ChangeLog.md +7/−0
- hledger-iadd.cabal +8/−9
- src/Model.hs +23/−19
- tests/ModelSpec.hs +16/−3
ChangeLog.md view
@@ -1,3 +1,10 @@+# 1.3.14 [2021-03-13]++ - bugfix: Fix test failures+ - bugfix: Fix amount suggestion in some circumstances+ - dependencies: Remove GHC 8.0, 8.2 and 8.4 from list of officially supported+ compilers. They might still work+ # 1.3.13 [2021-03-10] - dependencies: Support (and require) hledger-lib-1.21
hledger-iadd.cabal view
@@ -1,5 +1,5 @@ name: hledger-iadd-version: 1.3.13+version: 1.3.14 synopsis: A terminal UI as drop-in replacement for hledger add description: This is a terminal UI as drop-in replacement for hledger add. .@@ -30,11 +30,10 @@ category: Finance, Console build-type: Simple cabal-version: >=1.10-tested-with: GHC ==8.0.2- , GHC ==8.2.2- , GHC ==8.4.4- , GHC ==8.6.3- +tested-with: GHC ==8.6.5+ , GHC ==8.8.4+ , GHC ==8.10.4+ extra-source-files: doc/screencast.gif README.md@@ -61,7 +60,7 @@ , Data.Time.Ext default-language: Haskell2010 build-depends: base >= 4.9 && < 5- , hledger-lib >= 1.20.99 && < 1.22+ , hledger-lib >= 1.21 && < 1.22 , brick >= 0.27 , vty >= 5.4 , text@@ -88,7 +87,7 @@ default-language: Haskell2010 build-depends: base >= 4.9 && < 5 , hledger-iadd- , hledger-lib >= 1.20.99 && < 1.22+ , hledger-lib >= 1.21 && < 1.22 , brick >= 0.27 , vty >= 5.4 , text@@ -116,7 +115,7 @@ default-language: Haskell2010 build-depends: base >= 4.9 && < 5 , hledger-iadd- , hledger-lib >= 1.20.99 && < 1.22+ , hledger-lib >= 1.21 && < 1.22 , text , transformers >= 0.3 , time >= 1.5
src/Model.hs view
@@ -17,6 +17,7 @@ -- * Helpers exported for easier testing , accountsByFrequency , isDuplicateTransaction+ , isSubsetTransaction ) where import Data.Function@@ -31,10 +32,12 @@ import qualified Hledger as HL import Data.Foldable import Control.Applicative+import Control.Arrow ((&&&)) import AmountParser import DateParser + type Comment = Text type Duplicate = Bool @@ -61,7 +64,7 @@ DescriptionQuestion day comment -> return $ Right $ Step $ AccountQuestion HL.nulltransaction { HL.tdate = day- , HL.tdescription = (fromEither entryText)+ , HL.tdescription = fromEither entryText , HL.tcomment = comment } "" -- empty comment@@ -69,7 +72,7 @@ | T.null (fromEither entryText) && transactionBalanced trans -> return $ Right $ Step $ FinalQuestion trans (isDuplicateTransaction journal trans) | T.null (fromEither entryText) -- unbalanced- -> return $ Left $ "Transaction not balanced! Please balance your transaction before adding it to the journal."+ -> return $ Left "Transaction not balanced! Please balance your transaction before adding it to the journal." | otherwise -> return $ Right $ Step $ AmountQuestion (fromEither entryText) trans comment AmountQuestion name trans comment -> case parseAmount journal (fromEither entryText) of@@ -105,7 +108,7 @@ context j matchAlgo _ entryText (AccountQuestion _ _) = return $ let names = accountsByFrequency j in filter (matches matchAlgo entryText) names-context journal _ _ entryText (AmountQuestion _ _ _) = return $+context journal _ _ entryText (AmountQuestion {}) = return $ maybeToList $ T.pack . HL.showMixedAmount <$> trySumAmount journal entryText context _ _ _ _ (FinalQuestion _ _) = return [] @@ -119,17 +122,17 @@ suggest journal _ (AccountQuestion trans _) = return $ if numPostings trans /= 0 && transactionBalanced trans then Nothing- else HL.paccount <$> (suggestAccountPosting journal trans)-suggest journal _ (AmountQuestion account trans _) = return $ fmap (T.pack . HL.showMixedAmount) $ do+ else HL.paccount <$> suggestAccountPosting journal trans+suggest journal _ (AmountQuestion account trans _) = return $ fmap (T.pack . HL.showMixedAmount) $ case findLastSimilar journal trans of Nothing | null (HL.tpostings trans) -> Nothing -- Don't suggest an amount for first account | otherwise -> Just $ negativeAmountSum trans- Just last+ Just last | transactionBalanced trans || (trans `isSubsetTransaction` last)- -> HL.pamount <$> (findPostingByAcc account last)+ -> HL.pamount <$> findPostingByAcc account last | otherwise -> Just $ negativeAmountSum trans suggest _ _ (FinalQuestion _ _) = return $ Just "y"@@ -179,16 +182,16 @@ | otherwise = matches' (T.toCaseFold a) (T.toCaseFold b) where matches' a' b'- | algo == Fuzzy && T.any (== ':') b' = all (`fuzzyMatch` (T.splitOn ":" b')) (T.words a')+ | algo == Fuzzy && T.any (== ':') b' = all (`fuzzyMatch` T.splitOn ":" b') (T.words a') | otherwise = all (`T.isInfixOf` b') (T.words a') fuzzyMatch :: Text -> [Text] -> Bool fuzzyMatch _ [] = False-fuzzyMatch query (part : partsRest) = case (T.uncons query) of+fuzzyMatch query (part : partsRest) = case T.uncons query of Nothing -> True Just (c, queryRest) | c == ':' -> fuzzyMatch queryRest partsRest- | otherwise -> fuzzyMatch query partsRest || case (T.uncons part) of+ | otherwise -> fuzzyMatch query partsRest || case T.uncons part of Nothing -> False Just (c2, partRest) | c == c2 -> fuzzyMatch queryRest (partRest : partsRest)@@ -202,7 +205,7 @@ } addPosting :: HL.Posting -> HL.Transaction -> HL.Transaction-addPosting p t = t { HL.tpostings = (HL.tpostings t) ++ [p] }+addPosting p t = t { HL.tpostings = HL.tpostings t ++ [p] } trySumAmount :: HL.Journal -> Text -> Maybe HL.MixedAmount trySumAmount ctx = either (const Nothing) Just . parseAmount ctx@@ -230,7 +233,7 @@ suggestCorrespondingPosting :: HL.Transaction -> HL.Transaction -> Maybe HL.Posting suggestCorrespondingPosting current reference = let postingsEntered = length curPostings in- if postingsEntered < (length refPostings) then+ if postingsEntered < length refPostings then Just (refPostings !! postingsEntered) else suggestNextPosting current reference@@ -245,7 +248,7 @@ suggestAccountPosting journal trans = case findLastSimilar journal trans of Just t -> suggestNextPosting trans t- Nothing -> (last <$> listToMaybe' (HL.jtxns journal)) >>= (suggestCorrespondingPosting trans)+ Nothing -> listToMaybe' (HL.jtxns journal) >>= suggestCorrespondingPosting trans . last -- | Return the first Posting that matches the given account name in the transaction findPostingByAcc :: HL.AccountName -> HL.Transaction -> Maybe HL.Posting@@ -264,8 +267,9 @@ null (deleteFirstsBy cmpPosting currPostings origPostings) where cmpPosting a b = HL.paccount a == HL.paccount b- && HL.pamount a == HL.pamount b+ && cmpAmount (HL.pamount a) (HL.pamount b) + cmpAmount (HL.Mixed a) (HL.Mixed b) = ((==) `on` map (HL.acommodity &&& HL.aquantity)) a b listToMaybe' :: [a] -> Maybe [a] listToMaybe' [] = Nothing@@ -276,7 +280,7 @@ -- | Returns True if all postings balance and the transaction is not empty transactionBalanced :: HL.Transaction -> Bool-transactionBalanced trans = HL.isTransactionBalanced Nothing trans+transactionBalanced = HL.isTransactionBalanced Nothing -- | Computes the sum of all postings in the transaction and inverts it negativeAmountSum :: HL.Transaction -> HL.MixedAmount@@ -287,7 +291,7 @@ -- | Compare two transaction descriptions based on their number of occurences in -- the given journal. descUses :: HL.Journal -> Text -> Text -> Ordering-descUses journal = compare `on` (Down . flip HM.lookup usesMap)+descUses journal = compare `on` Down . flip HM.lookup usesMap where usesMap = foldr (count . HL.tdescription) HM.empty $ HL.jtxns journal -- Add one to the current count of this element@@ -305,12 +309,12 @@ declaredAccounts = HL.expandAccountNames (HL.journalAccountNamesDeclared journal) mapWithDeclared = foldr insertIfNotPresent mapWithSubaccounts declaredAccounts in- map fst (sortBy (compare `on` (Down . snd)) (HM.toList mapWithDeclared))+ map fst (sortBy (compare `on` Down . snd) (HM.toList mapWithDeclared)) where insertOrPlusOne = HM.alter (Just . maybe 1 (+1))- insertIfNotPresent account = HM.insertWith (flip const) account 0+ insertIfNotPresent account = HM.insertWith (\ _ x -> x) account 0 subaccounts m = HL.expandAccountNames (HM.keys m) -- | Deterimine if a given transaction already occurs in the journal@@ -333,7 +337,7 @@ postingAttributes = [ cmp HL.pdate, cmp HL.pdate2, cmp HL.pstatus, cmp HL.paccount , cmpMixedAmount `on` HL.pamount, cmpPType `on` HL.ptype- , (fmap fold . liftA2 cmpBalanceAssertion) `on` HL.pbalanceassertion+ , fmap fold . liftA2 cmpBalanceAssertion `on` HL.pbalanceassertion ] -- | Ammount attributes that are compared to determine duplicates
tests/ModelSpec.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} module ModelSpec (spec) where import Test.Hspec@@ -23,7 +24,7 @@ describe "setCurrentComment" setCurrentCommentSpec describe "setTransactionComment" setTransactionCommentSpec describe "isDuplicateTransaction" isDuplicateTransactionSpec-+ describe "isSubsetTransaction" isSubsetTransactionSpec suggestSpec :: Spec suggestSpec = do@@ -91,7 +92,8 @@ it "includes accounts from the 'account directive'" $ do let j = (mkJournal [ ((2017, 1, 1), "Foo", [("x:y", 2)]) ]) { HL.jdeclaredaccounts = [("foo:bar", HL.nullaccountdeclarationinfo)]}- accountsByFrequency j `shouldContain` ["foo:bar", "foo"]+ accountsByFrequency j `shouldContain` ["foo:bar"]+ accountsByFrequency j `shouldContain` ["foo"] setCurrentCommentSpec :: Spec@@ -193,7 +195,7 @@ -- We use 'read' in the following because hledger-lib 1.19 changed the -- type of 'asprecision' from Int to 'AmountPrecision'. 'read' works in -- both cases.- a2 = (HL.eur 0.5) { HL.astyle = HL.amountstyle { HL.asprecision = read "15"} }+ a2 = (HL.eur 0.5) { HL.astyle = HL.amountstyle { HL.asprecision = HL.Precision 15 } } p1 = mkPosting ("Test", -1) p2 = HL.nullposting { HL.paccount = "Toast", HL.pamount = HL.Mixed [a1] }@@ -204,6 +206,17 @@ t2 = t0 { HL.tpostings = [p1,p3,p3] } isDuplicateTransaction (HL.addTransaction t1 HL.nulljournal) t2 `shouldBe` True++isSubsetTransactionSpec :: Spec+isSubsetTransactionSpec =+ it "ignores amount presentation" $ do+ let t1 = mkTransaction ((2021,3,12), "Test", [("Test", 1)])+ t2' = mkTransaction ((2021,3,12), "Test", [("Toast", -1)])+ testPosting = HL.nullposting+ { HL.paccount = "Test"+ , HL.pamount = HL.mixed [ (HL.eur 1) { HL.astyle = HL.amountstyle { HL.asdecimalpoint = Just ';' }}]}+ t2 = t2' { HL.tpostings = testPosting : HL.tpostings t2' }+ isSubsetTransaction t1 t2 `shouldBe` True -- Helpers