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_Wrap (j m) Forall_Journal_GL_Expanded
372 , Format.Journal_Leijen_Table_Cells j m
373 , Format.Journal_Filter Context j m
376 instance Journal_GL JCC.Journal GL_JCC
377 instance Journal_GL Ledger.Journal GL_Ledger
379 -- ** Type 'Forall_Journal_GL'
381 data Forall_Journal_GL
382 = forall j m. Journal_GL j m
383 => Forall_Journal_GL (j m)
385 instance Format.Journal Forall_Journal_GL where
386 type Journal_Format Forall_Journal_GL = Format_Journal_GL
388 (Forall_Journal_GL j) =
389 Format.journal_format j
390 instance Format.Journal_Empty Forall_Journal_GL where
393 Format_JCC () -> Forall_Journal_GL (mempty::JCC.Journal GL_JCC)
394 Format_Ledger () -> Forall_Journal_GL (mempty::Ledger.Journal GL_Ledger)
395 instance Format.Journal_Monoid Forall_Journal_GL where
397 (Forall_Journal_GL j) =
399 Format.journal_flatten j
400 journal_fold f (Forall_Journal_GL j) =
401 Format.journal_fold (f . Forall_Journal_GL) j
402 instance Monoid Forall_Journal_GL where
403 mempty = Forall_Journal_GL (mempty::JCC.Journal GL_JCC)
405 case (mappend `on` Format.journal_format) x y of
406 Format_JCC j -> Forall_Journal_GL j
407 Format_Ledger j -> Forall_Journal_GL j
411 j:jn -> foldl' mappend j jn
414 -- *** 'journal_read'
416 type Journal_Filter_Simplified transaction
419 (Filter.Filter_Transaction transaction))
420 type Journal_Read_Cons txn
421 = txn -> Filter.Filtered (Journal_Filter_Simplified txn) txn
423 :: Context -> FilePath
424 -> IO (Either (Format.Message W.Doc) Forall_Journal_GL)
426 case ctx_input_format ctx of
428 let wrap (j::JCC.Journal GL_JCC)
429 = Forall_Journal_GL j in
430 let cons :: Journal_Read_Cons (JCC.Charted JCC.Transaction)
431 = Filter.Filtered (ctx_filter_transaction ctx) in
432 liftM ((+++) Format.Message wrap) .
433 Format.journal_read cons
435 let wrap (j::Ledger.Journal GL_Ledger)
436 = Forall_Journal_GL j in
437 let cons :: Journal_Read_Cons (Ledger.Charted Ledger.Transaction)
438 = Filter.Filtered (ctx_filter_transaction ctx) in
439 liftM ((+++) Format.Message wrap) .
440 Format.journal_read cons
443 -- Instances 'Format.Journal_Filter'
447 , Format.Journal_Chart j
449 , Journal_GL j (GL.GL t)
451 , Format.Journal_Account_Section j ~ Text
452 , GL.Transaction_Posting t
453 ~ Chart.Charted (Format.Journal_Account j)
454 (Format.Journal_Posting j)
455 , GL.Posting_Quantity (GL.Transaction_Posting t)
456 ~ Map (Format.Journal_Unit j)
457 (Polarized (Format.Journal_Quantity j))
458 , Format.Journal_Quantity j ~ Decimal
459 , Format.Journal_Account_Section j
460 ~ Account.Account_Section (GL.Posting_Account (GL.Transaction_Posting t))
461 , Ord (Format.Journal_Unit j)
462 , Unit.Unit (Format.Journal_Unit j)
463 ) => Format.Journal_Filter Context j (GL.GL t) where
464 journal_filter ctx j =
466 TreeMap.map_Maybe_with_Path
467 (\acct expanded_lines ->
468 let chart = Format.journal_chart j in
469 case Map.mapMaybeWithKey
473 { GL.gl_line_transaction = _t
474 , GL.gl_line_posting = p
479 let sqty = (Map.!) s unit in
480 if Filter.test (ctx_filter_gl ctx)
481 ( (Chart.account_tags acct chart, acct)
483 , (unit, Polarize.polarize qty)
486 then (Seq.|>) acc line
487 { GL.gl_line_posting =
488 journal_posting_amounts_set j
489 (Map.singleton unit qty) <$> p
490 , GL.gl_line_sum = Map.singleton unit sqty
495 (journal_posting_amounts j $ Chart.charted p)
498 m | Seq.null m -> Nothing
501 (GL.inclusive expanded_lines)
503 m | Map.null m -> Strict.Nothing
506 (\(GL.Expanded gl) -> gl) .
508 instance Format.Journal_Filter Context (Const Forall_Journal_GL) () where
510 (Const (Forall_Journal_GL j)) =
511 Const $ Forall_Journal_GL $
512 Format.journal_filter ctx j
514 -- Instances 'Format.Journal_Leijen_Table_Cells'
517 ( Format.Journal_Content j
520 , Quantity.Addable (Format.Journal_Quantity j)
521 , GL.Transaction_Posting t
522 ~ Chart.Charted (Format.Journal_Account j)
523 (Format.Journal_Posting j)
524 , Format.Journal_Transaction j ~ GL.Transaction_Line t
525 , GL.Posting_Quantity (Chart.Charted (Format.Journal_Account j)
526 (Format.Journal_Posting j))
527 ~ Map (Format.Journal_Unit j)
528 (Polarized (Format.Journal_Quantity j))
529 , GL.Posting_Quantity (Format.Journal_Posting j)
530 ~ Map (Format.Journal_Unit j)
531 (Polarized (Format.Journal_Quantity j))
532 -- , GL.Posting_Account t ~ Format.Journal_Account j
533 -- , Leijen.Table.Cell_of_forall_param j (TreeMap.Path as)
534 , Leijen.Table.Cell_of_forall_param j Date
535 , Leijen.Table.Cell_of_forall_param j Text
536 , Ord (Format.Journal_Unit j)
538 ) => Format.Journal_Leijen_Table_Cells j (GL.GL t) where
539 journal_leijen_table_cells jnl =
540 flip (TreeMap.foldr_with_Path
542 flip $ Map.foldrWithKey
546 { GL.gl_line_transaction = t
547 , GL.gl_line_posting = p
550 flip (Map.foldrWithKey
552 let ms = Map.lookup unit s in
556 , cell_of $ (unit,) <$> Polarize.polarizable_positive qty
557 , cell_of $ (unit,) <$> Polarize.polarizable_negative qty
558 , cell_of $ (unit,) <$> (ms >>= Polarize.polarized_positive)
559 , cell_of $ (unit,) <$> (ms >>= Polarize.polarized_negative)
560 , cell_of $ (unit,) . Polarize.depolarize <$> ms
561 , cell_of $ journal_transaction_wording jnl t
564 (journal_posting_amounts jnl $ Chart.charted p)
569 (Format.journal_content jnl)
571 cell_of :: Leijen.Table.Cell_of_forall_param j x => x -> Leijen.Table.Cell
572 cell_of = Leijen.Table.cell_of_forall_param jnl
574 instance Format.Journal_Leijen_Table_Cells (Const Forall_Journal_GL) () where
575 journal_leijen_table_cells
576 (Const (Forall_Journal_GL j)) =
577 Format.journal_leijen_table_cells j
603 -- Instances GL.GL -> GL.Expanded
607 , Journal_GL_Expanded j (GL.Expanded t)
609 -- NOTE: constraint from GL.expanded
611 ) => Format.Journal_Wrap (j (GL.GL t))
612 Forall_Journal_GL_Expanded where
614 Forall_Journal_GL_Expanded .
617 instance Format.Journal_Wrap Forall_Journal_GL
618 Forall_Journal_GL_Expanded where
619 journal_wrap (Forall_Journal_GL j) = Format.journal_wrap j
622 -- * 'GL.GL_Expanded'
624 -- ** Type 'Format_GL_Expanded'
626 type Format_Journal_GL_Expanded
628 ( JCC.Journal GL_Expanded_JCC)
629 (Ledger.Journal GL_Expanded_Ledger)
633 = GL.Expanded (JCC.Charted JCC.Transaction)
634 instance Format.Journal (JCC.Journal GL_Expanded_JCC) where
635 type Journal_Format (JCC.Journal GL_Expanded_JCC)
636 = Format_Journal_GL_Expanded
637 journal_format = Format_JCC
640 type GL_Expanded_Ledger
641 = GL.Expanded (Ledger.Charted Ledger.Transaction)
642 instance Format.Journal (Ledger.Journal GL_Expanded_Ledger) where
643 type Journal_Format (Ledger.Journal GL_Expanded_Ledger)
644 = Format_Journal_GL_Expanded
645 journal_format = Format_Ledger
647 -- ** Class 'Journal_GL_Expanded'
650 ( Format.Journal (j m)
651 , Format.Journal_Format (j m) ~ Format_Journal_GL_Expanded
652 -- , Format.Journal_Leijen_Table_Cells j m
653 , Format.Journal_Filter Context j m
654 ) => Journal_GL_Expanded j m where
655 journal_posting_amounts
657 -> Format.Journal_Posting j
658 -> Map (Format.Journal_Unit j)
659 (Format.Journal_Quantity j)
660 journal_posting_amounts_set
662 -> Map (Format.Journal_Unit j)
663 (Format.Journal_Quantity j)
664 -> Format.Journal_Posting j
665 -> Format.Journal_Posting j
667 instance Journal_GL_Expanded JCC.Journal GL_Expanded_JCC
669 journal_posting_amounts _j = JCC.posting_amounts
670 journal_posting_amounts_set _j posting_amounts p =
671 p { JCC.posting_amounts }
672 instance Journal_GL_Expanded Ledger.Journal GL_Expanded_Ledger
674 journal_posting_amounts _j = Ledger.posting_amounts
675 journal_posting_amounts_set _j posting_amounts p =
676 p { Ledger.posting_amounts }
678 -- ** Type 'Forall_Journal_GL_Expanded'
680 data Forall_Journal_GL_Expanded
681 = forall j m. Journal_GL_Expanded j m
682 => Forall_Journal_GL_Expanded (j m)
684 instance Format.Journal Forall_Journal_GL_Expanded where
685 type Journal_Format Forall_Journal_GL_Expanded = Format_Journal_GL_Expanded
687 (Forall_Journal_GL_Expanded j) =
688 Format.journal_format j
690 -- Instances 'Format.Journal_Filter'
694 , Format.Journal_Chart j
695 , Journal_GL_Expanded j (GL.Expanded t)
697 , Format.Journal_Account_Section j ~ Text
698 , GL.Transaction_Posting t ~ Chart.Charted (Format.Journal_Account j) (Format.Journal_Posting j)
699 , GL.Posting_Quantity (GL.Transaction_Posting t)
700 ~ Map (Format.Journal_Unit j) (Polarized (Format.Journal_Quantity j))
701 , Format.Journal_Quantity j ~ Decimal
702 , Format.Journal_Account_Section j
703 ~ Account.Account_Section (GL.Posting_Account (GL.Transaction_Posting t))
704 , Ord (Format.Journal_Unit j)
705 , Unit.Unit (Format.Journal_Unit j)
706 ) => Format.Journal_Filter Context j (GL.Expanded t) where
707 journal_filter ctx j =
709 TreeMap.map_Maybe_with_Path
710 (\acct expanded_lines ->
711 let chart = Format.journal_chart j in
712 case Map.mapMaybeWithKey
716 { GL.gl_line_transaction = _t
717 , GL.gl_line_posting = Chart.Charted ch p
722 let sqty = (Map.!) s unit in
723 if Filter.test (ctx_filter_gl ctx)
724 ( (Chart.account_tags acct chart, acct)
726 , (unit, Polarize.polarize qty)
729 then (Seq.|>) acc line
730 { GL.gl_line_posting =
732 journal_posting_amounts_set j
733 (Map.singleton unit qty) p
734 , GL.gl_line_sum = Map.singleton unit sqty
739 (journal_posting_amounts j p)
742 m | Seq.null m -> Nothing
745 (GL.inclusive expanded_lines)
747 m | Map.null m -> Strict.Nothing
748 m -> Strict.Just $ expanded_lines { GL.inclusive=m }
750 (\(GL.Expanded gl) -> gl) <$> j
752 instance Format.Journal_Filter Context (Const Forall_Journal_GL_Expanded) () where
754 (Const (Forall_Journal_GL_Expanded j)) =
755 Const $ Forall_Journal_GL_Expanded $
756 Format.journal_filter ctx j
760 run :: C.Context -> [String] -> IO ()
765 [] -> x{ctx_output=[(Write.Mode_Append, "-")]}
767 Args.parse c usage options (context, args)
769 liftM partitionEithers $ do
770 CLI.Env.paths c $ ctx_input ctx ++ inputs
773 liftIO $ runExceptT $ Ledger.Read.file
774 (Ledger.Read.context ( ctx_filter_transaction ctx
775 , ctx_filter_posting ctx )
779 Left ko -> return $ Left (path, ko)
780 Right ok -> return $ Right ok
781 case read_journals of
782 (errs@(_:_), _journals) ->
783 forM_ errs $ \(_path, err) -> do
786 Write.debug c $ "filter: transaction: " ++ show (ctx_filter_transaction ctx)
787 Write.debug c $ "filter: posting: " ++ show (ctx_filter_posting ctx)
788 Write.debug c $ "filter: gl: " ++ show (ctx_filter_gl ctx)
789 let (amount_styles, gl) = ledger_gl ctx journals
791 Write.write c Write.style (ctx_output ctx) $ do
794 [ Table.column (Lang.translate lang Lang.Title_Account) Table.Align_Left
795 , Table.column (Lang.translate lang Lang.Title_Date) Table.Align_Left
796 , Table.column (Lang.translate lang Lang.Title_Debit) Table.Align_Right
797 , Table.column (Lang.translate lang Lang.Title_Credit) Table.Align_Right
798 , Table.column (Lang.translate lang Lang.Title_Running_debit) Table.Align_Right
799 , Table.column (Lang.translate lang Lang.Title_Running_credit) Table.Align_Right
800 , Table.column (Lang.translate lang Lang.Title_Running_balance) Table.Align_Right
801 , Table.column (Lang.translate lang Lang.Title_Description) Table.Align_Left
803 write_gl amount_styles gl (repeat [])
809 -> [ Ledger.Journal (GL.GL (Ledger.Charted Ledger.Transaction)) ]
810 -> ( Ledger.Amount.Styles
811 , GL (Ledger.Charted Ledger.Transaction)
813 ledger_gl ctx journals =
814 let (_chart, amount_styles, gl) =
818 ( Ledger.journal_chart j
819 , Ledger.journal_amount_styles j
823 { Ledger.journal_sections=g
830 TreeMap.map_Maybe_with_Path
831 (\acct expanded_lines ->
832 case Map.mapMaybeWithKey
836 { GL.gl_line_transaction = _t
837 , GL.gl_line_posting = Ledger.Charted c p
842 let sqty = (Map.!) s unit in
843 if Filter.test (ctx_filter_gl ctx)
844 ( (Chart.account_tags acct c, acct)
846 , (unit, Polarize.polarize qty)
849 then (Seq.|>) acc line
850 { GL.gl_line_posting = Ledger.Charted c p
851 { Ledger.posting_amounts = Map.singleton unit qty }
852 , GL.gl_line_sum = Map.singleton unit sqty
857 (Ledger.posting_amounts p)
859 m | Seq.null m -> Nothing
862 (GL.inclusive expanded_lines) of
863 m | Map.null m -> Strict.Nothing
869 :: Ledger.Amount.Styles
870 -> GL (Ledger.Charted Ledger.Transaction)
873 write_gl amount_styles (GL gl) =
874 flip (TreeMap.foldr_with_Path
876 flip $ Map.foldrWithKey
880 { GL.gl_line_transaction = Ledger.Charted _ t
881 , GL.gl_line_posting = Ledger.Charted _ p
884 flip (Map.foldrWithKey
886 let ms = Map.lookup unit s in
888 [ let ptype = Ledger.Posting_Type_Regular in
890 { Table.cell_content = Ledger.Write.account ptype acct
891 , Table.cell_width = Ledger.Write.account_length ptype acct
894 { Table.cell_content = Date.Write.date date
895 , Table.cell_width = Date.Write.date_length date
897 , cell_amount unit (Polarize.polarizable_positive qty)
898 , cell_amount unit (Polarize.polarizable_negative qty)
899 , cell_amount unit (ms >>= Polarize.polarized_positive)
900 , cell_amount unit (ms >>= Polarize.polarized_negative)
901 , cell_amount unit (liftM Polarize.depolarize ms)
902 , let descr = Ledger.transaction_wording t in
904 { Table.cell_content = toDoc () descr
905 , Table.cell_width = Text.length descr
909 (Ledger.posting_amounts p)
915 cell_amount :: Ledger.Unit -> Maybe Ledger.Quantity -> Table.Cell
916 cell_amount unit mq =
918 Nothing -> Table.cell
920 let a = Ledger.Amount.Amount unit q in
921 let sa = Ledger.Amount.style amount_styles a in
923 { Table.cell_content = Amount.Write.amount sa
924 , Table.cell_width = Amount.Write.amount_length sa