From 2b0ed12530df9ad9f490ffdddd04bccc224747e8 Mon Sep 17 00:00:00 2001 From: Narayan Bhat <48803246+Narayanbhat166@users.noreply.github.com> Date: Thu, 11 May 2023 20:34:45 +0530 Subject: [PATCH] refactor(session_token): add support for business filtering in payments session (#1128) --- .../router/src/core/payment_methods/cards.rs | 22 +-- crates/router/src/core/payments.rs | 22 +-- crates/router/src/core/payments/helpers.rs | 19 +++ crates/router/src/core/payments/operations.rs | 4 + .../operations/payment_complete_authorize.rs | 1 + .../payments/operations/payment_confirm.rs | 1 + .../payments/operations/payment_create.rs | 1 + .../operations/payment_method_validate.rs | 1 + .../payments/operations/payment_session.rs | 154 ++++++++++-------- .../core/payments/operations/payment_start.rs | 1 + .../payments/operations/payment_status.rs | 1 + .../payments/operations/payment_update.rs | 1 + crates/router/src/types/api.rs | 3 +- 13 files changed, 127 insertions(+), 104 deletions(-) diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index b3c7c031c5..8e12da732b 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -838,7 +838,8 @@ pub async fn list_payment_methods( .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?; // filter out connectors based on the business country - let filtered_mcas = filter_mca_based_on_business_details(all_mcas, payment_intent.as_ref()); + let filtered_mcas = + helpers::filter_mca_based_on_business_details(all_mcas, payment_intent.as_ref()); logger::debug!(mca_before_filtering=?filtered_mcas); @@ -1214,25 +1215,6 @@ async fn filter_payment_methods( Ok(()) } -fn filter_mca_based_on_business_details( - merchant_connector_accounts: Vec< - storage_models::merchant_connector_account::MerchantConnectorAccount, - >, - payment_intent: Option<&storage_models::payment_intent::PaymentIntent>, -) -> Vec { - if let Some(payment_intent) = payment_intent { - merchant_connector_accounts - .into_iter() - .filter(|mca| { - mca.business_country == payment_intent.business_country - && mca.business_label == payment_intent.business_label - }) - .collect::>() - } else { - merchant_connector_accounts - } -} - fn filter_pm_based_on_config<'a>( config: &'a crate::configs::settings::ConnectorFilters, connector: &'a str, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 26ba2e1065..ee34498981 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -536,7 +536,7 @@ where pub async fn call_multiple_connectors_service( state: &AppState, merchant_account: &storage::MerchantAccount, - connectors: Vec, + connectors: Vec, _operation: &Op, mut payment_data: PaymentData, customer: &Option, @@ -558,15 +558,16 @@ where let call_connectors_start_time = Instant::now(); let mut join_handlers = Vec::with_capacity(connectors.len()); - for connector in connectors.iter() { - let connector_id = connector.connector.id(); + for session_connector_data in connectors.iter() { + let connector_id = session_connector_data.connector.connector.id(); + let router_data = payment_data .construct_router_data(state, connector_id, merchant_account, customer) .await?; let res = router_data.decide_flows( state, - connector, + &session_connector_data.connector, customer, CallConnectorAction::Trigger, merchant_account, @@ -577,8 +578,8 @@ where let result = join_all(join_handlers).await; - for (connector_res, connector) in result.into_iter().zip(connectors) { - let connector_name = connector.connector_name.to_string(); + for (connector_res, session_connector) in result.into_iter().zip(connectors) { + let connector_name = session_connector.connector.connector_name.to_string(); match connector_res { Ok(connector_response) => { if let Ok(types::PaymentsResponseData::SessionResponse { session_token }) = @@ -1077,18 +1078,13 @@ where { let connector_choice = operation .to_domain()? - .get_connector(merchant_account, state, req) + .get_connector(merchant_account, state, req, &payment_data.payment_intent) .await?; let connector = if should_call_connector(operation, payment_data) { Some(match connector_choice { api::ConnectorChoice::SessionMultiple(session_connectors) => { - api::ConnectorCallType::Multiple( - session_connectors - .into_iter() - .map(|c| c.connector) - .collect(), - ) + api::ConnectorCallType::Multiple(session_connectors) } api::ConnectorChoice::StraightThrough(straight_through) => connector_selection( diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 8741ac0ca5..5c834a874d 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -43,6 +43,25 @@ use crate::{ }, }; +pub fn filter_mca_based_on_business_details( + merchant_connector_accounts: Vec< + storage_models::merchant_connector_account::MerchantConnectorAccount, + >, + payment_intent: Option<&storage_models::payment_intent::PaymentIntent>, +) -> Vec { + if let Some(payment_intent) = payment_intent { + merchant_connector_accounts + .into_iter() + .filter(|mca| { + mca.business_country == payment_intent.business_country + && mca.business_label == payment_intent.business_label + }) + .collect::>() + } else { + merchant_connector_accounts + } +} + pub async fn get_address_for_payment_request( db: &dyn StorageInterface, req_address: Option<&api::Address>, diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index b53e3307fb..773f219cf0 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -127,6 +127,7 @@ pub trait Domain: Send + Sync { merchant_account: &storage::MerchantAccount, state: &AppState, request: &R, + payment_intent: &storage::payment_intent::PaymentIntent, ) -> CustomResult; } @@ -196,6 +197,7 @@ where _merchant_account: &storage::MerchantAccount, state: &AppState, _request: &api::PaymentsRetrieveRequest, + _payment_intent: &storage::payment_intent::PaymentIntent, ) -> CustomResult { helpers::get_connector_default(state, None).await } @@ -263,6 +265,7 @@ where _merchant_account: &storage::MerchantAccount, state: &AppState, _request: &api::PaymentsCaptureRequest, + _payment_intent: &storage::payment_intent::PaymentIntent, ) -> CustomResult { helpers::get_connector_default(state, None).await } @@ -318,6 +321,7 @@ where _merchant_account: &storage::MerchantAccount, state: &AppState, _request: &api::PaymentsCancelRequest, + _payment_intent: &storage::payment_intent::PaymentIntent, ) -> CustomResult { helpers::get_connector_default(state, None).await } diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs index ec6d7f7a38..ef0b3c215c 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -266,6 +266,7 @@ impl Domain for CompleteAuthorize { _merchant_account: &storage::MerchantAccount, state: &AppState, request: &api::PaymentsRequest, + _payment_intent: &storage::payment_intent::PaymentIntent, ) -> CustomResult { // Use a new connector in the confirm call or use the same one which was passed when // creating the payment or if none is passed then use the routing algorithm diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 4813bbf624..852935dfe5 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -285,6 +285,7 @@ impl Domain for PaymentConfirm { _merchant_account: &storage::MerchantAccount, state: &AppState, request: &api::PaymentsRequest, + _payment_intent: &storage::payment_intent::PaymentIntent, ) -> CustomResult { // Use a new connector in the confirm call or use the same one which was passed when // creating the payment or if none is passed then use the routing algorithm diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 0a6b3bd488..9746768c19 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -303,6 +303,7 @@ impl Domain for PaymentCreate { _merchant_account: &storage::MerchantAccount, state: &AppState, request: &api::PaymentsRequest, + _payment_intent: &storage::payment_intent::PaymentIntent, ) -> CustomResult { helpers::get_connector_default(state, request.routing.clone()).await } diff --git a/crates/router/src/core/payments/operations/payment_method_validate.rs b/crates/router/src/core/payments/operations/payment_method_validate.rs index d8df71ab8e..b328a00945 100644 --- a/crates/router/src/core/payments/operations/payment_method_validate.rs +++ b/crates/router/src/core/payments/operations/payment_method_validate.rs @@ -278,6 +278,7 @@ where _merchant_account: &storage::MerchantAccount, state: &AppState, _request: &api::VerifyRequest, + _payment_intent: &storage::payment_intent::PaymentIntent, ) -> CustomResult { helpers::get_connector_default(state, None).await } diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index 0206ee91ba..de8bed67d5 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -281,16 +281,26 @@ where Ok((Box::new(self), None)) } + /// Returns `Vec` + /// Steps carried out in this function + /// Get all the `merchant_connector_accounts` which are not disabled + /// Filter out connectors which have `invoke_sdk_client` enabled in `payment_method_types` + /// If session token is requested for certain wallets only, then return them, else + /// return all eligible connectors + /// + /// `GetToken` parameter specifies whether to get the session token from connector integration + /// or from separate implementation ( for googlepay - from metadata and applepay - from metadata and call connector) async fn get_connector<'a>( &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, request: &api::PaymentsSessionRequest, + payment_intent: &storage::payment_intent::PaymentIntent, ) -> RouterResult { let connectors = &state.conf.connectors; let db = &state.store; - let connector_accounts = db + let all_connector_accounts = db .find_merchant_connector_account_by_merchant_id_and_disabled_list( &merchant_account.merchant_id, false, @@ -299,84 +309,88 @@ where .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Database error when querying for merchant connector accounts")?; + let filtered_connector_accounts = helpers::filter_mca_based_on_business_details( + all_connector_accounts, + Some(payment_intent), + ); + + let requested_payment_method_types = request.wallets.clone(); let mut connector_and_supporting_payment_method_type = Vec::new(); - for connector_account in connector_accounts { - let payment_methods = connector_account - .payment_methods_enabled - .unwrap_or_default(); - for payment_method in payment_methods { - let parsed_payment_method_result: Result< - PaymentMethodsEnabled, - error_stack::Report, - > = payment_method.clone().parse_value("payment_method"); - - match parsed_payment_method_result { - Ok(parsed_payment_method) => { - let payment_method_types = parsed_payment_method + filtered_connector_accounts + .into_iter() + .for_each(|connector_account| { + let res = connector_account + .payment_methods_enabled + .unwrap_or_default() + .into_iter() + .map(|payment_methods_enabled| { + payment_methods_enabled + .parse_value::("payment_methods_enabled") + }) + .filter_map(|parsed_payment_method_result| { + let error = parsed_payment_method_result.as_ref().err(); + logger::error!(session_token_parsing_error=?error); + parsed_payment_method_result.ok() + }) + .flat_map(|parsed_payment_methods_enabled| { + parsed_payment_methods_enabled .payment_method_types - .unwrap_or_default(); - for payment_method_type in payment_method_types { - if matches!( - payment_method_type.payment_experience, - Some(api_models::enums::PaymentExperience::InvokeSdkClient) - ) { - let connector_and_wallet = ( + .unwrap_or_default() + .into_iter() + .filter(|payment_method_type| { + let is_invoke_sdk_client = matches!( + payment_method_type.payment_experience, + Some(api_models::enums::PaymentExperience::InvokeSdkClient) + ); + + // If session token is requested for the payment method type, + // filter it out + // if not, then create all sessions tokens + let is_sent_in_request = requested_payment_method_types + .contains(&payment_method_type.payment_method_type) + || requested_payment_method_types.is_empty(); + + is_invoke_sdk_client && is_sent_in_request + }) + .map(|payment_method_type| { + ( connector_account.connector_name.to_owned(), payment_method_type.payment_method_type, - ); - connector_and_supporting_payment_method_type - .push(connector_and_wallet); - } - } - } - Err(parsing_error) => { - logger::debug!(session_token_parsing_error=?parsing_error); - } + connector_account.business_sub_label.to_owned(), + ) + }) + .collect::>() + }) + .collect::>(); + connector_and_supporting_payment_method_type.extend(res); + }); + + let mut session_connector_data = + Vec::with_capacity(connector_and_supporting_payment_method_type.len()); + + for (connector, payment_method_type, business_sub_label) in + connector_and_supporting_payment_method_type + { + match api::ConnectorData::get_connector_by_name( + connectors, + &connector, + api::GetToken::from(payment_method_type), + ) { + Ok(connector_data) => session_connector_data.push(api::SessionConnectorData { + payment_method_type, + connector: connector_data, + business_sub_label, + }), + Err(error) => { + logger::error!(session_token_error=?error) } } } - let requested_payment_method_types = request.wallets.clone(); - - let connectors_data = if !requested_payment_method_types.is_empty() { - let mut connectors_data = Vec::new(); - for payment_method_type in requested_payment_method_types { - for connector_and_payment_method_type in - &connector_and_supporting_payment_method_type - { - if connector_and_payment_method_type.1 == payment_method_type { - let connector_details = api::ConnectorData::get_connector_by_name( - connectors, - connector_and_payment_method_type.0.as_str(), - api::GetToken::from(connector_and_payment_method_type.1), - )?; - connectors_data.push(api::SessionConnectorData { - payment_method_type, - connector: connector_details, - }); - } - } - } - connectors_data - } else { - let mut connectors_data = Vec::new(); - - for connector_and_payment_method_type in connector_and_supporting_payment_method_type { - let connector_details = api::ConnectorData::get_connector_by_name( - connectors, - connector_and_payment_method_type.0.as_str(), - api::GetToken::from(connector_and_payment_method_type.1), - )?; - connectors_data.push(api::SessionConnectorData { - payment_method_type: connector_and_payment_method_type.1, - connector: connector_details, - }); - } - connectors_data - }; - - Ok(api::ConnectorChoice::SessionMultiple(connectors_data)) + Ok(api::ConnectorChoice::SessionMultiple( + session_connector_data, + )) } } diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index be798bc600..3149bfea9e 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -249,6 +249,7 @@ where _merchant_account: &storage::MerchantAccount, state: &AppState, _request: &api::PaymentsStartRequest, + _payment_intent: &storage::payment_intent::PaymentIntent, ) -> CustomResult { helpers::get_connector_default(state, None).await } diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index 22da256adf..acc38bc82c 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -102,6 +102,7 @@ impl Domain for PaymentStatus { _merchant_account: &storage::MerchantAccount, state: &AppState, request: &api::PaymentsRequest, + _payment_intent: &storage::payment_intent::PaymentIntent, ) -> CustomResult { helpers::get_connector_default(state, request.routing.clone()).await } diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 4f0be30e58..6f41bf646d 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -359,6 +359,7 @@ impl Domain for PaymentUpdate { _merchant_account: &storage::MerchantAccount, state: &AppState, request: &api::PaymentsRequest, + _payment_intent: &storage::payment_intent::PaymentIntent, ) -> CustomResult { helpers::get_connector_default(state, request.routing.clone()).await } diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 4b4b2f803e..8bcd3a056f 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -154,6 +154,7 @@ pub struct ConnectorData { pub struct SessionConnectorData { pub payment_method_type: api_enums::PaymentMethodType, pub connector: ConnectorData, + pub business_sub_label: Option, } pub enum ConnectorChoice { @@ -164,7 +165,7 @@ pub enum ConnectorChoice { #[derive(Clone)] pub enum ConnectorCallType { - Multiple(Vec), + Multiple(Vec), Single(ConnectorData), }