1 {-# LANGUAGE ExistentialQuantification #-}
2 {-# LANGUAGE FlexibleContexts #-}
3 {-# LANGUAGE FlexibleInstances #-}
4 {-# LANGUAGE MultiParamTypeClasses #-}
5 {-# LANGUAGE NamedFieldPuns #-}
6 {-# LANGUAGE OverloadedStrings #-}
7 {-# LANGUAGE Rank2Types #-}
8 {-# LANGUAGE ScopedTypeVariables #-}
9 {-# LANGUAGE TupleSections #-}
10 {-# LANGUAGE TypeFamilies #-}
11 {-# OPTIONS_GHC -fno-warn-orphans #-}
12 module Hcompta.CLI.Command.GL where
14 import Control.Applicative (Const(..), (<$>))
15 import Control.Arrow (first, (+++))
16 import Control.Monad (Monad(..), liftM, mapM)
17 import Control.Monad.IO.Class (liftIO)
19 import Data.Decimal (Decimal)
20 import Data.Either (Either(..), partitionEithers)
21 import Data.Foldable (Foldable(..))
22 import Data.Function (($), (.), on, id, flip)
23 import Data.Functor (Functor(..))
24 import Data.List ((++), repeat)
25 import Data.Map.Strict (Map)
26 import qualified Data.Map.Strict as Map
27 import Data.Maybe (Maybe(..))
28 import Data.Monoid (Monoid(..))
30 import qualified Data.Sequence as Seq
31 import qualified Data.Strict.Maybe as Strict
32 import Data.String (String)
33 import Data.Text (Text)
34 import Prelude (Bounded(..), unlines, zipWith)
35 import System.Console.GetOpt
40 import System.Environment as Env (getProgName)
41 import System.Exit (exitSuccess)
42 import qualified System.IO as IO
43 import System.IO (FilePath, IO)
45 import qualified Hcompta.Account as Account
46 import qualified Hcompta.CLI.Args as Args
47 import qualified Hcompta.CLI.Context as C
48 import qualified Hcompta.CLI.Env as CLI.Env
49 import Hcompta.CLI.Format.Ledger ()
50 import Hcompta.CLI.Format.JCC ()
51 import qualified Hcompta.CLI.Lang as Lang
52 import qualified Hcompta.CLI.Lib.Leijen.Table as Leijen.Table
53 import qualified Hcompta.CLI.Write as Write
54 import qualified Hcompta.Chart as Chart
55 import Hcompta.Date (Date)
56 import qualified Hcompta.Filter as Filter
57 import qualified Hcompta.Filter.Read as Filter.Read
58 import qualified Hcompta.Format.JCC as JCC
59 import qualified Hcompta.Format.Ledger as Ledger
60 import qualified Hcompta.GL as GL
61 import Hcompta.Lib.Leijen (toDoc, ToDoc(..))
62 import qualified Hcompta.Lib.TreeMap as TreeMap
63 import Hcompta.Polarize (Polarized)
64 import qualified Hcompta.Polarize as Polarize
65 import qualified Hcompta.Posting as Posting
66 import qualified Hcompta.Filter.Amount as Filter.Amount
67 import Hcompta.CLI.Format (Format(..), Formats)
68 import qualified Hcompta.CLI.Format as Format
69 import qualified Hcompta.Lib.Leijen as W
70 import qualified Hcompta.Lib.Parsec as R
71 import qualified Hcompta.Unit as Unit
72 import qualified Hcompta.Quantity as Quantity
76 { ctx_filter_transaction :: forall t.
77 ( Filter.Transaction t
78 , Filter.Amount_Quantity
79 (Posting.Posting_Amount
80 (Filter.Transaction_Posting t))
81 ~ Filter.Amount.Quantity
82 ) => Filter.Simplified
84 (Filter.Filter_Transaction t))
85 , ctx_filter_gl :: forall b.
87 , Filter.Amount_Quantity
89 ~ Filter.Amount.Quantity
90 ) => Filter.Simplified
93 , ctx_input :: [FilePath]
94 , ctx_input_format :: Formats
95 , ctx_output :: [(Write.Mode, FilePath)]
96 , ctx_output_format :: Maybe Formats
98 -- , ctx_filter_gl :: Filter.Simplified
99 -- (Filter.Filter_Bool
101 -- ( (Account_Tags, Ledger.Account)
103 -- , (Ledger.Unit, Polarize.Polarized Ledger.Quantity)
104 -- , (Ledger.Unit, Polarize.Polarized Ledger.Quantity) )))
105 -- , ctx_filter_posting :: Filter.Simplified
106 -- (Filter.Filter_Bool
107 -- (Filter.Filter_Posting
108 -- (Ledger.Charted Ledger.Posting)))
109 , ctx_reduce_date :: Bool
115 { ctx_filter_gl = Filter.Simplified $ Right True
116 -- , ctx_filter_posting = Filter.Simplified $ Right True
117 , ctx_filter_transaction = Filter.Simplified $ Right True
119 , ctx_input_format = mempty
121 , ctx_output_format = mempty
122 , ctx_reduce_date = True
125 usage :: C.Context -> IO String
127 bin <- Env.getProgName
129 [ C.translate c Lang.Section_Description
130 , " "++C.translate c Lang.Help_Command_General_Ledger
132 , C.translate c Lang.Section_Syntax
133 , " "++bin++" gl ["++C.translate c Lang.Type_Option++"] [...]"++
134 " ["++C.translate c Lang.Type_File_Journal++"] [...]"
136 , usageInfo (C.translate c Lang.Section_Options) (options c)
139 options :: C.Context -> Args.Options Context
141 [ Option "g" ["filter-gl"]
142 (ReqArg (\s ctx -> do
144 R.runParserT_with_Error
145 Filter.Read.filter_gl
146 Filter.Read.context "" s
148 Left (ko::[R.Error Filter.Read.Error]) -> Write.fatal c ko
152 Filter.and (ctx_filter_gl ctx) $
154 Filter.Read.get_Forall_Filter_GL_Decimal <$> flt)
156 C.translate c Lang.Type_Filter_General_Ledger) $
157 C.translate c Lang.Help_Option_Filter_General_Ledger
158 {-, Option "p" ["filter-posting"]
159 (ReqArg (\s ctx -> do
160 ctx_filter_posting <-
161 liftM ((ctx_filter_posting ctx <>) . Filter.simplify) $
162 liftIO $ Filter.Read.read Filter.Read.filter_posting s
164 Left ko -> Write.fatal c $ ko
165 Right ok -> return ok
166 return $ ctx{ctx_filter_posting}) $
167 C.translate c Lang.Type_Filter_Posting) $
168 C.translate c Lang.Help_Option_Filter_Posting
170 , Option "t" ["filter-transaction"]
171 (ReqArg (\s ctx -> do
173 R.runParserT_with_Error
174 Filter.Read.filter_transaction
175 Filter.Read.context "" s
177 Left ko -> Write.fatal c ko
180 ctx{ctx_filter_transaction =
181 Filter.and (ctx_filter_transaction ctx) $
183 Filter.Read.get_Forall_Filter_Transaction_Decimal <$> flt)
185 C.translate c Lang.Type_Filter_Transaction) $
186 C.translate c Lang.Help_Option_Filter_Transaction
187 , Option "h" ["help"]
189 usage c >>= IO.hPutStr IO.stderr
191 C.translate c Lang.Help_Option_Help
192 , Option "i" ["input"]
193 (ReqArg (\s ctx -> do
194 return $ ctx{ctx_input=s:ctx_input ctx}) $
195 C.translate c Lang.Type_File_Journal) $
196 C.translate c Lang.Help_Option_Input
197 , Option "f" ["input-format"]
198 (OptArg (\arg ctx -> do
199 ctx_input_format <- case arg of
200 Nothing -> return $ Format_JCC ()
201 Just "jcc" -> return $ Format_JCC ()
202 Just "ledger" -> return $ Format_Ledger ()
203 Just _ -> Write.fatal c $
204 W.text "--input-format option expects \"jcc\", or \"ledger\" as value"
205 return $ ctx{ctx_input_format})
208 , Option "o" ["output"]
209 (ReqArg (\s ctx -> do
210 return $ ctx{ctx_output=(Write.Mode_Append, s):ctx_output ctx}) $
211 C.translate c Lang.Type_File) $
212 C.translate c Lang.Help_Option_Output
213 , Option "F" ["output-format"]
214 (ReqArg (\arg ctx -> do
215 ctx_output_format <- case arg of
216 "jcc" -> return $ Just $ Format_JCC ()
217 "ledger" -> return $ Just $ Format_Ledger ()
219 W.text "--output-format option expects \"jcc\", or \"ledger\" as value"
220 return $ ctx{ctx_output_format})
223 , Option "O" ["overwrite"]
224 (ReqArg (\s ctx -> do
225 return $ ctx{ctx_output=(Write.Mode_Over, s):ctx_output ctx}) $
226 C.translate c Lang.Type_File) $
227 C.translate c Lang.Help_Option_Overwrite
228 {- NOTE: not used so far.
229 , Option "" ["reduce-date"]
230 (OptArg (\arg c ctx -> do
231 ctx_reduce_date <- case arg of
232 Nothing -> return $ True
233 Just "yes" -> return $ True
234 Just "no" -> return $ False
235 Just _ -> Write.fatal c $
236 W.text "--reduce-date option expects \"yes\", or \"no\" as value"
237 return $ ctx{ctx_reduce_date})
239 "use advanced date reducer to speed up filtering"
243 run :: C.Context -> [String] -> IO ()
248 [] -> x{ctx_output=[(Write.Mode_Append, "-")]}
250 Args.parse c usage options (context, args)
251 input_paths <- CLI.Env.paths c $ ctx_input ctx ++ inputs
252 read_journals <- mapM (liftIO . journal_read ctx) input_paths
253 case partitionEithers read_journals of
254 (errs@(_:_), _journals) -> Write.fatals c errs
255 ([], (journals::[Forall_Journal_GL])) -> do
258 fmap Format.journal_flatten $
259 case ctx_output_format ctx of
260 Just f -> Format.journal_empty f:journals
262 with_color <- Write.with_color c IO.stdout
263 W.displayIO IO.stdout $
264 W.renderPretty with_color 1.0 maxBound $
265 toDoc () $ Leijen.Table.table_of (c, ctx) gl
267 Write.debug c $ "filter: transaction: " ++ show (ctx_filter_transaction ctx)
268 Write.debug c $ "filter: posting: " ++ show (ctx_filter_posting ctx)
269 Write.debug c $ "filter: balance: " ++ show (ctx_filter_balance ctx)
272 instance Leijen.Table.Table_of (C.Context, Context) Forall_Journal_GL where
273 table_of (c, ctx) gl =
274 let lang = C.lang c in
276 [ Leijen.Table.column (Lang.translate lang Lang.Title_Account) Leijen.Table.Align_Left
277 , Leijen.Table.column (Lang.translate lang Lang.Title_Date) Leijen.Table.Align_Left
278 , Leijen.Table.column (Lang.translate lang Lang.Title_Debit) Leijen.Table.Align_Right
279 , Leijen.Table.column (Lang.translate lang Lang.Title_Credit) Leijen.Table.Align_Right
280 , Leijen.Table.column (Lang.translate lang Lang.Title_Running_debit) Leijen.Table.Align_Right
281 , Leijen.Table.column (Lang.translate lang Lang.Title_Running_credit) Leijen.Table.Align_Right
282 , Leijen.Table.column (Lang.translate lang Lang.Title_Running_balance) Leijen.Table.Align_Right
283 , Leijen.Table.column (Lang.translate lang Lang.Title_Description) Leijen.Table.Align_Left
285 Format.journal_leijen_table_cells
286 (Format.journal_filter ctx $
287 (Const::x -> Const x ()) gl) $
293 -- ** Type 'Format_GL'
295 type Format_Journal_GL
297 ( JCC.Journal GL_JCC)
298 (Ledger.Journal GL_Ledger)
302 = GL.GL (JCC.Charted JCC.Transaction)
303 -- = GL.GL JCC.Transaction
304 instance Format.Journal (JCC.Journal GL_JCC) where
305 type Journal_Format (JCC.Journal GL_JCC)
307 journal_format = Format_JCC
311 -- = GL.GL Ledger.Transaction
312 = GL.GL (Ledger.Charted Ledger.Transaction)
313 instance Format.Journal (Ledger.Journal GL_Ledger) where
314 type Journal_Format (Ledger.Journal GL_Ledger)
316 journal_format = Format_Ledger
318 -- ** Class 'Journal'
321 ( Format.Journal_Read j
322 , Ord (Account.Account_Section (Format.Journal_Account j))
323 , Leijen.Table.Cell_of_forall_param j
324 (TreeMap.Path (Account.Account_Section
325 (GL.Posting_Account (Format.Journal_Posting j))))
326 , Leijen.Table.Cell_of_forall_param j
327 (Format.Journal_Unit j, Format.Journal_Quantity j)
328 , Leijen.Table.Cell_of_forall_param j
329 (TreeMap.Path (Account.Account_Section (GL.Posting_Account
330 (Chart.Charted (Format.Journal_Account j)
331 (Format.Journal_Posting j)))))
332 , Polarize.Polarizable (Format.Journal_Quantity j)
335 journal_transaction_wording
337 -> Format.Journal_Transaction j
339 journal_posting_amounts
341 -> Format.Journal_Posting j
342 -> Map (Format.Journal_Unit j)
343 (Format.Journal_Quantity j)
344 journal_posting_amounts_set
346 -> Map (Format.Journal_Unit j)
347 (Format.Journal_Quantity j)
348 -> Format.Journal_Posting j
349 -> Format.Journal_Posting j
351 instance Journal JCC.Journal
353 journal_transaction_wording _j = JCC.transaction_wording
354 journal_posting_amounts _j = JCC.posting_amounts
355 journal_posting_amounts_set _j posting_amounts p =
356 p { JCC.posting_amounts }
357 instance Journal Ledger.Journal
359 journal_transaction_wording _j = Ledger.transaction_wording
360 journal_posting_amounts _j = Ledger.posting_amounts
361 journal_posting_amounts_set _j posting_amounts p =
362 p { Ledger.posting_amounts }
364 -- ** Class 'Journal_GL'
367 ( Format.Journal (j m)
368 , Format.Journal_Format (j m) ~ Format_Journal_GL
369 , Format.Journal_Read j
370 , Format.Journal_Monoid (j m)
371 , Format.Journal_Leijen_Table_Cells j m
372 , Format.Journal_Filter Context j m
375 instance Journal_GL JCC.Journal GL_JCC
376 instance Journal_GL Ledger.Journal GL_Ledger
378 -- ** Type 'Forall_Journal_GL'
380 data Forall_Journal_GL
381 = forall j m. Journal_GL j m
382 => Forall_Journal_GL (j m)
384 instance Format.Journal Forall_Journal_GL where
385 type Journal_Format Forall_Journal_GL = Format_Journal_GL
387 (Forall_Journal_GL j) =
388 Format.journal_format j
389 instance Format.Journal_Empty Forall_Journal_GL where
392 Format_JCC () -> Forall_Journal_GL (mempty::JCC.Journal GL_JCC)
393 Format_Ledger () -> Forall_Journal_GL (mempty::Ledger.Journal GL_Ledger)
394 instance Format.Journal_Monoid Forall_Journal_GL where
396 (Forall_Journal_GL j) =
398 Format.journal_flatten j
399 journal_fold f (Forall_Journal_GL j) =
400 Format.journal_fold (f . Forall_Journal_GL) j
401 instance Monoid Forall_Journal_GL where
402 mempty = Forall_Journal_GL (mempty::JCC.Journal GL_JCC)
404 case (mappend `on` Format.journal_format) x y of
405 Format_JCC j -> Forall_Journal_GL j
406 Format_Ledger j -> Forall_Journal_GL j
410 j:jn -> foldl' mappend j jn
413 -- *** 'journal_read'
415 type Journal_Filter_Simplified transaction
418 (Filter.Filter_Transaction transaction))
419 type Journal_Read_Cons txn
420 = txn -> Filter.Filtered (Journal_Filter_Simplified txn) txn
422 :: Context -> FilePath
423 -> IO (Either (Format.Message W.Doc) Forall_Journal_GL)
425 case ctx_input_format ctx of
427 let wrap (j::JCC.Journal GL_JCC)
428 = Forall_Journal_GL j in
429 let cons :: Journal_Read_Cons (JCC.Charted JCC.Transaction)
430 = Filter.Filtered (ctx_filter_transaction ctx) in
431 liftM ((+++) Format.Message wrap) .
432 Format.journal_read cons
434 let wrap (j::Ledger.Journal GL_Ledger)
435 = Forall_Journal_GL j in
436 let cons :: Journal_Read_Cons (Ledger.Charted Ledger.Transaction)
437 = Filter.Filtered (ctx_filter_transaction ctx) in
438 liftM ((+++) Format.Message wrap) .
439 Format.journal_read cons
442 -- Instances 'Format.Journal_Filter'
446 , Format.Journal_Chart j
448 , Journal_GL j (GL.GL t)
450 , Format.Journal_Account_Section j ~ Text
451 , GL.Transaction_Posting t
452 ~ Chart.Charted (Format.Journal_Account j)
453 (Format.Journal_Posting j)
454 , GL.Posting_Quantity (GL.Transaction_Posting t)
455 ~ Map (Format.Journal_Unit j)
456 (Polarized (Format.Journal_Quantity j))
457 , Format.Journal_Quantity j ~ Decimal
458 , Format.Journal_Account_Section j
459 ~ Account.Account_Section (GL.Posting_Account (GL.Transaction_Posting t))
460 , Ord (Format.Journal_Unit j)
461 , Unit.Unit (Format.Journal_Unit j)
462 ) => Format.Journal_Filter Context j (GL.GL t) where
463 journal_filter ctx j =
465 TreeMap.map_Maybe_with_Path
466 (\acct expanded_lines ->
467 let chart = Format.journal_chart j in
468 case Map.mapMaybeWithKey
472 { GL.gl_line_transaction = _t
473 , GL.gl_line_posting = p
478 let sqty = (Map.!) s unit in
479 if Filter.test (ctx_filter_gl ctx)
480 ( (Chart.account_tags acct chart, acct)
482 , (unit, Polarize.polarize qty)
485 then (Seq.|>) acc line
486 { GL.gl_line_posting =
487 journal_posting_amounts_set j
488 (Map.singleton unit qty) <$> p
489 , GL.gl_line_sum = Map.singleton unit sqty
494 (journal_posting_amounts j $ Chart.charted p)
497 m | Seq.null m -> Nothing
500 (GL.inclusive expanded_lines)
502 m | Map.null m -> Strict.Nothing
505 (\(GL.Expanded gl) -> gl) .
507 instance Format.Journal_Filter Context (Const Forall_Journal_GL) () where
509 (Const (Forall_Journal_GL j)) =
510 Const $ Forall_Journal_GL $
511 Format.journal_filter ctx j
513 -- Instances 'Format.Journal_Leijen_Table_Cells'
516 ( Format.Journal_Content j
519 , Quantity.Addable (Format.Journal_Quantity j)
520 , GL.Transaction_Posting t
521 ~ Chart.Charted (Format.Journal_Account j)
522 (Format.Journal_Posting j)
523 , Format.Journal_Transaction j ~ GL.Transaction_Line t
524 , GL.Posting_Quantity (Chart.Charted (Format.Journal_Account j)
525 (Format.Journal_Posting j))
526 ~ Map (Format.Journal_Unit j)
527 (Polarized (Format.Journal_Quantity j))
528 , GL.Posting_Quantity (Format.Journal_Posting j)
529 ~ Map (Format.Journal_Unit j)
530 (Polarized (Format.Journal_Quantity j))
531 -- , GL.Posting_Account t ~ Format.Journal_Account j
532 -- , Leijen.Table.Cell_of_forall_param j (TreeMap.Path as)
533 , Leijen.Table.Cell_of_forall_param j Date
534 , Leijen.Table.Cell_of_forall_param j Text
535 , Ord (Format.Journal_Unit j)
537 ) => Format.Journal_Leijen_Table_Cells j (GL.GL t) where
538 journal_leijen_table_cells jnl =
539 flip (TreeMap.foldr_with_Path
541 flip $ Map.foldrWithKey
545 { GL.gl_line_transaction = t
546 , GL.gl_line_posting = p
549 flip (Map.foldrWithKey
551 let ms = Map.lookup unit s in
555 , cell_of $ (unit,) <$> Polarize.polarizable_positive qty
556 , cell_of $ (unit,) <$> Polarize.polarizable_negative qty
557 , cell_of $ (unit,) <$> (ms >>= Polarize.polarized_positive)
558 , cell_of $ (unit,) <$> (ms >>= Polarize.polarized_negative)
559 , cell_of $ (unit,) . Polarize.depolarize <$> ms
560 , cell_of $ journal_transaction_wording jnl t
563 (journal_posting_amounts jnl $ Chart.charted p)
568 (Format.journal_content jnl)
570 cell_of :: Leijen.Table.Cell_of_forall_param j x => x -> Leijen.Table.Cell
571 cell_of = Leijen.Table.cell_of_forall_param jnl
573 instance Format.Journal_Leijen_Table_Cells (Const Forall_Journal_GL) () where
574 journal_leijen_table_cells
575 (Const (Forall_Journal_GL j)) =
576 Format.journal_leijen_table_cells j
602 -- Instances GL.GL -> GL.Expanded
606 , Journal_GL_Expanded j (GL.Expanded t)
608 -- NOTE: constraint from GL.expanded
610 ) => Format.Journal_Wrap (j (GL.GL t))
611 Forall_Journal_GL_Expanded where
613 Forall_Journal_GL_Expanded .
616 instance Format.Journal_Wrap Forall_Journal_GL
617 Forall_Journal_GL_Expanded where
618 journal_wrap (Forall_Journal_GL j) = Format.journal_wrap j
621 -- * 'GL.GL_Expanded'
623 -- ** Type 'Format_GL_Expanded'
625 type Format_Journal_GL_Expanded
627 ( JCC.Journal GL_Expanded_JCC)
628 (Ledger.Journal GL_Expanded_Ledger)
632 = GL.Expanded (JCC.Charted JCC.Transaction)
633 instance Format.Journal (JCC.Journal GL_Expanded_JCC) where
634 type Journal_Format (JCC.Journal GL_Expanded_JCC)
635 = Format_Journal_GL_Expanded
636 journal_format = Format_JCC
639 type GL_Expanded_Ledger
640 = GL.Expanded (Ledger.Charted Ledger.Transaction)
641 instance Format.Journal (Ledger.Journal GL_Expanded_Ledger) where
642 type Journal_Format (Ledger.Journal GL_Expanded_Ledger)
643 = Format_Journal_GL_Expanded
644 journal_format = Format_Ledger
646 -- ** Class 'Journal_GL_Expanded'
649 ( Format.Journal (j m)
650 , Format.Journal_Format (j m) ~ Format_Journal_GL_Expanded
651 -- , Format.Journal_Leijen_Table_Cells j m
652 , Format.Journal_Filter Context j m
653 ) => Journal_GL_Expanded j m where
654 journal_posting_amounts
656 -> Format.Journal_Posting j
657 -> Map (Format.Journal_Unit j)
658 (Format.Journal_Quantity j)
659 journal_posting_amounts_set
661 -> Map (Format.Journal_Unit j)
662 (Format.Journal_Quantity j)
663 -> Format.Journal_Posting j
664 -> Format.Journal_Posting j
666 instance Journal_GL_Expanded JCC.Journal GL_Expanded_JCC
668 journal_posting_amounts _j = JCC.posting_amounts
669 journal_posting_amounts_set _j posting_amounts p =
670 p { JCC.posting_amounts }
671 instance Journal_GL_Expanded Ledger.Journal GL_Expanded_Ledger
673 journal_posting_amounts _j = Ledger.posting_amounts
674 journal_posting_amounts_set _j posting_amounts p =
675 p { Ledger.posting_amounts }
677 -- ** Type 'Forall_Journal_GL_Expanded'
679 data Forall_Journal_GL_Expanded
680 = forall j m. Journal_GL_Expanded j m
681 => Forall_Journal_GL_Expanded (j m)
683 instance Format.Journal Forall_Journal_GL_Expanded where
684 type Journal_Format Forall_Journal_GL_Expanded = Format_Journal_GL_Expanded
686 (Forall_Journal_GL_Expanded j) =
687 Format.journal_format j
689 -- Instances 'Format.Journal_Filter'
693 , Format.Journal_Chart j
694 , Journal_GL_Expanded j (GL.Expanded t)
696 , Format.Journal_Account_Section j ~ Text
697 , GL.Transaction_Posting t ~ Chart.Charted (Format.Journal_Account j) (Format.Journal_Posting j)
698 , GL.Posting_Quantity (GL.Transaction_Posting t)
699 ~ Map (Format.Journal_Unit j) (Polarized (Format.Journal_Quantity j))
700 , Format.Journal_Quantity j ~ Decimal
701 , Format.Journal_Account_Section j
702 ~ Account.Account_Section (GL.Posting_Account (GL.Transaction_Posting t))
703 , Ord (Format.Journal_Unit j)
704 , Unit.Unit (Format.Journal_Unit j)
705 ) => Format.Journal_Filter Context j (GL.Expanded t) where
706 journal_filter ctx j =
708 TreeMap.map_Maybe_with_Path
709 (\acct expanded_lines ->
710 let chart = Format.journal_chart j in
711 case Map.mapMaybeWithKey
715 { GL.gl_line_transaction = _t
716 , GL.gl_line_posting = Chart.Charted ch p
721 let sqty = (Map.!) s unit in
722 if Filter.test (ctx_filter_gl ctx)
723 ( (Chart.account_tags acct chart, acct)
725 , (unit, Polarize.polarize qty)
728 then (Seq.|>) acc line
729 { GL.gl_line_posting =
731 journal_posting_amounts_set j
732 (Map.singleton unit qty) p
733 , GL.gl_line_sum = Map.singleton unit sqty
738 (journal_posting_amounts j p)
741 m | Seq.null m -> Nothing
744 (GL.inclusive expanded_lines)
746 m | Map.null m -> Strict.Nothing
747 m -> Strict.Just $ expanded_lines { GL.inclusive=m }
749 (\(GL.Expanded gl) -> gl) <$> j
751 instance Format.Journal_Filter Context (Const Forall_Journal_GL_Expanded) () where
753 (Const (Forall_Journal_GL_Expanded j)) =
754 Const $ Forall_Journal_GL_Expanded $
755 Format.journal_filter ctx j
759 run :: C.Context -> [String] -> IO ()
764 [] -> x{ctx_output=[(Write.Mode_Append, "-")]}
766 Args.parse c usage options (context, args)
768 liftM partitionEithers $ do
769 CLI.Env.paths c $ ctx_input ctx ++ inputs
772 liftIO $ runExceptT $ Ledger.Read.file
773 (Ledger.Read.context ( ctx_filter_transaction ctx
774 , ctx_filter_posting ctx )
778 Left ko -> return $ Left (path, ko)
779 Right ok -> return $ Right ok
780 case read_journals of
781 (errs@(_:_), _journals) ->
782 forM_ errs $ \(_path, err) -> do
785 Write.debug c $ "filter: transaction: " ++ show (ctx_filter_transaction ctx)
786 Write.debug c $ "filter: posting: " ++ show (ctx_filter_posting ctx)
787 Write.debug c $ "filter: gl: " ++ show (ctx_filter_gl ctx)
788 let (amount_styles, gl) = ledger_gl ctx journals
790 Write.write c Write.style (ctx_output ctx) $ do
793 [ Table.column (Lang.translate lang Lang.Title_Account) Table.Align_Left
794 , Table.column (Lang.translate lang Lang.Title_Date) Table.Align_Left
795 , Table.column (Lang.translate lang Lang.Title_Debit) Table.Align_Right
796 , Table.column (Lang.translate lang Lang.Title_Credit) Table.Align_Right
797 , Table.column (Lang.translate lang Lang.Title_Running_debit) Table.Align_Right
798 , Table.column (Lang.translate lang Lang.Title_Running_credit) Table.Align_Right
799 , Table.column (Lang.translate lang Lang.Title_Running_balance) Table.Align_Right
800 , Table.column (Lang.translate lang Lang.Title_Description) Table.Align_Left
802 write_gl amount_styles gl (repeat [])
808 -> [ Ledger.Journal (GL.GL (Ledger.Charted Ledger.Transaction)) ]
809 -> ( Ledger.Amount.Styles
810 , GL (Ledger.Charted Ledger.Transaction)
812 ledger_gl ctx journals =
813 let (_chart, amount_styles, gl) =
817 ( Ledger.journal_chart j
818 , Ledger.journal_amount_styles j
822 { Ledger.journal_sections=g
829 TreeMap.map_Maybe_with_Path
830 (\acct expanded_lines ->
831 case Map.mapMaybeWithKey
835 { GL.gl_line_transaction = _t
836 , GL.gl_line_posting = Ledger.Charted c p
841 let sqty = (Map.!) s unit in
842 if Filter.test (ctx_filter_gl ctx)
843 ( (Chart.account_tags acct c, acct)
845 , (unit, Polarize.polarize qty)
848 then (Seq.|>) acc line
849 { GL.gl_line_posting = Ledger.Charted c p
850 { Ledger.posting_amounts = Map.singleton unit qty }
851 , GL.gl_line_sum = Map.singleton unit sqty
856 (Ledger.posting_amounts p)
858 m | Seq.null m -> Nothing
861 (GL.inclusive expanded_lines) of
862 m | Map.null m -> Strict.Nothing
868 :: Ledger.Amount.Styles
869 -> GL (Ledger.Charted Ledger.Transaction)
872 write_gl amount_styles (GL gl) =
873 flip (TreeMap.foldr_with_Path
875 flip $ Map.foldrWithKey
879 { GL.gl_line_transaction = Ledger.Charted _ t
880 , GL.gl_line_posting = Ledger.Charted _ p
883 flip (Map.foldrWithKey
885 let ms = Map.lookup unit s in
887 [ let ptype = Ledger.Posting_Type_Regular in
889 { Table.cell_content = Ledger.Write.account ptype acct
890 , Table.cell_width = Ledger.Write.account_length ptype acct
893 { Table.cell_content = Date.Write.date date
894 , Table.cell_width = Date.Write.date_length date
896 , cell_amount unit (Polarize.polarizable_positive qty)
897 , cell_amount unit (Polarize.polarizable_negative qty)
898 , cell_amount unit (ms >>= Polarize.polarized_positive)
899 , cell_amount unit (ms >>= Polarize.polarized_negative)
900 , cell_amount unit (liftM Polarize.depolarize ms)
901 , let descr = Ledger.transaction_wording t in
903 { Table.cell_content = toDoc () descr
904 , Table.cell_width = Text.length descr
908 (Ledger.posting_amounts p)
914 cell_amount :: Ledger.Unit -> Maybe Ledger.Quantity -> Table.Cell
915 cell_amount unit mq =
917 Nothing -> Table.cell
919 let a = Ledger.Amount.Amount unit q in
920 let sa = Ledger.Amount.style amount_styles a in
922 { Table.cell_content = Amount.Write.amount sa
923 , Table.cell_width = Amount.Write.amount_length sa