1 {-# LANGUAGE NamedFieldPuns #-}
2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE ScopedTypeVariables #-}
4 {-# LANGUAGE TupleSections #-}
5 module Hcompta.CLI.Command.Journal where
7 import Control.Monad (Monad(..), forM_, liftM, mapM)
8 import Control.Monad.IO.Class (liftIO)
9 import Control.Monad.Trans.Except (runExceptT)
11 import Data.Either (Either(..), partitionEithers)
12 import Data.Foldable (Foldable(..))
13 import Data.List ((++), replicate)
14 import Data.Maybe (Maybe(..))
15 import Data.Monoid (Monoid(..), (<>))
16 import Data.String (String)
17 import Prelude (($), (.), FilePath, IO, flip, unlines)
18 import Text.Show (Show(..))
19 import System.Console.GetOpt
23 import System.Environment as Env (getProgName)
24 import System.Exit (exitSuccess)
25 import qualified System.IO as IO
27 import qualified Hcompta.CLI.Args as Args
28 import qualified Hcompta.CLI.Context as Context
29 import qualified Hcompta.CLI.Format.Ledger as CLI.Ledger
30 import qualified Hcompta.CLI.Write as Write
31 -- import qualified Hcompta.Date as Date
32 import qualified Hcompta.Filter as Filter
33 import qualified Hcompta.Filter.Read as Filter.Read
34 -- import qualified Hcompta.Filter.Reduce as Filter.Reduce
35 import qualified Hcompta.Format.Ledger as Ledger
36 import qualified Hcompta.Format.Ledger.Journal as Ledger.Journal
37 import qualified Hcompta.Format.Ledger.Read as Ledger.Read
38 import qualified Hcompta.Format.Ledger.Write as Ledger.Write
39 import qualified Hcompta.Lib.Leijen as W
40 import qualified Hcompta.Journal as Journal
44 { ctx_input :: [FilePath]
46 , ctx_reduce_date :: Bool
47 , ctx_filter_transaction :: Filter.Simplified
49 (Filter.Filter_Transaction
58 , ctx_reduce_date = True
59 , ctx_filter_transaction = mempty
64 bin <- Env.getProgName
65 let pad = replicate (length bin) ' '
68 , " "++bin++" journal [-i JOURNAL_FILE]"
69 , " "++pad++" [-t TRANSACTION_FILTER]"
70 , " "++pad++" [JOURNAL_FILE] [...]"
72 , usageInfo "OPTIONS" options
75 options :: Args.Options Ctx
78 (NoArg (\_context _ctx -> do
79 usage >>= IO.hPutStr IO.stderr
82 , Option "i" ["input"]
83 (ReqArg (\s _context ctx -> do
84 return $ ctx{ctx_input=s:ctx_input ctx}) "FILE")
85 "read data from given file, multiple uses merge the data as would a concatenation do"
87 (OptArg (\arg context ctx -> do
88 ctx_align <- case arg of
89 Nothing -> return $ True
90 Just "yes" -> return $ True
91 Just "no" -> return $ False
92 Just _ -> Write.fatal context $
93 W.text "--align option expects \"yes\", or \"no\" as value"
94 return $ ctx{ctx_align})
97 {- NOTE: not used so far.
98 , Option "" ["reduce-date"]
99 (OptArg (\arg context ctx -> do
100 ctx_reduce_date <- case arg of
101 Nothing -> return $ True
102 Just "yes" -> return $ True
103 Just "no" -> return $ False
104 Just _ -> Write.fatal context $
105 W.text "--reduce-date option expects \"yes\", or \"no\" as value"
106 return $ ctx{ctx_reduce_date})
108 "use advanced date reducer to speed up filtering"
110 , Option "t" ["transaction-filter"]
111 (ReqArg (\s context ctx -> do
112 ctx_filter_transaction <-
113 liftM ((ctx_filter_transaction ctx <>) . Filter.simplify) $
114 liftIO $ Filter.Read.read Filter.Read.filter_transaction s
116 Left ko -> Write.fatal context $ ko
118 Write.debug context $ "filter: transaction: " ++ show ok
120 return $ ctx{ctx_filter_transaction}) "FILTER")
121 "filter at transaction level, multiple uses are merged with a logical AND"
124 run :: Context.Context -> [String] -> IO ()
125 run context args = do
126 (ctx, inputs) <- Args.parse context usage options (nil, args)
128 liftM Data.Either.partitionEithers $ do
129 CLI.Ledger.paths context $ ctx_input ctx ++ inputs
132 liftIO $ runExceptT $ Ledger.Read.file
133 (Ledger.Read.context (ctx_filter_transaction ctx) Ledger.journal)
136 Left ko -> return $ Left (path, ko)
137 Right ok -> return $ Right ok
138 case read_journals of
139 (errs@(_:_), _journals) ->
140 forM_ errs $ \(_path, err) -> do
141 Write.fatal context $ err
143 Write.debug context $ "filter: transaction: " ++ show (ctx_filter_transaction ctx)
144 {- NOTE: not used so far
146 if ctx_reduce_date ctx
147 then Filter.Reduce.bool_date <$> ctx_filter_transaction ctx
149 Write.debug context $ "filter: transaction: reducer: " ++ show reducer_date
151 style_color <- Write.with_color context IO.stdout
152 let sty = Ledger.Write.Style
153 { Ledger.Write.style_align = ctx_align ctx
154 , Ledger.Write.style_color
156 let journal = ledger_journal ctx journals
157 Ledger.Write.put sty IO.stdout $ do
158 Ledger.Write.transactions journal
162 -> [ Ledger.Journal (Journal.Journal Ledger.Transaction) ]
163 -> Journal.Journal Ledger.Transaction
164 ledger_journal _ctx =
166 (flip $ Ledger.Journal.fold
167 (\Ledger.Journal{Ledger.journal_transactions=j} ->