Skip to content

Commit 92e8e52

Browse files
authored
Recognize declined transactions from OK responses (#9)
1 parent 9300166 commit 92e8e52

3 files changed

Lines changed: 37 additions & 9 deletions

File tree

connexpay/src/Web/Connexpay/Payments.hs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module Web.Connexpay.Payments
55
, ExpirationDate(..)
66
, Customer(..)
77
, RiskData(..)
8+
, AuthorizeResult(..)
89
, AuthResponse(..)
910
, TransactionStatus(..)
1011
, authorisePayment
@@ -26,12 +27,13 @@ import Web.Connexpay.Types
2627

2728
-- | Authorise a credit card payment.
2829
authorisePayment
29-
:: Connexpay -> Env -> AuthRequest -> IO (Response AuthError AuthResponse)
30-
authorisePayment connexpay env raw = guessResponseErrorType guessAuthError <$>
31-
doRequest connexpay env "authonlys" RequestBody
32-
{ raw
33-
, logMasker = maskAuthRequest
34-
}
30+
:: Connexpay -> Env -> AuthRequest -> IO (Response AuthError AuthorizeResult)
31+
authorisePayment connexpay env raw =
32+
bimapResponse (guessErrorType guessAuthError) postProcessAuthResponse <$>
33+
doRequest connexpay env "authonlys" RequestBody
34+
{ raw
35+
, logMasker = maskAuthRequest
36+
}
3537

3638
-- | Void payment
3739
voidPayment :: Connexpay -> Env -> VoidRequest -> IO (Response () ())

connexpay/src/Web/Connexpay/Payments/Types.hs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Web.Connexpay.Payments.Types where
66
import Data.Aeson
77
import Data.Aeson.TH
88
import Data.Fixed
9+
import Data.Function
910
import Data.Int (Int32)
1011
import Data.Maybe
1112
import Data.Text (Text)
@@ -116,13 +117,38 @@ instance ToJSON RiskData where
116117
maskRiskData :: LogMasker RiskData
117118
maskRiskData = id
118119

120+
data AuthorizeResult
121+
= Authorized AuthResponse
122+
-- ^ Transaction has been created and authorized successfully
123+
| Declined AuthResponse
124+
-- ^ Transaction has been created, but not authorized,
125+
-- e.g. declined by internal Connexpay fraud checks
126+
| Ambiguous AuthResponse
127+
-- ^ We can't interpret the result, e.g. wasProcess=true,
128+
-- but transaction status is not approved.
129+
-- Something for further investigation.
130+
deriving stock (Show)
131+
132+
postProcessAuthResponse :: AuthResponse -> AuthorizeResult
133+
postProcessAuthResponse resp = resp & case (completed, statusOk) of
134+
(True, True) -> Authorized
135+
(False, False) -> Declined
136+
_ -> Ambiguous
137+
where
138+
-- Connexpay documentation is not very clear about 'wasProcessed' semantics
139+
-- when it is missing, so we are intentionally strict here with the idea
140+
-- to warn about all 'Ambiguous' cases and adjust this code accordingly.
141+
completed = resp.wasProcessed == Just True
142+
statusOk = resp.status `elem` [TransactionApproved, TransactionApprovedWarning]
143+
119144
data AuthResponse = AuthResponse
120145
{ guid :: AuthOnlyGuid
121146
, status :: TransactionStatus
122147
, processorStatusCode :: Maybe Text
123148
, processorResponseMessage :: Maybe Text
124149
, addressVerificationCode :: Maybe Text
125150
, cvvVerificationCode :: Maybe Text
151+
, wasProcessed :: Maybe Bool
126152
} deriving stock (Show)
127153

128154
-- | Transaction status in Connexpay
@@ -139,7 +165,7 @@ data TransactionStatus
139165
-- ^ Processor errored out
140166
| TransactionOther Text
141167
-- ^ In case they return something unexpected
142-
deriving stock (Show)
168+
deriving stock (Eq, Show)
143169

144170
instance FromJSON TransactionStatus where
145171
parseJSON = withText "TransactionStatus" $ pure . \case

connexpay/src/Web/Connexpay/Types.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ bimapResponse f g = \case
6767
BadRequest body -> BadRequest body
6868
MissingOrExpiredToken -> MissingOrExpiredToken
6969

70-
guessResponseErrorType :: (Error () -> e) -> Response () a -> Response e a
71-
guessResponseErrorType mkErr = bimapResponse (\e -> e { errorType = mkErr e }) id
70+
guessErrorType :: (Error () -> e) -> Error () -> Error e
71+
guessErrorType mkErr e = e { errorType = mkErr e }
7272

7373
data Error e = Error
7474
{ message :: Text

0 commit comments

Comments
 (0)