packages feed

snelstart-import-1.0.0: src/SnelstartImport/N26.hs

{-# LANGUAGE DeriveAnyClass #-}
-- | this is whatever N26 spits out, it's some custom csv format.
--   it appears unstable. (has changed once before)
module SnelstartImport.N26
  ( readN26,
    readN26BS,
    N26 (..),
    TransactionType(..),
    Date(..)
  )
where

import SnelstartImport.Currency
import Data.Text
import Data.Text.Encoding
import Data.Csv
import Data.Time
import GHC.Generics
import qualified Data.ByteString.Lazy as BS
import Data.Vector

data MutatieSoort = Overschijving | Diversen | Incasso
  deriving Show

data BijAf = Bij | Af
  deriving Show

data TransactionType = MastercardPayment | OutgoingTransfer | Income | N26Referal | DirectDebit
  deriving stock (Show, Eq)


instance FromField TransactionType where
  parseField field = case decodeUtf8 field of
    "Presentment" -> pure MastercardPayment
    "Debit Transfer" -> pure OutgoingTransfer
    "Income" -> pure Income
    "Credit Transfer" -> pure Income
    "Presentment Refund" -> pure Income
    "Reward" -> pure N26Referal
    "Direct Debit" -> pure DirectDebit
    other -> fail $ "TransactionType unkown" <> unpack other

newtype Date = Date { unDate :: UTCTime }
  deriving newtype (Show, Eq, Read)

instance FromField Date where
  parseField field =
    fmap Date $ parseTimeM True defaultTimeLocale "%Y-%m-%d" $ unpack $ decodeUtf8 field

data N26 = N26  {
  date :: Date, -- booking date
  valueDate :: Date,
  payee :: Text, -- partner name
  accountNumber :: Text, -- partner iban
  transactionType :: TransactionType,
  paymentReference :: Text,
  accountName :: Text,
  amountEur :: Currency , -- amount (eur)
  amountForegin :: Maybe Currency , -- original amount
  typeForeign :: Text, -- original currency
  exchangeRate :: Text
  }
  deriving stock (Generic, Show, Eq)
  deriving anyclass FromRecord


readN26 :: FilePath -> IO (Either String (Vector N26))
readN26 path = do
  lines' <- BS.readFile path
  pure $ readN26BS lines'


readN26BS :: BS.ByteString -> Either String (Vector N26)
readN26BS = decode HasHeader