mirror of
https://github.com/simonmichael/hledger.git
synced 2024-11-08 07:09:28 +03:00
strict mode: -s/--strict requires posted accounts to be declared
This commit is contained in:
parent
ea0d4901ab
commit
ec3ad14ae5
@ -90,6 +90,9 @@ m4_define({{_inputoptions_}}, {{
|
||||
`-I --ignore-assertions`
|
||||
: disable balance assertion checks (note: does not disable balance assignments)
|
||||
|
||||
`-s --strict`
|
||||
: do extra error checking (check that all posted accounts are declared)
|
||||
|
||||
}} )m4_dnl
|
||||
m4_dnl
|
||||
m4_define({{_reportingoptions_}}, {{
|
||||
|
@ -198,6 +198,7 @@ data InputOpts = InputOpts {
|
||||
,pivot_ :: String -- ^ use the given field's value as the account name
|
||||
,auto_ :: Bool -- ^ generate automatic postings when journal is parsed
|
||||
,commoditystyles_ :: Maybe (M.Map CommoditySymbol AmountStyle) -- ^ optional commodity display styles affecting all files
|
||||
,strict_ :: Bool -- ^ do extra error checking (eg, all posted accounts are declared)
|
||||
} deriving (Show)
|
||||
|
||||
instance Default InputOpts where def = definputopts
|
||||
@ -214,6 +215,7 @@ definputopts = InputOpts
|
||||
, pivot_ = ""
|
||||
, auto_ = False
|
||||
, commoditystyles_ = Nothing
|
||||
, strict_ = False
|
||||
}
|
||||
|
||||
rawOptsToInputOpts :: RawOpts -> InputOpts
|
||||
@ -229,6 +231,7 @@ rawOptsToInputOpts rawopts = InputOpts{
|
||||
,pivot_ = stringopt "pivot" rawopts
|
||||
,auto_ = boolopt "auto" rawopts
|
||||
,commoditystyles_ = Nothing
|
||||
,strict_ = boolopt "strict" rawopts
|
||||
}
|
||||
|
||||
--- ** parsing utilities
|
||||
@ -317,7 +320,7 @@ parseAndFinaliseJournal' parser iopts f txt = do
|
||||
-- - infer transaction-implied market prices from transaction prices
|
||||
--
|
||||
journalFinalise :: InputOpts -> FilePath -> Text -> ParsedJournal -> ExceptT String IO Journal
|
||||
journalFinalise InputOpts{auto_,ignore_assertions_,commoditystyles_} f txt pj = do
|
||||
journalFinalise InputOpts{auto_,ignore_assertions_,commoditystyles_,strict_} f txt pj = do
|
||||
t <- liftIO getClockTime
|
||||
d <- liftIO getCurrentDay
|
||||
let pj' =
|
||||
@ -326,33 +329,53 @@ journalFinalise InputOpts{auto_,ignore_assertions_,commoditystyles_} f txt pj =
|
||||
& journalSetLastReadTime t -- save the last read time
|
||||
& journalReverse -- convert all lists to the order they were parsed
|
||||
|
||||
-- Infer and apply canonical styles for each commodity (or throw an error).
|
||||
-- This affects transaction balancing/assertions/assignments, so needs to be done early.
|
||||
case journalApplyCommodityStyles pj' of
|
||||
Left e -> throwError e
|
||||
Right pj'' -> either throwError return $
|
||||
pj''
|
||||
& (if not auto_ || null (jtxnmodifiers pj')
|
||||
then
|
||||
-- Auto postings are not active.
|
||||
-- Balance all transactions and maybe check balance assertions.
|
||||
journalBalanceTransactions (not ignore_assertions_)
|
||||
else \j -> do -- Either monad
|
||||
-- Auto postings are active.
|
||||
-- Balance all transactions without checking balance assertions,
|
||||
j' <- journalBalanceTransactions False j
|
||||
-- then add the auto postings
|
||||
-- (Note adding auto postings after balancing means #893b fails;
|
||||
-- adding them before balancing probably means #893a, #928, #938 fail.)
|
||||
case journalModifyTransactions d j' of
|
||||
Left e -> throwError e
|
||||
Right j'' -> do
|
||||
-- then apply commodity styles once more, to style the auto posting amounts. (XXX inefficient ?)
|
||||
j''' <- journalApplyCommodityStyles j''
|
||||
-- then check balance assertions.
|
||||
journalBalanceTransactions (not ignore_assertions_) j'''
|
||||
)
|
||||
& fmap journalInferMarketPricesFromTransactions -- infer market prices from commodity-exchanging transactions
|
||||
-- If in strict mode, check all postings are to declared accounts
|
||||
case if strict_ then journalCheckAccountsDeclared pj' else Right () of
|
||||
Left e -> throwError e
|
||||
Right () ->
|
||||
|
||||
-- Infer and apply canonical styles for each commodity (or throw an error).
|
||||
-- This affects transaction balancing/assertions/assignments, so needs to be done early.
|
||||
case journalApplyCommodityStyles pj' of
|
||||
Left e -> throwError e
|
||||
Right pj'' -> either throwError return $
|
||||
pj''
|
||||
& (if not auto_ || null (jtxnmodifiers pj'')
|
||||
then
|
||||
-- Auto postings are not active.
|
||||
-- Balance all transactions and maybe check balance assertions.
|
||||
journalBalanceTransactions (not ignore_assertions_)
|
||||
else \j -> do -- Either monad
|
||||
-- Auto postings are active.
|
||||
-- Balance all transactions without checking balance assertions,
|
||||
j' <- journalBalanceTransactions False j
|
||||
-- then add the auto postings
|
||||
-- (Note adding auto postings after balancing means #893b fails;
|
||||
-- adding them before balancing probably means #893a, #928, #938 fail.)
|
||||
case journalModifyTransactions d j' of
|
||||
Left e -> throwError e
|
||||
Right j'' -> do
|
||||
-- then apply commodity styles once more, to style the auto posting amounts. (XXX inefficient ?)
|
||||
j''' <- journalApplyCommodityStyles j''
|
||||
-- then check balance assertions.
|
||||
journalBalanceTransactions (not ignore_assertions_) j'''
|
||||
)
|
||||
& fmap journalInferMarketPricesFromTransactions -- infer market prices from commodity-exchanging transactions
|
||||
|
||||
-- | Check that all the journal's postings are to accounts declared with
|
||||
-- account directives, returning an error message otherwise.
|
||||
journalCheckAccountsDeclared :: Journal -> Either String ()
|
||||
journalCheckAccountsDeclared j = sequence_ $ map checkacct $ journalPostings j
|
||||
where
|
||||
checkacct Posting{paccount,ptransaction}
|
||||
| paccount `elem` as = Right ()
|
||||
| otherwise =
|
||||
Left $ "\nstrict mode: undeclared account \""++T.unpack paccount++"\" is posted to"
|
||||
++ case ptransaction of
|
||||
Just Transaction{tsourcepos} -> "\n at: "++showGenericSourcePos tsourcepos
|
||||
Nothing -> ""
|
||||
where
|
||||
as = journalAccountNamesDeclared j
|
||||
|
||||
setYear :: Year -> JournalParser m ()
|
||||
setYear y = modify' (\j -> j{jparsedefaultyear=Just y})
|
||||
|
@ -1046,24 +1046,45 @@ in another commodity. See [Valuation](hledger.html#valuation).
|
||||
|
||||
### Declaring accounts
|
||||
|
||||
`account` directives can be used to pre-declare accounts.
|
||||
Though not required, they can provide several benefits:
|
||||
`account` directives can be used to declare accounts
|
||||
(ie, the places that amounts are transferred from and to).
|
||||
Though not required, these declarations can provide several benefits:
|
||||
|
||||
- They can document your intended chart of accounts, providing a reference.
|
||||
- They can store extra information about accounts (account numbers, notes, etc.)
|
||||
- They can help hledger know your accounts' types (asset, liability, equity, revenue, expense),
|
||||
useful for reports like balancesheet and incomestatement.
|
||||
- They control account display order in reports, allowing non-alphabetic sorting
|
||||
(eg Revenues to appear above Expenses).
|
||||
- They can store extra information about accounts (account numbers, notes, etc.)
|
||||
- They help with account name completion
|
||||
in the add command, hledger-iadd, hledger-web, ledger-mode etc.
|
||||
- In [strict mode], they restrict which accounts may be posted to by transactions,
|
||||
which helps detect typos.
|
||||
|
||||
[strict mode]: hledger.html#strict-mode
|
||||
|
||||
The simplest form is just the word `account` followed by a hledger-style
|
||||
[account name](journal.html#account-names), eg:
|
||||
[account name](journal.html#account-names), eg this account directive declares the `assets:bank:checking` account:
|
||||
|
||||
```journal
|
||||
account assets:bank:checking
|
||||
```
|
||||
|
||||
#### Account existence
|
||||
|
||||
By default, accounts come into existence when a transaction references them.
|
||||
This is convenient, but when you mis-spell an account name in a transaction,
|
||||
hledger won't be able to detect it. Usually this isn't a big problem, as you'll
|
||||
notice the error in balance reports, or when reconciling account balances.
|
||||
|
||||
When you want more error checking, you can enable [strict mode] with the `-s`/`--strict` flag. Then hledger will will report an error if any transaction references
|
||||
an account that has not been declared by an account directive. Some things to note:
|
||||
|
||||
- The declaration is case-sensitive; transactions must use the correct account name capitalisation.
|
||||
- The account directive's scope is "whole file and below" (see [directives](#directives)). This means it affects all of the current file, and any files it includes, but not parent or sibling files. The position of account directives within the file does not matter, though it's usual to put them at the top.
|
||||
- Accounts can only be declared in `journal` files (but will affect included files in other formats).
|
||||
- It's currently not possible to declare "all possible subaccounts" with a wildcard; every account posted to must be declared.
|
||||
|
||||
#### Account comments
|
||||
|
||||
[Comments](#comments), beginning with a semicolon, can be added:
|
||||
|
@ -125,6 +125,7 @@ inputflags = [
|
||||
,flagNone ["anon"] (setboolopt "anon") "anonymize accounts and payees"
|
||||
,flagReq ["pivot"] (\s opts -> Right $ setopt "pivot" s opts) "TAGNAME" "use some other field/tag for account names"
|
||||
,flagNone ["ignore-assertions","I"] (setboolopt "ignore-assertions") "ignore any balance assertions"
|
||||
,flagNone ["strict","s"] (setboolopt "strict") "do extra error checking (check that all posted accounts are declared)"
|
||||
]
|
||||
|
||||
-- | Common report-related flags: --period, --cost, etc.
|
||||
|
@ -761,6 +761,22 @@ If you need either of those things, you can
|
||||
- use a single parent file which [includes](journal.html#including-other-files) the others
|
||||
- or concatenate the files into one before reading, eg: `cat a.journal b.journal | hledger -f- CMD`.
|
||||
|
||||
## Strict mode
|
||||
|
||||
hledger checks input files for valid data.
|
||||
By default, the most important errors are detected, while still accepting
|
||||
easy journal files without a lot of declarations:
|
||||
|
||||
- Are the input files parseable, with valid syntax ?
|
||||
- Are all transactions balanced ?
|
||||
- Do all balance assertions pass ?
|
||||
|
||||
With the `-s`/`--strict` flag, additional checks are performed:
|
||||
|
||||
- Are all accounts referenced by transactions declared with an account directive ?
|
||||
|
||||
*experimental.*
|
||||
|
||||
## Output destination
|
||||
|
||||
hledger commands send their output to the terminal by default.
|
||||
|
Loading…
Reference in New Issue
Block a user