dev:close: refactor
This commit is contained in:
parent
38d9f1760e
commit
f53f3a0194
@ -8,7 +8,6 @@ module Hledger.Cli.Commands.Close (
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Monad (when)
|
|
||||||
import Data.Function (on)
|
import Data.Function (on)
|
||||||
import Data.List (groupBy)
|
import Data.List (groupBy)
|
||||||
import Data.Maybe (fromMaybe)
|
import Data.Maybe (fromMaybe)
|
||||||
@ -20,6 +19,7 @@ import System.Console.CmdArgs.Explicit as C
|
|||||||
|
|
||||||
import Hledger
|
import Hledger
|
||||||
import Hledger.Cli.CliOptions
|
import Hledger.Cli.CliOptions
|
||||||
|
import Safe (lastDef, readMay)
|
||||||
|
|
||||||
defretaindesc = "retain earnings"
|
defretaindesc = "retain earnings"
|
||||||
defclosedesc = "closing balances"
|
defclosedesc = "closing balances"
|
||||||
@ -54,25 +54,20 @@ closemode = hledgerCommandMode
|
|||||||
)
|
)
|
||||||
([], Just $ argsFlag "[--close | --open | --migrate | --retain] [ACCTQUERY]")
|
([], Just $ argsFlag "[--close | --open | --migrate | --retain] [ACCTQUERY]")
|
||||||
|
|
||||||
|
-- | The close command's mode. Really a subcommand.
|
||||||
|
data CloseMode = Migrate | Close | Open | Assert | Assign | Retain deriving (Eq,Show,Read,Enum)
|
||||||
|
|
||||||
|
-- | Pick the rightmost flag spelled like a CloseMode (--migrate, --close, --open, etc), or default to Close.
|
||||||
|
closeModeFromRawOpts :: RawOpts -> CloseMode
|
||||||
|
closeModeFromRawOpts rawopts = lastDef Close $ collectopts (\(name,_) -> readMay (capitalise name)) rawopts
|
||||||
|
|
||||||
-- Debugger, beware: close is incredibly devious; simple rules combine to make a horrid maze.
|
-- Debugger, beware: close is incredibly devious; simple rules combine to make a horrid maze.
|
||||||
-- Tests are in hledger/test/close.test.
|
-- Tests are in hledger/test/close.test.
|
||||||
-- This code is also used by the close command.
|
|
||||||
close copts@CliOpts{rawopts_=rawopts, reportspec_=rspec0} j = do
|
close copts@CliOpts{rawopts_=rawopts, reportspec_=rspec0} j = do
|
||||||
let
|
let
|
||||||
-- currently only one of the six mode flags takes effect at a time (hledger close --close --open only does --open).
|
mode_ = closeModeFromRawOpts rawopts
|
||||||
(close_, open_, assert_, assign_, defclosedesc_, defopendesc_, defcloseacct_, defacctsq_) = if
|
defacctsq_ = if mode_ == Retain then Type [Revenue, Expense] else Type [Asset, Liability]
|
||||||
| boolopt "retain" rawopts -> (True, False, False, False, defretaindesc, undefined, defretainacct, Type [Revenue, Expense])
|
defcloseacct_ = if mode_ == Retain then defretainacct else defcloseacct
|
||||||
| boolopt "migrate" rawopts -> (True, True, False, False, defclosedesc, defopendesc, defcloseacct, Type [Asset, Liability])
|
|
||||||
| boolopt "assign" rawopts -> (False, False, False, True, undefined, defopendesc, defcloseacct, Type [Asset, Liability])
|
|
||||||
| boolopt "assert" rawopts -> (False, False, True, False, defclosedesc, undefined, defcloseacct, Type [Asset, Liability])
|
|
||||||
| boolopt "open" rawopts -> (False, True, False, False, undefined, defopendesc, defcloseacct, Type [Asset, Liability])
|
|
||||||
| otherwise {- close -} -> (True, False, False, False, defclosedesc, undefined, defcloseacct, Type [Asset, Liability])
|
|
||||||
|
|
||||||
-- descriptions to use for the closing/opening transactions
|
|
||||||
closedesc = T.pack $ fromMaybe defclosedesc_ $ maybestringopt "close-desc" rawopts
|
|
||||||
opendesc = T.pack $ fromMaybe defopendesc_ $ maybestringopt "open-desc" rawopts
|
|
||||||
|
|
||||||
-- equity/balancing accounts to use
|
|
||||||
closeacct = T.pack $ fromMaybe defcloseacct_ $ maybestringopt "close-acct" rawopts
|
closeacct = T.pack $ fromMaybe defcloseacct_ $ maybestringopt "close-acct" rawopts
|
||||||
openacct = maybe closeacct T.pack $ maybestringopt "open-acct" rawopts
|
openacct = maybe closeacct T.pack $ maybestringopt "open-acct" rawopts
|
||||||
|
|
||||||
@ -115,100 +110,110 @@ close copts@CliOpts{rawopts_=rawopts, reportspec_=rspec0} j = do
|
|||||||
interleaved = boolopt "interleaved" rawopts
|
interleaved = boolopt "interleaved" rawopts
|
||||||
|
|
||||||
-- the closing (balance-asserting or balance-zeroing) transaction
|
-- the closing (balance-asserting or balance-zeroing) transaction
|
||||||
closetxn = nulltransaction{tdate=closedate, tdescription=closedesc, tpostings=closeps}
|
mclosetxn
|
||||||
closeps
|
| mode_ `notElem` [Migrate, Close, Assert, Retain] = Nothing
|
||||||
-- XXX some duplication
|
| otherwise = Just nulltransaction{tdate=closedate, tdescription=closedesc, tpostings=closeps}
|
||||||
| assert_ =
|
where
|
||||||
[ posting{
|
closedesc = T.pack $ fromMaybe defclosedesc_ $ maybestringopt "close-desc" rawopts
|
||||||
paccount = a
|
where defclosedesc_ = if mode_ == Retain then defretaindesc else defclosedesc
|
||||||
,pamount = mixedAmount $ precise b{aquantity=0, aprice=Nothing}
|
closeps
|
||||||
-- after each commodity's last posting, assert 0 balance (#1035)
|
-- XXX some duplication
|
||||||
-- balance assertion amounts are unpriced (#824)
|
| mode_ == Assert =
|
||||||
,pbalanceassertion =
|
[ posting{
|
||||||
if islast
|
paccount = a
|
||||||
then Just nullassertion{baamount=precise b}
|
,pamount = mixedAmount $ precise b{aquantity=0, aprice=Nothing}
|
||||||
else Nothing
|
-- after each commodity's last posting, assert 0 balance (#1035)
|
||||||
}
|
-- balance assertion amounts are unpriced (#824)
|
||||||
| -- get the balances for each commodity and transaction price
|
,pbalanceassertion =
|
||||||
(a,mb) <- acctbals
|
if islast
|
||||||
, let bs0 = amounts mb
|
then Just nullassertion{baamount=precise b}
|
||||||
-- mark the last balance in each commodity with True
|
else Nothing
|
||||||
, let bs2 = concat [reverse $ zip (reverse bs1) (True : repeat False)
|
}
|
||||||
| bs1 <- groupBy ((==) `on` acommodity) bs0]
|
| -- get the balances for each commodity and transaction price
|
||||||
, (b, islast) <- bs2
|
(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
|
||||||
|
]
|
||||||
|
|
||||||
| otherwise =
|
| otherwise =
|
||||||
concat [
|
concat [
|
||||||
posting{paccount = a
|
posting{paccount = a
|
||||||
,pamount = mixedAmount . precise $ negate b
|
,pamount = mixedAmount . precise $ negate b
|
||||||
-- after each commodity's last posting, assert 0 balance (#1035)
|
-- after each commodity's last posting, assert 0 balance (#1035)
|
||||||
-- balance assertion amounts are unpriced (#824)
|
-- balance assertion amounts are unpriced (#824)
|
||||||
,pbalanceassertion =
|
,pbalanceassertion =
|
||||||
if islast
|
if islast
|
||||||
then Just nullassertion{baamount=precise b{aquantity=0, aprice=Nothing}}
|
then Just nullassertion{baamount=precise b{aquantity=0, aprice=Nothing}}
|
||||||
else Nothing
|
else Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
-- maybe an interleaved posting transferring this balance to equity
|
-- maybe an interleaved posting transferring this balance to equity
|
||||||
: [posting{paccount=closeacct, pamount=mixedAmount $ precise b} | interleaved]
|
: [posting{paccount=closeacct, pamount=mixedAmount $ precise b} | interleaved]
|
||||||
|
|
||||||
| -- get the balances for each commodity and transaction price
|
| -- get the balances for each commodity and transaction price
|
||||||
(a,mb) <- acctbals
|
(a,mb) <- acctbals
|
||||||
, let bs0 = amounts mb
|
, let bs0 = amounts mb
|
||||||
-- mark the last balance in each commodity with True
|
-- mark the last balance in each commodity with True
|
||||||
, let bs2 = concat [reverse $ zip (reverse bs1) (True : repeat False)
|
, let bs2 = concat [reverse $ zip (reverse bs1) (True : repeat False)
|
||||||
| bs1 <- groupBy ((==) `on` acommodity) bs0]
|
| bs1 <- groupBy ((==) `on` acommodity) bs0]
|
||||||
, (b, islast) <- bs2
|
, (b, islast) <- bs2
|
||||||
]
|
]
|
||||||
|
|
||||||
-- or a final multicommodity posting transferring all balances to equity
|
-- or a final multicommodity posting transferring all balances to equity
|
||||||
-- (print will show this as multiple single-commodity postings)
|
-- (print will show this as multiple single-commodity postings)
|
||||||
++ [posting{paccount=closeacct, pamount=if explicit then mixedAmountSetFullPrecision totalamt else missingmixedamt} | not interleaved]
|
++ [posting{paccount=closeacct, pamount=if explicit then mixedAmountSetFullPrecision totalamt else missingmixedamt} | not interleaved]
|
||||||
|
|
||||||
-- the opening (balance-assigning or balance-unzeroing) transaction
|
-- the opening (balance-assigning or balance-unzeroing) transaction
|
||||||
opentxn = nulltransaction{tdate=opendate, tdescription=opendesc, tpostings=openps}
|
mopentxn
|
||||||
openps
|
| mode_ `notElem` [Migrate, Open, Assign] = Nothing
|
||||||
| assign_ =
|
| otherwise = Just nulltransaction{tdate=opendate, tdescription=opendesc, tpostings=openps}
|
||||||
[ posting{paccount = a
|
where
|
||||||
,pamount = missingmixedamt
|
opendesc = T.pack $ fromMaybe defopendesc $ maybestringopt "open-desc" rawopts
|
||||||
,pbalanceassertion = Just nullassertion{baamount=b}
|
openps
|
||||||
-- case mcommoditysum of
|
| mode_ == Assign =
|
||||||
-- Just s -> Just nullassertion{baamount=precise s}
|
[ posting{paccount = a
|
||||||
-- Nothing -> Nothing
|
,pamount = missingmixedamt
|
||||||
}
|
,pbalanceassertion = Just nullassertion{baamount=b}
|
||||||
|
-- case mcommoditysum of
|
||||||
|
-- Just s -> Just nullassertion{baamount=precise s}
|
||||||
|
-- Nothing -> Nothing
|
||||||
|
}
|
||||||
|
|
||||||
| (a,mb) <- acctbals
|
| (a,mb) <- acctbals
|
||||||
, let bs0 = amounts mb
|
, let bs0 = amounts mb
|
||||||
-- mark the last balance in each commodity with the unpriced sum in that commodity (for a balance assertion)
|
-- 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)
|
, let bs2 = concat [reverse $ zip (reverse bs1) (Just commoditysum : repeat Nothing)
|
||||||
| bs1 <- groupBy ((==) `on` acommodity) bs0
|
| bs1 <- groupBy ((==) `on` acommodity) bs0
|
||||||
, let commoditysum = (sum bs1)]
|
, let commoditysum = (sum bs1)]
|
||||||
, (b, _mcommoditysum) <- bs2
|
, (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 =
|
| otherwise =
|
||||||
concat [
|
concat [
|
||||||
posting{paccount = a
|
posting{paccount = a
|
||||||
,pamount = mixedAmount $ precise b
|
,pamount = mixedAmount $ precise b
|
||||||
,pbalanceassertion =
|
,pbalanceassertion =
|
||||||
case mcommoditysum of
|
case mcommoditysum of
|
||||||
Just s -> Just nullassertion{baamount=precise s{aprice=Nothing}}
|
Just s -> Just nullassertion{baamount=precise s{aprice=Nothing}}
|
||||||
Nothing -> Nothing
|
Nothing -> Nothing
|
||||||
}
|
}
|
||||||
: [posting{paccount=openacct, pamount=mixedAmount . precise $ negate b} | interleaved]
|
: [posting{paccount=openacct, pamount=mixedAmount . precise $ negate b} | interleaved]
|
||||||
|
|
||||||
| (a,mb) <- acctbals
|
| (a,mb) <- acctbals
|
||||||
, let bs0 = amounts mb
|
, let bs0 = amounts mb
|
||||||
-- mark the last balance in each commodity with the unpriced sum in that commodity (for a balance assertion)
|
-- 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)
|
, let bs2 = concat [reverse $ zip (reverse bs1) (Just commoditysum : repeat Nothing)
|
||||||
| bs1 <- groupBy ((==) `on` acommodity) bs0
|
| bs1 <- groupBy ((==) `on` acommodity) bs0
|
||||||
, let commoditysum = (sum bs1)]
|
, let commoditysum = (sum bs1)]
|
||||||
, (b, mcommoditysum) <- bs2
|
, (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]
|
||||||
|
|
||||||
-- print them
|
-- print them
|
||||||
when (close_ || assert_) . T.putStr $ showTransaction closetxn
|
maybe (pure ()) (T.putStr . showTransaction) mclosetxn
|
||||||
when (open_ || assign_) . T.putStr $ showTransaction opentxn
|
maybe (pure ()) (T.putStr . showTransaction) mopentxn
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user