diff --git a/hledger-lib/Hledger/Data/Journal.hs b/hledger-lib/Hledger/Data/Journal.hs index 843638c0b..c6ee1cc4d 100644 --- a/hledger-lib/Hledger/Data/Journal.hs +++ b/hledger-lib/Hledger/Data/Journal.hs @@ -296,29 +296,6 @@ journalAccountNameTree = accountNameTreeFrom . journalAccountNames -- queries for standard account types --- | 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 -> - -- 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 [ - Or $ map (Acct . accountNameToAccountRegex) as - ,Not $ Or $ map (Acct . accountNameToAccountRegex) differentlytypedsubs - ] - where - differentlytypedsubs = concat - [subs | (t,bs) <- M.toList (jdeclaredaccounttypes j) - , t /= atype - , let subs = [b | b <- bs, any (`isAccountNamePrefixOf` b) as] - ] - -- | 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 @@ -369,12 +346,43 @@ journalProfitAndLossAccountQuery j = Or [journalRevenueAccountQuery j ,journalExpenseAccountQuery j ] --- | A query for Cash (-equivalent) accounts in this journal (ie, --- accounts which appear on the cashflow statement.) This is currently --- hard-coded to be all the Asset accounts except for those with names --- containing the case-insensitive regular expression @(receivable|:A/R|:fixed)@. +-- | 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 = And [journalAssetAccountQuery j, Not $ Acct "(receivable|:A/R|:fixed)"] +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 -> + -- 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 [ + Or $ map (Acct . accountNameToAccountRegex) as + ,Not $ Or $ map (Acct . accountNameToAccountRegex) differentlytypedsubs + ] + where + differentlytypedsubs = concat + [subs | (t,bs) <- M.toList (jdeclaredaccounttypes j) + , t /= atype + , let subs = [b | b <- bs, any (`isAccountNamePrefixOf` b) as] + ] -- Various kinds of filtering on journals. We do it differently depending -- on the command. diff --git a/hledger-lib/Hledger/Data/Types.hs b/hledger-lib/Hledger/Data/Types.hs index 4f3d78dae..5c2457059 100644 --- a/hledger-lib/Hledger/Data/Types.hs +++ b/hledger-lib/Hledger/Data/Types.hs @@ -121,6 +121,7 @@ data AccountType = | Equity | Revenue | Expense + | Cash -- ^ a subtype of Asset - liquid assets to show in cashflow report deriving (Show,Eq,Ord,Data,Generic) instance NFData AccountType diff --git a/hledger-lib/Hledger/Read/JournalReader.hs b/hledger-lib/Hledger/Read/JournalReader.hs index d7289730c..746a4c05d 100644 --- a/hledger-lib/Hledger/Read/JournalReader.hs +++ b/hledger-lib/Hledger/Read/JournalReader.hs @@ -380,10 +380,12 @@ parseAccountTypeCode s = "r" -> Right Revenue "expense" -> Right Expense "x" -> Right Expense + "cash" -> Right Cash + "c" -> Right Cash _ -> Left err where err = "invalid account type code "++T.unpack s++", should be one of " ++ - (intercalate ", " $ ["A","L","E","R","X","ASSET","LIABILITY","EQUITY","REVENUE","EXPENSE"]) + (intercalate ", " $ ["A","L","E","R","X","C","Asset","Liability","Equity","Revenue","Expense","Cash"]) -- Add an account declaration to the journal, auto-numbering it. addAccountDeclaration :: (AccountName,Text,[Tag]) -> JournalParser m () diff --git a/hledger-lib/hledger_journal.m4.md b/hledger-lib/hledger_journal.m4.md index 0a9a6b058..f2b12b6c8 100644 --- a/hledger-lib/hledger_journal.m4.md +++ b/hledger-lib/hledger_journal.m4.md @@ -1087,37 +1087,88 @@ account ACCTNAME [ACCTTYPE] [;COMMENT] #### Account types -hledger recognises five types (or classes) of account: Asset, Liability, Equity, Revenue, Expense. -This is used by a few accounting-aware reports such as [balancesheet][], [incomestatement][] and [cashflow][]. +hledger recognises five main types of account, +corresponding to the account classes in the [accounting equation][]: -[balancesheet]: hledger.html#balancesheet -[cashflow]: hledger.html#cashflow -[incomestatement]: hledger.html#incomestatement +`Asset`, `Liability`, `Equity`, `Revenue`, `Expense`. + +These account types are important for controlling which accounts +appear in the [balancesheet][], [balancesheetequity][], +[incomestatement][] reports (and probably for other things in future). + +There is also the `Cash` type, which is a subtype of `Asset`, +and which causes accounts to appear in the [cashflow][] report. +("Cash" here means [liquid assets][CCE], eg typically bank balances +but not investments or receivables.) + +##### Declaring account types + +Generally, to make these reports work you should declare your +top-level accounts and their types, +using [account directives](#declaring-accounts) +with `type:` [tags](journal.html#tags). + +The tag's value should be one of: +`Asset`, `Liability`, `Equity`, `Revenue`, `Expense`, `Cash`, +`A`, `L`, `E`, `R`, `X`, `C` (all case insensitive). +The type is inherited by all subaccounts except where they override it. +Here's a complete example: + +```journal +account assets ; type: Asset +account assets:bank ; type: Cash +account assets:cash ; type: Cash +account liabilities ; type: Liability +account equity ; type: Equity +account revenues ; type: Revenue +account expenses ; type: Expense +``` ##### Auto-detected account types -If you name your top-level accounts with some variation of -`assets`, `liabilities`/`debts`, `equity`, `revenues`/`income`, or `expenses`, -their types are detected automatically. +If you happen to use common english top-level account names, you may +not need to declare account types, as they will be detected +automatically using the following rules: -##### Account types declared with tags +| If name matches [regular expression][]: | account type is: +|-----------------------------------------|----------------- +| `^assets?(:|$)` | `Asset` +| `^(debts?|liabilit(y|ies))(:|$)` | `Liability` +| `^equity(:|$)` | `Equity` +| `^(income|revenue)s?(:|$)` | `Revenue` +| `^expenses?(:|$)` | `Expense` + +| If account type is `Asset` and name does not contain regular expression: | account type is: +|--------------------------------------------------------------------------|----------------- +| `(investment|receivable|:A/R|:fixed)` | `Cash` + +Even so, explicit declarations may be a good idea, for clarity and +predictability. + +##### Interference from auto-detected account types + +If you assign any account type, it's a good idea to assign all of +them, to prevent any confusion from mixing declared and auto-detected +types. Although it's unlikely to happen in real life, here's an +example: with the following journal, `balancesheetequity` shows +"liabilities" in both Liabilities and Equity sections. Declaring another +account as `type:Liability` would fix it: -More generally, you can declare an account's type with an account directive, -by writing a `type:` [tag](journal.html#tags) in a comment, followed by one of the words -`Asset`, `Liability`, `Equity`, `Revenue`, `Expense`, -or one of the letters `ALERX` (case insensitive): ```journal -account assets ; type:Asset -account liabilities ; type:Liability -account equity ; type:Equity -account revenues ; type:Revenue -account expenses ; type:Expense +account liabilities ; type:Equity + +2020-01-01 + assets 1 + liabilities 1 + equity -2 ``` -##### Account types declared with account type codes +##### Old account type syntax + +In some hledger journals you might instead see this old syntax (the +letters ALERX, separated from the account name by two or more spaces); +this is deprecated and may be removed soon: -Or, you can write one of those letters separated from the account name by two or more spaces, -but this should probably be considered deprecated as of hledger 1.13: ```journal account assets A account liabilities L @@ -1126,18 +1177,15 @@ account revenues R account expenses X ``` -##### Overriding auto-detected types -If you ever override the types of those auto-detected english account names mentioned above, -you might need to help the reports a bit. Eg: -```journal -; make "liabilities" not have the liability type - who knows why -account liabilities ; type:E +[balancesheet]: hledger.html#balancesheet +[balancesheetequity]: hledger.html#balancesheetequity +[cashflow]: hledger.html#cashflow +[incomestatement]: hledger.html#incomestatement +[CCE]: https://en.wikipedia.org/wiki/Cash_and_cash_equivalents +[regular expression]: hledger.html#regular-expressions +[account equation]: https://en.wikipedia.org/wiki/Accounting_equation -; we need to ensure some other account has the liability type, -; otherwise balancesheet would still show "liabilities" under Liabilities -account - ; type:L -``` #### Account display order