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.Functor (Functor(..))
14 import Data.List ((++), replicate)
15 import Data.Maybe (Maybe(..))
16 import Data.Monoid (Monoid(..), (<>))
17 import Data.String (String)
18 import Data.Tuple (snd)
19 import Prelude (($), (.), FilePath, IO, flip, unlines)
20 import Text.Show (Show(..))
21 import System.Console.GetOpt
25 import System.Environment as Env (getProgName)
26 import System.Exit (exitSuccess)
27 import qualified System.IO as IO
29 import Hcompta.Chart (Chart)
30 import qualified Hcompta.CLI.Args as Args
31 import qualified Hcompta.CLI.Context as Context
32 import qualified Hcompta.CLI.Format.Ledger as CLI.Ledger
33 import qualified Hcompta.CLI.Write as Write
34 -- import qualified Hcompta.Date as Date
35 import qualified Hcompta.Filter as Filter
36 import qualified Hcompta.Filter.Read as Filter.Read
37 -- import qualified Hcompta.Filter.Reduce as Filter.Reduce
38 import qualified Hcompta.Format.Ledger as Ledger
39 import qualified Hcompta.Format.Ledger.Journal as Ledger.Journal
40 import qualified Hcompta.Format.Ledger.Read as Ledger.Read
41 import qualified Hcompta.Format.Ledger.Write as Ledger.Write
42 import qualified Hcompta.Lib.Leijen as W
43 import qualified Hcompta.Journal as Journal
47 { ctx_input :: [FilePath]
49 , ctx_reduce_date :: Bool
50 , ctx_filter_transaction :: Filter.Simplified
52 (Filter.Filter_Transaction
53 (Chart, Ledger.Transaction)))
61 , ctx_reduce_date = True
62 , ctx_filter_transaction = mempty
67 bin <- Env.getProgName
68 let pad = replicate (length bin) ' '
71 , " "++bin++" journal [-i FILE_JOURNAL]"
72 , " "++pad++" [-t FILTER_TRANSACTION]"
73 , " "++pad++" [FILE_JOURNAL] [...]"
75 , usageInfo "OPTIONS" options
78 options :: Args.Options Ctx
81 (NoArg (\_context _ctx -> do
82 usage >>= IO.hPutStr IO.stderr
85 , Option "i" ["input"]
86 (ReqArg (\s _context ctx -> do
87 return $ ctx{ctx_input=s:ctx_input ctx}) "FILE")
88 "read data from given file, multiple uses merge the data as would a concatenation do"
90 (OptArg (\arg context ctx -> do
91 ctx_align <- case arg of
92 Nothing -> return $ True
93 Just "yes" -> return $ True
94 Just "no" -> return $ False
95 Just _ -> Write.fatal context $
96 W.text "--align option expects \"yes\", or \"no\" as value"
97 return $ ctx{ctx_align})
100 {- NOTE: not used so far.
101 , Option "" ["reduce-date"]
102 (OptArg (\arg context ctx -> do
103 ctx_reduce_date <- case arg of
104 Nothing -> return $ True
105 Just "yes" -> return $ True
106 Just "no" -> return $ False
107 Just _ -> Write.fatal context $
108 W.text "--reduce-date option expects \"yes\", or \"no\" as value"
109 return $ ctx{ctx_reduce_date})
111 "use advanced date reducer to speed up filtering"
113 , Option "t" ["transaction-filter"]
114 (ReqArg (\s context ctx -> do
115 ctx_filter_transaction <-
116 liftM ((ctx_filter_transaction ctx <>) . Filter.simplify) $
117 liftIO $ Filter.Read.read Filter.Read.filter_transaction s
119 Left ko -> Write.fatal context $ ko
121 Write.debug context $ "filter: transaction: " ++ show ok
123 return $ ctx{ctx_filter_transaction}) "FILTER_TRANSACTION")
124 "filter at transaction level, multiple uses are merged with a logical AND"
127 run :: Context.Context -> [String] -> IO ()
128 run context args = do
129 (ctx, inputs) <- Args.parse context usage options (nil, args)
131 liftM Data.Either.partitionEithers $ do
132 CLI.Ledger.paths context $ ctx_input ctx ++ inputs
135 liftIO $ runExceptT $ Ledger.Read.file
136 (Ledger.Read.context (ctx_filter_transaction ctx) Ledger.journal)
139 Left ko -> return $ Left (path, ko)
140 Right ok -> return $ Right ok
141 case read_journals of
142 (errs@(_:_), _journals) ->
143 forM_ errs $ \(_path, err) -> do
144 Write.fatal context $ err
146 Write.debug context $ "filter: transaction: " ++ show (ctx_filter_transaction ctx)
147 {- NOTE: not used so far
149 if ctx_reduce_date ctx
150 then Filter.Reduce.bool_date <$> ctx_filter_transaction ctx
152 Write.debug context $ "filter: transaction: reducer: " ++ show reducer_date
154 style_color <- Write.with_color context IO.stdout
155 let sty = Ledger.Write.Style
156 { Ledger.Write.style_align = ctx_align ctx
157 , Ledger.Write.style_color
159 let (_chart, journal) = ledger_journal ctx $ journals
160 Ledger.Write.put sty IO.stdout $ do
161 Ledger.Write.transactions $ fmap snd journal
165 -> [ Ledger.Journal (Journal.Journal (Chart, Ledger.Transaction)) ]
166 -> (Chart, Journal.Journal (Chart, Ledger.Transaction))
167 ledger_journal _ctx =
171 (Ledger.journal_chart j,) $
174 { Ledger.journal_sections=t