fix(connector_customer): create connector_customer on requirement basis (#1097)

This commit is contained in:
Narayan Bhat
2023-05-10 20:40:36 +05:30
committed by GitHub
parent da3b5201b4
commit e833a1ddee
5 changed files with 82 additions and 77 deletions

View File

@ -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),
} }

View File

@ -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 {

View File

@ -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,

View File

@ -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
} }

View File

@ -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
} }