hledger-lib 1.52 → 1.52.1
raw patch · 11 files changed
+99/−81 lines, 11 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Hledger.Data: UnrealisedGain :: AccountType
+ Hledger.Data.Balancing: [account_types_] :: BalancingOpts -> Map AccountName AccountType
+ Hledger.Data.Balancing: account_types :: HasBalancingOpts c => Lens' c (Map AccountName AccountType)
+ Hledger.Data.Types: UnrealisedGain :: AccountType
+ Hledger.Utils.Test: dependentTestGroup :: TestName -> DependencyType -> [TestTree] -> TestTree
+ Hledger.Utils.Test: inOrderTestGroup :: TestName -> [TestTree] -> TestTree
- Hledger.Data.Balancing: BalancingOpts :: Bool -> Bool -> Maybe (Map CommoditySymbol AmountStyle) -> TransactionBalancingPrecision -> BalancingOpts
+ Hledger.Data.Balancing: BalancingOpts :: Bool -> Bool -> Maybe (Map CommoditySymbol AmountStyle) -> TransactionBalancingPrecision -> Map AccountName AccountType -> BalancingOpts
Files
- CHANGES.md +3/−0
- Hledger/Data/AccountName.hs +8/−8
- Hledger/Data/Balancing.hs +8/−5
- Hledger/Data/Types.hs +29/−24
- Hledger/Query.hs +22/−19
- Hledger/Read/Common.hs +1/−1
- Hledger/Read/JournalReader.hs +20/−18
- Hledger/Reports/AccountTransactionsReport.hs +1/−1
- Hledger/Reports/MultiBalanceReport.hs +1/−0
- Hledger/Reports/PostingsReport.hs +2/−1
- hledger-lib.cabal +4/−4
CHANGES.md view
@@ -17,6 +17,9 @@ For user-visible changes, see the hledger package changelog. +# 1.52.1 2026-04-28+ + # 1.52 2026-03-20 Breaking changes
Hledger/Data/AccountName.hs view
@@ -112,7 +112,6 @@ | regexMatchText liabilityAccountRegex a = Just Liability | regexMatchText conversionAccountRegex a = Just Conversion | regexMatchText equityAccountRegex a = Just Equity- | regexMatchText gainAccountRegex a = Just Gain | regexMatchText revenueAccountRegex a = Just Revenue | regexMatchText expenseAccountRegex a = Just Expense | otherwise = Nothing@@ -450,13 +449,14 @@ accountNameInferType "revenues" @?= Just Revenue accountNameInferType "revenue" @?= Just Revenue accountNameInferType "income" @?= Just Revenue- accountNameInferType "income:gains" @?= Just Gain- accountNameInferType "revenue:gain" @?= Just Gain- accountNameInferType "revenues:capital-gains" @?= Just Gain- accountNameInferType "income:capitalgain" @?= Just Gain- accountNameInferType "income:losses" @?= Just Gain- accountNameInferType "revenue:capital-loss" @?= Just Gain- accountNameInferType "income:gains:realized" @?= Just Gain+ -- Gain type is no longer inferred from names; these are now Revenue+ accountNameInferType "income:gains" @?= Just Revenue+ accountNameInferType "revenue:gain" @?= Just Revenue+ accountNameInferType "revenues:capital-gains" @?= Just Revenue+ accountNameInferType "income:capitalgain" @?= Just Revenue+ accountNameInferType "income:losses" @?= Just Revenue+ accountNameInferType "revenue:capital-loss" @?= Just Revenue+ accountNameInferType "income:gains:realized" @?= Just Revenue ,testCase "joinAccountNames" $ do joinAccountNames "assets" "cash" @?= "assets:cash" joinAccountNames "assets:cash" "a" @?= "assets:cash:a"
Hledger/Data/Balancing.hs view
@@ -66,6 +66,7 @@ -- Distinct from InputOpts{infer_costs_}. , commodity_styles_ :: Maybe (M.Map CommoditySymbol AmountStyle) -- ^ commodity display styles , txn_balancing_ :: TransactionBalancingPrecision+ , account_types_ :: M.Map AccountName AccountType -- ^ account type map, passed through for any balancing helpers that need it } deriving (Eq, Ord, Show) defbalancingopts :: BalancingOpts@@ -74,6 +75,7 @@ , infer_balancing_costs_ = True , commodity_styles_ = Nothing , txn_balancing_ = TBPExact+ , account_types_ = M.empty } -- | Check that this transaction would appear balanced to a human when displayed.@@ -193,7 +195,7 @@ (t', inferredamtsandaccts) <- t & (if infer_balancing_costs_ bopts then transactionInferBalancingCosts else id) & dbg9With (lbl "amounts after balancing-cost-inferring".show.map showMixedAmountOneLine.transactionAmounts)- & transactionInferBalancingAmount (fromMaybe M.empty $ commodity_styles_ bopts)+ & transactionInferBalancingAmount (fromMaybe M.empty $ commodity_styles_ bopts) (account_types_ bopts) <&> dbg9With (lbl "balancing amounts inferred".show.map (second showMixedAmountOneLine).snd) case transactionCheckBalanced bopts t' of [] -> Right (txnTieKnot t', inferredamtsandaccts)@@ -242,9 +244,10 @@ -- have the same price(s), and will be converted to the price commodity. transactionInferBalancingAmount :: M.Map CommoditySymbol AmountStyle -- ^ commodity display styles+ -> M.Map AccountName AccountType -- ^ account type map (passed through; reserved for future use) -> Transaction -> Either String (Transaction, [(AccountName, MixedAmount)])-transactionInferBalancingAmount styles t@Transaction{tpostings=ps}+transactionInferBalancingAmount styles _atypes t@Transaction{tpostings=ps} | length amountlessrealps > 1 = Left $ transactionBalanceError t ["There can't be more than one real posting with no amount."@@ -793,10 +796,10 @@ testGroup "Balancing" [ testCase "transactionInferBalancingAmount" $ do- (fst <$> transactionInferBalancingAmount M.empty nulltransaction) @?= Right nulltransaction- (fst <$> transactionInferBalancingAmount M.empty nulltransaction{tpostings = ["a" `post` usd (-5), "b" `post` missingamt]}) @?=+ (fst <$> transactionInferBalancingAmount M.empty M.empty nulltransaction) @?= Right nulltransaction+ (fst <$> transactionInferBalancingAmount M.empty M.empty nulltransaction{tpostings = ["a" `post` usd (-5), "b" `post` missingamt]}) @?= Right nulltransaction{tpostings = ["a" `post` usd (-5), "b" `post` usd 5]}- (fst <$> transactionInferBalancingAmount M.empty nulltransaction{tpostings = ["a" `post` usd (-5), "b" `post` (eur 3 @@ usd 4), "c" `post` missingamt]}) @?=+ (fst <$> transactionInferBalancingAmount M.empty 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]} , testGroup "balanceSingleTransaction" [
Hledger/Data/Types.hs view
@@ -187,20 +187,22 @@ | Equity | Revenue | Expense- | Cash -- ^ a subtype of Asset - liquid assets to show in cashflow report- | Conversion -- ^ a subtype of Equity - account with which to balance commodity conversions- | Gain -- ^ a subtype of Revenue - capital gains/losses+ | Cash -- ^ a subtype of Asset - liquid assets to show in cashflow report+ | Conversion -- ^ a subtype of Equity - account with which to balance commodity conversions+ | Gain -- ^ a subtype of Revenue - realised capital gains/losses+ | UnrealisedGain -- ^ a subtype of Equity - accumulated unrealised capital gains/losses (used by hledger 2) deriving (Eq,Ord,Generic) instance Show AccountType where- show Asset = "A"- show Liability = "L"- show Equity = "E"- show Revenue = "R"- show Expense = "X"- show Cash = "C"- show Conversion = "V"- show Gain = "G"+ show Asset = "A"+ show Liability = "L"+ show Equity = "E"+ show Revenue = "R"+ show Expense = "X"+ show Cash = "C"+ show Conversion = "V"+ show Gain = "G"+ show UnrealisedGain = "U" isBalanceSheetAccountType :: AccountType -> Bool isBalanceSheetAccountType t = t `elem` [@@ -208,7 +210,8 @@ Liability, Equity, Cash,- Conversion+ Conversion,+ UnrealisedGain ] isIncomeStatementAccountType :: AccountType -> Bool@@ -221,18 +224,20 @@ -- | Check whether the first argument is a subtype of the second: either equal -- or one of the defined subtypes. isAccountSubtypeOf :: AccountType -> AccountType -> Bool-isAccountSubtypeOf Asset Asset = True-isAccountSubtypeOf Liability Liability = True-isAccountSubtypeOf Equity Equity = True-isAccountSubtypeOf Revenue Revenue = True-isAccountSubtypeOf Expense Expense = True-isAccountSubtypeOf Cash Cash = True-isAccountSubtypeOf Cash Asset = True-isAccountSubtypeOf Conversion Conversion = True-isAccountSubtypeOf Conversion Equity = True-isAccountSubtypeOf Gain Gain = True-isAccountSubtypeOf Gain Revenue = True-isAccountSubtypeOf _ _ = False+isAccountSubtypeOf Asset Asset = True+isAccountSubtypeOf Liability Liability = True+isAccountSubtypeOf Equity Equity = True+isAccountSubtypeOf Revenue Revenue = True+isAccountSubtypeOf Expense Expense = True+isAccountSubtypeOf Cash Cash = True+isAccountSubtypeOf Cash Asset = True+isAccountSubtypeOf Conversion Conversion = True+isAccountSubtypeOf Conversion Equity = True+isAccountSubtypeOf Gain Gain = True+isAccountSubtypeOf Gain Revenue = True+isAccountSubtypeOf UnrealisedGain UnrealisedGain = True+isAccountSubtypeOf UnrealisedGain Equity = True+isAccountSubtypeOf _ _ = False -- not worth the trouble, letters defined in accountdirectivep for now --instance Read AccountType
Hledger/Query.hs view
@@ -519,8 +519,8 @@ accountTypeChoices allowlongform = intercalate ", " -- keep synced with parseAccountType- $ ["A","L","E","R","X","C","V","G"]- ++ if allowlongform then ["Asset","Liability","Equity","Revenue","Expense","Cash","Conversion","Gain"] else []+ $ ["A","L","E","R","X","C","V","G","U"]+ ++ if allowlongform then ["Asset","Liability","Equity","Revenue","Expense","Cash","Conversion","Gain","UnrealisedGain"] else [] -- | Case-insensitively parse one single-letter code, or one long-form word if permitted, to an account type. -- On failure, returns the unparseable text.@@ -528,23 +528,26 @@ parseAccountType allowlongform s = case T.toLower s of -- keep synced with accountTypeChoices- "a" -> Right Asset- "l" -> Right Liability- "e" -> Right Equity- "r" -> Right Revenue- "x" -> Right Expense- "c" -> Right Cash- "v" -> Right Conversion- "g" -> Right Gain- "asset" | allowlongform -> Right Asset- "liability" | allowlongform -> Right Liability- "equity" | allowlongform -> Right Equity- "revenue" | allowlongform -> Right Revenue- "expense" | allowlongform -> Right Expense- "cash" | allowlongform -> Right Cash- "conversion" | allowlongform -> Right Conversion- "gains" | allowlongform -> Right Gain- _ -> Left $ T.unpack s+ "a" -> Right Asset+ "l" -> Right Liability+ "e" -> Right Equity+ "r" -> Right Revenue+ "x" -> Right Expense+ "c" -> Right Cash+ "v" -> Right Conversion+ "g" -> Right Gain+ "u" -> Right UnrealisedGain+ "asset" | allowlongform -> Right Asset+ "liability" | allowlongform -> Right Liability+ "equity" | allowlongform -> Right Equity+ "revenue" | allowlongform -> Right Revenue+ "expense" | allowlongform -> Right Expense+ "cash" | allowlongform -> Right Cash+ "conversion" | allowlongform -> Right Conversion+ "gain" | allowlongform -> Right Gain+ "unrealisedgain" | allowlongform -> Right UnrealisedGain+ "unrealizedgain" | allowlongform -> Right UnrealisedGain+ _ -> Left $ T.unpack s -- | Parse the value part of a "status:" query, or return an error. parseStatus :: T.Text -> Either String Status
Hledger/Read/Common.hs view
@@ -404,7 +404,7 @@ -- >>= \j -> deepseq (concatMap (T.unpack.showTransaction).jtxns $ j) (return j) <&> dbg9With (lbl "amounts after styling, forecasting, auto-posting".showJournalPostingAmountsDebug) >>= (\j -> if checkordereddates then journalCheckOrdereddates j $> j else Right j) -- check ordereddates before assertions. The outer parentheses are needed.- >>= journalBalanceTransactions balancingopts_{ignore_assertions_=not checkassertions} -- infer balance assignments and missing amounts, and maybe check balance assertions.+ >>= (\j -> journalBalanceTransactions balancingopts_{ignore_assertions_=not checkassertions, account_types_ = jaccounttypes j} j) -- infer balance assignments and missing amounts, and maybe check balance assertions. <&> dbg9With (lbl "amounts after transaction-balancing".showJournalPostingAmountsDebug) -- <&> dbg9With (("journalFinalise amounts after styling, forecasting, auto postings, transaction balancing"<>).showJournalPostingAmountsDebug) >>= journalInferCommodityStyles -- infer commodity styles once more now that all posting amounts are present
Hledger/Read/JournalReader.hs view
@@ -549,26 +549,28 @@ parseAccountTypeCode :: Text -> Either String AccountType parseAccountTypeCode s = case T.toLower s of- "asset" -> Right Asset- "a" -> Right Asset- "liability" -> Right Liability- "l" -> Right Liability- "equity" -> Right Equity- "e" -> Right Equity- "revenue" -> Right Revenue- "r" -> Right Revenue- "expense" -> Right Expense- "x" -> Right Expense- "cash" -> Right Cash- "c" -> Right Cash- "conversion" -> Right Conversion- "v" -> Right Conversion- "gains" -> Right Gain- "g" -> Right Gain- _ -> Left err+ "asset" -> Right Asset+ "a" -> Right Asset+ "liability" -> Right Liability+ "l" -> Right Liability+ "equity" -> Right Equity+ "e" -> Right Equity+ "revenue" -> Right Revenue+ "r" -> Right Revenue+ "expense" -> Right Expense+ "x" -> Right Expense+ "cash" -> Right Cash+ "c" -> Right Cash+ "conversion" -> Right Conversion+ "v" -> Right Conversion+ "gain" -> Right Gain+ "g" -> Right Gain+ "unrealisedgain" -> Right UnrealisedGain+ "u" -> Right UnrealisedGain+ _ -> Left err where err = T.unpack $ "invalid account type code "<>s<>", should be one of " <>- T.intercalate ", " ["A","L","E","R","X","C","V","G","Asset","Liability","Equity","Revenue","Expense","Cash","Conversion","Gain"]+ T.intercalate ", " ["A","L","E","R","X","C","V","G","U","Asset","Liability","Equity","Revenue","Expense","Cash","Conversion","Gain","UnrealisedGain"] -- Add an account declaration to the journal, auto-numbering it. addAccountDeclaration :: (AccountName,Text,[Tag],SourcePos) -> JournalParser m ()
Hledger/Reports/AccountTransactionsReport.hs view
@@ -146,7 +146,7 @@ | balanceaccum_ ropts == Historical = sumPostings priorps | otherwise = nullmixedamt where- priorps = dbg5 "priorps" . journalPostings $ filterJournalPostings priorq acctJournal+ priorps = dbg5 "priorps" . filter hasAmount . journalPostings $ filterJournalPostings priorq acctJournal priorq = dbg5 "priorq" $ And [thisacctq, tostartdateq, datelessreportq] tostartdateq = case mstartdate of
Hledger/Reports/MultiBalanceReport.hs view
@@ -183,6 +183,7 @@ getPostings :: ReportSpec -> Journal -> PriceOracle -> DateSpan -> [Posting] getPostings rspec@ReportSpec{_rsQuery=query, _rsReportOpts=ropts} j priceoracle reportspan = setPostingsCount+ . filter hasAmount -- omit postings with no definite amount . journalPostings $ journalValueAndFilterPostingsWith rspec' j priceoracle where
Hledger/Reports/PostingsReport.hs view
@@ -156,9 +156,10 @@ dbg5 "beforeps, duringps" $ span (beforestartq `matchesPosting`) beforeandduringps where beforestartq = dbg3 "beforestartq" $ dateqtype $ DateSpan Nothing (Exact <$> spanStart reportspan)- beforeandduringps = + beforeandduringps = sortOn (postingDateOrDate2 (whichDate ropts)) -- sort postings by date or date2 . (if invert_ ropts then map postingNegateMainAmount else id) -- with --invert, invert amounts+ . filter hasAmount -- omit postings with no definite amount . journalPostings -- With most calls we will not require transaction prices past this point, and can get a big -- speed improvement by stripping them early. In some cases, such as in hledger-ui, we still
hledger-lib.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: hledger-lib-version: 1.52+version: 1.52.1 synopsis: A library providing the core functionality of hledger description: This library contains hledger's core functionality. It is used by most hledger* packages so that they support the same@@ -124,7 +124,7 @@ hs-source-dirs: ./ ghc-options: -Wall -Wno-incomplete-uni-patterns -Wno-missing-signatures -Wno-orphans -Wno-type-defaults -Wno-unused-do-bind- cpp-options: -DVERSION="1.52"+ cpp-options: -DVERSION="1.52.1" build-depends: Decimal >=0.5.1 , Glob >=0.9@@ -184,7 +184,7 @@ hs-source-dirs: test ghc-options: -Wall -Wno-incomplete-uni-patterns -Wno-missing-signatures -Wno-orphans -Wno-type-defaults -Wno-unused-do-bind- cpp-options: -DVERSION="1.52"+ cpp-options: -DVERSION="1.52.1" build-depends: Decimal >=0.5.1 , Glob >=0.7@@ -245,7 +245,7 @@ hs-source-dirs: test ghc-options: -Wall -Wno-incomplete-uni-patterns -Wno-missing-signatures -Wno-orphans -Wno-type-defaults -Wno-unused-do-bind- cpp-options: -DVERSION="1.52"+ cpp-options: -DVERSION="1.52.1" build-depends: Decimal >=0.5.1 , Glob >=0.9