adyen/
payment.rs

1use super::action::Action;
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use std::fmt;
4
5#[derive(Serialize, Deserialize, Debug, Clone)]
6#[serde(rename_all = "camelCase")]
7pub struct AdditionalData {
8    pub card_holder_name: String,
9    pub issuer_country: String,
10    pub card_summary: String,
11    pub expiry_date: String,    // The expiry date on the card (M/yyyy).
12    pub payment_method: String, // visa, mastercard, etc.
13
14    /// The Adyen alias of the card.
15    /// https://docs.adyen.com/api-explorer/Checkout/latest/post/payments#responses-200-additionalData-listOfValues-alias
16    pub alias: Option<String>,
17    pub alias_type: Option<String>,
18
19    #[serde(rename = "recurring.recurringDetailReference")]
20    #[serde(skip_serializing_if = "Option::is_none")]
21    #[serde(default)]
22    pub recurring_detail_reference: Option<String>,
23}
24
25#[derive(Serialize, Deserialize, Debug, Clone)]
26#[serde(tag = "resultCode")]
27pub enum Response {
28    /// The payment has been successfully authenticated with 3D Secure 2. Returned for 3D Secure 2
29    /// authentication-only transactions.
30    #[serde(rename_all = "camelCase")]
31    AuthenticationFinished {},
32
33    /// The transaction does not require 3D Secure authentication. Returned for standalone
34    /// authentication-only integrations (cf.
35    /// https://docs.adyen.com/online-payments/3d-secure/other-3ds-flows/authentication-only).
36    #[serde(rename_all = "camelCase")]
37    AuthenticationNotRequired {},
38
39    /// The payment was successfully authorised. This state serves as an indicator to proceed with
40    /// the delivery of goods and services. This is a final state.
41    #[serde(rename_all = "camelCase")]
42    Authorised {
43        #[serde(skip_serializing_if = "Option::is_none")]
44        #[serde(default)]
45        additional_data: Option<AdditionalData>,
46
47        psp_reference: String,
48
49        merchant_reference: String,
50    },
51
52    /// Indicates the payment has been cancelled (either by the shopper or the merchant) before
53    /// processing was completed. This is a final state.
54    #[serde(rename_all = "camelCase")]
55    Cancelled {
56        #[serde(rename = "refusalReasonCode")]
57        #[serde(skip_serializing_if = "Option::is_none")]
58        #[serde(default)]
59        refusal_reason: Option<RefusalReason>,
60
61        psp_reference: String,
62    },
63
64    /// The issuer requires further shopper interaction before the payment can be authenticated.
65    /// Returned for 3D Secure 2 transactions.
66    ChallengeShopper { action: Action },
67
68    /// There was an error when the payment was being processed. The reason is given in the
69    /// refusalReason field. This is a final state.
70    #[serde(rename_all = "camelCase")]
71    Error {
72        #[serde(rename = "refusalReasonCode")]
73        refusal_reason: RefusalReason,
74
75        psp_reference: String,
76    },
77
78    /// The issuer requires the shopper's device fingerprint before the payment can be
79    /// authenticated. Returned for 3D Secure 2 transactions.
80    #[serde(rename_all = "camelCase")]
81    IdentifyShopper { action: Action },
82
83    /// The payment has been authorised for a partial amount. This happens for card payments when
84    /// the merchant supports Partial Authorisations and the cardholder has insufficient funds.
85    #[serde(rename_all = "camelCase")]
86    PartiallyAuthorised {},
87
88    /// Indicates that it is not possible to obtain the final status of the payment. This can
89    /// happen if the systems providing final status information for the payment are unavailable,
90    /// or if the shopper needs to take further action to complete the payment.
91    #[serde(rename_all = "camelCase")]
92    Pending { action: Action },
93
94    /// Indicates that the response contains additional information that you need to present to a
95    /// shopper, so that they can use it to complete a payment.
96    #[serde(rename_all = "camelCase")]
97    PresentToShopper {},
98
99    /// Indicates the payment has successfully been received by Adyen, and will be processed. This
100    /// is the initial state for all payments.
101    #[serde(rename_all = "camelCase")]
102    Received {},
103
104    /// Indicates the shopper should be redirected to an external web page or app to complete the
105    /// authorisation.
106    #[serde(rename_all = "camelCase")]
107    RedirectShopper { action: Action },
108
109    /// Indicates the payment was refused. The reason is given in the refusalReason field. This is
110    /// a final state.
111    #[serde(rename_all = "camelCase")]
112    Refused {
113        #[serde(rename = "refusalReasonCode")]
114        refusal_reason: RefusalReason,
115
116        psp_reference: String,
117    },
118}
119
120/// Represents various reasons why a transaction might be refused.
121/// https://docs.adyen.com/development-resources/refusal-reasons/
122#[derive(Clone, Debug, PartialEq)]
123pub enum RefusalReason {
124    /// The transaction was outright refused.
125    Refused,
126
127    /// The transaction needs a referral.
128    Referral,
129
130    /// An error occurred on the acquirer's end.
131    AcquirerError,
132
133    /// The card used is blocked and cannot be used for transactions.
134    BlockedCard,
135
136    /// The card has expired.
137    ExpiredCard,
138
139    /// The amount provided in the transaction does not match the expected amount.
140    InvalidAmount,
141
142    /// The card number provided is invalid.
143    InvalidCardNumber,
144
145    /// Could not contact the issuer to authorize the transaction.
146    IssuerUnavailable,
147
148    /// The type of transaction is not supported by the shopper's bank.
149    NotSupported,
150
151    /// 3D Secure authentication was not performed or failed.
152    ThreeDNotAuthenticated,
153
154    /// Insufficient funds in the account to cover the transaction.
155    NotEnoughBalance,
156
157    /// Possible fraud detected by the acquirer.
158    AcquirerFraud,
159
160    /// The transaction was cancelled by the system.
161    Cancelled,
162
163    /// The transaction was cancelled by the shopper.
164    ShopperCancelled,
165
166    /// The PIN entered is invalid.
167    InvalidPin,
168
169    /// The PIN was entered incorrectly too many times.
170    PinTriesExceeded,
171
172    /// The PIN could not be validated.
173    PinValidationNotPossible,
174
175    /// The transaction was flagged as fraudulent due to risk checks.
176    Fraud,
177
178    /// The transaction was not submitted correctly for processing.
179    NotSubmitted,
180
181    /// The transaction was flagged as fraudulent after both pre and post authorization checks.
182    FraudCancelled,
183
184    /// The transaction is not permitted based on various conditions.
185    TransactionNotPermitted,
186
187    /// The Card Verification Code (CVC) was declined.
188    CvcDeclined,
189
190    /// The card has restrictions or is invalid for the transaction context.
191    RestrictedCard,
192
193    /// The authorization for recurring transactions was revoked.
194    RevocationOfAuth,
195
196    /// A generic decline where the specific reason cannot be mapped accurately.
197    DeclinedNonGeneric,
198
199    /// The amount withdrawn exceeds the card's limit.
200    WithdrawalAmountExceeded,
201
202    /// The number of withdrawals exceeds the card's limit.
203    WithdrawalCountExceeded,
204
205    /// The issuer suspects fraud in the transaction.
206    IssuerSuspectedFraud,
207
208    /// Address Verification System (AVS) failed.
209    AvsDeclined,
210
211    /// The card requires an online PIN for the transaction.
212    CardRequiresOnlinePin,
213
214    /// The card does not have a checking account linked.
215    NoCheckingAccountAvailable,
216
217    /// The card does not have a savings account linked.
218    NoSavingsAccountAvailable,
219
220    /// A mobile PIN is required for the transaction.
221    MobilePinRequired,
222
223    /// The shopper abandoned the transaction after a contactless payment attempt failed.
224    ContactlessFallback,
225
226    /// Authentication is required for the transaction.
227    AuthenticationRequired,
228
229    /// The RReq was not received from DS during 3D Secure flow.
230    RReqNotReceived,
231
232    /// The current AID (Application Identifier) is in the penalty box.
233    CurrentAidInPenaltyBox,
234
235    /// Card Verification Method (CVM) like PIN or signature is required.
236    CvmRequiredRestartPayment,
237
238    /// An error occurred during 3D Secure authentication.
239    ThreeDsAuthenticationError,
240
241    /// Transaction blocked by Adyen to prevent excessive retry fees.
242    TransactionBlockedByAdyen,
243}
244
245impl Serialize for RefusalReason {
246    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
247    where
248        S: Serializer,
249    {
250        let code = match self {
251            RefusalReason::Refused => "2",
252            RefusalReason::Referral => "3",
253            RefusalReason::AcquirerError => "4",
254            RefusalReason::BlockedCard => "5",
255            RefusalReason::ExpiredCard => "6",
256            RefusalReason::InvalidAmount => "7",
257            RefusalReason::InvalidCardNumber => "8",
258            RefusalReason::IssuerUnavailable => "9",
259            RefusalReason::NotSupported => "10",
260            RefusalReason::ThreeDNotAuthenticated => "11",
261            RefusalReason::NotEnoughBalance => "12",
262            RefusalReason::AcquirerFraud => "14",
263            RefusalReason::Cancelled => "15",
264            RefusalReason::ShopperCancelled => "16",
265            RefusalReason::InvalidPin => "17",
266            RefusalReason::PinTriesExceeded => "18",
267            RefusalReason::PinValidationNotPossible => "19",
268            RefusalReason::Fraud => "20",
269            RefusalReason::NotSubmitted => "21",
270            RefusalReason::FraudCancelled => "22",
271            RefusalReason::TransactionNotPermitted => "23",
272            RefusalReason::CvcDeclined => "24",
273            RefusalReason::RestrictedCard => "25",
274            RefusalReason::RevocationOfAuth => "26",
275            RefusalReason::DeclinedNonGeneric => "27",
276            RefusalReason::WithdrawalAmountExceeded => "28",
277            RefusalReason::WithdrawalCountExceeded => "29",
278            RefusalReason::IssuerSuspectedFraud => "31",
279            RefusalReason::AvsDeclined => "32",
280            RefusalReason::CardRequiresOnlinePin => "33",
281            RefusalReason::NoCheckingAccountAvailable => "34",
282            RefusalReason::NoSavingsAccountAvailable => "35",
283            RefusalReason::MobilePinRequired => "36",
284            RefusalReason::ContactlessFallback => "37",
285            RefusalReason::AuthenticationRequired => "38",
286            RefusalReason::RReqNotReceived => "39",
287            RefusalReason::CurrentAidInPenaltyBox => "40",
288            RefusalReason::CvmRequiredRestartPayment => "41",
289            RefusalReason::ThreeDsAuthenticationError => "42",
290            RefusalReason::TransactionBlockedByAdyen => "46",
291        };
292        serializer.serialize_str(code)
293    }
294}
295
296impl<'de> Deserialize<'de> for RefusalReason {
297    fn deserialize<D>(deserializer: D) -> Result<RefusalReason, D::Error>
298    where
299        D: Deserializer<'de>,
300    {
301        struct RefusalReasonVisitor;
302
303        impl<'de> serde::de::Visitor<'de> for RefusalReasonVisitor {
304            type Value = RefusalReason;
305
306            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
307                formatter.write_str("a string representing a refusal reason code")
308            }
309
310            fn visit_str<E>(self, value: &str) -> Result<RefusalReason, E>
311            where
312                E: serde::de::Error,
313            {
314                match value {
315                    "2" => Ok(RefusalReason::Refused),
316                    "3" => Ok(RefusalReason::Referral),
317                    "4" => Ok(RefusalReason::AcquirerError),
318                    "5" => Ok(RefusalReason::BlockedCard),
319                    "6" => Ok(RefusalReason::ExpiredCard),
320                    "7" => Ok(RefusalReason::InvalidAmount),
321                    "8" => Ok(RefusalReason::InvalidCardNumber),
322                    "9" => Ok(RefusalReason::IssuerUnavailable),
323                    "10" => Ok(RefusalReason::NotSupported),
324                    "11" => Ok(RefusalReason::ThreeDNotAuthenticated),
325                    "12" => Ok(RefusalReason::NotEnoughBalance),
326                    "14" => Ok(RefusalReason::AcquirerFraud),
327                    "15" => Ok(RefusalReason::Cancelled),
328                    "16" => Ok(RefusalReason::ShopperCancelled),
329                    "17" => Ok(RefusalReason::InvalidPin),
330                    "18" => Ok(RefusalReason::PinTriesExceeded),
331                    "19" => Ok(RefusalReason::PinValidationNotPossible),
332                    "20" => Ok(RefusalReason::Fraud),
333                    "21" => Ok(RefusalReason::NotSubmitted),
334                    "22" => Ok(RefusalReason::FraudCancelled),
335                    "23" => Ok(RefusalReason::TransactionNotPermitted),
336                    "24" => Ok(RefusalReason::CvcDeclined),
337                    "25" => Ok(RefusalReason::RestrictedCard),
338                    "26" => Ok(RefusalReason::RevocationOfAuth),
339                    "27" => Ok(RefusalReason::DeclinedNonGeneric),
340                    "28" => Ok(RefusalReason::WithdrawalAmountExceeded),
341                    "29" => Ok(RefusalReason::WithdrawalCountExceeded),
342                    "31" => Ok(RefusalReason::IssuerSuspectedFraud),
343                    "32" => Ok(RefusalReason::AvsDeclined),
344                    "33" => Ok(RefusalReason::CardRequiresOnlinePin),
345                    "34" => Ok(RefusalReason::NoCheckingAccountAvailable),
346                    "35" => Ok(RefusalReason::NoSavingsAccountAvailable),
347                    "36" => Ok(RefusalReason::MobilePinRequired),
348                    "37" => Ok(RefusalReason::ContactlessFallback),
349                    "38" => Ok(RefusalReason::AuthenticationRequired),
350                    "39" => Ok(RefusalReason::RReqNotReceived),
351                    "40" => Ok(RefusalReason::CurrentAidInPenaltyBox),
352                    "41" => Ok(RefusalReason::CvmRequiredRestartPayment),
353                    "42" => Ok(RefusalReason::ThreeDsAuthenticationError),
354                    "46" => Ok(RefusalReason::TransactionBlockedByAdyen),
355                    _ => Err(serde::de::Error::unknown_variant(
356                        value,
357                        &[
358                            "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "14", "15",
359                            "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27",
360                            "28", "29", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40",
361                            "41", "42", "46",
362                        ],
363                    )),
364                }
365            }
366        }
367
368        deserializer.deserialize_str(RefusalReasonVisitor)
369    }
370}