packages feed

csv-to-qif-0.3: src/Qifer.hs

-----------------------------------------------------------------------------
--
-- Module      :  Qifer
-- Copyright   :  (c) Ingolf Wagner
-- License     :  BSD3
--
-- Maintainer  :  Ingolf Wagner <palipalo9@googlemail.com>
-- Stability   :  unstable
-- Portability :
--
-- |
--
-----------------------------------------------------------------------------

module Qifer where

import Data.List
import Text.Regex.TDFA

type CSV = [Row]
type Row = [Column]
type Column = String

data Transaction = Transaction { date :: String
                                , description :: String
                                , text :: String
                                , balance :: String
                               } deriving (Eq,Show)

type Position = Int

data Rule = Rule { dateField :: Position
                   , descField :: [Position]
                   , textField :: [Position]
                   , balanceField :: Position
                 } deriving (Show)

highestPosition :: Rule -> Position
highestPosition (Rule dF tF ltF bF) =
    maximum . concat $ [[dF],tF,ltF,[bF]]

toTransactions :: Rule -> CSV -> [Transaction]
toTransactions _ []        = []
toTransactions rule (c:sv)
    | (highestPosition rule) >= (length c) = stepDeeper
    | otherwise                            = transform : stepDeeper
    where pick n     = (c !! (n rule))
          pock n     = concat . intersperse " " . map (\k -> c !! k ) $ (n rule)
          stepDeeper = toTransactions rule sv
          transform  = (Transaction (pick dateField)
                                    (pock descField)
                                    (pock textField)
                                    (pick balanceField))

qifHeader :: String
qifHeader = "!Type:Bank"

toQif :: Transaction -> [String]
toQif trans = ["P" ++ d, "T" ++ money, "D" ++ time, "M" ++ msg]
    where   d     = (description trans)
            money = (balance trans)
            time  = (date trans)
            msg   = (text trans)

transToQif :: [Transaction] -> [String]
transToQif trans = qifHeader : (foo trans)
    where   foo []     = []
            foo (t:ts) = (toQif t) ++ ["^"] ++ (foo ts)

-- | updates a Transaction if regex works
updateTransaction :: String -> String -> Transaction -> Transaction
updateTransaction regex replacement transaction =
    transaction { description = updateDesc }
    where
        updateDesc  = if matches then replacement else (description transaction)
        matches     = (description transaction) =~ regex :: Bool

-- | very inefficient but better than nothing
update :: [(String,String)] -> [Transaction] -> [Transaction]
update _ []         = []
update regex (t:ts) = (updateSingle regex t) : (update regex ts)
    where
        updateSingle [] r                                 = r
        updateSingle ((rgx,replacement):rest) transaction =
            if updatedTrans == transaction
            then
                updateSingle rest transaction
            else
                updatedTrans
            where
                updatedTrans = updateTransaction rgx replacement transaction