diff --git a/config/deployments/production.toml b/config/deployments/production.toml index 9b9b6aac22..355c75a396 100644 --- a/config/deployments/production.toml +++ b/config/deployments/production.toml @@ -253,6 +253,13 @@ debit = { currency = "USD" } apple_pay = { currency = "USD" } google_pay = { currency = "USD" } + +[pm_filters.cybersource] +credit = { currency = "USD" } +debit = { currency = "USD" } +apple_pay = { currency = "USD" } +google_pay = { currency = "USD" } + [pm_filters.braintree] paypal.currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,RUB,SGD,SEK,CHF,THB,USD" diff --git a/config/deployments/sandbox.toml b/config/deployments/sandbox.toml index 891e4b1f17..e5e44ae7ef 100644 --- a/config/deployments/sandbox.toml +++ b/config/deployments/sandbox.toml @@ -257,6 +257,12 @@ debit = { currency = "USD" } apple_pay = { currency = "USD" } google_pay = { currency = "USD" } +[pm_filters.cybersource] +credit = { currency = "USD" } +debit = { currency = "USD" } +apple_pay = { currency = "USD" } +google_pay = { currency = "USD" } + [pm_filters.braintree] paypal.currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,RUB,SGD,SEK,CHF,THB,USD" diff --git a/config/development.toml b/config/development.toml index a3f9eb54bb..8a249754d1 100644 --- a/config/development.toml +++ b/config/development.toml @@ -395,6 +395,13 @@ debit = { currency = "USD" } apple_pay = { currency = "USD" } google_pay = { currency = "USD" } + +[pm_filters.cybersource] +credit = { currency = "USD" } +debit = { currency = "USD" } +apple_pay = { currency = "USD" } +google_pay = { currency = "USD" } + [pm_filters.braintree] paypal = { currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,RUB,SGD,SEK,CHF,THB,USD" } credit = { not_available_flows = { capture_method = "manual" } } diff --git a/crates/router/src/connector/bankofamerica.rs b/crates/router/src/connector/bankofamerica.rs index c95fed8566..19bc3f9875 100644 --- a/crates/router/src/connector/bankofamerica.rs +++ b/crates/router/src/connector/bankofamerica.rs @@ -211,33 +211,57 @@ impl ConnectorCommon for Bankofamerica { }; match response { transformers::BankOfAmericaErrorResponse::StandardError(response) => { - let (code, connector_reason) = match response.error_information { - Some(ref error_info) => (error_info.reason.clone(), error_info.message.clone()), - None => ( - response - .reason - .map_or(consts::NO_ERROR_CODE.to_string(), |reason| { - reason.to_string() - }), - response - .message - .map_or(error_message.to_string(), |message| message), - ), - }; - let message = match response.details { - Some(details) => details - .iter() - .map(|det| format!("{} : {}", det.field, det.reason)) - .collect::>() - .join(", "), - None => connector_reason.clone(), + let (code, message, reason) = match response.error_information { + Some(ref error_info) => { + let detailed_error_info = error_info.details.as_ref().map(|details| { + details + .iter() + .map(|det| format!("{} : {}", det.field, det.reason)) + .collect::>() + .join(", ") + }); + ( + error_info.reason.clone(), + error_info.reason.clone(), + transformers::get_error_reason( + Some(error_info.message.clone()), + detailed_error_info, + None, + ), + ) + } + None => { + let detailed_error_info = response.details.map(|details| { + details + .iter() + .map(|det| format!("{} : {}", det.field, det.reason)) + .collect::>() + .join(", ") + }); + ( + response + .reason + .clone() + .map_or(consts::NO_ERROR_CODE.to_string(), |reason| { + reason.to_string() + }), + response + .reason + .map_or(error_message.to_string(), |reason| reason.to_string()), + transformers::get_error_reason( + response.message, + detailed_error_info, + None, + ), + ) + } }; Ok(ErrorResponse { status_code: res.status_code, code, message, - reason: Some(connector_reason), + reason, attempt_status: None, connector_transaction_id: None, }) diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs index 90151f12ae..7446749e73 100644 --- a/crates/router/src/connector/bankofamerica/transformers.rs +++ b/crates/router/src/connector/bankofamerica/transformers.rs @@ -106,6 +106,7 @@ pub enum BankOfAmericaActionsList { #[serde(rename_all = "camelCase")] pub enum BankOfAmericaActionsTokenType { PaymentInstrument, + Customer, } #[derive(Debug, Serialize)] @@ -202,11 +203,11 @@ pub struct ApplePayPaymentInformation { #[derive(Debug, Serialize)] #[serde(untagged)] pub enum PaymentInformation { - Cards(CardPaymentInformation), - GooglePay(GooglePayPaymentInformation), - ApplePay(ApplePayPaymentInformation), - ApplePayToken(ApplePayTokenPaymentInformation), - MandatePayment(MandatePaymentInformation), + Cards(Box), + GooglePay(Box), + ApplePay(Box), + ApplePayToken(Box), + MandatePayment(Box), } #[derive(Debug, Serialize)] @@ -422,9 +423,9 @@ impl ..item.data }) } - BankOfAmericaSetupMandatesResponse::ErrorInformation(ref error_response) => { + BankOfAmericaSetupMandatesResponse::ErrorInformation(error_response) => { let response = Err(types::ErrorResponse::foreign_from(( - error_response, + &*error_response, item.http_code, ))); Ok(Self { @@ -640,7 +641,10 @@ impl if is_customer_initiated_mandate_payment(&item.router_data.request) { ( Some(vec![BankOfAmericaActionsList::TokenCreate]), - Some(vec![BankOfAmericaActionsTokenType::PaymentInstrument]), + Some(vec![ + BankOfAmericaActionsTokenType::PaymentInstrument, + BankOfAmericaActionsTokenType::Customer, + ]), Some(BankOfAmericaAuthorizationOptions { initiator: Some(BankOfAmericaPaymentInitiator { initiator_type: Some(BankOfAmericaPaymentInitiatorTypes::Customer), @@ -1237,16 +1241,11 @@ impl let payment_instrument = BankOfAmericaPaymentInstrument { id: connector_mandate_id.into(), }; - let email = item.router_data.request.get_email().ok(); - let bill_to = email.and_then(|email_id| { - item.router_data - .get_billing() - .ok() - .and_then(|billing_details| build_bill_to(billing_details, email_id).ok()) - }); - let order_information = OrderInformationWithBill::from((item, bill_to)); + let order_information = OrderInformationWithBill::from((item, None)); let payment_information = - PaymentInformation::MandatePayment(MandatePaymentInformation { payment_instrument }); + PaymentInformation::MandatePayment(Box::new(MandatePaymentInformation { + payment_instrument, + })); let client_reference_information = ClientReferenceInformation::from(item); let merchant_defined_information = item.router_data.request.metadata.clone().map(|metadata| { @@ -1356,21 +1355,21 @@ pub struct ClientAuthSetupInfoResponse { #[serde(untagged)] pub enum BankOfAmericaAuthSetupResponse { ClientAuthSetupInfo(Box), - ErrorInformation(BankOfAmericaErrorInformationResponse), + ErrorInformation(Box), } #[derive(Debug, Deserialize, Serialize)] #[serde(untagged)] pub enum BankOfAmericaPaymentsResponse { ClientReferenceInformation(Box), - ErrorInformation(BankOfAmericaErrorInformationResponse), + ErrorInformation(Box), } #[derive(Debug, Deserialize, Serialize)] #[serde(untagged)] pub enum BankOfAmericaSetupMandatesResponse { ClientReferenceInformation(Box), - ErrorInformation(BankOfAmericaErrorInformationResponse), + ErrorInformation(Box), } #[derive(Clone, Debug, Deserialize, Serialize)] @@ -1539,6 +1538,7 @@ pub struct BankOfAmericaErrorInformationResponse { pub struct BankOfAmericaErrorInformation { reason: Option, message: Option, + details: Option>, } impl @@ -1560,22 +1560,41 @@ impl Option, ), ) -> Self { - let error_reason = error_response - .error_information - .message - .to_owned() - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()); - let error_message = error_response.error_information.reason.to_owned(); + let detailed_error_info = + error_response + .error_information + .details + .as_ref() + .map(|details| { + details + .iter() + .map(|details| format!("{} : {}", details.field, details.reason)) + .collect::>() + .join(", ") + }); + + let reason = get_error_reason( + error_response.error_information.message.clone(), + detailed_error_info, + None, + ); let response = Err(types::ErrorResponse { - code: error_message + code: error_response + .error_information + .reason .clone() .unwrap_or(consts::NO_ERROR_CODE.to_string()), - message: error_message.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: Some(error_reason), + message: error_response + .error_information + .reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason, status_code: item.http_code, attempt_status: None, connector_transaction_id: Some(error_response.id.clone()), }); + match transaction_status { Some(status) => Self { response, @@ -1704,18 +1723,37 @@ impl ..item.data }), BankOfAmericaAuthSetupResponse::ErrorInformation(error_response) => { - let error_reason = error_response - .error_information - .message - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()); - let error_message = error_response.error_information.reason; + let detailed_error_info = + error_response + .error_information + .to_owned() + .details + .map(|error_details| { + error_details + .iter() + .map(|details| format!("{} : {}", details.field, details.reason)) + .collect::>() + .join(", ") + }); + + let reason = get_error_reason( + error_response.error_information.message, + detailed_error_info, + None, + ); + Ok(Self { response: Err(types::ErrorResponse { - code: error_message + code: error_response + .error_information + .reason .clone() .unwrap_or(consts::NO_ERROR_CODE.to_string()), - message: error_message.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: Some(error_reason), + message: error_response + .error_information + .reason + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason, status_code: item.http_code, attempt_status: None, connector_transaction_id: Some(error_response.id.clone()), @@ -1767,8 +1805,8 @@ pub struct BankOfAmericaAuthValidateRequest { #[derive(Debug, Serialize)] #[serde(untagged)] pub enum BankOfAmericaPreProcessingRequest { - AuthEnrollment(BankOfAmericaAuthEnrollmentRequest), - AuthValidate(BankOfAmericaAuthValidateRequest), + AuthEnrollment(Box), + AuthValidate(Box), } impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsPreProcessingRouterData>> @@ -1840,16 +1878,21 @@ impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsPreProcessingRouterData>> amount_details, bill_to: Some(bill_to), }; - Ok(Self::AuthEnrollment(BankOfAmericaAuthEnrollmentRequest { - payment_information, - client_reference_information, - consumer_authentication_information: - BankOfAmericaConsumerAuthInformationRequest { - return_url: item.router_data.request.get_complete_authorize_url()?, - reference_id, - }, - order_information, - })) + Ok(Self::AuthEnrollment(Box::new( + BankOfAmericaAuthEnrollmentRequest { + payment_information, + client_reference_information, + consumer_authentication_information: + BankOfAmericaConsumerAuthInformationRequest { + return_url: item + .router_data + .request + .get_complete_authorize_url()?, + reference_id, + }, + order_information, + }, + ))) } Some(_) | None => { let redirect_payload: BankOfAmericaRedirectionAuthResponse = redirect_response @@ -1862,15 +1905,17 @@ impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsPreProcessingRouterData>> .parse_value("BankOfAmericaRedirectionAuthResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; let order_information = OrderInformation { amount_details }; - Ok(Self::AuthValidate(BankOfAmericaAuthValidateRequest { - payment_information, - client_reference_information, - consumer_authentication_information: - BankOfAmericaConsumerAuthInformationValidateRequest { - authentication_transaction_id: redirect_payload.transaction_id, - }, - order_information, - })) + Ok(Self::AuthValidate(Box::new( + BankOfAmericaAuthValidateRequest { + payment_information, + client_reference_information, + consumer_authentication_information: + BankOfAmericaConsumerAuthInformationValidateRequest { + authentication_transaction_id: redirect_payload.transaction_id, + }, + order_information, + }, + ))) } } } @@ -1960,7 +2005,7 @@ pub struct ClientAuthCheckInfoResponse { #[serde(untagged)] pub enum BankOfAmericaPreProcessingResponse { ClientAuthCheckInfo(Box), - ErrorInformation(BankOfAmericaErrorInformationResponse), + ErrorInformation(Box), } impl From for enums::AttemptStatus { @@ -2061,9 +2106,9 @@ impl }) } } - BankOfAmericaPreProcessingResponse::ErrorInformation(ref error_response) => { + BankOfAmericaPreProcessingResponse::ErrorInformation(error_response) => { let response = Err(types::ErrorResponse::foreign_from(( - error_response, + &*error_response, item.http_code, ))); Ok(Self { @@ -2141,7 +2186,7 @@ impl } BankOfAmericaPaymentsResponse::ErrorInformation(ref error_response) => { Ok(Self::foreign_from(( - &error_response.clone(), + &*error_response.clone(), item, Some(enums::AttemptStatus::Failure), ))) @@ -2214,7 +2259,7 @@ impl } BankOfAmericaPaymentsResponse::ErrorInformation(ref error_response) => { Ok(Self::foreign_from(( - &error_response.clone(), + &*error_response.clone(), item, Some(enums::AttemptStatus::Failure), ))) @@ -2291,7 +2336,7 @@ impl }) } BankOfAmericaPaymentsResponse::ErrorInformation(ref error_response) => { - Ok(Self::foreign_from((&error_response.clone(), item, None))) + Ok(Self::foreign_from((&*error_response.clone(), item, None))) } } } @@ -2328,22 +2373,15 @@ impl }) } BankOfAmericaPaymentsResponse::ErrorInformation(ref error_response) => { - Ok(Self::foreign_from((&error_response.clone(), item, None))) + Ok(Self::foreign_from((&*error_response.clone(), item, None))) } } } } -#[derive(Debug, Deserialize, Serialize)] -#[serde(untagged)] -pub enum BankOfAmericaTransactionResponse { - ApplicationInformation(Box), - ErrorInformation(BankOfAmericaErrorInformationResponse), -} - #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub struct BankOfAmericaApplicationInfoResponse { +pub struct BankOfAmericaTransactionResponse { id: String, application_information: ApplicationInformation, client_reference_information: Option, @@ -2368,7 +2406,7 @@ pub struct FraudMarkingInformation { #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ApplicationInformation { - status: BankofamericaPaymentStatus, + status: Option, } impl @@ -2390,19 +2428,20 @@ impl types::PaymentsResponseData, >, ) -> Result { - match item.response { - BankOfAmericaTransactionResponse::ApplicationInformation(app_response) => { + match item.response.application_information.status { + Some(app_status) => { let status = enums::AttemptStatus::foreign_from(( - app_response.application_information.status, + app_status, item.data.request.is_auto_capture()?, )); let connector_response = match item.data.payment_method { - common_enums::PaymentMethod::Card => app_response + common_enums::PaymentMethod::Card => item + .response .processor_information .as_ref() .and_then(|processor_information| { - app_response + item.response .consumer_authentication_information .as_ref() .map(|consumer_auth_information| { @@ -2430,11 +2469,11 @@ impl if utils::is_payment_failure(status) { Ok(Self { response: Err(types::ErrorResponse::foreign_from(( - &app_response.error_information, + &item.response.error_information, &risk_info, Some(status), item.http_code, - app_response.id.clone(), + item.response.id.clone(), ))), status: enums::AttemptStatus::Failure, connector_response, @@ -2445,16 +2484,17 @@ impl status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId( - app_response.id.clone(), + item.response.id.clone(), ), redirection_data: None, mandate_reference: None, connector_metadata: None, network_txn_id: None, - connector_response_reference_id: app_response + connector_response_reference_id: item + .response .client_reference_information .map(|cref| cref.code) - .unwrap_or(Some(app_response.id)), + .unwrap_or(Some(item.response.id)), incremental_authorization_allowed: None, charge_id: None, }), @@ -2463,17 +2503,17 @@ impl }) } } - BankOfAmericaTransactionResponse::ErrorInformation(error_response) => Ok(Self { + None => Ok(Self { status: item.data.status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId( - error_response.id.clone(), + item.response.id.clone(), ), redirection_data: None, mandate_reference: None, connector_metadata: None, network_txn_id: None, - connector_response_reference_id: Some(error_response.id), + connector_response_reference_id: Some(item.response.id), incremental_authorization_allowed: None, charge_id: None, }), @@ -2704,7 +2744,8 @@ impl TryFrom>, } #[derive(Debug, Default, Deserialize, Serialize)] @@ -2830,13 +2872,24 @@ impl }) }) .unwrap_or(Some("".to_string())); - let error_reason = error_data - .clone() - .map(|error_details| { - error_details.message.unwrap_or("".to_string()) - + &avs_message.unwrap_or("".to_string()) + + let detailed_error_info = error_data.to_owned().and_then(|error_info| { + error_info.details.map(|error_details| { + error_details + .iter() + .map(|details| format!("{} : {}", details.field, details.reason)) + .collect::>() + .join(", ") }) - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()); + }); + + let reason = get_error_reason( + error_data + .clone() + .and_then(|error_details| error_details.message), + detailed_error_info, + avs_message, + ); let error_message = error_data .clone() .and_then(|error_details| error_details.reason); @@ -2848,7 +2901,7 @@ impl message: error_message .clone() .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: Some(error_reason.clone()), + reason, status_code, attempt_status, connector_transaction_id: Some(transaction_id.clone()), @@ -3012,7 +3065,7 @@ impl TryFrom<&domain::Card> for PaymentInformation { Ok(issuer) => Some(String::from(issuer)), Err(_) => None, }; - Ok(Self::Cards(CardPaymentInformation { + Ok(Self::Cards(Box::new(CardPaymentInformation { card: Card { number: ccard.card_number.clone(), expiration_month: ccard.card_exp_month.clone(), @@ -3020,7 +3073,7 @@ impl TryFrom<&domain::Card> for PaymentInformation { security_code: ccard.card_cvc.clone(), card_type, }, - })) + }))) } } @@ -3031,7 +3084,7 @@ impl TryFrom<&Box> for PaymentInformation { let expiration_month = apple_pay_data.get_expiry_month()?; let expiration_year = apple_pay_data.get_four_digit_expiry_year()?; - Ok(Self::ApplePay(ApplePayPaymentInformation { + Ok(Self::ApplePay(Box::new(ApplePayPaymentInformation { tokenized_card: TokenizedCard { number: apple_pay_data.application_primary_account_number.clone(), cryptogram: apple_pay_data @@ -3042,32 +3095,32 @@ impl TryFrom<&Box> for PaymentInformation { expiration_year, expiration_month, }, - })) + }))) } } impl From<&domain::ApplePayWalletData> for PaymentInformation { fn from(apple_pay_data: &domain::ApplePayWalletData) -> Self { - Self::ApplePayToken(ApplePayTokenPaymentInformation { + Self::ApplePayToken(Box::new(ApplePayTokenPaymentInformation { fluid_data: FluidData { value: Secret::from(apple_pay_data.payment_data.clone()), }, tokenized_card: ApplePayTokenizedCard { transaction_type: TransactionType::ApplePay, }, - }) + })) } } impl From<&domain::GooglePayWalletData> for PaymentInformation { fn from(google_pay_data: &domain::GooglePayWalletData) -> Self { - Self::GooglePay(GooglePayPaymentInformation { + Self::GooglePay(Box::new(GooglePayPaymentInformation { fluid_data: FluidData { value: Secret::from( consts::BASE64_ENGINE.encode(google_pay_data.tokenization_data.token.clone()), ), }, - }) + })) } } @@ -3075,18 +3128,36 @@ impl ForeignFrom<(&BankOfAmericaErrorInformationResponse, u16)> for types::Error fn foreign_from( (error_response, status_code): (&BankOfAmericaErrorInformationResponse, u16), ) -> Self { - let error_reason = error_response - .error_information - .message - .to_owned() - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()); - let error_message = error_response.error_information.reason.to_owned(); + let detailed_error_info = + error_response + .error_information + .to_owned() + .details + .map(|error_details| { + error_details + .iter() + .map(|details| format!("{} : {}", details.field, details.reason)) + .collect::>() + .join(", ") + }); + + let reason = get_error_reason( + error_response.error_information.message.to_owned(), + detailed_error_info, + None, + ); Self { - code: error_message + code: error_response + .error_information + .reason .clone() .unwrap_or(consts::NO_ERROR_CODE.to_string()), - message: error_message.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: Some(error_reason), + message: error_response + .error_information + .reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason, status_code, attempt_status: None, connector_transaction_id: Some(error_response.id.clone()), @@ -3101,7 +3172,10 @@ fn get_boa_mandate_action_details() -> ( ) { ( Some(vec![BankOfAmericaActionsList::TokenCreate]), - Some(vec![BankOfAmericaActionsTokenType::PaymentInstrument]), + Some(vec![ + BankOfAmericaActionsTokenType::PaymentInstrument, + BankOfAmericaActionsTokenType::Customer, + ]), Some(BankOfAmericaAuthorizationOptions { initiator: Some(BankOfAmericaPaymentInitiator { initiator_type: Some(BankOfAmericaPaymentInitiatorTypes::Customer), @@ -3137,3 +3211,30 @@ fn is_customer_initiated_mandate_payment(item: &types::CompleteAuthorizeData) -> }) // add check for customer_acceptance } + +pub fn get_error_reason( + error_info: Option, + detailed_error_info: Option, + avs_error_info: Option, +) -> Option { + match (error_info, detailed_error_info, avs_error_info) { + (Some(message), Some(details), Some(avs_message)) => Some(format!( + "{}, detailed_error_information: {}, avs_message: {}", + message, details, avs_message + )), + (Some(message), Some(details), None) => Some(format!( + "{}, detailed_error_information: {}", + message, details + )), + (Some(message), None, Some(avs_message)) => { + Some(format!("{}, avs_message: {}", message, avs_message)) + } + (None, Some(details), Some(avs_message)) => { + Some(format!("{}, avs_message: {}", details, avs_message)) + } + (Some(message), None, None) => Some(message), + (None, Some(details), None) => Some(details), + (None, None, Some(avs_message)) => Some(avs_message), + (None, None, None) => None, + } +} diff --git a/crates/router/src/connector/cybersource.rs b/crates/router/src/connector/cybersource.rs index 3cccb8dcf5..1f8de46884 100644 --- a/crates/router/src/connector/cybersource.rs +++ b/crates/router/src/connector/cybersource.rs @@ -134,33 +134,58 @@ impl ConnectorCommon for Cybersource { Ok(transformers::CybersourceErrorResponse::StandardError(response)) => { event_builder.map(|i| i.set_error_response_body(&response)); router_env::logger::info!(connector_response=?response); - let (code, connector_reason) = match response.error_information { - Some(ref error_info) => (error_info.reason.clone(), error_info.message.clone()), - None => ( - response - .reason - .map_or(consts::NO_ERROR_CODE.to_string(), |reason| { - reason.to_string() - }), - response - .message - .map_or(error_message.to_string(), |message| message), - ), - }; - let message = match response.details { - Some(details) => details - .iter() - .map(|det| format!("{} : {}", det.field, det.reason)) - .collect::>() - .join(", "), - None => connector_reason.clone(), + + let (code, message, reason) = match response.error_information { + Some(ref error_info) => { + let detailed_error_info = error_info.details.as_ref().map(|details| { + details + .iter() + .map(|det| format!("{} : {}", det.field, det.reason)) + .collect::>() + .join(", ") + }); + ( + error_info.reason.clone(), + error_info.reason.clone(), + transformers::get_error_reason( + Some(error_info.message.clone()), + detailed_error_info, + None, + ), + ) + } + None => { + let detailed_error_info = response.details.map(|details| { + details + .iter() + .map(|det| format!("{} : {}", det.field, det.reason)) + .collect::>() + .join(", ") + }); + ( + response + .reason + .clone() + .map_or(consts::NO_ERROR_CODE.to_string(), |reason| { + reason.to_string() + }), + response + .reason + .map_or(error_message.to_string(), |reason| reason.to_string()), + transformers::get_error_reason( + response.message, + detailed_error_info, + None, + ), + ) + } }; Ok(types::ErrorResponse { status_code: res.status_code, code, message, - reason: Some(connector_reason), + reason, attempt_status: None, connector_transaction_id: None, }) @@ -410,6 +435,38 @@ impl ) -> CustomResult { self.build_error_response(res, event_builder) } + + fn get_5xx_error_response( + &self, + res: types::Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + let response: cybersource::CybersourceServerErrorResponse = res + .response + .parse_struct("CybersourceServerErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + + event_builder.map(|event| event.set_response_body(&response)); + router_env::logger::info!(error_response=?response); + + let attempt_status = match response.reason { + Some(reason) => match reason { + transformers::Reason::SystemError => Some(enums::AttemptStatus::Failure), + transformers::Reason::ServerTimeout | transformers::Reason::ServiceTimeout => None, + }, + None => None, + }; + Ok(types::ErrorResponse { + status_code: res.status_code, + reason: response.status.clone(), + code: response.status.unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: response + .message + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + attempt_status, + connector_transaction_id: None, + }) + } } impl diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs index b800563364..3250cb1ba8 100644 --- a/crates/router/src/connector/cybersource/transformers.rs +++ b/crates/router/src/connector/cybersource/transformers.rs @@ -76,7 +76,10 @@ impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest { }; let (action_list, action_token_types, authorization_options) = ( Some(vec![CybersourceActionsList::TokenCreate]), - Some(vec![CybersourceActionsTokenType::PaymentInstrument]), + Some(vec![ + CybersourceActionsTokenType::PaymentInstrument, + CybersourceActionsTokenType::Customer, + ]), Some(CybersourceAuthorizationOptions { initiator: Some(CybersourcePaymentInitiator { initiator_type: Some(CybersourcePaymentInitiatorTypes::Customer), @@ -99,7 +102,7 @@ impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest { Err(_) => None, }; ( - PaymentInformation::Cards(CardPaymentInformation { + PaymentInformation::Cards(Box::new(CardPaymentInformation { card: Card { number: ccard.card_number, expiration_month: ccard.card_exp_month, @@ -107,7 +110,7 @@ impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest { security_code: Some(ccard.card_cvc), card_type, }, - }), + })), None, ) } @@ -120,17 +123,20 @@ impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest { let expiration_month = decrypt_data.get_expiry_month()?; let expiration_year = decrypt_data.get_four_digit_expiry_year()?; ( - PaymentInformation::ApplePay(ApplePayPaymentInformation { - tokenized_card: TokenizedCard { - number: decrypt_data.application_primary_account_number, - cryptogram: decrypt_data - .payment_data - .online_payment_cryptogram, - transaction_type: TransactionType::ApplePay, - expiration_year, - expiration_month, + PaymentInformation::ApplePay(Box::new( + ApplePayPaymentInformation { + tokenized_card: TokenizedCard { + number: decrypt_data + .application_primary_account_number, + cryptogram: decrypt_data + .payment_data + .online_payment_cryptogram, + transaction_type: TransactionType::ApplePay, + expiration_year, + expiration_month, + }, }, - }), + )), Some(PaymentSolution::ApplePay), ) } @@ -139,21 +145,23 @@ impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest { )?, }, None => ( - PaymentInformation::ApplePayToken(ApplePayTokenPaymentInformation { - fluid_data: FluidData { - value: Secret::from(apple_pay_data.payment_data), - descriptor: Some(FLUID_DATA_DESCRIPTOR.to_string()), + PaymentInformation::ApplePayToken(Box::new( + ApplePayTokenPaymentInformation { + fluid_data: FluidData { + value: Secret::from(apple_pay_data.payment_data), + descriptor: Some(FLUID_DATA_DESCRIPTOR.to_string()), + }, + tokenized_card: ApplePayTokenizedCard { + transaction_type: TransactionType::ApplePay, + }, }, - tokenized_card: ApplePayTokenizedCard { - transaction_type: TransactionType::ApplePay, - }, - }), + )), Some(PaymentSolution::ApplePay), ), } } domain::WalletData::GooglePay(google_pay_data) => ( - PaymentInformation::GooglePay(GooglePayPaymentInformation { + PaymentInformation::GooglePay(Box::new(GooglePayPaymentInformation { fluid_data: FluidData { value: Secret::from( consts::BASE64_ENGINE @@ -161,7 +169,7 @@ impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest { ), descriptor: None, }, - }), + })), Some(PaymentSolution::GooglePay), ), domain::WalletData::AliPayQr(_) @@ -287,6 +295,7 @@ pub enum CybersourceActionsList { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub enum CybersourceActionsTokenType { + Customer, PaymentInstrument, } @@ -389,11 +398,11 @@ pub struct GooglePayPaymentInformation { #[derive(Debug, Serialize)] #[serde(untagged)] pub enum PaymentInformation { - Cards(CardPaymentInformation), - GooglePay(GooglePayPaymentInformation), - ApplePay(ApplePayPaymentInformation), - ApplePayToken(ApplePayTokenPaymentInformation), - MandatePayment(MandatePaymentInformation), + Cards(Box), + GooglePay(Box), + ApplePay(Box), + ApplePayToken(Box), + MandatePayment(Box), } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -549,7 +558,10 @@ impl })) { ( Some(vec![CybersourceActionsList::TokenCreate]), - Some(vec![CybersourceActionsTokenType::PaymentInstrument]), + Some(vec![ + CybersourceActionsTokenType::PaymentInstrument, + CybersourceActionsTokenType::Customer, + ]), Some(CybersourceAuthorizationOptions { initiator: Some(CybersourcePaymentInitiator { initiator_type: Some(CybersourcePaymentInitiatorTypes::Customer), @@ -768,7 +780,10 @@ impl { ( Some(vec![CybersourceActionsList::TokenCreate]), - Some(vec![CybersourceActionsTokenType::PaymentInstrument]), + Some(vec![ + CybersourceActionsTokenType::PaymentInstrument, + CybersourceActionsTokenType::Customer, + ]), Some(CybersourceAuthorizationOptions { initiator: Some(CybersourcePaymentInitiator { initiator_type: Some(CybersourcePaymentInitiatorTypes::Customer), @@ -802,13 +817,13 @@ impl impl From<( &CybersourceRouterData<&types::PaymentsAuthorizeRouterData>, - BillTo, + Option, )> for OrderInformationWithBill { fn from( (item, bill_to): ( &CybersourceRouterData<&types::PaymentsAuthorizeRouterData>, - BillTo, + Option, ), ) -> Self { Self { @@ -816,7 +831,7 @@ impl total_amount: item.amount.to_owned(), currency: item.router_data.request.currency, }, - bill_to: Some(bill_to), + bill_to, } } } @@ -900,7 +915,7 @@ impl ) -> Result { let email = item.router_data.request.get_email()?; let bill_to = build_bill_to(item.router_data.get_billing()?, email)?; - let order_information = OrderInformationWithBill::from((item, bill_to)); + let order_information = OrderInformationWithBill::from((item, Some(bill_to))); let card_issuer = ccard.get_card_issuer(); let card_type = match card_issuer { @@ -908,7 +923,7 @@ impl Err(_) => None, }; - let payment_information = PaymentInformation::Cards(CardPaymentInformation { + let payment_information = PaymentInformation::Cards(Box::new(CardPaymentInformation { card: Card { number: ccard.card_number, expiration_month: ccard.card_exp_month, @@ -916,7 +931,7 @@ impl security_code: Some(ccard.card_cvc), card_type: card_type.clone(), }, - }); + })); let processing_information = ProcessingInformation::try_from((item, None, card_type))?; let client_reference_information = ClientReferenceInformation::from(item); @@ -986,7 +1001,7 @@ impl Err(_) => None, }; - let payment_information = PaymentInformation::Cards(CardPaymentInformation { + let payment_information = PaymentInformation::Cards(Box::new(CardPaymentInformation { card: Card { number: ccard.card_number, expiration_month: ccard.card_exp_month, @@ -994,7 +1009,7 @@ impl security_code: Some(ccard.card_cvc), card_type, }, - }); + })); let client_reference_information = ClientReferenceInformation::from(item); let three_ds_info: CybersourceThreeDSMetadata = item @@ -1059,7 +1074,7 @@ impl ) -> Result { let email = item.router_data.request.get_email()?; let bill_to = build_bill_to(item.router_data.get_billing()?, email)?; - let order_information = OrderInformationWithBill::from((item, bill_to)); + let order_information = OrderInformationWithBill::from((item, Some(bill_to))); let processing_information = ProcessingInformation::try_from(( item, Some(PaymentSolution::ApplePay), @@ -1068,15 +1083,16 @@ impl let client_reference_information = ClientReferenceInformation::from(item); let expiration_month = apple_pay_data.get_expiry_month()?; let expiration_year = apple_pay_data.get_four_digit_expiry_year()?; - let payment_information = PaymentInformation::ApplePay(ApplePayPaymentInformation { - tokenized_card: TokenizedCard { - number: apple_pay_data.application_primary_account_number, - cryptogram: apple_pay_data.payment_data.online_payment_cryptogram, - transaction_type: TransactionType::ApplePay, - expiration_year, - expiration_month, - }, - }); + let payment_information = + PaymentInformation::ApplePay(Box::new(ApplePayPaymentInformation { + tokenized_card: TokenizedCard { + number: apple_pay_data.application_primary_account_number, + cryptogram: apple_pay_data.payment_data.online_payment_cryptogram, + transaction_type: TransactionType::ApplePay, + expiration_year, + expiration_month, + }, + })); let merchant_defined_information = item.router_data.request.metadata.clone().map(|metadata| { Vec::::foreign_from(metadata.peek().to_owned()) @@ -1125,16 +1141,17 @@ impl ) -> Result { let email = item.router_data.request.get_email()?; let bill_to = build_bill_to(item.router_data.get_billing()?, email)?; - let order_information = OrderInformationWithBill::from((item, bill_to)); + let order_information = OrderInformationWithBill::from((item, Some(bill_to))); - let payment_information = PaymentInformation::GooglePay(GooglePayPaymentInformation { - fluid_data: FluidData { - value: Secret::from( - consts::BASE64_ENGINE.encode(google_pay_data.tokenization_data.token), - ), - descriptor: None, - }, - }); + let payment_information = + PaymentInformation::GooglePay(Box::new(GooglePayPaymentInformation { + fluid_data: FluidData { + value: Secret::from( + consts::BASE64_ENGINE.encode(google_pay_data.tokenization_data.token), + ), + descriptor: None, + }, + })); let processing_information = ProcessingInformation::try_from((item, Some(PaymentSolution::GooglePay), None))?; let client_reference_information = ClientReferenceInformation::from(item); @@ -1186,7 +1203,7 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>> let bill_to = build_bill_to(item.router_data.get_billing()?, email)?; let order_information = - OrderInformationWithBill::from((item, bill_to)); + OrderInformationWithBill::from((item, Some(bill_to))); let processing_information = ProcessingInformation::try_from(( item, @@ -1196,7 +1213,7 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>> let client_reference_information = ClientReferenceInformation::from(item); let payment_information = PaymentInformation::ApplePayToken( - ApplePayTokenPaymentInformation { + Box::new(ApplePayTokenPaymentInformation { fluid_data: FluidData { value: Secret::from(apple_pay_data.payment_data), descriptor: Some(FLUID_DATA_DESCRIPTOR.to_string()), @@ -1204,7 +1221,7 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>> tokenized_card: ApplePayTokenizedCard { transaction_type: TransactionType::ApplePay, }, - }, + }), ); let merchant_defined_information = item.router_data.request.metadata.clone().map(|metadata| { @@ -1328,11 +1345,11 @@ impl let payment_instrument = CybersoucrePaymentInstrument { id: connector_mandate_id.into(), }; - let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(item.router_data.get_billing()?, email)?; - let order_information = OrderInformationWithBill::from((item, bill_to)); + let order_information = OrderInformationWithBill::from((item, None)); let payment_information = - PaymentInformation::MandatePayment(MandatePaymentInformation { payment_instrument }); + PaymentInformation::MandatePayment(Box::new(MandatePaymentInformation { + payment_instrument, + })); let client_reference_information = ClientReferenceInformation::from(item); let merchant_defined_information = item.router_data.request.metadata.clone().map(|metadata| { @@ -1370,15 +1387,16 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>> Ok(issuer) => Some(String::from(issuer)), Err(_) => None, }; - let payment_information = PaymentInformation::Cards(CardPaymentInformation { - card: Card { - number: ccard.card_number, - expiration_month: ccard.card_exp_month, - expiration_year: ccard.card_exp_year, - security_code: Some(ccard.card_cvc), - card_type, - }, - }); + let payment_information = + PaymentInformation::Cards(Box::new(CardPaymentInformation { + card: Card { + number: ccard.card_number, + expiration_month: ccard.card_exp_month, + expiration_year: ccard.card_exp_year, + security_code: Some(ccard.card_cvc), + card_type, + }, + })); let client_reference_information = ClientReferenceInformation::from(item); Ok(Self { payment_information, @@ -1664,8 +1682,8 @@ impl From for common_enums::Authoriza #[derive(Debug, Deserialize, Serialize)] #[serde(untagged)] pub enum CybersourcePaymentsResponse { - ClientReferenceInformation(CybersourceClientReferenceResponse), - ErrorInformation(CybersourceErrorInformationResponse), + ClientReferenceInformation(Box), + ErrorInformation(Box), } #[derive(Clone, Debug, Deserialize, Serialize)] @@ -1706,8 +1724,8 @@ pub struct ClientAuthSetupInfoResponse { #[derive(Debug, Deserialize, Serialize)] #[serde(untagged)] pub enum CybersourceAuthSetupResponse { - ClientAuthSetupInfo(ClientAuthSetupInfoResponse), - ErrorInformation(CybersourceErrorInformationResponse), + ClientAuthSetupInfo(Box), + ErrorInformation(Box), } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -1720,8 +1738,8 @@ pub struct CybersourcePaymentsIncrementalAuthorizationResponse { #[derive(Debug, Deserialize, Serialize)] #[serde(untagged)] pub enum CybersourceSetupMandatesResponse { - ClientReferenceInformation(CybersourceClientReferenceResponse), - ErrorInformation(CybersourceErrorInformationResponse), + ClientReferenceInformation(Box), + ErrorInformation(Box), } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -1773,6 +1791,7 @@ pub struct CybersourceTokenInformation { pub struct CybersourceErrorInformation { reason: Option, message: Option, + details: Option>, } impl @@ -1794,18 +1813,36 @@ impl Option, ), ) -> Self { - let error_reason = error_response - .error_information - .message - .to_owned() - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()); - let error_message = error_response.error_information.reason.to_owned(); + let detailed_error_info = + error_response + .error_information + .details + .to_owned() + .map(|details| { + details + .iter() + .map(|details| format!("{} : {}", details.field, details.reason)) + .collect::>() + .join(", ") + }); + + let reason = get_error_reason( + error_response.error_information.message.clone(), + detailed_error_info, + None, + ); let response = Err(types::ErrorResponse { - code: error_message + code: error_response + .error_information + .reason .clone() .unwrap_or(consts::NO_ERROR_CODE.to_string()), - message: error_message.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: Some(error_reason), + message: error_response + .error_information + .reason + .clone() + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + reason, status_code: item.http_code, attempt_status: None, connector_transaction_id: Some(error_response.id.clone()), @@ -1931,7 +1968,7 @@ impl } CybersourcePaymentsResponse::ErrorInformation(ref error_response) => { Ok(Self::foreign_from(( - &error_response.clone(), + &*error_response.clone(), item, Some(enums::AttemptStatus::Failure), ))) @@ -1990,10 +2027,24 @@ impl ..item.data }), CybersourceAuthSetupResponse::ErrorInformation(error_response) => { - let error_reason = error_response - .error_information - .message - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()); + let detailed_error_info = + error_response + .error_information + .details + .to_owned() + .map(|details| { + details + .iter() + .map(|details| format!("{} : {}", details.field, details.reason)) + .collect::>() + .join(", ") + }); + + let reason = get_error_reason( + error_response.error_information.message, + detailed_error_info, + None, + ); let error_message = error_response.error_information.reason; Ok(Self { response: Err(types::ErrorResponse { @@ -2001,7 +2052,7 @@ impl .clone() .unwrap_or(consts::NO_ERROR_CODE.to_string()), message: error_message.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: Some(error_reason), + reason, status_code: item.http_code, attempt_status: None, connector_transaction_id: Some(error_response.id.clone()), @@ -2053,8 +2104,8 @@ pub struct CybersourceAuthValidateRequest { #[derive(Debug, Serialize)] #[serde(untagged)] pub enum CybersourcePreProcessingRequest { - AuthEnrollment(CybersourceAuthEnrollmentRequest), - AuthValidate(CybersourceAuthValidateRequest), + AuthEnrollment(Box), + AuthValidate(Box), } impl TryFrom<&CybersourceRouterData<&types::PaymentsPreProcessingRouterData>> @@ -2079,15 +2130,17 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsPreProcessingRouterData>> Ok(issuer) => Some(String::from(issuer)), Err(_) => None, }; - Ok(PaymentInformation::Cards(CardPaymentInformation { - card: Card { - number: ccard.card_number, - expiration_month: ccard.card_exp_month, - expiration_year: ccard.card_exp_year, - security_code: Some(ccard.card_cvc), - card_type, + Ok(PaymentInformation::Cards(Box::new( + CardPaymentInformation { + card: Card { + number: ccard.card_number, + expiration_month: ccard.card_exp_month, + expiration_year: ccard.card_exp_year, + security_code: Some(ccard.card_cvc), + card_type, + }, }, - })) + ))) } domain::PaymentMethodData::Wallet(_) | domain::PaymentMethodData::CardRedirect(_) @@ -2140,16 +2193,21 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsPreProcessingRouterData>> amount_details, bill_to: Some(bill_to), }; - Ok(Self::AuthEnrollment(CybersourceAuthEnrollmentRequest { - payment_information, - client_reference_information, - consumer_authentication_information: - CybersourceConsumerAuthInformationRequest { - return_url: item.router_data.request.get_complete_authorize_url()?, - reference_id, - }, - order_information, - })) + Ok(Self::AuthEnrollment(Box::new( + CybersourceAuthEnrollmentRequest { + payment_information, + client_reference_information, + consumer_authentication_information: + CybersourceConsumerAuthInformationRequest { + return_url: item + .router_data + .request + .get_complete_authorize_url()?, + reference_id, + }, + order_information, + }, + ))) } Some(_) | None => { let redirect_payload: CybersourceRedirectionAuthResponse = redirect_response @@ -2162,15 +2220,17 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsPreProcessingRouterData>> .parse_value("CybersourceRedirectionAuthResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; let order_information = OrderInformation { amount_details }; - Ok(Self::AuthValidate(CybersourceAuthValidateRequest { - payment_information, - client_reference_information, - consumer_authentication_information: - CybersourceConsumerAuthInformationValidateRequest { - authentication_transaction_id: redirect_payload.transaction_id, - }, - order_information, - })) + Ok(Self::AuthValidate(Box::new( + CybersourceAuthValidateRequest { + payment_information, + client_reference_information, + consumer_authentication_information: + CybersourceConsumerAuthInformationValidateRequest { + authentication_transaction_id: redirect_payload.transaction_id, + }, + order_information, + }, + ))) } } } @@ -2260,7 +2320,7 @@ pub struct ClientAuthCheckInfoResponse { #[serde(untagged)] pub enum CybersourcePreProcessingResponse { ClientAuthCheckInfo(Box), - ErrorInformation(CybersourceErrorInformationResponse), + ErrorInformation(Box), } impl From for enums::AttemptStatus { @@ -2360,19 +2420,32 @@ impl }) } } - CybersourcePreProcessingResponse::ErrorInformation(ref error_response) => { - let error_reason = error_response - .error_information - .message - .to_owned() - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()); + CybersourcePreProcessingResponse::ErrorInformation(error_response) => { + let detailed_error_info = + error_response + .error_information + .details + .to_owned() + .map(|details| { + details + .iter() + .map(|details| format!("{} : {}", details.field, details.reason)) + .collect::>() + .join(", ") + }); + + let reason = get_error_reason( + error_response.error_information.message, + detailed_error_info, + None, + ); let error_message = error_response.error_information.reason.to_owned(); let response = Err(types::ErrorResponse { code: error_message .clone() .unwrap_or(consts::NO_ERROR_CODE.to_string()), message: error_message.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: Some(error_reason), + reason, status_code: item.http_code, attempt_status: None, connector_transaction_id: Some(error_response.id.clone()), @@ -2428,7 +2501,7 @@ impl } CybersourcePaymentsResponse::ErrorInformation(ref error_response) => { Ok(Self::foreign_from(( - &error_response.clone(), + &*error_response.clone(), item, Some(enums::AttemptStatus::Failure), ))) @@ -2481,7 +2554,7 @@ impl }) } CybersourcePaymentsResponse::ErrorInformation(ref error_response) => { - Ok(Self::foreign_from((&error_response.clone(), item, None))) + Ok(Self::foreign_from((&*error_response.clone(), item, None))) } } } @@ -2518,7 +2591,7 @@ impl }) } CybersourcePaymentsResponse::ErrorInformation(ref error_response) => { - Ok(Self::foreign_from((&error_response.clone(), item, None))) + Ok(Self::foreign_from((&*error_response.clone(), item, None))) } } } @@ -2602,19 +2675,32 @@ impl ..item.data }) } - CybersourceSetupMandatesResponse::ErrorInformation(ref error_response) => { - let error_reason = error_response - .error_information - .message - .to_owned() - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()); + CybersourceSetupMandatesResponse::ErrorInformation(error_response) => { + let detailed_error_info = + error_response + .error_information + .details + .to_owned() + .map(|details| { + details + .iter() + .map(|details| format!("{} : {}", details.field, details.reason)) + .collect::>() + .join(", ") + }); + + let reason = get_error_reason( + error_response.error_information.clone().message, + detailed_error_info, + None, + ); let error_message = error_response.error_information.reason.to_owned(); let response = Err(types::ErrorResponse { code: error_message .clone() .unwrap_or(consts::NO_ERROR_CODE.to_string()), message: error_message.unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: Some(error_reason), + reason, status_code: item.http_code, attempt_status: None, connector_transaction_id: Some(error_response.id.clone()), @@ -2677,16 +2763,9 @@ impl } } -#[derive(Debug, Deserialize, Serialize)] -#[serde(untagged)] -pub enum CybersourceTransactionResponse { - ApplicationInformation(CybersourceApplicationInfoResponse), - ErrorInformation(CybersourceErrorInformationResponse), -} - #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -pub struct CybersourceApplicationInfoResponse { +pub struct CybersourceTransactionResponse { id: String, application_information: ApplicationInformation, client_reference_information: Option, @@ -2696,7 +2775,7 @@ pub struct CybersourceApplicationInfoResponse { #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ApplicationInformation { - status: CybersourcePaymentStatus, + status: Option, } impl @@ -2718,10 +2797,10 @@ impl types::PaymentsResponseData, >, ) -> Result { - match item.response { - CybersourceTransactionResponse::ApplicationInformation(app_response) => { + match item.response.application_information.status { + Some(status) => { let status = enums::AttemptStatus::foreign_from(( - app_response.application_information.status, + status, item.data.request.is_auto_capture()?, )); let incremental_authorization_allowed = @@ -2730,11 +2809,11 @@ impl if utils::is_payment_failure(status) { Ok(Self { response: Err(types::ErrorResponse::foreign_from(( - &app_response.error_information, + &item.response.error_information, &risk_info, Some(status), item.http_code, - app_response.id.clone(), + item.response.id.clone(), ))), status: enums::AttemptStatus::Failure, ..item.data @@ -2744,16 +2823,17 @@ impl status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId( - app_response.id.clone(), + item.response.id.clone(), ), redirection_data: None, mandate_reference: None, connector_metadata: None, network_txn_id: None, - connector_response_reference_id: app_response + connector_response_reference_id: item + .response .client_reference_information .map(|cref| cref.code) - .unwrap_or(Some(app_response.id)), + .unwrap_or(Some(item.response.id)), incremental_authorization_allowed, charge_id: None, }), @@ -2761,17 +2841,17 @@ impl }) } } - CybersourceTransactionResponse::ErrorInformation(error_response) => Ok(Self { + None => Ok(Self { status: item.data.status, response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId( - error_response.id.clone(), + item.response.id.clone(), ), redirection_data: None, mandate_reference: None, connector_metadata: None, network_txn_id: None, - connector_response_reference_id: Some(error_response.id), + connector_response_reference_id: Some(item.response.id), incremental_authorization_allowed: None, charge_id: None, }), @@ -2903,7 +2983,8 @@ impl TryFrom for PaymentInformation { security_code: None, card_type, }; - Ok(Self::Cards(CardPaymentInformation { card })) + Ok(Self::Cards(Box::new(CardPaymentInformation { card }))) } PayoutMethodData::Bank(_) | PayoutMethodData::Wallet(_) => { Err(errors::ConnectorError::NotSupported { @@ -3208,10 +3289,10 @@ pub struct CybersourceAuthenticationErrorResponse { #[derive(Debug, Deserialize, Serialize)] #[serde(untagged)] pub enum CybersourceErrorResponse { - AuthenticationError(CybersourceAuthenticationErrorResponse), + AuthenticationError(Box), //If the request resource is not available/exists in cybersource - NotAvailableError(CybersourceNotAvailableErrorResponse), - StandardError(CybersourceStandardErrorResponse), + NotAvailableError(Box), + StandardError(Box), } #[derive(Debug, Deserialize, Clone, Serialize)] @@ -3225,6 +3306,7 @@ pub struct Details { pub struct ErrorInformation { pub message: String, pub reason: String, + pub details: Option>, } #[derive(Debug, Default, Deserialize, Serialize)] @@ -3262,17 +3344,24 @@ impl }) }) .unwrap_or(Some("".to_string())); - let error_reason = error_data - .clone() - .map(|error_details| { - error_details.message.unwrap_or("".to_string()) - + &avs_message.unwrap_or("".to_string()) - }) - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()); - let error_message = error_data - .clone() - .and_then(|error_details| error_details.reason); + let detailed_error_info = error_data + .clone() + .map(|error_data| match error_data.details { + Some(details) => details + .iter() + .map(|details| format!("{} : {}", details.field, details.reason)) + .collect::>() + .join(", "), + None => "".to_string(), + }); + + let reason = get_error_reason( + error_data.clone().and_then(|error_info| error_info.message), + detailed_error_info, + avs_message, + ); + let error_message = error_data.clone().and_then(|error_info| error_info.reason); Self { code: error_message .clone() @@ -3280,10 +3369,37 @@ impl message: error_message .clone() .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), - reason: Some(error_reason.clone()), + reason, status_code, attempt_status, connector_transaction_id: Some(transaction_id.clone()), } } } + +pub fn get_error_reason( + error_info: Option, + detailed_error_info: Option, + avs_error_info: Option, +) -> Option { + match (error_info, detailed_error_info, avs_error_info) { + (Some(message), Some(details), Some(avs_message)) => Some(format!( + "{}, detailed_error_information: {}, avs_message: {}", + message, details, avs_message + )), + (Some(message), Some(details), None) => Some(format!( + "{}, detailed_error_information: {}", + message, details + )), + (Some(message), None, Some(avs_message)) => { + Some(format!("{}, avs_message: {}", message, avs_message)) + } + (None, Some(details), Some(avs_message)) => { + Some(format!("{}, avs_message: {}", details, avs_message)) + } + (Some(message), None, None) => Some(message), + (None, Some(details), None) => Some(details), + (None, None, Some(avs_message)) => Some(avs_message), + (None, None, None) => None, + } +}