close: add the --interleaved flag; refactor a little

Interleaved equity postings make troubleshooting easier.
This commit is contained in:
Simon Michael 2020-01-18 05:00:55 -08:00
parent a5ff9d6a63
commit 1e9f30bafc
3 changed files with 91 additions and 27 deletions

View File

@ -27,14 +27,18 @@ closemode = hledgerCommandMode
,flagNone ["opening"] (setboolopt "opening") "show just opening transaction" ,flagNone ["opening"] (setboolopt "opening") "show just opening transaction"
,flagReq ["close-to"] (\s opts -> Right $ setopt "close-to" s opts) "ACCT" ("account to transfer closing balances to (default: "++defclosingacct++")") ,flagReq ["close-to"] (\s opts -> Right $ setopt "close-to" s opts) "ACCT" ("account to transfer closing balances to (default: "++defclosingacct++")")
,flagReq ["open-from"] (\s opts -> Right $ setopt "open-from" s opts) "ACCT" ("account to transfer opening balances from (default: "++defopeningacct++")") ,flagReq ["open-from"] (\s opts -> Right $ setopt "open-from" s opts) "ACCT" ("account to transfer opening balances from (default: "++defopeningacct++")")
,flagNone ["interleaved"] (setboolopt "interleaved") "keep equity and non-equity postings adjacent"
] ]
[generalflagsgroup1] [generalflagsgroup1]
hiddenflags hiddenflags
([], Just $ argsFlag "[QUERY]") ([], Just $ argsFlag "[QUERY]")
-- debugger, beware: close is incredibly devious. simple rules combine to make a horrid maze.
close CliOpts{rawopts_=rawopts, reportopts_=ropts} j = do close CliOpts{rawopts_=rawopts, reportopts_=ropts} j = do
today <- getCurrentDay today <- getCurrentDay
let let
-- interleave equity postings next to the corresponding closing posting, or put them all at the end ?
interleaved = boolopt "interleaved" rawopts
(opening, closing) = (opening, closing) =
case (boolopt "opening" rawopts, boolopt "closing" rawopts) of case (boolopt "opening" rawopts, boolopt "closing" rawopts) of
(False, False) -> (True, True) -- by default show both opening and closing (False, False) -> (True, True) -- by default show both opening and closing
@ -46,17 +50,29 @@ close CliOpts{rawopts_=rawopts, reportopts_=ropts} j = do
openingdate = fromMaybe today $ queryEndDate False q openingdate = fromMaybe today $ queryEndDate False q
closingdate = addDays (-1) openingdate closingdate = addDays (-1) openingdate
(acctbals,_) = balanceReportFromMultiBalanceReport ropts_ q j (acctbals,_) = balanceReportFromMultiBalanceReport ropts_ q j
balancingamt = negate $ sum $ map (\(_,_,_,b) -> normaliseMixedAmount b) acctbals balancingamt = sum $ map (\(_,_,_,b) -> normaliseMixedAmount b) acctbals
-- since balance assertion amounts are required to be exact, the -- since balance assertion amounts are required to be exact, the
-- amounts in opening/closing transactions should be too (#941, #1137) -- amounts in opening/closing transactions should be too (#941, #1137)
setprec = setFullPrecision setprec = setFullPrecision
-- balance assertion amounts will be unpriced (#824) closingps = concat
-- only the last posting in each commodity will have a balance assertion (#1035) [[posting{paccount = a
closingps = [posting{paccount = a
,pamount = mixed [setprec $ negate b] ,pamount = mixed [setprec $ negate b]
,pbalanceassertion = if islast then Just nullassertion{baamount=setprec b{aquantity=0, aprice=Nothing}} else Nothing -- after each commodity's last posting, assert 0 balance (#1035)
-- balance assertion amounts are unpriced (#824)
,pbalanceassertion =
if islast
then Just nullassertion{baamount=setprec b{aquantity=0, aprice=Nothing}}
else Nothing
} }
] ++
if interleaved then
-- a corresponding posting transferring the above balance to equity
[posting{paccount = closingacct
,pamount = Mixed [b]
}
]
else []
| (a,_,_,mb) <- acctbals | (a,_,_,mb) <- acctbals
-- the balances in each commodity, and for each transaction price -- the balances in each commodity, and for each transaction price
, let bs = amounts $ normaliseMixedAmount mb , let bs = amounts $ normaliseMixedAmount mb
@ -65,20 +81,31 @@ close CliOpts{rawopts_=rawopts, reportopts_=ropts} j = do
| bs <- groupBy ((==) `on` acommodity) bs] | bs <- groupBy ((==) `on` acommodity) bs]
, (b, islast) <- bs' , (b, islast) <- bs'
] ]
-- The balancing posting to equity. Allow this one to have a multicommodity amount,
-- and don't try to assert its balance.
++ ++
if interleaved then []
else
-- a final posting transferring all the balances to equity
-- (print will show it as multiple single-commodity postings)
[posting{paccount = closingacct [posting{paccount = closingacct
,pamount = negate balancingamt ,pamount = balancingamt
} }
] ]
openingps = [posting{paccount = a openingps = concat
[[posting{paccount = a
,pamount = mixed [setprec b] ,pamount = mixed [setprec b]
,pbalanceassertion = case mcommoditysum of ,pbalanceassertion = case mcommoditysum of
Just s -> Just nullassertion{baamount=setprec s{aprice=Nothing}} Just s -> Just nullassertion{baamount=setprec s{aprice=Nothing}}
Nothing -> Nothing Nothing -> Nothing
} }
] ++
if interleaved then
-- a corresponding posting transferring the above balance from equity
[posting{paccount = openingacct
,pamount = Mixed [negate b]
}
]
else []
| (a,_,_,mb) <- acctbals | (a,_,_,mb) <- acctbals
-- the balances in each commodity, and for each transaction price -- the balances in each commodity, and for each transaction price
, let bs = amounts $ normaliseMixedAmount mb , let bs = amounts $ normaliseMixedAmount mb
@ -89,8 +116,12 @@ close CliOpts{rawopts_=rawopts, reportopts_=ropts} j = do
, (b, mcommoditysum) <- bs' , (b, mcommoditysum) <- bs'
] ]
++ ++
if interleaved then []
else
-- a final posting transferring all the balances from equity
-- (print will show it as multiple single-commodity postings)
[posting{paccount = openingacct [posting{paccount = openingacct
,pamount = balancingamt ,pamount = negate balancingamt
} }
] ]

View File

@ -13,6 +13,9 @@ or you can customise these with the `--close-to` and `--open-from` options.
You can choose to print just one of the transactions by using the You can choose to print just one of the transactions by using the
`--opening` or `--closing` flag. `--opening` or `--closing` flag.
The equity postings appear at the end of the transaction by default;
with `--interleaved`, they appear beside their corresponding closing postings.
If you split your journal files by time (eg yearly), you will If you split your journal files by time (eg yearly), you will
typically run this command at the end of the year, and save the typically run this command at the end of the year, and save the
closing transaction as last entry of the old file, and the opening closing transaction as last entry of the old file, and the opening

View File

@ -237,3 +237,33 @@ $ hledger -f- close -p 2016 assets liabilities
>=0 >=0
# 9. With --interleaved, balanced posting pairs are adjacent.
# (And balances with the same cost are not necessarily combined into
# a single posting. Eg the 5734 EUR above is 5733 EUR and 1 EUR below.)
$ hledger -f- close -p 2016 assets liabilities --interleaved
2016-12-31 closing balances
assets:bank -5,733.00 EUR = 0.00 EUR
equity:closing balances 5,733.00 EUR
liabilities:employer $-10,000.00
equity:closing balances $10,000.00
liabilities:employer $5,000.00 @ 0.93 EUR
equity:closing balances $-5,000.00 @ 0.93 EUR
liabilities:employer $5,000.00 @ 0.95 EUR = $0.00
equity:closing balances $-5,000.00 @ 0.95 EUR
liabilities:employer -1.00 EUR = 0.00 EUR
equity:closing balances 1.00 EUR
2017-01-01 opening balances
assets:bank 5,733.00 EUR = 5,733.00 EUR
equity:opening balances -5,733.00 EUR
liabilities:employer $10,000.00
equity:opening balances $-10,000.00
liabilities:employer $-5,000.00 @ 0.93 EUR
equity:opening balances $5,000.00 @ 0.93 EUR
liabilities:employer $-5,000.00 @ 0.95 EUR = $0.00
equity:opening balances $5,000.00 @ 0.95 EUR
liabilities:employer 1.00 EUR = 1.00 EUR
equity:opening balances -1.00 EUR
>=0