mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +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