1 {-| 2 3 A 'Ledger' is derived from a 'Journal' by applying a filter specification 4 to select 'Transaction's and 'Posting's of interest. It contains the 5 filtered journal and knows the resulting chart of accounts, account 6 balances, and postings in each account. 7 8 -} 9 10 module Hledger.Data.Ledger 11 where 12 import Data.Map (Map, findWithDefault, fromList) 13 import Data.Tree 14 import Test.HUnit 15 import Text.Printf 16 17 import Hledger.Utils 18 import Hledger.Data.Types 19 import Hledger.Data.Account (nullacct) 20 import Hledger.Data.AccountName 21 import Hledger.Data.Journal 22 import Hledger.Data.Posting 23 import Hledger.Data.Matching 24 25 26 instance Show Ledger where 27 show l = printf "Ledger with %d transactions, %d accounts\n%s" 28 (length (jtxns $ journal l) + 29 length (jmodifiertxns $ journal l) + 30 length (jperiodictxns $ journal l)) 31 (length $ accountnames l) 32 (showtree $ accountnametree l) 33 34 nullledger :: Ledger 35 nullledger = Ledger{ 36 journal = nulljournal, 37 accountnametree = nullaccountnametree, 38 accountmap = fromList [] 39 } 40 41 -- | Filter a journal's transactions as specified, and then process them 42 -- to derive a ledger containing all balances, the chart of accounts, 43 -- canonicalised commodities etc. 44 journalToLedger :: FilterSpec -> Journal -> Ledger 45 journalToLedger fs j = nullledger{journal=j',accountnametree=t,accountmap=m} 46 where j' = filterJournalPostings fs{depth=Nothing} j 47 (t, m) = journalAccountInfo j' 48 49 -- | Filter a journal's transactions as specified, and then process them 50 -- to derive a ledger containing all balances, the chart of accounts, 51 -- canonicalised commodities etc. 52 -- Like journalToLedger but uses the new matchers. 53 journalToLedger2 :: Matcher -> Journal -> Ledger 54 journalToLedger2 m j = nullledger{journal=j',accountnametree=t,accountmap=amap} 55 where j' = filterJournalPostings2 m j 56 (t, amap) = journalAccountInfo j' 57 58 -- | List a ledger's account names. 59 ledgerAccountNames :: Ledger -> [AccountName] 60 ledgerAccountNames = drop 1 . flatten . accountnametree 61 62 -- | Get the named account from a ledger. 63 ledgerAccount :: Ledger -> AccountName -> Account 64 ledgerAccount l a = findWithDefault nullacct a $ accountmap l 65 66 -- | List a ledger's accounts, in tree order 67 ledgerAccounts :: Ledger -> [Account] 68 ledgerAccounts = drop 1 . flatten . ledgerAccountTree 9999 69 70 -- | List a ledger's top-level accounts, in tree order 71 ledgerTopAccounts :: Ledger -> [Account] 72 ledgerTopAccounts = map root . branches . ledgerAccountTree 9999 73 74 -- | List a ledger's bottom-level (subaccount-less) accounts, in tree order 75 ledgerLeafAccounts :: Ledger -> [Account] 76 ledgerLeafAccounts = leaves . ledgerAccountTree 9999 77 78 -- | Accounts in ledger whose name matches the pattern, in tree order. 79 ledgerAccountsMatching :: [String] -> Ledger -> [Account] 80 ledgerAccountsMatching pats = filter (matchpats pats . aname) . accounts 81 82 -- | List a ledger account's immediate subaccounts 83 ledgerSubAccounts :: Ledger -> Account -> [Account] 84 ledgerSubAccounts l Account{aname=a} = 85 map (ledgerAccount l) $ filter (`isSubAccountNameOf` a) $ accountnames l 86 87 -- | List a ledger's postings, in the order parsed. 88 ledgerPostings :: Ledger -> [Posting] 89 ledgerPostings = journalPostings . journal 90 91 -- | Get a ledger's tree of accounts to the specified depth. 92 ledgerAccountTree :: Int -> Ledger -> Tree Account 93 ledgerAccountTree depth l = treemap (ledgerAccount l) $ treeprune depth $ accountnametree l 94 95 -- | Get a ledger's tree of accounts rooted at the specified account. 96 ledgerAccountTreeAt :: Ledger -> Account -> Maybe (Tree Account) 97 ledgerAccountTreeAt l acct = subtreeat acct $ ledgerAccountTree 9999 l 98 99 -- | The (fully specified) date span containing all the ledger's (filtered) transactions, 100 -- or DateSpan Nothing Nothing if there are none. 101 ledgerDateSpan :: Ledger -> DateSpan 102 ledgerDateSpan = postingsDateSpan . ledgerPostings 103 104 -- | Convenience aliases. 105 accountnames :: Ledger -> [AccountName] 106 accountnames = ledgerAccountNames 107 108 account :: Ledger -> AccountName -> Account 109 account = ledgerAccount 110 111 accounts :: Ledger -> [Account] 112 accounts = ledgerAccounts 113 114 topaccounts :: Ledger -> [Account] 115 topaccounts = ledgerTopAccounts 116 117 accountsmatching :: [String] -> Ledger -> [Account] 118 accountsmatching = ledgerAccountsMatching 119 120 subaccounts :: Ledger -> Account -> [Account] 121 subaccounts = ledgerSubAccounts 122 123 postings :: Ledger -> [Posting] 124 postings = ledgerPostings 125 126 commodities :: Ledger -> Map String Commodity 127 commodities = journalCanonicalCommodities . journal 128 129 accounttree :: Int -> Ledger -> Tree Account 130 accounttree = ledgerAccountTree 131 132 accounttreeat :: Ledger -> Account -> Maybe (Tree Account) 133 accounttreeat = ledgerAccountTreeAt 134 135 -- datespan :: Ledger -> DateSpan 136 -- datespan = ledgerDateSpan 137 138 rawdatespan :: Ledger -> DateSpan 139 rawdatespan = journalDateSpan . journal 140 141 ledgeramounts :: Ledger -> [MixedAmount] 142 ledgeramounts = journalAmounts . journal 143 144 tests_Hledger_Data_Ledger = TestList 145 [ 146 ] 147