{-# LANGUAGE CPP #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
module Hledger.Cli.Commands.Aregister (
aregistermode
,aregister
,tests_Aregister
) where
import Data.Aeson (toJSON)
import Data.Aeson.Text (encodeToLazyText)
import Data.List
import Data.Maybe
#if !(MIN_VERSION_base(4,11,0))
import Data.Semigroup ((<>))
#endif
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import Data.Time (addDays)
import Safe (headDef)
import System.Console.CmdArgs.Explicit
import Hledger.Read.CsvReader (CSV, CsvRecord, printCSV)
import Hledger
import Hledger.Cli.CliOptions
import Hledger.Cli.Utils
aregistermode :: Mode RawOpts
aregistermode = CommandDoc
-> [Flag RawOpts]
-> [(CommandDoc, [Flag RawOpts])]
-> [Flag RawOpts]
-> ([Arg RawOpts], Maybe (Arg RawOpts))
-> Mode RawOpts
hledgerCommandMode
$(embedFileRelative "Hledger/Cli/Commands/Aregister.txt")
([
[CommandDoc] -> (RawOpts -> RawOpts) -> CommandDoc -> Flag RawOpts
forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"txn-dates"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"txn-dates")
CommandDoc
"filter strictly by transaction date, not posting date. Warning: this can show a wrong running balance."
,[CommandDoc] -> (RawOpts -> RawOpts) -> CommandDoc -> Flag RawOpts
forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"no-elide"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"no-elide") CommandDoc
"don't show only 2 commodities per amount"
,[CommandDoc]
-> Update RawOpts -> CommandDoc -> CommandDoc -> Flag RawOpts
forall a.
[CommandDoc] -> Update a -> CommandDoc -> CommandDoc -> Flag a
flagReq [CommandDoc
"width",CommandDoc
"w"] (\CommandDoc
s RawOpts
opts -> RawOpts -> Either CommandDoc RawOpts
forall a b. b -> Either a b
Right (RawOpts -> Either CommandDoc RawOpts)
-> RawOpts -> Either CommandDoc RawOpts
forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc -> RawOpts -> RawOpts
setopt CommandDoc
"width" CommandDoc
s RawOpts
opts) CommandDoc
"N"
(CommandDoc
"set output width (default: " CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++
#ifdef mingw32_HOST_OS
show defaultWidth
#else
CommandDoc
"terminal width"
#endif
CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++ CommandDoc
" or $COLUMNS). -wN,M sets description width as well."
)
,[CommandDoc] -> Flag RawOpts
outputFormatFlag [CommandDoc
"txt",CommandDoc
"csv",CommandDoc
"json"]
,Flag RawOpts
outputFileFlag
])
[(CommandDoc, [Flag RawOpts])
generalflagsgroup1]
[Flag RawOpts]
hiddenflags
([], Arg RawOpts -> Maybe (Arg RawOpts)
forall a. a -> Maybe a
Just (Arg RawOpts -> Maybe (Arg RawOpts))
-> Arg RawOpts -> Maybe (Arg RawOpts)
forall a b. (a -> b) -> a -> b
$ CommandDoc -> Arg RawOpts
argsFlag CommandDoc
"ACCTPAT [QUERY]")
aregister :: CliOpts -> Journal -> IO ()
aregister :: CliOpts -> Journal -> IO ()
aregister opts :: CliOpts
opts@CliOpts{rawopts_ :: CliOpts -> RawOpts
rawopts_=RawOpts
rawopts,reportspec_ :: CliOpts -> ReportSpec
reportspec_=ReportSpec
rspec} Journal
j = do
Day
d <- IO Day
getCurrentDay
(CommandDoc
apat,[Text]
querystring) <- case CommandDoc -> RawOpts -> [CommandDoc]
listofstringopt CommandDoc
"args" RawOpts
rawopts of
[] -> CommandDoc -> IO (CommandDoc, [Text])
forall (m :: * -> *) a. MonadFail m => CommandDoc -> m a
fail CommandDoc
"aregister needs an account, please provide an account name or pattern"
(CommandDoc
a:[CommandDoc]
as) -> (CommandDoc, [Text]) -> IO (CommandDoc, [Text])
forall (m :: * -> *) a. Monad m => a -> m a
return (CommandDoc
a, (CommandDoc -> Text) -> [CommandDoc] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map CommandDoc -> Text
T.pack [CommandDoc]
as)
Query
argsquery <- (CommandDoc -> IO Query)
-> ((Query, [QueryOpt]) -> IO Query)
-> Either CommandDoc (Query, [QueryOpt])
-> IO Query
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either CommandDoc -> IO Query
forall (m :: * -> *) a. MonadFail m => CommandDoc -> m a
fail (Query -> IO Query
forall (m :: * -> *) a. Monad m => a -> m a
return (Query -> IO Query)
-> ((Query, [QueryOpt]) -> Query)
-> (Query, [QueryOpt])
-> IO Query
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Query, [QueryOpt]) -> Query
forall a b. (a, b) -> a
fst) (Either CommandDoc (Query, [QueryOpt]) -> IO Query)
-> Either CommandDoc (Query, [QueryOpt]) -> IO Query
forall a b. (a -> b) -> a -> b
$ Day -> [Text] -> Either CommandDoc (Query, [QueryOpt])
parseQueryList Day
d [Text]
querystring
let
acct :: Text
acct = Text -> [Text] -> Text
forall a. a -> [a] -> a
headDef (CommandDoc -> Text
forall a. CommandDoc -> a
error' (CommandDoc -> Text) -> CommandDoc -> Text
forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc
forall a. Show a => a -> CommandDoc
show CommandDoc
apatCommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
" did not match any account")
([Text] -> Text) -> ([Text] -> [Text]) -> [Text] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> [Text]
filterAccts ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ Journal -> [Text]
journalAccountNames Journal
j
filterAccts :: [Text] -> [Text]
filterAccts = case CommandDoc -> Either CommandDoc Regexp
toRegexCI CommandDoc
apat of
Right Regexp
re -> (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
filter (Regexp -> CommandDoc -> Bool
regexMatch Regexp
re (CommandDoc -> Bool) -> (Text -> CommandDoc) -> Text -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> CommandDoc
T.unpack)
Left CommandDoc
_ -> [Text] -> [Text] -> [Text]
forall a b. a -> b -> a
const []
inclusive :: Bool
inclusive = Bool
True
thisacctq :: Query
thisacctq = Regexp -> Query
Acct (Regexp -> Query) -> Regexp -> Query
forall a b. (a -> b) -> a -> b
$ (if Bool
inclusive then Text -> Regexp
accountNameToAccountRegex else Text -> Regexp
accountNameToAccountOnlyRegex) Text
acct
ropts' :: ReportOpts
ropts' = (ReportSpec -> ReportOpts
rsOpts ReportSpec
rspec) {
depth_ :: Maybe Int
depth_=Maybe Int
forall a. Maybe a
Nothing
, balancetype_ :: BalanceType
balancetype_= BalanceType
HistoricalBalance
}
rspec' :: ReportSpec
rspec' = ReportSpec
rspec{ rsQuery :: Query
rsQuery=Query -> Query
simplifyQuery (Query -> Query) -> Query -> Query
forall a b. (a -> b) -> a -> b
$ [Query] -> Query
And [ReportOpts -> Query
queryFromFlags ReportOpts
ropts', Query
argsquery]
, rsOpts :: ReportOpts
rsOpts=ReportOpts
ropts'
}
reportq :: Query
reportq = [Query] -> Query
And [ReportSpec -> Query
rsQuery ReportSpec
rspec', Bool -> Query
excludeforecastq (Maybe DateSpan -> Bool
forall a. Maybe a -> Bool
isJust (Maybe DateSpan -> Bool) -> Maybe DateSpan -> Bool
forall a b. (a -> b) -> a -> b
$ ReportOpts -> Maybe DateSpan
forecast_ ReportOpts
ropts')]
where
excludeforecastq :: Bool -> Query
excludeforecastq Bool
True = Query
Any
excludeforecastq Bool
False =
[Query] -> Query
And [
Query -> Query
Not (DateSpan -> Query
Date (DateSpan -> Query) -> DateSpan -> Query
forall a b. (a -> b) -> a -> b
$ Maybe Day -> Maybe Day -> DateSpan
DateSpan (Day -> Maybe Day
forall a. a -> Maybe a
Just (Day -> Maybe Day) -> Day -> Maybe Day
forall a b. (a -> b) -> a -> b
$ Integer -> Day -> Day
addDays Integer
1 Day
d) Maybe Day
forall a. Maybe a
Nothing)
,Query -> Query
Not Query
generatedTransactionTag
]
(CommandDoc
balancelabel,[AccountTransactionsReportItem]
items) = ReportSpec
-> Journal
-> Query
-> Query
-> (CommandDoc, [AccountTransactionsReportItem])
accountTransactionsReport ReportSpec
rspec' Journal
j Query
reportq Query
thisacctq
items' :: [AccountTransactionsReportItem]
items' = (if ReportOpts -> Bool
empty_ ReportOpts
ropts' then [AccountTransactionsReportItem] -> [AccountTransactionsReportItem]
forall a. a -> a
id else (AccountTransactionsReportItem -> Bool)
-> [AccountTransactionsReportItem]
-> [AccountTransactionsReportItem]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool)
-> (AccountTransactionsReportItem -> Bool)
-> AccountTransactionsReportItem
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MixedAmount -> Bool
mixedAmountLooksZero (MixedAmount -> Bool)
-> (AccountTransactionsReportItem -> MixedAmount)
-> AccountTransactionsReportItem
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AccountTransactionsReportItem -> MixedAmount
forall a b c d e f. (a, b, c, d, e, f) -> e
fifth6)) ([AccountTransactionsReportItem]
-> [AccountTransactionsReportItem])
-> [AccountTransactionsReportItem]
-> [AccountTransactionsReportItem]
forall a b. (a -> b) -> a -> b
$
[AccountTransactionsReportItem] -> [AccountTransactionsReportItem]
forall a. [a] -> [a]
reverse [AccountTransactionsReportItem]
items
render :: (CommandDoc, [AccountTransactionsReportItem]) -> CommandDoc
render | CommandDoc
fmtCommandDoc -> CommandDoc -> Bool
forall a. Eq a => a -> a -> Bool
==CommandDoc
"json" = (CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
"\n") (CommandDoc -> CommandDoc)
-> ((CommandDoc, [AccountTransactionsReportItem]) -> CommandDoc)
-> (CommandDoc, [AccountTransactionsReportItem])
-> CommandDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> CommandDoc
T.unpack (Text -> CommandDoc)
-> ((CommandDoc, [AccountTransactionsReportItem]) -> Text)
-> (CommandDoc, [AccountTransactionsReportItem])
-> CommandDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
TL.toStrict (Text -> Text)
-> ((CommandDoc, [AccountTransactionsReportItem]) -> Text)
-> (CommandDoc, [AccountTransactionsReportItem])
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> Text
forall a. ToJSON a => a -> Text
encodeToLazyText (Value -> Text)
-> ((CommandDoc, [AccountTransactionsReportItem]) -> Value)
-> (CommandDoc, [AccountTransactionsReportItem])
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CommandDoc, [AccountTransactionsReportItem]) -> Value
forall a. ToJSON a => a -> Value
toJSON
| CommandDoc
fmtCommandDoc -> CommandDoc -> Bool
forall a. Eq a => a -> a -> Bool
==CommandDoc
"csv" = (CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
"\n") (CommandDoc -> CommandDoc)
-> ((CommandDoc, [AccountTransactionsReportItem]) -> CommandDoc)
-> (CommandDoc, [AccountTransactionsReportItem])
-> CommandDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CSV -> CommandDoc
printCSV (CSV -> CommandDoc)
-> ((CommandDoc, [AccountTransactionsReportItem]) -> CSV)
-> (CommandDoc, [AccountTransactionsReportItem])
-> CommandDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Query
-> Query -> (CommandDoc, [AccountTransactionsReportItem]) -> CSV
accountTransactionsReportAsCsv Query
reportq Query
thisacctq
| CommandDoc
fmtCommandDoc -> CommandDoc -> Bool
forall a. Eq a => a -> a -> Bool
==CommandDoc
"txt" = CliOpts
-> Query
-> Query
-> (CommandDoc, [AccountTransactionsReportItem])
-> CommandDoc
accountTransactionsReportAsText CliOpts
opts Query
reportq Query
thisacctq
| Bool
otherwise = CommandDoc
-> (CommandDoc, [AccountTransactionsReportItem]) -> CommandDoc
forall a b. a -> b -> a
const (CommandDoc
-> (CommandDoc, [AccountTransactionsReportItem]) -> CommandDoc)
-> CommandDoc
-> (CommandDoc, [AccountTransactionsReportItem])
-> CommandDoc
forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc
forall a. CommandDoc -> a
error' (CommandDoc -> CommandDoc) -> CommandDoc -> CommandDoc
forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc
unsupportedOutputFormatError CommandDoc
fmt
where
fmt :: CommandDoc
fmt = CliOpts -> CommandDoc
outputFormatFromOpts CliOpts
opts
CliOpts -> CommandDoc -> IO ()
writeOutput CliOpts
opts (CommandDoc -> IO ()) -> CommandDoc -> IO ()
forall a b. (a -> b) -> a -> b
$ (CommandDoc, [AccountTransactionsReportItem]) -> CommandDoc
render (CommandDoc
balancelabel,[AccountTransactionsReportItem]
items')
accountTransactionsReportAsCsv :: Query -> Query -> AccountTransactionsReport -> CSV
accountTransactionsReportAsCsv :: Query
-> Query -> (CommandDoc, [AccountTransactionsReportItem]) -> CSV
accountTransactionsReportAsCsv Query
reportq Query
thisacctq (CommandDoc
_,[AccountTransactionsReportItem]
is) =
[CommandDoc
"txnidx",CommandDoc
"date",CommandDoc
"code",CommandDoc
"description",CommandDoc
"otheraccounts",CommandDoc
"change",CommandDoc
"balance"]
[CommandDoc] -> CSV -> CSV
forall a. a -> [a] -> [a]
: (AccountTransactionsReportItem -> [CommandDoc])
-> [AccountTransactionsReportItem] -> CSV
forall a b. (a -> b) -> [a] -> [b]
map (Query -> Query -> AccountTransactionsReportItem -> [CommandDoc]
accountTransactionsReportItemAsCsvRecord Query
reportq Query
thisacctq) [AccountTransactionsReportItem]
is
accountTransactionsReportItemAsCsvRecord :: Query -> Query -> AccountTransactionsReportItem -> CsvRecord
accountTransactionsReportItemAsCsvRecord :: Query -> Query -> AccountTransactionsReportItem -> [CommandDoc]
accountTransactionsReportItemAsCsvRecord
Query
reportq Query
thisacctq
(t :: Transaction
t@Transaction{Integer
tindex :: Transaction -> Integer
tindex :: Integer
tindex,Text
tcode :: Transaction -> Text
tcode :: Text
tcode,Text
tdescription :: Transaction -> Text
tdescription :: Text
tdescription}, Transaction
_, Bool
_issplit, CommandDoc
otheracctsstr, MixedAmount
change, MixedAmount
balance)
= [CommandDoc
idx,CommandDoc
date,CommandDoc
code,CommandDoc
desc,CommandDoc
otheracctsstr,CommandDoc
amt,CommandDoc
bal]
where
idx :: CommandDoc
idx = Integer -> CommandDoc
forall a. Show a => a -> CommandDoc
show Integer
tindex
date :: CommandDoc
date = Day -> CommandDoc
showDate (Day -> CommandDoc) -> Day -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Query -> Query -> Transaction -> Day
transactionRegisterDate Query
reportq Query
thisacctq Transaction
t
code :: CommandDoc
code = Text -> CommandDoc
T.unpack Text
tcode
desc :: CommandDoc
desc = Text -> CommandDoc
T.unpack Text
tdescription
amt :: CommandDoc
amt = Bool -> MixedAmount -> CommandDoc
showMixedAmountOneLineWithoutPrice Bool
False MixedAmount
change
bal :: CommandDoc
bal = Bool -> MixedAmount -> CommandDoc
showMixedAmountOneLineWithoutPrice Bool
False MixedAmount
balance
accountTransactionsReportAsText :: CliOpts -> Query -> Query -> AccountTransactionsReport -> String
accountTransactionsReportAsText :: CliOpts
-> Query
-> Query
-> (CommandDoc, [AccountTransactionsReportItem])
-> CommandDoc
accountTransactionsReportAsText
copts :: CliOpts
copts@CliOpts{reportspec_ :: CliOpts -> ReportSpec
reportspec_=ReportSpec{rsOpts :: ReportSpec -> ReportOpts
rsOpts=ReportOpts{Bool
no_elide_ :: ReportOpts -> Bool
no_elide_ :: Bool
no_elide_}}} Query
reportq Query
thisacctq (CommandDoc
_balancelabel,[AccountTransactionsReportItem]
items)
= [CommandDoc] -> CommandDoc
unlines ([CommandDoc] -> CommandDoc) -> [CommandDoc] -> CommandDoc
forall a b. (a -> b) -> a -> b
$ CommandDoc
title CommandDoc -> [CommandDoc] -> [CommandDoc]
forall a. a -> [a] -> [a]
:
(AccountTransactionsReportItem -> CommandDoc)
-> [AccountTransactionsReportItem] -> [CommandDoc]
forall a b. (a -> b) -> [a] -> [b]
map (CliOpts
-> Query
-> Query
-> Int
-> Int
-> AccountTransactionsReportItem
-> CommandDoc
accountTransactionsReportItemAsText CliOpts
copts Query
reportq Query
thisacctq Int
amtwidth Int
balwidth) [AccountTransactionsReportItem]
items
where
amtwidth :: Int
amtwidth = [Int] -> Int
forall a. Ord a => [a] -> a
maximumStrict ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ Int
12 Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: (AccountTransactionsReportItem -> Int)
-> [AccountTransactionsReportItem] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map ((CommandDoc, Int) -> Int
forall a b. (a, b) -> b
snd ((CommandDoc, Int) -> Int)
-> (AccountTransactionsReportItem -> (CommandDoc, Int))
-> AccountTransactionsReportItem
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MixedAmount -> (CommandDoc, Int)
showamt (MixedAmount -> (CommandDoc, Int))
-> (AccountTransactionsReportItem -> MixedAmount)
-> AccountTransactionsReportItem
-> (CommandDoc, Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AccountTransactionsReportItem -> MixedAmount
forall a b c d e f. (a, b, c, d, e, f) -> e
itemamt) [AccountTransactionsReportItem]
items
balwidth :: Int
balwidth = [Int] -> Int
forall a. Ord a => [a] -> a
maximumStrict ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ Int
12 Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: (AccountTransactionsReportItem -> Int)
-> [AccountTransactionsReportItem] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map ((CommandDoc, Int) -> Int
forall a b. (a, b) -> b
snd ((CommandDoc, Int) -> Int)
-> (AccountTransactionsReportItem -> (CommandDoc, Int))
-> AccountTransactionsReportItem
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MixedAmount -> (CommandDoc, Int)
showamt (MixedAmount -> (CommandDoc, Int))
-> (AccountTransactionsReportItem -> MixedAmount)
-> AccountTransactionsReportItem
-> (CommandDoc, Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AccountTransactionsReportItem -> MixedAmount
forall a b c d e f. (a, b, c, d, e, f) -> f
itembal) [AccountTransactionsReportItem]
items
showamt :: MixedAmount -> (CommandDoc, Int)
showamt = (Amount -> CommandDoc)
-> Maybe Int
-> Maybe Int
-> Bool
-> MixedAmount
-> (CommandDoc, Int)
showMixedOneLine Amount -> CommandDoc
showAmountWithoutPrice (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
12) Maybe Int
mmax Bool
False
where mmax :: Maybe Int
mmax = if Bool
no_elide_ then Maybe Int
forall a. Maybe a
Nothing else Int -> Maybe Int
forall a. a -> Maybe a
Just Int
32
itemamt :: (a, b, c, d, e, f) -> e
itemamt (a
_,b
_,c
_,d
_,e
a,f
_) = e
a
itembal :: (a, b, c, d, e, f) -> f
itembal (a
_,b
_,c
_,d
_,e
_,f
a) = f
a
title :: CommandDoc
title = Text -> CommandDoc
T.unpack (Text -> CommandDoc) -> Text -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Text -> (Text -> Text) -> Maybe Text -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"" ((Text
"Transactions in "Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>)(Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>Text
" and subaccounts:")) Maybe Text
macct
where
macct :: Maybe Text
macct = case (Query -> Bool) -> Query -> Query
filterQuery Query -> Bool
queryIsAcct Query
thisacctq of
Acct Regexp
r -> Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text)
-> (CommandDoc -> Text) -> CommandDoc -> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Text -> Text
T.drop Int
1 (Text -> Text) -> (CommandDoc -> Text) -> CommandDoc -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Text -> Text
T.dropEnd Int
5 (Text -> Text) -> (CommandDoc -> Text) -> CommandDoc -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CommandDoc -> Text
T.pack (CommandDoc -> Maybe Text) -> CommandDoc -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Regexp -> CommandDoc
reString Regexp
r
Query
_ -> Maybe Text
forall a. Maybe a
Nothing
accountTransactionsReportItemAsText :: CliOpts -> Query -> Query -> Int -> Int -> AccountTransactionsReportItem -> String
accountTransactionsReportItemAsText :: CliOpts
-> Query
-> Query
-> Int
-> Int
-> AccountTransactionsReportItem
-> CommandDoc
accountTransactionsReportItemAsText
copts :: CliOpts
copts@CliOpts{reportspec_ :: CliOpts -> ReportSpec
reportspec_=ReportSpec{rsOpts :: ReportSpec -> ReportOpts
rsOpts=ReportOpts{Bool
color_ :: ReportOpts -> Bool
color_ :: Bool
color_}}}
Query
reportq Query
thisacctq Int
preferredamtwidth Int
preferredbalwidth
(t :: Transaction
t@Transaction{Text
tdescription :: Text
tdescription :: Transaction -> Text
tdescription}, Transaction
_, Bool
_issplit, CommandDoc
otheracctsstr, MixedAmount
change, MixedAmount
balance)
= CommandDoc -> [CommandDoc] -> CommandDoc
forall a. [a] -> [[a]] -> [a]
intercalate CommandDoc
"\n" ([CommandDoc] -> CommandDoc) -> [CommandDoc] -> CommandDoc
forall a b. (a -> b) -> a -> b
$
[CommandDoc] -> CommandDoc
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [Maybe Int -> Maybe Int -> Bool -> Bool -> CommandDoc -> CommandDoc
fitString (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
datewidth) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
datewidth) Bool
True Bool
True CommandDoc
date
,CommandDoc
" "
,Maybe Int -> Maybe Int -> Bool -> Bool -> CommandDoc -> CommandDoc
fitString (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
descwidth) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
descwidth) Bool
True Bool
True CommandDoc
desc
,CommandDoc
" "
,Maybe Int -> Maybe Int -> Bool -> Bool -> CommandDoc -> CommandDoc
fitString (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
acctwidth) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
acctwidth) Bool
True Bool
True CommandDoc
accts
,CommandDoc
" "
,CommandDoc
amtfirstline
,CommandDoc
" "
,CommandDoc
balfirstline
]
CommandDoc -> [CommandDoc] -> [CommandDoc]
forall a. a -> [a] -> [a]
:
[[CommandDoc] -> CommandDoc
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [CommandDoc
spacer
,CommandDoc
a
,CommandDoc
" "
,CommandDoc
b
]
| (CommandDoc
a,CommandDoc
b) <- [CommandDoc] -> [CommandDoc] -> [(CommandDoc, CommandDoc)]
forall a b. [a] -> [b] -> [(a, b)]
zip [CommandDoc]
amtrest [CommandDoc]
balrest
]
where
(Int
totalwidth,Maybe Int
mdescwidth) = CliOpts -> (Int, Maybe Int)
registerWidthsFromOpts CliOpts
copts
(Int
datewidth, CommandDoc
date) = (Int
10, Day -> CommandDoc
showDate (Day -> CommandDoc) -> Day -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Query -> Query -> Transaction -> Day
transactionRegisterDate Query
reportq Query
thisacctq Transaction
t)
(Int
amtwidth, Int
balwidth)
| Int
shortfall Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = (Int
preferredamtwidth, Int
preferredbalwidth)
| Bool
otherwise = (Int
adjustedamtwidth, Int
adjustedbalwidth)
where
mincolwidth :: Int
mincolwidth = Int
2
maxamtswidth :: Int
maxamtswidth = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int
totalwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
- (Int
datewidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
mincolwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
mincolwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2))
shortfall :: Int
shortfall = (Int
preferredamtwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
preferredbalwidth) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
maxamtswidth
amtwidthproportion :: Double
amtwidthproportion = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
preferredamtwidth Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
preferredamtwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
preferredbalwidth)
adjustedamtwidth :: Int
adjustedamtwidth = Double -> Int
forall a b. (RealFrac a, Integral b) => a -> b
round (Double -> Int) -> Double -> Int
forall a b. (a -> b) -> a -> b
$ Double
amtwidthproportion Double -> Double -> Double
forall a. Num a => a -> a -> a
* Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
maxamtswidth
adjustedbalwidth :: Int
adjustedbalwidth = Int
maxamtswidth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
adjustedamtwidth
remaining :: Int
remaining = Int
totalwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
- (Int
datewidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
amtwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
balwidth)
(Int
descwidth, Int
acctwidth) = (Int
w, Int
remaining Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
w)
where
w :: Int
w = Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe ((Int
remaining Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2) Maybe Int
mdescwidth
desc :: CommandDoc
desc = Text -> CommandDoc
T.unpack Text
tdescription
accts :: CommandDoc
accts =
CommandDoc
otheracctsstr
amt :: CommandDoc
amt = (CommandDoc, Int) -> CommandDoc
forall a b. (a, b) -> a
fst ((CommandDoc, Int) -> CommandDoc)
-> (CommandDoc, Int) -> CommandDoc
forall a b. (a -> b) -> a -> b
$ (Amount -> CommandDoc)
-> Maybe Int
-> Maybe Int
-> Bool
-> MixedAmount
-> (CommandDoc, Int)
showMixed Amount -> CommandDoc
showAmountWithoutPrice (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
amtwidth) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
balwidth) Bool
color_ MixedAmount
change
bal :: CommandDoc
bal = (CommandDoc, Int) -> CommandDoc
forall a b. (a, b) -> a
fst ((CommandDoc, Int) -> CommandDoc)
-> (CommandDoc, Int) -> CommandDoc
forall a b. (a -> b) -> a -> b
$ (Amount -> CommandDoc)
-> Maybe Int
-> Maybe Int
-> Bool
-> MixedAmount
-> (CommandDoc, Int)
showMixed Amount -> CommandDoc
showAmountWithoutPrice (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
balwidth) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
balwidth) Bool
color_ MixedAmount
balance
([CommandDoc]
amtlines, [CommandDoc]
ballines) = (CommandDoc -> [CommandDoc]
lines CommandDoc
amt, CommandDoc -> [CommandDoc]
lines CommandDoc
bal)
(Int
amtlen, Int
ballen) = ([CommandDoc] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [CommandDoc]
amtlines, [CommandDoc] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [CommandDoc]
ballines)
numlines :: Int
numlines = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
amtlen Int
ballen)
(CommandDoc
amtfirstline:[CommandDoc]
amtrest) = Int -> [CommandDoc] -> [CommandDoc]
forall a. Int -> [a] -> [a]
take Int
numlines ([CommandDoc] -> [CommandDoc]) -> [CommandDoc] -> [CommandDoc]
forall a b. (a -> b) -> a -> b
$ [CommandDoc]
amtlines [CommandDoc] -> [CommandDoc] -> [CommandDoc]
forall a. [a] -> [a] -> [a]
++ CommandDoc -> [CommandDoc]
forall a. a -> [a]
repeat (Int -> Char -> CommandDoc
forall a. Int -> a -> [a]
replicate Int
amtwidth Char
' ')
(CommandDoc
balfirstline:[CommandDoc]
balrest) = Int -> [CommandDoc] -> [CommandDoc]
forall a. Int -> [a] -> [a]
take Int
numlines ([CommandDoc] -> [CommandDoc]) -> [CommandDoc] -> [CommandDoc]
forall a b. (a -> b) -> a -> b
$ Int -> CommandDoc -> [CommandDoc]
forall a. Int -> a -> [a]
replicate (Int
numlines Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
ballen) (Int -> Char -> CommandDoc
forall a. Int -> a -> [a]
replicate Int
balwidth Char
' ') [CommandDoc] -> [CommandDoc] -> [CommandDoc]
forall a. [a] -> [a] -> [a]
++ [CommandDoc]
ballines
spacer :: CommandDoc
spacer = Int -> Char -> CommandDoc
forall a. Int -> a -> [a]
replicate (Int
totalwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
- (Int
amtwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
balwidth)) Char
' '
tests_Aregister :: TestTree
tests_Aregister = CommandDoc -> [TestTree] -> TestTree
tests CommandDoc
"Aregister" [
]