Skip to content

Commit

Permalink
Merge pull request #1 from RileyEv/transactions
Browse files Browse the repository at this point in the history
Add Transactions API
  • Loading branch information
RileyEv authored Feb 13, 2022
2 parents 2aef3e3 + 9399e85 commit 14b566f
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 26 deletions.
50 changes: 45 additions & 5 deletions src/Bank/TrueLayer/DataAPI/Accounts.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,52 @@ module Bank.TrueLayer.DataAPI.Accounts
( accounts
) where

import Bank.TrueLayer.DataAPI.Schema (Accounts)
import Bank.TrueLayer.DataAPI.Schema
( AccountBalances
, AccountId (..)
, Accounts
, DirectDebits
, Ip (..)
, StandingOrders
, TransactionParams
, Transactions
, addTransactionParams
)
import Bank.TrueLayer.Internal
(AccessToken, Endpoint, defaults, fromString, getWithAuthAndOptions, header, (&), (.~))
(AccessToken, Endpoint, defaults, fromString, getWithAuthAndOptions, header, (&), (.~), (</>))


accounts :: String -> Endpoint -> AccessToken -> IO (Maybe Accounts)
accounts ip = do
accounts :: Ip -> Endpoint -> AccessToken -> IO (Maybe Accounts)
accounts (Ip ip) = do
let opts = defaults & header "X-PSU-IP" .~ [fromString ip]
getWithAuthAndOptions defaults "/data/v1/accounts"
getWithAuthAndOptions opts "/data/v1/accounts"

account :: Ip -> AccountId -> Endpoint -> AccessToken -> IO (Maybe Accounts)
account (Ip ip) (AccountId accountId) = do
let opts = defaults & header "X-PSU-IP" .~ [fromString ip]
getWithAuthAndOptions opts ("/data/v1/accounts" </> accountId)

accountBalance :: Ip -> AccountId -> Endpoint -> AccessToken -> IO (Maybe AccountBalances)
accountBalance (Ip ip) (AccountId accountId) = do
let opts = defaults & header "X-PSU-IP" .~ [fromString ip]
getWithAuthAndOptions opts ("/data/v1/accounts" </> accountId </> "balance")

transactions :: Ip -> AccountId -> Maybe TransactionParams -> Endpoint -> AccessToken -> IO (Maybe Transactions)
transactions (Ip ip) (AccountId accountId) params endpoint accessToken = do
opts <- addTransactionParams params (defaults & header "X-PSU-IP" .~ [fromString ip])
getWithAuthAndOptions opts ("/data/v1/accounts" </> accountId </> "transactions")endpoint accessToken

pendingTransactions :: Ip -> AccountId -> Maybe TransactionParams -> Endpoint -> AccessToken -> IO (Maybe Transactions)
pendingTransactions (Ip ip) (AccountId accountId) params endpoint accessToken = do
opts <- addTransactionParams params (defaults & header "X-PSU-IP" .~ [fromString ip])
getWithAuthAndOptions opts ("/data/v1/accounts" </> accountId </> "transactions/pending") endpoint accessToken

standingOrders :: Ip -> AccountId -> Endpoint -> AccessToken -> IO (Maybe StandingOrders)
standingOrders (Ip ip) (AccountId accountId) = do
let opts = defaults & header "X-PSU-IP" .~ [fromString ip]
getWithAuthAndOptions opts ("/data/v1/accounts" </> accountId </> "standing-orders")

directDebits :: Ip -> AccountId -> Endpoint -> AccessToken -> IO (Maybe DirectDebits)
directDebits (Ip ip) (AccountId accountId) = do
let opts = defaults & header "X-PSU-IP" .~ [fromString ip]
getWithAuthAndOptions opts ("/data/v1/accounts" </> accountId </> "direct-debits")
51 changes: 43 additions & 8 deletions src/Bank/TrueLayer/DataAPI/Cards.hs
Original file line number Diff line number Diff line change
@@ -1,20 +1,55 @@
module Bank.TrueLayer.DataAPI.Cards
( cards
, card
, cardBalance
) where

import Bank.TrueLayer.Internal
(AccessToken, Endpoint, defaults, fromString, getWithAuthAndOptions, header, (&), (.~), (</>))
( AccessToken
, Endpoint
, Options
, defaults
, fromString
, getWithAuthAndOptions
, header
, param
, (&)
, (.~)
, (</>)
)

import Bank.TrueLayer.DataAPI.Schema (AccountId (..), CardBalances, Cards)
import Bank.TrueLayer.DataAPI.Schema
( AccountId (..)
, Card
, CardBalances
, Cards
, Ip (..)
, TransactionParams
, Transactions
, addTransactionParams
)

cards :: String -> Endpoint -> AccessToken -> IO (Maybe Cards)
cards ip = do
cards :: Ip -> Endpoint -> AccessToken -> IO (Maybe Cards)
cards (Ip ip) = do
let opts = defaults & header "X-PSU-IP" .~ [fromString ip]
getWithAuthAndOptions defaults "/data/v1/cards"
getWithAuthAndOptions opts "/data/v1/cards"

card :: Ip -> AccountId -> Endpoint -> AccessToken -> IO (Maybe Cards)
card (Ip ip) (AccountId accountId) = do
let opts = defaults & header "X-PSU-IP" .~ [fromString ip]
getWithAuthAndOptions opts ("/data/v1/cards" </> accountId)

cardBalance :: String -> AccountId -> Endpoint -> AccessToken -> IO (Maybe CardBalances)
cardBalance ip (AccountId accountId) = do
cardBalance :: Ip -> AccountId -> Endpoint -> AccessToken -> IO (Maybe CardBalances)
cardBalance (Ip ip) (AccountId accountId) = do
let opts = defaults & header "X-PSU-IP" .~ [fromString ip]
getWithAuthAndOptions defaults ("/data/v1/cards" </> accountId </> "balance")
getWithAuthAndOptions opts ("/data/v1/cards" </> accountId </> "balance")

transactions :: Ip -> AccountId -> Maybe TransactionParams -> Endpoint -> AccessToken -> IO (Maybe Transactions)
transactions (Ip ip) (AccountId accountId) params endpoint accessToken = do
opts <- addTransactionParams params (defaults & header "X-PSU-IP" .~ [fromString ip])
getWithAuthAndOptions opts ("/data/v1/cards" </> accountId </> "transactions") endpoint accessToken

pendingTransactions :: Ip -> AccountId -> Maybe TransactionParams -> Endpoint -> AccessToken -> IO (Maybe Transactions)
pendingTransactions (Ip ip) (AccountId accountId) params endpoint accessToken = do
opts <- addTransactionParams params (defaults & header "X-PSU-IP" .~ [fromString ip])
getWithAuthAndOptions opts ("/data/v1/cards" </> accountId </> "transactions/pending") endpoint accessToken
158 changes: 146 additions & 12 deletions src/Bank/TrueLayer/DataAPI/Schema.hs
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
module Bank.TrueLayer.DataAPI.Schema
( Accounts(..)
, AccountId(..)
, Cards(..)
, Card(..)
, CardBalances(..)
) where
{-# LANGUAGE RecordWildCards #-}
module Bank.TrueLayer.DataAPI.Schema where

import Data.Aeson (FromJSON (..), ToJSON (..))
import Data.Time.Calendar (Day)
import Data.Time.LocalTime (ZonedTime)
import Data.Aeson (FromJSON (..), ToJSON (..))
import Data.String (IsString)
import Data.Time.Calendar (Day)
import Data.Time.LocalTime (ZonedTime)
import GHC.Generics (Generic)

import Bank.TrueLayer.Internal (Options, fromString, param, (&), (.~))
import Text.Read.Lex (Number)

newtype Ip = Ip String
deriving (Show)

import GHC.Generics (Generic)


newtype Accounts = Accounts { results :: [Account] }
Expand All @@ -30,6 +32,22 @@ data Account = Account
}
deriving (FromJSON, Generic, Show, ToJSON)

data AccountBalance = AccountBalance
{ currency :: String
, available :: Double
, current :: Double
, overdraft :: Maybe Double
, update_timestamp :: Maybe String
}
deriving (FromJSON, Generic, Show, ToJSON)

data AccountBalances = AccountBalances
{ results :: [AccountBalance]
, status :: Maybe String
}
deriving (FromJSON, Generic, Show, ToJSON)


newtype AccountId = AccountId String
deriving (FromJSON, Generic, Show, ToJSON)

Expand Down Expand Up @@ -77,6 +95,122 @@ data CardBalance = CardBalance
}
deriving (FromJSON, Generic, Show, ToJSON)

data DirectDebit = DirectDebit
{ direct_debit_id :: String
, timestamp :: String
, name :: String
, status :: String
, previous_payment_timestamp :: Maybe String
, previous_payment_amount :: Maybe Double
, currency :: Maybe String
, meta :: Maybe DirectDebitMeta
}
deriving (FromJSON, Generic, Show, ToJSON)

data DirectDebitMeta = DirectDebitMeta
{ provider_mandate_identification :: Maybe String
, provider_account_id :: Maybe String
}
deriving (FromJSON, Generic, Show, ToJSON)

data DirectDebits = DirectDebits
{ results :: [DirectDebit]
, status :: String
}
deriving (FromJSON, Generic, Show, ToJSON)


newtype Provider = Provider { provider_id :: ProviderId }
deriving (FromJSON, Generic, Show, ToJSON)

newtype ProviderId = ProviderId String
deriving (FromJSON, Generic, Show, ToJSON)

data RunningBalance = RunningBalance
{ amoung :: Double
, currency :: String
}
deriving (FromJSON, Generic, Show, ToJSON)

data StandingOrder = StandingOrder
{ frequency :: String
, status :: Maybe String
, timestamp :: String
, currency :: Maybe String
, meta :: Maybe StandingOrderMeta
, next_payment_date :: Maybe String
, next_payment_amount :: Maybe Double
, first_payment_date :: Maybe String
, first_payment_amount :: Maybe Double
, final_payment_date :: Maybe String
, final_payment_amount :: Maybe Double
, payee :: Maybe String
, reference :: Maybe String
}
deriving (FromJSON, Generic, Show, ToJSON)

newtype StandingOrderMeta = StandingOrderMeta { provider_account_id :: Maybe String }
deriving (FromJSON, Generic, Show, ToJSON)

data StandingOrders = StandingOrders
{ results :: [StandingOrder]
, status :: String
}
deriving (FromJSON, Generic, Show, ToJSON)

data Transaction = Transaction
{ transaction_id :: TransactionId
, normalised_provider_transaction_id :: Maybe TransactionId
, provider_transaction_id :: Maybe TransactionId
, timestamp :: ZonedTime
, description :: String
, amount :: Double -- pounds
, currency :: String
, transaction_type :: String
, transaction_category :: String
, transaction_classification :: [String]
, merchant_name :: Maybe String
, running_balance :: Maybe RunningBalance
, meta :: Maybe TransactionMeta
}
deriving (FromJSON, Generic, Show, ToJSON)

data TransactionMeta = TransactionMeta
{ provider_transaction_category :: Maybe String
, provider_reference :: Maybe String
, provider_merchant_name :: Maybe String
, provider_category :: Maybe String
, address :: Maybe String
, provider_id :: Maybe ProviderId
, counter_party_preferred_name :: Maybe String
, counter_party_iban :: Maybe String
, user_comments :: Maybe String
, debtor_account_name :: Maybe String
, transaction_type :: Maybe String
, provider_source :: Maybe String
, cardNumber :: Maybe String
, location :: Maybe String
}
deriving (FromJSON, Generic, Show, ToJSON)

newtype Provider = Provider { provider_id :: String }
newtype TransactionId = TransactionId String
deriving (FromJSON, Generic, Show, ToJSON)

newtype Transactions = Transactions { results :: [Transaction] }
deriving (FromJSON, Generic, Show, ToJSON)

data TransactionParams = TransactionParams
{ to :: Maybe String
, from :: Maybe String
}
deriving (Show)

addTransactionParams :: Maybe TransactionParams -> Options -> IO Options
addTransactionParams (Just TransactionParams{..}) opts = do
opts <- case to of
Just to -> return $ opts & param "to" .~ [fromString to]
Nothing -> return opts
case from of
Just from -> return $ opts & param "from" .~ [fromString from]
Nothing -> return opts
addTransactionParams Nothing opts = return opts
3 changes: 2 additions & 1 deletion src/Bank/TrueLayer/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Bank.TrueLayer.Internal
, postWithAuth
, defaults
, header
, param
, fromString
, (.~)
, (&)
Expand All @@ -19,7 +20,7 @@ import Data.String (fromString)
import Data.Text.Encoding (encodeUtf8)
import Network.OAuth.OAuth2 (AccessToken (..))
import Network.Wreq
(Options, asJSON, auth, defaults, getWith, header, oauth2Bearer, postWith, responseBody)
(Options, asJSON, auth, defaults, getWith, header, oauth2Bearer, param, postWith, responseBody)
import System.FilePath ((</>))

newtype Endpoint = Endpoint String
Expand Down

0 comments on commit 14b566f

Please sign in to comment.