journal: account directives can declare account types
Previously you had to use one of the standard english account names (assets, liabilities..) for top-level accounts, if you wanted to use the bs/bse/cf/is commands. Now, account directives can specify which of the big five categories an account belongs to - asset, liability, equity, revenue or expense - by writing one of the letters A, L, E, R or X two or more spaces after the account name (where the numeric account code used to be). This might change. Some thoughts influencing the current syntax: - easy to type and read - does not require multiple lines - does not depend on any particular account numbering scheme - allows more types later if needed - still anglocentric, but only a little - could be treated as syntactic sugar for account tags later - seems to be compatible with (ignored by) current Ledger The current design permits unlimited account type declarations anywhere in the account tree. So you could declare a liability account somewhere under assets, and maybe a revenue account under that, and another asset account even further down. In such cases you start to see oddities like accounts appearing in multiple places in a tree-mode report. In theory the reports will still behave reasonably, but this has not been tested too hard. In any case this is clearly too much freedom. I have left it this way, for now, in case it helps with: - modelling contra accounts ? - multiple files. I suspect the extra expressiveness may come in handy when combining multiple files with account type declarations, rewriting account names, apply parent accounts etc. If we only allowed type declarations on top-level accounts, or only allowed a single account of each type, complications seem likely.
This commit is contained in:
parent
678e8c28e4
commit
c1236fa6e9
@ -162,16 +162,17 @@ instance Sem.Semigroup Journal where
|
|||||||
,jparseparentaccounts = jparseparentaccounts j2
|
,jparseparentaccounts = jparseparentaccounts j2
|
||||||
,jparsealiases = jparsealiases j2
|
,jparsealiases = jparsealiases j2
|
||||||
-- ,jparsetransactioncount = jparsetransactioncount j1 + jparsetransactioncount j2
|
-- ,jparsetransactioncount = jparsetransactioncount j1 + jparsetransactioncount j2
|
||||||
,jparsetimeclockentries = jparsetimeclockentries j1 <> jparsetimeclockentries j2
|
,jparsetimeclockentries = jparsetimeclockentries j1 <> jparsetimeclockentries j2
|
||||||
,jincludefilestack = jincludefilestack j2
|
,jincludefilestack = jincludefilestack j2
|
||||||
,jdeclaredaccounts = jdeclaredaccounts j1 <> jdeclaredaccounts j2
|
,jdeclaredaccounts = jdeclaredaccounts j1 <> jdeclaredaccounts j2
|
||||||
|
,jdeclaredaccounttypes = jdeclaredaccounttypes j1 <> jdeclaredaccounttypes j2
|
||||||
,jcommodities = jcommodities j1 <> jcommodities j2
|
,jcommodities = jcommodities j1 <> jcommodities j2
|
||||||
,jinferredcommodities = jinferredcommodities j1 <> jinferredcommodities j2
|
,jinferredcommodities = jinferredcommodities j1 <> jinferredcommodities j2
|
||||||
,jmarketprices = jmarketprices j1 <> jmarketprices j2
|
,jmarketprices = jmarketprices j1 <> jmarketprices j2
|
||||||
,jtxnmodifiers = jtxnmodifiers j1 <> jtxnmodifiers j2
|
,jtxnmodifiers = jtxnmodifiers j1 <> jtxnmodifiers j2
|
||||||
,jperiodictxns = jperiodictxns j1 <> jperiodictxns j2
|
,jperiodictxns = jperiodictxns j1 <> jperiodictxns j2
|
||||||
,jtxns = jtxns j1 <> jtxns j2
|
,jtxns = jtxns j1 <> jtxns j2
|
||||||
,jfinalcommentlines = jfinalcommentlines j2
|
,jfinalcommentlines = jfinalcommentlines j2 -- XXX discards j1's ?
|
||||||
,jfiles = jfiles j1 <> jfiles j2
|
,jfiles = jfiles j1 <> jfiles j2
|
||||||
,jlastreadtime = max (jlastreadtime j1) (jlastreadtime j2)
|
,jlastreadtime = max (jlastreadtime j1) (jlastreadtime j2)
|
||||||
}
|
}
|
||||||
@ -193,8 +194,9 @@ nulljournal = Journal {
|
|||||||
,jparsetimeclockentries = []
|
,jparsetimeclockentries = []
|
||||||
,jincludefilestack = []
|
,jincludefilestack = []
|
||||||
,jdeclaredaccounts = []
|
,jdeclaredaccounts = []
|
||||||
,jcommodities = M.fromList []
|
,jdeclaredaccounttypes = M.empty
|
||||||
,jinferredcommodities = M.fromList []
|
,jcommodities = M.empty
|
||||||
|
,jinferredcommodities = M.empty
|
||||||
,jmarketprices = []
|
,jmarketprices = []
|
||||||
,jtxnmodifiers = []
|
,jtxnmodifiers = []
|
||||||
,jperiodictxns = []
|
,jperiodictxns = []
|
||||||
|
|||||||
@ -113,7 +113,26 @@ instance Default Interval where def = NoInterval
|
|||||||
instance NFData Interval
|
instance NFData Interval
|
||||||
|
|
||||||
type AccountName = Text
|
type AccountName = Text
|
||||||
type AccountCode = Int
|
|
||||||
|
data AccountType =
|
||||||
|
Asset
|
||||||
|
| Liability
|
||||||
|
| Equity
|
||||||
|
| Revenue
|
||||||
|
| Expense
|
||||||
|
deriving (Show,Eq,Ord,Data,Generic)
|
||||||
|
|
||||||
|
instance NFData AccountType
|
||||||
|
|
||||||
|
-- not worth the trouble, letters defined in accountdirectivep for now
|
||||||
|
--instance Read AccountType
|
||||||
|
-- where
|
||||||
|
-- readsPrec _ ('A' : xs) = [(Asset, xs)]
|
||||||
|
-- readsPrec _ ('L' : xs) = [(Liability, xs)]
|
||||||
|
-- readsPrec _ ('E' : xs) = [(Equity, xs)]
|
||||||
|
-- readsPrec _ ('R' : xs) = [(Revenue, xs)]
|
||||||
|
-- readsPrec _ ('X' : xs) = [(Expense, xs)]
|
||||||
|
-- readsPrec _ _ = []
|
||||||
|
|
||||||
data AccountAlias = BasicAlias AccountName AccountName
|
data AccountAlias = BasicAlias AccountName AccountName
|
||||||
| RegexAlias Regexp Replacement
|
| RegexAlias Regexp Replacement
|
||||||
@ -369,6 +388,7 @@ data Journal = Journal {
|
|||||||
,jincludefilestack :: [FilePath]
|
,jincludefilestack :: [FilePath]
|
||||||
-- principal data
|
-- principal data
|
||||||
,jdeclaredaccounts :: [AccountName] -- ^ Accounts declared by account directives, in parse order (after journal finalisation)
|
,jdeclaredaccounts :: [AccountName] -- ^ Accounts declared by account directives, in parse order (after journal finalisation)
|
||||||
|
,jdeclaredaccounttypes :: M.Map AccountType [AccountName] -- ^ Accounts whose type has been declared in account directives (usually 5 top-level accounts)
|
||||||
,jcommodities :: M.Map CommoditySymbol Commodity -- ^ commodities and formats declared by commodity directives
|
,jcommodities :: M.Map CommoditySymbol Commodity -- ^ commodities and formats declared by commodity directives
|
||||||
,jinferredcommodities :: M.Map CommoditySymbol AmountStyle -- ^ commodities and formats inferred from journal amounts TODO misnamed - jusedstyles
|
,jinferredcommodities :: M.Map CommoditySymbol AmountStyle -- ^ commodities and formats inferred from journal amounts TODO misnamed - jusedstyles
|
||||||
,jmarketprices :: [MarketPrice]
|
,jmarketprices :: [MarketPrice]
|
||||||
|
|||||||
@ -43,6 +43,7 @@ module Hledger.Read.Common (
|
|||||||
getDefaultAmountStyle,
|
getDefaultAmountStyle,
|
||||||
getAmountStyle,
|
getAmountStyle,
|
||||||
pushDeclaredAccount,
|
pushDeclaredAccount,
|
||||||
|
addDeclaredAccountType,
|
||||||
pushParentAccount,
|
pushParentAccount,
|
||||||
popParentAccount,
|
popParentAccount,
|
||||||
getParentAccount,
|
getParentAccount,
|
||||||
@ -311,6 +312,10 @@ getAmountStyle commodity = do
|
|||||||
pushDeclaredAccount :: AccountName -> JournalParser m ()
|
pushDeclaredAccount :: AccountName -> JournalParser m ()
|
||||||
pushDeclaredAccount acct = modify' (\j -> j{jdeclaredaccounts = acct : jdeclaredaccounts j})
|
pushDeclaredAccount acct = modify' (\j -> j{jdeclaredaccounts = acct : jdeclaredaccounts j})
|
||||||
|
|
||||||
|
addDeclaredAccountType :: AccountName -> AccountType -> JournalParser m ()
|
||||||
|
addDeclaredAccountType acct atype =
|
||||||
|
modify' (\j -> j{jdeclaredaccounttypes = M.insertWith (++) atype [acct] (jdeclaredaccounttypes j)})
|
||||||
|
|
||||||
pushParentAccount :: AccountName -> JournalParser m ()
|
pushParentAccount :: AccountName -> JournalParser m ()
|
||||||
pushParentAccount acct = modify' (\j -> j{jparseparentaccounts = acct : jparseparentaccounts j})
|
pushParentAccount acct = modify' (\j -> j{jparseparentaccounts = acct : jparseparentaccounts j})
|
||||||
|
|
||||||
|
|||||||
@ -69,6 +69,7 @@ import Control.Monad
|
|||||||
import Control.Monad.Except (ExceptT(..))
|
import Control.Monad.Except (ExceptT(..))
|
||||||
import Control.Monad.State.Strict
|
import Control.Monad.State.Strict
|
||||||
import Data.Bifunctor (first)
|
import Data.Bifunctor (first)
|
||||||
|
import Data.Maybe
|
||||||
import qualified Data.Map.Strict as M
|
import qualified Data.Map.Strict as M
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.String
|
import Data.String
|
||||||
@ -257,10 +258,29 @@ accountdirectivep :: JournalParser m ()
|
|||||||
accountdirectivep = do
|
accountdirectivep = do
|
||||||
string "account"
|
string "account"
|
||||||
lift (skipSome spacenonewline)
|
lift (skipSome spacenonewline)
|
||||||
acct <- modifiedaccountnamep -- account directives can be modified by alias/apply account
|
-- the account name, possibly modified by preceding alias or apply account directives
|
||||||
_ :: Maybe String <- (optional $ lift $ skipSome spacenonewline >> some digitChar) -- compatibility: ignore account codes supported in 1.9/1.10
|
acct <- modifiedaccountnamep
|
||||||
|
-- and maybe something else after two or more spaces ?
|
||||||
|
matype :: Maybe AccountType <- lift $ fmap (fromMaybe Nothing) $ optional $ do
|
||||||
|
skipSome spacenonewline -- at least one more space in addition to the one consumed by modifiedaccountp
|
||||||
|
choice [
|
||||||
|
-- a numeric account code, as supported in 1.9-1.10 ? currently ignored
|
||||||
|
some digitChar >> return Nothing
|
||||||
|
-- a letter account type code (ALERX), as added in 1.11 ?
|
||||||
|
,char 'A' >> return (Just Asset)
|
||||||
|
,char 'L' >> return (Just Liability)
|
||||||
|
,char 'E' >> return (Just Equity)
|
||||||
|
,char 'R' >> return (Just Revenue)
|
||||||
|
,char 'X' >> return (Just Expense)
|
||||||
|
]
|
||||||
newline
|
newline
|
||||||
|
-- Ledger-style indented subdirectives on following lines ? ignore
|
||||||
skipMany indentedlinep
|
skipMany indentedlinep
|
||||||
|
|
||||||
|
-- update the journal
|
||||||
|
case matype of
|
||||||
|
Nothing -> return ()
|
||||||
|
Just atype -> addDeclaredAccountType acct atype
|
||||||
pushDeclaredAccount acct
|
pushDeclaredAccount acct
|
||||||
|
|
||||||
indentedlinep :: JournalParser m String
|
indentedlinep :: JournalParser m String
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user