    //Converting Intent-Attempt array to Response if no error
    let data: Vec<api::PaymentsResponse> = pi_pa_tuple_vec
        .change_context(errors::ApiErrorResponse::InternalServerError)?
        .into_iter()
        .map(ForeignFrom::foreign_from)
        .collect();

    Ok(services::ApplicationResponse::Json(
        api::PaymentListResponse {
            size: data.len(),
            data,
        },
    ))
}

#[cfg(all(feature = "v2", feature = "olap"))]
pub async fn list_payments(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    constraints: api::PaymentListConstraints,
) -> RouterResponse<payments_api::PaymentListResponse> {
    common_utils::metrics::utils::record_operation_time(
        async {
            let limit = &constraints.limit;
            helpers::validate_payment_list_request_for_joins(*limit)?;
            let db: &dyn StorageInterface = state.store.as_ref();
            let fetch_constraints = constraints.clone().into();
            let list: Vec<(storage::PaymentIntent, Option<storage::PaymentAttempt>)> = db
                .get_filtered_payment_intents_attempt(
                    &(&state).into(),
                    merchant_context.get_merchant_account().get_id(),
                    &fetch_constraints,
                    merchant_context.get_merchant_key_store(),
                    merchant_context.get_merchant_account().storage_scheme,
                )
                .await
                .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
            let data: Vec<api_models::payments::PaymentsListResponseItem> =
                list.into_iter().map(ForeignFrom::foreign_from).collect();

            let active_attempt_ids = db
                .get_filtered_active_attempt_ids_for_total_count(
                    merchant_context.get_merchant_account().get_id(),
                    &fetch_constraints,
                    merchant_context.get_merchant_account().storage_scheme,
                )
                .await
                .to_not_found_response(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Error while retrieving active_attempt_ids for merchant")?;

            let total_count = if constraints.has_no_attempt_filters() {
                i64::try_from(active_attempt_ids.len())
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Error while converting from usize to i64")
            } else {
                let active_attempt_ids = active_attempt_ids
                    .into_iter()
                    .flatten()
                    .collect::<Vec<String>>();

                db.get_total_count_of_filtered_payment_attempts(
                    merchant_context.get_merchant_account().get_id(),
                    &active_attempt_ids,
                    constraints.connector,
                    constraints.payment_method_type,
                    constraints.payment_method_subtype,
                    constraints.authentication_type,
                    constraints.merchant_connector_id,
                    constraints.card_network,
                    merchant_context.get_merchant_account().storage_scheme,
                )
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Error while retrieving total count of payment attempts")
            }?;

            Ok(services::ApplicationResponse::Json(
                api_models::payments::PaymentListResponse {
                    count: data.len(),
                    total_count,
                    data,
                },
            ))
        },
        &metrics::PAYMENT_LIST_LATENCY,
        router_env::metric_attributes!((
            "merchant_id",
            merchant_context.get_merchant_account().get_id().clone()
        )),
    )
    .await
}

#[cfg(all(feature = "olap", feature = "v1"))]
pub async fn apply_filters_on_payments(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id_list: Option<Vec<id_type::ProfileId>>,
    constraints: api::PaymentListFilterConstraints,
) -> RouterResponse<api::PaymentListResponseV2> {
    common_utils::metrics::utils::record_operation_time(
        async {
            let limit = &constraints.limit;
            helpers::validate_payment_list_request_for_joins(*limit)?;
            let db: &dyn StorageInterface = state.store.as_ref();
            let pi_fetch_constraints = (constraints.clone(), profile_id_list.clone()).try_into()?;
            let list: Vec<(storage::PaymentIntent, storage::PaymentAttempt)> = db
                .get_filtered_payment_intents_attempt(
                    &(&state).into(),
                    merchant_context.get_merchant_account().get_id(),
                    &pi_fetch_constraints,
                    merchant_context.get_merchant_key_store(),
                    merchant_context.get_merchant_account().storage_scheme,
                )
                .await
                .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
            let data: Vec<api::PaymentsResponse> =
                list.into_iter().map(ForeignFrom::foreign_from).collect();

            let active_attempt_ids = db
                .get_filtered_active_attempt_ids_for_total_count(
                    merchant_context.get_merchant_account().get_id(),
                    &pi_fetch_constraints,
                    merchant_context.get_merchant_account().storage_scheme,
                )
                .await
                .to_not_found_response(errors::ApiErrorResponse::InternalServerError)?;

            let total_count = if constraints.has_no_attempt_filters() {
                i64::try_from(active_attempt_ids.len())
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Error while converting from usize to i64")
            } else {
                db.get_total_count_of_filtered_payment_attempts(
                    merchant_context.get_merchant_account().get_id(),
                    &active_attempt_ids,
                    constraints.connector,
                    constraints.payment_method,
                    constraints.payment_method_type,
                    constraints.authentication_type,
                    constraints.merchant_connector_id,
                    constraints.card_network,
                    constraints.card_discovery,
                    merchant_context.get_merchant_account().storage_scheme,
                )
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
            }?;

            Ok(services::ApplicationResponse::Json(
                api::PaymentListResponseV2 {
                    count: data.len(),
                    total_count,
                    data,
                },
            ))
        },
        &metrics::PAYMENT_LIST_LATENCY,
        router_env::metric_attributes!((
            "merchant_id",
            merchant_context.get_merchant_account().get_id().clone()
        )),
    )
    .await
}

#[cfg(all(feature = "olap", feature = "v1"))]
pub async fn get_filters_for_payments(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    time_range: common_utils::types::TimeRange,
) -> RouterResponse<api::PaymentListFilters> {
    let db = state.store.as_ref();
    let pi = db
        .filter_payment_intents_by_time_range_constraints(
            &(&state).into(),
            merchant_context.get_merchant_account().get_id(),
            &time_range,
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

    let filters = db
        .get_filters_for_payments(
            pi.as_slice(),
            merchant_context.get_merchant_account().get_id(),
            // since OLAP doesn't have KV. Force to get the data from PSQL.
            storage_enums::MerchantStorageScheme::PostgresOnly,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

    Ok(services::ApplicationResponse::Json(
        api::PaymentListFilters {
            connector: filters.connector,
            currency: filters.currency,
            status: filters.status,
            payment_method: filters.payment_method,
            payment_method_type: filters.payment_method_type,
            authentication_type: filters.authentication_type,
        },
    ))
}

#[cfg(feature = "olap")]
pub async fn get_payment_filters(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id_list: Option<Vec<id_type::ProfileId>>,
) -> RouterResponse<api::PaymentListFiltersV2> {
    let merchant_connector_accounts = if let services::ApplicationResponse::Json(data) =
        super::admin::list_payment_connectors(
            state,
            merchant_context.get_merchant_account().get_id().to_owned(),
            profile_id_list,
        )
        .await?
    {
        data
    } else {
        return Err(errors::ApiErrorResponse::InternalServerError.into());
    };

    let mut connector_map: HashMap<String, Vec<MerchantConnectorInfo>> = HashMap::new();
    let mut payment_method_types_map: HashMap<
        enums::PaymentMethod,
        HashSet<enums::PaymentMethodType>,
    > = HashMap::new();

    // populate connector map
    merchant_connector_accounts
        .iter()
        .filter_map(|merchant_connector_account| {
            merchant_connector_account
                .connector_label
                .as_ref()
                .map(|label| {
                    let info = merchant_connector_account.to_merchant_connector_info(label);
                    (merchant_connector_account.get_connector_name(), info)
                })
        })
        .for_each(|(connector_name, info)| {
            connector_map
                .entry(connector_name.to_string())
                .or_default()
                .push(info);
        });

    // populate payment method type map
    merchant_connector_accounts
        .iter()
        .flat_map(|merchant_connector_account| {
            merchant_connector_account.payment_methods_enabled.as_ref()
        })
        .map(|payment_methods_enabled| {
            payment_methods_enabled
                .iter()
                .filter_map(|payment_method_enabled| {
                    payment_method_enabled
                        .get_payment_method_type()
                        .map(|types_vec| {
                            (
                                payment_method_enabled.get_payment_method(),
                                types_vec.clone(),
                            )
                        })
                })
        })
        .for_each(|payment_methods_enabled| {
            payment_methods_enabled.for_each(
                |(payment_method_option, payment_method_types_vec)| {
                    if let Some(payment_method) = payment_method_option {
                        payment_method_types_map
                            .entry(payment_method)
                            .or_default()
                            .extend(payment_method_types_vec.iter().filter_map(
                                |req_payment_method_types| {
                                    req_payment_method_types.get_payment_method_type()
                                },
                            ));
                    }
                },
            );
        });

    Ok(services::ApplicationResponse::Json(
        api::PaymentListFiltersV2 {
            connector: connector_map,
            currency: enums::Currency::iter().collect(),
            status: enums::IntentStatus::iter().collect(),
            payment_method: payment_method_types_map,
            authentication_type: enums::AuthenticationType::iter().collect(),
            card_network: enums::CardNetwork::iter().collect(),
            card_discovery: enums::CardDiscovery::iter().collect(),
        },
    ))
}

#[cfg(feature = "olap")]
pub async fn get_aggregates_for_payments(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id_list: Option<Vec<id_type::ProfileId>>,
    time_range: common_utils::types::TimeRange,
) -> RouterResponse<api::PaymentsAggregateResponse> {
    let db = state.store.as_ref();
    let intent_status_with_count = db
        .get_intent_status_with_count(
            merchant_context.get_merchant_account().get_id(),
            profile_id_list,
            &time_range,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

    let mut status_map: HashMap<enums::IntentStatus, i64> =
        intent_status_with_count.into_iter().collect();
    for status in enums::IntentStatus::iter() {
        status_map.entry(status).or_default();
    }

    Ok(services::ApplicationResponse::Json(
        api::PaymentsAggregateResponse {
            status_with_count: status_map,
        },
    ))
}

#[cfg(feature = "v1")]
pub async fn add_process_sync_task(
    db: &dyn StorageInterface,
    payment_attempt: &storage::PaymentAttempt,
    schedule_time: time::PrimitiveDateTime,
) -> CustomResult<(), errors::StorageError> {
    let tracking_data = api::PaymentsRetrieveRequest {
        force_sync: true,
        merchant_id: Some(payment_attempt.merchant_id.clone()),
        resource_id: api::PaymentIdType::PaymentAttemptId(payment_attempt.get_id().to_owned()),
        ..Default::default()
    };
    let runner = storage::ProcessTrackerRunner::PaymentsSyncWorkflow;
    let task = "PAYMENTS_SYNC";
    let tag = ["SYNC", "PAYMENT"];
    let process_tracker_id = pt_utils::get_process_tracker_id(
        runner,
        task,
        payment_attempt.get_id(),
        &payment_attempt.merchant_id,
    );
    let process_tracker_entry = storage::ProcessTrackerNew::new(
        process_tracker_id,
        task,
        runner,
        tag,
        tracking_data,
        None,
        schedule_time,
        common_types::consts::API_VERSION,
    )
    .map_err(errors::StorageError::from)?;

    db.insert_process(process_tracker_entry).await?;
    Ok(())
}

#[cfg(feature = "v2")]
pub async fn reset_process_sync_task(
    db: &dyn StorageInterface,
    payment_attempt: &storage::PaymentAttempt,
    schedule_time: time::PrimitiveDateTime,
) -> Result<(), errors::ProcessTrackerError> {
    todo!()
}

#[cfg(feature = "v1")]
pub async fn reset_process_sync_task(
    db: &dyn StorageInterface,
    payment_attempt: &storage::PaymentAttempt,
    schedule_time: time::PrimitiveDateTime,
) -> Result<(), errors::ProcessTrackerError> {
    let runner = storage::ProcessTrackerRunner::PaymentsSyncWorkflow;
    let task = "PAYMENTS_SYNC";
    let process_tracker_id = pt_utils::get_process_tracker_id(
        runner,
        task,
        payment_attempt.get_id(),
        &payment_attempt.merchant_id,
    );
    let psync_process = db
        .find_process_by_id(&process_tracker_id)
        .await?
        .ok_or(errors::ProcessTrackerError::ProcessFetchingFailed)?;
    db.as_scheduler()
        .reset_process(psync_process, schedule_time)
        .await?;
    Ok(())
}

#[cfg(feature = "v1")]
pub fn update_straight_through_routing<F, D>(
    payment_data: &mut D,
    request_straight_through: serde_json::Value,
) -> CustomResult<(), errors::ParsingError>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    let _: api_models::routing::StaticRoutingAlgorithm = request_straight_through
        .clone()
        .parse_value("RoutingAlgorithm")
        .attach_printable("Invalid straight through routing rules format")?;

    payment_data.set_straight_through_algorithm_in_payment_attempt(request_straight_through);

    Ok(())
}

#[cfg(feature = "v1")]
pub fn is_pre_network_tokenization_enabled(
    state: &SessionState,
    business_profile: &domain::Profile,
    customer_acceptance: Option<Secret<serde_json::Value>>,
    connector_name: enums::Connector,
) -> bool {
    let ntid_supported_connectors = &state
        .conf
        .network_transaction_id_supported_connectors
        .connector_list;

    let is_nt_supported_connector = ntid_supported_connectors.contains(&connector_name);

    business_profile.is_network_tokenization_enabled
        && business_profile.is_pre_network_tokenization_enabled
        && customer_acceptance.is_some()
        && is_nt_supported_connector
}

#[cfg(feature = "v1")]
pub async fn get_vault_operation_for_pre_network_tokenization(
    state: &SessionState,
    customer_id: id_type::CustomerId,
    card_data: &hyperswitch_domain_models::payment_method_data::Card,
) -> payments::VaultOperation {
    let pre_tokenization_response =
        tokenization::pre_payment_tokenization(state, customer_id, card_data)
            .await
            .ok();
    match pre_tokenization_response {
        Some((Some(token_response), Some(token_ref))) => {
            let token_data = domain::NetworkTokenData::from(token_response);
            let network_token_data_for_vault = payments::NetworkTokenDataForVault {
                network_token_data: token_data.clone(),
                network_token_req_ref_id: token_ref,
            };

            payments::VaultOperation::SaveCardAndNetworkTokenData(Box::new(
                payments::CardAndNetworkTokenDataForVault {
                    card_data: card_data.clone(),
                    network_token: network_token_data_for_vault.clone(),
                },
            ))
        }
        Some((None, Some(token_ref))) => {
            payments::VaultOperation::SaveCardData(payments::CardDataForVault {
                card_data: card_data.clone(),
                network_token_req_ref_id: Some(token_ref),
            })
        }
        _ => payments::VaultOperation::SaveCardData(payments::CardDataForVault {
            card_data: card_data.clone(),
            network_token_req_ref_id: None,
        }),
    }
}

#[cfg(feature = "v1")]
#[allow(clippy::too_many_arguments)]
pub async fn get_connector_choice<F, Req, D>(
    operation: &BoxedOperation<'_, F, Req, D>,
    state: &SessionState,
    req: &Req,
    merchant_context: &domain::MerchantContext,
    business_profile: &domain::Profile,
    payment_data: &mut D,
    eligible_connectors: Option<Vec<enums::RoutableConnectors>>,
    mandate_type: Option<api::MandateTransactionType>,
) -> RouterResult<Option<ConnectorCallType>>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    let connector_choice = operation
        .to_domain()?
        .get_connector(
            merchant_context,
            &state.clone(),
            req,
            payment_data.get_payment_intent(),
        )
        .await?;

    let connector = if should_call_connector(operation, payment_data) {
        Some(match connector_choice {
            api::ConnectorChoice::SessionMultiple(connectors) => {
                let routing_output = perform_session_token_routing(
                    state.clone(),
                    merchant_context,
                    business_profile,
                    payment_data,
                    connectors,
                )
                .await?;
                ConnectorCallType::SessionMultiple(routing_output)
            }

            api::ConnectorChoice::StraightThrough(straight_through) => {
                connector_selection(
                    state,
                    merchant_context,
                    business_profile,
                    payment_data,
                    Some(straight_through),
                    eligible_connectors,
                    mandate_type,
                )
                .await?
            }

            api::ConnectorChoice::Decide => {
                connector_selection(
                    state,
                    merchant_context,
                    business_profile,
                    payment_data,
                    None,
                    eligible_connectors,
                    mandate_type,
                )
                .await?
            }
        })
    } else if let api::ConnectorChoice::StraightThrough(algorithm) = connector_choice {
        update_straight_through_routing(payment_data, algorithm)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to update straight through routing algorithm")?;

        None
    } else {
        None
    };
    Ok(connector)
}

async fn get_eligible_connector_for_nti<T: core_routing::GetRoutableConnectorsForChoice, F, D>(
    state: &SessionState,
    key_store: &domain::MerchantKeyStore,
    payment_data: &D,
    connector_choice: T,

    business_profile: &domain::Profile,
) -> RouterResult<(
    api_models::payments::MandateReferenceId,
    hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId,
    api::ConnectorData,
)>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    // Since this flow will only be used in the MIT flow, recurring details are mandatory.
    let recurring_payment_details = payment_data
        .get_recurring_details()
        .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)
        .attach_printable("Failed to fetch recurring details for mit")?;

    let (mandate_reference_id, card_details_for_network_transaction_id)= hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId::get_nti_and_card_details_for_mit_flow(recurring_payment_details.clone()).get_required_value("network transaction id and card details").attach_printable("Failed to fetch network transaction id and card details for mit")?;

    helpers::validate_card_expiry(
        &card_details_for_network_transaction_id.card_exp_month,
        &card_details_for_network_transaction_id.card_exp_year,
    )?;

    let network_transaction_id_supported_connectors = &state
        .conf
        .network_transaction_id_supported_connectors
        .connector_list
        .iter()
        .map(|value| value.to_string())
        .collect::<HashSet<_>>();

    let eligible_connector_data_list = connector_choice
        .get_routable_connectors(&*state.store, business_profile)
        .await?
        .filter_network_transaction_id_flow_supported_connectors(
            network_transaction_id_supported_connectors.to_owned(),
        )
        .construct_dsl_and_perform_eligibility_analysis(
            state,
            key_store,
            payment_data,
            business_profile.get_id(),
        )
        .await
        .attach_printable("Failed to fetch eligible connector data")?;

    let eligible_connector_data = eligible_connector_data_list
        .first()
        .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)
        .attach_printable(
            "No eligible connector found for the network transaction id based mit flow",
        )?;
    Ok((
        mandate_reference_id,
        card_details_for_network_transaction_id,
        eligible_connector_data.clone(),
    ))
}

pub async fn set_eligible_connector_for_nti_in_payment_data<F, D>(
    state: &SessionState,
    business_profile: &domain::Profile,
    key_store: &domain::MerchantKeyStore,
    payment_data: &mut D,
    connector_choice: api::ConnectorChoice,
) -> RouterResult<api::ConnectorData>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    let (mandate_reference_id, card_details_for_network_transaction_id, eligible_connector_data) =
        match connector_choice {
            api::ConnectorChoice::StraightThrough(straight_through) => {
                get_eligible_connector_for_nti(
                    state,
                    key_store,
                    payment_data,
                    core_routing::StraightThroughAlgorithmTypeSingle(straight_through),
                    business_profile,
                )
                .await?
            }
            api::ConnectorChoice::Decide => {
                get_eligible_connector_for_nti(
                    state,
                    key_store,
                    payment_data,
                    core_routing::DecideConnector,
                    business_profile,
                )
                .await?
            }
            api::ConnectorChoice::SessionMultiple(_) => {
                Err(errors::ApiErrorResponse::InternalServerError).attach_printable(
                    "Invalid routing rule configured for nti and card details based mit flow",
                )?
            }
        };

    // Set the eligible connector in the attempt
    payment_data
        .set_connector_in_payment_attempt(Some(eligible_connector_data.connector_name.to_string()));

    // Set `NetworkMandateId` as the MandateId
    payment_data.set_mandate_id(payments_api::MandateIds {
        mandate_id: None,
        mandate_reference_id: Some(mandate_reference_id),
    });

    // Set the card details received in the recurring details within the payment method data.
    payment_data.set_payment_method_data(Some(
        hyperswitch_domain_models::payment_method_data::PaymentMethodData::CardDetailsForNetworkTransactionId(card_details_for_network_transaction_id),
    ));

    Ok(eligible_connector_data)
}

#[cfg(feature = "v1")]
#[allow(clippy::too_many_arguments)]
pub async fn connector_selection<F, D>(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    business_profile: &domain::Profile,
    payment_data: &mut D,
    request_straight_through: Option<serde_json::Value>,
    eligible_connectors: Option<Vec<enums::RoutableConnectors>>,
    mandate_type: Option<api::MandateTransactionType>,
) -> RouterResult<ConnectorCallType>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    let request_straight_through: Option<api::routing::StraightThroughAlgorithm> =
        request_straight_through
            .map(|val| val.parse_value("RoutingAlgorithm"))
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Invalid straight through routing rules format")?;

    let mut routing_data = storage::RoutingData {
        routed_through: payment_data.get_payment_attempt().connector.clone(),

        merchant_connector_id: payment_data
            .get_payment_attempt()
            .merchant_connector_id
            .clone(),

        algorithm: request_straight_through.clone(),
        routing_info: payment_data
            .get_payment_attempt()
            .straight_through_algorithm
            .clone()
            .map(|val| val.parse_value("PaymentRoutingInfo"))
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Invalid straight through algorithm format found in payment attempt")?
            .unwrap_or(storage::PaymentRoutingInfo {
                algorithm: None,
                pre_routing_results: None,
            }),
    };

    let decided_connector = decide_connector(
        state.clone(),
        merchant_context,
        business_profile,
        payment_data,
        request_straight_through,
        &mut routing_data,
        eligible_connectors,
        mandate_type,
    )
    .await?;

    let encoded_info = routing_data
        .routing_info
        .encode_to_value()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("error serializing payment routing info to serde value")?;

    payment_data.set_connector_in_payment_attempt(routing_data.routed_through);

    payment_data.set_merchant_connector_id_in_attempt(routing_data.merchant_connector_id);
    payment_data.set_straight_through_algorithm_in_payment_attempt(encoded_info);

    Ok(decided_connector)
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
pub async fn connector_selection<F, D>(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    business_profile: &domain::Profile,
    payment_data: &mut D,
    mandate_type: Option<api::MandateTransactionType>,
) -> RouterResult<ConnectorCallType>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    let mut routing_data = storage::RoutingData {
        routed_through: payment_data.get_payment_attempt().connector.clone(),

        merchant_connector_id: payment_data
            .get_payment_attempt()
            .merchant_connector_id
            .clone(),
        pre_routing_connector_choice: payment_data.get_pre_routing_result().and_then(
            |pre_routing_results| {
                pre_routing_results
                    .get(&payment_data.get_payment_attempt().payment_method_subtype)
                    .cloned()
            },
        ),

        algorithm_requested: payment_data
            .get_payment_intent()
            .routing_algorithm_id
            .clone(),
    };

    let payment_dsl_input = core_routing::PaymentsDslInput::new(
        None,
        payment_data.get_payment_attempt(),
        payment_data.get_payment_intent(),
        payment_data.get_payment_method_data(),
        payment_data.get_address(),
        None,
        payment_data.get_currency(),
    );

    let decided_connector = decide_connector(
        state.clone(),
        merchant_context,
        business_profile,
        &mut routing_data,
        payment_dsl_input,
        mandate_type,
    )
    .await?;

    payment_data.set_connector_in_payment_attempt(routing_data.routed_through);

    payment_data.set_merchant_connector_id_in_attempt(routing_data.merchant_connector_id);

    Ok(decided_connector)
}

#[allow(clippy::too_many_arguments)]
#[cfg(feature = "v2")]
pub async fn decide_connector(
    state: SessionState,
    merchant_context: &domain::MerchantContext,
    business_profile: &domain::Profile,
    routing_data: &mut storage::RoutingData,
    payment_dsl_input: core_routing::PaymentsDslInput<'_>,
    mandate_type: Option<api::MandateTransactionType>,
) -> RouterResult<ConnectorCallType> {
    // If the connector was already decided previously, use the same connector
    // This is in case of flows like payments_sync, payments_cancel where the successive operations
    // with the connector have to be made using the same connector account.

    let predetermined_info_cloned = routing_data
        .routed_through
        .as_ref()
        .zip(routing_data.merchant_connector_id.as_ref())
        .map(|(cn_ref, mci_ref)| (cn_ref.clone(), mci_ref.clone()));

    match (
        predetermined_info_cloned,
        routing_data.pre_routing_connector_choice.as_ref(),
    ) {
        // Condition 1: Connector was already decided previously
        (Some((owned_connector_name, owned_merchant_connector_id)), _) => {
            api::ConnectorData::get_connector_by_name(
                &state.conf.connectors,
                &owned_connector_name,
                api::GetToken::Connector,
                Some(owned_merchant_connector_id.clone()),
            )
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Invalid connector name received in 'routed_through'")
            .map(|connector_data| {
                routing_data.routed_through = Some(owned_connector_name);
                ConnectorCallType::PreDetermined(connector_data.into())
            })
        }
        // Condition 2: Pre-routing connector choice
        (None, Some(routable_connector_choice)) => {
            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()
                }
            };

            routable_connector_list
                .first()
                .ok_or_else(|| {
                    report!(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)
                        .attach_printable("No first routable connector in pre_routing_connector_choice")
                })
                .and_then(|first_routable_connector| {
                    routing_data.routed_through = Some(first_routable_connector.connector.to_string());
                    routing_data
                        .merchant_connector_id
                        .clone_from(&first_routable_connector.merchant_connector_id);

                    let pre_routing_connector_data_list_result: RouterResult<Vec<api::ConnectorData>> = routable_connector_list
                        .iter()
                        .map(|connector_choice| {
                            api::ConnectorData::get_connector_by_name(
                                &state.conf.connectors,
                                &connector_choice.connector.to_string(),
                                api::GetToken::Connector,
                                connector_choice.merchant_connector_id.clone(),
                            )
                            .change_context(errors::ApiErrorResponse::InternalServerError)
                            .attach_printable("Invalid connector name received while processing pre_routing_connector_choice")
                        })
                        .collect::<Result<Vec<_>, _>>(); // Collects into RouterResult<Vec<ConnectorData>>

                    pre_routing_connector_data_list_result
                        .and_then(|list| {
                            list.first()
                                .cloned()
                                .ok_or_else(|| {
                                    report!(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)
                                        .attach_printable("Empty pre_routing_connector_data_list after mapping")
                                })
                                .map(|first_data| ConnectorCallType::PreDetermined(first_data.into()))
                        })
                })
        }
        (None, None) => {
            route_connector_v2_for_payments(
                &state,
                merchant_context,
                business_profile,
                payment_dsl_input,
                routing_data,
                mandate_type,
            )
            .await
        }
    }
}

#[allow(clippy::too_many_arguments)]
#[cfg(feature = "v1")]
pub async fn decide_connector<F, D>(
    state: SessionState,
    merchant_context: &domain::MerchantContext,
    business_profile: &domain::Profile,
    payment_data: &mut D,
    request_straight_through: Option<api::routing::StraightThroughAlgorithm>,
    routing_data: &mut storage::RoutingData,
    eligible_connectors: Option<Vec<enums::RoutableConnectors>>,
    mandate_type: Option<api::MandateTransactionType>,
) -> RouterResult<ConnectorCallType>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    // If the connector was already decided previously, use the same connector
    // This is in case of flows like payments_sync, payments_cancel where the successive operations
    // with the connector have to be made using the same connector account.
    if let Some(ref connector_name) = payment_data.get_payment_attempt().connector {
        // Connector was already decided previously, use the same connector
        let connector_data = api::ConnectorData::get_connector_by_name(
            &state.conf.connectors,
            connector_name,
            api::GetToken::Connector,
            payment_data
                .get_payment_attempt()
                .merchant_connector_id
                .clone(),
        )
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Invalid connector name received in 'routed_through'")?;

        routing_data.routed_through = Some(connector_name.clone());
        logger::debug!("euclid_routing: predetermined connector present in attempt");
        return Ok(ConnectorCallType::PreDetermined(connector_data.into()));
    }

    if let Some(mandate_connector_details) = payment_data.get_mandate_connector().as_ref() {
        let connector_data = api::ConnectorData::get_connector_by_name(
            &state.conf.connectors,
            &mandate_connector_details.connector,
            api::GetToken::Connector,
            mandate_connector_details.merchant_connector_id.clone(),
        )
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Invalid connector name received in 'routed_through'")?;

        routing_data.routed_through = Some(mandate_connector_details.connector.clone());

        routing_data
            .merchant_connector_id
            .clone_from(&mandate_connector_details.merchant_connector_id);

        logger::debug!("euclid_routing: predetermined mandate connector");
        return Ok(ConnectorCallType::PreDetermined(connector_data.into()));
    }

    if let Some((pre_routing_results, storage_pm_type)) =
        routing_data.routing_info.pre_routing_results.as_ref().zip(
            payment_data
                .get_payment_attempt()
                .payment_method_type
                .as_ref(),
        )
    {
        if let (Some(routable_connector_choice), None) = (
            pre_routing_results.get(storage_pm_type),
            &payment_data.get_token_data(),
        ) {
            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(first_routable_connector.connector.to_string());

            routing_data
                .merchant_connector_id
                .clone_from(&first_routable_connector.merchant_connector_id);

            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,
                    connector_choice.merchant_connector_id.clone(),
                )
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Invalid connector name received")?
                .into();

                pre_routing_connector_data_list.push(connector_data);
            }

            #[cfg(feature = "retry")]
            let should_do_retry = retry::config_should_call_gsm(
                &*state.store,
                merchant_context.get_merchant_account().get_id(),
                business_profile,
            )
            .await;

            #[cfg(feature = "retry")]
            if payment_data.get_payment_attempt().payment_method_type
                == Some(storage_enums::PaymentMethodType::ApplePay)
                && should_do_retry
            {
                let retryable_connector_data = helpers::get_apple_pay_retryable_connectors(
                    &state,
                    merchant_context,
                    payment_data,
                    &pre_routing_connector_data_list,
                    first_routable_connector
                        .merchant_connector_id
                        .clone()
                        .as_ref(),
                    business_profile.clone(),
                )
                .await?;

                if let Some(connector_data_list) = retryable_connector_data {
                    if connector_data_list.len() > 1 {
                        logger::info!("Constructed apple pay retryable connector list");
                        return Ok(ConnectorCallType::Retryable(connector_data_list));
                    }
                }
            }

            logger::debug!("euclid_routing: pre-routing connector present");

            let first_pre_routing_connector_data_list = pre_routing_connector_data_list
                .first()
                .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)?;

            helpers::override_setup_future_usage_to_on_session(&*state.store, payment_data).await?;

            return Ok(ConnectorCallType::PreDetermined(
                first_pre_routing_connector_data_list.clone(),
            ));
        }
    }

    if let Some(routing_algorithm) = request_straight_through {
        let (mut connectors, check_eligibility) = routing::perform_straight_through_routing(
            &routing_algorithm,
            payment_data.get_creds_identifier(),
        )
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed execution of straight through routing")?;

        payment_data.set_routing_approach_in_attempt(Some(
            common_enums::RoutingApproach::StraightThroughRouting,
        ));

        if check_eligibility {
            let transaction_data = core_routing::PaymentsDslInput::new(
                payment_data.get_setup_mandate(),
                payment_data.get_payment_attempt(),
                payment_data.get_payment_intent(),
                payment_data.get_payment_method_data(),
                payment_data.get_address(),
                payment_data.get_recurring_details(),
                payment_data.get_currency(),
            );

            connectors = routing::perform_eligibility_analysis_with_fallback(
                &state.clone(),
                merchant_context.get_merchant_key_store(),
                connectors,
                &TransactionData::Payment(transaction_data),
                eligible_connectors,
                business_profile,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)


impl api::PaymentSync for Nmi {}


impl api::PaymentAuthorize for Square {}

impl api::PaymentAuthorize for for Square


pub struct CardNetworkTokenizeRequest {
    /// Merchant ID associated with the tokenization request
    #[schema(example = "merchant_1671528864", value_type = String)]
    pub merchant_id: id_type::MerchantId,

    /// Details of the card or payment method to be tokenized
    #[serde(flatten)]
    pub data: TokenizeDataRequest,

    /// Customer details
    #[schema(value_type = CustomerDetails)]
    pub customer: payments::CustomerDetails,

    /// The billing details of the payment method
    #[schema(value_type = Option<Address>)]
    pub billing: Option<payments::Address>,

    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
    #[schema(value_type = Option<Object>, example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// The name of the bank/ provider issuing the payment method to the end user
    pub payment_method_issuer: Option<String>,
}


File: crates/euclid/src/frontend.rs

pub mod ast;
pub mod dir;
pub mod vir;


File: crates/api_models/src/events/payment.rs

use common_utils::events::{ApiEventMetric, ApiEventsType};

#[cfg(feature = "v2")]
use super::{
    PaymentAttemptListRequest, PaymentAttemptListResponse, PaymentStartRedirectionRequest,
    PaymentsCreateIntentRequest, PaymentsGetIntentRequest, PaymentsIntentResponse, PaymentsRequest,
    RecoveryPaymentsCreate, RecoveryPaymentsResponse,
};
#[cfg(feature = "v2")]
use crate::payment_methods::{
    ListMethodsForPaymentMethodsRequest, PaymentMethodListResponseForSession,
};
use crate::{
    payment_methods::{
        self, ListCountriesCurrenciesRequest, ListCountriesCurrenciesResponse,
        PaymentMethodCollectLinkRenderRequest, PaymentMethodCollectLinkRequest,
        PaymentMethodCollectLinkResponse, PaymentMethodMigrateResponse, PaymentMethodResponse,
        PaymentMethodUpdate,
    },
    payments::{
        self, PaymentListConstraints, PaymentListFilters, PaymentListFiltersV2,
        PaymentListResponse, PaymentsAggregateResponse, PaymentsSessionResponse,
        RedirectionResponse,
    },
};
#[cfg(feature = "v1")]
use crate::{
    payment_methods::{PaymentMethodListRequest, PaymentMethodListResponse},
    payments::{
        ExtendedCardInfoResponse, PaymentIdType, PaymentListFilterConstraints,
        PaymentListResponseV2, PaymentsApproveRequest, PaymentsCancelPostCaptureRequest,
        PaymentsCancelRequest, PaymentsCaptureRequest, PaymentsCompleteAuthorizeRequest,
        PaymentsDynamicTaxCalculationRequest, PaymentsDynamicTaxCalculationResponse,
        PaymentsExternalAuthenticationRequest, PaymentsExternalAuthenticationResponse,
        PaymentsIncrementalAuthorizationRequest, PaymentsManualUpdateRequest,
        PaymentsManualUpdateResponse, PaymentsPostSessionTokensRequest,
        PaymentsPostSessionTokensResponse, PaymentsRejectRequest, PaymentsRetrieveRequest,
        PaymentsStartRequest, PaymentsUpdateMetadataRequest, PaymentsUpdateMetadataResponse,
    },
};

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsRetrieveRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        match self.resource_id {
            PaymentIdType::PaymentIntentId(ref id) => Some(ApiEventsType::Payment {
                payment_id: id.clone(),
            }),
            _ => None,
        }
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsStartRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsCaptureRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.to_owned(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsCompleteAuthorizeRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsDynamicTaxCalculationRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsPostSessionTokensRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsUpdateMetadataRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsUpdateMetadataResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsPostSessionTokensResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsDynamicTaxCalculationResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsCancelRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsCancelPostCaptureRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsApproveRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsRejectRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for payments::PaymentsRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        match self.payment_id {
            Some(PaymentIdType::PaymentIntentId(ref id)) => Some(ApiEventsType::Payment {
                payment_id: id.clone(),
            }),
            _ => None,
        }
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentsCreateIntentRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentsRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentsGetIntentRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentAttemptListRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_intent_id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentAttemptListResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentsIntentResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for payments::PaymentsResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for payments::PaymentsResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

impl ApiEventMetric for PaymentMethodResponse {
    #[cfg(feature = "v1")]
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.payment_method_id.clone(),
            payment_method: self.payment_method,
            payment_method_type: self.payment_method_type,
        })
    }

    #[cfg(feature = "v2")]
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.id.clone(),
            payment_method_type: self.payment_method_type,
            payment_method_subtype: self.payment_method_subtype,
        })
    }
}

impl ApiEventMetric for PaymentMethodMigrateResponse {
    #[cfg(feature = "v1")]
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.payment_method_response.payment_method_id.clone(),
            payment_method: self.payment_method_response.payment_method,
            payment_method_type: self.payment_method_response.payment_method_type,
        })
    }

    #[cfg(feature = "v2")]
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.payment_method_response.id.clone(),
            payment_method_type: self.payment_method_response.payment_method_type,
            payment_method_subtype: self.payment_method_response.payment_method_subtype,
        })
    }
}

impl ApiEventMetric for PaymentMethodUpdate {}

#[cfg(feature = "v1")]
impl ApiEventMetric for payment_methods::DefaultPaymentMethod {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.payment_method_id.clone(),
            payment_method: None,
            payment_method_type: None,
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for payment_methods::PaymentMethodDeleteResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.id.clone(),
            payment_method_type: None,
            payment_method_subtype: None,
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for payment_methods::PaymentMethodDeleteResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.payment_method_id.clone(),
            payment_method: None,
            payment_method_type: None,
        })
    }
}

impl ApiEventMetric for payment_methods::CustomerPaymentMethodsListResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentMethodListRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethodList {
            payment_id: self
                .client_secret
                .as_ref()
                .and_then(|cs| cs.rsplit_once("_secret_"))
                .map(|(pid, _)| pid.to_string()),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for ListMethodsForPaymentMethodsRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethodList {
            payment_id: self
                .client_secret
                .as_ref()
                .and_then(|cs| cs.rsplit_once("_secret_"))
                .map(|(pid, _)| pid.to_string()),
        })
    }
}

impl ApiEventMetric for ListCountriesCurrenciesRequest {}

impl ApiEventMetric for ListCountriesCurrenciesResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentMethodListResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for payment_methods::CustomerDefaultPaymentMethodResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethod {
            payment_method_id: self.default_payment_method_id.clone().unwrap_or_default(),
            payment_method: Some(self.payment_method),
            payment_method_type: self.payment_method_type,
        })
    }
}

impl ApiEventMetric for PaymentMethodCollectLinkRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        self.pm_collect_link_id
            .as_ref()
            .map(|id| ApiEventsType::PaymentMethodCollectLink {
                link_id: id.clone(),
            })
    }
}

impl ApiEventMetric for PaymentMethodCollectLinkRenderRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethodCollectLink {
            link_id: self.pm_collect_link_id.clone(),
        })
    }
}

impl ApiEventMetric for PaymentMethodCollectLinkResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::PaymentMethodCollectLink {
            link_id: self.pm_collect_link_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentListFilterConstraints {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}

impl ApiEventMetric for PaymentListFilters {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}
impl ApiEventMetric for PaymentListFiltersV2 {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}

impl ApiEventMetric for PaymentListConstraints {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}

impl ApiEventMetric for PaymentListResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for RecoveryPaymentsCreate {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for RecoveryPaymentsResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentListResponseV2 {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}
impl ApiEventMetric for PaymentsAggregateResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::ResourceListAPI)
    }
}

impl ApiEventMetric for RedirectionResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsIncrementalAuthorizationRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsExternalAuthenticationResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsExternalAuthenticationRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for ExtendedCardInfoResponse {}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsManualUpdateRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentsManualUpdateResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

impl ApiEventMetric for PaymentsSessionResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.payment_id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentStartRedirectionRequest {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
impl ApiEventMetric for payments::PaymentMethodListResponseForPayments {
    // Payment id would be populated by the request
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        None
    }
}
#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentMethodListResponseForSession {}

#[cfg(feature = "v2")]
impl ApiEventMetric for payments::PaymentsCaptureResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Payment {
            payment_id: self.id.clone(),
        })
    }
}


OpenAPI Block Path: components.schemas.BankDebitAdditionalData
{
  "oneOf": [
    {
      "type": "object",
      "required": [
        "ach"
      ],
      "properties": {
        "ach": {
          "$ref": "#/components/schemas/AchBankDebitAdditionalData"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "bacs"
      ],
      "properties": {
        "bacs": {
          "$ref": "#/components/schemas/BacsBankDebitAdditionalData"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "becs"
      ],
      "properties": {
        "becs": {
          "$ref": "#/components/schemas/BecsBankDebitAdditionalData"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "sepa"
      ],
      "properties": {
        "sepa": {
          "$ref": "#/components/schemas/SepaBankDebitAdditionalData"
        }
      }
    }
  ]
}


impl OpenSearchClient {
    pub async fn create(conf: &OpenSearchConfig) -> CustomResult<Self, OpenSearchError> {
        let url = Url::parse(&conf.host).map_err(|_| OpenSearchError::ConnectionError)?;
        let transport = match &conf.auth {
            OpenSearchAuth::Basic { username, password } => {
                let credentials = Credentials::Basic(username.clone(), password.clone());
                TransportBuilder::new(SingleNodeConnectionPool::new(url))
                    .cert_validation(CertificateValidation::None)
                    .auth(credentials)
                    .build()
                    .map_err(|_| OpenSearchError::ConnectionError)?
            }
            OpenSearchAuth::Aws { region } => {
                let region_provider = RegionProviderChain::first_try(Region::new(region.clone()));
                let sdk_config = aws_config::from_env().region(region_provider).load().await;
                let conn_pool = SingleNodeConnectionPool::new(url);
                TransportBuilder::new(conn_pool)
                    .auth(
                        sdk_config
                            .clone()
                            .try_into()
                            .map_err(|_| OpenSearchError::ConnectionError)?,
                    )
                    .service_name("es")
                    .build()
                    .map_err(|_| OpenSearchError::ConnectionError)?
            }
        };
        Ok(Self {
            transport: transport.clone(),
            client: OpenSearch::new(transport),
            indexes: conf.indexes.clone(),
        })
    }

    pub fn search_index_to_opensearch_index(&self, index: SearchIndex) -> String {
        match index {
            SearchIndex::PaymentAttempts => self.indexes.payment_attempts.clone(),
            SearchIndex::PaymentIntents => self.indexes.payment_intents.clone(),
            SearchIndex::Refunds => self.indexes.refunds.clone(),
            SearchIndex::Disputes => self.indexes.disputes.clone(),
            SearchIndex::SessionizerPaymentAttempts => {
                self.indexes.sessionizer_payment_attempts.clone()
            }
            SearchIndex::SessionizerPaymentIntents => {
                self.indexes.sessionizer_payment_intents.clone()
            }
            SearchIndex::SessionizerRefunds => self.indexes.sessionizer_refunds.clone(),
            SearchIndex::SessionizerDisputes => self.indexes.sessionizer_disputes.clone(),
        }
    }

    pub async fn execute(
        &self,
        query_builder: OpenSearchQueryBuilder,
    ) -> CustomResult<Response, OpenSearchError> {
        match query_builder.query_type {
            OpenSearchQuery::Msearch(ref indexes) => {
                let payload = query_builder
                    .construct_payload(indexes)
                    .change_context(OpenSearchError::QueryBuildingError)?;

                let payload_with_indexes = payload.into_iter().zip(indexes).fold(
                    Vec::new(),
                    |mut payload_with_indexes, (index_hit, index)| {
                        payload_with_indexes.push(
                            json!({"index": self.search_index_to_opensearch_index(*index)}).into(),
                        );
                        payload_with_indexes.push(JsonBody::new(index_hit.clone()));
                        payload_with_indexes
                    },
                );

                self.client
                    .msearch(MsearchParts::None)
                    .body(payload_with_indexes)
                    .send()
                    .await
                    .change_context(OpenSearchError::ResponseError)
            }
            OpenSearchQuery::Search(index) => {
                let payload = query_builder
                    .clone()
                    .construct_payload(&[index])
                    .change_context(OpenSearchError::QueryBuildingError)?;

                let final_payload = payload.first().unwrap_or(&Value::Null);

                self.client
                    .search(SearchParts::Index(&[
                        &self.search_index_to_opensearch_index(index)
                    ]))
                    .from(query_builder.offset.unwrap_or(0))
                    .size(query_builder.count.unwrap_or(10))
                    .body(final_payload)
                    .send()
                    .await
                    .change_context(OpenSearchError::ResponseError)
            }
        }
    }
}


OpenAPI Block Path: components.schemas.SamsungPayWalletCredentials
{
  "oneOf": [
    {
      "$ref": "#/components/schemas/SamsungPayWebWalletData"
    },
    {
      "$ref": "#/components/schemas/SamsungPayAppWalletData"
    }
  ]
}


pub struct WebhookPaymentEntity {
//     pub id: String,
//     pub status: RazorpayWebhookPaymentStatus,
// }


impl api::PaymentVoid for Paystack {}


File: crates/analytics/src/payment_intents/metrics/sessionized_metrics/smart_retried_amount.rs

use std::collections::HashSet;

use api_models::{
    analytics::{
        payment_intents::{
            PaymentIntentDimensions, PaymentIntentFilters, PaymentIntentMetricsBucketIdentifier,
        },
        Granularity, TimeRange,
    },
    enums::IntentStatus,
};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

use super::PaymentIntentMetricRow;
use crate::{
    enums::AuthInfo,
    query::{
        Aggregate, FilterTypes, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql,
        Window,
    },
    types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
};

#[derive(Default)]
pub(crate) struct SmartRetriedAmount;

#[async_trait::async_trait]
impl<T> super::PaymentIntentMetric<T> for SmartRetriedAmount
where
    T: AnalyticsDataSource + super::PaymentIntentMetricAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_metrics(
        &self,
        dimensions: &[PaymentIntentDimensions],
        auth: &AuthInfo,
        filters: &PaymentIntentFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>
    {
        let mut query_builder: QueryBuilder<T> =
            QueryBuilder::new(AnalyticsCollection::PaymentIntentSessionized);

        for dim in dimensions.iter() {
            query_builder.add_select_column(dim).switch()?;
        }
        query_builder
            .add_select_column(Aggregate::Sum {
                field: "amount",
                alias: Some("total"),
            })
            .switch()?;

        query_builder
            .add_select_column("(attempt_count = 1) as first_attempt")
            .switch()?;

        query_builder.add_select_column("currency").switch()?;
        query_builder
            .add_select_column(Aggregate::Min {
                field: "created_at",
                alias: Some("start_bucket"),
            })
            .switch()?;
        query_builder
            .add_select_column(Aggregate::Max {
                field: "created_at",
                alias: Some("end_bucket"),
            })
            .switch()?;

        filters.set_filter_clause(&mut query_builder).switch()?;

        auth.set_filter_clause(&mut query_builder).switch()?;

        query_builder
            .add_custom_filter_clause("attempt_count", "1", FilterTypes::Gt)
            .switch()?;
        query_builder
            .add_custom_filter_clause("status", IntentStatus::Succeeded, FilterTypes::Equal)
            .switch()?;
        time_range
            .set_filter_clause(&mut query_builder)
            .attach_printable("Error filtering time range")
            .switch()?;

        for dim in dimensions.iter() {
            query_builder
                .add_group_by_clause(dim)
                .attach_printable("Error grouping by dimensions")
                .switch()?;
        }

        query_builder
            .add_group_by_clause("first_attempt")
            .attach_printable("Error grouping by first_attempt")
            .switch()?;
        query_builder
            .add_group_by_clause("currency")
            .attach_printable("Error grouping by currency")
            .switch()?;
        if let Some(granularity) = granularity {
            granularity
                .set_group_by_clause(&mut query_builder)
                .attach_printable("Error adding granularity")
                .switch()?;
        }

        query_builder
            .execute_query::<PaymentIntentMetricRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| {
                Ok((
                    PaymentIntentMetricsBucketIdentifier::new(
                        i.status.as_ref().map(|i| i.0),
                        i.currency.as_ref().map(|i| i.0),
                        i.profile_id.clone(),
                        i.connector.clone(),
                        i.authentication_type.as_ref().map(|i| i.0),
                        i.payment_method.clone(),
                        i.payment_method_type.clone(),
                        i.card_network.clone(),
                        i.merchant_id.clone(),
                        i.card_last_4.clone(),
                        i.card_issuer.clone(),
                        i.error_reason.clone(),
                        TimeRange {
                            start_time: match (granularity, i.start_bucket) {
                                (Some(g), Some(st)) => g.clip_to_start(st)?,
                                _ => time_range.start_time,
                            },
                            end_time: granularity.as_ref().map_or_else(
                                || Ok(time_range.end_time),
                                |g| i.end_bucket.map(|et| g.clip_to_end(et)).transpose(),
                            )?,
                        },
                    ),
                    i,
                ))
            })
            .collect::<error_stack::Result<
                HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
                crate::query::PostProcessingError,
            >>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


OpenAPI Block Path: components.schemas.SplitPaymentsRequest
{
  "oneOf": [
    {
      "type": "object",
      "required": [
        "stripe_split_payment"
      ],
      "properties": {
        "stripe_split_payment": {
          "$ref": "#/components/schemas/StripeSplitPaymentRequest"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "adyen_split_payment"
      ],
      "properties": {
        "adyen_split_payment": {
          "$ref": "#/components/schemas/AdyenSplitData"
        }
      }
    },
    {
      "type": "object",
      "required": [
        "xendit_split_payment"
      ],
      "properties": {
        "xendit_split_payment": {
          "$ref": "#/components/schemas/XenditSplitRequest"
        }
      }
    }
  ],
  "description": "Fee information for Split Payments to be charged on the payment being collected"
}


impl api::PaymentToken for Datatrans {}

impl api::PaymentToken for for Datatrans


pub struct AcsProtocolVersion {
    pub version: common_utils::types::SemanticVersion,
    pub acs_info_ind: Vec<String>,
    pub three_ds_method_url: Option<String>,
    pub supported_msg_ext: Option<Vec<SupportedMsgExt>>,
}


impl api::RefundExecute for Fiuu {}


File: crates/analytics/src/active_payments/metrics/active_payments.rs

use std::collections::HashSet;

use api_models::analytics::{
    active_payments::ActivePaymentsMetricsBucketIdentifier, Granularity, TimeRange,
};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

use super::ActivePaymentsMetricRow;
use crate::{
    query::{Aggregate, FilterTypes, GroupByClause, QueryBuilder, QueryFilter, ToSql, Window},
    types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
};

#[derive(Default)]
pub(super) struct ActivePayments;

#[async_trait::async_trait]
impl<T> super::ActivePaymentsMetric<T> for ActivePayments
where
    T: AnalyticsDataSource + super::ActivePaymentsMetricAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_metrics(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        publishable_key: &str,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<
        HashSet<(
            ActivePaymentsMetricsBucketIdentifier,
            ActivePaymentsMetricRow,
        )>,
    > {
        let mut query_builder: QueryBuilder<T> =
            QueryBuilder::new(AnalyticsCollection::ActivePaymentsAnalytics);

        query_builder
            .add_select_column(Aggregate::DistinctCount {
                field: "payment_id",
                alias: Some("count"),
            })
            .switch()?;

        query_builder
            .add_custom_filter_clause(
                "merchant_id",
                format!("'{}','{}'", merchant_id.get_string_repr(), publishable_key),
                FilterTypes::In,
            )
            .switch()?;

        query_builder
            .add_negative_filter_clause("payment_id", "")
            .switch()?;

        query_builder
            .add_custom_filter_clause(
                "flow_type",
                "'sdk', 'payment', 'payment_redirection_response'",
                FilterTypes::In,
            )
            .switch()?;

        time_range
            .set_filter_clause(&mut query_builder)
            .attach_printable("Error filtering time range")
            .switch()?;

        query_builder
            .execute_query::<ActivePaymentsMetricRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| Ok((ActivePaymentsMetricsBucketIdentifier::new(None), i)))
            .collect::<error_stack::Result<
                HashSet<(
                    ActivePaymentsMetricsBucketIdentifier,
                    ActivePaymentsMetricRow,
                )>,
                crate::query::PostProcessingError,
            >>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


impl PaymentMethodSession {
    pub fn server(state: AppState) -> Scope {
        let mut route = web::scope("/v2/payment-method-sessions").app_data(web::Data::new(state));
        route = route.service(
            web::resource("")
                .route(web::post().to(payment_methods::payment_methods_session_create)),
        );

        route =
            route.service(
                web::scope("/{payment_method_session_id}")
                    .service(
                        web::resource("")
                            .route(web::get().to(payment_methods::payment_methods_session_retrieve))
                            .route(web::put().to(payment_methods::payment_methods_session_update))
                            .route(web::delete().to(
                                payment_methods::payment_method_session_delete_saved_payment_method,
                            )),
                    )
                    .service(web::resource("/list-payment-methods").route(
                        web::get().to(payment_methods::payment_method_session_list_payment_methods),
                    ))
                    .service(
                        web::resource("/confirm")
                            .route(web::post().to(payment_methods::payment_method_session_confirm)),
                    )
                    .service(web::resource("/update-saved-payment-method").route(
                        web::put().to(
                            payment_methods::payment_method_session_update_saved_payment_method,
                        ),
                    )),
            );

        route
    }
}


impl api::PaymentSession for Thunes {}


pub struct BackendOutput<O> {
    pub rule_name: Option<String>,
    pub connector_selection: O,
}


pub struct NovalnetAuthorizationResponse {
    expiry_date: Option<String>,
    auto_action: Option<String>,
}


pub struct PaystackAuthType {
    pub(super) api_key: Secret<String>,
}


pub fn comparison(input: &str) -> ParseResult<&str, ast::Comparison> {
    error::context(
        "condition",
        combinator::map(
            sequence::tuple((
                skip_ws(complete::take_while1(|c: char| {
                    c.is_ascii_alphabetic() || c == '.' || c == '_'
                })),
                skip_ws(comparison_type),
                skip_ws(value_type),
            )),
            |tup: (&str, ast::ComparisonType, ast::ValueType)| ast::Comparison {
                lhs: tup.0.to_string(),
                comparison: tup.1,
                value: tup.2,
                metadata: std::collections::HashMap::new(),
            },
        ),
    )(input)
}


impl ValidateStatusForOperation for PaymentsCapture {
    /// Validate if the current operation can be performed on the current status of the payment intent
    fn validate_status_for_operation(
        &self,
        intent_status: common_enums::IntentStatus,
    ) -> Result<(), errors::ApiErrorResponse> {
        match intent_status {
            common_enums::IntentStatus::RequiresCapture
            | common_enums::IntentStatus::PartiallyAuthorizedAndRequiresCapture
            | common_enums::IntentStatus::PartiallyCapturedAndCapturable => Ok(()),
            common_enums::IntentStatus::Succeeded
            | common_enums::IntentStatus::Conflicted
            | common_enums::IntentStatus::Failed
            | common_enums::IntentStatus::Cancelled
            | common_enums::IntentStatus::CancelledPostCapture
            | common_enums::IntentStatus::Processing
            | common_enums::IntentStatus::RequiresCustomerAction
            | common_enums::IntentStatus::RequiresMerchantAction
            | common_enums::IntentStatus::RequiresPaymentMethod
            | common_enums::IntentStatus::PartiallyCaptured
            | common_enums::IntentStatus::RequiresConfirmation
            | common_enums::IntentStatus::Expired => {
                Err(errors::ApiErrorResponse::PaymentUnexpectedState {
                    current_flow: format!("{self:?}"),
                    field_name: "status".to_string(),
                    current_value: intent_status.to_string(),
                    states: [
                        common_enums::IntentStatus::RequiresCapture,
                        common_enums::IntentStatus::PartiallyCapturedAndCapturable,
                    ]
                    .map(|enum_value| enum_value.to_string())
                    .join(", "),
                })
            }
        }
    }
}

impl ValidateStatusForOperation for for PaymentsCapture


pub struct PaymentMethodUpdateMems {
    pub orig: PaymentMethod,
    pub update_data: PaymentMethodUpdateInternal,
}


File: crates/router/tests/connectors/cashtocode.rs

use common_utils::id_type;
use hyperswitch_domain_models::address::{Address, AddressDetails};
use router::types::{self, domain, storage::enums};

use crate::{
    connector_auth,
    utils::{self, ConnectorActions},
};

#[derive(Clone, Copy)]
struct CashtocodeTest;
impl ConnectorActions for CashtocodeTest {}
impl utils::Connector for CashtocodeTest {
    fn get_data(&self) -> types::api::ConnectorData {
        use router::connector::Cashtocode;
        utils::construct_connector_data_old(
            Box::new(Cashtocode::new()),
            types::Connector::Cashtocode,
            types::api::GetToken::Connector,
            None,
        )
    }

    fn get_auth_token(&self) -> types::ConnectorAuthType {
        utils::to_connector_auth_type(
            connector_auth::ConnectorAuthentication::new()
                .cashtocode
                .expect("Missing connector authentication configuration")
                .into(),
        )
    }

    fn get_name(&self) -> String {
        "cashtocode".to_string()
    }
}

static CONNECTOR: CashtocodeTest = CashtocodeTest {};

impl CashtocodeTest {
    fn get_payment_authorize_data(
        payment_method_type: Option<enums::PaymentMethodType>,
        payment_method_data: domain::PaymentMethodData,
    ) -> Option<types::PaymentsAuthorizeData> {
        let cust_id = id_type::CustomerId::try_from(std::borrow::Cow::from("John Doe"));
        Some(types::PaymentsAuthorizeData {
            amount: 1000,
            currency: enums::Currency::EUR,
            payment_method_data,
            confirm: true,
            statement_descriptor_suffix: None,
            statement_descriptor: None,
            setup_future_usage: None,
            mandate_id: None,
            off_session: None,
            setup_mandate_details: None,
            capture_method: None,
            browser_info: None,
            order_details: None,
            order_category: None,
            email: None,
            customer_name: None,
            payment_experience: None,
            payment_method_type,
            session_token: None,
            enrolled_for_3ds: false,
            related_transaction_id: None,
            router_return_url: Some(String::from("https://google.com")),
            webhook_url: None,
            complete_authorize_url: None,
            customer_id: cust_id.ok(),
            surcharge_details: None,
            request_incremental_authorization: false,
            metadata: None,
            authentication_data: None,
            customer_acceptance: None,
            ..utils::PaymentAuthorizeType::default().0
        })
    }

    fn get_payment_info() -> Option<utils::PaymentInfo> {
        Some(utils::PaymentInfo {
            address: Some(types::PaymentAddress::new(
                None,
                Some(Address {
                    address: Some(AddressDetails {
                        country: Some(api_models::enums::CountryAlpha2::US),
                        ..Default::default()
                    }),
                    phone: None,
                    email: None,
                }),
                None,
                None,
            )),
            ..Default::default()
        })
    }
}

//fetch payurl for payment create
#[actix_web::test]
async fn should_fetch_pay_url_classic() {
    let authorize_response = CONNECTOR
        .make_payment(
            CashtocodeTest::get_payment_authorize_data(
                Some(enums::PaymentMethodType::ClassicReward),
                domain::payments::PaymentMethodData::Reward,
            ),
            CashtocodeTest::get_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        authorize_response.status,
        enums::AttemptStatus::AuthenticationPending
    );
}

#[actix_web::test]
async fn should_fetch_pay_url_evoucher() {
    let authorize_response = CONNECTOR
        .make_payment(
            CashtocodeTest::get_payment_authorize_data(
                Some(enums::PaymentMethodType::Evoucher),
                domain::payments::PaymentMethodData::Reward,
            ),
            CashtocodeTest::get_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        authorize_response.status,
        enums::AttemptStatus::AuthenticationPending
    );
}


pub struct CustomerBody {
    email: pii::Email,
}


pub async fn fetch_dynamic_routing_configs<T>(
    state: &SessionState,
    profile_id: &id_type::ProfileId,
    routing_id: id_type::RoutingId,
) -> RouterResult<T>
where
    T: serde::de::DeserializeOwned
        + Clone
        + DynamicRoutingCache
        + Cacheable
        + serde::Serialize
        + Debug,
{
    let key = format!(
        "{}_{}",
        profile_id.get_string_repr(),
        routing_id.get_string_repr()
    );

    if let Some(config) =
        T::get_cached_dynamic_routing_config_for_profile(state, key.as_str()).await
    {
        Ok(config.as_ref().clone())
    } else {
        let func = || async {
            let routing_algorithm = state
                .store
                .find_routing_algorithm_by_profile_id_algorithm_id(profile_id, &routing_id)
                .await
                .change_context(errors::StorageError::ValueNotFound(
                    "RoutingAlgorithm".to_string(),
                ))
                .attach_printable("unable to retrieve routing_algorithm for profile from db")?;

            let dynamic_routing_config = routing_algorithm
                .algorithm_data
                .parse_value::<T>("dynamic_routing_config")
                .change_context(errors::StorageError::DeserializationFailed)
                .attach_printable("unable to parse dynamic_routing_config")?;

            Ok(dynamic_routing_config)
        };

        let dynamic_routing_config =
            T::refresh_dynamic_routing_cache(state, key.as_str(), func).await?;

        Ok(dynamic_routing_config)
    }
}


impl api::PaymentToken for Globepay {}


pub trait PaymentMethodsStorageInterface:
    Send
    + Sync
    + dyn_clone::DynClone
    + pm_domain::PaymentMethodInterface<Error = errors::StorageError>
    + cards_info::CardsInfoInterface<Error = errors::StorageError>
    + customer::CustomerInterface<Error = errors::StorageError>
    + 'static
{
}


pub struct PaymentProcessorTokenWithRetryInfo {
    /// The complete token status information
    pub token_status: PaymentProcessorTokenStatus,
    /// Hours to wait before next retry attempt (max of daily/monthly wait)
    pub retry_wait_time_hours: i64,
    /// Number of retries remaining in the 30-day rolling window
    pub monthly_retry_remaining: i32,
}


pub fn new() -> &'static Self {
        &Self {
            amount_converter: &MinorUnitForConnector,
        }
    }


pub struct DynamicData {
    pub dynamic_data_value: Option<Secret<String>>,
    pub dynamic_data_type: Option<String>,
    pub ds_trans_id: Option<String>,
}


pub struct PreAuthenticationVersionCall;


File: crates/router/src/types/api.rs
 Public functions: 6
 Public structs: 2

pub mod admin;
pub mod api_keys;
pub mod authentication;
pub mod configs;
#[cfg(feature = "olap")]
pub mod connector_onboarding;
pub mod customers;
pub mod disputes;
pub mod enums;
pub mod ephemeral_key;
pub mod files;
#[cfg(feature = "frm")]
pub mod fraud_check;
pub mod mandates;
pub mod payment_link;
pub mod payment_methods;
pub mod payments;
#[cfg(feature = "payouts")]
pub mod payouts;
pub mod poll;
pub mod refunds;
pub mod routing;
#[cfg(feature = "olap")]
pub mod verify_connector;
#[cfg(feature = "olap")]
pub mod webhook_events;
pub mod webhooks;

pub mod authentication_v2;
pub mod connector_mapping;
pub mod disputes_v2;
pub mod feature_matrix;
pub mod files_v2;
#[cfg(feature = "frm")]
pub mod fraud_check_v2;
pub mod payments_v2;
#[cfg(feature = "payouts")]
pub mod payouts_v2;
pub mod refunds_v2;

use std::{fmt::Debug, str::FromStr};

use api_models::routing::{self as api_routing, RoutableConnectorChoice};
use common_enums::RoutableConnectors;
use error_stack::ResultExt;
pub use hyperswitch_domain_models::router_flow_types::{
    access_token_auth::{AccessTokenAuth, AccessTokenAuthentication},
    mandate_revoke::MandateRevoke,
    webhooks::VerifyWebhookSource,
};
pub use hyperswitch_interfaces::{
    api::{
        authentication::{
            ConnectorAuthentication, ConnectorPostAuthentication, ConnectorPreAuthentication,
            ConnectorPreAuthenticationVersionCall, ExternalAuthentication,
        },
        authentication_v2::{
            ConnectorAuthenticationV2, ConnectorPostAuthenticationV2, ConnectorPreAuthenticationV2,
            ConnectorPreAuthenticationVersionCallV2, ExternalAuthenticationV2,
        },
        fraud_check::FraudCheck,
        revenue_recovery::{
            BillingConnectorInvoiceSyncIntegration, BillingConnectorPaymentsSyncIntegration,
            RevenueRecovery, RevenueRecoveryRecordBack,
        },
        revenue_recovery_v2::RevenueRecoveryV2,
        BoxedConnector, Connector, ConnectorAccessToken, ConnectorAccessTokenV2,
        ConnectorAuthenticationToken, ConnectorAuthenticationTokenV2, ConnectorCommon,
        ConnectorCommonExt, ConnectorMandateRevoke, ConnectorMandateRevokeV2,
        ConnectorTransactionId, ConnectorVerifyWebhookSource, ConnectorVerifyWebhookSourceV2,
        CurrencyUnit,
    },
    connector_integration_v2::{BoxedConnectorV2, ConnectorV2},
};
use rustc_hash::FxHashMap;

#[cfg(feature = "frm")]
pub use self::fraud_check::*;
#[cfg(feature = "payouts")]
pub use self::payouts::*;
pub use self::{
    admin::*, api_keys::*, authentication::*, configs::*, connector_mapping::*, customers::*,
    disputes::*, files::*, payment_link::*, payment_methods::*, payments::*, poll::*, refunds::*,
    refunds_v2::*, webhooks::*,
};
use super::transformers::ForeignTryFrom;
use crate::{
    connector, consts,
    core::{
        errors::{self, CustomResult},
        payments::types as payments_types,
    },
    services::connector_integration_interface::ConnectorEnum,
    types::{self, api::enums as api_enums},
};
#[derive(Clone)]
pub enum ConnectorCallType {
    PreDetermined(ConnectorRoutingData),
    Retryable(Vec<ConnectorRoutingData>),
    SessionMultiple(SessionConnectorDatas),
    #[cfg(feature = "v2")]
    Skip,
}

impl From<ConnectorData> for ConnectorRoutingData {
    fn from(connector_data: ConnectorData) -> Self {
        Self {
            connector_data,
            network: None,
        }
    }
}

#[derive(Clone, Debug)]
pub struct SessionConnectorData {
    pub payment_method_sub_type: api_enums::PaymentMethodType,
    pub payment_method_type: api_enums::PaymentMethod,
    pub connector: ConnectorData,
    pub business_sub_label: Option<String>,
}

impl SessionConnectorData {
    pub fn new(
        payment_method_sub_type: api_enums::PaymentMethodType,
        connector: ConnectorData,
        business_sub_label: Option<String>,
        payment_method_type: api_enums::PaymentMethod,
    ) -> Self {
        Self {
            payment_method_sub_type,
            connector,
            business_sub_label,
            payment_method_type,
        }
    }
}

common_utils::create_list_wrapper!(
    SessionConnectorDatas,
    SessionConnectorData,
    impl_functions: {
        pub fn apply_filter_for_session_routing(&self) -> Self {
            let routing_enabled_pmts = &consts::ROUTING_ENABLED_PAYMENT_METHOD_TYPES;
            let routing_enabled_pms = &consts::ROUTING_ENABLED_PAYMENT_METHODS;
            self
                .iter()
                .filter(|connector_data| {
                    routing_enabled_pmts.contains(&connector_data.payment_method_sub_type)
                        || routing_enabled_pms.contains(&connector_data.payment_method_type)
                })
                .cloned()
                .collect()
        }
        pub fn filter_and_validate_for_session_flow(self, routing_results: &FxHashMap<api_enums::PaymentMethodType, Vec<routing::SessionRoutingChoice>>) -> Result<Self, errors::ApiErrorResponse> {
            let mut final_list = Self::new(Vec::new());
            let routing_enabled_pmts = &consts::ROUTING_ENABLED_PAYMENT_METHOD_TYPES;
            for connector_data in self {
                if !routing_enabled_pmts.contains(&connector_data.payment_method_sub_type) {
                    final_list.push(connector_data);
                } else if let Some(choice) = routing_results.get(&connector_data.payment_method_sub_type) {
                    let routing_choice = choice
                        .first()
                        .ok_or(errors::ApiErrorResponse::InternalServerError)?;
                    if connector_data.connector.connector_name == routing_choice.connector.connector_name
                        && connector_data.connector.merchant_connector_id
                            == routing_choice.connector.merchant_connector_id
                    {
                        final_list.push(connector_data);
                    }
                }
            }
            Ok(final_list)
        }
    }
);

pub fn convert_connector_data_to_routable_connectors(
    connectors: &[ConnectorRoutingData],
) -> CustomResult<Vec<RoutableConnectorChoice>, common_utils::errors::ValidationError> {
    connectors
        .iter()
        .map(|connectors_routing_data| {
            RoutableConnectorChoice::foreign_try_from(
                connectors_routing_data.connector_data.clone(),
            )
        })
        .collect()
}

impl ForeignTryFrom<ConnectorData> for RoutableConnectorChoice {
    type Error = error_stack::Report<common_utils::errors::ValidationError>;
    fn foreign_try_from(from: ConnectorData) -> Result<Self, Self::Error> {
        match RoutableConnectors::foreign_try_from(from.connector_name) {
            Ok(connector) => Ok(Self {
                choice_kind: api_routing::RoutableChoiceKind::FullStruct,
                connector,
                merchant_connector_id: from.merchant_connector_id,
            }),
            Err(e) => Err(common_utils::errors::ValidationError::InvalidValue {
                message: format!("This is not a routable connector: {e:?}"),
            })?,
        }
    }
}

/// Session Surcharge type
pub enum SessionSurchargeDetails {
    /// Surcharge is calculated by hyperswitch
    Calculated(payments_types::SurchargeMetadata),
    /// Surcharge is sent by merchant
    PreDetermined(payments_types::SurchargeDetails),
}

impl SessionSurchargeDetails {
    pub fn fetch_surcharge_details(
        &self,
        payment_method: enums::PaymentMethod,
        payment_method_type: enums::PaymentMethodType,
        card_network: Option<&enums::CardNetwork>,
    ) -> Option<payments_types::SurchargeDetails> {
        match self {
            Self::Calculated(surcharge_metadata) => surcharge_metadata
                .get_surcharge_details(payments_types::SurchargeKey::PaymentMethodData(
                    payment_method,
                    payment_method_type,
                    card_network.cloned(),
                ))
                .cloned(),
            Self::PreDetermined(surcharge_details) => Some(surcharge_details.clone()),
        }
    }
}

pub enum ConnectorChoice {
    SessionMultiple(SessionConnectorDatas),
    StraightThrough(serde_json::Value),
    Decide,
}

#[cfg(test)]
mod test {
    #![allow(clippy::unwrap_used)]
    use super::*;

    #[test]
    fn test_convert_connector_parsing_success() {
        let result = enums::Connector::from_str("aci");
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), enums::Connector::Aci);

        let result = enums::Connector::from_str("shift4");
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), enums::Connector::Shift4);

        let result = enums::Connector::from_str("authorizedotnet");
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), enums::Connector::Authorizedotnet);
    }

    #[test]
    fn test_convert_connector_parsing_fail_for_unknown_type() {
        let result = enums::Connector::from_str("unknowntype");
        assert!(result.is_err());

        let result = enums::Connector::from_str("randomstring");
        assert!(result.is_err());
    }

    #[test]
    fn test_convert_connector_parsing_fail_for_camel_case() {
        let result = enums::Connector::from_str("Paypal");
        assert!(result.is_err());

        let result = enums::Connector::from_str("Authorizedotnet");
        assert!(result.is_err());

        let result = enums::Connector::from_str("Opennode");
        assert!(result.is_err());
    }
}

#[derive(Clone)]
pub struct TaxCalculateConnectorData {
    pub connector: ConnectorEnum,
    pub connector_name: enums::TaxConnectors,
}

impl TaxCalculateConnectorData {
    pub fn get_connector_by_name(name: &str) -> CustomResult<Self, errors::ApiErrorResponse> {
        let connector_name = enums::TaxConnectors::from_str(name)
            .change_context(errors::ApiErrorResponse::IncorrectConnectorNameGiven)
            .attach_printable_lazy(|| format!("unable to parse connector: {name}"))?;
        let connector = Self::convert_connector(connector_name)?;
        Ok(Self {
            connector,
            connector_name,
        })
    }

    fn convert_connector(
        connector_name: enums::TaxConnectors,
    ) -> CustomResult<ConnectorEnum, errors::ApiErrorResponse> {
        match connector_name {
            enums::TaxConnectors::Taxjar => {
                Ok(ConnectorEnum::Old(Box::new(connector::Taxjar::new())))
            }
        }
    }
}


impl Responder {
        let flow = AnalyticsFlow::GetRefundFilters;
        Box::pin(api::server_wrap(
            flow,
            state,
            &req,
            json_payload.into_inner(),
            |state, auth: AuthenticationData, req: GetRefundFilterRequest, _| async move {
                let org_id = auth.merchant_account.get_org_id();
                let auth: AuthInfo = AuthInfo::OrgLevel {
                    org_id: org_id.clone(),
                };
                analytics::refunds::get_filters(&state.pool, req, &auth)
                    .await
                    .map(ApplicationResponse::Json)
            },
            auth::auth_type(
                &auth::PlatformOrgAdminAuth {
                    is_admin_auth_allowed: false,
                    organization_id: None,
                },
                &auth::JWTAuth {
                    permission: Permission::OrganizationAnalyticsRead,
                },
                req.headers(),
            ),
            api_locking::LockAction::NotApplicable,
        ))
        .await
    }


pub async fn receive_incoming_relay_webhook<W: types::OutgoingWebhookType>(
    state: web::Data<AppState>,
    req: HttpRequest,
    body: web::Bytes,
    path: web::Path<(
        common_utils::id_type::MerchantId,
        common_utils::id_type::MerchantConnectorAccountId,
    )


pub(crate) struct ApiKeyUpdateInternal {
    pub name: Option<String>,
    pub description: Option<String>,
    pub expires_at: Option<Option<PrimitiveDateTime>>,
    pub last_used: Option<PrimitiveDateTime>,
}