diff --git a/hledger-lib/Hledger/Data/Journal.hs b/hledger-lib/Hledger/Data/Journal.hs index c6ee1cc4d..46783037b 100644 --- a/hledger-lib/Hledger/Data/Journal.hs +++ b/hledger-lib/Hledger/Data/Journal.hs @@ -297,39 +297,52 @@ journalAccountNameTree = accountNameTreeFrom . journalAccountNames -- queries for standard account types -- | A query for accounts in this journal which have been --- declared as Asset by account directives, or otherwise for --- accounts with names matched by the case-insensitive regular expression --- @^assets?(:|$)@. +-- declared as Asset (or Cash, a subtype of Asset) by account directives, +-- or otherwise for accounts with names matched by the case-insensitive +-- regular expression @^assets?(:|$)@. journalAssetAccountQuery :: Journal -> Query -journalAssetAccountQuery = journalAccountTypeQuery Asset "^assets?(:|$)" +journalAssetAccountQuery j = journalAccountTypeQuery [Asset,Cash] "^assets?(:|$)" j + +-- | A query for "Cash" (liquid asset) accounts in this journal, ie accounts +-- declared as Cash by account directives, or otherwise with names matched by the +-- case-insensitive regular expression @^assets?(:|$)@. and not including +-- the case-insensitive regular expression @(investment|receivable|:A/R|:fixed)@. +journalCashAccountQuery :: Journal -> Query +journalCashAccountQuery j = + case M.lookup Cash (jdeclaredaccounttypes j) of + Just _ -> journalAccountTypeQuery [Cash] notused j + where notused = error' "journalCashAccountQuery: this should not have happened!" -- XXX ugly + Nothing -> And [journalAssetAccountQuery j + ,Not $ Acct "(investment|receivable|:A/R|:fixed)" + ] -- | A query for accounts in this journal which have been -- declared as Liability by account directives, or otherwise for -- accounts with names matched by the case-insensitive regular expression -- @^(debts?|liabilit(y|ies))(:|$)@. journalLiabilityAccountQuery :: Journal -> Query -journalLiabilityAccountQuery = journalAccountTypeQuery Liability "^(debts?|liabilit(y|ies))(:|$)" +journalLiabilityAccountQuery = journalAccountTypeQuery [Liability] "^(debts?|liabilit(y|ies))(:|$)" -- | A query for accounts in this journal which have been -- declared as Equity by account directives, or otherwise for -- accounts with names matched by the case-insensitive regular expression -- @^equity(:|$)@. journalEquityAccountQuery :: Journal -> Query -journalEquityAccountQuery = journalAccountTypeQuery Equity "^equity(:|$)" +journalEquityAccountQuery = journalAccountTypeQuery [Equity] "^equity(:|$)" -- | A query for accounts in this journal which have been -- declared as Revenue by account directives, or otherwise for -- accounts with names matched by the case-insensitive regular expression -- @^(income|revenue)s?(:|$)@. journalRevenueAccountQuery :: Journal -> Query -journalRevenueAccountQuery = journalAccountTypeQuery Revenue "^(income|revenue)s?(:|$)" +journalRevenueAccountQuery = journalAccountTypeQuery [Revenue] "^(income|revenue)s?(:|$)" -- | A query for accounts in this journal which have been -- declared as Expense by account directives, or otherwise for -- accounts with names matched by the case-insensitive regular expression -- @^expenses?(:|$)@. journalExpenseAccountQuery :: Journal -> Query -journalExpenseAccountQuery = journalAccountTypeQuery Expense "^expenses?(:|$)" +journalExpenseAccountQuery = journalAccountTypeQuery [Expense] "^expenses?(:|$)" -- | A query for Asset, Liability & Equity accounts in this journal. -- Cf . @@ -346,31 +359,21 @@ journalProfitAndLossAccountQuery j = Or [journalRevenueAccountQuery j ,journalExpenseAccountQuery j ] --- | A query for "Cash" (liquid asset) accounts in this journal (ie, --- accounts which appear on the cashflow statement.) This is the --- accounts declared to be Cash type, or if none of these are --- declared, the Asset accounts whose names do not contain the --- case-insensitive regular expression @(investment|receivable|:A/R|:fixed)@. -journalCashAccountQuery :: Journal -> Query -journalCashAccountQuery j = - case M.lookup Cash (jdeclaredaccounttypes j) of - Just _ -> journalAccountTypeQuery Cash notused j - where notused = error' "journalCashAccountQuery: this should not have happened!" - Nothing -> And - [journalAssetAccountQuery j - ,Not $ Acct "(investment|receivable|:A/R|:fixed)" - ] - --- | Get a query for accounts of a certain type (Asset, Liability..) in this journal. --- The query will match all accounts which were declared as that type by account directives, --- plus all their subaccounts which have not been declared as a different type. --- If no accounts were declared as this type, the query will instead match accounts --- with names matched by the provided case-insensitive regular expression. -journalAccountTypeQuery :: AccountType -> Regexp -> Journal -> Query -journalAccountTypeQuery atype fallbackregex j = - case M.lookup atype (jdeclaredaccounttypes j) of - Nothing -> Acct fallbackregex - Just as -> +-- | Get a query for accounts of the specified types (Asset, Liability..) in this journal. +-- The query will match all accounts which were declared as one of +-- these types by account directives, plus all their subaccounts which +-- have not been declared as some other type. +-- Or if no accounts were declared with these types, the query will +-- instead match accounts with names matched by the provided +-- case-insensitive regular expression. +journalAccountTypeQuery :: [AccountType] -> Regexp -> Journal -> Query +journalAccountTypeQuery atypes fallbackregex Journal{jdeclaredaccounttypes} = + let + declaredacctsoftype :: [AccountName] = + concat $ catMaybes [M.lookup t jdeclaredaccounttypes | t <- atypes] + in case declaredacctsoftype of + [] -> Acct fallbackregex + as -> -- XXX Query isn't able to match account type since that requires extra info from the journal. -- So we do a hacky search by name instead. And [ @@ -379,8 +382,8 @@ journalAccountTypeQuery atype fallbackregex j = ] where differentlytypedsubs = concat - [subs | (t,bs) <- M.toList (jdeclaredaccounttypes j) - , t /= atype + [subs | (t,bs) <- M.toList jdeclaredaccounttypes + , not $ t `elem` atypes , let subs = [b | b <- bs, any (`isAccountNamePrefixOf` b) as] ] @@ -1407,11 +1410,18 @@ tests_Journal = tests "Journal" [ journalAccountNamesMatching q = filter (q `matchesAccount`) . journalAccountNames namesfrom qfunc = journalAccountNamesMatching (qfunc j) j in [ - test "assets" $ assertEqual "" (namesfrom journalAssetAccountQuery) ["assets","assets:bank","assets:bank:checking","assets:bank:saving","assets:cash"] - ,test "liabilities" $ assertEqual "" (namesfrom journalLiabilityAccountQuery) ["liabilities","liabilities:debts"] - ,test "equity" $ assertEqual "" (namesfrom journalEquityAccountQuery) [] - ,test "income" $ assertEqual "" (namesfrom journalRevenueAccountQuery) ["income","income:gifts","income:salary"] - ,test "expenses" $ assertEqual "" (namesfrom journalExpenseAccountQuery) ["expenses","expenses:food","expenses:supplies"] + test "assets" $ assertEqual "" ["assets","assets:bank","assets:bank:checking","assets:bank:saving","assets:cash"] + (namesfrom journalAssetAccountQuery) + ,test "cash" $ assertEqual "" ["assets","assets:bank","assets:bank:checking","assets:bank:saving","assets:cash"] + (namesfrom journalCashAccountQuery) + ,test "liabilities" $ assertEqual "" ["liabilities","liabilities:debts"] + (namesfrom journalLiabilityAccountQuery) + ,test "equity" $ assertEqual "" [] + (namesfrom journalEquityAccountQuery) + ,test "income" $ assertEqual "" ["income","income:gifts","income:salary"] + (namesfrom journalRevenueAccountQuery) + ,test "expenses" $ assertEqual "" ["expenses","expenses:food","expenses:supplies"] + (namesfrom journalExpenseAccountQuery) ] ,tests "journalBalanceTransactions" [ diff --git a/tests/journal/account-types.test b/tests/journal/account-types.test new file mode 100644 index 000000000..a8c71f1f7 --- /dev/null +++ b/tests/journal/account-types.test @@ -0,0 +1,74 @@ +; # Here some accounts with type Asset and Cash are declared and +; # Liability, Equity, Revenue and Expense accounts are inferred. +; < +; account assets ; type:Asset +; account assets:cash ; type:Cash +; account liabilities + +; 2020-01-01 +; assets 1 +; assets:cash 1 +; liabilities -1 +; revenues 1 +; expenses -1 +; equity + +; # 1. bse reports the balance sheet accounts in the proper section. +; # A Cash account is also an Asset. +; $ hledger -f- bse +; Balance Sheet With Equity 2020-01-01 + +; || 2020-01-01 +; =============++============ +; Assets || +; -------------++------------ +; assets || 1 +; assets:cash || 1 +; -------------++------------ +; || 2 +; =============++============ +; Liabilities || +; -------------++------------ +; liabilities || 1 +; -------------++------------ +; || 1 +; =============++============ +; Equity || +; -------------++------------ +; equity || 1 +; -------------++------------ +; || 1 +; =============++============ +; Net: || 0 + +; # 2. cashflow reports the Cash account. +; $ hledger -f- cf +; Cashflow Statement 2020-01-01 + +; || 2020-01-01 +; =============++============ +; Cash flows || +; -------------++------------ +; assets:cash || 1 +; -------------++------------ +; || 1 + +; # 3. is reports the income statement accounts in the proper section. +; $ hledger -f- is +; Income Statement 2020-01-01 + +; || 2020-01-01 +; ==========++============ +; Revenues || +; ----------++------------ +; revenues || 1 +; ----------++------------ +; || 1 +; ==========++============ +; Expenses || +; ----------++------------ +; expenses || 1 +; ----------++------------ +; || 1 +; ==========++============ +; Net: || 0