1 {-# LANGUAGE BangPatterns #-}
2 {-# LANGUAGE DeriveDataTypeable #-}
3 {-# LANGUAGE FlexibleInstances #-}
4 {-# LANGUAGE MultiParamTypeClasses #-}
5 {-# LANGUAGE NamedFieldPuns #-}
6 {-# LANGUAGE OverloadedStrings #-}
7 {-# LANGUAGE TupleSections #-}
8 {-# LANGUAGE TypeFamilies #-}
9 {-# OPTIONS_GHC -fno-warn-orphans #-}
10 module Hcompta.Format.Ledger where
12 -- import Control.Applicative (Const(..))
14 import Data.Data (Data(..))
15 import Data.Eq (Eq(..))
16 import Data.Functor (Functor(..))
17 import Data.Functor.Compose (Compose(..))
19 import Data.Map.Strict (Map)
20 import qualified Data.Map.Strict as Data.Map
21 import Data.Maybe (Maybe(..))
22 import Data.Monoid (Monoid(..))
23 import Data.Text (Text)
24 import Data.Tuple (fst, snd)
25 import Data.Typeable (Typeable)
26 import Prelude (($), (.), FilePath, Num(..), flip, undefined)
27 import Text.Parsec.Pos (SourcePos, initialPos)
28 import Text.Show (Show)
30 import qualified Hcompta.Account as Account
31 import Hcompta.Amount (Amount)
32 import qualified Hcompta.Amount as Amount
33 -- import Hcompta.Balance (Balance(..))
34 import qualified Hcompta.Balance as Balance
35 import Hcompta.Chart (Chart)
36 import qualified Hcompta.Chart as Chart
37 import Hcompta.Date (Date)
38 import qualified Hcompta.Date as Date
39 import qualified Hcompta.Filter as Filter
40 -- import Hcompta.GL (GL(..))
41 import qualified Hcompta.GL as GL
42 import qualified Hcompta.Journal as Journal
43 -- import Hcompta.Lib.Consable
44 import Hcompta.Lib.Parsec ()
45 import qualified Hcompta.Stats as Stats
46 import qualified Hcompta.Tag as Tag
49 type Description = Text
58 { account_path :: Account.Account_Path
59 , account_tags :: Tag.Tags
66 data Monoid ts => Journal ts
68 { journal_file :: FilePath
69 , journal_includes :: [Journal ts]
70 , journal_last_read_time :: Date
71 , journal_sections :: !ts
72 , journal_unit_styles :: Map Amount.Unit Amount.Style
73 , journal_chart :: Chart
74 } deriving (Data, Eq, Show, Typeable)
76 journal :: Monoid ts => Journal ts
79 { journal_file = mempty
80 , journal_includes = mempty
81 , journal_last_read_time = Date.nil
82 , journal_sections = mempty
83 , journal_unit_styles = mempty
84 , journal_chart = mempty
87 -- * Type 'Transaction'
91 { transaction_code :: Code
92 , transaction_comments_before :: [Comment]
93 , transaction_comments_after :: [Comment]
94 , transaction_dates :: (Date, [Date])
95 , transaction_description :: Description
96 , transaction_postings :: Map Account.Account_Path [Posting]
97 , transaction_virtual_postings :: Map Account.Account_Path [Posting]
98 , transaction_balanced_virtual_postings :: Map Account.Account_Path [Posting]
99 , transaction_sourcepos :: SourcePos
100 , transaction_status :: Status
101 , transaction_tags :: Tag.Tags
102 } deriving (Data, Eq, Show, Typeable)
104 transaction :: Transaction
107 { transaction_code = ""
108 , transaction_comments_before = []
109 , transaction_comments_after = []
110 , transaction_dates = (Date.nil, [])
111 , transaction_description = ""
112 , transaction_postings = mempty
113 , transaction_virtual_postings = mempty
114 , transaction_balanced_virtual_postings = mempty
115 , transaction_sourcepos = initialPos ""
116 , transaction_status = False
117 , transaction_tags = mempty
120 instance Filter.Transaction (Chart, Transaction) where
121 type Transaction_Posting (Chart, Transaction) = (Chart, Posting)
122 type Transaction_Postings (Chart, Transaction) = Compose [] (Compose (Map Account.Account_Path) [])
123 transaction_date = fst . transaction_dates . snd
124 transaction_description = transaction_description . snd
125 transaction_postings (c, t) =
128 [ Compose $ transaction_postings t
130 transaction_postings_virtual (c, t) =
133 [ Compose $ transaction_virtual_postings t
134 , Compose $ transaction_balanced_virtual_postings t
136 transaction_tags = transaction_tags . snd
138 --instance Journal.Transaction Transaction where
139 -- transaction_date = fst . transaction_dates
140 instance Journal.Transaction (Chart, Transaction) where
141 transaction_date = fst . transaction_dates . snd
143 instance Stats.Transaction Transaction where
144 type Transaction_Posting Transaction = Posting
145 type Transaction_Postings Transaction = Compose [] (Compose (Map Account.Account_Path) [])
146 transaction_date = fst . transaction_dates
147 transaction_postings t =
149 [ Compose $ transaction_postings t
150 , Compose $ transaction_virtual_postings t
151 , Compose $ transaction_balanced_virtual_postings t
153 transaction_postings_size t =
154 Data.Map.size (transaction_postings t) +
155 Data.Map.size (transaction_virtual_postings t) +
156 Data.Map.size (transaction_balanced_virtual_postings t)
157 transaction_tags = transaction_tags
158 instance Stats.Transaction (Chart, Transaction) where
159 type Transaction_Posting (Chart, Transaction) = Stats.Transaction_Posting Transaction
160 type Transaction_Postings (Chart, Transaction) = Stats.Transaction_Postings Transaction
161 transaction_date = Stats.transaction_date . snd
162 transaction_postings = Stats.transaction_postings . snd
163 transaction_postings_size = Stats.transaction_postings_size . snd
164 transaction_tags = Stats.transaction_tags . snd
166 instance GL.Transaction Transaction where
167 type Transaction_Posting Transaction = Posting
168 type Transaction_Postings Transaction = Compose [] (Compose (Map Account.Account_Path) [])
169 transaction_date = fst . transaction_dates
170 transaction_postings t =
172 [ Compose $ transaction_postings t
173 , Compose $ transaction_virtual_postings t
174 , Compose $ transaction_balanced_virtual_postings t
176 transaction_postings_filter f t =
177 t{ transaction_postings =
179 (\p -> case filter f p of
182 (transaction_postings t)
183 , transaction_virtual_postings =
185 (\p -> case filter f p of
188 (transaction_virtual_postings t)
189 , transaction_balanced_virtual_postings =
191 (\p -> case filter f p of
194 (transaction_balanced_virtual_postings t)
196 instance GL.Transaction (Chart, Transaction) where
197 type Transaction_Posting (Chart, Transaction) = (Chart, GL.Transaction_Posting Transaction)
198 type Transaction_Postings (Chart, Transaction) = GL.Transaction_Postings Transaction
199 transaction_date = GL.transaction_date . snd
200 transaction_postings (c, t) = fmap (c,) $ GL.transaction_postings t
201 transaction_postings_filter f (c, t) =
202 (c, t{ transaction_postings =
204 (\p -> case filter f $ fmap (c,) p of
206 ps -> Just $ fmap snd ps)
207 (transaction_postings t)
208 , transaction_virtual_postings =
210 (\p -> case filter f $ fmap (c,) p of
212 ps -> Just $ fmap snd ps)
213 (transaction_virtual_postings t)
214 , transaction_balanced_virtual_postings =
216 (\p -> case filter f $ fmap (c,) p of
218 ps -> Just $ fmap snd ps)
219 (transaction_balanced_virtual_postings t)
222 -- | Return a 'Data.Map.Map' associating
223 -- the given 'Transaction's with their respective 'Date'.
224 transaction_by_Date :: [Transaction] -> (Compose (Map Date) []) Transaction
225 transaction_by_Date =
227 Data.Map.fromListWith (flip (++)) .
228 Data.List.map (\t -> (fst $ transaction_dates t, [t]))
234 { posting_account :: Account.Account_Path
235 , posting_amounts :: Map Amount.Unit Amount
236 , posting_comments :: [Comment]
237 , posting_dates :: [Date]
238 , posting_sourcepos :: SourcePos
239 , posting_status :: Bool
240 , posting_tags :: Tag.Tags
241 } deriving (Data, Eq, Show, Typeable)
243 instance Filter.Account (Chart, Account.Account_Path) where
245 account_tags (c, a) = Chart.account_tags a c
247 posting :: Account.Account_Path -> Posting
250 { posting_account = acct
251 , posting_amounts = mempty
252 , posting_comments = mempty
253 , posting_dates = mempty
254 , posting_status = False
255 , posting_sourcepos = initialPos ""
256 , posting_tags = mempty
259 instance Balance.Posting Posting where
260 type Posting_Amount Posting = Amount.Sum Amount
261 posting_account = posting_account
262 posting_amounts = Data.Map.map Amount.sum . posting_amounts
263 posting_set_amounts amounts p =
264 p { posting_amounts=Data.Map.map Amount.sum_balance amounts }
266 instance Balance.Posting (Chart, Posting) where
267 type Posting_Amount (Chart, Posting) = Amount.Sum Amount
268 posting_account = posting_account . snd
269 posting_amounts = Data.Map.map Amount.sum . posting_amounts . snd
270 posting_set_amounts amounts (c, p) =
271 (c, p { posting_amounts=Data.Map.map Amount.sum_balance amounts })
273 instance Filter.Posting (Chart, Posting) where
274 type Posting_Account (Chart, Posting) = (Chart, Account.Account_Path)
275 type Posting_Amount (Chart, Posting) = Amount
276 posting_account (c, p) = (c, posting_account p)
277 posting_amounts = posting_amounts . snd
278 posting_type = undefined
279 -- NOTE: the posting_type will be given to Filter.test
280 -- through instance Posting p => Posting (Posting_Type, p)
281 -- by Filter.transaction_postings
282 -- and Filter.transaction_postings_virtual
284 instance GL.Posting Posting where
285 type Posting_Amount Posting = Amount.Sum (Map Amount.Unit Amount)
286 posting_account = posting_account
287 posting_amount = Amount.sum . posting_amounts
289 instance GL.Posting (Chart, Posting) where
290 type Posting_Amount (Chart, Posting) = GL.Posting_Amount Posting
291 posting_account = posting_account . snd
292 posting_amount = Amount.sum . posting_amounts . snd
294 instance Stats.Posting Posting where
295 type Posting_Amount Posting = Amount
296 posting_account = posting_account
297 posting_amounts = posting_amounts
299 -- ** 'Posting' mappings
301 type Posting_by_Account
302 = Map Account.Account_Path [Posting]
304 type Posting_by_Amount_and_Account
305 = Map Amount.By_Unit Posting_by_Account
307 type Posting_by_Signs_and_Account
308 = Map Amount.Signs Posting_by_Account
310 -- | Return a Data.'Data.Map.Map' associating the given 'Posting's with their respective 'Account'.
311 posting_by_Account :: [Posting] -> Posting_by_Account
313 Data.Map.fromListWith (flip (++)) .
315 (\p -> (posting_account p, [p]))
317 posting_by_Amount_and_Account :: Posting_by_Account -> Posting_by_Amount_and_Account
318 posting_by_Amount_and_Account =
319 Data.Map.foldlWithKey
324 (Data.Map.unionWith (++))
326 (Data.Map.singleton acct [p])))))
329 posting_by_Signs_and_Account :: Posting_by_Account -> Posting_by_Signs_and_Account
330 posting_by_Signs_and_Account =
331 Data.Map.foldlWithKey
336 (Data.Map.unionWith (++))
337 (Amount.signs $ posting_amounts p)
338 (Data.Map.singleton acct [p])))))