enh:close: add --assert and --assign modes, generating assertions or assignments
This commit is contained in:
parent
30de688765
commit
59999e4ada
@ -32,6 +32,8 @@ closemode = hledgerCommandMode
|
||||
[flagNone ["close"] (setboolopt "close") "show a closing transaction (default)"
|
||||
,flagNone ["open"] (setboolopt "open") "show an opening transaction"
|
||||
,flagNone ["migrate"] (setboolopt "migrate") "show both closing and opening transactions"
|
||||
,flagNone ["assert"] (setboolopt "assert") "show closing balance assertions"
|
||||
,flagNone ["assign"] (setboolopt "assign") "show opening balance assignments (an alternative to closing/opening transactions)"
|
||||
,flagNone ["retain"] (setboolopt "retain") "show a retain earnings transaction (for RX accounts)"
|
||||
,flagNone ["explicit","x"] (setboolopt "explicit") "show all amounts explicitly"
|
||||
,flagNone ["show-costs"] (setboolopt "show-costs") "show amounts with different costs separately"
|
||||
@ -57,11 +59,14 @@ closemode = hledgerCommandMode
|
||||
-- This code is also used by the close command.
|
||||
close copts@CliOpts{rawopts_=rawopts, reportspec_=rspec0} j = do
|
||||
let
|
||||
(close_, open_, defclosedesc_, defopendesc_, defcloseacct_, defacctsq_) = if
|
||||
| boolopt "retain" rawopts -> (True, False, defretaindesc, undefined, defretainacct, Type [Revenue, Expense])
|
||||
| boolopt "migrate" rawopts -> (True, True, defclosedesc, defopendesc, defcloseacct, Type [Asset, Liability, Equity])
|
||||
| boolopt "open" rawopts -> (False, True, undefined, defopendesc, defcloseacct, Type [Asset, Liability, Equity])
|
||||
| otherwise -> (True, False, defclosedesc, undefined, defcloseacct, Type [Asset, Liability, Equity])
|
||||
-- currently only one of the six mode flags takes effect at a time (hledger close --close --open only does --open).
|
||||
(close_, open_, assert_, assign_, defclosedesc_, defopendesc_, defcloseacct_, defacctsq_) = if
|
||||
| boolopt "retain" rawopts -> (True, False, False, False, defretaindesc, undefined, defretainacct, Type [Revenue, Expense])
|
||||
| boolopt "migrate" rawopts -> (True, True, False, False, defclosedesc, defopendesc, defcloseacct, Type [Asset, Liability, Equity])
|
||||
| boolopt "assign" rawopts -> (False, False, False, True, undefined, defopendesc, defcloseacct, Type [Asset, Liability, Equity])
|
||||
| boolopt "assert" rawopts -> (False, False, True, False, defclosedesc, undefined, defcloseacct, Type [Asset, Liability, Equity])
|
||||
| boolopt "open" rawopts -> (False, True, False, False, undefined, defopendesc, defcloseacct, Type [Asset, Liability, Equity])
|
||||
| otherwise -> (True, False, False, False, defclosedesc, undefined, defcloseacct, Type [Asset, Liability, Equity]) -- close
|
||||
|
||||
-- descriptions to use for the closing/opening transactions
|
||||
closedesc = T.pack $ fromMaybe defclosedesc_ $ maybestringopt "close-desc" rawopts
|
||||
@ -106,59 +111,101 @@ close copts@CliOpts{rawopts_=rawopts, reportspec_=rspec0} j = do
|
||||
-- interleave equity postings next to the corresponding closing posting, or put them all at the end ?
|
||||
interleaved = boolopt "interleaved" rawopts
|
||||
|
||||
-- the closing transaction
|
||||
-- the closing (balance-asserting or balance-zeroing) transaction
|
||||
closetxn = nulltransaction{tdate=closedate, tdescription=closedesc, tpostings=closeps}
|
||||
closeps =
|
||||
concat [
|
||||
posting{paccount = a
|
||||
,pamount = mixedAmount . precise $ 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=precise b{aquantity=0, aprice=Nothing}}
|
||||
else Nothing
|
||||
}
|
||||
|
||||
-- maybe an interleaved posting transferring this balance to equity
|
||||
: [posting{paccount=closeacct, pamount=mixedAmount $ precise b} | interleaved]
|
||||
|
||||
| -- get the balances for each commodity and transaction price
|
||||
(a,mb) <- acctbals
|
||||
, let bs0 = amounts mb
|
||||
-- mark the last balance in each commodity with True
|
||||
, let bs2 = concat [reverse $ zip (reverse bs1) (True : repeat False)
|
||||
| bs1 <- groupBy ((==) `on` acommodity) bs0]
|
||||
, (b, islast) <- bs2
|
||||
closeps
|
||||
-- XXX some duplication
|
||||
| assert_ =
|
||||
[ posting{
|
||||
paccount = a
|
||||
,pamount = mixedAmount $ precise b{aquantity=0, aprice=Nothing}
|
||||
-- after each commodity's last posting, assert 0 balance (#1035)
|
||||
-- balance assertion amounts are unpriced (#824)
|
||||
,pbalanceassertion =
|
||||
if islast
|
||||
then Just nullassertion{baamount=precise b}
|
||||
else Nothing
|
||||
}
|
||||
| -- get the balances for each commodity and transaction price
|
||||
(a,mb) <- acctbals
|
||||
, let bs0 = amounts mb
|
||||
-- mark the last balance in each commodity with True
|
||||
, let bs2 = concat [reverse $ zip (reverse bs1) (True : repeat False)
|
||||
| bs1 <- groupBy ((==) `on` acommodity) bs0]
|
||||
, (b, islast) <- bs2
|
||||
]
|
||||
|
||||
-- or a final multicommodity posting transferring all balances to equity
|
||||
-- (print will show this as multiple single-commodity postings)
|
||||
++ [posting{paccount=closeacct, pamount=if explicit then mixedAmountSetFullPrecision totalamt else missingmixedamt} | not interleaved]
|
||||
| otherwise =
|
||||
concat [
|
||||
posting{paccount = a
|
||||
,pamount = mixedAmount . precise $ 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=precise b{aquantity=0, aprice=Nothing}}
|
||||
else Nothing
|
||||
}
|
||||
|
||||
-- the opening transaction
|
||||
-- maybe an interleaved posting transferring this balance to equity
|
||||
: [posting{paccount=closeacct, pamount=mixedAmount $ precise b} | interleaved]
|
||||
|
||||
| -- get the balances for each commodity and transaction price
|
||||
(a,mb) <- acctbals
|
||||
, let bs0 = amounts mb
|
||||
-- mark the last balance in each commodity with True
|
||||
, let bs2 = concat [reverse $ zip (reverse bs1) (True : repeat False)
|
||||
| bs1 <- groupBy ((==) `on` acommodity) bs0]
|
||||
, (b, islast) <- bs2
|
||||
]
|
||||
|
||||
-- or a final multicommodity posting transferring all balances to equity
|
||||
-- (print will show this as multiple single-commodity postings)
|
||||
++ [posting{paccount=closeacct, pamount=if explicit then mixedAmountSetFullPrecision totalamt else missingmixedamt} | not interleaved]
|
||||
|
||||
-- the opening (balance-assigning or balance-unzeroing) transaction
|
||||
opentxn = nulltransaction{tdate=opendate, tdescription=opendesc, tpostings=openps}
|
||||
openps =
|
||||
concat [
|
||||
posting{paccount = a
|
||||
,pamount = mixedAmount $ precise b
|
||||
,pbalanceassertion =
|
||||
case mcommoditysum of
|
||||
Just s -> Just nullassertion{baamount=precise s{aprice=Nothing}}
|
||||
Nothing -> Nothing
|
||||
}
|
||||
: [posting{paccount=openacct, pamount=mixedAmount . precise $ negate b} | interleaved]
|
||||
openps
|
||||
| assign_ =
|
||||
[ posting{paccount = a
|
||||
,pamount = missingmixedamt
|
||||
,pbalanceassertion = Just nullassertion{baamount=b}
|
||||
-- case mcommoditysum of
|
||||
-- Just s -> Just nullassertion{baamount=precise s}
|
||||
-- Nothing -> Nothing
|
||||
}
|
||||
|
||||
| (a,mb) <- acctbals
|
||||
, let bs0 = amounts mb
|
||||
-- mark the last balance in each commodity with the unpriced sum in that commodity (for a balance assertion)
|
||||
, let bs2 = concat [reverse $ zip (reverse bs1) (Just commoditysum : repeat Nothing)
|
||||
| bs1 <- groupBy ((==) `on` acommodity) bs0
|
||||
, let commoditysum = (sum bs1)]
|
||||
, (b, mcommoditysum) <- bs2
|
||||
| (a,mb) <- acctbals
|
||||
, let bs0 = amounts mb
|
||||
-- mark the last balance in each commodity with the unpriced sum in that commodity (for a balance assertion)
|
||||
, let bs2 = concat [reverse $ zip (reverse bs1) (Just commoditysum : repeat Nothing)
|
||||
| bs1 <- groupBy ((==) `on` acommodity) bs0
|
||||
, let commoditysum = (sum bs1)]
|
||||
, (b, _mcommoditysum) <- bs2
|
||||
]
|
||||
++ [posting{paccount=openacct, pamount=if explicit then mixedAmountSetFullPrecision (maNegate totalamt) else missingmixedamt} | not interleaved]
|
||||
++ [posting{paccount=openacct, pamount=if explicit then mixedAmountSetFullPrecision (maNegate totalamt) else missingmixedamt} | not interleaved]
|
||||
|
||||
| otherwise =
|
||||
concat [
|
||||
posting{paccount = a
|
||||
,pamount = mixedAmount $ precise b
|
||||
,pbalanceassertion =
|
||||
case mcommoditysum of
|
||||
Just s -> Just nullassertion{baamount=precise s{aprice=Nothing}}
|
||||
Nothing -> Nothing
|
||||
}
|
||||
: [posting{paccount=openacct, pamount=mixedAmount . precise $ negate b} | interleaved]
|
||||
|
||||
| (a,mb) <- acctbals
|
||||
, let bs0 = amounts mb
|
||||
-- mark the last balance in each commodity with the unpriced sum in that commodity (for a balance assertion)
|
||||
, let bs2 = concat [reverse $ zip (reverse bs1) (Just commoditysum : repeat Nothing)
|
||||
| bs1 <- groupBy ((==) `on` acommodity) bs0
|
||||
, let commoditysum = (sum bs1)]
|
||||
, (b, mcommoditysum) <- bs2
|
||||
]
|
||||
++ [posting{paccount=openacct, pamount=if explicit then mixedAmountSetFullPrecision (maNegate totalamt) else missingmixedamt} | not interleaved]
|
||||
|
||||
-- print them
|
||||
when close_ . T.putStr $ showTransaction closetxn
|
||||
when open_ . T.putStr $ showTransaction opentxn
|
||||
when (close_ || assert_) . T.putStr $ showTransaction closetxn
|
||||
when (open_ || assign_) . T.putStr $ showTransaction opentxn
|
||||
|
||||
@ -2,42 +2,58 @@
|
||||
|
||||
(equity)
|
||||
|
||||
Generate transactions which transfer account balances to and/or from
|
||||
another account (typically equity).
|
||||
This can be useful for migrating balances to a new journal file,
|
||||
or for merging earnings into equity at end of accounting period.
|
||||
|
||||
By default, it prints a transaction that zeroes out ALE accounts
|
||||
(asset, liability, equity accounts; this requires account types to be configured);
|
||||
or if ACCTQUERY is provided, the accounts matched by that.
|
||||
A transaction-generating command which generates several kinds of "closing"
|
||||
and/or "opening" transactions useful in certain situations.
|
||||
It prints one or two transactions to stdout, but does not write them to the journal automatically.
|
||||
|
||||
*(experimental)*
|
||||
|
||||
_FLAGS
|
||||
|
||||
This command has four main modes, corresponding to the most common use cases:
|
||||
This command is most often used when migrating balances to a new
|
||||
journal file, at the start of a new financial year. There are a few
|
||||
ways to do that, we're not sure which is best, and this command has
|
||||
other uses as well; so it currently has six modes, selected by a mode
|
||||
flag. Use only one of these flags at a time:
|
||||
|
||||
1. With `--close` (default), it prints a "closing balances" transaction
|
||||
that zeroes out ALE (asset, liability, equity) accounts by default
|
||||
(this requires [account types](hledger.md#account-types) to be inferred or declared);
|
||||
or, the accounts matched by the provided ACCTQUERY arguments.
|
||||
1. With `--close` (or no mode flag) it prints a "closing balances" transaction
|
||||
that zeroes out all the ALE (asset, liability, equity) accounts, by default
|
||||
(this requires inferred or declared [account types](hledger.md#account-types));
|
||||
or, the accounts matched by ACCTQUERY arguments you provide.
|
||||
The balances are transferred to an equity account.
|
||||
|
||||
2. With `--open`, it prints an opposite "opening balances" transaction that restores
|
||||
those balances from zero. This is similar to Ledger's equity command.
|
||||
2. With `--open`, it prints an opposite "opening balances" transaction that
|
||||
"unzeros" the same accounts, restoring their balances from zero.
|
||||
(This mode is similar to Ledger's equity command.)
|
||||
|
||||
3. With `--migrate`, it prints both the closing and opening transactions.
|
||||
This is the preferred way to migrate balances to a new file:
|
||||
run `hledger close --migrate`,
|
||||
add the closing transaction at the end of the old file, and
|
||||
add the opening transaction at the start of the new file.
|
||||
The matching closing/opening transactions cancel each other out,
|
||||
preserving correct balances during multi-file reporting.
|
||||
3. With `--migrate`, it prints both the `--close` and the `--open` transactions.
|
||||
This is a common way to migrate balances to a new file at year end;
|
||||
run `hledger close --migrate` (or `hledger close --close` and `hleddger close --open`)
|
||||
and add the closing transaction at the end of the old file,
|
||||
and the opening transaction at the start of the new file.
|
||||
This allows you to use the new file by itself, or together with previous file(s),
|
||||
and still get correct balances either way,
|
||||
because the matching closing/opening transactions will cancel each other out.
|
||||
(You will need to exclude them sometimes, eg to see an end of year balance sheet;
|
||||
`not:opening/closing` often works.)
|
||||
|
||||
4. With `--retain`, it prints a "retain earnings" transaction that transfers
|
||||
4. With `--assert` it prints a "closing balances" transaction that
|
||||
just asserts the current balances, without changing them.
|
||||
|
||||
5. With `--assign` it prints an "opening balances" transaction that
|
||||
restores the account balances by using balance assignments,
|
||||
which always succeed and do need to be preceded by a closing transaction.
|
||||
This is an alternative to `--close` and `--open`: at year end
|
||||
you can `--assert` in the old file and `--assign` in the new file;
|
||||
(or skip the `--assert` and just do the `--assign`).
|
||||
This sacrifices some error checking, but could be convenient if you are
|
||||
often doing cleanups or fixes which break your closing/opening transactions.
|
||||
|
||||
6. With `--retain`, it prints a "retain earnings" transaction that transfers
|
||||
RX (revenue and expense) balances to `equity:retained earnings`.
|
||||
Businesses traditionally do this at the end of each accounting period;
|
||||
it is less necessary with computer-based accounting, but it could still be useful
|
||||
if you want to see the accounting equation (A=L+E) satisfied.
|
||||
This is a traditional end-of-period bookkeeping operation also called "closing the books";
|
||||
in personal accounting you probably will not need this but it could be useful
|
||||
if you want to see the accounting equation (A=L+E) balanced.
|
||||
|
||||
In all modes, the defaults can be overridden:
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user