{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
module Hledger.Cli.Commands.Close (
closemode
,close
)
where
import Control.Monad (when)
import Data.Maybe
import Data.String.Here
import Data.Time.Calendar
import Hledger
import Hledger.Cli.CliOptions
import System.Console.CmdArgs.Explicit as C
closemode = hledgerCommandMode
[here| close equity
Print a "closing balances" transaction that brings all accounts (or with
query arguments, just the matched accounts) to a zero (historical) balance,
followed by an opposite "opening balances" transaction that restores the
balances from zero.
FLAGS
The opening transaction is useful to carry over asset/liability balances
if you choose to start a new journal file, eg yearly. The closing transaction
can be a useful complement, allowing you to optionally include old files
(for more history) without disturbing the asset/liability balances
(since the closing/opening pairs cancel out).
This command may also be useful for closing out expense/income accounts
for a period (ie "closing the books" in accounting).
Both transactions include balance assertions for the closed/reopened accounts.
You probably shouldn't use status or realness queries (eg -C or -R) with this
command, or the balance assertions will require that query to pass.
By default, the closing transaction is dated yesterday, with balances
calculated as of end of yesterday, and the opening transaction is dated today.
To close on some other date, use: `hledger close -e OPENINGDATE ...`.
(-p or date: can also be used, the begin date is ignored.)
You can chose to print just one of the transactions with `--opening`
or `--closing`.
For example, carrying asset/liability balances into a new file for 2018:
```
$ hledger close -f 2017.journal -e 2018/1/1 ^assets ^liab >>2017.journal
# cut & paste the opening transaction from 2017.journal to a new 2018.journal
# now:
$ hledger bs -f 2018.journal # correct balances
$ hledger bs -f 2018.journal -f 2017.journal # still correct
$ hledger bs -f 2017.journal not:desc:closing # must exclude closing txn
```
Transactions spanning the closing date may complicate matters. Eg, if
closing at end of 2017:
```
2017/12/31
expenses:food 1
assets:bank:checking -1 ; date:2018/1/1
```
|]
[flagNone ["opening"] (\opts -> setboolopt "opening" opts) "show just opening transaction"
,flagNone ["closing"] (\opts -> setboolopt "closing" opts) "show just closing transaction"
]
[generalflagsgroup1]
[]
([], Just $ argsFlag "[QUERY]")
close CliOpts{rawopts_=rawopts, reportopts_=ropts} j = do
today <- getCurrentDay
let
(opening, closing) =
case (boolopt "opening" rawopts, boolopt "closing" rawopts) of
(False, False) -> (True, True)
(o, c) -> (o, c)
ropts_ = ropts{balancetype_=HistoricalBalance, accountlistmode_=ALFlat}
q = queryFromOpts today ropts_
openingdate = fromMaybe today $ queryEndDate False q
closingdate = addDays (-1) openingdate
(acctbals,_) = balanceReportFromMultiBalanceReport ropts_ q j
balancingamt = negate $ sum $ map (\(_,_,_,b) -> normaliseMixedAmountSquashPricesForDisplay b) acctbals
ps = [posting{paccount=a
,pamount=mixed [b]
,pbalanceassertion=Just assertion{ baamount=b }
}
|(a,_,_,mb) <- acctbals
,b <- amounts $ normaliseMixedAmountSquashPricesForDisplay mb
]
++ [posting{paccount="equity:opening balances", pamount=balancingamt}]
nps = [posting{paccount=a
,pamount=mixed [negate b]
,pbalanceassertion=Just assertion{ baamount=b{aquantity=0} }
}
|(a,_,_,mb) <- acctbals
,b <- amounts $ normaliseMixedAmountSquashPricesForDisplay mb
]
++ [posting{paccount="equity:closing balances", pamount=negate balancingamt}]
when closing $ putStr $ showTransaction (nulltransaction{tdate=closingdate, tdescription="closing balances", tpostings=nps})
when opening $ putStr $ showTransaction (nulltransaction{tdate=openingdate, tdescription="opening balances", tpostings=ps})