    let 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)
    .attach_printable("failed eligibility analysis and fallback")?;

    // dynamic success based connector selection
    #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
    let connectors = if let Some(algo) = business_profile.dynamic_routing_algorithm.clone() {
        let dynamic_routing_config: api_models::routing::DynamicRoutingAlgorithmRef = algo
            .parse_value("DynamicRoutingAlgorithmRef")
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("unable to deserialize DynamicRoutingAlgorithmRef from JSON")?;
        let dynamic_split = api_models::routing::RoutingVolumeSplit {
            routing_type: api_models::routing::RoutingType::Dynamic,
            split: dynamic_routing_config
                .dynamic_routing_volume_split
                .unwrap_or_default(),
        };
        let static_split: api_models::routing::RoutingVolumeSplit =
            api_models::routing::RoutingVolumeSplit {
                routing_type: api_models::routing::RoutingType::Static,
                split: consts::DYNAMIC_ROUTING_MAX_VOLUME
                    - dynamic_routing_config
                        .dynamic_routing_volume_split
                        .unwrap_or_default(),
            };
        let volume_split_vec = vec![dynamic_split, static_split];
        let routing_choice = routing::perform_dynamic_routing_volume_split(volume_split_vec, None)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("failed to perform volume split on routing type")?;

        if routing_choice.routing_type.is_dynamic_routing() {
            if state.conf.open_router.dynamic_routing_enabled {
                routing::perform_dynamic_routing_with_open_router(
                    state,
                    connectors.clone(),
                    business_profile,
                    payment_attempt,
                    payment_data,
                )
                .await
                .map_err(|e| logger::error!(open_routing_error=?e))
                .unwrap_or(connectors)
            } else {
                let dynamic_routing_config_params_interpolator =
                    routing_helpers::DynamicRoutingConfigParamsInterpolator::new(
                        payment_data.get_payment_attempt().payment_method,
                        payment_data.get_payment_attempt().payment_method_type,
                        payment_data.get_payment_attempt().authentication_type,
                        payment_data.get_payment_attempt().currency,
                        payment_data
                            .get_billing_address()
                            .and_then(|address| address.address)
                            .and_then(|address| address.country),
                        payment_data
                            .get_payment_attempt()
                            .payment_method_data
                            .as_ref()
                            .and_then(|data| data.as_object())
                            .and_then(|card| card.get("card"))
                            .and_then(|data| data.as_object())
                            .and_then(|card| card.get("card_network"))
                            .and_then(|network| network.as_str())
                            .map(|network| network.to_string()),
                        payment_data
                            .get_payment_attempt()
                            .payment_method_data
                            .as_ref()
                            .and_then(|data| data.as_object())
                            .and_then(|card| card.get("card"))
                            .and_then(|data| data.as_object())
                            .and_then(|card| card.get("card_isin"))
                            .and_then(|card_isin| card_isin.as_str())
                            .map(|card_isin| card_isin.to_string()),
                    );

                routing::perform_dynamic_routing_with_intelligent_router(
                    state,
                    connectors.clone(),
                    business_profile,
                    dynamic_routing_config_params_interpolator,
                    payment_data,
                )
                .await
                .map_err(|e| logger::error!(dynamic_routing_error=?e))
                .unwrap_or(connectors)
            }
        } else {
            connectors
        }
    } else {
        connectors
    };

    let connector_data = connectors
        .into_iter()
        .map(|conn| {
            api::ConnectorData::get_connector_by_name(
                &state.conf.connectors,
                &conn.connector.to_string(),
                api::GetToken::Connector,
                conn.merchant_connector_id,
            )
            .map(|connector_data| connector_data.into())
        })
        .collect::<CustomResult<Vec<_>, _>>()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Invalid connector name received")?;

    decide_multiplex_connector_for_normal_or_recurring_payment(
        state,
        payment_data,
        routing_data,
        connector_data,
        mandate_type,
        business_profile.is_connector_agnostic_mit_enabled,
        business_profile.is_network_tokenization_enabled,
    )
    .await
}

#[cfg(feature = "payouts")]
#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
pub async fn route_connector_v1_for_payouts(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    business_profile: &domain::Profile,
    transaction_data: &payouts::PayoutData,
    routing_data: &mut storage::RoutingData,
    eligible_connectors: Option<Vec<enums::RoutableConnectors>>,
) -> RouterResult<ConnectorCallType> {
    todo!()
}

#[cfg(feature = "payouts")]
#[cfg(feature = "v1")]
#[allow(clippy::too_many_arguments)]
pub async fn route_connector_v1_for_payouts(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    business_profile: &domain::Profile,
    transaction_data: &payouts::PayoutData,
    routing_data: &mut storage::RoutingData,
    eligible_connectors: Option<Vec<enums::RoutableConnectors>>,
) -> RouterResult<ConnectorCallType> {
    let routing_algorithm_id = {
        let routing_algorithm = business_profile.payout_routing_algorithm.clone();

        let algorithm_ref = routing_algorithm
            .map(|ra| ra.parse_value::<api::routing::RoutingAlgorithmRef>("RoutingAlgorithmRef"))
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Could not decode merchant routing algorithm ref")?
            .unwrap_or_default();
        algorithm_ref.algorithm_id
    };

    let (connectors, _) = routing::perform_static_routing_v1(
        state,
        merchant_context.get_merchant_account().get_id(),
        routing_algorithm_id.as_ref(),
        business_profile,
        &TransactionData::Payout(transaction_data),
    )
    .await
    .change_context(errors::ApiErrorResponse::InternalServerError)?;
    let connectors = routing::perform_eligibility_analysis_with_fallback(
        &state.clone(),
        merchant_context.get_merchant_key_store(),
        connectors,
        &TransactionData::Payout(transaction_data),
        eligible_connectors,
        business_profile,
    )
    .await
    .change_context(errors::ApiErrorResponse::InternalServerError)
    .attach_printable("failed eligibility analysis and fallback")?;
    let first_connector_choice = connectors
        .first()
        .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)
        .attach_printable("Empty connector list returned")?
        .clone();

    let connector_data = connectors
        .into_iter()
        .map(|conn| {
            api::ConnectorData::get_connector_by_name(
                &state.conf.connectors,
                &conn.connector.to_string(),
                api::GetToken::Connector,
                conn.merchant_connector_id,
            )
            .map(|connector_data| connector_data.into())
        })
        .collect::<CustomResult<Vec<_>, _>>()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Invalid connector name received")?;

    routing_data.routed_through = Some(first_connector_choice.connector.to_string());

    routing_data.merchant_connector_id = first_connector_choice.merchant_connector_id;

    Ok(ConnectorCallType::Retryable(connector_data))
}

#[cfg(feature = "v2")]
pub async fn payment_external_authentication(
    _state: SessionState,
    _merchant_context: domain::MerchantContext,
    _req: api_models::payments::PaymentsExternalAuthenticationRequest,
) -> RouterResponse<api_models::payments::PaymentsExternalAuthenticationResponse> {
    todo!()
}

#[cfg(feature = "v1")]
#[instrument(skip_all)]
pub async fn payment_external_authentication<F: Clone + Sync>(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    req: api_models::payments::PaymentsExternalAuthenticationRequest,
) -> RouterResponse<api_models::payments::PaymentsExternalAuthenticationResponse> {
    use super::unified_authentication_service::types::ExternalAuthentication;
    use crate::core::unified_authentication_service::{
        types::UnifiedAuthenticationService, utils::external_authentication_update_trackers,
    };

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

    let merchant_id = merchant_context.get_merchant_account().get_id();
    let storage_scheme = merchant_context.get_merchant_account().storage_scheme;
    let payment_id = req.payment_id;
    let payment_intent = db
        .find_payment_intent_by_payment_id_merchant_id(
            key_manager_state,
            &payment_id,
            merchant_id,
            merchant_context.get_merchant_key_store(),
            storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
    let attempt_id = payment_intent.active_attempt.get_id().clone();
    let payment_attempt = db
        .find_payment_attempt_by_payment_id_merchant_id_attempt_id(
            &payment_intent.payment_id,
            merchant_id,
            &attempt_id.clone(),
            storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
    if payment_attempt.external_three_ds_authentication_attempted != Some(true) {
        Err(errors::ApiErrorResponse::PreconditionFailed {
            message:
                "You cannot authenticate this payment because payment_attempt.external_three_ds_authentication_attempted is false".to_owned(),
        })?
    }
    helpers::validate_payment_status_against_allowed_statuses(
        payment_intent.status,
        &[storage_enums::IntentStatus::RequiresCustomerAction],
        "authenticate",
    )?;

    let optional_customer = match &payment_intent.customer_id {
        Some(customer_id) => Some(
            state
                .store
                .find_customer_by_customer_id_merchant_id(
                    key_manager_state,
                    customer_id,
                    merchant_context.get_merchant_account().get_id(),
                    merchant_context.get_merchant_key_store(),
                    storage_scheme,
                )
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable_lazy(|| {
                    format!("error while finding customer with customer_id {customer_id:?}")
                })?,
        ),
        None => None,
    };

    let profile_id = payment_intent
        .profile_id
        .as_ref()
        .get_required_value("profile_id")
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("'profile_id' not set in payment intent")?;
    let currency = payment_attempt.currency.get_required_value("currency")?;
    let amount = payment_attempt.get_total_amount();
    let shipping_address = helpers::create_or_find_address_for_payment_by_request(
        &state,
        None,
        payment_intent.shipping_address_id.as_deref(),
        merchant_id,
        payment_intent.customer_id.as_ref(),
        merchant_context.get_merchant_key_store(),
        &payment_intent.payment_id,
        storage_scheme,
    )
    .await?;
    let billing_address = helpers::create_or_find_address_for_payment_by_request(
        &state,
        None,
        payment_attempt
            .payment_method_billing_address_id
            .as_deref()
            .or(payment_intent.billing_address_id.as_deref()),
        merchant_id,
        payment_intent.customer_id.as_ref(),
        merchant_context.get_merchant_key_store(),
        &payment_intent.payment_id,
        storage_scheme,
    )
    .await?;
    let authentication_connector = payment_attempt
        .authentication_connector
        .clone()
        .ok_or(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("authentication_connector not found in payment_attempt")?;
    let merchant_connector_account = helpers::get_merchant_connector_account(
        &state,
        merchant_id,
        None,
        merchant_context.get_merchant_key_store(),
        profile_id,
        authentication_connector.as_str(),
        None,
    )
    .await?;
    let authentication = db
        .find_authentication_by_merchant_id_authentication_id(
            merchant_id,
            &payment_attempt
                .authentication_id
                .clone()
                .ok_or(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("missing authentication_id in payment_attempt")?,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Error while fetching authentication record")?;

    let business_profile = state
        .store
        .find_business_profile_by_profile_id(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            profile_id,
        )
        .await
        .change_context(errors::ApiErrorResponse::ProfileNotFound {
            id: profile_id.get_string_repr().to_owned(),
        })?;

    let payment_method_details = helpers::get_payment_method_details_from_payment_token(
        &state,
        &payment_attempt,
        &payment_intent,
        merchant_context.get_merchant_key_store(),
        storage_scheme,
    )
    .await?
    .ok_or(errors::ApiErrorResponse::InternalServerError)
    .attach_printable("missing payment_method_details")?;
    let browser_info: Option<BrowserInformation> = payment_attempt
        .browser_info
        .clone()
        .map(|browser_information| browser_information.parse_value("BrowserInformation"))
        .transpose()
        .change_context(errors::ApiErrorResponse::InvalidDataValue {
            field_name: "browser_info",
        })?;
    let payment_connector_name = payment_attempt
        .connector
        .as_ref()
        .ok_or(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("missing connector in payment_attempt")?;
    let return_url = Some(helpers::create_authorize_url(
        &state.base_url,
        &payment_attempt.clone(),
        payment_connector_name,
    ));
    let mca_id_option = merchant_connector_account.get_mca_id(); // Bind temporary value
    let merchant_connector_account_id_or_connector_name = mca_id_option
        .as_ref()
        .map(|mca_id| mca_id.get_string_repr())
        .unwrap_or(&authentication_connector);

    let webhook_url = helpers::create_webhook_url(
        &state.base_url,
        merchant_id,
        merchant_connector_account_id_or_connector_name,
    );

    let authentication_details = business_profile
        .authentication_connector_details
        .clone()
        .get_required_value("authentication_connector_details")
        .attach_printable("authentication_connector_details not configured by the merchant")?;

    let authentication_response = if helpers::is_merchant_eligible_authentication_service(
        merchant_context.get_merchant_account().get_id(),
        &state,
    )
    .await?
    {
        let auth_response =
            <ExternalAuthentication as UnifiedAuthenticationService>::authentication(
                &state,
                &business_profile,
                &payment_method_details.1,
                browser_info,
                Some(amount),
                Some(currency),
                authentication::MessageCategory::Payment,
                req.device_channel,
                authentication.clone(),
                return_url,
                req.sdk_information,
                req.threeds_method_comp_ind,
                optional_customer.and_then(|customer| customer.email.map(pii::Email::from)),
                webhook_url,
                &merchant_connector_account,
                &authentication_connector,
                Some(payment_intent.payment_id),
            )
            .await?;
        let authentication = external_authentication_update_trackers(
            &state,
            auth_response,
            authentication.clone(),
            None,
            merchant_context.get_merchant_key_store(),
            None,
            None,
            None,
            None,
        )
        .await?;
        authentication::AuthenticationResponse::try_from(authentication)?
    } else {
        Box::pin(authentication_core::perform_authentication(
            &state,
            business_profile.merchant_id,
            authentication_connector,
            payment_method_details.0,
            payment_method_details.1,
            billing_address
                .as_ref()
                .map(|address| address.into())
                .ok_or(errors::ApiErrorResponse::MissingRequiredField {
                    field_name: "billing_address",
                })?,
            shipping_address.as_ref().map(|address| address.into()),
            browser_info,
            merchant_connector_account,
            Some(amount),
            Some(currency),
            authentication::MessageCategory::Payment,
            req.device_channel,
            authentication,
            return_url,
            req.sdk_information,
            req.threeds_method_comp_ind,
            optional_customer.and_then(|customer| customer.email.map(pii::Email::from)),
            webhook_url,
            authentication_details.three_ds_requestor_url.clone(),
            payment_intent.psd2_sca_exemption_type,
            payment_intent.payment_id,
            payment_intent.force_3ds_challenge_trigger.unwrap_or(false),
            merchant_context.get_merchant_key_store(),
        ))
        .await?
    };
    Ok(services::ApplicationResponse::Json(
        api_models::payments::PaymentsExternalAuthenticationResponse {
            transaction_status: authentication_response.trans_status,
            acs_url: authentication_response
                .acs_url
                .as_ref()
                .map(ToString::to_string),
            challenge_request: authentication_response.challenge_request,
            // If challenge_request_key is None, we send "creq" as a static value which is standard 3DS challenge form field name
            challenge_request_key: authentication_response
                .challenge_request_key
                .or(Some(consts::CREQ_CHALLENGE_REQUEST_KEY.to_string())),
            acs_reference_number: authentication_response.acs_reference_number,
            acs_trans_id: authentication_response.acs_trans_id,
            three_dsserver_trans_id: authentication_response.three_dsserver_trans_id,
            acs_signed_content: authentication_response.acs_signed_content,
            three_ds_requestor_url: authentication_details.three_ds_requestor_url,
            three_ds_requestor_app_url: authentication_details.three_ds_requestor_app_url,
        },
    ))
}

#[instrument(skip_all)]
#[cfg(feature = "v2")]
pub async fn payment_start_redirection(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    req: api_models::payments::PaymentStartRedirectionRequest,
) -> RouterResponse<serde_json::Value> {
    let db = &*state.store;
    let key_manager_state = &(&state).into();

    let storage_scheme = merchant_context.get_merchant_account().storage_scheme;

    let payment_intent = db
        .find_payment_intent_by_id(
            key_manager_state,
            &req.id,
            merchant_context.get_merchant_key_store(),
            storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

    //TODO: send valid html error pages in this case, or atleast redirect to valid html error pages
    utils::when(
        payment_intent.status != storage_enums::IntentStatus::RequiresCustomerAction,
        || {
            Err(errors::ApiErrorResponse::PaymentUnexpectedState {
                current_flow: "PaymentStartRedirection".to_string(),
                field_name: "status".to_string(),
                current_value: payment_intent.status.to_string(),
                states: ["requires_customer_action".to_string()].join(", "),
            })
        },
    )?;

    let payment_attempt = db
        .find_payment_attempt_by_id(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            payment_intent
                .active_attempt_id
                .as_ref()
                .ok_or(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("missing active attempt in payment_intent")?,
            storage_scheme,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Error while fetching payment_attempt")?;
    let redirection_data = payment_attempt
        .redirection_data
        .clone()
        .ok_or(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("missing authentication_data in payment_attempt")?;

    Ok(services::ApplicationResponse::Form(Box::new(
        services::RedirectionFormData {
            redirect_form: redirection_data,
            payment_method_data: None,
            amount: payment_attempt.amount_details.get_net_amount().to_string(),
            currency: payment_intent.amount_details.currency.to_string(),
        },
    )))
}

#[instrument(skip_all)]
pub async fn get_extended_card_info(
    state: SessionState,
    merchant_id: id_type::MerchantId,
    payment_id: id_type::PaymentId,
) -> RouterResponse<payments_api::ExtendedCardInfoResponse> {
    let redis_conn = state
        .store
        .get_redis_conn()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to get redis connection")?;

    let key = helpers::get_redis_key_for_extended_card_info(&merchant_id, &payment_id);
    let payload = redis_conn
        .get_key::<String>(&key.into())
        .await
        .change_context(errors::ApiErrorResponse::ExtendedCardInfoNotFound)?;

    Ok(services::ApplicationResponse::Json(
        payments_api::ExtendedCardInfoResponse { payload },
    ))
}

#[cfg(all(feature = "olap", feature = "v1"))]
pub async fn payments_manual_update(
    state: SessionState,
    req: api_models::payments::PaymentsManualUpdateRequest,
) -> RouterResponse<api_models::payments::PaymentsManualUpdateResponse> {
    let api_models::payments::PaymentsManualUpdateRequest {
        payment_id,
        attempt_id,
        merchant_id,
        attempt_status,
        error_code,
        error_message,
        error_reason,
        connector_transaction_id,
    } = req;
    let key_manager_state = &(&state).into();
    let key_store = state
        .store
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            &merchant_id,
            &state.store.get_master_key().to_vec().into(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)
        .attach_printable("Error while fetching the key store by merchant_id")?;
    let merchant_account = state
        .store
        .find_merchant_account_by_merchant_id(key_manager_state, &merchant_id, &key_store)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)
        .attach_printable("Error while fetching the merchant_account by merchant_id")?;
    let payment_attempt = state
        .store
        .find_payment_attempt_by_payment_id_merchant_id_attempt_id(
            &payment_id,
            &merchant_id,
            &attempt_id.clone(),
            merchant_account.storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
        .attach_printable(
            "Error while fetching the payment_attempt by payment_id, merchant_id and attempt_id",
        )?;

    let payment_intent = state
        .store
        .find_payment_intent_by_payment_id_merchant_id(
            key_manager_state,
            &payment_id,
            merchant_account.get_id(),
            &key_store,
            merchant_account.storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
        .attach_printable("Error while fetching the payment_intent by payment_id, merchant_id")?;

    let option_gsm = if let Some(((code, message), connector_name)) = error_code
        .as_ref()
        .zip(error_message.as_ref())
        .zip(payment_attempt.connector.as_ref())
    {
        helpers::get_gsm_record(
            &state,
            Some(code.to_string()),
            Some(message.to_string()),
            connector_name.to_string(),
            // We need to get the unified_code and unified_message of the Authorize flow
            "Authorize".to_string(),
        )
        .await
    } else {
        None
    };
    // Update the payment_attempt
    let attempt_update = storage::PaymentAttemptUpdate::ManualUpdate {
        status: attempt_status,
        error_code,
        error_message,
        error_reason,
        updated_by: merchant_account.storage_scheme.to_string(),
        unified_code: option_gsm.as_ref().and_then(|gsm| gsm.unified_code.clone()),
        unified_message: option_gsm.and_then(|gsm| gsm.unified_message),
        connector_transaction_id,
    };
    let updated_payment_attempt = state
        .store
        .update_payment_attempt_with_attempt_id(
            payment_attempt.clone(),
            attempt_update,
            merchant_account.storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
        .attach_printable("Error while updating the payment_attempt")?;
    // If the payment_attempt is active attempt for an intent, update the intent status
    if payment_intent.active_attempt.get_id() == payment_attempt.attempt_id {
        let intent_status = enums::IntentStatus::foreign_from(updated_payment_attempt.status);
        let payment_intent_update = storage::PaymentIntentUpdate::ManualUpdate {
            status: Some(intent_status),
            updated_by: merchant_account.storage_scheme.to_string(),
        };
        state
            .store
            .update_payment_intent(
                key_manager_state,
                payment_intent,
                payment_intent_update,
                &key_store,
                merchant_account.storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
            .attach_printable("Error while updating payment_intent")?;
    }
    Ok(services::ApplicationResponse::Json(
        api_models::payments::PaymentsManualUpdateResponse {
            payment_id: updated_payment_attempt.payment_id,
            attempt_id: updated_payment_attempt.attempt_id,
            merchant_id: updated_payment_attempt.merchant_id,
            attempt_status: updated_payment_attempt.status,
            error_code: updated_payment_attempt.error_code,
            error_message: updated_payment_attempt.error_message,
            error_reason: updated_payment_attempt.error_reason,
            connector_transaction_id: updated_payment_attempt.connector_transaction_id,
        },
    ))
}

pub trait PaymentMethodChecker<F> {
    fn should_update_in_post_update_tracker(&self) -> bool;
    fn should_update_in_update_tracker(&self) -> bool;
}
#[cfg(feature = "v1")]
impl<F: Clone> PaymentMethodChecker<F> for PaymentData<F> {
    fn should_update_in_post_update_tracker(&self) -> bool {
        let payment_method_type = self
            .payment_intent
            .tax_details
            .as_ref()
            .and_then(|tax_details| tax_details.payment_method_type.as_ref().map(|pmt| pmt.pmt));

        matches!(
            payment_method_type,
            Some(storage_enums::PaymentMethodType::Paypal)
        )
    }

    fn should_update_in_update_tracker(&self) -> bool {
        let payment_method_type = self
            .payment_intent
            .tax_details
            .as_ref()
            .and_then(|tax_details| tax_details.payment_method_type.as_ref().map(|pmt| pmt.pmt));

        matches!(
            payment_method_type,
            Some(storage_enums::PaymentMethodType::ApplePay)
                | Some(storage_enums::PaymentMethodType::GooglePay)
        )
    }
}

pub trait OperationSessionGetters<F> {
    fn get_payment_attempt(&self) -> &storage::PaymentAttempt;
    #[cfg(feature = "v2")]
    fn list_payments_attempts(&self) -> &Vec<storage::PaymentAttempt>;
    fn get_payment_intent(&self) -> &storage::PaymentIntent;
    #[cfg(feature = "v2")]
    fn get_client_secret(&self) -> &Option<Secret<String>>;
    fn get_payment_method_info(&self) -> Option<&domain::PaymentMethod>;
    fn get_payment_method_token(&self) -> Option<&PaymentMethodToken>;
    fn get_mandate_id(&self) -> Option<&payments_api::MandateIds>;
    fn get_address(&self) -> &PaymentAddress;
    fn get_creds_identifier(&self) -> Option<&str>;
    fn get_token(&self) -> Option<&str>;
    fn get_multiple_capture_data(&self) -> Option<&types::MultipleCaptureData>;
    fn get_payment_link_data(&self) -> Option<api_models::payments::PaymentLinkResponse>;
    fn get_ephemeral_key(&self) -> Option<ephemeral_key::EphemeralKey>;
    fn get_setup_mandate(&self) -> Option<&MandateData>;
    fn get_poll_config(&self) -> Option<router_types::PollConfig>;
    fn get_authentication(
        &self,
    ) -> Option<&hyperswitch_domain_models::router_request_types::authentication::AuthenticationStore>;
    fn get_frm_message(&self) -> Option<FraudCheck>;
    fn get_refunds(&self) -> Vec<diesel_refund::Refund>;
    fn get_disputes(&self) -> Vec<storage::Dispute>;
    fn get_authorizations(&self) -> Vec<diesel_models::authorization::Authorization>;
    fn get_attempts(&self) -> Option<Vec<storage::PaymentAttempt>>;
    fn get_recurring_details(&self) -> Option<&RecurringDetails>;
    // TODO: this should be a mandatory field, should we throw an error instead of returning an Option?
    fn get_payment_intent_profile_id(&self) -> Option<&id_type::ProfileId>;
    fn get_currency(&self) -> storage_enums::Currency;
    fn get_amount(&self) -> api::Amount;
    fn get_payment_attempt_connector(&self) -> Option<&str>;
    fn get_billing_address(&self) -> Option<hyperswitch_domain_models::address::Address>;
    fn get_payment_method_data(&self) -> Option<&domain::PaymentMethodData>;
    fn get_sessions_token(&self) -> Vec<api::SessionToken>;
    fn get_token_data(&self) -> Option<&storage::PaymentTokenData>;
    fn get_mandate_connector(&self) -> Option<&MandateConnectorDetails>;
    fn get_force_sync(&self) -> Option<bool>;
    #[cfg(feature = "v1")]
    fn get_all_keys_required(&self) -> Option<bool>;
    fn get_capture_method(&self) -> Option<enums::CaptureMethod>;
    fn get_merchant_connector_id_in_attempt(&self) -> Option<id_type::MerchantConnectorAccountId>;
    #[cfg(feature = "v2")]
    fn get_merchant_connector_details(
        &self,
    ) -> Option<common_types::domain::MerchantConnectorAuthDetails>;

    fn get_connector_customer_id(&self) -> Option<String>;

    #[cfg(feature = "v1")]
    fn get_whole_connector_response(&self) -> Option<Secret<String>>;

    #[cfg(feature = "v1")]
    fn get_vault_operation(&self) -> Option<&domain_payments::VaultOperation>;

    #[cfg(feature = "v2")]
    fn get_optional_payment_attempt(&self) -> Option<&storage::PaymentAttempt>;

    #[cfg(feature = "v2")]
    fn get_pre_routing_result(
        &self,
    ) -> Option<HashMap<enums::PaymentMethodType, domain::PreRoutingConnectorChoice>>;

    #[cfg(feature = "v2")]
    fn get_optional_external_vault_session_details(&self) -> Option<api::VaultSessionDetails>;
    #[cfg(feature = "v1")]
    fn get_click_to_pay_service_details(&self) -> Option<&api_models::payments::CtpServiceDetails>;

    #[cfg(feature = "v1")]
    fn get_is_manual_retry_enabled(&self) -> Option<bool>;
}

pub trait OperationSessionSetters<F> {
    // Setter functions for PaymentData
    fn set_payment_intent(&mut self, payment_intent: storage::PaymentIntent);
    #[cfg(feature = "v2")]
    fn set_client_secret(&mut self, client_secret: Option<Secret<String>>);
    fn set_payment_attempt(&mut self, payment_attempt: storage::PaymentAttempt);
    fn set_payment_method_data(&mut self, payment_method_data: Option<domain::PaymentMethodData>);
    fn set_payment_method_token(&mut self, payment_method_token: Option<PaymentMethodToken>);
    fn set_email_if_not_present(&mut self, email: pii::Email);
    fn set_payment_method_id_in_attempt(&mut self, payment_method_id: Option<String>);
    fn set_pm_token(&mut self, token: String);
    fn set_connector_customer_id(&mut self, customer_id: Option<String>);
    fn push_sessions_token(&mut self, token: api::SessionToken);
    fn set_surcharge_details(&mut self, surcharge_details: Option<types::SurchargeDetails>);
    fn set_merchant_connector_id_in_attempt(
        &mut self,
        merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
    );
    fn set_card_network(&mut self, card_network: enums::CardNetwork);
    fn set_co_badged_card_data(
        &mut self,
        debit_routing_output: &api_models::open_router::DebitRoutingOutput,
    );
    #[cfg(feature = "v1")]
    fn set_capture_method_in_attempt(&mut self, capture_method: enums::CaptureMethod);
    fn set_frm_message(&mut self, frm_message: FraudCheck);
    fn set_payment_intent_status(&mut self, status: storage_enums::IntentStatus);
    fn set_authentication_type_in_attempt(
        &mut self,
        authentication_type: Option<enums::AuthenticationType>,
    );
    fn set_recurring_mandate_payment_data(
        &mut self,
        recurring_mandate_payment_data:
            hyperswitch_domain_models::router_data::RecurringMandatePaymentData,
    );
    fn set_mandate_id(&mut self, mandate_id: api_models::payments::MandateIds);
    fn set_setup_future_usage_in_payment_intent(
        &mut self,
        setup_future_usage: storage_enums::FutureUsage,
    );

    #[cfg(feature = "v1")]
    fn set_straight_through_algorithm_in_payment_attempt(
        &mut self,
        straight_through_algorithm: serde_json::Value,
    );

    #[cfg(feature = "v2")]
    fn set_prerouting_algorithm_in_payment_intent(
        &mut self,
        straight_through_algorithm: storage::PaymentRoutingInfo,
    );

    fn set_connector_in_payment_attempt(&mut self, connector: Option<String>);

    #[cfg(feature = "v1")]
    fn set_vault_operation(&mut self, vault_operation: domain_payments::VaultOperation);

    #[cfg(feature = "v2")]
    fn set_connector_request_reference_id(&mut self, reference_id: Option<String>);

    fn set_connector_response_reference_id(&mut self, reference_id: Option<String>);

    #[cfg(feature = "v2")]
    fn set_vault_session_details(
        &mut self,
        external_vault_session_details: Option<api::VaultSessionDetails>,
    );
    fn set_routing_approach_in_attempt(&mut self, routing_approach: Option<enums::RoutingApproach>);

    fn set_connector_request_reference_id_in_payment_attempt(
        &mut self,
        connector_request_reference_id: String,
    );
    #[cfg(feature = "v2")]
    fn set_cancellation_reason(&mut self, cancellation_reason: Option<String>);
}

#[cfg(feature = "v1")]
impl<F: Clone> OperationSessionGetters<F> for PaymentData<F> {
    fn get_payment_attempt(&self) -> &storage::PaymentAttempt {
        &self.payment_attempt
    }

    fn get_payment_intent(&self) -> &storage::PaymentIntent {
        &self.payment_intent
    }

    fn get_payment_method_info(&self) -> Option<&domain::PaymentMethod> {
        self.payment_method_info.as_ref()
    }

    fn get_payment_method_token(&self) -> Option<&PaymentMethodToken> {
        self.payment_method_token.as_ref()
    }

    fn get_mandate_id(&self) -> Option<&payments_api::MandateIds> {
        self.mandate_id.as_ref()
    }

    // what is this address find out and not required remove this
    fn get_address(&self) -> &PaymentAddress {
        &self.address
    }
    fn get_merchant_connector_id_in_attempt(&self) -> Option<id_type::MerchantConnectorAccountId> {
        self.payment_attempt.merchant_connector_id.clone()
    }

    fn get_creds_identifier(&self) -> Option<&str> {
        self.creds_identifier.as_deref()
    }

    fn get_token(&self) -> Option<&str> {
        self.token.as_deref()
    }

    fn get_multiple_capture_data(&self) -> Option<&types::MultipleCaptureData> {
        self.multiple_capture_data.as_ref()
    }

    fn get_payment_link_data(&self) -> Option<api_models::payments::PaymentLinkResponse> {
        self.payment_link_data.clone()
    }

    fn get_ephemeral_key(&self) -> Option<ephemeral_key::EphemeralKey> {
        self.ephemeral_key.clone()
    }

    fn get_setup_mandate(&self) -> Option<&MandateData> {
        self.setup_mandate.as_ref()
    }

    fn get_poll_config(&self) -> Option<router_types::PollConfig> {
        self.poll_config.clone()
    }

    fn get_authentication(
        &self,
    ) -> Option<&hyperswitch_domain_models::router_request_types::authentication::AuthenticationStore>
    {
        self.authentication.as_ref()
    }

    fn get_frm_message(&self) -> Option<FraudCheck> {
        self.frm_message.clone()
    }

    fn get_refunds(&self) -> Vec<diesel_refund::Refund> {
        self.refunds.clone()
    }

    fn get_disputes(&self) -> Vec<storage::Dispute> {
        self.disputes.clone()
    }

    fn get_authorizations(&self) -> Vec<diesel_models::authorization::Authorization> {
        self.authorizations.clone()
    }

    fn get_attempts(&self) -> Option<Vec<storage::PaymentAttempt>> {
        self.attempts.clone()
    }

    fn get_recurring_details(&self) -> Option<&RecurringDetails> {
        self.recurring_details.as_ref()
    }

    #[cfg(feature = "v1")]
    fn get_payment_intent_profile_id(&self) -> Option<&id_type::ProfileId> {
        self.payment_intent.profile_id.as_ref()
    }

    #[cfg(feature = "v2")]
    fn get_payment_intent_profile_id(&self) -> Option<&id_type::ProfileId> {
        Some(&self.payment_intent.profile_id)
    }

    fn get_currency(&self) -> storage_enums::Currency {
        self.currency
    }

    fn get_amount(&self) -> api::Amount {
        self.amount
    }


// Implementation: impl Payme
// File: crates/hyperswitch_connectors/src/connectors/payme.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl Payme


// Struct: FrmFilters
// File: crates/api_models/src/analytics/frm.rs
// Module: api_models
// Implementations: 0

pub struct FrmFilters


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

pub struct TrustlyDetails


// Struct: RefundResponse
// File: crates/hyperswitch_connectors/src/connectors/flexiti/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RefundResponse


// File: crates/hyperswitch_interfaces/src/api/authentication.rs
// Module: hyperswitch_interfaces

use hyperswitch_domain_models::{
    router_flow_types::authentication::{
        Authentication, PostAuthentication, PreAuthentication, PreAuthenticationVersionCall,
    },
    router_request_types::authentication::{
        ConnectorAuthenticationRequestData, ConnectorPostAuthenticationRequestData,
        PreAuthNRequestData,
    },
    router_response_types::AuthenticationResponseData,
};

use crate::api::ConnectorIntegration;

/// trait ConnectorAuthentication
pub trait ConnectorAuthentication:
    ConnectorIntegration<Authentication, ConnectorAuthenticationRequestData, AuthenticationResponseData>
{
}

/// trait ConnectorPreAuthentication
pub trait ConnectorPreAuthentication:
    ConnectorIntegration<PreAuthentication, PreAuthNRequestData, AuthenticationResponseData>
{
}

/// trait ConnectorPreAuthenticationVersionCall
pub trait ConnectorPreAuthenticationVersionCall:
    ConnectorIntegration<PreAuthenticationVersionCall, PreAuthNRequestData, AuthenticationResponseData>
{
}

/// trait ConnectorPostAuthentication
pub trait ConnectorPostAuthentication:
    ConnectorIntegration<
    PostAuthentication,
    ConnectorPostAuthenticationRequestData,
    AuthenticationResponseData,
>
{
}

/// trait ExternalAuthentication
pub trait ExternalAuthentication:
    super::ConnectorCommon
    + ConnectorAuthentication
    + ConnectorPreAuthentication
    + ConnectorPreAuthenticationVersionCall
    + ConnectorPostAuthentication
{
}


// File: crates/router/src/utils/storage_partitioning.rs
// Module: router

pub use storage_impl::redis::kv_store::{KvStorePartition, PartitionKey};


// Function: validate
// File: crates/router/src/configs/validations.rs
// Module: router

pub fn validate(&self) -> Result<(), ApplicationError>


// Implementation: impl api::MandateSetup for for Braintree
// File: crates/hyperswitch_connectors/src/connectors/braintree.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::MandateSetup for for Braintree


// Function: form_payments_info
// File: crates/router/src/core/payment_methods.rs
// Module: router

pub fn form_payments_info(
        payment_intent: PaymentIntent,
        merchant_context: &domain::MerchantContext,
        profile: domain::Profile,
        db: &dyn StorageInterface,
        key_manager_state: &util_types::keymanager::KeyManagerState,
    ) -> RouterResult<Self>


// Struct: PaymentGetListAttempts
// File: crates/hyperswitch_domain_models/src/router_flow_types/payments.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct PaymentGetListAttempts


// Struct: StripePaymentCancelRequest
// File: crates/router/src/compatibility/stripe/payment_intents/types.rs
// Module: router
// Implementations: 0

pub struct StripePaymentCancelRequest


// Struct: CeleroTransactionResponseData
// File: crates/hyperswitch_connectors/src/connectors/celero/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 1

pub struct CeleroTransactionResponseData


// Implementation: impl PayoutAttemptUpdate
// File: crates/diesel_models/src/payout_attempt.rs
// Module: diesel_models
// Methods: 1 total (1 public)

impl PayoutAttemptUpdate


// Module Structure
// File: crates/hyperswitch_connectors/src/connectors/tokenio.rs
// Module: hyperswitch_connectors

// Public submodules:
pub mod transformers;


// Function: find_by_payment_method_id
// File: crates/diesel_models/src/query/payment_method.rs
// Module: diesel_models

pub fn find_by_payment_method_id(
        conn: &PgPooledConn,
        payment_method_id: &str,
    ) -> StorageResult<Self>


// Function: check_ppcp_custom_status
// File: crates/router/src/types/api/connector_onboarding/paypal.rs
// Module: router

pub fn check_ppcp_custom_status(&self) -> Option<api::PayPalOnboardingStatus>


// Struct: PaymentThreshold
// File: crates/hyperswitch_connectors/src/connectors/coinbase/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentThreshold


#[cfg(feature = "v2")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsPostSessionTokensData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        todo!()
    }
}

#[cfg(feature = "v1")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsPostSessionTokensData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        let payment_data = additional_data.payment_data.clone();
        let surcharge_amount = payment_data
            .surcharge_details
            .as_ref()
            .map(|surcharge_details| surcharge_details.get_total_surcharge_amount())
            .unwrap_or_default();
        let shipping_cost = payment_data
            .payment_intent
            .shipping_cost
            .unwrap_or_default();
        // amount here would include amount, surcharge_amount and shipping_cost
        let amount = payment_data.payment_intent.amount + shipping_cost + surcharge_amount;
        let merchant_order_reference_id = payment_data
            .payment_intent
            .merchant_order_reference_id
            .clone();
        let router_base_url = &additional_data.router_base_url;
        let connector_name = &additional_data.connector_name;
        let attempt = &payment_data.payment_attempt;
        let router_return_url = Some(helpers::create_redirect_url(
            router_base_url,
            attempt,
            connector_name,
            payment_data.creds_identifier.as_deref(),
        ));
        Ok(Self {
            amount, //need to change after we move to connector module
            order_amount: payment_data.payment_intent.amount,
            currency: payment_data.currency,
            merchant_order_reference_id,
            capture_method: payment_data.payment_attempt.capture_method,
            shipping_cost: payment_data.payment_intent.shipping_cost,
            setup_future_usage: payment_data.payment_attempt.setup_future_usage_applied,
            router_return_url,
        })
    }
}

#[cfg(feature = "v2")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsUpdateMetadataData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        todo!()
    }
}

#[cfg(feature = "v1")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsUpdateMetadataData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        let payment_data = additional_data.payment_data.clone();
        let connector = api::ConnectorData::get_connector_by_name(
            &additional_data.state.conf.connectors,
            &additional_data.connector_name,
            api::GetToken::Connector,
            payment_data.payment_attempt.merchant_connector_id.clone(),
        )?;
        Ok(Self {
            metadata: payment_data
                .payment_intent
                .metadata
                .map(Secret::new)
                .ok_or(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("payment_intent.metadata not found")?,
            connector_transaction_id: connector
                .connector
                .connector_transaction_id(&payment_data.payment_attempt)?
                .ok_or(errors::ApiErrorResponse::ResourceIdNotFound)?,
        })
    }
}

impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsRejectData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        let payment_data = additional_data.payment_data;
        let amount = payment_data.payment_attempt.get_total_amount();
        Ok(Self {
            amount: Some(amount.get_amount_as_i64()), //need to change after we move to connector module
            currency: Some(payment_data.currency),
        })
    }
}

#[cfg(feature = "v2")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsSessionData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        let payment_data = additional_data.payment_data.clone();

        let order_details = additional_data
            .payment_data
            .payment_intent
            .order_details
            .map(|order_details| {
                order_details
                    .iter()
                    .map(|data| data.to_owned().expose())
                    .collect()
            });

        let surcharge_amount = payment_data
            .surcharge_details
            .as_ref()
            .map(|surcharge_details| surcharge_details.get_total_surcharge_amount())
            .unwrap_or_default();

        let amount = payment_data.payment_intent.amount_details.order_amount;

        let shipping_cost = payment_data
            .payment_intent
            .amount_details
            .shipping_cost
            .unwrap_or_default();

        // net_amount here would include amount, surcharge_amount and shipping_cost
        let net_amount = amount + surcharge_amount + shipping_cost;

        let required_amount_type = StringMajorUnitForConnector;

        let apple_pay_amount = required_amount_type
            .convert(net_amount, payment_data.currency)
            .change_context(errors::ApiErrorResponse::PreconditionFailed {
                message: "Failed to convert amount to string major unit for applePay".to_string(),
            })?;

        let apple_pay_recurring_details = payment_data
            .payment_intent
            .feature_metadata
            .and_then(|feature_metadata| feature_metadata.apple_pay_recurring_details)
            .map(|apple_pay_recurring_details| {
                ForeignInto::foreign_into((apple_pay_recurring_details, apple_pay_amount))
            });

        let order_tax_amount = payment_data
            .payment_intent
            .amount_details
            .tax_details
            .clone()
            .and_then(|tax| tax.get_default_tax_amount());

        Ok(Self {
            amount: amount.get_amount_as_i64(), //need to change once we move to connector module
            minor_amount: amount,
            currency: payment_data.currency,
            country: payment_data.address.get_payment_method_billing().and_then(
                |billing_address| {
                    billing_address
                        .address
                        .as_ref()
                        .and_then(|address| address.country)
                },
            ),
            order_details,
            surcharge_details: payment_data.surcharge_details,
            email: payment_data.email,
            apple_pay_recurring_details,
            customer_name: None,
            metadata: payment_data.payment_intent.metadata,
            order_tax_amount,
            shipping_cost: payment_data.payment_intent.amount_details.shipping_cost,
        })
    }
}

#[cfg(feature = "v1")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsSessionData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        let payment_data = additional_data.payment_data.clone();

        let order_details = additional_data
            .payment_data
            .payment_intent
            .order_details
            .map(|order_details| {
                order_details
                    .iter()
                    .map(|data| {
                        data.to_owned()
                            .parse_value("OrderDetailsWithAmount")
                            .change_context(errors::ApiErrorResponse::InvalidDataValue {
                                field_name: "OrderDetailsWithAmount",
                            })
                            .attach_printable("Unable to parse OrderDetailsWithAmount")
                    })
                    .collect::<Result<Vec<_>, _>>()
            })
            .transpose()?;

        let surcharge_amount = payment_data
            .surcharge_details
            .as_ref()
            .map(|surcharge_details| surcharge_details.get_total_surcharge_amount())
            .unwrap_or_default();

        let amount = payment_data.payment_intent.amount;

        let shipping_cost = payment_data
            .payment_intent
            .shipping_cost
            .unwrap_or_default();

        // net_amount here would include amount, surcharge_amount and shipping_cost
        let net_amount = amount + surcharge_amount + shipping_cost;

        let required_amount_type = StringMajorUnitForConnector;

        let apple_pay_amount = required_amount_type
            .convert(net_amount, payment_data.currency)
            .change_context(errors::ApiErrorResponse::PreconditionFailed {
                message: "Failed to convert amount to string major unit for applePay".to_string(),
            })?;

        let apple_pay_recurring_details = payment_data
            .payment_intent
            .feature_metadata
            .map(|feature_metadata| {
                feature_metadata
                    .parse_value::<diesel_models::types::FeatureMetadata>("FeatureMetadata")
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed parsing FeatureMetadata")
            })
            .transpose()?
            .and_then(|feature_metadata| feature_metadata.apple_pay_recurring_details)
            .map(|apple_pay_recurring_details| {
                ForeignFrom::foreign_from((apple_pay_recurring_details, apple_pay_amount))
            });

        let order_tax_amount = payment_data
            .payment_intent
            .tax_details
            .clone()
            .and_then(|tax| tax.get_default_tax_amount());

        let shipping_cost = payment_data.payment_intent.shipping_cost;

        let metadata = payment_data
            .payment_intent
            .metadata
            .clone()
            .map(Secret::new);

        Ok(Self {
            amount: net_amount.get_amount_as_i64(), //need to change once we move to connector module
            minor_amount: amount,
            currency: payment_data.currency,
            country: payment_data.address.get_payment_method_billing().and_then(
                |billing_address| {
                    billing_address
                        .address
                        .as_ref()
                        .and_then(|address| address.country)
                },
            ),
            order_details,
            email: payment_data.email,
            surcharge_details: payment_data.surcharge_details,
            apple_pay_recurring_details,
            customer_name: None,
            order_tax_amount,
            shipping_cost,
            metadata,
        })
    }
}

impl
    ForeignFrom<(
        diesel_models::types::ApplePayRecurringDetails,
        StringMajorUnit,
    )> for api_models::payments::ApplePayRecurringPaymentRequest
{
    fn foreign_from(
        (apple_pay_recurring_details, net_amount): (
            diesel_models::types::ApplePayRecurringDetails,
            StringMajorUnit,
        ),
    ) -> Self {
        Self {
            payment_description: apple_pay_recurring_details.payment_description,
            regular_billing: api_models::payments::ApplePayRegularBillingRequest {
                amount: net_amount,
                label: apple_pay_recurring_details.regular_billing.label,
                payment_timing: api_models::payments::ApplePayPaymentTiming::Recurring,
                recurring_payment_start_date: apple_pay_recurring_details
                    .regular_billing
                    .recurring_payment_start_date,
                recurring_payment_end_date: apple_pay_recurring_details
                    .regular_billing
                    .recurring_payment_end_date,
                recurring_payment_interval_unit: apple_pay_recurring_details
                    .regular_billing
                    .recurring_payment_interval_unit
                    .map(ForeignFrom::foreign_from),
                recurring_payment_interval_count: apple_pay_recurring_details
                    .regular_billing
                    .recurring_payment_interval_count,
            },
            billing_agreement: apple_pay_recurring_details.billing_agreement,
            management_u_r_l: apple_pay_recurring_details.management_url,
        }
    }
}

impl ForeignFrom<diesel_models::types::ApplePayRecurringDetails>
    for api_models::payments::ApplePayRecurringDetails
{
    fn foreign_from(
        apple_pay_recurring_details: diesel_models::types::ApplePayRecurringDetails,
    ) -> Self {
        Self {
            payment_description: apple_pay_recurring_details.payment_description,
            regular_billing: ForeignFrom::foreign_from(apple_pay_recurring_details.regular_billing),
            billing_agreement: apple_pay_recurring_details.billing_agreement,
            management_url: apple_pay_recurring_details.management_url,
        }
    }
}

impl ForeignFrom<diesel_models::types::ApplePayRegularBillingDetails>
    for api_models::payments::ApplePayRegularBillingDetails
{
    fn foreign_from(
        apple_pay_regular_billing: diesel_models::types::ApplePayRegularBillingDetails,
    ) -> Self {
        Self {
            label: apple_pay_regular_billing.label,
            recurring_payment_start_date: apple_pay_regular_billing.recurring_payment_start_date,
            recurring_payment_end_date: apple_pay_regular_billing.recurring_payment_end_date,
            recurring_payment_interval_unit: apple_pay_regular_billing
                .recurring_payment_interval_unit
                .map(ForeignFrom::foreign_from),
            recurring_payment_interval_count: apple_pay_regular_billing
                .recurring_payment_interval_count,
        }
    }
}

impl ForeignFrom<diesel_models::types::RecurringPaymentIntervalUnit>
    for api_models::payments::RecurringPaymentIntervalUnit
{
    fn foreign_from(
        apple_pay_recurring_payment_interval_unit: diesel_models::types::RecurringPaymentIntervalUnit,
    ) -> Self {
        match apple_pay_recurring_payment_interval_unit {
            diesel_models::types::RecurringPaymentIntervalUnit::Day => Self::Day,
            diesel_models::types::RecurringPaymentIntervalUnit::Month => Self::Month,
            diesel_models::types::RecurringPaymentIntervalUnit::Year => Self::Year,
            diesel_models::types::RecurringPaymentIntervalUnit::Hour => Self::Hour,
            diesel_models::types::RecurringPaymentIntervalUnit::Minute => Self::Minute,
        }
    }
}

impl ForeignFrom<diesel_models::types::RedirectResponse>
    for api_models::payments::RedirectResponse
{
    fn foreign_from(redirect_res: diesel_models::types::RedirectResponse) -> Self {
        Self {
            param: redirect_res.param,
            json_payload: redirect_res.json_payload,
        }
    }
}

#[cfg(feature = "v1")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::SetupMandateRequestData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        let payment_data = additional_data.payment_data;
        let router_base_url = &additional_data.router_base_url;
        let connector_name = &additional_data.connector_name;
        let attempt = &payment_data.payment_attempt;
        let router_return_url = Some(helpers::create_redirect_url(
            router_base_url,
            attempt,
            connector_name,
            payment_data.creds_identifier.as_deref(),
        ));
        let browser_info: Option<types::BrowserInformation> = attempt
            .browser_info
            .clone()
            .map(|b| b.parse_value("BrowserInformation"))
            .transpose()
            .change_context(errors::ApiErrorResponse::InvalidDataValue {
                field_name: "browser_info",
            })?;

        let customer_name = additional_data
            .customer_data
            .as_ref()
            .and_then(|customer_data| {
                customer_data
                    .name
                    .as_ref()
                    .map(|customer| customer.clone().into_inner())
            });
        let amount = payment_data.payment_attempt.get_total_amount();
        let merchant_connector_account_id_or_connector_name = payment_data
            .payment_attempt
            .merchant_connector_id
            .as_ref()
            .map(|mca_id| mca_id.get_string_repr())
            .unwrap_or(connector_name);
        let webhook_url = Some(helpers::create_webhook_url(
            router_base_url,
            &attempt.merchant_id,
            merchant_connector_account_id_or_connector_name,
        ));
        let complete_authorize_url = Some(helpers::create_complete_authorize_url(
            router_base_url,
            attempt,
            connector_name,
            payment_data.creds_identifier.as_deref(),
        ));

        let connector = api_models::enums::Connector::from_str(connector_name)
            .change_context(errors::ConnectorError::InvalidConnectorName)
            .change_context(errors::ApiErrorResponse::InvalidDataValue {
                field_name: "connector",
            })
            .attach_printable_lazy(|| {
                format!("unable to parse connector name {connector_name:?}")
            })?;

        let connector_testing_data = payment_data
            .payment_intent
            .connector_metadata
            .as_ref()
            .map(|cm| {
                cm.clone()
                    .parse_value::<api_models::payments::ConnectorMetadata>("ConnectorMetadata")
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed parsing ConnectorMetadata")
            })
            .transpose()?
            .and_then(|cm| match connector {
                api_models::enums::Connector::Adyen => cm
                    .adyen
                    .map(|adyen_cm| adyen_cm.testing)
                    .map(|testing_data| {
                        serde_json::to_value(testing_data)
                            .change_context(errors::ApiErrorResponse::InternalServerError)
                            .attach_printable("Failed to parse Adyen testing data")
                    }),
                _ => None,
            })
            .transpose()?
            .map(pii::SecretSerdeValue::new);

        let is_off_session = get_off_session(
            payment_data.mandate_id.as_ref(),
            payment_data.payment_intent.off_session,
        );

        Ok(Self {
            currency: payment_data.currency,
            confirm: true,
            amount: Some(amount.get_amount_as_i64()), //need to change once we move to connector module
            minor_amount: Some(amount),
            payment_method_data: (payment_data
                .payment_method_data
                .get_required_value("payment_method_data")?),
            statement_descriptor_suffix: payment_data.payment_intent.statement_descriptor_suffix,
            setup_future_usage: payment_data.payment_attempt.setup_future_usage_applied,
            off_session: is_off_session,
            mandate_id: payment_data.mandate_id.clone(),
            setup_mandate_details: payment_data.setup_mandate,
            customer_acceptance: payment_data.customer_acceptance,
            router_return_url,
            email: payment_data.email,
            customer_name,
            return_url: payment_data.payment_intent.return_url,
            browser_info,
            payment_method_type: attempt.payment_method_type,
            request_incremental_authorization: matches!(
                payment_data
                    .payment_intent
                    .request_incremental_authorization,
                Some(RequestIncrementalAuthorization::True)
            ),
            metadata: payment_data.payment_intent.metadata.clone().map(Into::into),
            shipping_cost: payment_data.payment_intent.shipping_cost,
            webhook_url,
            complete_authorize_url,
            capture_method: payment_data.payment_attempt.capture_method,
            connector_testing_data,
            customer_id: payment_data.payment_intent.customer_id,
            enable_partial_authorization: payment_data.payment_intent.enable_partial_authorization,
            payment_channel: payment_data.payment_intent.payment_channel,
            related_transaction_id: None,
            enrolled_for_3ds: true,
            is_stored_credential: payment_data.payment_attempt.is_stored_credential,
        })
    }
}

#[cfg(feature = "v2")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::SetupMandateRequestData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        todo!()
    }
}

impl ForeignTryFrom<types::CaptureSyncResponse> for storage::CaptureUpdate {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn foreign_try_from(
        capture_sync_response: types::CaptureSyncResponse,
    ) -> Result<Self, Self::Error> {
        match capture_sync_response {
            types::CaptureSyncResponse::Success {
                resource_id,
                status,
                connector_response_reference_id,
                ..
            } => {
                let (connector_capture_id, processor_capture_data) = match resource_id {
                    types::ResponseId::EncodedData(_) | types::ResponseId::NoResponseId => {
                        (None, None)
                    }
                    types::ResponseId::ConnectorTransactionId(id) => {
                        let (txn_id, txn_data) =
                            common_utils_type::ConnectorTransactionId::form_id_and_data(id);
                        (Some(txn_id), txn_data)
                    }
                };
                Ok(Self::ResponseUpdate {
                    status: enums::CaptureStatus::foreign_try_from(status)?,
                    connector_capture_id,
                    connector_response_reference_id,
                    processor_capture_data,
                })
            }
            types::CaptureSyncResponse::Error {
                code,
                message,
                reason,
                status_code,
                ..
            } => Ok(Self::ErrorUpdate {
                status: match status_code {
                    500..=511 => enums::CaptureStatus::Pending,
                    _ => enums::CaptureStatus::Failed,
                },
                error_code: Some(code),
                error_message: Some(message),
                error_reason: reason,
            }),
        }
    }
}

#[cfg(feature = "v1")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::CompleteAuthorizeData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        let payment_data = additional_data.payment_data;
        let router_base_url = &additional_data.router_base_url;
        let connector_name = &additional_data.connector_name;
        let attempt = &payment_data.payment_attempt;
        let browser_info: Option<types::BrowserInformation> = payment_data
            .payment_attempt
            .browser_info
            .clone()
            .map(|b| b.parse_value("BrowserInformation"))
            .transpose()
            .change_context(errors::ApiErrorResponse::InvalidDataValue {
                field_name: "browser_info",
            })?;

        let redirect_response = payment_data.redirect_response.map(|redirect| {
            types::CompleteAuthorizeRedirectResponse {
                params: redirect.param,
                payload: redirect.json_payload,
            }
        });
        let amount = payment_data.payment_attempt.get_total_amount();
        let complete_authorize_url = Some(helpers::create_complete_authorize_url(
            router_base_url,
            attempt,
            connector_name,
            payment_data.creds_identifier.as_deref(),
        ));
        let braintree_metadata = payment_data
            .payment_intent
            .connector_metadata
            .clone()
            .map(|cm| {
                cm.parse_value::<api_models::payments::ConnectorMetadata>("ConnectorMetadata")
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed parsing ConnectorMetadata")
            })
            .transpose()?
            .and_then(|cm| cm.braintree);

        let merchant_account_id = braintree_metadata
            .as_ref()
            .and_then(|braintree| braintree.merchant_account_id.clone());
        let merchant_config_currency =
            braintree_metadata.and_then(|braintree| braintree.merchant_config_currency);

        let is_off_session = get_off_session(
            payment_data.mandate_id.as_ref(),
            payment_data.payment_intent.off_session,
        );

        Ok(Self {
            setup_future_usage: payment_data.payment_intent.setup_future_usage,
            mandate_id: payment_data.mandate_id.clone(),
            off_session: is_off_session,
            setup_mandate_details: payment_data.setup_mandate.clone(),
            confirm: payment_data.payment_attempt.confirm,
            statement_descriptor_suffix: payment_data.payment_intent.statement_descriptor_suffix,
            capture_method: payment_data.payment_attempt.capture_method,
            amount: amount.get_amount_as_i64(), // need to change once we move to connector module
            minor_amount: amount,
            currency: payment_data.currency,
            browser_info,
            email: payment_data.email,
            payment_method_data: payment_data.payment_method_data,
            connector_transaction_id: payment_data
                .payment_attempt
                .get_connector_payment_id()
                .map(ToString::to_string),
            redirect_response,
            connector_meta: payment_data.payment_attempt.connector_metadata,
            complete_authorize_url,
            metadata: payment_data.payment_intent.metadata,
            customer_acceptance: payment_data.customer_acceptance,
            merchant_account_id,
            merchant_config_currency,
            threeds_method_comp_ind: payment_data.threeds_method_comp_ind,
            is_stored_credential: payment_data.payment_attempt.is_stored_credential,
        })
    }
}

#[cfg(feature = "v2")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::CompleteAuthorizeData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        todo!()
    }
}

#[cfg(feature = "v2")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsPreProcessingData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        todo!()
    }
}

#[cfg(feature = "v1")]
impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsPreProcessingData {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
        let payment_data = additional_data.payment_data;
        let payment_method_data = payment_data.payment_method_data;
        let router_base_url = &additional_data.router_base_url;
        let attempt = &payment_data.payment_attempt;
        let connector_name = &additional_data.connector_name;

        let order_details = payment_data
            .payment_intent
            .order_details
            .map(|order_details| {
                order_details
                    .iter()
                    .map(|data| {
                        data.to_owned()
                            .parse_value("OrderDetailsWithAmount")
                            .change_context(errors::ApiErrorResponse::InvalidDataValue {
                                field_name: "OrderDetailsWithAmount",
                            })
                            .attach_printable("Unable to parse OrderDetailsWithAmount")
                    })
                    .collect::<Result<Vec<_>, _>>()
            })
            .transpose()?;
        let merchant_connector_account_id_or_connector_name = payment_data
            .payment_attempt
            .merchant_connector_id
            .as_ref()
            .map(|mca_id| mca_id.get_string_repr())
            .unwrap_or(connector_name);
        let webhook_url = Some(helpers::create_webhook_url(
            router_base_url,
            &attempt.merchant_id,
            merchant_connector_account_id_or_connector_name,
        ));
        let router_return_url = Some(helpers::create_redirect_url(
            router_base_url,
            attempt,
            connector_name,
            payment_data.creds_identifier.as_deref(),
        ));
        let complete_authorize_url = Some(helpers::create_complete_authorize_url(
            router_base_url,
            attempt,
            connector_name,
            payment_data.creds_identifier.as_deref(),
        ));
        let browser_info: Option<types::BrowserInformation> = payment_data
            .payment_attempt
            .browser_info
            .clone()
            .map(|b| b.parse_value("BrowserInformation"))
            .transpose()
            .change_context(errors::ApiErrorResponse::InvalidDataValue {
                field_name: "browser_info",
            })?;
        let amount = payment_data.payment_attempt.get_total_amount();
        Ok(Self {
            payment_method_data,
            email: payment_data.email,
            currency: Some(payment_data.currency),
            amount: Some(amount.get_amount_as_i64()), // need to change this once we move to connector module
            minor_amount: Some(amount),
            payment_method_type: payment_data.payment_attempt.payment_method_type,
            setup_mandate_details: payment_data.setup_mandate,
            capture_method: payment_data.payment_attempt.capture_method,
            order_details,
            router_return_url,
            webhook_url,
            complete_authorize_url,
            browser_info,
            surcharge_details: payment_data.surcharge_details,
            connector_transaction_id: payment_data
                .payment_attempt
                .get_connector_payment_id()
                .map(ToString::to_string),
            redirect_response: None,
            mandate_id: payment_data.mandate_id,
            related_transaction_id: None,
            enrolled_for_3ds: true,
            split_payments: payment_data.payment_intent.split_payments,
            metadata: payment_data.payment_intent.metadata.map(Secret::new),
            customer_acceptance: payment_data.customer_acceptance,
            setup_future_usage: payment_data.payment_intent.setup_future_usage,
            is_stored_credential: payment_data.payment_attempt.is_stored_credential,
        })
    }
}

impl ForeignFrom<payments::FraudCheck> for FrmMessage {
    fn foreign_from(fraud_check: payments::FraudCheck) -> Self {
        Self {
            frm_name: fraud_check.frm_name,
            frm_transaction_id: fraud_check.frm_transaction_id,
            frm_transaction_type: Some(fraud_check.frm_transaction_type.to_string()),
            frm_status: Some(fraud_check.frm_status.to_string()),
            frm_score: fraud_check.frm_score,
            frm_reason: fraud_check.frm_reason,
            frm_error: fraud_check.frm_error,
        }
    }
}

impl ForeignFrom<CustomerDetails> for router_request_types::CustomerDetails {
    fn foreign_from(customer: CustomerDetails) -> Self {
        Self {
            customer_id: Some(customer.id),
            name: customer.name,
            email: customer.email,
            phone: customer.phone,
            phone_country_code: customer.phone_country_code,
            tax_registration_id: customer.tax_registration_id,
        }
    }
}

/// The response amount details in the confirm intent response will have the combined fields from
/// intent amount details and attempt amount details.
#[cfg(feature = "v2")]
impl
    ForeignFrom<(
        &hyperswitch_domain_models::payments::AmountDetails,
        &hyperswitch_domain_models::payments::payment_attempt::AttemptAmountDetails,
    )> for api_models::payments::PaymentAmountDetailsResponse
{
    fn foreign_from(
        (intent_amount_details, attempt_amount_details): (
            &hyperswitch_domain_models::payments::AmountDetails,
            &hyperswitch_domain_models::payments::payment_attempt::AttemptAmountDetails,
        ),
    ) -> Self {
        Self {
            order_amount: intent_amount_details.order_amount,
            currency: intent_amount_details.currency,
            shipping_cost: attempt_amount_details.get_shipping_cost(),
            order_tax_amount: attempt_amount_details.get_order_tax_amount(),
            external_tax_calculation: intent_amount_details.skip_external_tax_calculation,
            surcharge_calculation: intent_amount_details.skip_surcharge_calculation,
            surcharge_amount: attempt_amount_details.get_surcharge_amount(),
            tax_on_surcharge: attempt_amount_details.get_tax_on_surcharge(),
            net_amount: attempt_amount_details.get_net_amount(),
            amount_to_capture: attempt_amount_details.get_amount_to_capture(),
            amount_capturable: attempt_amount_details.get_amount_capturable(),
            amount_captured: intent_amount_details.amount_captured,
        }
    }
}

/// The response amount details in the confirm intent response will have the combined fields from
/// intent amount details and attempt amount details.
#[cfg(feature = "v2")]
impl
    ForeignFrom<(
        &hyperswitch_domain_models::payments::AmountDetails,
        Option<&hyperswitch_domain_models::payments::payment_attempt::AttemptAmountDetails>,
    )> for api_models::payments::PaymentAmountDetailsResponse
{
    fn foreign_from(
        (intent_amount_details, attempt_amount_details): (
            &hyperswitch_domain_models::payments::AmountDetails,
            Option<&hyperswitch_domain_models::payments::payment_attempt::AttemptAmountDetails>,
        ),
    ) -> Self {
        Self {
            order_amount: intent_amount_details.order_amount,
            currency: intent_amount_details.currency,
            shipping_cost: attempt_amount_details
                .and_then(|attempt_amount| attempt_amount.get_shipping_cost())
                .or(intent_amount_details.shipping_cost),
            order_tax_amount: attempt_amount_details
                .and_then(|attempt_amount| attempt_amount.get_order_tax_amount())
                .or(intent_amount_details
                    .tax_details
                    .as_ref()
                    .and_then(|tax_details| tax_details.get_default_tax_amount())),
            external_tax_calculation: intent_amount_details.skip_external_tax_calculation,
            surcharge_calculation: intent_amount_details.skip_surcharge_calculation,
            surcharge_amount: attempt_amount_details
                .and_then(|attempt| attempt.get_surcharge_amount())
                .or(intent_amount_details.surcharge_amount),
            tax_on_surcharge: attempt_amount_details
                .and_then(|attempt| attempt.get_tax_on_surcharge())
                .or(intent_amount_details.tax_on_surcharge),
            net_amount: attempt_amount_details
                .map(|attempt| attempt.get_net_amount())
                .unwrap_or(intent_amount_details.calculate_net_amount()),
            amount_to_capture: attempt_amount_details
                .and_then(|attempt| attempt.get_amount_to_capture()),
            amount_capturable: attempt_amount_details
                .map(|attempt| attempt.get_amount_capturable())
                .unwrap_or(MinorUnit::zero()),
            amount_captured: intent_amount_details.amount_captured,
        }
    }
}

#[cfg(feature = "v2")]
impl ForeignFrom<&hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt>
    for api_models::payments::PaymentAttemptResponse
{
    fn foreign_from(
        attempt: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
    ) -> Self {
        let payment_method_data: Option<
            api_models::payments::PaymentMethodDataResponseWithBilling,
        > = attempt
            .payment_method_data
            .clone()
            .and_then(|data| serde_json::from_value(data.expose().clone()).ok());
        Self {
            id: attempt.get_id().to_owned(),
            status: attempt.status,
            amount: api_models::payments::PaymentAttemptAmountDetails::foreign_from(
                &attempt.amount_details,
            ),
            connector: attempt.connector.clone(),
            error: attempt
                .error
                .as_ref()
                .map(api_models::payments::ErrorDetails::foreign_from),
            authentication_type: attempt.authentication_type,
            created_at: attempt.created_at,
            modified_at: attempt.modified_at,
            cancellation_reason: attempt.cancellation_reason.clone(),
            payment_token: attempt
                .connector_token_details
                .as_ref()
                .and_then(|details| details.connector_mandate_id.clone()),
            connector_metadata: attempt.connector_metadata.clone(),
            payment_experience: attempt.payment_experience,
            payment_method_type: attempt.payment_method_type,
            connector_reference_id: attempt.connector_response_reference_id.clone(),
            payment_method_subtype: attempt.get_payment_method_type(),
            connector_payment_id: attempt
                .get_connector_payment_id()
                .map(|str| common_utils::types::ConnectorTransactionId::from(str.to_owned())),
            payment_method_id: attempt.payment_method_id.clone(),
            client_source: attempt.client_source.clone(),
            client_version: attempt.client_version.clone(),
            feature_metadata: attempt
                .feature_metadata
                .as_ref()
                .map(api_models::payments::PaymentAttemptFeatureMetadata::foreign_from),
            payment_method_data,
        }
    }
}

#[cfg(feature = "v2")]
impl ForeignFrom<&hyperswitch_domain_models::payments::payment_attempt::AttemptAmountDetails>
    for api_models::payments::PaymentAttemptAmountDetails
{
    fn foreign_from(
        amount: &hyperswitch_domain_models::payments::payment_attempt::AttemptAmountDetails,
    ) -> Self {
        Self {
            net_amount: amount.get_net_amount(),
            amount_to_capture: amount.get_amount_to_capture(),
            surcharge_amount: amount.get_surcharge_amount(),
            tax_on_surcharge: amount.get_tax_on_surcharge(),
            amount_capturable: amount.get_amount_capturable(),
            shipping_cost: amount.get_shipping_cost(),
            order_tax_amount: amount.get_order_tax_amount(),
        }
    }
}

#[cfg(feature = "v2")]
impl ForeignFrom<&diesel_models::types::BillingConnectorPaymentDetails>
    for api_models::payments::BillingConnectorPaymentDetails
{
    fn foreign_from(metadata: &diesel_models::types::BillingConnectorPaymentDetails) -> Self {
        Self {
            payment_processor_token: metadata.payment_processor_token.clone(),
            connector_customer_id: metadata.connector_customer_id.clone(),
        }
    }
}

#[cfg(feature = "v2")]
impl ForeignFrom<&diesel_models::types::BillingConnectorPaymentMethodDetails>
    for api_models::payments::BillingConnectorPaymentMethodDetails
{
    fn foreign_from(metadata: &diesel_models::types::BillingConnectorPaymentMethodDetails) -> Self {
        match metadata {
            diesel_models::types::BillingConnectorPaymentMethodDetails::Card(card_details) => {
                Self::Card(api_models::payments::BillingConnectorAdditionalCardInfo {
                    card_issuer: card_details.card_issuer.clone(),
                    card_network: card_details.card_network.clone(),
                })
            }
        }
    }
}

#[cfg(feature = "v2")]
impl ForeignFrom<&hyperswitch_domain_models::payments::payment_attempt::ErrorDetails>
    for api_models::payments::ErrorDetails
{
    fn foreign_from(
        error_details: &hyperswitch_domain_models::payments::payment_attempt::ErrorDetails,
    ) -> Self {
        Self {
            code: error_details.code.to_owned(),
            message: error_details.message.to_owned(),
            unified_code: error_details.unified_code.clone(),
            unified_message: error_details.unified_message.clone(),
            network_advice_code: error_details.network_advice_code.clone(),
            network_decline_code: error_details.network_decline_code.clone(),
            network_error_message: error_details.network_error_message.clone(),
        }
    }
}

#[cfg(feature = "v2")]
impl
    ForeignFrom<
        &hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptFeatureMetadata,
    > for api_models::payments::PaymentAttemptFeatureMetadata
{
    fn foreign_from(
        feature_metadata: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptFeatureMetadata,
    ) -> Self {
        let revenue_recovery = feature_metadata.revenue_recovery.as_ref().map(|recovery| {
            api_models::payments::PaymentAttemptRevenueRecoveryData {
                attempt_triggered_by: recovery.attempt_triggered_by,
                charge_id: recovery.charge_id.clone(),
            }
        });
        Self { revenue_recovery }
    }
}

#[cfg(feature = "v2")]
impl ForeignFrom<&diesel_models::types::FeatureMetadata> for api_models::payments::FeatureMetadata {


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

// Documentation: Indicates whether the syncing with the connector should be allowed or not

pub fn should_force_sync_with_connector(self) -> bool


// Struct: ResultData
// File: crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ResultData


// File: crates/analytics/src/sdk_events.rs
// Module: analytics

pub mod accumulator;
mod core;
pub mod events;
pub mod filters;
pub mod metrics;
pub mod types;
pub use accumulator::{SdkEventMetricAccumulator, SdkEventMetricsAccumulator};

pub use self::core::{get_filters, get_metrics, sdk_events_core};


// Struct: CreateCustomerResponse
// File: crates/router/src/compatibility/stripe/customers/types.rs
// Module: router
// Implementations: 0

pub struct CreateCustomerResponse


// Struct: BlackhawknetworkRefundRequest
// File: crates/hyperswitch_connectors/src/connectors/blackhawknetwork/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BlackhawknetworkRefundRequest