{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module Hledger.Cli.Commands.Print (
printmode
,print'
,originalTransaction
)
where
import Data.Maybe (isJust)
import Data.Text (Text)
import Data.List (intercalate)
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import System.Console.CmdArgs.Explicit
import Hledger.Read.CsvReader (CSV, printCSV)
import Hledger
import Hledger.Cli.CliOptions
import Hledger.Cli.Utils
import Hledger.Cli.Commands.Add ( transactionsSimilarTo )
printmode = hledgerCommandMode
$(embedFileRelative "Hledger/Cli/Commands/Print.txt")
([let arg = "STR" in
flagReq ["match","m"] (\s opts -> Right $ setopt "match" s opts) arg
("show the transaction whose description is most similar to "++arg++", and is most recent")
,flagNone ["explicit","x"] (setboolopt "explicit")
"show all amounts explicitly"
,flagNone ["new"] (setboolopt "new")
"show only newer-dated transactions added in each file since last run"
,outputFormatFlag ["txt","csv","json","sql"]
,outputFileFlag
])
[generalflagsgroup1]
hiddenflags
([], Just $ argsFlag "[QUERY]")
print' :: CliOpts -> Journal -> IO ()
print' opts j = do
case maybestringopt "match" $ rawopts_ opts of
Nothing -> printEntries opts j
Just desc -> printMatch opts j $ T.pack desc
printEntries :: CliOpts -> Journal -> IO ()
printEntries opts@CliOpts{reportopts_=ropts} j = do
d <- getCurrentDay
let q = queryFromOpts d ropts
fmt = outputFormatFromOpts opts
render = case fmt of
"txt" -> entriesReportAsText opts
"csv" -> (++"\n") . printCSV . entriesReportAsCsv
"json" -> (++"\n") . TL.unpack . toJsonText
"sql" -> entriesReportAsSql
_ -> const $ error' $ unsupportedOutputFormatError fmt
writeOutput opts $ render $ entriesReport ropts q j
entriesReportAsText :: CliOpts -> EntriesReport -> String
entriesReportAsText opts = concatMap (showTransaction . whichtxn)
where
whichtxn
| boolopt "explicit" (rawopts_ opts)
|| (isJust $ value_ $ reportopts_ opts) = id
| otherwise = originalTransaction
originalTransaction t = t { tpostings = map originalPostingPreservingAccount $ tpostings t }
originalPostingPreservingAccount p = (originalPosting p) { paccount = paccount p }
entriesReportAsSql :: EntriesReport -> String
entriesReportAsSql txns =
"create table if not exists postings(id serial,txnidx int,date1 date,date2 date,status text,code text,description text,comment text,account text,amount numeric,commodity text,credit numeric,debit numeric,posting_status text,posting_comment text);\n"++
"insert into postings(txnidx,date1,date2,status,code,description,comment,account,amount,commodity,credit,debit,posting_status,posting_comment) values\n"++
(intercalate "," (map values csv))
++";\n"
where
values vs = "(" ++ (intercalate "," $ map toSql vs) ++ ")\n"
toSql "" = "NULL"
toSql s = "'" ++ (concatMap quoteChar s) ++ "'"
quoteChar '\'' = "''"
quoteChar c = [c]
csv = concatMap transactionToCSV txns
entriesReportAsCsv :: EntriesReport -> CSV
entriesReportAsCsv txns =
["txnidx","date","date2","status","code","description","comment","account","amount","commodity","credit","debit","posting-status","posting-comment"] :
concatMap transactionToCSV txns
transactionToCSV :: Transaction -> CSV
transactionToCSV t =
map (\p -> show idx:date:date2:status:code:description:comment:p)
(concatMap postingToCSV $ tpostings t)
where
idx = tindex t
description = T.unpack $ tdescription t
date = showDate (tdate t)
date2 = maybe "" showDate (tdate2 t)
status = show $ tstatus t
code = T.unpack $ tcode t
comment = chomp $ strip $ T.unpack $ tcomment t
postingToCSV :: Posting -> CSV
postingToCSV p =
map (\(a@(Amount {aquantity=q,acommodity=c})) ->
let a_ = a{acommodity="",astyle=(astyle a){asdigitgroups=Nothing},aprice=Nothing} in
let amount = showAmount a_ in
let commodity = T.unpack c in
let credit = if q < 0 then showAmount $ negate a_ else "" in
let debit = if q >= 0 then showAmount a_ else "" in
[account, amount, commodity, credit, debit, status, comment])
amounts
where
Mixed amounts = pamount p
status = show $ pstatus p
account = showAccountName Nothing (ptype p) (paccount p)
comment = chomp $ strip $ T.unpack $ pcomment p
printMatch :: CliOpts -> Journal -> Text -> IO ()
printMatch CliOpts{reportopts_=ropts} j desc = do
d <- getCurrentDay
let q = queryFromOpts d ropts
case similarTransaction' j q desc of
Nothing -> putStrLn "no matches found."
Just t -> putStr $ showTransaction t
where
similarTransaction' :: Journal -> Query -> Text -> Maybe Transaction
similarTransaction' j q desc
| null historymatches = Nothing
| otherwise = Just $ snd $ head historymatches
where
historymatches = transactionsSimilarTo j q desc