mirror of
https://github.com/simonmichael/hledger.git
synced 2025-01-07 11:19:32 +03:00
imp: default V accounts become just E when a new V account is declared
The equity:conversion account, and its variations equity:trade(s) and equity:trading, normally detected as V/Conversion type, now become ordinary E/Equity accounts if some other account is declared as V/Conversion type. This is motivated by the next commit, in which `check accounts` will stop warning about conversion accounts and their subaccounts, which means all of the above names and their subaccounts would remain always exempt from strict account checking. Now, if the user declares their own conversion account, those default accounts will become controllable by account checking again. Which at least reduces the allowlist a bit. Hopefully this won't cause hassles.
This commit is contained in:
parent
da11d74ae6
commit
d985e89bad
@ -21,6 +21,7 @@ module Hledger.Data.AccountName (
|
||||
,accountNameTreeFrom
|
||||
,accountSummarisedName
|
||||
,accountNameInferType
|
||||
,accountNameInferTypeExcept
|
||||
,accountNameType
|
||||
,defaultBaseConversionAccount
|
||||
,assetAccountRegex
|
||||
@ -84,27 +85,6 @@ acctsepchar = ':'
|
||||
acctsep :: Text
|
||||
acctsep = T.pack [acctsepchar]
|
||||
|
||||
-- accountNameComponents :: AccountName -> [String]
|
||||
-- accountNameComponents = splitAtElement acctsepchar
|
||||
|
||||
accountNameComponents :: AccountName -> [Text]
|
||||
accountNameComponents = T.splitOn acctsep
|
||||
|
||||
accountNameFromComponents :: [Text] -> AccountName
|
||||
accountNameFromComponents = T.intercalate acctsep
|
||||
|
||||
accountLeafName :: AccountName -> Text
|
||||
accountLeafName = last . accountNameComponents
|
||||
|
||||
-- | Truncate all account name components but the last to two characters.
|
||||
accountSummarisedName :: AccountName -> Text
|
||||
accountSummarisedName a
|
||||
-- length cs > 1 = take 2 (head cs) ++ ":" ++ a'
|
||||
| length cs > 1 = T.intercalate ":" (map (T.take 2) $ init cs) <> ":" <> a'
|
||||
| otherwise = a'
|
||||
where
|
||||
cs = accountNameComponents a
|
||||
a' = accountLeafName a
|
||||
-- The base conversion account name used by --infer-equity,
|
||||
-- when no other account of type V/Conversion has been declared.
|
||||
defaultBaseConversionAccount = "equity:conversion"
|
||||
@ -132,6 +112,15 @@ accountNameInferType a
|
||||
| regexMatchText expenseAccountRegex a = Just Expense
|
||||
| otherwise = Nothing
|
||||
|
||||
-- | Like accountNameInferType, but exclude the provided types from the guesses.
|
||||
-- Used eg to prevent "equity:conversion" being inferred as Conversion when a different
|
||||
-- account has been declared with that type.
|
||||
accountNameInferTypeExcept :: [AccountType] -> AccountName -> Maybe AccountType
|
||||
accountNameInferTypeExcept excludedtypes a =
|
||||
case accountNameInferType a of
|
||||
Just t | not $ t `elem` excludedtypes -> Just t
|
||||
_ -> Nothing
|
||||
|
||||
-- Extract the 'AccountType' of an 'AccountName' by looking it up in the
|
||||
-- provided Map, traversing the parent accounts if necessary. If none of those
|
||||
-- work, try 'accountNameInferType'.
|
||||
@ -139,6 +128,28 @@ accountNameType :: M.Map AccountName AccountType -> AccountName -> Maybe Account
|
||||
accountNameType atypes a = asum (map (`M.lookup` atypes) $ a : parentAccountNames a)
|
||||
<|> accountNameInferType a
|
||||
|
||||
-- accountNameComponents :: AccountName -> [String]
|
||||
-- accountNameComponents = splitAtElement acctsepchar
|
||||
|
||||
accountNameComponents :: AccountName -> [Text]
|
||||
accountNameComponents = T.splitOn acctsep
|
||||
|
||||
accountNameFromComponents :: [Text] -> AccountName
|
||||
accountNameFromComponents = T.intercalate acctsep
|
||||
|
||||
accountLeafName :: AccountName -> Text
|
||||
accountLeafName = last . accountNameComponents
|
||||
|
||||
-- | Truncate all account name components but the last to two characters.
|
||||
accountSummarisedName :: AccountName -> Text
|
||||
accountSummarisedName a
|
||||
-- length cs > 1 = take 2 (head cs) ++ ":" ++ a'
|
||||
| length cs > 1 = T.intercalate ":" (map (T.take 2) $ init cs) <> ":" <> a'
|
||||
| otherwise = a'
|
||||
where
|
||||
cs = accountNameComponents a
|
||||
a' = accountLeafName a
|
||||
|
||||
-- | The level (depth) of an account name.
|
||||
--
|
||||
-- >>> accountNameLevel "" -- special case
|
||||
|
@ -579,7 +579,7 @@ journalAddAccountTypes j = j{jaccounttypes = journalAccountTypes j}
|
||||
|
||||
-- | An account type inherited from the parent account(s),
|
||||
-- and whether it was originally declared by an account directive (true) or inferred from an account name (false).
|
||||
type ParentAccountType = ( AccountType, Bool )
|
||||
type ParentAccountType = (AccountType, Bool)
|
||||
|
||||
-- | Build a map of all known account types, explicitly declared
|
||||
-- or inferred from the account's parent or name.
|
||||
@ -587,11 +587,12 @@ journalAccountTypes :: Journal -> M.Map AccountName AccountType
|
||||
journalAccountTypes j = M.fromList [(a,acctType) | (a, Just (acctType,_)) <- flatten t']
|
||||
where
|
||||
t = accountNameTreeFrom $ journalAccountNames j :: Tree AccountName
|
||||
-- Map from the top of the account tree down to the leaves, applying any explicitly declared account types,
|
||||
-- Traverse downward through the account tree, applying any explicitly declared account types,
|
||||
-- otherwise inferring account types from account names when possible, and propagating account types downward.
|
||||
-- Declared account types (possibly inherited from parent) are preferred, inferred types are used as a fallback.
|
||||
t' = setTypeHereAndBelow Nothing t :: Tree (AccountName, Maybe (AccountType, Bool))
|
||||
where
|
||||
declaredtypes = M.keys $ jdeclaredaccounttypes j
|
||||
declaredtypesbyname = journalDeclaredAccountTypes j & fmap (,True)
|
||||
setTypeHereAndBelow :: Maybe ParentAccountType -> Tree AccountName -> Tree (AccountName, Maybe ParentAccountType)
|
||||
setTypeHereAndBelow mparenttype (Node a subs) = Node (a, mnewtype) (map (setTypeHereAndBelow mnewtype) subs)
|
||||
@ -601,9 +602,9 @@ journalAccountTypes j = M.fromList [(a,acctType) | (a, Just (acctType,_)) <- fla
|
||||
mthisacctdeclaredtype = M.lookup a declaredtypesbyname
|
||||
mparentacctdeclaredtype = if fromMaybe False $ snd <$> mparenttype then mparenttype else Nothing
|
||||
mparentacctinferredtype = if not $ fromMaybe True $ snd <$> mparenttype then mparenttype else Nothing
|
||||
mthisacctinferredtype = accountNameInferType a & fmap (,False)
|
||||
mthisacctinferredtype = accountNameInferTypeExcept declaredtypes a & fmap (,False) -- XXX not sure about this Except logic.. but for now, tests pass
|
||||
|
||||
-- | Build a map of the account types explicitly declared for each account.
|
||||
-- | Build a map from account names to explicitly declared account types.
|
||||
journalDeclaredAccountTypes :: Journal -> M.Map AccountName AccountType
|
||||
journalDeclaredAccountTypes Journal{jdeclaredaccounttypes} =
|
||||
M.fromList $ concat [map (,t) as | (t,as) <- M.toList jdeclaredaccounttypes]
|
||||
|
@ -39,3 +39,56 @@ account asset
|
||||
$ hledger -f - accounts --types
|
||||
asset ; type: A
|
||||
unknown ; type:
|
||||
|
||||
# ** 7. equity:conversion, and several other names, are detected as V/Conversion type by default.
|
||||
<
|
||||
account equity:conversion
|
||||
account equity:trade
|
||||
account equity:trades
|
||||
account equity:trading
|
||||
$ hledger -f- accounts --types
|
||||
equity:conversion ; type: V
|
||||
equity:trade ; type: V
|
||||
equity:trades ; type: V
|
||||
equity:trading ; type: V
|
||||
|
||||
# ** 8. If any other account name is declared with V type, those default names become just ordinary equity accounts.
|
||||
<
|
||||
account trade ; type: V
|
||||
account equity:conversion
|
||||
account equity:trade
|
||||
account equity:trades
|
||||
account equity:trading
|
||||
$ hledger -f- accounts --types
|
||||
trade ; type: V
|
||||
equity:conversion ; type: E
|
||||
equity:trade ; type: E
|
||||
equity:trades ; type: E
|
||||
equity:trading ; type: E
|
||||
|
||||
# ** 9. --infer-equity uses equity:conversion as its base account by default.
|
||||
<
|
||||
2024-01-01
|
||||
a 1A
|
||||
b -1B
|
||||
|
||||
$ hledger -f- accounts --infer-equity
|
||||
a
|
||||
b
|
||||
equity:conversion:A-B:A
|
||||
equity:conversion:A-B:B
|
||||
|
||||
# ** 10. With a custom conversion account declared, --infer-equity uses that instead.
|
||||
<
|
||||
account trade ; type:V
|
||||
|
||||
2024-01-01
|
||||
a 1A
|
||||
b -1B
|
||||
|
||||
$ hledger -f- accounts --infer-equity
|
||||
trade
|
||||
trade:A-B:A
|
||||
trade:A-B:B
|
||||
a
|
||||
b
|
||||
|
Loading…
Reference in New Issue
Block a user