mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	refactor(connector): [BOA/CYBS] add customer token for mandates and refactor psync (#4815)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
		| @ -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" | ||||
|  | ||||
|  | ||||
| @ -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" | ||||
|  | ||||
|  | ||||
| @ -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" } } | ||||
|  | ||||
| @ -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::<Vec<_>>() | ||||
|                         .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::<Vec<_>>() | ||||
|                                 .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::<Vec<_>>() | ||||
|                                 .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, | ||||
|                 }) | ||||
|  | ||||
| @ -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<CardPaymentInformation>), | ||||
|     GooglePay(Box<GooglePayPaymentInformation>), | ||||
|     ApplePay(Box<ApplePayPaymentInformation>), | ||||
|     ApplePayToken(Box<ApplePayTokenPaymentInformation>), | ||||
|     MandatePayment(Box<MandatePaymentInformation>), | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Serialize)] | ||||
| @ -422,9 +423,9 @@ impl<F, T> | ||||
|                     ..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<ClientAuthSetupInfoResponse>), | ||||
|     ErrorInformation(BankOfAmericaErrorInformationResponse), | ||||
|     ErrorInformation(Box<BankOfAmericaErrorInformationResponse>), | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Deserialize, Serialize)] | ||||
| #[serde(untagged)] | ||||
| pub enum BankOfAmericaPaymentsResponse { | ||||
|     ClientReferenceInformation(Box<BankOfAmericaClientReferenceResponse>), | ||||
|     ErrorInformation(BankOfAmericaErrorInformationResponse), | ||||
|     ErrorInformation(Box<BankOfAmericaErrorInformationResponse>), | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Deserialize, Serialize)] | ||||
| #[serde(untagged)] | ||||
| pub enum BankOfAmericaSetupMandatesResponse { | ||||
|     ClientReferenceInformation(Box<BankOfAmericaClientReferenceResponse>), | ||||
|     ErrorInformation(BankOfAmericaErrorInformationResponse), | ||||
|     ErrorInformation(Box<BankOfAmericaErrorInformationResponse>), | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Debug, Deserialize, Serialize)] | ||||
| @ -1539,6 +1538,7 @@ pub struct BankOfAmericaErrorInformationResponse { | ||||
| pub struct BankOfAmericaErrorInformation { | ||||
|     reason: Option<String>, | ||||
|     message: Option<String>, | ||||
|     details: Option<Vec<Details>>, | ||||
| } | ||||
|  | ||||
| impl<F, T> | ||||
| @ -1560,22 +1560,41 @@ impl<F, T> | ||||
|             Option<enums::AttemptStatus>, | ||||
|         ), | ||||
|     ) -> 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::<Vec<_>>() | ||||
|                         .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<F, T> | ||||
|                 ..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::<Vec<_>>() | ||||
|                                 .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<BankOfAmericaAuthEnrollmentRequest>), | ||||
|     AuthValidate(Box<BankOfAmericaAuthValidateRequest>), | ||||
| } | ||||
|  | ||||
| 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<ClientAuthCheckInfoResponse>), | ||||
|     ErrorInformation(BankOfAmericaErrorInformationResponse), | ||||
|     ErrorInformation(Box<BankOfAmericaErrorInformationResponse>), | ||||
| } | ||||
|  | ||||
| impl From<BankOfAmericaAuthEnrollmentStatus> for enums::AttemptStatus { | ||||
| @ -2061,9 +2106,9 @@ impl<F> | ||||
|                     }) | ||||
|                 } | ||||
|             } | ||||
|             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<F> | ||||
|             } | ||||
|             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<F> | ||||
|             } | ||||
|             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<F> | ||||
|                 }) | ||||
|             } | ||||
|             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<F> | ||||
|                 }) | ||||
|             } | ||||
|             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<BankOfAmericaApplicationInfoResponse>), | ||||
|     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<ClientReferenceInformation>, | ||||
| @ -2368,7 +2406,7 @@ pub struct FraudMarkingInformation { | ||||
| #[derive(Debug, Deserialize, Serialize)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct ApplicationInformation { | ||||
|     status: BankofamericaPaymentStatus, | ||||
|     status: Option<BankofamericaPaymentStatus>, | ||||
| } | ||||
|  | ||||
| impl<F> | ||||
| @ -2390,19 +2428,20 @@ impl<F> | ||||
|             types::PaymentsResponseData, | ||||
|         >, | ||||
|     ) -> Result<Self, Self::Error> { | ||||
|         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<F> | ||||
|                 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<F> | ||||
|                         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<F> | ||||
|                     }) | ||||
|                 } | ||||
|             } | ||||
|             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<types::RefundsResponseRouterData<api::RSync, BankOfAmericaRsyncResp | ||||
|                         Err(types::ErrorResponse::foreign_from(( | ||||
|                             &Some(BankOfAmericaErrorInformation { | ||||
|                                 message: Some(consts::REFUND_VOIDED.to_string()), | ||||
|                                 reason: None, | ||||
|                                 reason: Some(consts::REFUND_VOIDED.to_string()), | ||||
|                                 details: None, | ||||
|                             }), | ||||
|                             &None, | ||||
|                             None, | ||||
| @ -2793,6 +2834,7 @@ pub struct Details { | ||||
| pub struct ErrorInformation { | ||||
|     pub message: String, | ||||
|     pub reason: String, | ||||
|     pub details: Option<Vec<Details>>, | ||||
| } | ||||
|  | ||||
| #[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::<Vec<_>>() | ||||
|                     .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<ApplePayPredecryptData>> 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<ApplePayPredecryptData>> 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::<Vec<_>>() | ||||
|                         .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<String>, | ||||
|     detailed_error_info: Option<String>, | ||||
|     avs_error_info: Option<String>, | ||||
| ) -> Option<String> { | ||||
|     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, | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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::<Vec<_>>() | ||||
|                         .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::<Vec<_>>() | ||||
|                                 .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::<Vec<_>>() | ||||
|                                 .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<types::ErrorResponse, errors::ConnectorError> { | ||||
|         self.build_error_response(res, event_builder) | ||||
|     } | ||||
|  | ||||
|     fn get_5xx_error_response( | ||||
|         &self, | ||||
|         res: types::Response, | ||||
|         event_builder: Option<&mut ConnectorEvent>, | ||||
|     ) -> CustomResult<types::ErrorResponse, errors::ConnectorError> { | ||||
|         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 | ||||
|  | ||||
| @ -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<CardPaymentInformation>), | ||||
|     GooglePay(Box<GooglePayPaymentInformation>), | ||||
|     ApplePay(Box<ApplePayPaymentInformation>), | ||||
|     ApplePayToken(Box<ApplePayTokenPaymentInformation>), | ||||
|     MandatePayment(Box<MandatePaymentInformation>), | ||||
| } | ||||
|  | ||||
| #[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<BillTo>, | ||||
|     )> for OrderInformationWithBill | ||||
| { | ||||
|     fn from( | ||||
|         (item, bill_to): ( | ||||
|             &CybersourceRouterData<&types::PaymentsAuthorizeRouterData>, | ||||
|             BillTo, | ||||
|             Option<BillTo>, | ||||
|         ), | ||||
|     ) -> 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<Self, Self::Error> { | ||||
|         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<Self, Self::Error> { | ||||
|         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::<MerchantDefinedInformation>::foreign_from(metadata.peek().to_owned()) | ||||
| @ -1125,16 +1141,17 @@ impl | ||||
|     ) -> Result<Self, Self::Error> { | ||||
|         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<CybersourceIncrementalAuthorizationStatus> for common_enums::Authoriza | ||||
| #[derive(Debug, Deserialize, Serialize)] | ||||
| #[serde(untagged)] | ||||
| pub enum CybersourcePaymentsResponse { | ||||
|     ClientReferenceInformation(CybersourceClientReferenceResponse), | ||||
|     ErrorInformation(CybersourceErrorInformationResponse), | ||||
|     ClientReferenceInformation(Box<CybersourceClientReferenceResponse>), | ||||
|     ErrorInformation(Box<CybersourceErrorInformationResponse>), | ||||
| } | ||||
|  | ||||
| #[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<ClientAuthSetupInfoResponse>), | ||||
|     ErrorInformation(Box<CybersourceErrorInformationResponse>), | ||||
| } | ||||
|  | ||||
| #[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<CybersourceClientReferenceResponse>), | ||||
|     ErrorInformation(Box<CybersourceErrorInformationResponse>), | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||||
| @ -1773,6 +1791,7 @@ pub struct CybersourceTokenInformation { | ||||
| pub struct CybersourceErrorInformation { | ||||
|     reason: Option<String>, | ||||
|     message: Option<String>, | ||||
|     details: Option<Vec<Details>>, | ||||
| } | ||||
|  | ||||
| impl<F, T> | ||||
| @ -1794,18 +1813,36 @@ impl<F, T> | ||||
|             Option<enums::AttemptStatus>, | ||||
|         ), | ||||
|     ) -> 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::<Vec<_>>() | ||||
|                         .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<F> | ||||
|             } | ||||
|             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<F> | ||||
|                 ..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::<Vec<_>>() | ||||
|                                 .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<F> | ||||
|                             .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<CybersourceAuthEnrollmentRequest>), | ||||
|     AuthValidate(Box<CybersourceAuthValidateRequest>), | ||||
| } | ||||
|  | ||||
| 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<ClientAuthCheckInfoResponse>), | ||||
|     ErrorInformation(CybersourceErrorInformationResponse), | ||||
|     ErrorInformation(Box<CybersourceErrorInformationResponse>), | ||||
| } | ||||
|  | ||||
| impl From<CybersourceAuthEnrollmentStatus> for enums::AttemptStatus { | ||||
| @ -2360,19 +2420,32 @@ impl<F> | ||||
|                     }) | ||||
|                 } | ||||
|             } | ||||
|             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::<Vec<_>>() | ||||
|                                 .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<F> | ||||
|             } | ||||
|             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<F> | ||||
|                 }) | ||||
|             } | ||||
|             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<F> | ||||
|                 }) | ||||
|             } | ||||
|             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<F, T> | ||||
|                     ..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::<Vec<_>>() | ||||
|                                 .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<F, T> | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[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<ClientReferenceInformation>, | ||||
| @ -2696,7 +2775,7 @@ pub struct CybersourceApplicationInfoResponse { | ||||
| #[derive(Clone, Debug, Deserialize, Serialize)] | ||||
| #[serde(rename_all = "camelCase")] | ||||
| pub struct ApplicationInformation { | ||||
|     status: CybersourcePaymentStatus, | ||||
|     status: Option<CybersourcePaymentStatus>, | ||||
| } | ||||
|  | ||||
| impl<F> | ||||
| @ -2718,10 +2797,10 @@ impl<F> | ||||
|             types::PaymentsResponseData, | ||||
|         >, | ||||
|     ) -> Result<Self, Self::Error> { | ||||
|         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<F> | ||||
|                 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<F> | ||||
|                         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<F> | ||||
|                     }) | ||||
|                 } | ||||
|             } | ||||
|             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<types::RefundsResponseRouterData<api::RSync, CybersourceRsyncRespon | ||||
|                         Err(types::ErrorResponse::foreign_from(( | ||||
|                             &Some(CybersourceErrorInformation { | ||||
|                                 message: Some(consts::REFUND_VOIDED.to_string()), | ||||
|                                 reason: None, | ||||
|                                 reason: Some(consts::REFUND_VOIDED.to_string()), | ||||
|                                 details: None, | ||||
|                             }), | ||||
|                             &None, | ||||
|                             None, | ||||
| @ -3099,7 +3180,7 @@ impl TryFrom<PayoutMethodData> 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<CybersourceAuthenticationErrorResponse>), | ||||
|     //If the request resource is not available/exists in cybersource | ||||
|     NotAvailableError(CybersourceNotAvailableErrorResponse), | ||||
|     StandardError(CybersourceStandardErrorResponse), | ||||
|     NotAvailableError(Box<CybersourceNotAvailableErrorResponse>), | ||||
|     StandardError(Box<CybersourceStandardErrorResponse>), | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Deserialize, Clone, Serialize)] | ||||
| @ -3225,6 +3306,7 @@ pub struct Details { | ||||
| pub struct ErrorInformation { | ||||
|     pub message: String, | ||||
|     pub reason: String, | ||||
|     pub details: Option<Vec<Details>>, | ||||
| } | ||||
|  | ||||
| #[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::<Vec<_>>() | ||||
|                     .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<String>, | ||||
|     detailed_error_info: Option<String>, | ||||
|     avs_error_info: Option<String>, | ||||
| ) -> Option<String> { | ||||
|     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, | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 AkshayaFoiger
					AkshayaFoiger