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"
,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++")")
,flagNone ["interleaved"] (setboolopt "interleaved") "keep equity and non-equity postings adjacent"
]
[generalflagsgroup1]
hiddenflags
([], 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
today <- getCurrentDay
let
-- interleave equity postings next to the corresponding closing posting, or put them all at the end ?
interleaved = boolopt "interleaved" rawopts
(opening, closing) =
case (boolopt "opening" rawopts, boolopt "closing" rawopts) of
(False, False) -> (True, True) -- by default show both opening and closing
@ -46,51 +50,78 @@ close CliOpts{rawopts_=rawopts, reportopts_=ropts} j = do
openingdate = fromMaybe today $ queryEndDate False q
closingdate = addDays (-1) openingdate
(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
-- amounts in opening/closing transactions should be too (#941, #1137)
setprec = setFullPrecision
-- balance assertion amounts will be unpriced (#824)
-- only the last posting in each commodity will have a balance assertion (#1035)
closingps = [posting{paccount = a
,pamount = mixed [setprec $ negate b]
,pbalanceassertion = if islast then Just nullassertion{baamount=setprec b{aquantity=0, aprice=Nothing}} else Nothing
}
| (a,_,_,mb) <- acctbals
-- the balances in each commodity, and for each transaction price
, let bs = amounts $ normaliseMixedAmount mb
-- mark the last balance in each commodity
, let bs' = concat [reverse $ zip (reverse bs) (True : repeat False)
| bs <- groupBy ((==) `on` acommodity) bs]
, (b, islast) <- bs'
closingps = concat
[[posting{paccount = a
,pamount = mixed [setprec $ negate b]
-- 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
-- the balances in each commodity, and for each transaction price
, let bs = amounts $ normaliseMixedAmount mb
-- mark the last balance in each commodity
, let bs' = concat [reverse $ zip (reverse bs) (True : repeat False)
| bs <- groupBy ((==) `on` acommodity) 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
,pamount = negate balancingamt
,pamount = balancingamt
}
]
openingps = [posting{paccount = a
openingps = concat
[[posting{paccount = a
,pamount = mixed [setprec b]
,pbalanceassertion = case mcommoditysum of
Just s -> Just nullassertion{baamount=setprec s{aprice=Nothing}}
Nothing -> Nothing
}
| (a,_,_,mb) <- acctbals
-- the balances in each commodity, and for each transaction price
, let bs = amounts $ normaliseMixedAmount mb
-- mark the last balance in each commodity, with the unpriced sum in that commodity
, let bs' = concat [reverse $ zip (reverse bs) (Just commoditysum : repeat Nothing)
| bs <- groupBy ((==) `on` acommodity) bs
, let commoditysum = (sum bs)]
, (b, mcommoditysum) <- bs'
] ++
if interleaved then
-- a corresponding posting transferring the above balance from equity
[posting{paccount = openingacct
,pamount = Mixed [negate b]
}
]
else []
| (a,_,_,mb) <- acctbals
-- the balances in each commodity, and for each transaction price
, let bs = amounts $ normaliseMixedAmount mb
-- mark the last balance in each commodity, with the unpriced sum in that commodity
, let bs' = concat [reverse $ zip (reverse bs) (Just commoditysum : repeat Nothing)
| bs <- groupBy ((==) `on` acommodity) bs
, let commoditysum = (sum 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
,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
`--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
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

View File

@ -237,3 +237,33 @@ $ hledger -f- close -p 2016 assets liabilities
>=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