From ecf51b5e3a30f055634edfafcd36f64cef535a53 Mon Sep 17 00:00:00 2001 From: AkshayaFoiger <131388445+AkshayaFoiger@users.noreply.github.com> Date: Tue, 9 Jan 2024 12:31:39 +0530 Subject: [PATCH] fix(connector): [BOA, Cybersource] capture error_code (#3239) Co-authored-by: Sahkal Poddar Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: Arjun Karthik --- .../connector/bankofamerica/transformers.rs | 188 ++++++++--------- .../src/connector/cybersource/transformers.rs | 197 ++++++++---------- crates/router/src/connector/utils.rs | 40 ++++ 3 files changed, 220 insertions(+), 205 deletions(-) diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs index aa47efbe714..71a44b5a6e6 100644 --- a/crates/router/src/connector/bankofamerica/transformers.rs +++ b/crates/router/src/connector/bankofamerica/transformers.rs @@ -681,60 +681,17 @@ fn get_error_response_if_failure( u16, ), ) -> Option { - if is_payment_failure(status) { - let (message, reason) = match info_response.error_information.as_ref() { - Some(error_info) => ( - error_info - .message - .clone() - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - error_info.reason.clone(), - ), - None => (consts::NO_ERROR_MESSAGE.to_string(), None), - }; - - Some(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), - message, - reason, - status_code: http_code, - attempt_status: Some(enums::AttemptStatus::Failure), - connector_transaction_id: Some(info_response.id.clone()), - }) + if utils::is_payment_failure(status) { + Some(types::ErrorResponse::from(( + &info_response.error_information, + http_code, + info_response.id.clone(), + ))) } else { None } } -fn is_payment_failure(status: enums::AttemptStatus) -> bool { - match status { - common_enums::AttemptStatus::AuthenticationFailed - | common_enums::AttemptStatus::AuthorizationFailed - | common_enums::AttemptStatus::CaptureFailed - | common_enums::AttemptStatus::VoidFailed - | common_enums::AttemptStatus::Failure => true, - common_enums::AttemptStatus::Started - | common_enums::AttemptStatus::RouterDeclined - | common_enums::AttemptStatus::AuthenticationPending - | common_enums::AttemptStatus::AuthenticationSuccessful - | common_enums::AttemptStatus::Authorized - | common_enums::AttemptStatus::Charged - | common_enums::AttemptStatus::Authorizing - | common_enums::AttemptStatus::CodInitiated - | common_enums::AttemptStatus::Voided - | common_enums::AttemptStatus::VoidInitiated - | common_enums::AttemptStatus::CaptureInitiated - | common_enums::AttemptStatus::AutoRefunded - | common_enums::AttemptStatus::PartialCharged - | common_enums::AttemptStatus::PartialChargedAndChargeable - | common_enums::AttemptStatus::Unresolved - | common_enums::AttemptStatus::Pending - | common_enums::AttemptStatus::PaymentMethodAwaited - | common_enums::AttemptStatus::ConfirmationAwaited - | common_enums::AttemptStatus::DeviceDataCollectionPending => false, - } -} - fn get_payment_response( (info_response, status, http_code): ( &BankOfAmericaClientReferenceResponse, @@ -796,17 +753,22 @@ impl }) } BankOfAmericaPaymentsResponse::ErrorInformation(error_response) => Ok(Self { - response: Err(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), - message: error_response - .error_information - .message - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: error_response.error_information.reason, - status_code: item.http_code, - attempt_status: None, - connector_transaction_id: Some(error_response.id), - }), + response: { + let error_reason = &error_response.error_information.reason; + + Err(types::ErrorResponse { + code: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason: error_response.error_information.message, + status_code: item.http_code, + attempt_status: None, + connector_transaction_id: Some(error_response.id), + }) + }, status: enums::AttemptStatus::Failure, ..item.data }), @@ -845,17 +807,21 @@ impl }) } BankOfAmericaPaymentsResponse::ErrorInformation(error_response) => Ok(Self { - response: Err(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), - message: error_response - .error_information - .message - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: error_response.error_information.reason, - status_code: item.http_code, - attempt_status: None, - connector_transaction_id: Some(error_response.id), - }), + response: { + let error_reason = &error_response.error_information.reason; + Err(types::ErrorResponse { + code: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason: error_response.error_information.message, + status_code: item.http_code, + attempt_status: None, + connector_transaction_id: Some(error_response.id), + }) + }, ..item.data }), } @@ -893,17 +859,21 @@ impl }) } BankOfAmericaPaymentsResponse::ErrorInformation(error_response) => Ok(Self { - response: Err(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), - message: error_response - .error_information - .message - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: error_response.error_information.reason, - status_code: item.http_code, - attempt_status: None, - connector_transaction_id: Some(error_response.id), - }), + response: { + let error_reason = &error_response.error_information.reason; + Err(types::ErrorResponse { + code: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason: error_response.error_information.message, + status_code: item.http_code, + attempt_status: None, + connector_transaction_id: Some(error_response.id), + }) + }, ..item.data }), } @@ -957,25 +927,13 @@ impl app_response.application_information.status, item.data.request.is_auto_capture()?, )); - if is_payment_failure(status) { - let (message, reason) = match app_response.error_information { - Some(error_info) => ( - error_info - .message - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - error_info.reason, - ), - None => (consts::NO_ERROR_MESSAGE.to_string(), None), - }; + if utils::is_payment_failure(status) { Ok(Self { - response: Err(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), - message, - reason, - status_code: item.http_code, - attempt_status: Some(enums::AttemptStatus::Failure), - connector_transaction_id: Some(app_response.id), - }), + response: Err(types::ErrorResponse::from(( + &app_response.error_information, + item.http_code, + app_response.id.clone(), + ))), status: enums::AttemptStatus::Failure, ..item.data }) @@ -1261,3 +1219,33 @@ pub struct ErrorInformation { pub struct AuthenticationErrorInformation { pub rmsg: String, } + +impl From<(&Option, u16, String)> for types::ErrorResponse { + fn from( + (error_data, status_code, transaction_id): ( + &Option, + u16, + String, + ), + ) -> Self { + let error_message = error_data + .clone() + .and_then(|error_details| error_details.message); + let error_reason = error_data + .clone() + .and_then(|error_details| error_details.reason); + + Self { + code: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason: error_message.clone(), + status_code, + attempt_status: Some(enums::AttemptStatus::Failure), + connector_transaction_id: Some(transaction_id.clone()), + } + } +} diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs index e6034f7af7f..e46833d2ecd 100644 --- a/crates/router/src/connector/cybersource/transformers.rs +++ b/crates/router/src/connector/cybersource/transformers.rs @@ -1147,18 +1147,21 @@ impl ), ) -> Self { Self { - response: Err(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), - message: error_response - .error_information - .message - .clone() - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: error_response.error_information.reason.clone(), - status_code: item.http_code, - attempt_status: None, - connector_transaction_id: Some(error_response.id.clone()), - }), + response: { + let error_reason = &error_response.error_information.reason; + Err(types::ErrorResponse { + code: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason: error_response.error_information.message.clone(), + status_code: item.http_code, + attempt_status: None, + connector_transaction_id: Some(error_response.id.clone()), + }) + }, ..item.data } } @@ -1171,60 +1174,17 @@ fn get_error_response_if_failure( u16, ), ) -> Option { - if is_payment_failure(status) { - let (message, reason) = match info_response.error_information.as_ref() { - Some(error_info) => ( - error_info - .message - .clone() - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - error_info.reason.clone(), - ), - None => (consts::NO_ERROR_MESSAGE.to_string(), None), - }; - - Some(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), - message, - reason, - status_code: http_code, - attempt_status: Some(enums::AttemptStatus::Failure), - connector_transaction_id: Some(info_response.id.clone()), - }) + if utils::is_payment_failure(status) { + Some(types::ErrorResponse::from(( + &info_response.error_information, + http_code, + info_response.id.clone(), + ))) } else { None } } -fn is_payment_failure(status: enums::AttemptStatus) -> bool { - match status { - common_enums::AttemptStatus::AuthenticationFailed - | common_enums::AttemptStatus::AuthorizationFailed - | common_enums::AttemptStatus::CaptureFailed - | common_enums::AttemptStatus::VoidFailed - | common_enums::AttemptStatus::Failure => true, - common_enums::AttemptStatus::Started - | common_enums::AttemptStatus::RouterDeclined - | common_enums::AttemptStatus::AuthenticationPending - | common_enums::AttemptStatus::AuthenticationSuccessful - | common_enums::AttemptStatus::Authorized - | common_enums::AttemptStatus::Charged - | common_enums::AttemptStatus::Authorizing - | common_enums::AttemptStatus::CodInitiated - | common_enums::AttemptStatus::Voided - | common_enums::AttemptStatus::VoidInitiated - | common_enums::AttemptStatus::CaptureInitiated - | common_enums::AttemptStatus::AutoRefunded - | common_enums::AttemptStatus::PartialCharged - | common_enums::AttemptStatus::PartialChargedAndChargeable - | common_enums::AttemptStatus::Unresolved - | common_enums::AttemptStatus::Pending - | common_enums::AttemptStatus::PaymentMethodAwaited - | common_enums::AttemptStatus::ConfirmationAwaited - | common_enums::AttemptStatus::DeviceDataCollectionPending => false, - } -} - fn get_payment_response( (info_response, status, http_code): ( &CybersourceClientReferenceResponse, @@ -1297,21 +1257,25 @@ impl ..item.data }) } - CybersourcePaymentsResponse::ErrorInformation(error_response) => Ok(Self { - response: Err(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), - message: error_response - .error_information - .message - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: error_response.error_information.reason, - status_code: item.http_code, - attempt_status: None, - connector_transaction_id: Some(error_response.id.clone()), - }), - status: enums::AttemptStatus::Failure, - ..item.data - }), + CybersourcePaymentsResponse::ErrorInformation(error_response) => { + let error_reason = &error_response.error_information.reason; + Ok(Self { + response: Err(types::ErrorResponse { + code: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason: error_response.error_information.message, + status_code: item.http_code, + attempt_status: None, + connector_transaction_id: Some(error_response.id.clone()), + }), + status: enums::AttemptStatus::Failure, + ..item.data + }) + } } } } @@ -1454,17 +1418,21 @@ impl }) } CybersourceSetupMandatesResponse::ErrorInformation(error_response) => Ok(Self { - response: Err(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), - message: error_response - .error_information - .message - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: error_response.error_information.reason, - status_code: item.http_code, - attempt_status: None, - connector_transaction_id: Some(error_response.id.clone()), - }), + response: { + let error_reason = &error_response.error_information.reason; + Err(types::ErrorResponse { + code: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason: error_response.error_information.message, + status_code: item.http_code, + attempt_status: None, + connector_transaction_id: Some(error_response.id.clone()), + }) + }, status: enums::AttemptStatus::Failure, ..item.data }), @@ -1569,25 +1537,13 @@ impl )); let incremental_authorization_allowed = Some(status == enums::AttemptStatus::Authorized); - if is_payment_failure(status) { - let (message, reason) = match app_response.error_information { - Some(error_info) => ( - error_info - .message - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - error_info.reason, - ), - None => (consts::NO_ERROR_MESSAGE.to_string(), None), - }; + if utils::is_payment_failure(status) { Ok(Self { - response: Err(types::ErrorResponse { - code: consts::NO_ERROR_CODE.to_string(), - message, - reason, - status_code: item.http_code, - attempt_status: Some(enums::AttemptStatus::Failure), - connector_transaction_id: Some(app_response.id), - }), + response: Err(types::ErrorResponse::from(( + &app_response.error_information, + item.http_code, + app_response.id.clone(), + ))), status: enums::AttemptStatus::Failure, ..item.data }) @@ -1802,3 +1758,34 @@ pub struct ErrorInformation { pub struct AuthenticationErrorInformation { pub rmsg: String, } + +impl From<(&Option, u16, String)> for types::ErrorResponse { + fn from( + (error_data, status_code, transaction_id): ( + &Option, + u16, + String, + ), + ) -> Self { + let error_message = error_data + .clone() + .and_then(|error_details| error_details.message); + + let error_reason = error_data + .clone() + .and_then(|error_details| error_details.reason); + + Self { + code: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: error_reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason: error_message.clone(), + status_code, + attempt_status: Some(enums::AttemptStatus::Failure), + connector_transaction_id: Some(transaction_id.clone()), + } + } +} diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index c44f8cd391e..0144a578eae 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -1797,3 +1797,43 @@ mod error_code_error_message_tests { assert_eq!(error_code_error_message_none, None); } } + +pub fn is_payment_failure(status: enums::AttemptStatus) -> bool { + match status { + common_enums::AttemptStatus::AuthenticationFailed + | common_enums::AttemptStatus::AuthorizationFailed + | common_enums::AttemptStatus::CaptureFailed + | common_enums::AttemptStatus::VoidFailed + | common_enums::AttemptStatus::Failure => true, + common_enums::AttemptStatus::Started + | common_enums::AttemptStatus::RouterDeclined + | common_enums::AttemptStatus::AuthenticationPending + | common_enums::AttemptStatus::AuthenticationSuccessful + | common_enums::AttemptStatus::Authorized + | common_enums::AttemptStatus::Charged + | common_enums::AttemptStatus::Authorizing + | common_enums::AttemptStatus::CodInitiated + | common_enums::AttemptStatus::Voided + | common_enums::AttemptStatus::VoidInitiated + | common_enums::AttemptStatus::CaptureInitiated + | common_enums::AttemptStatus::AutoRefunded + | common_enums::AttemptStatus::PartialCharged + | common_enums::AttemptStatus::PartialChargedAndChargeable + | common_enums::AttemptStatus::Unresolved + | common_enums::AttemptStatus::Pending + | common_enums::AttemptStatus::PaymentMethodAwaited + | common_enums::AttemptStatus::ConfirmationAwaited + | common_enums::AttemptStatus::DeviceDataCollectionPending => false, + } +} + +pub fn is_refund_failure(status: enums::RefundStatus) -> bool { + match status { + common_enums::RefundStatus::Failure | common_enums::RefundStatus::TransactionFailure => { + true + } + common_enums::RefundStatus::ManualReview + | common_enums::RefundStatus::Pending + | common_enums::RefundStatus::Success => false, + } +}