mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	fix(connector): [Bluesnap] Throw proper error message for redirection scenario (#1367)
Signed-off-by: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Co-authored-by: Prasunna Soppa <prasunna.soppa@juspay.in>
This commit is contained in:
		| @ -1094,9 +1094,15 @@ impl services::ConnectorRedirectResponse for Bluesnap { | |||||||
|  |  | ||||||
|         match redirection_result.status.as_str() { |         match redirection_result.status.as_str() { | ||||||
|             "Success" => Ok(payments::CallConnectorAction::Trigger), |             "Success" => Ok(payments::CallConnectorAction::Trigger), | ||||||
|             _ => Ok(payments::CallConnectorAction::StatusUpdate( |             _ => Ok(payments::CallConnectorAction::StatusUpdate { | ||||||
|                 enums::AttemptStatus::AuthenticationFailed, |                 status: enums::AttemptStatus::AuthenticationFailed, | ||||||
|             )), |                 error_code: redirection_result.code, | ||||||
|  |                 error_message: redirection_result | ||||||
|  |                     .info | ||||||
|  |                     .as_ref() | ||||||
|  |                     .and_then(|info| info.errors.as_ref().and_then(|error| error.first())) | ||||||
|  |                     .cloned(), | ||||||
|  |             }), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| use api_models::enums as api_enums; | use api_models::enums as api_enums; | ||||||
| use base64::Engine; | use base64::Engine; | ||||||
| use common_utils::{ | use common_utils::{ | ||||||
|  |     errors::CustomResult, | ||||||
|     ext_traits::{ByteSliceExt, StringExt, ValueExt}, |     ext_traits::{ByteSliceExt, StringExt, ValueExt}, | ||||||
|     pii::Email, |     pii::Email, | ||||||
| }; | }; | ||||||
| @ -9,7 +10,7 @@ use masking::ExposeInterface; | |||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
|  |  | ||||||
| use crate::{ | use crate::{ | ||||||
|     connector::utils::{self, RouterData}, |     connector::utils::{self, AddressDetailsData, PaymentsAuthorizeRequestData, RouterData}, | ||||||
|     consts, |     consts, | ||||||
|     core::errors, |     core::errors, | ||||||
|     pii::Secret, |     pii::Secret, | ||||||
| @ -27,6 +28,15 @@ pub struct BluesnapPaymentsRequest { | |||||||
|     card_transaction_type: BluesnapTxnType, |     card_transaction_type: BluesnapTxnType, | ||||||
|     three_d_secure: Option<BluesnapThreeDSecureInfo>, |     three_d_secure: Option<BluesnapThreeDSecureInfo>, | ||||||
|     transaction_fraud_info: Option<TransactionFraudInfo>, |     transaction_fraud_info: Option<TransactionFraudInfo>, | ||||||
|  |     card_holder_info: Option<BluesnapCardHolderInfo>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug, Serialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct BluesnapCardHolderInfo { | ||||||
|  |     first_name: Secret<String>, | ||||||
|  |     last_name: Secret<String>, | ||||||
|  |     email: Email, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Serialize)] | #[derive(Debug, Serialize)] | ||||||
| @ -149,13 +159,16 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BluesnapPaymentsRequest { | |||||||
|             Some(enums::CaptureMethod::Manual) => BluesnapTxnType::AuthOnly, |             Some(enums::CaptureMethod::Manual) => BluesnapTxnType::AuthOnly, | ||||||
|             _ => BluesnapTxnType::AuthCapture, |             _ => BluesnapTxnType::AuthCapture, | ||||||
|         }; |         }; | ||||||
|         let payment_method = match item.request.payment_method_data.clone() { |         let (payment_method, card_holder_info) = match item.request.payment_method_data.clone() { | ||||||
|             api::PaymentMethodData::Card(ccard) => Ok(PaymentMethodDetails::CreditCard(Card { |             api::PaymentMethodData::Card(ccard) => Ok(( | ||||||
|                 card_number: ccard.card_number, |                 PaymentMethodDetails::CreditCard(Card { | ||||||
|                 expiration_month: ccard.card_exp_month.clone(), |                     card_number: ccard.card_number, | ||||||
|                 expiration_year: ccard.card_exp_year.clone(), |                     expiration_month: ccard.card_exp_month.clone(), | ||||||
|                 security_code: ccard.card_cvc, |                     expiration_year: ccard.card_exp_year.clone(), | ||||||
|             })), |                     security_code: ccard.card_cvc, | ||||||
|  |                 }), | ||||||
|  |                 get_card_holder_info(item)?, | ||||||
|  |             )), | ||||||
|             api::PaymentMethodData::Wallet(wallet_data) => match wallet_data { |             api::PaymentMethodData::Wallet(wallet_data) => match wallet_data { | ||||||
|                 api_models::payments::WalletData::GooglePay(payment_method_data) => { |                 api_models::payments::WalletData::GooglePay(payment_method_data) => { | ||||||
|                     let gpay_object = Encode::<BluesnapGooglePayObject>::encode_to_string_of_json( |                     let gpay_object = Encode::<BluesnapGooglePayObject>::encode_to_string_of_json( | ||||||
| @ -166,10 +179,13 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BluesnapPaymentsRequest { | |||||||
|                         }, |                         }, | ||||||
|                     ) |                     ) | ||||||
|                     .change_context(errors::ConnectorError::RequestEncodingFailed)?; |                     .change_context(errors::ConnectorError::RequestEncodingFailed)?; | ||||||
|                     Ok(PaymentMethodDetails::Wallet(BluesnapWallet { |                     Ok(( | ||||||
|                         wallet_type: BluesnapWalletTypes::GooglePay, |                         PaymentMethodDetails::Wallet(BluesnapWallet { | ||||||
|                         encoded_payment_token: consts::BASE64_ENGINE.encode(gpay_object), |                             wallet_type: BluesnapWalletTypes::GooglePay, | ||||||
|                     })) |                             encoded_payment_token: consts::BASE64_ENGINE.encode(gpay_object), | ||||||
|  |                         }), | ||||||
|  |                         None, | ||||||
|  |                     )) | ||||||
|                 } |                 } | ||||||
|                 api_models::payments::WalletData::ApplePay(payment_method_data) => { |                 api_models::payments::WalletData::ApplePay(payment_method_data) => { | ||||||
|                     let apple_pay_payment_data = consts::BASE64_ENGINE |                     let apple_pay_payment_data = consts::BASE64_ENGINE | ||||||
| @ -230,10 +246,13 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BluesnapPaymentsRequest { | |||||||
|                     ) |                     ) | ||||||
|                     .change_context(errors::ConnectorError::RequestEncodingFailed)?; |                     .change_context(errors::ConnectorError::RequestEncodingFailed)?; | ||||||
|  |  | ||||||
|                     Ok(PaymentMethodDetails::Wallet(BluesnapWallet { |                     Ok(( | ||||||
|                         wallet_type: BluesnapWalletTypes::ApplePay, |                         PaymentMethodDetails::Wallet(BluesnapWallet { | ||||||
|                         encoded_payment_token: consts::BASE64_ENGINE.encode(apple_pay_object), |                             wallet_type: BluesnapWalletTypes::ApplePay, | ||||||
|                     })) |                             encoded_payment_token: consts::BASE64_ENGINE.encode(apple_pay_object), | ||||||
|  |                         }), | ||||||
|  |                         None, | ||||||
|  |                     )) | ||||||
|                 } |                 } | ||||||
|                 _ => Err(errors::ConnectorError::NotImplemented( |                 _ => Err(errors::ConnectorError::NotImplemented( | ||||||
|                     "Wallets".to_string(), |                     "Wallets".to_string(), | ||||||
| @ -252,6 +271,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BluesnapPaymentsRequest { | |||||||
|             transaction_fraud_info: Some(TransactionFraudInfo { |             transaction_fraud_info: Some(TransactionFraudInfo { | ||||||
|                 fraud_session_id: item.payment_id.clone(), |                 fraud_session_id: item.payment_id.clone(), | ||||||
|             }), |             }), | ||||||
|  |             card_holder_info, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -397,6 +417,7 @@ impl TryFrom<&types::PaymentsCompleteAuthorizeRouterData> for BluesnapPaymentsRe | |||||||
|             transaction_fraud_info: Some(TransactionFraudInfo { |             transaction_fraud_info: Some(TransactionFraudInfo { | ||||||
|                 fraud_session_id: item.payment_id.clone(), |                 fraud_session_id: item.payment_id.clone(), | ||||||
|             }), |             }), | ||||||
|  |             card_holder_info: None, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -411,6 +432,14 @@ pub struct BluesnapRedirectionResponse { | |||||||
| pub struct BluesnapThreeDsResult { | pub struct BluesnapThreeDsResult { | ||||||
|     three_d_secure: Option<BluesnapThreeDsReference>, |     three_d_secure: Option<BluesnapThreeDsReference>, | ||||||
|     pub status: String, |     pub status: String, | ||||||
|  |     pub code: Option<String>, | ||||||
|  |     pub info: Option<RedirectErrorMessage>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug, Deserialize)] | ||||||
|  | #[serde(rename_all = "camelCase")] | ||||||
|  | pub struct RedirectErrorMessage { | ||||||
|  |     pub errors: Option<Vec<String>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Deserialize)] | #[derive(Debug, Deserialize)] | ||||||
| @ -759,3 +788,14 @@ pub enum BluesnapErrors { | |||||||
|     PaymentError(BluesnapErrorResponse), |     PaymentError(BluesnapErrorResponse), | ||||||
|     AuthError(BluesnapAuthErrorResponse), |     AuthError(BluesnapAuthErrorResponse), | ||||||
| } | } | ||||||
|  |  | ||||||
|  | fn get_card_holder_info( | ||||||
|  |     item: &types::PaymentsAuthorizeRouterData, | ||||||
|  | ) -> CustomResult<Option<BluesnapCardHolderInfo>, errors::ConnectorError> { | ||||||
|  |     let address = item.get_billing_address()?; | ||||||
|  |     Ok(Some(BluesnapCardHolderInfo { | ||||||
|  |         first_name: address.get_first_name()?.clone(), | ||||||
|  |         last_name: address.get_last_name()?.clone(), | ||||||
|  |         email: item.request.get_email()?, | ||||||
|  |     })) | ||||||
|  | } | ||||||
|  | |||||||
| @ -1199,9 +1199,13 @@ impl services::ConnectorRedirectResponse for Checkout { | |||||||
|                 .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; |                 .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; | ||||||
|         let connector_action = query |         let connector_action = query | ||||||
|             .status |             .status | ||||||
|             .map(|checkout_status| { |             .map( | ||||||
|                 payments::CallConnectorAction::StatusUpdate(checkout_status.into()) |                 |checkout_status| payments::CallConnectorAction::StatusUpdate { | ||||||
|             }) |                     status: storage_models::enums::AttemptStatus::from(checkout_status), | ||||||
|  |                     error_code: None, | ||||||
|  |                     error_message: None, | ||||||
|  |                 }, | ||||||
|  |             ) | ||||||
|             .unwrap_or(payments::CallConnectorAction::Trigger); |             .unwrap_or(payments::CallConnectorAction::Trigger); | ||||||
|         Ok(connector_action) |         Ok(connector_action) | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -914,9 +914,11 @@ impl services::ConnectorRedirectResponse for Globalpay { | |||||||
|             payments::CallConnectorAction::Trigger, |             payments::CallConnectorAction::Trigger, | ||||||
|             |status| match status { |             |status| match status { | ||||||
|                 response::GlobalpayPaymentStatus::Captured => { |                 response::GlobalpayPaymentStatus::Captured => { | ||||||
|                     payments::CallConnectorAction::StatusUpdate( |                     payments::CallConnectorAction::StatusUpdate { | ||||||
|                         storage_models::enums::AttemptStatus::from(status), |                         status: storage_models::enums::AttemptStatus::from(status), | ||||||
|                     ) |                         error_code: None, | ||||||
|  |                         error_message: None, | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 _ => payments::CallConnectorAction::Trigger, |                 _ => payments::CallConnectorAction::Trigger, | ||||||
|             }, |             }, | ||||||
|  | |||||||
| @ -957,9 +957,11 @@ impl services::ConnectorRedirectResponse for Nuvei { | |||||||
|                             .switch()?; |                             .switch()?; | ||||||
|                     match acs_response.trans_status { |                     match acs_response.trans_status { | ||||||
|                         None | Some(nuvei::LiabilityShift::Failed) => { |                         None | Some(nuvei::LiabilityShift::Failed) => { | ||||||
|                             Ok(payments::CallConnectorAction::StatusUpdate( |                             Ok(payments::CallConnectorAction::StatusUpdate { | ||||||
|                                 enums::AttemptStatus::AuthenticationFailed, |                                 status: enums::AttemptStatus::AuthenticationFailed, | ||||||
|                             )) |                                 error_code: None, | ||||||
|  |                                 error_message: None, | ||||||
|  |                             }) | ||||||
|                         } |                         } | ||||||
|                         _ => Ok(payments::CallConnectorAction::Trigger), |                         _ => Ok(payments::CallConnectorAction::Trigger), | ||||||
|                     } |                     } | ||||||
|  | |||||||
| @ -1831,9 +1831,11 @@ impl services::ConnectorRedirectResponse for Stripe { | |||||||
|                     transformers::StripePaymentStatus::Failed => { |                     transformers::StripePaymentStatus::Failed => { | ||||||
|                         payments::CallConnectorAction::Trigger |                         payments::CallConnectorAction::Trigger | ||||||
|                     } |                     } | ||||||
|                     _ => payments::CallConnectorAction::StatusUpdate(enums::AttemptStatus::from( |                     _ => payments::CallConnectorAction::StatusUpdate { | ||||||
|                         status, |                         status: enums::AttemptStatus::from(status), | ||||||
|                     )), |                         error_code: None, | ||||||
|  |                         error_message: None, | ||||||
|  |                     }, | ||||||
|                 }, |                 }, | ||||||
|             )) |             )) | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -802,9 +802,11 @@ impl services::ConnectorRedirectResponse for Trustpay { | |||||||
|         Ok(query.status.map_or( |         Ok(query.status.map_or( | ||||||
|             payments::CallConnectorAction::Trigger, |             payments::CallConnectorAction::Trigger, | ||||||
|             |status| match status.as_str() { |             |status| match status.as_str() { | ||||||
|                 "SuccessOk" => payments::CallConnectorAction::StatusUpdate( |                 "SuccessOk" => payments::CallConnectorAction::StatusUpdate { | ||||||
|                     storage_models::enums::AttemptStatus::Charged, |                     status: storage_models::enums::AttemptStatus::Charged, | ||||||
|                 ), |                     error_code: None, | ||||||
|  |                     error_message: None, | ||||||
|  |                 }, | ||||||
|                 _ => payments::CallConnectorAction::Trigger, |                 _ => payments::CallConnectorAction::Trigger, | ||||||
|             }, |             }, | ||||||
|         )) |         )) | ||||||
|  | |||||||
| @ -429,6 +429,7 @@ pub trait CardData { | |||||||
|         delimiter: String, |         delimiter: String, | ||||||
|     ) -> Secret<String>; |     ) -> Secret<String>; | ||||||
|     fn get_expiry_date_as_yyyymm(&self, delimiter: &str) -> Secret<String>; |     fn get_expiry_date_as_yyyymm(&self, delimiter: &str) -> Secret<String>; | ||||||
|  |     fn get_expiry_year_4_digit(&self) -> Secret<String>; | ||||||
| } | } | ||||||
|  |  | ||||||
| impl CardData for api::Card { | impl CardData for api::Card { | ||||||
| @ -453,17 +454,21 @@ impl CardData for api::Card { | |||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
|     fn get_expiry_date_as_yyyymm(&self, delimiter: &str) -> Secret<String> { |     fn get_expiry_date_as_yyyymm(&self, delimiter: &str) -> Secret<String> { | ||||||
|         let mut x = self.card_exp_year.peek().clone(); |         let year = self.get_expiry_year_4_digit(); | ||||||
|         if x.len() == 2 { |  | ||||||
|             x = format!("20{}", x); |  | ||||||
|         } |  | ||||||
|         Secret::new(format!( |         Secret::new(format!( | ||||||
|             "{}{}{}", |             "{}{}{}", | ||||||
|             x, |             year.peek(), | ||||||
|             delimiter, |             delimiter, | ||||||
|             self.card_exp_month.peek().clone() |             self.card_exp_month.peek().clone() | ||||||
|         )) |         )) | ||||||
|     } |     } | ||||||
|  |     fn get_expiry_year_4_digit(&self) -> Secret<String> { | ||||||
|  |         let mut year = self.card_exp_year.peek().clone(); | ||||||
|  |         if year.len() == 2 { | ||||||
|  |             year = format!("20{}", year); | ||||||
|  |         } | ||||||
|  |         Secret::new(year) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[track_caller] | #[track_caller] | ||||||
|  | |||||||
| @ -937,7 +937,11 @@ where | |||||||
| pub enum CallConnectorAction { | pub enum CallConnectorAction { | ||||||
|     Trigger, |     Trigger, | ||||||
|     Avoid, |     Avoid, | ||||||
|     StatusUpdate(storage_enums::AttemptStatus), |     StatusUpdate { | ||||||
|  |         status: storage_enums::AttemptStatus, | ||||||
|  |         error_code: Option<String>, | ||||||
|  |         error_message: Option<String>, | ||||||
|  |     }, | ||||||
|     HandleResponse(Vec<u8>), |     HandleResponse(Vec<u8>), | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ use self::request::{ContentType, HeaderExt, RequestBuilderExt}; | |||||||
| pub use self::request::{Method, Request, RequestBuilder}; | pub use self::request::{Method, Request, RequestBuilder}; | ||||||
| use crate::{ | use crate::{ | ||||||
|     configs::settings::Connectors, |     configs::settings::Connectors, | ||||||
|  |     consts, | ||||||
|     core::{ |     core::{ | ||||||
|         errors::{self, CustomResult}, |         errors::{self, CustomResult}, | ||||||
|         payments, |         payments, | ||||||
| @ -190,8 +191,23 @@ where | |||||||
|             connector_integration.handle_response(req, response) |             connector_integration.handle_response(req, response) | ||||||
|         } |         } | ||||||
|         payments::CallConnectorAction::Avoid => Ok(router_data), |         payments::CallConnectorAction::Avoid => Ok(router_data), | ||||||
|         payments::CallConnectorAction::StatusUpdate(status) => { |         payments::CallConnectorAction::StatusUpdate { | ||||||
|  |             status, | ||||||
|  |             error_code, | ||||||
|  |             error_message, | ||||||
|  |         } => { | ||||||
|             router_data.status = status; |             router_data.status = status; | ||||||
|  |             let error_response = if error_code.is_some() | error_message.is_some() { | ||||||
|  |                 Some(ErrorResponse { | ||||||
|  |                     code: error_code.unwrap_or(consts::NO_ERROR_CODE.to_string()), | ||||||
|  |                     message: error_message.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), | ||||||
|  |                     status_code: 200, // This status code is ignored in redirection response it will override with 302 status code. | ||||||
|  |                     reason: None, | ||||||
|  |                 }) | ||||||
|  |             } else { | ||||||
|  |                 None | ||||||
|  |             }; | ||||||
|  |             router_data.response = error_response.map(Err).unwrap_or(router_data.response); | ||||||
|             Ok(router_data) |             Ok(router_data) | ||||||
|         } |         } | ||||||
|         payments::CallConnectorAction::Trigger => { |         payments::CallConnectorAction::Trigger => { | ||||||
|  | |||||||
| @ -1,11 +1,13 @@ | |||||||
| use std::str::FromStr; | use std::str::FromStr; | ||||||
|  |  | ||||||
|  | use api_models::payments::{Address, AddressDetails}; | ||||||
|  | use common_utils::pii::Email; | ||||||
| use masking::Secret; | use masking::Secret; | ||||||
| use router::types::{self, api, storage::enums, ConnectorAuthType}; | use router::types::{self, api, storage::enums, ConnectorAuthType, PaymentAddress}; | ||||||
|  |  | ||||||
| use crate::{ | use crate::{ | ||||||
|     connector_auth, |     connector_auth, | ||||||
|     utils::{self, ConnectorActions}, |     utils::{self, ConnectorActions, PaymentInfo}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #[derive(Clone, Copy)] | #[derive(Clone, Copy)] | ||||||
| @ -34,6 +36,28 @@ impl utils::Connector for BluesnapTest { | |||||||
|         "bluesnap".to_string() |         "bluesnap".to_string() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | fn payment_method_details() -> Option<types::PaymentsAuthorizeData> { | ||||||
|  |     Some(types::PaymentsAuthorizeData { | ||||||
|  |         email: Some(Email::from_str("test@gmail.com").unwrap()), | ||||||
|  |         ..utils::PaymentAuthorizeType::default().0 | ||||||
|  |     }) | ||||||
|  | } | ||||||
|  | fn get_payment_info() -> Option<PaymentInfo> { | ||||||
|  |     Some(PaymentInfo { | ||||||
|  |         address: Some(PaymentAddress { | ||||||
|  |             billing: Some(Address { | ||||||
|  |                 address: Some(AddressDetails { | ||||||
|  |                     first_name: Some(Secret::new("joseph".to_string())), | ||||||
|  |                     last_name: Some(Secret::new("Doe".to_string())), | ||||||
|  |                     ..Default::default() | ||||||
|  |                 }), | ||||||
|  |                 phone: None, | ||||||
|  |             }), | ||||||
|  |             ..Default::default() | ||||||
|  |         }), | ||||||
|  |         ..Default::default() | ||||||
|  |     }) | ||||||
|  | } | ||||||
|  |  | ||||||
| // Cards Positive Tests | // Cards Positive Tests | ||||||
| // Creates a payment using the manual capture flow (Non 3DS). | // Creates a payment using the manual capture flow (Non 3DS). | ||||||
| @ -42,7 +66,7 @@ impl utils::Connector for BluesnapTest { | |||||||
| #[actix_web::test] | #[actix_web::test] | ||||||
| async fn should_only_authorize_payment() { | async fn should_only_authorize_payment() { | ||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
|         .authorize_payment(None, None) |         .authorize_payment(payment_method_details(), get_payment_info()) | ||||||
|         .await |         .await | ||||||
|         .expect("Authorize payment response"); |         .expect("Authorize payment response"); | ||||||
|     assert_eq!(response.status, enums::AttemptStatus::Authorized); |     assert_eq!(response.status, enums::AttemptStatus::Authorized); | ||||||
| @ -54,7 +78,7 @@ async fn should_only_authorize_payment() { | |||||||
| #[actix_web::test] | #[actix_web::test] | ||||||
| async fn should_capture_authorized_payment() { | async fn should_capture_authorized_payment() { | ||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
|         .authorize_and_capture_payment(None, None, None) |         .authorize_and_capture_payment(payment_method_details(), None, get_payment_info()) | ||||||
|         .await |         .await | ||||||
|         .expect("Capture payment response"); |         .expect("Capture payment response"); | ||||||
|     assert_eq!(response.status, enums::AttemptStatus::Charged); |     assert_eq!(response.status, enums::AttemptStatus::Charged); | ||||||
| @ -67,12 +91,12 @@ async fn should_capture_authorized_payment() { | |||||||
| async fn should_partially_capture_authorized_payment() { | async fn should_partially_capture_authorized_payment() { | ||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
|         .authorize_and_capture_payment( |         .authorize_and_capture_payment( | ||||||
|             None, |             payment_method_details(), | ||||||
|             Some(types::PaymentsCaptureData { |             Some(types::PaymentsCaptureData { | ||||||
|                 amount_to_capture: 50, |                 amount_to_capture: 50, | ||||||
|                 ..utils::PaymentCaptureType::default().0 |                 ..utils::PaymentCaptureType::default().0 | ||||||
|             }), |             }), | ||||||
|             None, |             get_payment_info(), | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|         .expect("Capture payment response"); |         .expect("Capture payment response"); | ||||||
| @ -85,7 +109,7 @@ async fn should_partially_capture_authorized_payment() { | |||||||
| #[actix_web::test] | #[actix_web::test] | ||||||
| async fn should_sync_authorized_payment() { | async fn should_sync_authorized_payment() { | ||||||
|     let authorize_response = CONNECTOR |     let authorize_response = CONNECTOR | ||||||
|         .authorize_payment(None, None) |         .authorize_payment(payment_method_details(), get_payment_info()) | ||||||
|         .await |         .await | ||||||
|         .expect("Authorize payment response"); |         .expect("Authorize payment response"); | ||||||
|     let txn_id = utils::get_connector_transaction_id(authorize_response.response); |     let txn_id = utils::get_connector_transaction_id(authorize_response.response); | ||||||
| @ -112,13 +136,13 @@ async fn should_sync_authorized_payment() { | |||||||
| async fn should_void_authorized_payment() { | async fn should_void_authorized_payment() { | ||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
|         .authorize_and_void_payment( |         .authorize_and_void_payment( | ||||||
|             None, |             payment_method_details(), | ||||||
|             Some(types::PaymentsCancelData { |             Some(types::PaymentsCancelData { | ||||||
|                 connector_transaction_id: String::from(""), |                 connector_transaction_id: String::from(""), | ||||||
|                 cancellation_reason: Some("requested_by_customer".to_string()), |                 cancellation_reason: Some("requested_by_customer".to_string()), | ||||||
|                 ..Default::default() |                 ..Default::default() | ||||||
|             }), |             }), | ||||||
|             None, |             get_payment_info(), | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|         .expect("Void payment response"); |         .expect("Void payment response"); | ||||||
| @ -131,7 +155,7 @@ async fn should_void_authorized_payment() { | |||||||
| #[actix_web::test] | #[actix_web::test] | ||||||
| async fn should_refund_manually_captured_payment() { | async fn should_refund_manually_captured_payment() { | ||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
|         .capture_payment_and_refund(None, None, None, None) |         .capture_payment_and_refund(payment_method_details(), None, None, get_payment_info()) | ||||||
|         .await |         .await | ||||||
|         .unwrap(); |         .unwrap(); | ||||||
|     let rsync_response = CONNECTOR |     let rsync_response = CONNECTOR | ||||||
| @ -156,13 +180,13 @@ async fn should_refund_manually_captured_payment() { | |||||||
| async fn should_partially_refund_manually_captured_payment() { | async fn should_partially_refund_manually_captured_payment() { | ||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
|         .capture_payment_and_refund( |         .capture_payment_and_refund( | ||||||
|             None, |             payment_method_details(), | ||||||
|             None, |             None, | ||||||
|             Some(types::RefundsData { |             Some(types::RefundsData { | ||||||
|                 refund_amount: 50, |                 refund_amount: 50, | ||||||
|                 ..utils::PaymentRefundType::default().0 |                 ..utils::PaymentRefundType::default().0 | ||||||
|             }), |             }), | ||||||
|             None, |             get_payment_info(), | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|         .unwrap(); |         .unwrap(); | ||||||
| @ -187,7 +211,7 @@ async fn should_partially_refund_manually_captured_payment() { | |||||||
| #[actix_web::test] | #[actix_web::test] | ||||||
| async fn should_sync_manually_captured_refund() { | async fn should_sync_manually_captured_refund() { | ||||||
|     let refund_response = CONNECTOR |     let refund_response = CONNECTOR | ||||||
|         .capture_payment_and_refund(None, None, None, None) |         .capture_payment_and_refund(payment_method_details(), None, None, get_payment_info()) | ||||||
|         .await |         .await | ||||||
|         .unwrap(); |         .unwrap(); | ||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
| @ -210,7 +234,10 @@ async fn should_sync_manually_captured_refund() { | |||||||
| #[serial_test::serial] | #[serial_test::serial] | ||||||
| #[actix_web::test] | #[actix_web::test] | ||||||
| async fn should_make_payment() { | async fn should_make_payment() { | ||||||
|     let authorize_response = CONNECTOR.make_payment(None, None).await.unwrap(); |     let authorize_response = CONNECTOR | ||||||
|  |         .make_payment(payment_method_details(), get_payment_info()) | ||||||
|  |         .await | ||||||
|  |         .unwrap(); | ||||||
|     assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); |     assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -219,7 +246,10 @@ async fn should_make_payment() { | |||||||
| #[serial_test::serial] | #[serial_test::serial] | ||||||
| #[actix_web::test] | #[actix_web::test] | ||||||
| async fn should_sync_auto_captured_payment() { | async fn should_sync_auto_captured_payment() { | ||||||
|     let authorize_response = CONNECTOR.make_payment(None, None).await.unwrap(); |     let authorize_response = CONNECTOR | ||||||
|  |         .make_payment(payment_method_details(), get_payment_info()) | ||||||
|  |         .await | ||||||
|  |         .unwrap(); | ||||||
|     assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); |     assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); | ||||||
|     let txn_id = utils::get_connector_transaction_id(authorize_response.response); |     let txn_id = utils::get_connector_transaction_id(authorize_response.response); | ||||||
|     assert_ne!(txn_id, None, "Empty connector transaction id"); |     assert_ne!(txn_id, None, "Empty connector transaction id"); | ||||||
| @ -245,7 +275,7 @@ async fn should_sync_auto_captured_payment() { | |||||||
| #[actix_web::test] | #[actix_web::test] | ||||||
| async fn should_refund_auto_captured_payment() { | async fn should_refund_auto_captured_payment() { | ||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
|         .make_payment_and_refund(None, None, None) |         .make_payment_and_refund(payment_method_details(), None, get_payment_info()) | ||||||
|         .await |         .await | ||||||
|         .unwrap(); |         .unwrap(); | ||||||
|     let rsync_response = CONNECTOR |     let rsync_response = CONNECTOR | ||||||
| @ -270,12 +300,12 @@ async fn should_refund_auto_captured_payment() { | |||||||
| async fn should_partially_refund_succeeded_payment() { | async fn should_partially_refund_succeeded_payment() { | ||||||
|     let refund_response = CONNECTOR |     let refund_response = CONNECTOR | ||||||
|         .make_payment_and_refund( |         .make_payment_and_refund( | ||||||
|             None, |             payment_method_details(), | ||||||
|             Some(types::RefundsData { |             Some(types::RefundsData { | ||||||
|                 refund_amount: 50, |                 refund_amount: 50, | ||||||
|                 ..utils::PaymentRefundType::default().0 |                 ..utils::PaymentRefundType::default().0 | ||||||
|             }), |             }), | ||||||
|             None, |             get_payment_info(), | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|         .unwrap(); |         .unwrap(); | ||||||
| @ -299,7 +329,10 @@ async fn should_partially_refund_succeeded_payment() { | |||||||
| #[serial_test::serial] | #[serial_test::serial] | ||||||
| #[actix_web::test] | #[actix_web::test] | ||||||
| async fn should_refund_succeeded_payment_multiple_times() { | async fn should_refund_succeeded_payment_multiple_times() { | ||||||
|     let authorize_response = CONNECTOR.make_payment(None, None).await.unwrap(); |     let authorize_response = CONNECTOR | ||||||
|  |         .make_payment(payment_method_details(), get_payment_info()) | ||||||
|  |         .await | ||||||
|  |         .unwrap(); | ||||||
|     assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); |     assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); | ||||||
|     let transaction_id = utils::get_connector_transaction_id(authorize_response.response).unwrap(); |     let transaction_id = utils::get_connector_transaction_id(authorize_response.response).unwrap(); | ||||||
|     for _x in 0..2 { |     for _x in 0..2 { | ||||||
| @ -337,7 +370,7 @@ async fn should_refund_succeeded_payment_multiple_times() { | |||||||
| #[actix_web::test] | #[actix_web::test] | ||||||
| async fn should_sync_refund() { | async fn should_sync_refund() { | ||||||
|     let refund_response = CONNECTOR |     let refund_response = CONNECTOR | ||||||
|         .make_payment_and_refund(None, None, None) |         .make_payment_and_refund(payment_method_details(), None, get_payment_info()) | ||||||
|         .await |         .await | ||||||
|         .unwrap(); |         .unwrap(); | ||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
| @ -355,31 +388,6 @@ async fn should_sync_refund() { | |||||||
|     ); |     ); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Cards Negative scenerios |  | ||||||
| // Creates a payment with incorrect card number. |  | ||||||
|  |  | ||||||
| #[serial_test::serial] |  | ||||||
| #[actix_web::test] |  | ||||||
| async fn should_fail_payment_for_incorrect_card_number() { |  | ||||||
|     let response = CONNECTOR |  | ||||||
|         .make_payment( |  | ||||||
|             Some(types::PaymentsAuthorizeData { |  | ||||||
|                 payment_method_data: types::api::PaymentMethodData::Card(api::Card { |  | ||||||
|                     card_number: cards::CardNumber::from_str("1234567891011").unwrap(), |  | ||||||
|                     ..utils::CCardType::default().0 |  | ||||||
|                 }), |  | ||||||
|                 ..utils::PaymentAuthorizeType::default().0 |  | ||||||
|             }), |  | ||||||
|             None, |  | ||||||
|         ) |  | ||||||
|         .await |  | ||||||
|         .unwrap(); |  | ||||||
|     assert_eq!( |  | ||||||
|         response.response.unwrap_err().message, |  | ||||||
|         "Order creation failure due to problematic input.".to_string(), |  | ||||||
|     ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Creates a payment with incorrect CVC. | // Creates a payment with incorrect CVC. | ||||||
|  |  | ||||||
| #[serial_test::serial] | #[serial_test::serial] | ||||||
| @ -388,13 +396,15 @@ async fn should_fail_payment_for_incorrect_cvc() { | |||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
|         .make_payment( |         .make_payment( | ||||||
|             Some(types::PaymentsAuthorizeData { |             Some(types::PaymentsAuthorizeData { | ||||||
|  |                 email: Some(Email::from_str("test@gmail.com").unwrap()), | ||||||
|                 payment_method_data: types::api::PaymentMethodData::Card(api::Card { |                 payment_method_data: types::api::PaymentMethodData::Card(api::Card { | ||||||
|  |                     card_holder_name: Secret::new("John Doe".to_string()), | ||||||
|                     card_cvc: Secret::new("12345".to_string()), |                     card_cvc: Secret::new("12345".to_string()), | ||||||
|                     ..utils::CCardType::default().0 |                     ..utils::CCardType::default().0 | ||||||
|                 }), |                 }), | ||||||
|                 ..utils::PaymentAuthorizeType::default().0 |                 ..utils::PaymentAuthorizeType::default().0 | ||||||
|             }), |             }), | ||||||
|             None, |             get_payment_info(), | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|         .unwrap(); |         .unwrap(); | ||||||
| @ -412,13 +422,15 @@ async fn should_fail_payment_for_invalid_exp_month() { | |||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
|         .make_payment( |         .make_payment( | ||||||
|             Some(types::PaymentsAuthorizeData { |             Some(types::PaymentsAuthorizeData { | ||||||
|  |                 email: Some(Email::from_str("test@gmail.com").unwrap()), | ||||||
|                 payment_method_data: types::api::PaymentMethodData::Card(api::Card { |                 payment_method_data: types::api::PaymentMethodData::Card(api::Card { | ||||||
|  |                     card_holder_name: Secret::new("John Doe".to_string()), | ||||||
|                     card_exp_month: Secret::new("20".to_string()), |                     card_exp_month: Secret::new("20".to_string()), | ||||||
|                     ..utils::CCardType::default().0 |                     ..utils::CCardType::default().0 | ||||||
|                 }), |                 }), | ||||||
|                 ..utils::PaymentAuthorizeType::default().0 |                 ..utils::PaymentAuthorizeType::default().0 | ||||||
|             }), |             }), | ||||||
|             None, |             get_payment_info(), | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|         .unwrap(); |         .unwrap(); | ||||||
| @ -436,13 +448,15 @@ async fn should_fail_payment_for_incorrect_expiry_year() { | |||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
|         .make_payment( |         .make_payment( | ||||||
|             Some(types::PaymentsAuthorizeData { |             Some(types::PaymentsAuthorizeData { | ||||||
|  |                 email: Some(Email::from_str("test@gmail.com").unwrap()), | ||||||
|                 payment_method_data: types::api::PaymentMethodData::Card(api::Card { |                 payment_method_data: types::api::PaymentMethodData::Card(api::Card { | ||||||
|  |                     card_holder_name: Secret::new("John Doe".to_string()), | ||||||
|                     card_exp_year: Secret::new("2000".to_string()), |                     card_exp_year: Secret::new("2000".to_string()), | ||||||
|                     ..utils::CCardType::default().0 |                     ..utils::CCardType::default().0 | ||||||
|                 }), |                 }), | ||||||
|                 ..utils::PaymentAuthorizeType::default().0 |                 ..utils::PaymentAuthorizeType::default().0 | ||||||
|             }), |             }), | ||||||
|             None, |             get_payment_info(), | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|         .unwrap(); |         .unwrap(); | ||||||
| @ -457,7 +471,10 @@ async fn should_fail_payment_for_incorrect_expiry_year() { | |||||||
| #[serial_test::serial] | #[serial_test::serial] | ||||||
| #[actix_web::test] | #[actix_web::test] | ||||||
| async fn should_fail_void_payment_for_auto_capture() { | async fn should_fail_void_payment_for_auto_capture() { | ||||||
|     let authorize_response = CONNECTOR.make_payment(None, None).await.unwrap(); |     let authorize_response = CONNECTOR | ||||||
|  |         .make_payment(payment_method_details(), get_payment_info()) | ||||||
|  |         .await | ||||||
|  |         .unwrap(); | ||||||
|     assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); |     assert_eq!(authorize_response.status, enums::AttemptStatus::Charged); | ||||||
|     let txn_id = utils::get_connector_transaction_id(authorize_response.response); |     let txn_id = utils::get_connector_transaction_id(authorize_response.response); | ||||||
|     assert_ne!(txn_id, None, "Empty connector transaction id"); |     assert_ne!(txn_id, None, "Empty connector transaction id"); | ||||||
| @ -495,12 +512,12 @@ async fn should_fail_capture_for_invalid_payment() { | |||||||
| async fn should_fail_for_refund_amount_higher_than_payment_amount() { | async fn should_fail_for_refund_amount_higher_than_payment_amount() { | ||||||
|     let response = CONNECTOR |     let response = CONNECTOR | ||||||
|         .make_payment_and_refund( |         .make_payment_and_refund( | ||||||
|             None, |             payment_method_details(), | ||||||
|             Some(types::RefundsData { |             Some(types::RefundsData { | ||||||
|                 refund_amount: 150, |                 refund_amount: 150, | ||||||
|                 ..utils::PaymentRefundType::default().0 |                 ..utils::PaymentRefundType::default().0 | ||||||
|             }), |             }), | ||||||
|             None, |             get_payment_info(), | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|         .unwrap(); |         .unwrap(); | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 chikke srujan
					chikke srujan