git.iko.soy/typeable/connexpay
on master help sign in
Improve error handling a bit more.
commit50c8a0e2204ba49e0a35526ae7c015788ef3468e authorNick <nick@typeable.io> dateTue 30 Apr 2024, 16:12 (2 years ago) parent234bf5b
4 files changed+52−36
connexpay/src/Web/Connexpay.hs+5−2 connexpay/src/Web/Connexpay/Data.hs+45−1 connexpay/src/Web/Connexpay/Init.hs+1 connexpay/src/Web/Connexpay/Types.hs+1−33
connexpay/src/Web/Connexpay.hs+5−2
@@ -1,11 +1,14 @@
11module Web.Connexpay ( module Payments
22 , initConnexpay
3− , Connexpay
3+ , Connexpay(..)
44 , ConnexpayM
55 , PaymentError(..)
6+ , PaymentFailure(..)
7+ , describeFailure
68 , runConnexpay
79 ) where
810
11+import Web.Connexpay.Data
912import Web.Connexpay.Init
1013import 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 @@
11{-# LANGUAGE OverloadedStrings #-}
2−module Web.Connexpay.Data ( TransactionStatus (..)
2+module Web.Connexpay.Data ( TransactionStatus(..)
3+ , PaymentFailure(..)
4+ , describeFailure
5+ , guessFailure
6+ , ErrorMessage(..)
7+ , PaymentError(..)
38 ) where
49
510import Data.Aeson
611import Data.Aeson.Types
712import Data.Maybe (fromMaybe)
813import Data.Text (Text)
14+import Network.HTTP.Client
915
1016-- | Transaction status in Connexpay
1117-- The list is taken from https://docs.connexpay.com/reference/search-sales
@@ -30,3 +36,41 @@ statuses = [ ( "Transaction - Approved", TransactionApproved )
3036instance FromJSON TransactionStatus where
3137 parseJSON (String s) = pure (fromMaybe (TransactionOther s) (lookup s statuses))
3238 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 @@
22module Web.Connexpay.Init where
33
44import Web.Connexpay.Auth
5+import Web.Connexpay.Data
56import Web.Connexpay.Types
67import Web.Connexpay.Utils
78
connexpay/src/Web/Connexpay/Types.hs+1−33
@@ -1,6 +1,7 @@
11{-# LANGUAGE OverloadedStrings #-}
22module Web.Connexpay.Types where
33
4+import Web.Connexpay.Data
45import Web.Connexpay.Utils
56
67import Control.Concurrent.Async
@@ -9,7 +10,6 @@ import Control.Monad.Except (MonadError, ExceptT, runExceptT, throwError)
910import Control.Monad.IO.Class
1011import Control.Monad.Reader
1112import Data.Aeson
12−import Data.Aeson.Types (typeMismatch)
1313import Data.Text (Text)
1414import Data.Text qualified as Text
1515import Data.UUID (UUID)
@@ -32,38 +32,6 @@ data Connexpay = Connexpay { logAction :: Text -> IO ()
3232 , password :: Text
3333 }
3434
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−
6735newtype ConnexpayM a = ConnexpayM (ReaderT Connexpay (ExceptT PaymentError IO) a)
6836 deriving (Functor, Applicative, Monad, MonadIO, MonadReader Connexpay, MonadError PaymentError)
6937