git.iko.soy/typeable/connexpay
on master help sign in
Improve error handling a bit more.
50c8a0eNick
connexpay/src/Web/Connexpay.hs+5−2
@@ -1,11 +1,14 @@
1module Web.Connexpay ( module Payments
1module Web.Connexpay ( module Payments
2 , initConnexpay
2 , initConnexpay
3− , Connexpay
3+ , Connexpay(..)
4 , ConnexpayM
4 , ConnexpayM
5 , PaymentError(..)
5 , PaymentError(..)
6+ , PaymentFailure(..)
7+ , describeFailure
6 , runConnexpay
8 , runConnexpay
7 ) where
9 ) where
8
10
11+import Web.Connexpay.Data
9import Web.Connexpay.Init
12import Web.Connexpay.Init
10import Web.Connexpay.Payments as Payments
13import Web.Connexpay.Payments as Payments
11−import Web.Connexpay.Types as Export
14+import Web.Connexpay.Types
connexpay/src/Web/Connexpay/Data.hs+45−1
@@ -1,11 +1,17 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2−module Web.Connexpay.Data ( TransactionStatus (..)
2+module Web.Connexpay.Data ( TransactionStatus(..)
3+ , PaymentFailure(..)
4+ , describeFailure
5+ , guessFailure
6+ , ErrorMessage(..)
7+ , PaymentError(..)
3 ) where
8 ) where
4
9
5import Data.Aeson
10import Data.Aeson
6import Data.Aeson.Types
11import Data.Aeson.Types
7import Data.Maybe (fromMaybe)
12import Data.Maybe (fromMaybe)
8import Data.Text (Text)
13import Data.Text (Text)
14+import Network.HTTP.Client
9
15
10-- | Transaction status in Connexpay
16-- | Transaction status in Connexpay
11-- The list is taken from https://docs.connexpay.com/reference/search-sales
17-- The list is taken from https://docs.connexpay.com/reference/search-sales
@@ -30,3 +36,41 @@ statuses = [ ( "Transaction - Approved", TransactionApproved )
30instance FromJSON TransactionStatus where
36instance FromJSON TransactionStatus where
31 parseJSON (String s) = pure (fromMaybe (TransactionOther s) (lookup s statuses))
37 parseJSON (String s) = pure (fromMaybe (TransactionOther s) (lookup s statuses))
32 parseJSON v = typeMismatch "TransactionStatus" v
38 parseJSON v = typeMismatch "TransactionStatus" v
39+
40+-- | Payment failure types.
41+-- This type describes failures that related to either credit card being invalid,
42+-- client account having insufficient funds, and other non-technical conditions.
43+-- FIXME: this list is not exhaustive. Add more values whenever we encounter them.
44+data PaymentFailure = CVVFailed -- ^ CVV verification failure
45+ | CardInvalid -- ^ Credit card details are invalid
46+ | InvalidAmount -- ^ Money amount is invalid
47+ | LocalTransaction -- ^ Special case for transactions that were registered but did't go through somehow.
48+ deriving (Eq, Show)
49+
50+describeFailure :: PaymentFailure -> Text
51+describeFailure CVVFailed = "CVV authorisation failure"
52+describeFailure CardInvalid = "Invalid credit card details"
53+describeFailure InvalidAmount = "Invalid amount of money requested"
54+describeFailure LocalTransaction = "Transaction registered but not processed. Consult with payment processor."
55+
56+-- | Guess failure type from HTTP code and supplied error string.
57+guessFailure :: Int -> Text -> Maybe PaymentFailure
58+guessFailure 422 "Error code D2020. CVV2 verification failed." = Just CVVFailed
59+guessFailure 422 "Error code D2005. Invalid Card." = Just CardInvalid
60+guessFailure 422 "Amount field don't allow a value greater than $999,999.99" = Just InvalidAmount
61+guessFailure _ _ = Nothing
62+
63+-- | Error response from Connexpay
64+data ErrorMessage = ErrorMessage { message :: Text
65+ , errorId :: Text }
66+
67+instance FromJSON ErrorMessage where
68+ parseJSON (Object o) = ErrorMessage <$> o .: "message"
69+ <*> o .: "errorId"
70+ parseJSON v = typeMismatch "ErrorMessage" v
71+
72+data PaymentError = ParseError String
73+ | InvalidUrl String String
74+ | HttpFailure HttpExceptionContent
75+ | PaymentFailure PaymentFailure
76+ deriving (Show)
connexpay/src/Web/Connexpay/Init.hs+1
@@ -2,6 +2,7 @@
2module Web.Connexpay.Init where
2module Web.Connexpay.Init where
3
3
4import Web.Connexpay.Auth
4import Web.Connexpay.Auth
5+import Web.Connexpay.Data
5import Web.Connexpay.Types
6import Web.Connexpay.Types
6import Web.Connexpay.Utils
7import Web.Connexpay.Utils
7
8
connexpay/src/Web/Connexpay/Types.hs+1−33
@@ -1,6 +1,7 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2module Web.Connexpay.Types where
2module Web.Connexpay.Types where
3
3
4+import Web.Connexpay.Data
4import Web.Connexpay.Utils
5import Web.Connexpay.Utils
5
6
6import Control.Concurrent.Async
7import Control.Concurrent.Async
@@ -9,7 +10,6 @@ import Control.Monad.Except (MonadError, ExceptT, runExceptT, throwError)
9import Control.Monad.IO.Class
10import Control.Monad.IO.Class
10import Control.Monad.Reader
11import Control.Monad.Reader
11import Data.Aeson
12import Data.Aeson
12−import Data.Aeson.Types (typeMismatch)
13import Data.Text (Text)
13import Data.Text (Text)
14import Data.Text qualified as Text
14import Data.Text qualified as Text
15import Data.UUID (UUID)
15import Data.UUID (UUID)
@@ -32,38 +32,6 @@ data Connexpay = Connexpay { logAction :: Text -> IO ()
32 , password :: Text
32 , password :: Text
33 }
33 }
34
34
35−-- | Payment failure types.
36−-- This type describes failures that related to either credit card being invalid,
37−-- client account having insufficient funds, and other non-technical conditions.
38−-- FIXME: this list is not exhaustive. Add more values whenever we encounter them.
39−data PaymentFailure = CVVFailed -- ^ CVV verification failure
40− | CardInvalid -- ^ Credit card details are invalid
41− | InvalidAmount -- ^ Money amount is invalid
42− | LocalTransaction -- ^ Special case for transactions that were registered but did't go through somehow.
43− deriving (Eq, Show)
44−
45−-- | Guess failure type from HTTP code and supplied error string.
46−guessFailure :: Int -> Text -> Maybe PaymentFailure
47−guessFailure 422 "Error code D2020. CVV2 verification failed." = Just CVVFailed
48−guessFailure 422 "Error code D2005. Invalid Card." = Just CardInvalid
49−guessFailure 422 "Amount field don't allow a value greater than $999,999.99" = Just InvalidAmount
50−guessFailure _ _ = Nothing
51−
52−-- | Error response from Connexpay
53−data ErrorMessage = ErrorMessage { message :: Text
54− , errorId :: Text }
55−
56−instance FromJSON ErrorMessage where
57− parseJSON (Object o) = ErrorMessage <$> o .: "message"
58− <*> o .: "errorId"
59− parseJSON v = typeMismatch "ErrorMessage" v
60−
61−data PaymentError = ParseError String
62− | InvalidUrl String String
63− | HttpFailure HttpExceptionContent
64− | PaymentFailure PaymentFailure
65− deriving (Show)
66−
67newtype ConnexpayM a = ConnexpayM (ReaderT Connexpay (ExceptT PaymentError IO) a)
35newtype ConnexpayM a = ConnexpayM (ReaderT Connexpay (ExceptT PaymentError IO) a)
68 deriving (Functor, Applicative, Monad, MonadIO, MonadReader Connexpay, MonadError PaymentError)
36 deriving (Functor, Applicative, Monad, MonadIO, MonadReader Connexpay, MonadError PaymentError)
69
37