diff --git a/src/Bank/TrueLayer/DataAPI/Accounts.hs b/src/Bank/TrueLayer/DataAPI/Accounts.hs index ccd5cd8..a58c64d 100644 --- a/src/Bank/TrueLayer/DataAPI/Accounts.hs +++ b/src/Bank/TrueLayer/DataAPI/Accounts.hs @@ -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") diff --git a/src/Bank/TrueLayer/DataAPI/Cards.hs b/src/Bank/TrueLayer/DataAPI/Cards.hs index 408cce0..d5c3179 100644 --- a/src/Bank/TrueLayer/DataAPI/Cards.hs +++ b/src/Bank/TrueLayer/DataAPI/Cards.hs @@ -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 diff --git a/src/Bank/TrueLayer/DataAPI/Schema.hs b/src/Bank/TrueLayer/DataAPI/Schema.hs index 7132766..580ee85 100644 --- a/src/Bank/TrueLayer/DataAPI/Schema.hs +++ b/src/Bank/TrueLayer/DataAPI/Schema.hs @@ -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] } @@ -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) @@ -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 diff --git a/src/Bank/TrueLayer/Internal.hs b/src/Bank/TrueLayer/Internal.hs index b9274dd..d09622a 100644 --- a/src/Bank/TrueLayer/Internal.hs +++ b/src/Bank/TrueLayer/Internal.hs @@ -4,6 +4,7 @@ module Bank.TrueLayer.Internal , postWithAuth , defaults , header + , param , fromString , (.~) , (&) @@ -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