mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	feat(ucs): call pre-authentication during authorize as per connector (#9949)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
		| @ -138,6 +138,38 @@ impl UnifiedConnectorServiceClient { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Performs Payment Pre Authenticate | ||||
|     pub async fn payment_pre_authenticate( | ||||
|         &self, | ||||
|         payment_pre_authenticate_request: payments_grpc::PaymentServicePreAuthenticateRequest, | ||||
|         connector_auth_metadata: ConnectorAuthMetadata, | ||||
|         grpc_headers: GrpcHeadersUcs, | ||||
|     ) -> UnifiedConnectorServiceResult< | ||||
|         tonic::Response<payments_grpc::PaymentServicePreAuthenticateResponse>, | ||||
|     > { | ||||
|         let mut request = tonic::Request::new(payment_pre_authenticate_request); | ||||
|  | ||||
|         let connector_name = connector_auth_metadata.connector_name.clone(); | ||||
|         let metadata = | ||||
|             build_unified_connector_service_grpc_headers(connector_auth_metadata, grpc_headers)?; | ||||
|  | ||||
|         *request.metadata_mut() = metadata; | ||||
|  | ||||
|         self.client | ||||
|             .clone() | ||||
|             .pre_authenticate(request) | ||||
|             .await | ||||
|             .change_context(UnifiedConnectorServiceError::PaymentPreAuthenticateFailure) | ||||
|             .inspect_err(|error| { | ||||
|                 logger::error!( | ||||
|                     grpc_error=?error, | ||||
|                     method="payment_pre_authenticate", | ||||
|                     connector_name=?connector_name, | ||||
|                     "UCS payment pre authenticate gRPC call failed" | ||||
|                 ) | ||||
|             }) | ||||
|     } | ||||
|  | ||||
|     /// Performs Payment Authorize | ||||
|     pub async fn payment_authorize( | ||||
|         &self, | ||||
|  | ||||
| @ -753,12 +753,7 @@ impl ConnectorIntegration<PreAuthenticate, PaymentsPreAuthenticateData, Payments | ||||
|         req: &PaymentsPreAuthenticateRouterData, | ||||
|         _connectors: &Connectors, | ||||
|     ) -> CustomResult<RequestContent, errors::ConnectorError> { | ||||
|         let minor_amount = | ||||
|             req.request | ||||
|                 .minor_amount | ||||
|                 .ok_or(errors::ConnectorError::MissingRequiredField { | ||||
|                     field_name: "minor_amount", | ||||
|                 })?; | ||||
|         let minor_amount = req.request.minor_amount; | ||||
|         let currency = | ||||
|             req.request | ||||
|                 .currency | ||||
|  | ||||
| @ -2698,16 +2698,9 @@ impl TryFrom<&CybersourceRouterData<&PaymentsPreAuthenticateRouterData>> | ||||
|     fn try_from( | ||||
|         item: &CybersourceRouterData<&PaymentsPreAuthenticateRouterData>, | ||||
|     ) -> Result<Self, Self::Error> { | ||||
|         let payment_method_data = item | ||||
|             .router_data | ||||
|             .request | ||||
|             .payment_method_data | ||||
|             .as_ref() | ||||
|             .ok_or(errors::ConnectorError::MissingRequiredField { | ||||
|                 field_name: "payment_method_data", | ||||
|             })?; | ||||
|         let payment_method_data = item.router_data.request.payment_method_data.clone(); | ||||
|  | ||||
|         match payment_method_data.clone() { | ||||
|         match payment_method_data { | ||||
|             PaymentMethodData::Card(ccard) => { | ||||
|                 let card_type = match ccard | ||||
|                     .card_network | ||||
|  | ||||
| @ -618,20 +618,19 @@ impl TryFrom<PaymentsAuthorizeData> for PaymentsPreProcessingData { | ||||
|  | ||||
| #[derive(Debug, Clone, Serialize)] | ||||
| pub struct PaymentsPreAuthenticateData { | ||||
|     pub payment_method_data: Option<PaymentMethodData>, | ||||
|     pub amount: Option<i64>, | ||||
|     pub payment_method_data: PaymentMethodData, | ||||
|     pub amount: i64, | ||||
|     pub email: Option<pii::Email>, | ||||
|     pub currency: Option<storage_enums::Currency>, | ||||
|     pub payment_method_type: Option<storage_enums::PaymentMethodType>, | ||||
|     pub router_return_url: Option<String>, | ||||
|     pub complete_authorize_url: Option<String>, | ||||
|     pub browser_info: Option<BrowserInformation>, | ||||
|     pub connector_transaction_id: Option<String>, | ||||
|     pub enrolled_for_3ds: bool, | ||||
|     pub redirect_response: Option<CompleteAuthorizeRedirectResponse>, | ||||
|  | ||||
|     pub customer_name: Option<Secret<String>>, | ||||
|     pub metadata: Option<pii::SecretSerdeValue>, | ||||
|     // New amount for amount frame work | ||||
|     pub minor_amount: Option<MinorUnit>, | ||||
|     pub minor_amount: MinorUnit, | ||||
| } | ||||
|  | ||||
| impl TryFrom<PaymentsAuthorizeData> for PaymentsPreAuthenticateData { | ||||
| @ -639,17 +638,17 @@ impl TryFrom<PaymentsAuthorizeData> for PaymentsPreAuthenticateData { | ||||
|  | ||||
|     fn try_from(data: PaymentsAuthorizeData) -> Result<Self, Self::Error> { | ||||
|         Ok(Self { | ||||
|             payment_method_data: Some(data.payment_method_data), | ||||
|             amount: Some(data.amount), | ||||
|             minor_amount: Some(data.minor_amount), | ||||
|             payment_method_data: data.payment_method_data, | ||||
|             customer_name: data.customer_name, | ||||
|             metadata: data.metadata.map(Secret::new), | ||||
|             amount: data.amount, | ||||
|             minor_amount: data.minor_amount, | ||||
|             email: data.email, | ||||
|             currency: Some(data.currency), | ||||
|             payment_method_type: data.payment_method_type, | ||||
|             router_return_url: data.router_return_url, | ||||
|             complete_authorize_url: data.complete_authorize_url, | ||||
|             browser_info: data.browser_info, | ||||
|             connector_transaction_id: None, | ||||
|             redirect_response: None, | ||||
|             enrolled_for_3ds: data.enrolled_for_3ds, | ||||
|         }) | ||||
|     } | ||||
|  | ||||
| @ -77,6 +77,10 @@ pub enum UnifiedConnectorServiceError { | ||||
|     #[error("Failed to perform Payment Authorize from gRPC Server")] | ||||
|     PaymentAuthorizeFailure, | ||||
|  | ||||
|     /// Failed to perform Payment Authenticate from gRPC Server | ||||
|     #[error("Failed to perform Payment Pre Authenticate from gRPC Server")] | ||||
|     PaymentPreAuthenticateFailure, | ||||
|  | ||||
|     /// Failed to perform Payment Get from gRPC Server | ||||
|     #[error("Failed to perform Payment Get from gRPC Server")] | ||||
|     PaymentGetFailure, | ||||
|  | ||||
| @ -26,7 +26,7 @@ use crate::{ | ||||
|             self, access_token, customers, helpers, tokenization, transformers, PaymentData, | ||||
|         }, | ||||
|         unified_connector_service::{ | ||||
|             build_unified_connector_service_auth_metadata, | ||||
|             self, build_unified_connector_service_auth_metadata, | ||||
|             handle_unified_connector_service_response_for_payment_authorize, | ||||
|             handle_unified_connector_service_response_for_payment_repeat, ucs_logging_wrapper, | ||||
|         }, | ||||
| @ -565,7 +565,46 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu | ||||
|             ); | ||||
|             match alternate_flow { | ||||
|                 Some(api_interface::AlternateFlow::PreAuthenticate) => { | ||||
|                     // Todo: Call UCS PreAuthenticate here | ||||
|                     let authorize_request_data = self.request.clone(); | ||||
|                     let pre_authneticate_request_data = | ||||
|                         types::PaymentsPreAuthenticateData::try_from(self.request.to_owned())?; | ||||
|                     let pre_authneticate_response_data: Result< | ||||
|                         types::PaymentsResponseData, | ||||
|                         types::ErrorResponse, | ||||
|                     > = Err(types::ErrorResponse::default()); | ||||
|                     let mut pre_authenticate_router_data = helpers::router_data_type_conversion::< | ||||
|                         _, | ||||
|                         api::PreAuthenticate, | ||||
|                         _, | ||||
|                         _, | ||||
|                         _, | ||||
|                         _, | ||||
|                     >( | ||||
|                         self.clone(), | ||||
|                         pre_authneticate_request_data, | ||||
|                         pre_authneticate_response_data, | ||||
|                     ); | ||||
|                     let _ = call_unified_connector_service_pre_authenticate( | ||||
|                         &mut pre_authenticate_router_data, | ||||
|                         state, | ||||
|                         header_payload, | ||||
|                         lineage_ids, | ||||
|                         merchant_connector_account, | ||||
|                         merchant_context, | ||||
|                         unified_connector_service_execution_mode, | ||||
|                         merchant_order_reference_id, | ||||
|                     ) | ||||
|                     .await; | ||||
|                     // Convert back to authorize router data while preserving preprocessing response data. | ||||
|                     let pre_authenticate_response = pre_authenticate_router_data.response.clone(); | ||||
|                     let authorize_router_data = | ||||
|                         helpers::router_data_type_conversion::<_, api::Authorize, _, _, _, _>( | ||||
|                             pre_authenticate_router_data, | ||||
|                             authorize_request_data, | ||||
|                             pre_authenticate_response, | ||||
|                         ); | ||||
|                     *self = authorize_router_data; | ||||
|  | ||||
|                     Ok(()) | ||||
|                 } | ||||
|                 None => { | ||||
| @ -962,6 +1001,99 @@ async fn call_unified_connector_service_authorize( | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| #[allow(clippy::too_many_arguments)] | ||||
| async fn call_unified_connector_service_pre_authenticate( | ||||
|     router_data: &mut types::RouterData< | ||||
|         api::PreAuthenticate, | ||||
|         types::PaymentsPreAuthenticateData, | ||||
|         types::PaymentsResponseData, | ||||
|     >, | ||||
|     state: &SessionState, | ||||
|     header_payload: &domain_payments::HeaderPayload, | ||||
|     lineage_ids: grpc_client::LineageIds, | ||||
|     #[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType, | ||||
|     #[cfg(feature = "v2")] merchant_connector_account: domain::MerchantConnectorAccountTypeDetails, | ||||
|     merchant_context: &domain::MerchantContext, | ||||
|     unified_connector_service_execution_mode: enums::ExecutionMode, | ||||
|     merchant_order_reference_id: Option<String>, | ||||
| ) -> RouterResult<()> { | ||||
|     let client = state | ||||
|         .grpc_client | ||||
|         .unified_connector_service_client | ||||
|         .clone() | ||||
|         .ok_or(ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Failed to fetch Unified Connector Service client")?; | ||||
|  | ||||
|     let payment_pre_authenticate_request = | ||||
|         payments_grpc::PaymentServicePreAuthenticateRequest::foreign_try_from(&*router_data) | ||||
|             .change_context(ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Failed to construct Payment Authorize Request")?; | ||||
|  | ||||
|     let connector_auth_metadata = | ||||
|         build_unified_connector_service_auth_metadata(merchant_connector_account, merchant_context) | ||||
|             .change_context(ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Failed to construct request metadata")?; | ||||
|     let merchant_reference_id = header_payload | ||||
|         .x_reference_id | ||||
|         .clone() | ||||
|         .or(merchant_order_reference_id) | ||||
|         .map(|id| id_type::PaymentReferenceId::from_str(id.as_str())) | ||||
|         .transpose() | ||||
|         .inspect_err(|err| logger::warn!(error=?err, "Invalid Merchant ReferenceId found")) | ||||
|         .ok() | ||||
|         .flatten() | ||||
|         .map(ucs_types::UcsReferenceId::Payment); | ||||
|     let headers_builder = state | ||||
|         .get_grpc_headers_ucs(unified_connector_service_execution_mode) | ||||
|         .external_vault_proxy_metadata(None) | ||||
|         .merchant_reference_id(merchant_reference_id) | ||||
|         .lineage_ids(lineage_ids); | ||||
|     let updated_router_data = Box::pin(ucs_logging_wrapper( | ||||
|         router_data.clone(), | ||||
|         state, | ||||
|         payment_pre_authenticate_request, | ||||
|         headers_builder, | ||||
|         |mut router_data, payment_pre_authenticate_request, grpc_headers| async move { | ||||
|             let response = client | ||||
|                 .payment_pre_authenticate( | ||||
|                     payment_pre_authenticate_request, | ||||
|                     connector_auth_metadata, | ||||
|                     grpc_headers, | ||||
|                 ) | ||||
|                 .await | ||||
|                 .change_context(ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Failed to authorize payment")?; | ||||
|  | ||||
|             let payment_pre_authenticate_response = response.into_inner(); | ||||
|  | ||||
|             let (router_data_response, status_code) = | ||||
|                 unified_connector_service::handle_unified_connector_service_response_for_payment_pre_authenticate( | ||||
|                     payment_pre_authenticate_response.clone(), | ||||
|                 ) | ||||
|                 .change_context(ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Failed to deserialize UCS response")?; | ||||
|  | ||||
|             let router_data_response = router_data_response.map(|(response, status)| { | ||||
|                 router_data.status = status; | ||||
|                 response | ||||
|             }); | ||||
|             router_data.response = router_data_response; | ||||
|             router_data.raw_connector_response = payment_pre_authenticate_response | ||||
|                 .raw_connector_response | ||||
|                 .clone() | ||||
|                 .map(|raw_connector_response| raw_connector_response.expose().into()); | ||||
|             router_data.connector_http_status_code = Some(status_code); | ||||
|  | ||||
|             Ok((router_data, payment_pre_authenticate_response)) | ||||
|         }, | ||||
|     )) | ||||
|     .await?; | ||||
|  | ||||
|     // Copy back the updated data | ||||
|     *router_data = updated_router_data; | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| #[allow(clippy::too_many_arguments)] | ||||
| async fn call_unified_connector_service_repeat_payment( | ||||
|     router_data: &mut types::RouterData< | ||||
|  | ||||
| @ -770,6 +770,17 @@ pub fn handle_unified_connector_service_response_for_payment_authorize( | ||||
|     Ok((router_data_response, status_code)) | ||||
| } | ||||
|  | ||||
| pub fn handle_unified_connector_service_response_for_payment_pre_authenticate( | ||||
|     response: payments_grpc::PaymentServicePreAuthenticateResponse, | ||||
| ) -> UnifiedConnectorServiceResult { | ||||
|     let status_code = transformers::convert_connector_service_status_code(response.status_code)?; | ||||
|  | ||||
|     let router_data_response = | ||||
|         Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?; | ||||
|  | ||||
|     Ok((router_data_response, status_code)) | ||||
| } | ||||
|  | ||||
| pub fn handle_unified_connector_service_response_for_payment_capture( | ||||
|     response: payments_grpc::PaymentServiceCaptureResponse, | ||||
| ) -> UnifiedConnectorServiceResult { | ||||
|  | ||||
| @ -9,10 +9,10 @@ use hyperswitch_domain_models::{ | ||||
|     router_data::{ErrorResponse, RouterData}, | ||||
|     router_flow_types::{ | ||||
|         payments::{Authorize, Capture, PSync, SetupMandate}, | ||||
|         ExternalVaultProxy, | ||||
|         unified_authentication_service as uas_flows, ExternalVaultProxy, | ||||
|     }, | ||||
|     router_request_types::{ | ||||
|         AuthenticationData, ExternalVaultProxyPaymentsData, PaymentsAuthorizeData, | ||||
|         self, AuthenticationData, ExternalVaultProxyPaymentsData, PaymentsAuthorizeData, | ||||
|         PaymentsCancelData, PaymentsCaptureData, PaymentsSyncData, SetupMandateRequestData, | ||||
|     }, | ||||
|     router_response_types::{PaymentsResponseData, RedirectForm}, | ||||
| @ -118,6 +118,101 @@ impl | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl | ||||
|     transformers::ForeignTryFrom< | ||||
|         &RouterData< | ||||
|             uas_flows::PreAuthenticate, | ||||
|             router_request_types::PaymentsPreAuthenticateData, | ||||
|             PaymentsResponseData, | ||||
|         >, | ||||
|     > for payments_grpc::PaymentServicePreAuthenticateRequest | ||||
| { | ||||
|     type Error = error_stack::Report<UnifiedConnectorServiceError>; | ||||
|     fn foreign_try_from( | ||||
|         router_data: &RouterData< | ||||
|             uas_flows::PreAuthenticate, | ||||
|             router_request_types::PaymentsPreAuthenticateData, | ||||
|             PaymentsResponseData, | ||||
|         >, | ||||
|     ) -> Result<Self, Self::Error> { | ||||
|         let currency = payments_grpc::Currency::foreign_try_from( | ||||
|             router_data.request.currency.unwrap_or_default(), | ||||
|         )?; | ||||
|  | ||||
|         let payment_method = router_data | ||||
|             .request | ||||
|             .payment_method_type | ||||
|             .map(|payment_method_type| { | ||||
|                 unified_connector_service::build_unified_connector_service_payment_method( | ||||
|                     router_data.request.payment_method_data.clone(), | ||||
|                     payment_method_type, | ||||
|                 ) | ||||
|             }) | ||||
|             .transpose()?; | ||||
|  | ||||
|         let address = payments_grpc::PaymentAddress::foreign_try_from(router_data.address.clone())?; | ||||
|         let connector_metadata_string = router_data | ||||
|             .connector_meta_data | ||||
|             .as_ref() | ||||
|             .map(|metadata| metadata.encode_to_string_of_json()) | ||||
|             .transpose() | ||||
|             .change_context( | ||||
|                 UnifiedConnectorServiceError::RequestEncodingFailedWithReason( | ||||
|                     "Failed to serialize router_data.connector_meta_data to string of json" | ||||
|                         .to_string(), | ||||
|                 ), | ||||
|             )?; | ||||
|         let mut metadata = router_data | ||||
|             .request | ||||
|             .metadata | ||||
|             .as_ref() | ||||
|             .and_then(|val| val.peek().as_object()) | ||||
|             .map(|map| { | ||||
|                 map.iter() | ||||
|                     .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string()))) | ||||
|                     .collect::<HashMap<String, String>>() | ||||
|             }) | ||||
|             .unwrap_or_default(); | ||||
|         metadata.extend( | ||||
|             connector_metadata_string | ||||
|                 .map(|connector_metadata| ("connector_meta_data".to_string(), connector_metadata)), | ||||
|         ); | ||||
|         Ok(Self { | ||||
|             request_ref_id: Some(Identifier { | ||||
|                 id_type: Some(payments_grpc::identifier::IdType::Id( | ||||
|                     router_data.connector_request_reference_id.clone(), | ||||
|                 )), | ||||
|             }), | ||||
|             amount: router_data.request.amount, | ||||
|             currency: currency.into(), | ||||
|             minor_amount: router_data.request.minor_amount.get_amount_as_i64(), | ||||
|             payment_method, | ||||
|             email: router_data | ||||
|                 .request | ||||
|                 .email | ||||
|                 .clone() | ||||
|                 .map(|e| e.expose().expose().into()), | ||||
|             customer_name: router_data | ||||
|                 .request | ||||
|                 .customer_name | ||||
|                 .clone() | ||||
|                 .map(|customer_name| customer_name.peek().to_owned()), | ||||
|             address: Some(address), | ||||
|             enrolled_for_3ds: router_data.request.enrolled_for_3ds, | ||||
|             metadata, | ||||
|             return_url: router_data.request.router_return_url.clone(), | ||||
|             continue_redirection_url: router_data.request.complete_authorize_url.clone(), | ||||
|             access_token: None, | ||||
|             browser_info: router_data | ||||
|                 .request | ||||
|                 .browser_info | ||||
|                 .clone() | ||||
|                 .map(payments_grpc::BrowserInformation::foreign_try_from) | ||||
|                 .transpose()?, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl transformers::ForeignTryFrom<&RouterData<Capture, PaymentsCaptureData, PaymentsResponseData>> | ||||
|     for payments_grpc::PaymentServiceCaptureRequest | ||||
| { | ||||
| @ -229,7 +324,32 @@ impl | ||||
|             .clone() | ||||
|             .map(payments_grpc::AuthenticationData::foreign_try_from) | ||||
|             .transpose()?; | ||||
|  | ||||
|         let connector_metadata_string = router_data | ||||
|             .connector_meta_data | ||||
|             .as_ref() | ||||
|             .map(|metadata| metadata.encode_to_string_of_json()) | ||||
|             .transpose() | ||||
|             .change_context( | ||||
|                 UnifiedConnectorServiceError::RequestEncodingFailedWithReason( | ||||
|                     "Failed to serialize router_data.connector_meta_data to string of json" | ||||
|                         .to_string(), | ||||
|                 ), | ||||
|             )?; | ||||
|         let mut metadata = router_data | ||||
|             .request | ||||
|             .metadata | ||||
|             .as_ref() | ||||
|             .and_then(|val| val.as_object()) | ||||
|             .map(|map| { | ||||
|                 map.iter() | ||||
|                     .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string()))) | ||||
|                     .collect::<HashMap<String, String>>() | ||||
|             }) | ||||
|             .unwrap_or_default(); | ||||
|         metadata.extend( | ||||
|             connector_metadata_string | ||||
|                 .map(|connector_metadata| ("connector_meta_data".to_string(), connector_metadata)), | ||||
|         ); | ||||
|         Ok(Self { | ||||
|             amount: router_data.request.amount, | ||||
|             currency: currency.into(), | ||||
| @ -287,17 +407,7 @@ impl | ||||
|                 .customer_id | ||||
|                 .as_ref() | ||||
|                 .map(|id| id.get_string_repr().to_string()), | ||||
|             metadata: router_data | ||||
|                 .request | ||||
|                 .metadata | ||||
|                 .as_ref() | ||||
|                 .and_then(|val| val.as_object()) | ||||
|                 .map(|map| { | ||||
|                     map.iter() | ||||
|                         .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string()))) | ||||
|                         .collect::<HashMap<String, String>>() | ||||
|                 }) | ||||
|                 .unwrap_or_default(), | ||||
|             metadata, | ||||
|             test_mode: router_data.test_mode, | ||||
|             connector_customer_id: router_data.connector_customer.clone(), | ||||
|             merchant_account_metadata: HashMap::new(), | ||||
| @ -629,6 +739,111 @@ impl | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl transformers::ForeignTryFrom<payments_grpc::PaymentServicePreAuthenticateResponse> | ||||
|     for Result<(PaymentsResponseData, AttemptStatus), ErrorResponse> | ||||
| { | ||||
|     type Error = error_stack::Report<UnifiedConnectorServiceError>; | ||||
|     fn foreign_try_from( | ||||
|         response: payments_grpc::PaymentServicePreAuthenticateResponse, | ||||
|     ) -> Result<Self, Self::Error> { | ||||
|         let connector_response_reference_id = | ||||
|             response.response_ref_id.as_ref().and_then(|identifier| { | ||||
|                 identifier | ||||
|                     .id_type | ||||
|                     .clone() | ||||
|                     .and_then(|id_type| match id_type { | ||||
|                         payments_grpc::identifier::IdType::Id(id) => Some(id), | ||||
|                         payments_grpc::identifier::IdType::EncodedData(encoded_data) => { | ||||
|                             Some(encoded_data) | ||||
|                         } | ||||
|                         payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None, | ||||
|                     }) | ||||
|             }); | ||||
|  | ||||
|         let resource_id: router_request_types::ResponseId = match response | ||||
|             .transaction_id | ||||
|             .as_ref() | ||||
|             .and_then(|id| id.id_type.clone()) | ||||
|         { | ||||
|             Some(payments_grpc::identifier::IdType::Id(id)) => { | ||||
|                 router_request_types::ResponseId::ConnectorTransactionId(id) | ||||
|             } | ||||
|             Some(payments_grpc::identifier::IdType::EncodedData(encoded_data)) => { | ||||
|                 router_request_types::ResponseId::EncodedData(encoded_data) | ||||
|             } | ||||
|             Some(payments_grpc::identifier::IdType::NoResponseIdMarker(_)) | None => { | ||||
|                 router_request_types::ResponseId::NoResponseId | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         let (connector_metadata, redirection_data) = match response.redirection_data.clone() { | ||||
|             Some(redirection_data) => match redirection_data.form_type { | ||||
|                 Some(ref form_type) => match form_type { | ||||
|                     payments_grpc::redirect_form::FormType::Uri(uri) => { | ||||
|                         // For UPI intent, store the URI in connector_metadata for SDK UPI intent pattern | ||||
|                         let sdk_uri_info = api_models::payments::SdkUpiIntentInformation { | ||||
|                             sdk_uri: Url::parse(&uri.uri) | ||||
|                                 .change_context(UnifiedConnectorServiceError::ParsingFailed)?, | ||||
|                         }; | ||||
|                         ( | ||||
|                             Some(sdk_uri_info.encode_to_value()) | ||||
|                                 .transpose() | ||||
|                                 .change_context(UnifiedConnectorServiceError::ParsingFailed)?, | ||||
|                             None, | ||||
|                         ) | ||||
|                     } | ||||
|                     _ => ( | ||||
|                         None, | ||||
|                         Some(RedirectForm::foreign_try_from(redirection_data)).transpose()?, | ||||
|                     ), | ||||
|                 }, | ||||
|                 None => (None, None), | ||||
|             }, | ||||
|             None => (None, None), | ||||
|         }; | ||||
|  | ||||
|         let status_code = convert_connector_service_status_code(response.status_code)?; | ||||
|  | ||||
|         let response = if response.error_code.is_some() { | ||||
|             let attempt_status = match response.status() { | ||||
|                 payments_grpc::PaymentStatus::AttemptStatusUnspecified => None, | ||||
|                 _ => Some(AttemptStatus::foreign_try_from(response.status())?), | ||||
|             }; | ||||
|  | ||||
|             Err(ErrorResponse { | ||||
|                 code: response.error_code().to_owned(), | ||||
|                 message: response.error_message().to_owned(), | ||||
|                 reason: Some(response.error_message().to_owned()), | ||||
|                 status_code, | ||||
|                 attempt_status, | ||||
|                 connector_transaction_id: connector_response_reference_id, | ||||
|                 network_decline_code: None, | ||||
|                 network_advice_code: None, | ||||
|                 network_error_message: None, | ||||
|                 connector_metadata: None, | ||||
|             }) | ||||
|         } else { | ||||
|             let status = AttemptStatus::foreign_try_from(response.status())?; | ||||
|  | ||||
|             Ok(( | ||||
|                 PaymentsResponseData::TransactionResponse { | ||||
|                     resource_id, | ||||
|                     redirection_data: Box::new(redirection_data), | ||||
|                     mandate_reference: Box::new(None), | ||||
|                     connector_metadata, | ||||
|                     network_txn_id: response.network_txn_id.clone(), | ||||
|                     connector_response_reference_id, | ||||
|                     incremental_authorization_allowed: None, | ||||
|                     charges: None, | ||||
|                 }, | ||||
|                 status, | ||||
|             )) | ||||
|         }; | ||||
|  | ||||
|         Ok(response) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl transformers::ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse> | ||||
|     for Result<(PaymentsResponseData, AttemptStatus), ErrorResponse> | ||||
| { | ||||
| @ -651,10 +866,20 @@ impl transformers::ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse | ||||
|                     }) | ||||
|             }); | ||||
|  | ||||
|         let resource_id: hyperswitch_domain_models::router_request_types::ResponseId = match response.transaction_id.as_ref().and_then(|id| id.id_type.clone()) { | ||||
|             Some(payments_grpc::identifier::IdType::Id(id)) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(id), | ||||
|             Some(payments_grpc::identifier::IdType::EncodedData(encoded_data)) => hyperswitch_domain_models::router_request_types::ResponseId::EncodedData(encoded_data), | ||||
|             Some(payments_grpc::identifier::IdType::NoResponseIdMarker(_)) | None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId, | ||||
|         let resource_id: router_request_types::ResponseId = match response | ||||
|             .transaction_id | ||||
|             .as_ref() | ||||
|             .and_then(|id| id.id_type.clone()) | ||||
|         { | ||||
|             Some(payments_grpc::identifier::IdType::Id(id)) => { | ||||
|                 router_request_types::ResponseId::ConnectorTransactionId(id) | ||||
|             } | ||||
|             Some(payments_grpc::identifier::IdType::EncodedData(encoded_data)) => { | ||||
|                 router_request_types::ResponseId::EncodedData(encoded_data) | ||||
|             } | ||||
|             Some(payments_grpc::identifier::IdType::NoResponseIdMarker(_)) | None => { | ||||
|                 router_request_types::ResponseId::NoResponseId | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         let (connector_metadata, redirection_data) = match response.redirection_data.clone() { | ||||
| @ -749,10 +974,20 @@ impl transformers::ForeignTryFrom<payments_grpc::PaymentServiceCaptureResponse> | ||||
|  | ||||
|         let status_code = convert_connector_service_status_code(response.status_code)?; | ||||
|  | ||||
|         let resource_id: hyperswitch_domain_models::router_request_types::ResponseId = match response.transaction_id.as_ref().and_then(|id| id.id_type.clone()) { | ||||
|             Some(payments_grpc::identifier::IdType::Id(id)) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(id), | ||||
|             Some(payments_grpc::identifier::IdType::EncodedData(encoded_data)) => hyperswitch_domain_models::router_request_types::ResponseId::EncodedData(encoded_data), | ||||
|             Some(payments_grpc::identifier::IdType::NoResponseIdMarker(_)) | None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId, | ||||
|         let resource_id: router_request_types::ResponseId = match response | ||||
|             .transaction_id | ||||
|             .as_ref() | ||||
|             .and_then(|id| id.id_type.clone()) | ||||
|         { | ||||
|             Some(payments_grpc::identifier::IdType::Id(id)) => { | ||||
|                 router_request_types::ResponseId::ConnectorTransactionId(id) | ||||
|             } | ||||
|             Some(payments_grpc::identifier::IdType::EncodedData(encoded_data)) => { | ||||
|                 router_request_types::ResponseId::EncodedData(encoded_data) | ||||
|             } | ||||
|             Some(payments_grpc::identifier::IdType::NoResponseIdMarker(_)) | None => { | ||||
|                 router_request_types::ResponseId::NoResponseId | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         let response = if response.error_code.is_some() { | ||||
| @ -846,44 +1081,57 @@ impl transformers::ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse> | ||||
|         } else { | ||||
|             let status = AttemptStatus::foreign_try_from(response.status())?; | ||||
|  | ||||
|             Ok((PaymentsResponseData::TransactionResponse { | ||||
|                 resource_id: response.registration_id.as_ref().and_then(|identifier| { | ||||
|                     identifier | ||||
|                         .id_type | ||||
|                         .clone() | ||||
|                         .and_then(|id_type| match id_type { | ||||
|                             payments_grpc::identifier::IdType::Id(id) => Some( | ||||
|                                 hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(id), | ||||
|                             ), | ||||
|                             payments_grpc::identifier::IdType::EncodedData(encoded_data) => Some( | ||||
|                                 hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(encoded_data), | ||||
|                             ), | ||||
|                             payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None, | ||||
|             Ok(( | ||||
|                 PaymentsResponseData::TransactionResponse { | ||||
|                     resource_id: response | ||||
|                         .registration_id | ||||
|                         .as_ref() | ||||
|                         .and_then(|identifier| { | ||||
|                             identifier | ||||
|                                 .id_type | ||||
|                                 .clone() | ||||
|                                 .and_then(|id_type| match id_type { | ||||
|                                     payments_grpc::identifier::IdType::Id(id) => Some( | ||||
|                                         router_request_types::ResponseId::ConnectorTransactionId( | ||||
|                                             id, | ||||
|                                         ), | ||||
|                                     ), | ||||
|                                     payments_grpc::identifier::IdType::EncodedData( | ||||
|                                         encoded_data, | ||||
|                                     ) => Some( | ||||
|                                         router_request_types::ResponseId::ConnectorTransactionId( | ||||
|                                             encoded_data, | ||||
|                                         ), | ||||
|                                     ), | ||||
|                                     payments_grpc::identifier::IdType::NoResponseIdMarker(_) => { | ||||
|                                         None | ||||
|                                     } | ||||
|                                 }) | ||||
|                         }) | ||||
|                 }).unwrap_or(hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId), | ||||
|                 redirection_data: Box::new( | ||||
|                     response | ||||
|                         .redirection_data | ||||
|                         .clone() | ||||
|                         .map(RedirectForm::foreign_try_from) | ||||
|                         .transpose()? | ||||
|                 ), | ||||
|                 mandate_reference: Box::new( | ||||
|                     response.mandate_reference.map(|grpc_mandate| { | ||||
|                         .unwrap_or(router_request_types::ResponseId::NoResponseId), | ||||
|                     redirection_data: Box::new( | ||||
|                         response | ||||
|                             .redirection_data | ||||
|                             .clone() | ||||
|                             .map(RedirectForm::foreign_try_from) | ||||
|                             .transpose()?, | ||||
|                     ), | ||||
|                     mandate_reference: Box::new(response.mandate_reference.map(|grpc_mandate| { | ||||
|                         hyperswitch_domain_models::router_response_types::MandateReference { | ||||
|                             connector_mandate_id: grpc_mandate.mandate_id, | ||||
|                             payment_method_id: grpc_mandate.payment_method_id, | ||||
|                             mandate_metadata: None, | ||||
|                             connector_mandate_request_reference_id: None, | ||||
|                         } | ||||
|                     }) | ||||
|                 ), | ||||
|                 connector_metadata: None, | ||||
|                 network_txn_id: response.network_txn_id, | ||||
|                 connector_response_reference_id, | ||||
|                 incremental_authorization_allowed: response.incremental_authorization_allowed, | ||||
|                 charges: None, | ||||
|             }, status)) | ||||
|                     })), | ||||
|                     connector_metadata: None, | ||||
|                     network_txn_id: response.network_txn_id, | ||||
|                     connector_response_reference_id, | ||||
|                     incremental_authorization_allowed: response.incremental_authorization_allowed, | ||||
|                     charges: None, | ||||
|                 }, | ||||
|                 status, | ||||
|             )) | ||||
|         }; | ||||
|  | ||||
|         Ok(response) | ||||
| @ -942,19 +1190,26 @@ impl transformers::ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingR | ||||
|         } else { | ||||
|             let status = AttemptStatus::foreign_try_from(response.status())?; | ||||
|  | ||||
|             Ok((PaymentsResponseData::TransactionResponse { | ||||
|                 resource_id: match transaction_id.as_ref() { | ||||
|                     Some(transaction_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(transaction_id.clone()), | ||||
|                     None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId, | ||||
|             Ok(( | ||||
|                 PaymentsResponseData::TransactionResponse { | ||||
|                     resource_id: match transaction_id.as_ref() { | ||||
|                         Some(transaction_id) => { | ||||
|                             router_request_types::ResponseId::ConnectorTransactionId( | ||||
|                                 transaction_id.clone(), | ||||
|                             ) | ||||
|                         } | ||||
|                         None => router_request_types::ResponseId::NoResponseId, | ||||
|                     }, | ||||
|                     redirection_data: Box::new(None), | ||||
|                     mandate_reference: Box::new(None), | ||||
|                     connector_metadata: None, | ||||
|                     network_txn_id: response.network_txn_id.clone(), | ||||
|                     connector_response_reference_id, | ||||
|                     incremental_authorization_allowed: None, | ||||
|                     charges: None, | ||||
|                 }, | ||||
|                 redirection_data: Box::new(None), | ||||
|                 mandate_reference: Box::new(None), | ||||
|                 connector_metadata: None, | ||||
|                 network_txn_id: response.network_txn_id.clone(), | ||||
|                 connector_response_reference_id, | ||||
|                 incremental_authorization_allowed: None, | ||||
|                 charges: None, | ||||
|             }, status)) | ||||
|                 status, | ||||
|             )) | ||||
|         }; | ||||
|  | ||||
|         Ok(response) | ||||
| @ -1132,15 +1387,13 @@ impl transformers::ForeignTryFrom<AuthenticationType> for payments_grpc::Authent | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl | ||||
|     transformers::ForeignTryFrom< | ||||
|         hyperswitch_domain_models::router_request_types::BrowserInformation, | ||||
|     > for payments_grpc::BrowserInformation | ||||
| impl transformers::ForeignTryFrom<router_request_types::BrowserInformation> | ||||
|     for payments_grpc::BrowserInformation | ||||
| { | ||||
|     type Error = error_stack::Report<UnifiedConnectorServiceError>; | ||||
|  | ||||
|     fn foreign_try_from( | ||||
|         browser_info: hyperswitch_domain_models::router_request_types::BrowserInformation, | ||||
|         browser_info: router_request_types::BrowserInformation, | ||||
|     ) -> Result<Self, Self::Error> { | ||||
|         Ok(Self { | ||||
|             color_depth: browser_info.color_depth.map(|v| v.into()), | ||||
| @ -1497,31 +1750,41 @@ impl transformers::ForeignTryFrom<payments_grpc::PaymentServiceVoidResponse> | ||||
|  | ||||
|             Ok(( | ||||
|                 PaymentsResponseData::TransactionResponse { | ||||
|                     resource_id: response.transaction_id.as_ref().and_then(|identifier| { | ||||
|                         identifier | ||||
|                             .id_type | ||||
|                             .clone() | ||||
|                             .and_then(|id_type| match id_type { | ||||
|                                 payments_grpc::identifier::IdType::Id(id) => Some( | ||||
|                                     hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(id), | ||||
|                                 ), | ||||
|                                 payments_grpc::identifier::IdType::EncodedData(encoded_data) => Some( | ||||
|                                     hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(encoded_data), | ||||
|                                 ), | ||||
|                                 payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None, | ||||
|                             }) | ||||
|                     }).unwrap_or(hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId), | ||||
|                     redirection_data: Box::new(None), | ||||
|                     mandate_reference: Box::new( | ||||
|                         response.mandate_reference.map(|grpc_mandate| { | ||||
|                             hyperswitch_domain_models::router_response_types::MandateReference { | ||||
|                                 connector_mandate_id: grpc_mandate.mandate_id, | ||||
|                                 payment_method_id: grpc_mandate.payment_method_id, | ||||
|                                 mandate_metadata: None, | ||||
|                                 connector_mandate_request_reference_id: None, | ||||
|                             } | ||||
|                     resource_id: response | ||||
|                         .transaction_id | ||||
|                         .as_ref() | ||||
|                         .and_then(|identifier| { | ||||
|                             identifier | ||||
|                                 .id_type | ||||
|                                 .clone() | ||||
|                                 .and_then(|id_type| match id_type { | ||||
|                                     payments_grpc::identifier::IdType::Id(id) => Some( | ||||
|                                         router_request_types::ResponseId::ConnectorTransactionId( | ||||
|                                             id, | ||||
|                                         ), | ||||
|                                     ), | ||||
|                                     payments_grpc::identifier::IdType::EncodedData( | ||||
|                                         encoded_data, | ||||
|                                     ) => Some( | ||||
|                                         router_request_types::ResponseId::ConnectorTransactionId( | ||||
|                                             encoded_data, | ||||
|                                         ), | ||||
|                                     ), | ||||
|                                     payments_grpc::identifier::IdType::NoResponseIdMarker(_) => { | ||||
|                                         None | ||||
|                                     } | ||||
|                                 }) | ||||
|                         }) | ||||
|                     ), | ||||
|                         .unwrap_or(router_request_types::ResponseId::NoResponseId), | ||||
|                     redirection_data: Box::new(None), | ||||
|                     mandate_reference: Box::new(response.mandate_reference.map(|grpc_mandate| { | ||||
|                         hyperswitch_domain_models::router_response_types::MandateReference { | ||||
|                             connector_mandate_id: grpc_mandate.mandate_id, | ||||
|                             payment_method_id: grpc_mandate.payment_method_id, | ||||
|                             mandate_metadata: None, | ||||
|                             connector_mandate_request_reference_id: None, | ||||
|                         } | ||||
|                     })), | ||||
|                     connector_metadata: None, | ||||
|                     network_txn_id: None, | ||||
|                     connector_response_reference_id, | ||||
|  | ||||
| @ -77,12 +77,12 @@ pub use hyperswitch_domain_models::{ | ||||
|         PaymentMethodTokenizationData, PaymentsApproveData, PaymentsAuthorizeData, | ||||
|         PaymentsCancelData, PaymentsCancelPostCaptureData, PaymentsCaptureData, | ||||
|         PaymentsExtendAuthorizationData, PaymentsIncrementalAuthorizationData, | ||||
|         PaymentsPostProcessingData, PaymentsPostSessionTokensData, PaymentsPreProcessingData, | ||||
|         PaymentsRejectData, PaymentsSessionData, PaymentsSyncData, PaymentsTaxCalculationData, | ||||
|         PaymentsUpdateMetadataData, RefundsData, ResponseId, RetrieveFileRequestData, | ||||
|         SdkPaymentsSessionUpdateData, SetupMandateRequestData, SplitRefundsRequest, | ||||
|         SubmitEvidenceRequestData, SyncRequestType, UploadFileRequestData, VaultRequestData, | ||||
|         VerifyWebhookSourceRequestData, | ||||
|         PaymentsPostProcessingData, PaymentsPostSessionTokensData, PaymentsPreAuthenticateData, | ||||
|         PaymentsPreProcessingData, PaymentsRejectData, PaymentsSessionData, PaymentsSyncData, | ||||
|         PaymentsTaxCalculationData, PaymentsUpdateMetadataData, RefundsData, ResponseId, | ||||
|         RetrieveFileRequestData, SdkPaymentsSessionUpdateData, SetupMandateRequestData, | ||||
|         SplitRefundsRequest, SubmitEvidenceRequestData, SyncRequestType, UploadFileRequestData, | ||||
|         VaultRequestData, VerifyWebhookSourceRequestData, | ||||
|     }, | ||||
|     router_response_types::{ | ||||
|         revenue_recovery::{ | ||||
|  | ||||
| @ -46,6 +46,7 @@ use error_stack::ResultExt; | ||||
| pub use hyperswitch_domain_models::router_flow_types::{ | ||||
|     access_token_auth::{AccessTokenAuth, AccessTokenAuthentication}, | ||||
|     mandate_revoke::MandateRevoke, | ||||
|     unified_authentication_service::*, | ||||
|     webhooks::VerifyWebhookSource, | ||||
| }; | ||||
| pub use hyperswitch_interfaces::{ | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Hrithikesh
					Hrithikesh