        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?;

    match business_profile {
        Some(business_profile) => {
            core_utils::validate_profile_id_from_auth_layer(
                authentication_profile_id,
                &business_profile,
            )?;
            let routing_algo_ref: routing_types::RoutingAlgorithmRef = match transaction_type {
                enums::TransactionType::Payment => business_profile.routing_algorithm.clone(),
                #[cfg(feature = "payouts")]
                enums::TransactionType::Payout => business_profile.payout_routing_algorithm.clone(),
                enums::TransactionType::ThreeDsAuthentication => {
                    business_profile.three_ds_decision_rule_algorithm.clone()
                }
            }
            .map(|val| val.parse_value("RoutingAlgorithmRef"))
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("unable to deserialize routing algorithm ref from merchant account")?
            .unwrap_or_default();

            let timestamp = common_utils::date_time::now_unix_timestamp();

            match routing_algo_ref.algorithm_id {
                Some(algorithm_id) => {
                    let routing_algorithm: routing_types::RoutingAlgorithmRef =
                        routing_types::RoutingAlgorithmRef {
                            algorithm_id: None,
                            timestamp,
                            config_algo_id: routing_algo_ref.config_algo_id.clone(),
                            surcharge_config_algo_id: routing_algo_ref.surcharge_config_algo_id,
                        };

                    let record = db
                        .find_routing_algorithm_by_profile_id_algorithm_id(
                            &profile_id,
                            &algorithm_id,
                        )
                        .await
                        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
                    let response = record.foreign_into();
                    helpers::update_profile_active_algorithm_ref(
                        db,
                        key_manager_state,
                        merchant_context.get_merchant_key_store(),
                        business_profile,
                        routing_algorithm,
                        &transaction_type,
                    )
                    .await?;

                    metrics::ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
                    Ok(service_api::ApplicationResponse::Json(response))
                }
                None => Err(errors::ApiErrorResponse::PreconditionFailed {
                    message: "Algorithm is already inactive".to_string(),
                })?,
            }
        }
        None => Err(errors::ApiErrorResponse::InvalidRequestData {
            message: "The business_profile is not present".to_string(),
        }
        .into()),
    }
}

#[cfg(feature = "v2")]
pub async fn update_default_fallback_routing(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: common_utils::id_type::ProfileId,
    updated_list_of_connectors: Vec<routing_types::RoutableConnectorChoice>,
) -> RouterResponse<Vec<routing_types::RoutableConnectorChoice>> {
    metrics::ROUTING_UPDATE_CONFIG.add(1, &[]);
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")?;
    let profile_wrapper = admin::ProfileWrapper::new(profile);
    let default_list_of_connectors =
        profile_wrapper.get_default_fallback_list_of_connector_under_profile()?;

    utils::when(
        default_list_of_connectors.len() != updated_list_of_connectors.len(),
        || {
            Err(errors::ApiErrorResponse::PreconditionFailed {
                message: "current config and updated config have different lengths".to_string(),
            })
        },
    )?;

    let existing_set_of_default_connectors: FxHashSet<String> = FxHashSet::from_iter(
        default_list_of_connectors
            .iter()
            .map(|conn_choice| conn_choice.to_string()),
    );
    let updated_set_of_default_connectors: FxHashSet<String> = FxHashSet::from_iter(
        updated_list_of_connectors
            .iter()
            .map(|conn_choice| conn_choice.to_string()),
    );

    let symmetric_diff_between_existing_and_updated_connectors: Vec<String> =
        existing_set_of_default_connectors
            .symmetric_difference(&updated_set_of_default_connectors)
            .cloned()
            .collect();

    utils::when(
        !symmetric_diff_between_existing_and_updated_connectors.is_empty(),
        || {
            Err(errors::ApiErrorResponse::InvalidRequestData {
                message: format!(
                    "connector mismatch between old and new configs ({})",
                    symmetric_diff_between_existing_and_updated_connectors.join(", ")
                ),
            })
        },
    )?;
    profile_wrapper
        .update_default_fallback_routing_of_connectors_under_profile(
            db,
            &updated_list_of_connectors,
            key_manager_state,
            merchant_context.get_merchant_key_store(),
        )
        .await?;

    metrics::ROUTING_UPDATE_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(
        updated_list_of_connectors,
    ))
}

#[cfg(feature = "v1")]
pub async fn update_default_routing_config(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    updated_config: Vec<routing_types::RoutableConnectorChoice>,
    transaction_type: &enums::TransactionType,
) -> RouterResponse<Vec<routing_types::RoutableConnectorChoice>> {
    metrics::ROUTING_UPDATE_CONFIG.add(1, &[]);
    let db = state.store.as_ref();
    let default_config = helpers::get_merchant_default_config(
        db,
        merchant_context
            .get_merchant_account()
            .get_id()
            .get_string_repr(),
        transaction_type,
    )
    .await?;

    utils::when(default_config.len() != updated_config.len(), || {
        Err(errors::ApiErrorResponse::PreconditionFailed {
            message: "current config and updated config have different lengths".to_string(),
        })
    })?;

    let existing_set: FxHashSet<String> =
        FxHashSet::from_iter(default_config.iter().map(|c| c.to_string()));
    let updated_set: FxHashSet<String> =
        FxHashSet::from_iter(updated_config.iter().map(|c| c.to_string()));

    let symmetric_diff: Vec<String> = existing_set
        .symmetric_difference(&updated_set)
        .cloned()
        .collect();

    utils::when(!symmetric_diff.is_empty(), || {
        Err(errors::ApiErrorResponse::InvalidRequestData {
            message: format!(
                "connector mismatch between old and new configs ({})",
                symmetric_diff.join(", ")
            ),
        })
    })?;

    helpers::update_merchant_default_config(
        db,
        merchant_context
            .get_merchant_account()
            .get_id()
            .get_string_repr(),
        updated_config.clone(),
        transaction_type,
    )
    .await?;

    metrics::ROUTING_UPDATE_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(updated_config))
}

#[cfg(feature = "v2")]
pub async fn retrieve_default_fallback_algorithm_for_profile(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: common_utils::id_type::ProfileId,
) -> RouterResponse<Vec<routing_types::RoutableConnectorChoice>> {
    metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG.add(1, &[]);
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")?;

    let connectors_choice = admin::ProfileWrapper::new(profile)
        .get_default_fallback_list_of_connector_under_profile()?;

    metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(connectors_choice))
}

#[cfg(feature = "v1")]
pub async fn retrieve_default_routing_config(
    state: SessionState,
    profile_id: Option<common_utils::id_type::ProfileId>,
    merchant_context: domain::MerchantContext,
    transaction_type: &enums::TransactionType,
) -> RouterResponse<Vec<routing_types::RoutableConnectorChoice>> {
    metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG.add(1, &[]);
    let db = state.store.as_ref();
    let id = profile_id
        .map(|profile_id| profile_id.get_string_repr().to_owned())
        .unwrap_or_else(|| {
            merchant_context
                .get_merchant_account()
                .get_id()
                .get_string_repr()
                .to_string()
        });

    helpers::get_merchant_default_config(db, &id, transaction_type)
        .await
        .map(|conn_choice| {
            metrics::ROUTING_RETRIEVE_DEFAULT_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
            service_api::ApplicationResponse::Json(conn_choice)
        })
}

#[cfg(feature = "v2")]
pub async fn retrieve_routing_config_under_profile(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    query_params: RoutingRetrieveQuery,
    profile_id: common_utils::id_type::ProfileId,
    transaction_type: &enums::TransactionType,
) -> RouterResponse<routing_types::LinkedRoutingConfigRetrieveResponse> {
    metrics::ROUTING_RETRIEVE_LINK_CONFIG.add(1, &[]);
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")?;

    let record = db
        .list_routing_algorithm_metadata_by_profile_id(
            business_profile.get_id(),
            i64::from(query_params.limit.unwrap_or_default()),
            i64::from(query_params.offset.unwrap_or_default()),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;

    let active_algorithms = record
        .into_iter()
        .filter(|routing_rec| &routing_rec.algorithm_for == transaction_type)
        .map(|routing_algo| routing_algo.foreign_into())
        .collect::<Vec<_>>();

    metrics::ROUTING_RETRIEVE_LINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(
        routing_types::LinkedRoutingConfigRetrieveResponse::ProfileBased(active_algorithms),
    ))
}

#[cfg(feature = "v1")]
pub async fn retrieve_linked_routing_config(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    authentication_profile_id: Option<common_utils::id_type::ProfileId>,
    query_params: routing_types::RoutingRetrieveLinkQuery,
    transaction_type: enums::TransactionType,
) -> RouterResponse<routing_types::LinkedRoutingConfigRetrieveResponse> {
    metrics::ROUTING_RETRIEVE_LINK_CONFIG.add(1, &[]);

    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let merchant_key_store = merchant_context.get_merchant_key_store();
    let merchant_id = merchant_context.get_merchant_account().get_id();

    // Get business profiles
    let business_profiles = if let Some(profile_id) = query_params.profile_id {
        core_utils::validate_and_get_business_profile(
            db,
            key_manager_state,
            merchant_key_store,
            Some(&profile_id),
            merchant_id,
        )
        .await?
        .map(|profile| vec![profile])
        .get_required_value("Profile")
        .change_context(errors::ApiErrorResponse::ProfileNotFound {
            id: profile_id.get_string_repr().to_owned(),
        })?
    } else {
        let business_profile = db
            .list_profile_by_merchant_id(key_manager_state, merchant_key_store, merchant_id)
            .await
            .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
        core_utils::filter_objects_based_on_profile_id_list(
            authentication_profile_id.map(|profile_id| vec![profile_id]),
            business_profile,
        )
    };

    let mut active_algorithms = Vec::new();

    for business_profile in business_profiles {
        let profile_id = business_profile.get_id();

        // Handle static routing algorithm
        let routing_ref: routing_types::RoutingAlgorithmRef = match transaction_type {
            enums::TransactionType::Payment => &business_profile.routing_algorithm,
            #[cfg(feature = "payouts")]
            enums::TransactionType::Payout => &business_profile.payout_routing_algorithm,
            enums::TransactionType::ThreeDsAuthentication => {
                &business_profile.three_ds_decision_rule_algorithm
            }
        }
        .clone()
        .map(|val| val.parse_value("RoutingAlgorithmRef"))
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("unable to deserialize routing algorithm ref from merchant account")?
        .unwrap_or_default();

        if let Some(algorithm_id) = routing_ref.algorithm_id {
            let record = db
                .find_routing_algorithm_metadata_by_algorithm_id_profile_id(
                    &algorithm_id,
                    profile_id,
                )
                .await
                .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
            let hs_records: Vec<routing_types::RoutingDictionaryRecord> =
                vec![record.foreign_into()];
            let de_records = retrieve_decision_engine_active_rules(
                &state,
                &transaction_type,
                profile_id.clone(),
                hs_records.clone(),
            )
            .await;
            compare_and_log_result(
                de_records.clone(),
                hs_records.clone(),
                "list_active_routing".to_string(),
            );
            active_algorithms.append(
                &mut select_routing_result(&state, &business_profile, hs_records, de_records).await,
            );
        }

        // Handle dynamic routing algorithms
        let dynamic_routing_ref: routing_types::DynamicRoutingAlgorithmRef = business_profile
            .dynamic_routing_algorithm
            .clone()
            .map(|val| val.parse_value("DynamicRoutingAlgorithmRef"))
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable(
                "unable to deserialize dynamic routing algorithm ref from business profile",
            )?
            .unwrap_or_default();

        // Collect all dynamic algorithm IDs
        let mut dynamic_algorithm_ids = Vec::new();

        if let Some(sba) = &dynamic_routing_ref.success_based_algorithm {
            if let Some(id) = &sba.algorithm_id_with_timestamp.algorithm_id {
                dynamic_algorithm_ids.push(id.clone());
            }
        }
        if let Some(era) = &dynamic_routing_ref.elimination_routing_algorithm {
            if let Some(id) = &era.algorithm_id_with_timestamp.algorithm_id {
                dynamic_algorithm_ids.push(id.clone());
            }
        }
        if let Some(cbr) = &dynamic_routing_ref.contract_based_routing {
            if let Some(id) = &cbr.algorithm_id_with_timestamp.algorithm_id {
                dynamic_algorithm_ids.push(id.clone());
            }
        }

        // Fetch all dynamic algorithms
        for algorithm_id in dynamic_algorithm_ids {
            let record = db
                .find_routing_algorithm_metadata_by_algorithm_id_profile_id(
                    &algorithm_id,
                    profile_id,
                )
                .await
                .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
            if record.algorithm_for == transaction_type {
                active_algorithms.push(record.foreign_into());
            }
        }
    }

    metrics::ROUTING_RETRIEVE_LINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(
        routing_types::LinkedRoutingConfigRetrieveResponse::ProfileBased(active_algorithms),
    ))
}

pub async fn retrieve_decision_engine_active_rules(
    state: &SessionState,
    transaction_type: &enums::TransactionType,
    profile_id: common_utils::id_type::ProfileId,
    hs_records: Vec<routing_types::RoutingDictionaryRecord>,
) -> Vec<routing_types::RoutingDictionaryRecord> {
    let mut de_records =
        list_de_euclid_active_routing_algorithm(state, profile_id.get_string_repr().to_owned())
            .await
            .map_err(|e| {
                router_env::logger::error!(?e, "Failed to list DE Euclid active routing algorithm");
            })
            .ok() // Avoid throwing error if Decision Engine is not available or other errors thrown
            .unwrap_or_default();
    // Use Hs records to list the dynamic algorithms as DE is not supporting dynamic algorithms in HS standard
    let mut dynamic_algos = hs_records
        .into_iter()
        .filter(|record| record.kind == routing_types::RoutingAlgorithmKind::Dynamic)
        .collect::<Vec<_>>();
    de_records.append(&mut dynamic_algos);
    de_records
        .into_iter()
        .filter(|r| r.algorithm_for == Some(*transaction_type))
        .collect::<Vec<_>>()
}
// List all the default fallback algorithms under all the profile under a merchant
pub async fn retrieve_default_routing_config_for_profiles(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    transaction_type: &enums::TransactionType,
) -> RouterResponse<Vec<routing_types::ProfileDefaultRoutingConfig>> {
    metrics::ROUTING_RETRIEVE_CONFIG_FOR_PROFILE.add(1, &[]);
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let all_profiles = db
        .list_profile_by_merchant_id(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().get_id(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)
        .attach_printable("error retrieving all business profiles for merchant")?;

    let retrieve_config_futures = all_profiles
        .iter()
        .map(|prof| {
            helpers::get_merchant_default_config(
                db,
                prof.get_id().get_string_repr(),
                transaction_type,
            )
        })
        .collect::<Vec<_>>();

    let configs = futures::future::join_all(retrieve_config_futures)
        .await
        .into_iter()
        .collect::<Result<Vec<_>, _>>()?;

    let default_configs = configs
        .into_iter()
        .zip(all_profiles.iter().map(|prof| prof.get_id().to_owned()))
        .map(
            |(config, profile_id)| routing_types::ProfileDefaultRoutingConfig {
                profile_id,
                connectors: config,
            },
        )
        .collect::<Vec<_>>();

    metrics::ROUTING_RETRIEVE_CONFIG_FOR_PROFILE_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(default_configs))
}

pub async fn update_default_routing_config_for_profile(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    updated_config: Vec<routing_types::RoutableConnectorChoice>,
    profile_id: common_utils::id_type::ProfileId,
    transaction_type: &enums::TransactionType,
) -> RouterResponse<routing_types::ProfileDefaultRoutingConfig> {
    metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE.add(1, &[]);

    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")
    .change_context(errors::ApiErrorResponse::ProfileNotFound {
        id: profile_id.get_string_repr().to_owned(),
    })?;
    let default_config = helpers::get_merchant_default_config(
        db,
        business_profile.get_id().get_string_repr(),
        transaction_type,
    )
    .await?;

    utils::when(default_config.len() != updated_config.len(), || {
        Err(errors::ApiErrorResponse::PreconditionFailed {
            message: "current config and updated config have different lengths".to_string(),
        })
    })?;

    let existing_set = FxHashSet::from_iter(
        default_config
            .iter()
            .map(|c| (c.connector.to_string(), c.merchant_connector_id.as_ref())),
    );

    let updated_set = FxHashSet::from_iter(
        updated_config
            .iter()
            .map(|c| (c.connector.to_string(), c.merchant_connector_id.as_ref())),
    );

    let symmetric_diff = existing_set
        .symmetric_difference(&updated_set)
        .cloned()
        .collect::<Vec<_>>();

    utils::when(!symmetric_diff.is_empty(), || {
        let error_str = symmetric_diff
            .into_iter()
            .map(|(connector, ident)| format!("'{connector}:{ident:?}'"))
            .collect::<Vec<_>>()
            .join(", ");

        Err(errors::ApiErrorResponse::InvalidRequestData {
            message: format!("connector mismatch between old and new configs ({error_str})"),
        })
    })?;

    helpers::update_merchant_default_config(
        db,
        business_profile.get_id().get_string_repr(),
        updated_config.clone(),
        transaction_type,
    )
    .await?;

    metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(
        routing_types::ProfileDefaultRoutingConfig {
            profile_id: business_profile.get_id().to_owned(),
            connectors: updated_config,
        },
    ))
}

// Toggle the specific routing type as well as add the default configs in RoutingAlgorithm table
// and update the same in business profile table.

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
pub async fn toggle_specific_dynamic_routing(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    feature_to_enable: routing::DynamicRoutingFeatures,
    profile_id: common_utils::id_type::ProfileId,
    dynamic_routing_type: routing::DynamicRoutingType,
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
    metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(
        1,
        router_env::metric_attributes!(
            ("profile_id", profile_id.clone()),
            ("algorithm_type", dynamic_routing_type.to_string())
        ),
    );
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let business_profile: domain::Profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")
    .change_context(errors::ApiErrorResponse::ProfileNotFound {
        id: profile_id.get_string_repr().to_owned(),
    })?;

    let dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef = business_profile
        .dynamic_routing_algorithm
        .clone()
        .map(|val| val.parse_value("DynamicRoutingAlgorithmRef"))
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable(
            "unable to deserialize dynamic routing algorithm ref from business profile",
        )?
        .unwrap_or_default();

    match feature_to_enable {
        routing::DynamicRoutingFeatures::Metrics
        | routing::DynamicRoutingFeatures::DynamicConnectorSelection => {
            // occurs when algorithm is already present in the db
            // 1. If present with same feature then return response as already enabled
            // 2. Else update the feature and persist the same on db
            // 3. If not present in db then create a new default entry
            Box::pin(helpers::enable_dynamic_routing_algorithm(
                &state,
                merchant_context.get_merchant_key_store().clone(),
                business_profile,
                feature_to_enable,
                dynamic_routing_algo_ref,
                dynamic_routing_type,
                None,
            ))
            .await
        }
        routing::DynamicRoutingFeatures::None => {
            // disable specific dynamic routing for the requested profile
            helpers::disable_dynamic_routing_algorithm(
                &state,
                merchant_context.get_merchant_key_store().clone(),
                business_profile,
                dynamic_routing_algo_ref,
                dynamic_routing_type,
            )
            .await
        }
    }
}

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
pub async fn create_specific_dynamic_routing(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    feature_to_enable: routing::DynamicRoutingFeatures,
    profile_id: common_utils::id_type::ProfileId,
    dynamic_routing_type: routing::DynamicRoutingType,
    payload: routing_types::DynamicRoutingPayload,
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
    metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(
        1,
        router_env::metric_attributes!(
            ("profile_id", profile_id.clone()),
            ("algorithm_type", dynamic_routing_type.to_string())
        ),
    );
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let business_profile: domain::Profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")
    .change_context(errors::ApiErrorResponse::ProfileNotFound {
        id: profile_id.get_string_repr().to_owned(),
    })?;

    let dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef = business_profile
        .dynamic_routing_algorithm
        .clone()
        .map(|val| val.parse_value("DynamicRoutingAlgorithmRef"))
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable(
            "unable to deserialize dynamic routing algorithm ref from business profile",
        )?
        .unwrap_or_default();

    match feature_to_enable {
        routing::DynamicRoutingFeatures::Metrics
        | routing::DynamicRoutingFeatures::DynamicConnectorSelection => {
            Box::pin(helpers::enable_dynamic_routing_algorithm(
                &state,
                merchant_context.get_merchant_key_store().clone(),
                business_profile,
                feature_to_enable,
                dynamic_routing_algo_ref,
                dynamic_routing_type,
                Some(payload),
            ))
            .await
        }
        routing::DynamicRoutingFeatures::None => {
            // disable specific dynamic routing for the requested profile
            helpers::disable_dynamic_routing_algorithm(
                &state,
                merchant_context.get_merchant_key_store().clone(),
                business_profile,
                dynamic_routing_algo_ref,
                dynamic_routing_type,
            )
            .await
        }
    }
}

#[cfg(feature = "v1")]
pub async fn configure_dynamic_routing_volume_split(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: common_utils::id_type::ProfileId,
    routing_info: routing::RoutingVolumeSplit,
) -> RouterResponse<routing::RoutingVolumeSplit> {
    metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(
        1,
        router_env::metric_attributes!(("profile_id", profile_id.clone())),
    );
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    utils::when(
        routing_info.split > crate::consts::DYNAMIC_ROUTING_MAX_VOLUME,
        || {
            Err(errors::ApiErrorResponse::InvalidRequestData {
                message: "Dynamic routing volume split should be less than 100".to_string(),
            })
        },
    )?;

    let business_profile: domain::Profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")
    .change_context(errors::ApiErrorResponse::ProfileNotFound {
        id: profile_id.get_string_repr().to_owned(),
    })?;

    let mut dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef = business_profile
        .dynamic_routing_algorithm
        .clone()
        .map(|val| val.parse_value("DynamicRoutingAlgorithmRef"))
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable(
            "unable to deserialize dynamic routing algorithm ref from business profile",
        )?
        .unwrap_or_default();

    dynamic_routing_algo_ref.update_volume_split(Some(routing_info.split));

    helpers::update_business_profile_active_dynamic_algorithm_ref(
        db,
        &((&state).into()),
        merchant_context.get_merchant_key_store(),
        business_profile.clone(),
        dynamic_routing_algo_ref.clone(),
    )
    .await?;

    Ok(service_api::ApplicationResponse::Json(routing_info))
}

#[cfg(feature = "v1")]
pub async fn retrieve_dynamic_routing_volume_split(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: common_utils::id_type::ProfileId,
) -> RouterResponse<routing_types::RoutingVolumeSplitResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let business_profile: domain::Profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")
    .change_context(errors::ApiErrorResponse::ProfileNotFound {
        id: profile_id.get_string_repr().to_owned(),
    })?;

    let dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef = business_profile
        .dynamic_routing_algorithm
        .clone()
        .map(|val| val.parse_value("DynamicRoutingAlgorithmRef"))
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable(
            "unable to deserialize dynamic routing algorithm ref from business profile",
        )?
        .unwrap_or_default();

    let resp = routing_types::RoutingVolumeSplitResponse {
        split: dynamic_routing_algo_ref
            .dynamic_routing_volume_split
            .unwrap_or_default(),
    };

    Ok(service_api::ApplicationResponse::Json(resp))
}

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
pub async fn success_based_routing_update_configs(
    state: SessionState,
    request: routing_types::SuccessBasedRoutingConfig,
    algorithm_id: common_utils::id_type::RoutingId,
    profile_id: common_utils::id_type::ProfileId,
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
    metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE.add(
        1,
        router_env::metric_attributes!(
            ("profile_id", profile_id.clone()),
            (
                "algorithm_type",
                routing::DynamicRoutingType::SuccessRateBasedRouting.to_string()
            )
        ),
    );
    let db = state.store.as_ref();

    let dynamic_routing_algo_to_update = db
        .find_routing_algorithm_by_profile_id_algorithm_id(&profile_id, &algorithm_id)
        .await
        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;

    let mut config_to_update: routing::SuccessBasedRoutingConfig = dynamic_routing_algo_to_update
        .algorithm_data
        .parse_value::<routing::SuccessBasedRoutingConfig>("SuccessBasedRoutingConfig")
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("unable to deserialize algorithm data from routing table into SuccessBasedRoutingConfig")?;

    config_to_update.update(request);

    let updated_algorithm_id = common_utils::generate_routing_id_of_default_length();
    let timestamp = common_utils::date_time::now();
    let algo = RoutingAlgorithm {
        algorithm_id: updated_algorithm_id,
        profile_id: dynamic_routing_algo_to_update.profile_id,
        merchant_id: dynamic_routing_algo_to_update.merchant_id,
        name: dynamic_routing_algo_to_update.name,
        description: dynamic_routing_algo_to_update.description,
        kind: dynamic_routing_algo_to_update.kind,
        algorithm_data: serde_json::json!(config_to_update.clone()),
        created_at: timestamp,
        modified_at: timestamp,
        algorithm_for: dynamic_routing_algo_to_update.algorithm_for,
        decision_engine_routing_id: None,
    };
    let record = db
        .insert_routing_algorithm(algo)
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to insert record in routing algorithm table")?;

    // redact cache for success based routing configs
    let cache_key = format!(
        "{}_{}",
        profile_id.get_string_repr(),
        algorithm_id.get_string_repr()
    );
    let cache_entries_to_redact = vec![cache::CacheKind::SuccessBasedDynamicRoutingCache(
        cache_key.into(),
    )];
    let _ = cache::redact_from_redis_and_publish(
        state.store.get_cache_store().as_ref(),
        cache_entries_to_redact,
    )
    .await
    .map_err(|e| router_env::logger::error!("unable to publish into the redact channel for evicting the success based routing config cache {e:?}"));

    let new_record = record.foreign_into();

    metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE_SUCCESS_RESPONSE.add(
        1,
        router_env::metric_attributes!(("profile_id", profile_id.clone())),
    );

    if !state.conf.open_router.dynamic_routing_enabled {
        state
            .grpc_client
            .dynamic_routing
            .as_ref()
            .async_map(|dr_client| async {
                dr_client
                    .success_rate_client
                    .invalidate_success_rate_routing_keys(
                        profile_id.get_string_repr().into(),
                        state.get_grpc_headers(),
                    )
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to invalidate the routing keys")
            })
            .await
            .transpose()?;
    }

    Ok(service_api::ApplicationResponse::Json(new_record))
}

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
pub async fn elimination_routing_update_configs(
    state: SessionState,
    request: routing_types::EliminationRoutingConfig,
    algorithm_id: common_utils::id_type::RoutingId,
    profile_id: common_utils::id_type::ProfileId,
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
    metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE.add(
        1,
        router_env::metric_attributes!(
            ("profile_id", profile_id.clone()),
            (
                "algorithm_type",
                routing::DynamicRoutingType::EliminationRouting.to_string()
            )
        ),
    );

    let db = state.store.as_ref();

    let dynamic_routing_algo_to_update = db
        .find_routing_algorithm_by_profile_id_algorithm_id(&profile_id, &algorithm_id)
        .await
        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;

    let mut config_to_update: routing::EliminationRoutingConfig = dynamic_routing_algo_to_update
        .algorithm_data
        .parse_value::<routing::EliminationRoutingConfig>("EliminationRoutingConfig")
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable(
            "unable to deserialize algorithm data from routing table into EliminationRoutingConfig",
        )?;

    config_to_update.update(request);

    let updated_algorithm_id = common_utils::generate_routing_id_of_default_length();
    let timestamp = common_utils::date_time::now();
    let algo = RoutingAlgorithm {
        algorithm_id: updated_algorithm_id,
        profile_id: dynamic_routing_algo_to_update.profile_id,
        merchant_id: dynamic_routing_algo_to_update.merchant_id,
        name: dynamic_routing_algo_to_update.name,
        description: dynamic_routing_algo_to_update.description,
        kind: dynamic_routing_algo_to_update.kind,
        algorithm_data: serde_json::json!(config_to_update),
        created_at: timestamp,
        modified_at: timestamp,
        algorithm_for: dynamic_routing_algo_to_update.algorithm_for,
        decision_engine_routing_id: None,
    };

    let record = db
        .insert_routing_algorithm(algo)
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to insert record in routing algorithm table")?;

    // redact cache for elimination routing configs
    let cache_key = format!(
        "{}_{}",
        profile_id.get_string_repr(),
        algorithm_id.get_string_repr()
    );
    let cache_entries_to_redact = vec![cache::CacheKind::EliminationBasedDynamicRoutingCache(
        cache_key.into(),
    )];

    cache::redact_from_redis_and_publish(
        state.store.get_cache_store().as_ref(),
        cache_entries_to_redact,
    )
    .await
    .map_err(|e| router_env::logger::error!("unable to publish into the redact channel for evicting the elimination routing config cache {e:?}")).ok();

    let new_record = record.foreign_into();

    metrics::ROUTING_UPDATE_CONFIG_FOR_PROFILE_SUCCESS_RESPONSE.add(
        1,
        router_env::metric_attributes!(("profile_id", profile_id.clone())),
    );

    if !state.conf.open_router.dynamic_routing_enabled {
        state
            .grpc_client
            .dynamic_routing
            .as_ref()
            .async_map(|dr_client| async {
                dr_client
                    .elimination_based_client
                    .invalidate_elimination_bucket(
                        profile_id.get_string_repr().into(),
                        state.get_grpc_headers(),
                    )
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to invalidate the elimination routing keys")
            })
            .await
            .transpose()?;
    }

    Ok(service_api::ApplicationResponse::Json(new_record))
}

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
pub async fn contract_based_dynamic_routing_setup(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: common_utils::id_type::ProfileId,
    feature_to_enable: routing_types::DynamicRoutingFeatures,
    config: Option<routing_types::ContractBasedRoutingConfig>,
) -> RouterResult<service_api::ApplicationResponse<routing_types::RoutingDictionaryRecord>> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let business_profile: domain::Profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )


// Implementation: impl api::PaymentSync for for Paysafe
// File: crates/hyperswitch_connectors/src/connectors/paysafe.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentSync for for Paysafe


// Implementation: impl GpayTokenizationData
// File: crates/common_types/src/payments.rs
// Module: common_types
// Methods: 3 total (3 public)

impl GpayTokenizationData


// Function: clone_connector
// File: crates/router/src/routes/user.rs
// Module: router

pub fn clone_connector(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<user_api::CloneConnectorRequest>,
) -> HttpResponse


// Implementation: impl api::RefundExecute for for Forte
// File: crates/hyperswitch_connectors/src/connectors/forte.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundExecute for for Forte


// Function: update_from_request
// File: crates/hyperswitch_domain_models/src/payments.rs
// Module: hyperswitch_domain_models

pub fn update_from_request(self, req: &api_models::payments::AmountDetailsUpdate) -> Self


// Struct: ErrorData
// File: crates/hyperswitch_connectors/src/connectors/riskified/transformers/api.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ErrorData


// Trait: AuthServiceConnector
// File: crates/pm_auth/src/types/api.rs
// Module: pm_auth

pub trait AuthServiceConnector: AuthService + Send + Debug + PaymentInitiation


// Implementation: impl ExchangeRates
// File: crates/currency_conversion/src/types.rs
// Module: currency_conversion
// Methods: 3 total (3 public)

impl ExchangeRates


// Function: server
// File: crates/router/src/routes/app.rs
// Module: router

pub fn server(state: AppState) -> Scope


// Implementation: impl ConnectorPostAuthentication for for Gpayments
// File: crates/hyperswitch_connectors/src/connectors/gpayments.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl ConnectorPostAuthentication for for Gpayments


// Function: api_key_revoke
// File: crates/router/src/routes/api_keys.rs
// Module: router

pub fn api_key_revoke(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<(
        common_utils::id_type::MerchantId,
        common_utils::id_type::ApiKeyId,
    )


// File: crates/hyperswitch_domain_models/src/revenue_recovery.rs
// Module: hyperswitch_domain_models
// Public functions: 1
// Public structs: 4

use api_models::{payments as api_payments, webhooks};
use common_enums::enums as common_enums;
use common_types::primitive_wrappers;
use common_utils::{id_type, pii, types as util_types};
use time::PrimitiveDateTime;

use crate::{
    payments,
    router_response_types::revenue_recovery::{
        BillingConnectorInvoiceSyncResponse, BillingConnectorPaymentsSyncResponse,
    },
    ApiModelToDieselModelConvertor,
};

/// Recovery payload is unified struct constructed from billing connectors
#[derive(Debug)]
pub struct RevenueRecoveryAttemptData {
    /// transaction amount against invoice, accepted in minor unit.
    pub amount: util_types::MinorUnit,
    /// currency of the transaction
    pub currency: common_enums::Currency,
    /// merchant reference id at billing connector. ex: invoice_id
    pub merchant_reference_id: id_type::PaymentReferenceId,
    /// transaction id reference at payment connector
    pub connector_transaction_id: Option<util_types::ConnectorTransactionId>,
    /// error code sent by billing connector.
    pub error_code: Option<String>,
    /// error message sent by billing connector.
    pub error_message: Option<String>,
    /// mandate token at payment processor end.
    pub processor_payment_method_token: String,
    /// customer id at payment connector for which mandate is attached.
    pub connector_customer_id: String,
    /// Payment gateway identifier id at billing processor.
    pub connector_account_reference_id: String,
    /// timestamp at which transaction has been created at billing connector
    pub transaction_created_at: Option<PrimitiveDateTime>,
    /// transaction status at billing connector equivalent to payment attempt status.
    pub status: common_enums::AttemptStatus,
    /// payment method of payment attempt.
    pub payment_method_type: common_enums::PaymentMethod,
    /// payment method sub type of the payment attempt.
    pub payment_method_sub_type: common_enums::PaymentMethodType,
    /// This field can be returned for both approved and refused Mastercard payments.
    /// This code provides additional information about the type of transaction or the reason why the payment failed.
    /// If the payment failed, the network advice code gives guidance on if and when you can retry the payment.
    pub network_advice_code: Option<String>,
    /// For card errors resulting from a card issuer decline, a brand specific 2, 3, or 4 digit code which indicates the reason the authorization failed.
    pub network_decline_code: Option<String>,
    /// A string indicating how to proceed with an network error if payment gateway provide one. This is used to understand the network error code better.
    pub network_error_message: Option<String>,
    /// Number of attempts made for an invoice
    pub retry_count: Option<u16>,
    /// Time when next invoice will be generated which will be equal to the end time of the current invoice
    pub invoice_next_billing_time: Option<PrimitiveDateTime>,
    /// Time at which the invoice created
    pub invoice_billing_started_at_time: Option<PrimitiveDateTime>,
    /// stripe specific id used to validate duplicate attempts in revenue recovery flow
    pub charge_id: Option<String>,
    /// Additional card details
    pub card_info: api_payments::AdditionalCardInfo,
}

/// This is unified struct for Revenue Recovery Invoice Data and it is constructed from billing connectors
#[derive(Debug, Clone)]
pub struct RevenueRecoveryInvoiceData {
    /// invoice amount at billing connector
    pub amount: util_types::MinorUnit,
    /// currency of the amount.
    pub currency: common_enums::Currency,
    /// merchant reference id at billing connector. ex: invoice_id
    pub merchant_reference_id: id_type::PaymentReferenceId,
    /// billing address id of the invoice
    pub billing_address: Option<api_payments::Address>,
    /// Retry count of the invoice
    pub retry_count: Option<u16>,
    /// Ending date of the invoice or the Next billing time of the Subscription
    pub next_billing_at: Option<PrimitiveDateTime>,
    /// Invoice Starting Time
    pub billing_started_at: Option<PrimitiveDateTime>,
    /// metadata of the merchant
    pub metadata: Option<pii::SecretSerdeValue>,
    /// Allow partial authorization for this payment
    pub enable_partial_authorization: Option<primitive_wrappers::EnablePartialAuthorizationBool>,
}

#[derive(Clone, Debug)]
pub struct RecoveryPaymentIntent {
    pub payment_id: id_type::GlobalPaymentId,
    pub status: common_enums::IntentStatus,
    pub feature_metadata: Option<api_payments::FeatureMetadata>,
    pub merchant_id: id_type::MerchantId,
    pub merchant_reference_id: Option<id_type::PaymentReferenceId>,
    pub invoice_amount: util_types::MinorUnit,
    pub invoice_currency: common_enums::Currency,
    pub created_at: Option<PrimitiveDateTime>,
    pub billing_address: Option<api_payments::Address>,
}

#[derive(Clone, Debug)]
pub struct RecoveryPaymentAttempt {
    pub attempt_id: id_type::GlobalAttemptId,
    pub attempt_status: common_enums::AttemptStatus,
    pub feature_metadata: Option<api_payments::PaymentAttemptFeatureMetadata>,
    pub amount: util_types::MinorUnit,
    pub network_advice_code: Option<String>,
    pub network_decline_code: Option<String>,
    pub error_code: Option<String>,
    pub created_at: PrimitiveDateTime,
}

impl RecoveryPaymentAttempt {
    pub fn get_attempt_triggered_by(&self) -> Option<common_enums::TriggeredBy> {
        self.feature_metadata.as_ref().and_then(|metadata| {
            metadata
                .revenue_recovery
                .as_ref()
                .map(|recovery| recovery.attempt_triggered_by)
        })
    }
}

impl From<&RevenueRecoveryInvoiceData> for api_payments::AmountDetails {
    fn from(data: &RevenueRecoveryInvoiceData) -> Self {
        let amount = api_payments::AmountDetailsSetter {
            order_amount: data.amount.into(),
            currency: data.currency,
            shipping_cost: None,
            order_tax_amount: None,
            skip_external_tax_calculation: common_enums::TaxCalculationOverride::Skip,
            skip_surcharge_calculation: common_enums::SurchargeCalculationOverride::Skip,
            surcharge_amount: None,
            tax_on_surcharge: None,
        };
        Self::new(amount)
    }
}

impl From<&RevenueRecoveryInvoiceData> for api_payments::PaymentsCreateIntentRequest {
    fn from(data: &RevenueRecoveryInvoiceData) -> Self {
        let amount_details = api_payments::AmountDetails::from(data);
        Self {
            amount_details,
            merchant_reference_id: Some(data.merchant_reference_id.clone()),
            routing_algorithm_id: None,
            // Payments in the revenue recovery flow are always recurring transactions,
            // so capture method will be always automatic.
            capture_method: Some(common_enums::CaptureMethod::Automatic),
            authentication_type: Some(common_enums::AuthenticationType::NoThreeDs),
            billing: data.billing_address.clone(),
            shipping: None,
            customer_id: None,
            customer_present: Some(common_enums::PresenceOfCustomerDuringPayment::Absent),
            description: None,
            return_url: None,
            setup_future_usage: None,
            apply_mit_exemption: None,
            statement_descriptor: None,
            order_details: None,
            allowed_payment_method_types: None,
            metadata: data.metadata.clone(),
            connector_metadata: None,
            feature_metadata: None,
            payment_link_enabled: None,
            payment_link_config: None,
            request_incremental_authorization: None,
            session_expiry: None,
            frm_metadata: None,
            request_external_three_ds_authentication: None,
            force_3ds_challenge: None,
            merchant_connector_details: None,
            enable_partial_authorization: data.enable_partial_authorization,
        }
    }
}

impl From<&BillingConnectorInvoiceSyncResponse> for RevenueRecoveryInvoiceData {
    fn from(data: &BillingConnectorInvoiceSyncResponse) -> Self {
        Self {
            amount: data.amount,
            currency: data.currency,
            merchant_reference_id: data.merchant_reference_id.clone(),
            billing_address: data.billing_address.clone(),
            retry_count: data.retry_count,
            next_billing_at: data.ends_at,
            billing_started_at: data.created_at,
            metadata: None,
            enable_partial_authorization: None,
        }
    }
}

impl
    From<(
        &BillingConnectorPaymentsSyncResponse,
        &RevenueRecoveryInvoiceData,
    )> for RevenueRecoveryAttemptData
{
    fn from(
        data: (
            &BillingConnectorPaymentsSyncResponse,
            &RevenueRecoveryInvoiceData,
        ),
    ) -> Self {
        let billing_connector_payment_details = data.0;
        let invoice_details = data.1;
        Self {
            amount: billing_connector_payment_details.amount,
            currency: billing_connector_payment_details.currency,
            merchant_reference_id: billing_connector_payment_details
                .merchant_reference_id
                .clone(),
            connector_transaction_id: billing_connector_payment_details
                .connector_transaction_id
                .clone(),
            error_code: billing_connector_payment_details.error_code.clone(),
            error_message: billing_connector_payment_details.error_message.clone(),
            processor_payment_method_token: billing_connector_payment_details
                .processor_payment_method_token
                .clone(),
            connector_customer_id: billing_connector_payment_details
                .connector_customer_id
                .clone(),
            connector_account_reference_id: billing_connector_payment_details
                .connector_account_reference_id
                .clone(),
            transaction_created_at: billing_connector_payment_details.transaction_created_at,
            status: billing_connector_payment_details.status,
            payment_method_type: billing_connector_payment_details.payment_method_type,
            payment_method_sub_type: billing_connector_payment_details.payment_method_sub_type,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            retry_count: invoice_details.retry_count,
            invoice_next_billing_time: invoice_details.next_billing_at,
            charge_id: billing_connector_payment_details.charge_id.clone(),
            invoice_billing_started_at_time: invoice_details.billing_started_at,
            card_info: billing_connector_payment_details.card_info.clone(),
        }
    }
}

impl From<&RevenueRecoveryAttemptData> for api_payments::PaymentAttemptAmountDetails {
    fn from(data: &RevenueRecoveryAttemptData) -> Self {
        Self {
            net_amount: data.amount,
            amount_to_capture: None,
            surcharge_amount: None,
            tax_on_surcharge: None,
            amount_capturable: data.amount,
            shipping_cost: None,
            order_tax_amount: None,
        }
    }
}

impl From<&RevenueRecoveryAttemptData> for Option<api_payments::RecordAttemptErrorDetails> {
    fn from(data: &RevenueRecoveryAttemptData) -> Self {
        data.error_code
            .as_ref()
            .zip(data.error_message.clone())
            .map(|(code, message)| api_payments::RecordAttemptErrorDetails {
                code: code.to_string(),
                message: message.to_string(),
                network_advice_code: data.network_advice_code.clone(),
                network_decline_code: data.network_decline_code.clone(),
                network_error_message: data.network_error_message.clone(),
            })
    }
}

impl From<&payments::PaymentIntent> for RecoveryPaymentIntent {
    fn from(payment_intent: &payments::PaymentIntent) -> Self {
        Self {
            payment_id: payment_intent.id.clone(),
            status: payment_intent.status,
            feature_metadata: payment_intent
                .feature_metadata
                .clone()
                .map(|feature_metadata| feature_metadata.convert_back()),
            merchant_reference_id: payment_intent.merchant_reference_id.clone(),
            invoice_amount: payment_intent.amount_details.order_amount,
            invoice_currency: payment_intent.amount_details.currency,
            billing_address: payment_intent
                .billing_address
                .clone()
                .map(|address| api_payments::Address::from(address.into_inner())),
            merchant_id: payment_intent.merchant_id.clone(),
            created_at: Some(payment_intent.created_at),
        }
    }
}

impl From<&payments::payment_attempt::PaymentAttempt> for RecoveryPaymentAttempt {
    fn from(payment_attempt: &payments::payment_attempt::PaymentAttempt) -> Self {
        Self {
            attempt_id: payment_attempt.id.clone(),
            attempt_status: payment_attempt.status,
            feature_metadata: payment_attempt
                .feature_metadata
                .clone()
                .map(
                    |feature_metadata| api_payments::PaymentAttemptFeatureMetadata {
                        revenue_recovery: feature_metadata.revenue_recovery.map(|recovery| {
                            api_payments::PaymentAttemptRevenueRecoveryData {
                                attempt_triggered_by: recovery.attempt_triggered_by,
                                charge_id: recovery.charge_id,
                            }
                        }),
                    },
                ),
            amount: payment_attempt.amount_details.get_net_amount(),
            network_advice_code: payment_attempt
                .error
                .clone()
                .and_then(|error| error.network_advice_code),
            network_decline_code: payment_attempt
                .error
                .clone()
                .and_then(|error| error.network_decline_code),
            error_code: payment_attempt
                .error
                .as_ref()
                .map(|error| error.code.clone()),
            created_at: payment_attempt.created_at,
        }
    }
}


// Struct: PayoutAttemptUpdateInternal
// File: crates/diesel_models/src/payout_attempt.rs
// Module: diesel_models
// Implementations: 1
// Traits: Default

pub struct PayoutAttemptUpdateInternal


// Struct: PaymentMethodType
// File: crates/payment_methods/src/configs/settings.rs
// Module: payment_methods
// Implementations: 0

pub struct PaymentMethodType


// Implementation: impl WebhookEvents
// File: crates/router/src/routes/app.rs
// Module: router
// Methods: 1 total (1 public)

impl WebhookEvents


// Function: get_updated_vault_data
// File: crates/hyperswitch_domain_models/src/payments.rs
// Module: hyperswitch_domain_models

pub fn get_updated_vault_data(
        existing_vault_data: Option<&Self>,
        payment_method_data: &payment_method_data::PaymentMethodData,
    ) -> Option<Self>


// Struct: Multitenancy
// File: crates/drainer/src/settings.rs
// Module: drainer
// Implementations: 1

pub struct Multitenancy


// Function: update
// File: crates/diesel_models/src/query/payouts.rs
// Module: diesel_models

pub fn update(
        self,
        conn: &PgPooledConn,
        payout_update: PayoutsUpdate,
    ) -> StorageResult<Self>


// Implementation: impl api::PaymentsCompleteAuthorize for for Redsys
// File: crates/hyperswitch_connectors/src/connectors/redsys.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentsCompleteAuthorize for for Redsys


// Struct: Violations
// File: crates/hyperswitch_connectors/src/connectors/itaubank/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct Violations


// Implementation: impl Deref for for DisputePollingIntervalInHours
// File: crates/common_types/src/primitive_wrappers.rs
// Module: common_types
// Methods: 1 total (0 public)

impl Deref for for DisputePollingIntervalInHours


// Struct: MandatePaymentRequest
// File: crates/hyperswitch_connectors/src/connectors/elavon/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct MandatePaymentRequest


// Function: number_of_digits_after_decimal_point
// File: crates/common_enums/src/enums.rs
// Module: common_enums

pub fn number_of_digits_after_decimal_point(self) -> u8


// Function: get_filters_for_disputes
// File: crates/router/src/core/disputes.rs
// Module: router

pub fn get_filters_for_disputes(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
) -> RouterResponse<api_models::disputes::DisputeListFilters>


// Implementation: impl api::PaymentToken for for Katapult
// File: crates/hyperswitch_connectors/src/connectors/katapult.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentToken for for Katapult


// Function: api_key_retrieve
// File: crates/router/src/routes/api_keys.rs
// Module: router

pub fn api_key_retrieve(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<(
        common_utils::id_type::MerchantId,
        common_utils::id_type::ApiKeyId,
    )


// File: crates/router/src/services/authorization/permission_groups.rs
// Module: router

use std::{collections::HashMap, ops::Not};

use common_enums::{EntityType, ParentGroup, PermissionGroup, PermissionScope, Resource};
use strum::IntoEnumIterator;

use super::permissions::{self, ResourceExt};

pub trait PermissionGroupExt {
    fn scope(&self) -> PermissionScope;
    fn parent(&self) -> ParentGroup;
    fn resources(&self) -> Vec<Resource>;
    fn accessible_groups(&self) -> Vec<PermissionGroup>;
}

impl PermissionGroupExt for PermissionGroup {
    fn scope(&self) -> PermissionScope {
        match self {
            Self::OperationsView
            | Self::ConnectorsView
            | Self::WorkflowsView
            | Self::AnalyticsView
            | Self::UsersView
            | Self::MerchantDetailsView
            | Self::AccountView
            | Self::ReconOpsView
            | Self::ReconReportsView
            | Self::ThemeView => PermissionScope::Read,

            Self::OperationsManage
            | Self::ConnectorsManage
            | Self::WorkflowsManage
            | Self::UsersManage
            | Self::MerchantDetailsManage
            | Self::OrganizationManage
            | Self::AccountManage
            | Self::ReconOpsManage
            | Self::ReconReportsManage
            | Self::InternalManage
            | Self::ThemeManage => PermissionScope::Write,
        }
    }

    fn parent(&self) -> ParentGroup {
        match self {
            Self::OperationsView | Self::OperationsManage => ParentGroup::Operations,
            Self::ConnectorsView | Self::ConnectorsManage => ParentGroup::Connectors,
            Self::WorkflowsView | Self::WorkflowsManage => ParentGroup::Workflows,
            Self::AnalyticsView => ParentGroup::Analytics,
            Self::UsersView | Self::UsersManage => ParentGroup::Users,
            Self::MerchantDetailsView
            | Self::OrganizationManage
            | Self::MerchantDetailsManage
            | Self::AccountView
            | Self::AccountManage => ParentGroup::Account,

            Self::ThemeView | Self::ThemeManage => ParentGroup::Theme,
            Self::ReconOpsView | Self::ReconOpsManage => ParentGroup::ReconOps,
            Self::ReconReportsView | Self::ReconReportsManage => ParentGroup::ReconReports,
            Self::InternalManage => ParentGroup::Internal,
        }
    }

    fn resources(&self) -> Vec<Resource> {
        self.parent().resources()
    }

    fn accessible_groups(&self) -> Vec<Self> {
        match self {
            Self::OperationsView => vec![Self::OperationsView, Self::ConnectorsView],
            Self::OperationsManage => vec![
                Self::OperationsView,
                Self::OperationsManage,
                Self::ConnectorsView,
            ],

            Self::ConnectorsView => vec![Self::ConnectorsView],
            Self::ConnectorsManage => vec![Self::ConnectorsView, Self::ConnectorsManage],

            Self::WorkflowsView => vec![Self::WorkflowsView, Self::ConnectorsView],
            Self::WorkflowsManage => vec![
                Self::WorkflowsView,
                Self::WorkflowsManage,
                Self::ConnectorsView,
            ],

            Self::AnalyticsView => vec![Self::AnalyticsView, Self::OperationsView],

            Self::UsersView => vec![Self::UsersView],
            Self::UsersManage => {
                vec![Self::UsersView, Self::UsersManage]
            }

            Self::ReconOpsView => vec![Self::ReconOpsView],
            Self::ReconOpsManage => vec![Self::ReconOpsView, Self::ReconOpsManage],

            Self::ReconReportsView => vec![Self::ReconReportsView],
            Self::ReconReportsManage => vec![Self::ReconReportsView, Self::ReconReportsManage],

            Self::MerchantDetailsView => vec![Self::MerchantDetailsView],
            Self::MerchantDetailsManage => {
                vec![Self::MerchantDetailsView, Self::MerchantDetailsManage]
            }

            Self::OrganizationManage => vec![Self::OrganizationManage],

            Self::AccountView => vec![Self::AccountView],
            Self::AccountManage => vec![Self::AccountView, Self::AccountManage],

            Self::InternalManage => vec![Self::InternalManage],
            Self::ThemeView => vec![Self::ThemeView, Self::AccountView],
            Self::ThemeManage => vec![Self::ThemeManage, Self::AccountView],
        }
    }
}

pub trait ParentGroupExt {
    fn resources(&self) -> Vec<Resource>;
    fn get_descriptions_for_groups(
        entity_type: EntityType,
        groups: Vec<PermissionGroup>,
    ) -> Option<HashMap<ParentGroup, String>>;
    fn get_available_scopes(&self) -> Vec<PermissionScope>;
}

impl ParentGroupExt for ParentGroup {
    fn resources(&self) -> Vec<Resource> {
        match self {
            Self::Operations => OPERATIONS.to_vec(),
            Self::Connectors => CONNECTORS.to_vec(),
            Self::Workflows => WORKFLOWS.to_vec(),
            Self::Analytics => ANALYTICS.to_vec(),
            Self::Users => USERS.to_vec(),
            Self::Account => ACCOUNT.to_vec(),
            Self::ReconOps => RECON_OPS.to_vec(),
            Self::ReconReports => RECON_REPORTS.to_vec(),
            Self::Internal => INTERNAL.to_vec(),
            Self::Theme => THEME.to_vec(),
        }
    }

    fn get_descriptions_for_groups(
        entity_type: EntityType,
        groups: Vec<PermissionGroup>,
    ) -> Option<HashMap<Self, String>> {
        let descriptions_map = Self::iter()
            .filter_map(|parent| {
                if !groups.iter().any(|group| group.parent() == parent) {
                    return None;
                }
                let filtered_resources: Vec<_> = parent
                    .resources()
                    .into_iter()
                    .filter(|res| res.entities().iter().any(|entity| entity <= &entity_type))
                    .collect();

                if filtered_resources.is_empty() {
                    return None;
                }

                let description = filtered_resources
                    .iter()
                    .map(|res| permissions::get_resource_name(*res, entity_type))
                    .collect::<Option<Vec<_>>>()?
                    .join(", ");

                Some((parent, description))
            })
            .collect::<HashMap<_, _>>();

        descriptions_map
            .is_empty()
            .not()
            .then_some(descriptions_map)
    }

    fn get_available_scopes(&self) -> Vec<PermissionScope> {
        PermissionGroup::iter()
            .filter(|group| group.parent() == *self)
            .map(|group| group.scope())
            .collect()
    }
}

pub static OPERATIONS: [Resource; 8] = [
    Resource::Payment,
    Resource::Refund,
    Resource::Mandate,
    Resource::Dispute,
    Resource::Customer,
    Resource::Payout,
    Resource::Report,
    Resource::Account,
];

pub static CONNECTORS: [Resource; 2] = [Resource::Connector, Resource::Account];

pub static WORKFLOWS: [Resource; 5] = [
    Resource::Routing,
    Resource::ThreeDsDecisionManager,
    Resource::SurchargeDecisionManager,
    Resource::Account,
    Resource::RevenueRecovery,
];

pub static ANALYTICS: [Resource; 3] = [Resource::Analytics, Resource::Report, Resource::Account];

pub static USERS: [Resource; 2] = [Resource::User, Resource::Account];

pub static ACCOUNT: [Resource; 3] = [Resource::Account, Resource::ApiKey, Resource::WebhookEvent];

pub static RECON_OPS: [Resource; 8] = [
    Resource::ReconToken,
    Resource::ReconFiles,
    Resource::ReconUpload,
    Resource::RunRecon,
    Resource::ReconConfig,
    Resource::ReconAndSettlementAnalytics,
    Resource::ReconReports,
    Resource::Account,
];

pub static INTERNAL: [Resource; 1] = [Resource::InternalConnector];

pub static RECON_REPORTS: [Resource; 4] = [
    Resource::ReconToken,
    Resource::ReconAndSettlementAnalytics,
    Resource::ReconReports,
    Resource::Account,
];

pub static THEME: [Resource; 1] = [Resource::Theme];


// Function: find_by_merchant_id_connector_name
// File: crates/diesel_models/src/query/merchant_connector_account.rs
// Module: diesel_models

pub fn find_by_merchant_id_connector_name(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_name: &str,
    ) -> StorageResult<Vec<Self>>


// Struct: BankAccountIban
// File: crates/hyperswitch_connectors/src/connectors/worldline/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BankAccountIban


// File: crates/router/tests/connectors/gpayments.rs
// Module: router

use router::types;
use test_utils::connector_auth;

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

#[derive(Clone, Copy)]
#[allow(dead_code)]
struct GpaymentsTest;
impl ConnectorActions for GpaymentsTest {}
impl utils::Connector for GpaymentsTest {
    fn get_data(&self) -> types::api::ConnectorData {
        use router::connector::Gpayments;
        utils::construct_connector_data_old(
            Box::new(Gpayments::new()),
            types::Connector::Threedsecureio,
            // Added as Dummy connector as template code is added for future usage
            types::api::GetToken::Connector,
            None,
        )
    }

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

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


// Struct: BankOfAmericaPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BankOfAmericaPaymentsRequest


// File: crates/storage_impl/src/metrics.rs
// Module: storage_impl

use router_env::{counter_metric, gauge_metric, global_meter};

global_meter!(GLOBAL_METER, "ROUTER_API");

counter_metric!(KV_MISS, GLOBAL_METER); // No. of KV misses

// Metrics for KV
counter_metric!(KV_OPERATION_SUCCESSFUL, GLOBAL_METER);
counter_metric!(KV_OPERATION_FAILED, GLOBAL_METER);
counter_metric!(KV_PUSHED_TO_DRAINER, GLOBAL_METER);
counter_metric!(KV_FAILED_TO_PUSH_TO_DRAINER, GLOBAL_METER);
counter_metric!(KV_SOFT_KILL_ACTIVE_UPDATE, GLOBAL_METER);

// Metrics for In-memory cache
gauge_metric!(IN_MEMORY_CACHE_ENTRY_COUNT, GLOBAL_METER);
counter_metric!(IN_MEMORY_CACHE_HIT, GLOBAL_METER);
counter_metric!(IN_MEMORY_CACHE_MISS, GLOBAL_METER);
counter_metric!(IN_MEMORY_CACHE_EVICTION_COUNT, GLOBAL_METER);


// Struct: MandateRevokeFlowData
// File: crates/hyperswitch_domain_models/src/router_data_v2/flow_common_types.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct MandateRevokeFlowData


// Implementation: impl ConnectorSpecifications for for Thunes
// File: crates/hyperswitch_connectors/src/connectors/thunes.rs
// Module: hyperswitch_connectors
// Methods: 3 total (0 public)

impl ConnectorSpecifications for for Thunes


// Trait: PaymentIntentFilterAnalytics
// File: crates/analytics/src/payment_intents/filters.rs
// Module: analytics

pub trait PaymentIntentFilterAnalytics: LoadRow<PaymentIntentFilterRow>


// Implementation: impl auth_service::AuthServiceLinkToken for for Plaid
// File: crates/pm_auth/src/connector/plaid.rs
// Module: pm_auth
// Methods: 0 total (0 public)

impl auth_service::AuthServiceLinkToken for for Plaid


// Struct: AirwallexPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AirwallexPaymentsRequest


// Struct: RefundDistributionRow
// File: crates/analytics/src/refunds/distribution.rs
// Module: analytics
// Implementations: 0

pub struct RefundDistributionRow


// Function: get_sdk_event_metrics
// File: crates/analytics/src/lib.rs
// Module: analytics

pub fn get_sdk_event_metrics(
        &self,
        metric: &SdkEventMetrics,
        dimensions: &[SdkEventDimensions],
        publishable_key: &str,
        filters: &SdkEventFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
    ) -> types::MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>>