mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 01:57:45 +08:00 
			
		
		
		
	fix(connector_customer): create connector_customer on requirement basis (#1097)
This commit is contained in:
		| @ -120,16 +120,9 @@ where | |||||||
|         get_connector_tokenization_action(state, &operation, payment_data, &validate_result) |         get_connector_tokenization_action(state, &operation, payment_data, &validate_result) | ||||||
|             .await?; |             .await?; | ||||||
|  |  | ||||||
|     let connector_string = connector |     let updated_customer = call_create_connector_customer_if_required( | ||||||
|         .as_ref() |  | ||||||
|         .and_then(|connector_type| match connector_type { |  | ||||||
|             api::ConnectorCallType::Single(connector) => Some(connector.connector_name.to_string()), |  | ||||||
|             _ => None, |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|     let updated_customer = call_create_connector_customer( |  | ||||||
|         state, |         state, | ||||||
|         &connector_string, |         &payment_data.payment_attempt.connector.clone(), | ||||||
|         &customer, |         &customer, | ||||||
|         &merchant_account, |         &merchant_account, | ||||||
|         &mut payment_data, |         &mut payment_data, | ||||||
| @ -612,7 +605,7 @@ where | |||||||
|     Ok(payment_data) |     Ok(payment_data) | ||||||
| } | } | ||||||
|  |  | ||||||
| pub async fn call_create_connector_customer<F, Req>( | pub async fn call_create_connector_customer_if_required<F, Req>( | ||||||
|     state: &AppState, |     state: &AppState, | ||||||
|     connector_name: &Option<String>, |     connector_name: &Option<String>, | ||||||
|     customer: &Option<storage::Customer>, |     customer: &Option<storage::Customer>, | ||||||
| @ -640,14 +633,31 @@ where | |||||||
|                 connector_name, |                 connector_name, | ||||||
|                 api::GetToken::Connector, |                 api::GetToken::Connector, | ||||||
|             )?; |             )?; | ||||||
|             let router_data = payment_data |             let (is_eligible, connector_customer_id, connector_customer_map) = | ||||||
|                 .construct_router_data(state, connector.connector.id(), merchant_account, customer) |                 customers::should_call_connector_create_customer(state, &connector, customer)?; | ||||||
|                 .await?; |  | ||||||
|             let (connector_customer, customer_update) = router_data |             if is_eligible { | ||||||
|                 .create_connector_customer(state, &connector, customer) |                 // Create customer at connector and update the customer table to store this data | ||||||
|                 .await?; |                 let router_data = payment_data | ||||||
|             payment_data.connector_customer_id = connector_customer; |                     .construct_router_data( | ||||||
|             Ok(customer_update) |                         state, | ||||||
|  |                         connector.connector.id(), | ||||||
|  |                         merchant_account, | ||||||
|  |                         customer, | ||||||
|  |                     ) | ||||||
|  |                     .await?; | ||||||
|  |  | ||||||
|  |                 let (connector_customer, customer_update) = router_data | ||||||
|  |                     .create_connector_customer(state, &connector, connector_customer_map) | ||||||
|  |                     .await?; | ||||||
|  |  | ||||||
|  |                 payment_data.connector_customer_id = connector_customer; | ||||||
|  |                 Ok(customer_update) | ||||||
|  |             } else { | ||||||
|  |                 // Customer already created in previous calls use the same value, no need to update | ||||||
|  |                 payment_data.connector_customer_id = connector_customer_id; | ||||||
|  |                 Ok(None) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         None => Ok(None), |         None => Ok(None), | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -15,68 +15,62 @@ use crate::{ | |||||||
| pub async fn create_connector_customer<F: Clone, T: Clone>( | pub async fn create_connector_customer<F: Clone, T: Clone>( | ||||||
|     state: &AppState, |     state: &AppState, | ||||||
|     connector: &api::ConnectorData, |     connector: &api::ConnectorData, | ||||||
|     customer: &Option<storage::Customer>, |  | ||||||
|     router_data: &types::RouterData<F, T, types::PaymentsResponseData>, |     router_data: &types::RouterData<F, T, types::PaymentsResponseData>, | ||||||
|     customer_request_data: types::ConnectorCustomerData, |     customer_request_data: types::ConnectorCustomerData, | ||||||
|  |     connector_customer_map: Option<serde_json::Map<String, serde_json::Value>>, | ||||||
| ) -> RouterResult<(Option<String>, Option<storage::CustomerUpdate>)> { | ) -> RouterResult<(Option<String>, Option<storage::CustomerUpdate>)> { | ||||||
|     let (is_eligible, connector_customer_id, connector_customer_map) = |     let connector_integration: services::BoxedConnectorIntegration< | ||||||
|         should_call_connector_create_customer(state, connector, customer)?; |         '_, | ||||||
|  |         api::CreateConnectorCustomer, | ||||||
|  |         types::ConnectorCustomerData, | ||||||
|  |         types::PaymentsResponseData, | ||||||
|  |     > = connector.connector.get_connector_integration(); | ||||||
|  |  | ||||||
|     if is_eligible { |     let customer_response_data: Result<types::PaymentsResponseData, types::ErrorResponse> = | ||||||
|         let connector_integration: services::BoxedConnectorIntegration< |         Err(types::ErrorResponse::default()); | ||||||
|             '_, |  | ||||||
|             api::CreateConnectorCustomer, |  | ||||||
|             types::ConnectorCustomerData, |  | ||||||
|             types::PaymentsResponseData, |  | ||||||
|         > = connector.connector.get_connector_integration(); |  | ||||||
|  |  | ||||||
|         let customer_response_data: Result<types::PaymentsResponseData, types::ErrorResponse> = |     let customer_router_data = payments::helpers::router_data_type_conversion::< | ||||||
|             Err(types::ErrorResponse::default()); |         _, | ||||||
|  |         api::CreateConnectorCustomer, | ||||||
|  |         _, | ||||||
|  |         _, | ||||||
|  |         _, | ||||||
|  |         _, | ||||||
|  |     >( | ||||||
|  |         router_data.clone(), | ||||||
|  |         customer_request_data, | ||||||
|  |         customer_response_data, | ||||||
|  |     ); | ||||||
|  |  | ||||||
|         let customer_router_data = payments::helpers::router_data_type_conversion::< |     let resp = services::execute_connector_processing_step( | ||||||
|             _, |         state, | ||||||
|             api::CreateConnectorCustomer, |         connector_integration, | ||||||
|             _, |         &customer_router_data, | ||||||
|             _, |         payments::CallConnectorAction::Trigger, | ||||||
|             _, |     ) | ||||||
|             _, |     .await | ||||||
|         >( |     .map_err(|error| error.to_payment_failed_response())?; | ||||||
|             router_data.clone(), |  | ||||||
|             customer_request_data, |  | ||||||
|             customer_response_data, |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         let resp = services::execute_connector_processing_step( |     let connector_customer_id = match resp.response { | ||||||
|             state, |         Ok(response) => match response { | ||||||
|             connector_integration, |             types::PaymentsResponseData::ConnectorCustomerResponse { | ||||||
|             &customer_router_data, |                 connector_customer_id, | ||||||
|             payments::CallConnectorAction::Trigger, |             } => Some(connector_customer_id), | ||||||
|         ) |             _ => None, | ||||||
|         .await |         }, | ||||||
|         .map_err(|error| error.to_payment_failed_response())?; |         Err(err) => { | ||||||
|  |             logger::debug!(payment_method_tokenization_error=?err); | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|         let connector_customer_id = match resp.response { |     let update_customer = update_connector_customer_in_customers( | ||||||
|             Ok(response) => match response { |         connector, | ||||||
|                 types::PaymentsResponseData::ConnectorCustomerResponse { |         connector_customer_map, | ||||||
|                     connector_customer_id, |         &connector_customer_id, | ||||||
|                 } => Some(connector_customer_id), |     ) | ||||||
|                 _ => None, |     .await?; | ||||||
|             }, |     Ok((connector_customer_id, update_customer)) | ||||||
|             Err(err) => { |  | ||||||
|                 logger::debug!(payment_method_tokenization_error=?err); |  | ||||||
|                 None |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|         let update_customer = update_connector_customer_in_customers( |  | ||||||
|             connector, |  | ||||||
|             connector_customer_map, |  | ||||||
|             &connector_customer_id, |  | ||||||
|         ) |  | ||||||
|         .await?; |  | ||||||
|         Ok((connector_customer_id, update_customer)) |  | ||||||
|     } else { |  | ||||||
|         Ok((connector_customer_id, None)) |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| type CreateCustomerCheck = ( | type CreateCustomerCheck = ( | ||||||
| @ -96,6 +90,7 @@ pub fn should_call_connector_create_customer( | |||||||
|         .connector_customer |         .connector_customer | ||||||
|         .connector_list |         .connector_list | ||||||
|         .contains(&connector.connector_name); |         .contains(&connector.connector_name); | ||||||
|  |  | ||||||
|     if connector_customer_filter { |     if connector_customer_filter { | ||||||
|         match customer { |         match customer { | ||||||
|             Some(customer) => match &customer.connector_customer { |             Some(customer) => match &customer.connector_customer { | ||||||
|  | |||||||
| @ -74,7 +74,7 @@ pub trait Feature<F, T> { | |||||||
|         &self, |         &self, | ||||||
|         _state: &AppState, |         _state: &AppState, | ||||||
|         _connector: &api::ConnectorData, |         _connector: &api::ConnectorData, | ||||||
|         _customer: &Option<storage::Customer>, |         _connector_customer_map: Option<serde_json::Map<String, serde_json::Value>>, | ||||||
|     ) -> RouterResult<(Option<String>, Option<storage::CustomerUpdate>)> |     ) -> RouterResult<(Option<String>, Option<storage::CustomerUpdate>)> | ||||||
|     where |     where | ||||||
|         F: Clone, |         F: Clone, | ||||||
|  | |||||||
| @ -100,14 +100,14 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu | |||||||
|         &self, |         &self, | ||||||
|         state: &AppState, |         state: &AppState, | ||||||
|         connector: &api::ConnectorData, |         connector: &api::ConnectorData, | ||||||
|         customer: &Option<storage::Customer>, |         connector_customer_map: Option<serde_json::Map<String, serde_json::Value>>, | ||||||
|     ) -> RouterResult<(Option<String>, Option<storage::CustomerUpdate>)> { |     ) -> RouterResult<(Option<String>, Option<storage::CustomerUpdate>)> { | ||||||
|         customers::create_connector_customer( |         customers::create_connector_customer( | ||||||
|             state, |             state, | ||||||
|             connector, |             connector, | ||||||
|             customer, |  | ||||||
|             self, |             self, | ||||||
|             types::ConnectorCustomerData::try_from(self.request.to_owned())?, |             types::ConnectorCustomerData::try_from(self.request.to_owned())?, | ||||||
|  |             connector_customer_map, | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -84,14 +84,14 @@ impl Feature<api::Verify, types::VerifyRequestData> for types::VerifyRouterData | |||||||
|         &self, |         &self, | ||||||
|         state: &AppState, |         state: &AppState, | ||||||
|         connector: &api::ConnectorData, |         connector: &api::ConnectorData, | ||||||
|         customer: &Option<storage::Customer>, |         connector_customer_map: Option<serde_json::Map<String, serde_json::Value>>, | ||||||
|     ) -> RouterResult<(Option<String>, Option<storage::CustomerUpdate>)> { |     ) -> RouterResult<(Option<String>, Option<storage::CustomerUpdate>)> { | ||||||
|         customers::create_connector_customer( |         customers::create_connector_customer( | ||||||
|             state, |             state, | ||||||
|             connector, |             connector, | ||||||
|             customer, |  | ||||||
|             self, |             self, | ||||||
|             types::ConnectorCustomerData::try_from(self.request.to_owned())?, |             types::ConnectorCustomerData::try_from(self.request.to_owned())?, | ||||||
|  |             connector_customer_map, | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|     } |     } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Narayan Bhat
					Narayan Bhat