Bug: Include the pre-routing connectors in apple pay retries



Currently for apple pay pre-routing is done before the session call and only one connector is decided based on the routing logic. Now since we want to enable auto retries for apple pay we need to consider all the connectors form the routing rule and construct a list of it. After which this connectors should be filtered out with the connectors that supports apple pay simplified flow.

Once this is done there will be a list of connectors with which apple pay retries can we performed.
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index 0641c842390..04983ed8b19 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -2085,7 +2085,15 @@ pub async fn list_payment_methods(
             }
 
             if let Some(choice) = result.get(&intermediate.payment_method_type) {
-                intermediate.connector == choice.connector.connector_name.to_string()
+                if let Some(first_routable_connector) = choice.first() {
+                    intermediate.connector
+                        == first_routable_connector
+                            .connector
+                            .connector_name
+                            .to_string()
+                } else {
+                    false
+                }
             } else {
                 false
             }
@@ -2105,26 +2113,32 @@ pub async fn list_payment_methods(
 
         let mut pre_routing_results: HashMap<
             api_enums::PaymentMethodType,
-            routing_types::RoutableConnectorChoice,
+            storage::PreRoutingConnectorChoice,
         > = HashMap::new();
 
-        for (pm_type, choice) in result {
-            let routable_choice = routing_types::RoutableConnectorChoice {
-                #[cfg(feature = "backwards_compatibility")]
-                choice_kind: routing_types::RoutableChoiceKind::FullStruct,
-                connector: choice
-                    .connector
-                    .connector_name
-                    .to_string()
-                    .parse::<api_enums::RoutableConnectors>()
-                    .change_context(errors::ApiErrorResponse::InternalServerError)?,
-                #[cfg(feature = "connector_choice_mca_id")]
-                merchant_connector_id: choice.connector.merchant_connector_id,
-                #[cfg(not(feature = "connector_choice_mca_id"))]
-                sub_label: choice.sub_label,
-            };
-
-            pre_routing_results.insert(pm_type, routable_choice);
+        for (pm_type, routing_choice) in result {
+            let mut routable_choice_list = vec![];
+            for choice in routing_choice {
+                let routable_choice = routing_types::RoutableConnectorChoice {
+                    #[cfg(feature = "backwards_compatibility")]
+                    choice_kind: routing_types::RoutableChoiceKind::FullStruct,
+                    connector: choice
+                        .connector
+                        .connector_name
+                        .to_string()
+                        .parse::<api_enums::RoutableConnectors>()
+                        .change_context(errors::ApiErrorResponse::InternalServerError)?,
+                    #[cfg(feature = "connector_choice_mca_id")]
+                    merchant_connector_id: choice.connector.merchant_connector_id.clone(),
+                    #[cfg(not(feature = "connector_choice_mca_id"))]
+                    sub_label: choice.sub_label,
+                };
+                routable_choice_list.push(routable_choice);
+            }
+            pre_routing_results.insert(
+                pm_type,
+                storage::PreRoutingConnectorChoice::Multiple(routable_choice_list),
+            );
         }
 
         let redis_conn = db
@@ -2135,15 +2149,28 @@ pub async fn list_payment_methods(
         let mut val = Vec::new();
 
         for (payment_method_type, routable_connector_choice) in &pre_routing_results {
+            let routable_connector_list = match routable_connector_choice {
+                storage::PreRoutingConnectorChoice::Single(routable_connector) => {
+                    vec![routable_connector.clone()]
+                }
+                storage::PreRoutingConnectorChoice::Multiple(routable_connector_list) => {
+                    routable_connector_list.clone()
+                }
+            };
+
+            let first_routable_connector = routable_connector_list
+                .first()
+                .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)?;
+
             #[cfg(not(feature = "connector_choice_mca_id"))]
             let connector_label = get_connector_label(
                 payment_intent.business_country,
                 payment_intent.business_label.as_ref(),
                 #[cfg(not(feature = "connector_choice_mca_id"))]
-                routable_connector_choice.sub_label.as_ref(),
+                first_routable_connector.sub_label.as_ref(),
                 #[cfg(feature = "connector_choice_mca_id")]
                 None,
-                routable_connector_choice.connector.to_string().as_str(),
+                first_routable_connector.connector.to_string().as_str(),
             );
             #[cfg(not(feature = "connector_choice_mca_id"))]
             let matched_mca = filtered_mcas
@@ -2152,7 +2179,7 @@ pub async fn list_payment_methods(
 
             #[cfg(feature = "connector_choice_mca_id")]
             let matched_mca = filtered_mcas.iter().find(|m| {
-                routable_connector_choice.merchant_connector_id.as_ref()
+                first_routable_connector.merchant_connector_id.as_ref()
                     == Some(&m.merchant_connector_id)
             });
 
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index e1290637dbe..50eedcfb568 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -3182,32 +3182,51 @@ where
         .as_ref()
         .zip(payment_data.payment_attempt.payment_method_type.as_ref())
     {
-        if let (Some(choice), None) = (
+        if let (Some(routable_connector_choice), None) = (
             pre_routing_results.get(storage_pm_type),
             &payment_data.token_data,
         ) {
-            let connector_data = api::ConnectorData::get_connector_by_name(
-                &state.conf.connectors,
-                &choice.connector.to_string(),
-                api::GetToken::Connector,
-                #[cfg(feature = "connector_choice_mca_id")]
-                choice.merchant_connector_id.clone(),
-                #[cfg(not(feature = "connector_choice_mca_id"))]
-                None,
-            )
-            .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("Invalid connector name received")?;
+            let routable_connector_list = match routable_connector_choice {
+                storage::PreRoutingConnectorChoice::Single(routable_connector) => {
+                    vec![routable_connector.clone()]
+                }
+                storage::PreRoutingConnectorChoice::Multiple(routable_connector_list) => {
+                    routable_connector_list.clone()
+                }
+            };
+
+            let mut pre_routing_connector_data_list = vec![];
+
+            let first_routable_connector = routable_connector_list
+                .first()
+                .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)?;
 
-            routing_data.routed_through = Some(choice.connector.to_string());
+            routing_data.routed_through = Some(first_routable_connector.connector.to_string());
             #[cfg(feature = "connector_choice_mca_id")]
             {
                 routing_data
                     .merchant_connector_id
-                    .clone_from(&choice.merchant_connector_id);
+                    .clone_from(&first_routable_connector.merchant_connector_id);
             }
             #[cfg(not(feature = "connector_choice_mca_id"))]
             {
-                routing_data.business_sub_label = choice.sub_label.clone();
+                routing_data.business_sub_label = first_routable_connector.sub_label.clone();
+            }
+
+            for connector_choice in routable_connector_list.clone() {
+                let connector_data = api::ConnectorData::get_connector_by_name(
+                    &state.conf.connectors,
+                    &connector_choice.connector.to_string(),
+                    api::GetToken::Connector,
+                    #[cfg(feature = "connector_choice_mca_id")]
+                    connector_choice.merchant_connector_id.clone(),
+                    #[cfg(not(feature = "connector_choice_mca_id"))]
+                    None,
+                )
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("Invalid connector name received")?;
+
+                pre_routing_connector_data_list.push(connector_data);
             }
 
             #[cfg(all(feature = "retry", feature = "connector_choice_mca_id"))]
@@ -3224,8 +3243,11 @@ where
                     merchant_account,
                     payment_data,
                     key_store,
-                    connector_data.clone(),
-                    choice.merchant_connector_id.clone().as_ref(),
+                    &pre_routing_connector_data_list,
+                    first_routable_connector
+                        .merchant_connector_id
+                        .clone()
+                        .as_ref(),
                 )
                 .await?;
 
@@ -3237,7 +3259,13 @@ where
                 }
             }
 
-            return Ok(ConnectorCallType::PreDetermined(connector_data));
+            let first_pre_routing_connector_data_list = pre_routing_connector_data_list
+                .first()
+                .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)?;
+
+            return Ok(ConnectorCallType::PreDetermined(
+                first_pre_routing_connector_data_list.clone(),
+            ));
         }
     }
 
@@ -3614,11 +3642,22 @@ where
         }));
 
         let mut final_list: Vec<api::SessionConnectorData> = Vec::new();
-        for (routed_pm_type, choice) in pre_routing_results.into_iter() {
-            if let Some(session_connector_data) =
-                payment_methods.remove(&(choice.to_string(), routed_pm_type))
-            {
-                final_list.push(session_connector_data);
+        for (routed_pm_type, pre_routing_choice) in pre_routing_results.into_iter() {
+            let routable_connector_list = match pre_routing_choice {
+                storage::PreRoutingConnectorChoice::Single(routable_connector) => {
+                    vec![routable_connector.clone()]
+                }
+                storage::PreRoutingConnectorChoice::Multiple(routable_connector_list) => {
+                    routable_connector_list.clone()
+                }
+            };
+            for routable_connector in routable_connector_list {
+                if let Some(session_connector_data) =
+                    payment_methods.remove(&(routable_connector.to_string(), routed_pm_type))
+                {
+                    final_list.push(session_connector_data);
+                    break;
+                }
             }
         }
 
@@ -3666,8 +3705,11 @@ where
         if !routing_enabled_pms.contains(&connector_data.payment_method_type) {
             final_list.push(connector_data);
         } else if let Some(choice) = result.get(&connector_data.payment_method_type) {
-            if connector_data.connector.connector_name == choice.connector.connector_name {
-                connector_data.business_sub_label = choice.sub_label.clone();
+            let routing_choice = choice
+                .first()
+                .ok_or(errors::ApiErrorResponse::InternalServerError)?;
+            if connector_data.connector.connector_name == routing_choice.connector.connector_name {
+                connector_data.business_sub_label = routing_choice.sub_label.clone();
                 final_list.push(connector_data);
             }
         }
@@ -3678,7 +3720,10 @@ where
         if !routing_enabled_pms.contains(&connector_data.payment_method_type) {
             final_list.push(connector_data);
         } else if let Some(choice) = result.get(&connector_data.payment_method_type) {
-            if connector_data.connector.connector_name == choice.connector.connector_name {
+            let routing_choice = choice
+                .first()
+                .ok_or(errors::ApiErrorResponse::InternalServerError)?;
+            if connector_data.connector.connector_name == routing_choice.connector.connector_name {
                 final_list.push(connector_data);
             }
         }
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index c94c1c714c7..a3751465b2c 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -4022,7 +4022,7 @@ pub async fn get_apple_pay_retryable_connectors<F>(
     merchant_account: &domain::MerchantAccount,
     payment_data: &mut PaymentData<F>,
     key_store: &domain::MerchantKeyStore,
-    decided_connector_data: api::ConnectorData,
+    pre_routing_connector_data_list: &[api::ConnectorData],
     merchant_connector_id: Option<&String>,
 ) -> CustomResult<Option<Vec<api::ConnectorData>>, errors::ApiErrorResponse>
 where
@@ -4037,13 +4037,17 @@ where
             field_name: "profile_id",
         })?;
 
+    let pre_decided_connector_data_first = pre_routing_connector_data_list
+        .first()
+        .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)?;
+
     let merchant_connector_account_type = get_merchant_connector_account(
         &state,
         merchant_account.merchant_id.as_str(),
         payment_data.creds_identifier.to_owned(),
         key_store,
         profile_id,
-        &decided_connector_data.connector_name.to_string(),
+        &pre_decided_connector_data_first.connector_name.to_string(),
         merchant_connector_id,
     )
     .await?;
@@ -4070,7 +4074,7 @@ where
             Some(profile_id.to_string()),
         );
 
-        let mut connector_data_list = vec![decided_connector_data.clone()];
+        let mut connector_data_list = vec![pre_decided_connector_data_first.clone()];
 
         for merchant_connector_account in profile_specific_merchant_connector_account_list {
             if is_apple_pay_simplified_flow(
@@ -4107,16 +4111,31 @@ where
         .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("Failed to get merchant default fallback connectors config")?;
 
+        let mut routing_connector_data_list = Vec::new();
+
+        pre_routing_connector_data_list.iter().for_each(|pre_val| {
+            routing_connector_data_list.push(pre_val.merchant_connector_id.clone())
+        });
+
+        fallback_connetors_list.iter().for_each(|fallback_val| {
+            routing_connector_data_list
+                .iter()
+                .all(|val| *val != fallback_val.merchant_connector_id)
+                .then(|| {
+                    routing_connector_data_list.push(fallback_val.merchant_connector_id.clone())
+                });
+        });
+
         // connector_data_list is the list of connectors for which Apple Pay simplified flow is configured.
-        // This list is arranged in the same order as the merchant's default fallback connectors configuration.
-        let mut ordered_connector_data_list = vec![decided_connector_data.clone()];
-        fallback_connetors_list
+        // This list is arranged in the same order as the merchant's connectors routingconfiguration.
+
+        let mut ordered_connector_data_list = Vec::new();
+
+        routing_connector_data_list
             .iter()
-            .for_each(|fallback_connector| {
+            .for_each(|merchant_connector_id| {
                 let connector_data = connector_data_list.iter().find(|connector_data| {
-                    fallback_connector.merchant_connector_id == connector_data.merchant_connector_id
-                        && fallback_connector.merchant_connector_id
-                            != decided_connector_data.merchant_connector_id
+                    *merchant_connector_id == connector_data.merchant_connector_id
                 });
                 if let Some(connector_data_details) = connector_data {
                     ordered_connector_data_list.push(connector_data_details.clone());
diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs
index 4394637d99a..3afb933d467 100644
--- a/crates/router/src/core/payments/routing.rs
+++ b/crates/router/src/core/payments/routing.rs
@@ -855,7 +855,8 @@ pub async fn perform_eligibility_analysis_with_fallback<F: Clone>(
 pub async fn perform_session_flow_routing(
     session_input: SessionFlowRoutingInput<'_>,
     transaction_type: &api_enums::TransactionType,
-) -> RoutingResult<FxHashMap<api_enums::PaymentMethodType, routing_types::SessionRoutingChoice>> {
+) -> RoutingResult<FxHashMap<api_enums::PaymentMethodType, Vec<routing_types::SessionRoutingChoice>>>
+{
     let mut pm_type_map: FxHashMap<api_enums::PaymentMethodType, FxHashMap<String, api::GetToken>> =
         FxHashMap::default();
 
@@ -962,8 +963,10 @@ pub async fn perform_session_flow_routing(
             );
     }
 
-    let mut result: FxHashMap<api_enums::PaymentMethodType, routing_types::SessionRoutingChoice> =
-        FxHashMap::default();
+    let mut result: FxHashMap<
+        api_enums::PaymentMethodType,
+        Vec<routing_types::SessionRoutingChoice>,
+    > = FxHashMap::default();
 
     for (pm_type, allowed_connectors) in pm_type_map {
         let euclid_pmt: euclid_enums::PaymentMethodType = pm_type;
@@ -985,20 +988,37 @@ pub async fn perform_session_flow_routing(
             ))]
             profile_id: session_input.payment_intent.profile_id.clone(),
         };
-        let maybe_choice =
-            perform_session_routing_for_pm_type(session_pm_input, transaction_type).await?;
-
-        // (connector, sub_label)
-        if let Some(data) = maybe_choice {
-            result.insert(
-                pm_type,
-                routing_types::SessionRoutingChoice {
-                    connector: data.0,
+        let routable_connector_choice_option =
+            perform_session_routing_for_pm_type(&session_pm_input, transaction_type).await?;
+
+        if let Some(routable_connector_choice) = routable_connector_choice_option {
+            let mut session_routing_choice: Vec<routing_types::SessionRoutingChoice> = Vec::new();
+
+            for selection in routable_connector_choice {
+                let connector_name = selection.connector.to_string();
+                if let Some(get_token) = session_pm_input.allowed_connectors.get(&connector_name) {
+                    let connector_data = api::ConnectorData::get_connector_by_name(
+                        &session_pm_input.state.clone().conf.connectors,
+                        &connector_name,
+                        get_token.clone(),
+                        #[cfg(feature = "connector_choice_mca_id")]
+                        selection.merchant_connector_id,
+                        #[cfg(not(feature = "connector_choice_mca_id"))]
+                        None,
+                    )
+                    .change_context(errors::RoutingError::InvalidConnectorName(connector_name))?;
                     #[cfg(not(feature = "connector_choice_mca_id"))]
-                    sub_label: data.1,
-                    payment_method_type: pm_type,
-                },
-            );
+                    let sub_label = selection.sub_label;
+
+                    session_routing_choice.push(routing_types::SessionRoutingChoice {
+                        connector: connector_data,
+                        #[cfg(not(feature = "connector_choice_mca_id"))]
+                        sub_label: sub_label,
+                        payment_method_type: pm_type,
+                    });
+                }
+            }
+            result.insert(pm_type, session_routing_choice);
         }
     }
 
@@ -1006,9 +1026,9 @@ pub async fn perform_session_flow_routing(
 }
 
 async fn perform_session_routing_for_pm_type(
-    session_pm_input: SessionRoutingPmTypeInput<'_>,
+    session_pm_input: &SessionRoutingPmTypeInput<'_>,
     transaction_type: &api_enums::TransactionType,
-) -> RoutingResult<Option<(api::ConnectorData, Option<String>)>> {
+) -> RoutingResult<Option<Vec<api_models::routing::RoutableConnectorChoice>>> {
     let merchant_id = &session_pm_input.key_store.merchant_id;
 
     let chosen_connectors = match session_pm_input.routing_algorithm {
@@ -1091,7 +1111,7 @@ async fn perform_session_routing_for_pm_type(
             &session_pm_input.state.clone(),
             session_pm_input.key_store,
             fallback,
-            session_pm_input.backend_input,
+            session_pm_input.backend_input.clone(),
             None,
             #[cfg(feature = "business_profile_routing")]
             session_pm_input.profile_id.clone(),
@@ -1100,32 +1120,11 @@ async fn perform_session_routing_for_pm_type(
         .await?;
     }
 
-    let mut final_choice: Option<(api::ConnectorData, Option<String>)> = None;
-
-    for selection in final_selection {
-        let connector_name = selection.connector.to_string();
-        if let Some(get_token) = session_pm_input.allowed_connectors.get(&connector_name) {
-            let connector_data = api::ConnectorData::get_connector_by_name(
-                &session_pm_input.state.clone().conf.connectors,
-                &connector_name,
-                get_token.clone(),
-                #[cfg(feature = "connector_choice_mca_id")]
-                selection.merchant_connector_id,
-                #[cfg(not(feature = "connector_choice_mca_id"))]
-                None,
-            )
-            .change_context(errors::RoutingError::InvalidConnectorName(connector_name))?;
-            #[cfg(not(feature = "connector_choice_mca_id"))]
-            let sub_label = selection.sub_label;
-            #[cfg(feature = "connector_choice_mca_id")]
-            let sub_label = None;
-
-            final_choice = Some((connector_data, sub_label));
-            break;
-        }
+    if final_selection.is_empty() {
+        Ok(None)
+    } else {
+        Ok(Some(final_selection))
     }
-
-    Ok(final_choice)
 }
 
 pub fn make_dsl_input_for_surcharge(
diff --git a/crates/router/src/types/storage.rs b/crates/router/src/types/storage.rs
index 77550bedabe..79c8b2ed2f0 100644
--- a/crates/router/src/types/storage.rs
+++ b/crates/router/src/types/storage.rs
@@ -81,14 +81,21 @@ pub struct RoutingData {
 pub struct PaymentRoutingInfo {
     pub algorithm: Option<routing::StraightThroughAlgorithm>,
     pub pre_routing_results:
-        Option<HashMap<api_models::enums::PaymentMethodType, routing::RoutableConnectorChoice>>,
+        Option<HashMap<api_models::enums::PaymentMethodType, PreRoutingConnectorChoice>>,
 }
 
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 pub struct PaymentRoutingInfoInner {
     pub algorithm: Option<routing::StraightThroughAlgorithm>,
     pub pre_routing_results:
-        Option<HashMap<api_models::enums::PaymentMethodType, routing::RoutableConnectorChoice>>,
+        Option<HashMap<api_models::enums::PaymentMethodType, PreRoutingConnectorChoice>>,
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[serde(untagged)]
+pub enum PreRoutingConnectorChoice {
+    Single(routing::RoutableConnectorChoice),
+    Multiple(Vec<routing::RoutableConnectorChoice>),
 }
 
 #[derive(Debug, serde::Serialize, serde::Deserialize)]

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [x] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
Currently for apple pay pre-routing is done before the session call and only one connector is decided based on the routing logic. Now since we want to enable auto retries for apple pay we need to consider all the connectors form the routing rule and construct a list of it. After which this connectors should be filtered out with the connectors that supports apple pay simplified flow.

Once this is done there will be a list of connectors with which apple pay retries can we performed.

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
-> Create merchant account
-> Enable auto retries for the specific `merchant_id`
```
curl --location 'localhost:8080/configs/' \
--header 'api-key: test_admin' \
--header 'Content-Type: application/json' \
--data '{
    "key": "should_call_gsm_merchant_1718202727",
    "value": "true"
}'
```
-> Set the maximum retry counts for the auto retries enabled `merchant_id`
```
curl --location 'localhost:8080/configs/' \
--header 'api-key: test_admin' \
--header 'Content-Type: application/json' \
--data '{
    "key": "max_auto_retries_enabled_merchant_1718202727",
    "value": "1"
}'
```
-> Configure the error code and error message in the gsm
```
curl --location 'localhost:8080/gsm' \
--header 'api-key: test_admin' \
--header 'Content-Type: application/json' \
--data '{
    "connector": "stripe",
    "flow": "Authorize",
    "sub_flow": "sub_flow",
    "code": "No error code",
    "message": "No error message",
    "status": "Failure",
    "decision": "retry",
    "step_up_possible": false
}'
```
-> Create merchant connector accounts (enable apple pay simplified if you wish to retry the failed apple pay payment with it)
metadata for simplified flow
```
"apple_pay_combined": {
            "simplified": {
                "session_token_data": {
                    "initiative_context": "sdk-test-app.netlify.app",
                    "merchant_business_country": "US"
                },
                "payment_request_data": {
                    "label": "applepay",
                    "supported_networks": [
                        "visa",
                        "masterCard",
                        "amex",
                        "discover"
                    ],
                    "merchant_capabilities": [
                        "supports3DS"
                    ]
                }
            }
        }
```

-> Configure the routing rules for the configured connectors
```
curl --location 'http://localhost:8080/routing' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_T4l0hzK8OqmFbaNYGWEVhC6d0RkxRKPCMyA3Fi0C94C7kweFZSErnTz5fNuw8sCn' \
--data '{
    "name": "priority config",
    "description": "some desc",
    "algorithm": {
        "type": "priority",
        "data": [
            {
                "connector": "stripe",
                "merchant_connector_id": "mca_eF7yV3fNcAZ2wmGlKORq"
            },
            {
                "connector": "cybersource",
                "merchant_connector_id": "mca_YAgldl8pmWD7mlqKrPlj"
            },
            {
                "connector": "adyen",
                "merchant_connector_id": "mca_rkYJzRw3mSpDnPr25huU"
            },
            {
                "connector": "rapyd",
                "merchant_connector_id": "mca_Vjg1fbX8FKP2ywlU4kOq"
            }
        ]
    },
    "profile_id": "pro_Rv8QaYCARaEOCglUGXpa"
}'
```
<img width="1133" alt="image" src="https://github.com/juspay/hyperswitch/assets/83439957/0fc7248d-abcb-487f-b266-afa98b28b2d6">

-> Create a apple pay payment with confirm false
```
{
    "amount": 6500,
    "currency": "USD",
    "confirm": false,
    "amount_to_capture": 6500,
    "customer_id": "test_priority_routing",
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "authentication_type": "three_ds",
    "return_url": "https://google.com",
    "email": "something@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
       
    }
}
```
<img width="1001" alt="image" src="https://github.com/juspay/hyperswitch/assets/83439957/5674379f-7f8a-4705-ace3-f36f1d761671">

-> List payment methods for merchant
```
curl --location 'http://localhost:8080/account/payment_methods?client_secret=pay_uKquqDLCGBBzbXpsEKyy_secret_soCWAMLK8xCq7WZ42KQD' \
--header 'Accept: application/json' \
--header 'api-key: pk_dev_97bb28e2fc3b42099d802df96188f7ec'
```
<img width="1120" alt="image" src="https://github.com/juspay/hyperswitch/assets/83439957/9eac6d54-f99d-4b5a-bddb-3b1b8aecade2">

-> Confirm the payment with `payment_id`
```
curl --location 'http://localhost:8080/payments/pay_uKquqDLCGBBzbXpsEKyy/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_T4l0hzK8OqmFbaNYGWEVhC6d0RkxRKPCMyA3Fi0C94C7kweFZSErnTz5fNuw8sCn' \
--data '{
    "payment_method": "wallet",
    "payment_method_type": "apple_pay",
    "browser_info": {
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "127.0.0.1"
    },
    "payment_method_data": {
        "wallet": {
            "apple_pay": {
                "payment_data":"eyJkYXRhIjoiSWJKaWp1TTRXT0lpM1BZcTRWVlpIL2wwUld1Qm5JRk5vMHBsWGp1L1E2bW9uQ0JVOE9rVHFDbnkwWDlZVVBZYzVBMXRIckE1eTV0NlpsSFVkZFJyYlY3QXIzMVVEc0NSbVlDVDRweFdEQ0oxTnF5WWYrK3NPQThZRkh5di83aUJiTnJ6K1g0Q0dwelNtelRNL2V6TUxzY2VCdHM4dkozQk05VnRGdVY2bXJsN2lPcGNHUGlNam5wK2ZkaG1OYlNHcGt0Qmt4QVRmaHlpM3VjbWNBejNjYWlMV3RSN2Yrc2owUmlzL0pBcmhuVzVZdmNodE53K2prSFBXZW9HeG1KTEFFUW1HRnZ3dGJCaWFKVFEvVnpmdEJtK3RGYkliWTBYeFdrRXdSQllIajlCVnVmbEVDaVlKK2NYLytBdVhlS2ZHZHZMQWZrNjNSYmZJQm5hTVR6dWlXZ2tEM1N5T3hJbE82MGxveHFPSmkxbkgvQXZSdFlMOUt4NWM0dzEwYnZVcENZZys4aytpdmg0aEdIdTF3PT0iLCJzaWduYXR1cmUiOiJNSUFHQ1NxR1NJYjNEUUVIQXFDQU1JQUNBUUV4RFRBTEJnbGdoa2dCWlFNRUFnRXdnQVlKS29aSWh2Y05BUWNCQUFDZ2dEQ0NBK013Z2dPSW9BTUNBUUlDQ0JaalRJc09NRmNYTUFvR0NDcUdTTTQ5QkFNQ01Ib3hMakFzQmdOVkJBTU1KVUZ3Y0d4bElFRndjR3hwWTJGMGFXOXVJRWx1ZEdWbmNtRjBhVzl1SUVOQklDMGdSek14SmpBa0JnTlZCQXNNSFVGd2NHeGxJRU5sY25ScFptbGpZWFJwYjI0Z1FYVjBhRzl5YVhSNU1STXdFUVlEVlFRS0RBcEJjSEJzWlNCSmJtTXVNUXN3Q1FZRFZRUUdFd0pWVXpBZUZ3MHlOREEwTWpreE56UTNNamRhRncweU9UQTBNamd4TnpRM01qWmFNRjh4SlRBakJnTlZCQU1NSEdWall5MXpiWEF0WW5KdmEyVnlMWE5wWjI1ZlZVTTBMVkJTVDBReEZEQVNCZ05WQkFzTUMybFBVeUJUZVhOMFpXMXpNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVFzd0NRWURWUVFHRXdKVlV6QlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJNSVZkKzNyMXNleUlZOW8zWENRb1NHTng3QzlieXdvUFlSZ2xkbEs5S1ZCRzROQ0R0Z1I4MEIrZ3pNZkhGVEQ5K3N5SU5hNjFkVHY5SktKaVQ1OER4T2pnZ0lSTUlJQ0RUQU1CZ05WSFJNQkFmOEVBakFBTUI4R0ExVWRJd1FZTUJhQUZDUHlTY1JQaytUdkorYkU5aWhzUDZLNy9TNUxNRVVHQ0NzR0FRVUZCd0VCQkRrd056QTFCZ2dyQmdFRkJRY3dBWVlwYUhSMGNEb3ZMMjlqYzNBdVlYQndiR1V1WTI5dEwyOWpjM0F3TkMxaGNIQnNaV0ZwWTJFek1ESXdnZ0VkQmdOVkhTQUVnZ0VVTUlJQkVEQ0NBUXdHQ1NxR1NJYjNZMlFGQVRDQi9qQ0J3d1lJS3dZQkJRVUhBZ0l3Z2JZTWdiTlNaV3hwWVc1alpTQnZiaUIwYUdseklHTmxjblJwWm1sallYUmxJR0o1SUdGdWVTQndZWEowZVNCaGMzTjFiV1Z6SUdGalkyVndkR0Z1WTJVZ2IyWWdkR2hsSUhSb1pXNGdZWEJ3YkdsallXSnNaU0J6ZEdGdVpHRnlaQ0IwWlhKdGN5QmhibVFnWTI5dVpHbDBhVzl1Y3lCdlppQjFjMlVzSUdObGNuUnBabWxqWVhSbElIQnZiR2xqZVNCaGJtUWdZMlZ5ZEdsbWFXTmhkR2x2YmlCd2NtRmpkR2xqWlNCemRHRjBaVzFsYm5SekxqQTJCZ2dyQmdFRkJRY0NBUllxYUhSMGNEb3ZMM2QzZHk1aGNIQnNaUzVqYjIwdlkyVnlkR2xtYVdOaGRHVmhkWFJvYjNKcGRIa3ZNRFFHQTFVZEh3UXRNQ3N3S2FBbm9DV0dJMmgwZEhBNkx5OWpjbXd1WVhCd2JHVXVZMjl0TDJGd2NHeGxZV2xqWVRNdVkzSnNNQjBHQTFVZERnUVdCQlNVVjl0djFYU0Job21KZGk5K1Y0VUg1NXRZSkRBT0JnTlZIUThCQWY4RUJBTUNCNEF3RHdZSktvWklodmRqWkFZZEJBSUZBREFLQmdncWhrak9QUVFEQWdOSkFEQkdBaUVBeHZBanl5WVV1ekE0aUtGaW1ENGFrL0VGYjFENmVNMjV1a3lpUWN3VTRsNENJUUMrUE5EZjBXSkg5a2xFZFRnT25VVENLS0VJa0tPaDNISkxpMHk0aUpnWXZEQ0NBdTR3Z2dKMW9BTUNBUUlDQ0VsdEw3ODZtTnFYTUFvR0NDcUdTTTQ5QkFNQ01HY3hHekFaQmdOVkJBTU1Fa0Z3Y0d4bElGSnZiM1FnUTBFZ0xTQkhNekVtTUNRR0ExVUVDd3dkUVhCd2JHVWdRMlZ5ZEdsbWFXTmhkR2x2YmlCQmRYUm9iM0pwZEhreEV6QVJCZ05WQkFvTUNrRndjR3hsSUVsdVl5NHhDekFKQmdOVkJBWVRBbFZUTUI0WERURTBNRFV3TmpJek5EWXpNRm9YRFRJNU1EVXdOakl6TkRZek1Gb3dlakV1TUN3R0ExVUVBd3dsUVhCd2JHVWdRWEJ3YkdsallYUnBiMjRnU1c1MFpXZHlZWFJwYjI0Z1EwRWdMU0JITXpFbU1DUUdBMVVFQ3d3ZFFYQndiR1VnUTJWeWRHbG1hV05oZEdsdmJpQkJkWFJvYjNKcGRIa3hFekFSQmdOVkJBb01Da0Z3Y0d4bElFbHVZeTR4Q3pBSkJnTlZCQVlUQWxWVE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRThCY1JoQm5YWklYVkdsNGxnUWQyNklDaTc5NTdyazNnamZ4TGsrRXpWdFZtV3pXdUl0Q1hkZzBpVG51NkNQMTJGODZJeTNhN1puQyt5T2dwaFA5VVJhT0I5ekNCOURCR0JnZ3JCZ0VGQlFjQkFRUTZNRGd3TmdZSUt3WUJCUVVITUFHR0ttaDBkSEE2THk5dlkzTndMbUZ3Y0d4bExtTnZiUzl2WTNOd01EUXRZWEJ3YkdWeWIyOTBZMkZuTXpBZEJnTlZIUTRFRmdRVUkvSkp4RStUNU84bjVzVDJLR3cvb3J2OUxrc3dEd1lEVlIwVEFRSC9CQVV3QXdFQi96QWZCZ05WSFNNRUdEQVdnQlM3c042aFdET0ltcVNLbWQ2K3ZldXYyc3NrcXpBM0JnTlZIUjhFTURBdU1DeWdLcUFvaGlab2RIUndPaTh2WTNKc0xtRndjR3hsTG1OdmJTOWhjSEJzWlhKdmIzUmpZV2N6TG1OeWJEQU9CZ05WSFE4QkFmOEVCQU1DQVFZd0VBWUtLb1pJaHZkalpBWUNEZ1FDQlFBd0NnWUlLb1pJemowRUF3SURad0F3WkFJd09zOXlnMUVXbWJHRyt6WERWc3Bpdi9RWDdka1BkVTJpanI3eG5JRmVRcmVKK0pqM20xbWZtTlZCRFkrZDZjTCtBakF5TGRWRUliQ2pCWGRzWGZNNE81Qm4vUmQ4TENGdGxrL0djbW1DRW05VStIcDlHNW5MbXdtSklXRUdtUThKa2gwQUFER0NBWWN3Z2dHREFnRUJNSUdHTUhveExqQXNCZ05WQkFNTUpVRndjR3hsSUVGd2NHeHBZMkYwYVc5dUlFbHVkR1ZuY21GMGFXOXVJRU5CSUMwZ1J6TXhKakFrQmdOVkJBc01IVUZ3Y0d4bElFTmxjblJwWm1sallYUnBiMjRnUVhWMGFHOXlhWFI1TVJNd0VRWURWUVFLREFwQmNIQnNaU0JKYm1NdU1Rc3dDUVlEVlFRR0V3SlZVd0lJRm1OTWl3NHdWeGN3Q3dZSllJWklBV1VEQkFJQm9JR1RNQmdHQ1NxR1NJYjNEUUVKQXpFTEJna3Foa2lHOXcwQkJ3RXdIQVlKS29aSWh2Y05BUWtGTVE4WERUSTBNRFV5TVRBM016TXlORm93S0FZSktvWklodmNOQVFrME1Sc3dHVEFMQmdsZ2hrZ0JaUU1FQWdHaENnWUlLb1pJemowRUF3SXdMd1lKS29aSWh2Y05BUWtFTVNJRUlEa29VdTlwZ01JUHR2R0VEZi9tSXk3LzNjSTg2b3U5eTJaZkV6RkhuRFN0TUFvR0NDcUdTTTQ5QkFNQ0JFWXdSQUlnTWdkSG9rZHNWQndya3RYRzd1VmowMm9QVVNsQllaWGVPeXJyd3RsQk5MUUNJRDdzZnZPaThZcjVWNkVyNjFqU05sKzR3ZDhpR050YUxEdFRMZjNBQ0VhNkFBQUFBQUFBIiwiaGVhZGVyIjp7InB1YmxpY0tleUhhc2giOiJ4MnFmMTFaemRXbnFCZnc0U0NyOWxIYzZRc1JQOEp6Z2xrZnU5RTVkWUpnPSIsImVwaGVtZXJhbFB1YmxpY0tleSI6Ik1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTR0bHR1ODRmdzNldG5zeWR0ZXh5RnJVeVRhN3pqbXlYcjZ3OFIraU9TUm1qUDV5ZWlWUEs4OWFoZDJYM1JtaUZtUjQxdHN4S1AwOEpBZVYrSXpvUXBnPT0iLCJ0cmFuc2FjdGlvbklkIjoiMmEzZDYyYTUzZDBmMzg1NGUwNTA0Y2RhZDU2MzlmYjA2MjJiZTI0YzY0ZDg2ZGYxMDlkMTNjZjdkNTAxNjA1MSJ9LCJ2ZXJzaW9uIjoiRUNfdjEifQ==",
                "payment_method": {
                    "display_name": "Visa 0326",
                    "network": "Mastercard",
                    "type": "debit"
                },
                "transaction_identifier": "55CC32D7BF7890B9064433F15B9F23F849CF84AFD01E4E65DD8ADE306300E9D8"
            }
        }
    }
}'
```
<img width="1075" alt="image" src="https://github.com/juspay/hyperswitch/assets/83439957/9400e62e-7a9b-4f4b-b8af-cba74d61719e">

-> Retrieve the payment with the `payment_id`.
```
curl --location 'http://localhost:8080/payments/pay_uKquqDLCGBBzbXpsEKyy?expand_attempts=true' \
--header 'Accept: application/json' \
--header 'api-key: dev_T4l0hzK8OqmFbaNYGWEVhC6d0RkxRKPCMyA3Fi0C94C7kweFZSErnTz5fNuw8sCn'
```
<img width="737" alt="image" src="https://github.com/juspay/hyperswitch/assets/83439957/6b290982-7d4b-4e92-b21b-cd756c2d4f02">

In the above response we can see that apple payment got failed with stripe and it was auto retried with adyen based on the configured routing rule.

-> The routing rule configured during test is as shown below
<img width="1133" alt="image" src="https://github.com/juspay/hyperswitch/assets/83439957/c7916e7f-f3f8-4529-b90c-aafc67de28a9">

-> Below is entry of the pre-routing in the payment attempt table
"apple_pay": [{"connector": "stripe", "merchant_c
onnector_id": "mca_eF7yV3fNcAZ2wmGlKORq"}, {"connector": "cybersource", "merchant_connector_id": "mca_YAgldl8pmWD7mlqKrPlj"}, {"connector": "adyen", "merchant_connector_id": "mca_rkYJzRw3mSpDnPr25huU"}, {"connector": "rapyd", "merchant_connector_id": "mca_Vjg1fbX8FKP2ywlU4kOq"}],

-> The order of apple pay retryable connector as below. As per the routing rules the stripe comes in the first of the list followed by adyen, as apple pay simplified flow is configured only for stripe and adyen.
![image](https://github.com/juspay/hyperswitch/assets/83439957/220ebe4b-95f4-4dfa-ac9c-65202c399e96)


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
