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


impl api::ConnectorAccessToken for Worldpay {}

impl api::ConnectorAccessToken for for Worldpay


pub struct Card {
    pub card_number: cards::CardNumber,
    pub card_exp_month: Secret<String>,
    pub card_exp_year: Secret<String>,
    pub card_cvc: Secret<String>,
    pub card_issuer: Option<String>,
    pub card_network: Option<common_enums::CardNetwork>,
    pub card_type: Option<String>,
    pub card_issuing_country: Option<String>,
    pub bank_code: Option<String>,
    pub nick_name: Option<Secret<String>>,
    pub card_holder_name: Option<Secret<String>>,
    pub co_badged_card_data: Option<payment_methods::CoBadgedCardData>,
}


pub struct ListCountriesCurrenciesResponse {
    pub currencies: HashSet<api_enums::Currency>,
    pub countries: HashSet<CountryCodeWithName>,
}


pub struct GpaymentsAuthenticationRequest {
    pub acct_number: CardNumber,
    pub authentication_ind: String,
    pub browser_info_collected: BrowserInfoCollected,
    pub card_expiry_date: String,
    #[serde(rename = "notificationURL")]
    pub notification_url: String,
    pub merchant_id: common_utils::id_type::MerchantId,
    #[serde(rename = "threeDSCompInd")]
    pub three_ds_comp_ind: ThreeDsCompletionIndicator,
    pub message_category: String,
    pub purchase_amount: String,
    pub purchase_date: String,
    #[serde(rename = "threeDSServerTransID")]
    pub three_ds_server_trans_id: String,
}


File: crates/router/src/core/payments/flows/session_flow.rs

use api_models::{admin as admin_types, payments as payment_types};
use async_trait::async_trait;
use common_utils::{
    ext_traits::ByteSliceExt,
    request::RequestContent,
    types::{AmountConvertor, StringMajorUnitForConnector},
};
use error_stack::{Report, ResultExt};
#[cfg(feature = "v2")]
use hyperswitch_domain_models::payments::PaymentIntentData;
use masking::{ExposeInterface, ExposeOptionInterface};

use super::{ConstructFlowSpecificData, Feature};
use crate::{
    consts::PROTOCOL,
    core::{
        errors::{self, ConnectorErrorExt, RouterResult},
        payments::{self, access_token, customers, helpers, transformers, PaymentData},
    },
    headers, logger,
    routes::{self, app::settings, metrics},
    services,
    types::{
        self,
        api::{self, enums},
        domain,
    },
    utils::OptionExt,
};

#[cfg(feature = "v2")]
#[async_trait]
impl
    ConstructFlowSpecificData<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
    for PaymentIntentData<api::Session>
{
    async fn construct_router_data<'a>(
        &self,
        state: &routes::SessionState,
        connector_id: &str,
        merchant_context: &domain::MerchantContext,
        customer: &Option<domain::Customer>,
        merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
        merchant_recipient_data: Option<types::MerchantRecipientData>,
        header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
    ) -> RouterResult<types::PaymentsSessionRouterData> {
        Box::pin(transformers::construct_payment_router_data_for_sdk_session(
            state,
            self.clone(),
            connector_id,
            merchant_context,
            customer,
            merchant_connector_account,
            merchant_recipient_data,
            header_payload,
        ))
        .await
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl
    ConstructFlowSpecificData<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
    for PaymentData<api::Session>
{
    async fn construct_router_data<'a>(
        &self,
        state: &routes::SessionState,
        connector_id: &str,
        merchant_context: &domain::MerchantContext,
        customer: &Option<domain::Customer>,
        merchant_connector_account: &helpers::MerchantConnectorAccountType,
        merchant_recipient_data: Option<types::MerchantRecipientData>,
        header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
    ) -> RouterResult<types::PaymentsSessionRouterData> {
        Box::pin(transformers::construct_payment_router_data::<
            api::Session,
            types::PaymentsSessionData,
        >(
            state,
            self.clone(),
            connector_id,
            merchant_context,
            customer,
            merchant_connector_account,
            merchant_recipient_data,
            header_payload,
        ))
        .await
    }
}

#[async_trait]
impl Feature<api::Session, types::PaymentsSessionData> for types::PaymentsSessionRouterData {
    async fn decide_flows<'a>(
        self,
        state: &routes::SessionState,
        connector: &api::ConnectorData,
        call_connector_action: payments::CallConnectorAction,
        _connector_request: Option<services::Request>,
        business_profile: &domain::Profile,
        header_payload: hyperswitch_domain_models::payments::HeaderPayload,
        _return_raw_connector_response: Option<bool>,
    ) -> RouterResult<Self> {
        metrics::SESSION_TOKEN_CREATED.add(
            1,
            router_env::metric_attributes!(("connector", connector.connector_name.to_string())),
        );
        self.decide_flow(
            state,
            connector,
            Some(true),
            call_connector_action,
            business_profile,
            header_payload,
        )
        .await
    }

    async fn add_access_token<'a>(
        &self,
        state: &routes::SessionState,
        connector: &api::ConnectorData,
        merchant_context: &domain::MerchantContext,
        creds_identifier: Option<&str>,
    ) -> RouterResult<types::AddAccessTokenResult> {
        Box::pin(access_token::add_access_token(
            state,
            connector,
            merchant_context,
            self,
            creds_identifier,
        ))
        .await
    }

    async fn create_connector_customer<'a>(
        &self,
        state: &routes::SessionState,
        connector: &api::ConnectorData,
    ) -> RouterResult<Option<String>> {
        customers::create_connector_customer(
            state,
            connector,
            self,
            types::ConnectorCustomerData::try_from(self)?,
        )
        .await
    }
}

/// This function checks if for a given connector, payment_method and payment_method_type,
/// the list of required_field_type is present in dynamic fields
#[cfg(feature = "v1")]
fn is_dynamic_fields_required(
    required_fields: &settings::RequiredFields,
    payment_method: enums::PaymentMethod,
    payment_method_type: enums::PaymentMethodType,
    connector: types::Connector,
    required_field_type: Vec<enums::FieldType>,
) -> bool {
    required_fields
        .0
        .get(&payment_method)
        .and_then(|pm_type| pm_type.0.get(&payment_method_type))
        .and_then(|required_fields_for_connector| {
            required_fields_for_connector.fields.get(&connector)
        })
        .map(|required_fields_final| {
            required_fields_final
                .non_mandate
                .iter()
                .any(|(_, val)| required_field_type.contains(&val.field_type))
                || required_fields_final
                    .mandate
                    .iter()
                    .any(|(_, val)| required_field_type.contains(&val.field_type))
                || required_fields_final
                    .common
                    .iter()
                    .any(|(_, val)| required_field_type.contains(&val.field_type))
        })
        .unwrap_or(false)
}

/// This function checks if for a given connector, payment_method and payment_method_type,
/// the list of required_field_type is present in dynamic fields
#[cfg(feature = "v2")]
fn is_dynamic_fields_required(
    required_fields: &settings::RequiredFields,
    payment_method: enums::PaymentMethod,
    payment_method_type: enums::PaymentMethodType,
    connector: types::Connector,
    required_field_type: Vec<enums::FieldType>,
) -> bool {
    required_fields
        .0
        .get(&payment_method)
        .and_then(|pm_type| pm_type.0.get(&payment_method_type))
        .and_then(|required_fields_for_connector| {
            required_fields_for_connector.fields.get(&connector)
        })
        .map(|required_fields_final| {
            required_fields_final
                .non_mandate
                .iter()
                .flatten()
                .any(|field_info| required_field_type.contains(&field_info.field_type))
                || required_fields_final
                    .mandate
                    .iter()
                    .flatten()
                    .any(|field_info| required_field_type.contains(&field_info.field_type))
                || required_fields_final
                    .common
                    .iter()
                    .flatten()
                    .any(|field_info| required_field_type.contains(&field_info.field_type))
        })
        .unwrap_or(false)
}

fn build_apple_pay_session_request(
    state: &routes::SessionState,
    request: payment_types::ApplepaySessionRequest,
    apple_pay_merchant_cert: masking::Secret<String>,
    apple_pay_merchant_cert_key: masking::Secret<String>,
) -> RouterResult<services::Request> {
    let mut url = state.conf.connectors.applepay.base_url.to_owned();
    url.push_str("paymentservices/paymentSession");

    let session_request = services::RequestBuilder::new()
        .method(services::Method::Post)
        .url(url.as_str())
        .attach_default_headers()
        .headers(vec![(
            headers::CONTENT_TYPE.to_string(),
            "application/json".to_string().into(),
        )])
        .set_body(RequestContent::Json(Box::new(request)))
        .add_certificate(Some(apple_pay_merchant_cert))
        .add_certificate_key(Some(apple_pay_merchant_cert_key))
        .build();
    Ok(session_request)
}

async fn create_applepay_session_token(
    state: &routes::SessionState,
    router_data: &types::PaymentsSessionRouterData,
    connector: &api::ConnectorData,
    business_profile: &domain::Profile,
    header_payload: hyperswitch_domain_models::payments::HeaderPayload,
) -> RouterResult<types::PaymentsSessionRouterData> {
    let delayed_response = is_session_response_delayed(state, connector);
    if delayed_response {
        let delayed_response_apple_pay_session =
            Some(payment_types::ApplePaySessionResponse::NoSessionResponse(
                api_models::payments::NullObject,
            ));
        create_apple_pay_session_response(
            router_data,
            delayed_response_apple_pay_session,
            None, // Apple pay payment request will be none for delayed session response
            connector.connector_name.to_string(),
            delayed_response,
            payment_types::NextActionCall::Confirm,
            header_payload,
        )
    } else {
        // Get the apple pay metadata
        let apple_pay_metadata =
            helpers::get_applepay_metadata(router_data.connector_meta_data.clone())
                .attach_printable(
                    "Failed to to fetch apple pay certificates during session call",
                )?;

        // Get payment request data , apple pay session request and merchant keys
        let (
            payment_request_data,
            apple_pay_session_request_optional,
            apple_pay_merchant_cert,
            apple_pay_merchant_cert_key,
            apple_pay_merchant_identifier,
            merchant_business_country,
            merchant_configured_domain_optional,
        ) = match apple_pay_metadata {
            payment_types::ApplepaySessionTokenMetadata::ApplePayCombined(
                apple_pay_combined_metadata,
            ) => match apple_pay_combined_metadata {
                payment_types::ApplePayCombinedMetadata::Simplified {
                    payment_request_data,
                    session_token_data,
                } => {
                    logger::info!("Apple pay simplified flow");

                    let merchant_identifier = state
                        .conf
                        .applepay_merchant_configs
                        .get_inner()
                        .common_merchant_identifier
                        .clone()
                        .expose();

                    let merchant_business_country = session_token_data.merchant_business_country;

                    let apple_pay_session_request = get_session_request_for_simplified_apple_pay(
                        merchant_identifier.clone(),
                        session_token_data.clone(),
                    );

                    let apple_pay_merchant_cert = state
                        .conf
                        .applepay_decrypt_keys
                        .get_inner()
                        .apple_pay_merchant_cert
                        .clone();

                    let apple_pay_merchant_cert_key = state
                        .conf
                        .applepay_decrypt_keys
                        .get_inner()
                        .apple_pay_merchant_cert_key
                        .clone();

                    (
                        payment_request_data,
                        Ok(apple_pay_session_request),
                        apple_pay_merchant_cert,
                        apple_pay_merchant_cert_key,
                        merchant_identifier,
                        merchant_business_country,
                        Some(session_token_data.initiative_context),
                    )
                }
                payment_types::ApplePayCombinedMetadata::Manual {
                    payment_request_data,
                    session_token_data,
                } => {
                    logger::info!("Apple pay manual flow");

                    let apple_pay_session_request = get_session_request_for_manual_apple_pay(
                        session_token_data.clone(),
                        header_payload.x_merchant_domain.clone(),
                    );

                    let merchant_business_country = session_token_data.merchant_business_country;

                    (
                        payment_request_data,
                        apple_pay_session_request,
                        session_token_data.certificate.clone(),
                        session_token_data.certificate_keys,
                        session_token_data.merchant_identifier,
                        merchant_business_country,
                        session_token_data.initiative_context,
                    )
                }
            },
            payment_types::ApplepaySessionTokenMetadata::ApplePay(apple_pay_metadata) => {
                logger::info!("Apple pay manual flow");

                let apple_pay_session_request = get_session_request_for_manual_apple_pay(
                    apple_pay_metadata.session_token_data.clone(),
                    header_payload.x_merchant_domain.clone(),
                );

                let merchant_business_country = apple_pay_metadata
                    .session_token_data
                    .merchant_business_country;
                (
                    apple_pay_metadata.payment_request_data,
                    apple_pay_session_request,
                    apple_pay_metadata.session_token_data.certificate.clone(),
                    apple_pay_metadata
                        .session_token_data
                        .certificate_keys
                        .clone(),
                    apple_pay_metadata.session_token_data.merchant_identifier,
                    merchant_business_country,
                    apple_pay_metadata.session_token_data.initiative_context,
                )
            }
        };

        // Get amount info for apple pay
        let amount_info = get_apple_pay_amount_info(
            payment_request_data.label.as_str(),
            router_data.request.to_owned(),
        )?;

        let required_billing_contact_fields = if business_profile
            .always_collect_billing_details_from_wallet_connector
            .unwrap_or(false)
        {
            Some(payment_types::ApplePayBillingContactFields(vec![
                payment_types::ApplePayAddressParameters::PostalAddress,
            ]))
        } else if business_profile
            .collect_billing_details_from_wallet_connector
            .unwrap_or(false)
        {
            let billing_variants = enums::FieldType::get_billing_variants();
            is_dynamic_fields_required(
                &state.conf.required_fields,
                enums::PaymentMethod::Wallet,
                enums::PaymentMethodType::ApplePay,
                connector.connector_name,
                billing_variants,
            )
            .then_some(payment_types::ApplePayBillingContactFields(vec![
                payment_types::ApplePayAddressParameters::PostalAddress,
            ]))
        } else {
            None
        };

        let required_shipping_contact_fields = if business_profile
            .always_collect_shipping_details_from_wallet_connector
            .unwrap_or(false)
        {
            Some(payment_types::ApplePayShippingContactFields(vec![
                payment_types::ApplePayAddressParameters::PostalAddress,
                payment_types::ApplePayAddressParameters::Phone,
                payment_types::ApplePayAddressParameters::Email,
            ]))
        } else if business_profile
            .collect_shipping_details_from_wallet_connector
            .unwrap_or(false)
        {
            let shipping_variants = enums::FieldType::get_shipping_variants();
            is_dynamic_fields_required(
                &state.conf.required_fields,
                enums::PaymentMethod::Wallet,
                enums::PaymentMethodType::ApplePay,
                connector.connector_name,
                shipping_variants,
            )
            .then_some(payment_types::ApplePayShippingContactFields(vec![
                payment_types::ApplePayAddressParameters::PostalAddress,
                payment_types::ApplePayAddressParameters::Phone,
                payment_types::ApplePayAddressParameters::Email,
            ]))
        } else {
            None
        };

        // If collect_shipping_details_from_wallet_connector is false, we check if
        // collect_billing_details_from_wallet_connector is true. If it is, then we pass the Email and Phone in
        // ApplePayShippingContactFields as it is a required parameter and ApplePayBillingContactFields
        // does not contain Email and Phone.
        let required_shipping_contact_fields_updated = if required_billing_contact_fields.is_some()
            && required_shipping_contact_fields.is_none()
        {
            Some(payment_types::ApplePayShippingContactFields(vec![
                payment_types::ApplePayAddressParameters::Phone,
                payment_types::ApplePayAddressParameters::Email,
            ]))
        } else {
            required_shipping_contact_fields
        };

        // Get apple pay payment request
        let applepay_payment_request = get_apple_pay_payment_request(
            amount_info,
            payment_request_data,
            router_data.request.to_owned(),
            apple_pay_merchant_identifier.as_str(),
            merchant_business_country,
            required_billing_contact_fields,
            required_shipping_contact_fields_updated,
        )?;

        let apple_pay_session_response = match (
            header_payload.browser_name.clone(),
            header_payload.x_client_platform.clone(),
        ) {
            (Some(common_enums::BrowserName::Safari), Some(common_enums::ClientPlatform::Web))
            | (None, None) => {
                let apple_pay_session_request = apple_pay_session_request_optional
                    .attach_printable("Failed to obtain apple pay session request")?;
                let applepay_session_request = build_apple_pay_session_request(
                    state,
                    apple_pay_session_request.clone(),
                    apple_pay_merchant_cert.clone(),
                    apple_pay_merchant_cert_key.clone(),
                )?;

                let response = services::call_connector_api(
                    state,
                    applepay_session_request,
                    "create_apple_pay_session_token",
                )
                .await;

                let updated_response = match (
                    response.as_ref().ok(),
                    header_payload.x_merchant_domain.clone(),
                ) {
                    (Some(Err(error)), Some(_)) => {
                        logger::error!(
                            "Retry apple pay session call with the merchant configured domain {error:?}"
                        );
                        let merchant_configured_domain = merchant_configured_domain_optional
                            .get_required_value("apple pay domain")
                            .attach_printable("Failed to get domain for apple pay session call")?;
                        let apple_pay_retry_session_request =
                            payment_types::ApplepaySessionRequest {
                                initiative_context: merchant_configured_domain,
                                ..apple_pay_session_request
                            };
                        let applepay_retry_session_request = build_apple_pay_session_request(
                            state,
                            apple_pay_retry_session_request,
                            apple_pay_merchant_cert,
                            apple_pay_merchant_cert_key,
                        )?;
                        services::call_connector_api(
                            state,
                            applepay_retry_session_request,
                            "create_apple_pay_session_token",
                        )
                        .await
                    }
                    _ => response,
                };

                // logging the error if present in session call response
                log_session_response_if_error(&updated_response);
                updated_response
                    .ok()
                    .and_then(|apple_pay_res| {
                        apple_pay_res
                            .map(|res| {
                                let response: Result<
                                    payment_types::NoThirdPartySdkSessionResponse,
                                    Report<common_utils::errors::ParsingError>,
                                > = res.response.parse_struct("NoThirdPartySdkSessionResponse");

                                // logging the parsing failed error
                                if let Err(error) = response.as_ref() {
                                    logger::error!(?error);
                                };

                                response.ok()
                            })
                            .ok()
                    })
                    .flatten()
            }
            _ => {
                logger::debug!("Skipping apple pay session call based on the browser name");
                None
            }
        };

        let session_response =
            apple_pay_session_response.map(payment_types::ApplePaySessionResponse::NoThirdPartySdk);

        create_apple_pay_session_response(
            router_data,
            session_response,
            Some(applepay_payment_request),
            connector.connector_name.to_string(),
            delayed_response,
            payment_types::NextActionCall::Confirm,
            header_payload,
        )
    }
}

fn create_paze_session_token(
    router_data: &types::PaymentsSessionRouterData,
    _header_payload: hyperswitch_domain_models::payments::HeaderPayload,
) -> RouterResult<types::PaymentsSessionRouterData> {
    let paze_wallet_details = router_data
        .connector_wallets_details
        .clone()
        .parse_value::<payment_types::PazeSessionTokenData>("PazeSessionTokenData")
        .change_context(errors::ConnectorError::NoConnectorWalletDetails)
        .change_context(errors::ApiErrorResponse::InvalidDataFormat {
            field_name: "connector_wallets_details".to_string(),
            expected_format: "paze_metadata_format".to_string(),
        })?;
    let required_amount_type = StringMajorUnitForConnector;
    let transaction_currency_code = router_data.request.currency;
    let transaction_amount = required_amount_type
        .convert(router_data.request.minor_amount, transaction_currency_code)
        .change_context(errors::ApiErrorResponse::PreconditionFailed {
            message: "Failed to convert amount to string major unit for paze".to_string(),
        })?;
    Ok(types::PaymentsSessionRouterData {
        response: Ok(types::PaymentsResponseData::SessionResponse {
            session_token: payment_types::SessionToken::Paze(Box::new(
                payment_types::PazeSessionTokenResponse {
                    client_id: paze_wallet_details.data.client_id,
                    client_name: paze_wallet_details.data.client_name,
                    client_profile_id: paze_wallet_details.data.client_profile_id,
                    transaction_currency_code,
                    transaction_amount,
                    email_address: router_data.request.email.clone(),
                },
            )),
        }),
        ..router_data.clone()
    })
}

fn create_samsung_pay_session_token(
    state: &routes::SessionState,
    router_data: &types::PaymentsSessionRouterData,
    header_payload: hyperswitch_domain_models::payments::HeaderPayload,
    connector: &api::ConnectorData,
    business_profile: &domain::Profile,
) -> RouterResult<types::PaymentsSessionRouterData> {
    let samsung_pay_session_token_data = router_data
        .connector_wallets_details
        .clone()
        .parse_value::<payment_types::SamsungPaySessionTokenData>("SamsungPaySessionTokenData")
        .change_context(errors::ConnectorError::NoConnectorWalletDetails)
        .change_context(errors::ApiErrorResponse::InvalidDataFormat {
            field_name: "connector_wallets_details".to_string(),
            expected_format: "samsung_pay_metadata_format".to_string(),
        })?;

    let required_amount_type = StringMajorUnitForConnector;
    let samsung_pay_amount = required_amount_type
        .convert(
            router_data.request.minor_amount,
            router_data.request.currency,
        )
        .change_context(errors::ApiErrorResponse::PreconditionFailed {
            message: "Failed to convert amount to string major unit for Samsung Pay".to_string(),
        })?;

    let merchant_domain = match header_payload.x_client_platform {
        Some(common_enums::ClientPlatform::Web) => Some(
            header_payload
                .x_merchant_domain
                .get_required_value("samsung pay domain")
                .attach_printable("Failed to get domain for samsung pay session call")?,
        ),
        _ => None,
    };

    let samsung_pay_wallet_details = match samsung_pay_session_token_data.data {
        payment_types::SamsungPayCombinedMetadata::MerchantCredentials(
            samsung_pay_merchant_credentials,
        ) => samsung_pay_merchant_credentials,
        payment_types::SamsungPayCombinedMetadata::ApplicationCredentials(
            _samsung_pay_application_credentials,
        ) => Err(errors::ApiErrorResponse::NotSupported {
            message: "Samsung Pay decryption flow with application credentials is not implemented"
                .to_owned(),
        })?,
    };

    let formatted_payment_id = router_data.payment_id.replace("_", "-");

    let billing_address_required = is_billing_address_required_to_be_collected_from_wallet(
        state,
        connector,
        business_profile,
        enums::PaymentMethodType::SamsungPay,
    );

    let shipping_address_required = is_shipping_address_required_to_be_collected_form_wallet(
        state,
        connector,
        business_profile,
        enums::PaymentMethodType::SamsungPay,
    );

    Ok(types::PaymentsSessionRouterData {
        response: Ok(types::PaymentsResponseData::SessionResponse {
            session_token: payment_types::SessionToken::SamsungPay(Box::new(
                payment_types::SamsungPaySessionTokenResponse {
                    version: "2".to_string(),
                    service_id: samsung_pay_wallet_details.service_id,
                    order_number: formatted_payment_id,
                    merchant_payment_information:
                        payment_types::SamsungPayMerchantPaymentInformation {
                            name: samsung_pay_wallet_details.merchant_display_name,
                            url: merchant_domain,
                            country_code: samsung_pay_wallet_details.merchant_business_country,
                        },
                    amount: payment_types::SamsungPayAmountDetails {
                        amount_format: payment_types::SamsungPayAmountFormat::FormatTotalPriceOnly,
                        currency_code: router_data.request.currency,
                        total_amount: samsung_pay_amount,
                    },
                    protocol: payment_types::SamsungPayProtocolType::Protocol3ds,
                    allowed_brands: samsung_pay_wallet_details.allowed_brands,
                    billing_address_required,
                    shipping_address_required,
                },
            )),
        }),
        ..router_data.clone()
    })
}

/// Function to determine whether the billing address is required to be collected from the wallet,
/// based on business profile settings, the payment method type, and the connector's required fields
/// for the specific payment method.
///
/// If `always_collect_billing_details_from_wallet_connector` is enabled, it indicates that the
/// billing address is always required to be collected from the wallet.
///
/// If only `collect_billing_details_from_wallet_connector` is enabled, the billing address will be
/// collected only if the connector required fields for the specific payment method type contain
/// the billing fields.
fn is_billing_address_required_to_be_collected_from_wallet(
    state: &routes::SessionState,
    connector: &api::ConnectorData,
    business_profile: &domain::Profile,
    payment_method_type: enums::PaymentMethodType,
) -> bool {
    let always_collect_billing_details_from_wallet_connector = business_profile
        .always_collect_billing_details_from_wallet_connector
        .unwrap_or(false);

    if always_collect_billing_details_from_wallet_connector {
        always_collect_billing_details_from_wallet_connector
    } else if business_profile
        .collect_billing_details_from_wallet_connector
        .unwrap_or(false)
    {
        let billing_variants = enums::FieldType::get_billing_variants();

        is_dynamic_fields_required(
            &state.conf.required_fields,
            enums::PaymentMethod::Wallet,
            payment_method_type,
            connector.connector_name,
            billing_variants,
        )
    } else {
        false
    }
}

/// Function to determine whether the shipping address is required to be collected from the wallet,
/// based on business profile settings, the payment method type, and the connector required fields
/// for the specific payment method type.
///
/// If `always_collect_shipping_details_from_wallet_connector` is enabled, it indicates that the
/// shipping address is always required to be collected from the wallet.
///
/// If only `collect_shipping_details_from_wallet_connector` is enabled, the shipping address will be
/// collected only if the connector required fields for the specific payment method type contain
/// the shipping fields.
fn is_shipping_address_required_to_be_collected_form_wallet(
    state: &routes::SessionState,
    connector: &api::ConnectorData,
    business_profile: &domain::Profile,
    payment_method_type: enums::PaymentMethodType,
) -> bool {
    let always_collect_shipping_details_from_wallet_connector = business_profile
        .always_collect_shipping_details_from_wallet_connector
        .unwrap_or(false);

    if always_collect_shipping_details_from_wallet_connector {
        always_collect_shipping_details_from_wallet_connector
    } else if business_profile
        .collect_shipping_details_from_wallet_connector
        .unwrap_or(false)
    {
        let shipping_variants = enums::FieldType::get_shipping_variants();

        is_dynamic_fields_required(
            &state.conf.required_fields,
            enums::PaymentMethod::Wallet,
            payment_method_type,
            connector.connector_name,
            shipping_variants,
        )
    } else {
        false
    }
}

fn get_session_request_for_simplified_apple_pay(
    apple_pay_merchant_identifier: String,
    session_token_data: payment_types::SessionTokenForSimplifiedApplePay,
) -> payment_types::ApplepaySessionRequest {
    payment_types::ApplepaySessionRequest {
        merchant_identifier: apple_pay_merchant_identifier,
        display_name: "Apple pay".to_string(),
        initiative: "web".to_string(),
        initiative_context: session_token_data.initiative_context,
    }
}

fn get_session_request_for_manual_apple_pay(
    session_token_data: payment_types::SessionTokenInfo,
    merchant_domain: Option<String>,
) -> RouterResult<payment_types::ApplepaySessionRequest> {
    let initiative_context = merchant_domain
        .or_else(|| session_token_data.initiative_context.clone())
        .get_required_value("apple pay domain")
        .attach_printable("Failed to get domain for apple pay session call")?;

    Ok(payment_types::ApplepaySessionRequest {
        merchant_identifier: session_token_data.merchant_identifier.clone(),
        display_name: session_token_data.display_name.clone(),
        initiative: session_token_data.initiative.to_string(),
        initiative_context,
    })
}

fn get_apple_pay_amount_info(
    label: &str,
    session_data: types::PaymentsSessionData,
) -> RouterResult<payment_types::AmountInfo> {
    let required_amount_type = StringMajorUnitForConnector;
    let apple_pay_amount = required_amount_type
        .convert(session_data.minor_amount, session_data.currency)
        .change_context(errors::ApiErrorResponse::PreconditionFailed {
            message: "Failed to convert amount to string major unit for applePay".to_string(),
        })?;
    let amount_info = payment_types::AmountInfo {
        label: label.to_string(),
        total_type: Some("final".to_string()),
        amount: apple_pay_amount,
    };

    Ok(amount_info)
}

fn get_apple_pay_payment_request(
    amount_info: payment_types::AmountInfo,
    payment_request_data: payment_types::PaymentRequestMetadata,
    session_data: types::PaymentsSessionData,
    merchant_identifier: &str,
    merchant_business_country: Option<api_models::enums::CountryAlpha2>,
    required_billing_contact_fields: Option<payment_types::ApplePayBillingContactFields>,
    required_shipping_contact_fields: Option<payment_types::ApplePayShippingContactFields>,
) -> RouterResult<payment_types::ApplePayPaymentRequest> {
    let applepay_payment_request = payment_types::ApplePayPaymentRequest {
        country_code: merchant_business_country.or(session_data.country).ok_or(
            errors::ApiErrorResponse::MissingRequiredField {
                field_name: "country_code",
            },
        )?,
        currency_code: session_data.currency,
        total: amount_info,
        merchant_capabilities: Some(payment_request_data.merchant_capabilities),
        supported_networks: Some(payment_request_data.supported_networks),
        merchant_identifier: Some(merchant_identifier.to_string()),
        required_billing_contact_fields,
        required_shipping_contact_fields,
        recurring_payment_request: session_data.apple_pay_recurring_details,
    };
    Ok(applepay_payment_request)
}

fn create_apple_pay_session_response(
    router_data: &types::PaymentsSessionRouterData,
    session_response: Option<payment_types::ApplePaySessionResponse>,
    apple_pay_payment_request: Option<payment_types::ApplePayPaymentRequest>,
    connector_name: String,
    delayed_response: bool,
    next_action: payment_types::NextActionCall,
    header_payload: hyperswitch_domain_models::payments::HeaderPayload,
) -> RouterResult<types::PaymentsSessionRouterData> {
    match session_response {
        Some(response) => Ok(types::PaymentsSessionRouterData {
            response: Ok(types::PaymentsResponseData::SessionResponse {
                session_token: payment_types::SessionToken::ApplePay(Box::new(
                    payment_types::ApplepaySessionTokenResponse {
                        session_token_data: Some(response),
                        payment_request_data: apple_pay_payment_request,
                        connector: connector_name,
                        delayed_session_token: delayed_response,
                        sdk_next_action: { payment_types::SdkNextAction { next_action } },
                        connector_reference_id: None,
                        connector_sdk_public_key: None,
                        connector_merchant_id: None,
                    },
                )),
            }),
            ..router_data.clone()
        }),
        None => {
            match (
                header_payload.browser_name,
                header_payload.x_client_platform,
            ) {
                (
                    Some(common_enums::BrowserName::Safari),
                    Some(common_enums::ClientPlatform::Web),
                )
                | (None, None) => Ok(types::PaymentsSessionRouterData {
                    response: Ok(types::PaymentsResponseData::SessionResponse {
                        session_token: payment_types::SessionToken::NoSessionTokenReceived,
                    }),
                    ..router_data.clone()
                }),
                _ => Ok(types::PaymentsSessionRouterData {
                    response: Ok(types::PaymentsResponseData::SessionResponse {
                        session_token: payment_types::SessionToken::ApplePay(Box::new(
                            payment_types::ApplepaySessionTokenResponse {
                                session_token_data: None,
                                payment_request_data: apple_pay_payment_request,
                                connector: connector_name,
                                delayed_session_token: delayed_response,
                                sdk_next_action: { payment_types::SdkNextAction { next_action } },
                                connector_reference_id: None,
                                connector_sdk_public_key: None,
                                connector_merchant_id: None,
                            },
                        )),
                    }),
                    ..router_data.clone()
                }),
            }
        }
    }
}

fn create_gpay_session_token(
    state: &routes::SessionState,
    router_data: &types::PaymentsSessionRouterData,
    connector: &api::ConnectorData,
    business_profile: &domain::Profile,
) -> RouterResult<types::PaymentsSessionRouterData> {
    // connector_wallet_details is being parse into admin types to check specifically if google_pay field is present
    // this is being done because apple_pay details from metadata is also being filled into connector_wallets_details
    let google_pay_wallets_details = router_data
        .connector_wallets_details
        .clone()
        .parse_value::<admin_types::ConnectorWalletDetails>("ConnectorWalletDetails")
        .change_context(errors::ConnectorError::NoConnectorWalletDetails)
        .attach_printable(format!(
            "cannot parse connector_wallets_details from the given value {:?}",
            router_data.connector_wallets_details
        ))
        .map_err(|err| {
            logger::debug!(
                "Failed to parse connector_wallets_details for google_pay flow: {:?}",
                err
            );
        })
        .ok()
        .and_then(|connector_wallets_details| connector_wallets_details.google_pay);
    let connector_metadata = router_data.connector_meta_data.clone();
    let delayed_response = is_session_response_delayed(state, connector);

    if delayed_response {
        Ok(types::PaymentsSessionRouterData {
            response: Ok(types::PaymentsResponseData::SessionResponse {
                session_token: payment_types::SessionToken::GooglePay(Box::new(
                    payment_types::GpaySessionTokenResponse::ThirdPartyResponse(
                        payment_types::GooglePayThirdPartySdk {
                            delayed_session_token: true,
                            connector: connector.connector_name.to_string(),
                            sdk_next_action: payment_types::SdkNextAction {
                                next_action: payment_types::NextActionCall::Confirm,
                            },
                        },
                    ),
                )),
            }),
            ..router_data.clone()
        })
    } else {
        let is_billing_details_required = is_billing_address_required_to_be_collected_from_wallet(
            state,
            connector,
            business_profile,
            enums::PaymentMethodType::GooglePay,
        );

        let required_amount_type = StringMajorUnitForConnector;
        let google_pay_amount = required_amount_type
            .convert(
                router_data.request.minor_amount,
                router_data.request.currency,
            )
            .change_context(errors::ApiErrorResponse::PreconditionFailed {
                message: "Failed to convert amount to string major unit for googlePay".to_string(),
            })?;
        let session_data = router_data.request.clone();
        let transaction_info = payment_types::GpayTransactionInfo {
            country_code: session_data.country.unwrap_or_default(),
            currency_code: router_data.request.currency,
            total_price_status: "Final".to_string(),
            total_price: google_pay_amount,
        };

        let required_shipping_contact_fields =
            is_shipping_address_required_to_be_collected_form_wallet(
                state,
                connector,
                business_profile,
                enums::PaymentMethodType::GooglePay,
            );

        if google_pay_wallets_details.is_some() {
            let gpay_data = router_data
                .connector_wallets_details
                .clone()
                .parse_value::<payment_types::GooglePayWalletDetails>("GooglePayWalletDetails")
                .change_context(errors::ConnectorError::NoConnectorWalletDetails)
                .attach_printable(format!(
                    "cannot parse gpay connector_wallets_details from the given value {:?}",
                    router_data.connector_wallets_details
                ))
                .change_context(errors::ApiErrorResponse::InvalidDataFormat {
                    field_name: "connector_wallets_details".to_string(),
                    expected_format: "gpay_connector_wallets_details_format".to_string(),
                })?;

            let payment_types::GooglePayProviderDetails::GooglePayMerchantDetails(gpay_info) =
                gpay_data.google_pay.provider_details.clone();

            let gpay_allowed_payment_methods = get_allowed_payment_methods_from_cards(
                gpay_data,
                &gpay_info.merchant_info.tokenization_specification,
                is_billing_details_required,
            )?;

            Ok(types::PaymentsSessionRouterData {
                response: Ok(types::PaymentsResponseData::SessionResponse {
                    session_token: payment_types::SessionToken::GooglePay(Box::new(
                        payment_types::GpaySessionTokenResponse::GooglePaySession(
                            payment_types::GooglePaySessionResponse {
                                merchant_info: payment_types::GpayMerchantInfo {
                                    merchant_name: gpay_info.merchant_info.merchant_name,
                                    merchant_id: gpay_info.merchant_info.merchant_id,
                                },
                                allowed_payment_methods: vec![gpay_allowed_payment_methods],
                                transaction_info,
                                connector: connector.connector_name.to_string(),
                                sdk_next_action: payment_types::SdkNextAction {
                                    next_action: payment_types::NextActionCall::Confirm,
                                },
                                delayed_session_token: false,
                                secrets: None,
                                shipping_address_required: required_shipping_contact_fields,
                                // We pass Email as a required field irrespective of
                                // collect_billing_details_from_wallet_connector or
                                // collect_shipping_details_from_wallet_connector as it is common to both.
                                email_required: required_shipping_contact_fields
                                    || is_billing_details_required,
                                shipping_address_parameters:
                                    api_models::payments::GpayShippingAddressParameters {
                                        phone_number_required: required_shipping_contact_fields,
                                    },
                            },
                        ),
                    )),
                }),
                ..router_data.clone()
            })
        } else {
            let billing_address_parameters = is_billing_details_required.then_some(
                payment_types::GpayBillingAddressParameters {
                    phone_number_required: is_billing_details_required,
                    format: payment_types::GpayBillingAddressFormat::FULL,
                },
            );

            let gpay_data = connector_metadata
                .clone()
                .parse_value::<payment_types::GpaySessionTokenData>("GpaySessionTokenData")
                .change_context(errors::ConnectorError::NoConnectorMetaData)
                .attach_printable(format!(
                    "cannot parse gpay metadata from the given value {connector_metadata:?}"
                ))
                .change_context(errors::ApiErrorResponse::InvalidDataFormat {
                    field_name: "connector_metadata".to_string(),
                    expected_format: "gpay_metadata_format".to_string(),
                })?;

            let gpay_allowed_payment_methods = gpay_data
                .data
                .allowed_payment_methods
                .into_iter()
                .map(
                    |allowed_payment_methods| payment_types::GpayAllowedPaymentMethods {
                        parameters: payment_types::GpayAllowedMethodsParameters {
                            billing_address_required: Some(is_billing_details_required),
                            billing_address_parameters: billing_address_parameters.clone(),
                            ..allowed_payment_methods.parameters
                        },


pub async fn get_merchant_account_from_db(
        &self,
        state: SessionState,
    ) -> UserResult<MerchantAccount> {
        let key_manager_state = &(&state).into();
        let key_store = state
            .store
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                &self.merchant_id,
                &state.store.get_master_key().to_vec().into(),
            )
            .await
            .map_err(|e| {
                if e.current_context().is_db_not_found() {
                    e.change_context(UserErrors::MerchantIdNotFound)
                } else {
                    e.change_context(UserErrors::InternalServerError)
                }
            })?;
        let merchant_account = state
            .store
            .find_merchant_account_by_merchant_id(key_manager_state, &self.merchant_id, &key_store)
            .await
            .map_err(|e| {
                if e.current_context().is_db_not_found() {
                    e.change_context(UserErrors::MerchantIdNotFound)
                } else {
                    e.change_context(UserErrors::InternalServerError)
                }
            })?;
        Ok(merchant_account)
    }


impl IncomingWebhook for Iatapay {
    fn get_webhook_source_verification_algorithm(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
        Ok(Box::new(crypto::HmacSha256))
    }

    fn get_webhook_source_verification_signature(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let base64_signature = get_header_key_value("Authorization", request.headers)?;
        let base64_signature = base64_signature.replace("IATAPAY-HMAC-SHA256 ", "");
        base64_decode(base64_signature)
    }

    fn get_webhook_source_verification_message(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        _merchant_id: &common_utils::id_type::MerchantId,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let message = std::str::from_utf8(request.body)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
        Ok(message.to_string().into_bytes())
    }

    fn get_webhook_object_reference_id(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        let notif: iatapay::IatapayWebhookResponse = request
            .body
            .parse_struct("IatapayWebhookResponse")
            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
        match notif {
            iatapay::IatapayWebhookResponse::IatapayPaymentWebhookBody(wh_body) => {
                match wh_body.merchant_payment_id {
                    Some(merchant_payment_id) => {
                        Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
                            api_models::payments::PaymentIdType::PaymentAttemptId(
                                merchant_payment_id,
                            ),
                        ))
                    }
                    None => Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
                        api_models::payments::PaymentIdType::ConnectorTransactionId(
                            wh_body.iata_payment_id,
                        ),
                    )),
                }
            }
            iatapay::IatapayWebhookResponse::IatapayRefundWebhookBody(wh_body) => {
                match wh_body.merchant_refund_id {
                    Some(merchant_refund_id) => {
                        Ok(api_models::webhooks::ObjectReferenceId::RefundId(
                            api_models::webhooks::RefundIdType::RefundId(merchant_refund_id),
                        ))
                    }
                    None => Ok(api_models::webhooks::ObjectReferenceId::RefundId(
                        api_models::webhooks::RefundIdType::ConnectorRefundId(
                            wh_body.iata_refund_id,
                        ),
                    )),
                }
            }
        }
    }

    fn get_webhook_event_type(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
        let notif: iatapay::IatapayWebhookResponse = request
            .body
            .parse_struct("IatapayWebhookResponse")
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
        IncomingWebhookEvent::try_from(notif)
    }

    fn get_webhook_resource_object(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let notif: iatapay::IatapayWebhookResponse = request
            .body
            .parse_struct("IatapayWebhookResponse")
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;

        match notif {
            iatapay::IatapayWebhookResponse::IatapayPaymentWebhookBody(wh_body) => {
                Ok(Box::new(wh_body))
            }
            iatapay::IatapayWebhookResponse::IatapayRefundWebhookBody(refund_wh_body) => {
                Ok(Box::new(refund_wh_body))
            }
        }
    }
}


Documentation: api-reference/intelligent-router-api-reference/contract-routing/update-contract-information-for-an-entity.mdx
# Type: Doc File

---
openapi: post /contract_routing.ContractScoreCalculator/UpdateContract
---


impl api::ConnectorAccessToken for Thunes {}

impl api::ConnectorAccessToken for for Thunes


pub struct RoutingEventsResult {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub profile_id: common_utils::id_type::ProfileId,
    pub payment_id: String,
    pub routable_connectors: String,
    pub payment_connector: Option<String>,
    pub request_id: Option<String>,
    pub flow: String,
    pub url: Option<String>,
    pub request: String,
    pub response: Option<String>,
    pub error: Option<String>,
    pub status_code: Option<u16>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    pub method: String,
    pub routing_engine: String,
    pub routing_approach: Option<String>,
}


File: connector-template/test.rs

use hyperswitch_domain_models::payment_method_data::{Card, PaymentMethodData};
use masking::Secret;
use router::{
    types::{self, api, storage::enums,
}};

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

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

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

    fn get_name(&self) -> String {
        "{{project-name | downcase}}".to_string()
    }
}

static CONNECTOR: {{project-name | downcase | pascal_case}}Test = {{project-name | downcase | pascal_case}}Test {};

fn get_default_payment_info() -> Option<utils::PaymentInfo> {
    None
}

fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
    None
}

// Cards Positive Tests
// Creates a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_only_authorize_payment() {
    let response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized);
}

// Captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info())
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Partially captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(
            payment_method_details(),
            Some(types::PaymentsCaptureData {
                amount_to_capture: 50,
                ..utils::PaymentCaptureType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_authorized_payment() {
    let authorize_response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Authorized,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("PSync response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
}

// Voids a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_void_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_void_payment(
            payment_method_details(),
            Some(types::PaymentsCancelData {
                connector_transaction_id: String::from(""),
                cancellation_reason: Some("requested_by_customer".to_string()),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Void payment response");
    assert_eq!(response.status, enums::AttemptStatus::Voided);
}

// Refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(payment_method_details(), None, None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Synchronizes a refund using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_manually_captured_refund() {
    let refund_response = CONNECTOR
        .capture_payment_and_refund(payment_method_details(), None, None, get_default_payment_info())
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_make_payment() {
    let authorize_response = CONNECTOR.make_payment(payment_method_details(), get_default_payment_info()).await.unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_auto_captured_payment() {
    let authorize_response = CONNECTOR.make_payment(payment_method_details(), get_default_payment_info()).await.unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Charged,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                capture_method: Some(enums::CaptureMethod::Automatic),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(response.status, enums::AttemptStatus::Charged,);
}

// Refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_auto_captured_payment() {
    let response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_succeeded_payment() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        refund_response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_succeeded_payment_multiple_times() {
    CONNECTOR
        .make_payment_and_multiple_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await;
}

// Synchronizes a refund using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_refund() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Cards Negative scenarios
// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_cvc: Secret::new("12345".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's security code is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry month.
#[actix_web::test]
async fn should_fail_payment_for_invalid_exp_month() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_month: Secret::new("20".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration month is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry year.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_expiry_year() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration year is invalid.".to_string(),
    );
}

// Voids a payment using automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_fail_void_payment_for_auto_capture() {
    let authorize_response = CONNECTOR.make_payment(payment_method_details(), get_default_payment_info()).await.unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let void_response = CONNECTOR
        .void_payment(txn_id.unwrap(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        void_response.response.unwrap_err().message,
        "You cannot cancel this PaymentIntent because it has a status of succeeded."
    );
}

// Captures a payment using invalid connector payment id.
#[actix_web::test]
async fn should_fail_capture_for_invalid_payment() {
    let capture_response = CONNECTOR
        .capture_payment("123456789".to_string(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        capture_response.response.unwrap_err().message,
        String::from("No such payment_intent: '123456789'")
    );
}

// Refunds a payment with refund amount higher than payment amount.
#[actix_web::test]
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
    let response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 150,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Refund amount (₹1.50) is greater than charge amount (₹1.00)",
    );
}

// Connector dependent test cases goes here

// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests


pub fn get_acs_signed_content(&self) -> Option<String> {
        if let Self::Challenge(challenge_params) = self {
            challenge_params.acs_signed_content.clone()
        } else {
            None
        }
    }


OpenAPI Block Path: components.schemas.ProgramConnectorSelection
{
  "type": "object",
  "description": "The program, having a default connector selection and\na bunch of rules. Also can hold arbitrary metadata.",
  "required": [
    "defaultSelection",
    "rules",
    "metadata"
  ],
  "properties": {
    "defaultSelection": {
      "$ref": "#/components/schemas/ConnectorSelection"
    },
    "rules": {
      "$ref": "#/components/schemas/RuleConnectorSelection"
    },
    "metadata": {
      "type": "object",
      "additionalProperties": {}
    }
  }
}


pub struct AdyenPlatformAccountHolder {
    description: String,
    id: String,
}


pub fn get_user_id(&self) -> String {
        self.user_id.clone()
    }


impl Responder {
    let flow = Flow::IncomingWebhookReceive;
    let (merchant_id, connector_id) = path.into_inner();
    let is_relay_webhook = true;

    Box::pin(api::server_wrap(
        flow.clone(),
        state,
        &req,
        (),
        |state, auth, _, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            webhooks::incoming_webhooks_wrapper::<W>(
                &flow,
                state.to_owned(),
                req_state,
                &req,
                merchant_context,
                connector_id.get_string_repr(),
                body.clone(),
                is_relay_webhook,
            )
        },
        &auth::MerchantIdAuth(merchant_id),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub async fn payouts_create(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<payout_types::PayoutCreateRequest>,
) -> HttpResponse {
    let flow = Flow::PayoutsCreate;

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        json_payload.into_inner(),
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payouts_create_core(state, merchant_context, req)
        },
        &auth::HeaderAuth(auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        }),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl PaymentMethodsUpdateForm {
    pub fn validate_and_get_payment_method_records(self) -> UpdateValidationResult {
        let records = parse_update_csv(self.file.data.to_bytes()).map_err(|e| {
            errors::ApiErrorResponse::PreconditionFailed {
                message: e.to_string(),
            }
        })?;
        Ok((self.merchant_id.clone(), records))
    }
}


pub fn apply_changeset(self, source: PayoutAttempt) -> PayoutAttempt {
        let PayoutAttemptUpdateInternal {
            payout_token,
            connector_payout_id,
            status,
            error_message,
            error_code,
            is_eligible,
            business_country,
            business_label,
            connector,
            routing_info,
            last_modified_at,
            address_id,
            customer_id,
            merchant_connector_id,
            unified_code,
            unified_message,
            additional_payout_method_data,
            merchant_order_reference_id,
        } = self.into();
        PayoutAttempt {
            payout_token: payout_token.or(source.payout_token),
            connector_payout_id: connector_payout_id.or(source.connector_payout_id),
            status: status.unwrap_or(source.status),
            error_message: error_message.or(source.error_message),
            error_code: error_code.or(source.error_code),
            is_eligible: is_eligible.or(source.is_eligible),
            business_country: business_country.or(source.business_country),
            business_label: business_label.or(source.business_label),
            connector: connector.or(source.connector),
            routing_info: routing_info.or(source.routing_info),
            last_modified_at,
            address_id: address_id.or(source.address_id),
            customer_id: customer_id.or(source.customer_id),
            merchant_connector_id: merchant_connector_id.or(source.merchant_connector_id),
            unified_code: unified_code.or(source.unified_code),
            unified_message: unified_message.or(source.unified_message),
            additional_payout_method_data: additional_payout_method_data
                .or(source.additional_payout_method_data),
            merchant_order_reference_id: merchant_order_reference_id
                .or(source.merchant_order_reference_id),
            ..source
        }
    }


pub struct BlackhawknetworkVerifyAccountRequest {
    pub account_number: Secret<String>,
    pub product_line_id: Secret<String>,
    pub account_type: AccountType,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub pin: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub cvv2: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub expiration_date: Option<Secret<String>>,
}


    let body_bytes = bytes::Bytes::copy_from_slice(body);
    let parsed_param: GetnetWebhookNotificationResponse =
        parse_url_encoded_to_struct(body_bytes)
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
    let response_base64 = &parsed_param.response_base64.peek();
    let decoded_response = BASE64_ENGINE
        .decode(response_base64)
        .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;

    let getnet_webhook_notification_response: GetnetWebhookNotificationResponseBody =
        match serde_json::from_slice::<GetnetWebhookNotificationResponseBody>(&decoded_response) {
            Ok(response) => response,
            Err(_e) => {
                return Err(errors::ConnectorError::WebhookBodyDecodingFailed)?;
            }
        };

    Ok(getnet_webhook_notification_response)
}

pub fn get_webhook_response(
    body: &[u8],
) -> CustomResult<GetnetWebhookNotificationResponse, errors::ConnectorError> {
    let body_bytes = bytes::Bytes::copy_from_slice(body);
    let parsed_param: GetnetWebhookNotificationResponse =
        parse_url_encoded_to_struct(body_bytes)
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
    Ok(parsed_param)
}

pub fn get_incoming_webhook_event(
    transaction_type: GetnetTransactionType,
    transaction_status: GetnetPaymentStatus,
) -> IncomingWebhookEvent {
    match transaction_type {
        GetnetTransactionType::Purchase => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::PaymentIntentSuccess,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::PaymentIntentFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::PaymentIntentProcessing,
        },

        GetnetTransactionType::Authorization => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::PaymentIntentAuthorizationSuccess,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::PaymentIntentAuthorizationFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::PaymentIntentProcessing,
        },

        GetnetTransactionType::CaptureAuthorization => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::PaymentIntentCaptureSuccess,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::PaymentIntentCaptureFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::PaymentIntentCaptureFailure,
        },

        GetnetTransactionType::RefundPurchase => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::RefundSuccess,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::RefundFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::RefundFailure,
        },

        GetnetTransactionType::RefundCapture => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::RefundSuccess,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::RefundFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::RefundFailure,
        },

        GetnetTransactionType::VoidAuthorization => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::PaymentIntentCancelled,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::PaymentIntentCancelFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::PaymentIntentCancelFailure,
        },

        GetnetTransactionType::VoidPurchase => match transaction_status {
            GetnetPaymentStatus::Success => IncomingWebhookEvent::PaymentIntentCancelled,
            GetnetPaymentStatus::Failed => IncomingWebhookEvent::PaymentIntentCancelFailure,
            GetnetPaymentStatus::InProgress => IncomingWebhookEvent::PaymentIntentCancelFailure,
        },
    }
}


impl Subscription {
    pub async fn find_by_merchant_id_subscription_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        subscription_id: String,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::subscription_id.eq(subscription_id.to_owned())),
        )
        .await
    }

    pub async fn update_subscription_entry(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        subscription_id: String,
        subscription_update: SubscriptionUpdate,
    ) -> StorageResult<Self> {
        generics::generic_update_with_results::<
            <Self as HasTable>::Table,
            SubscriptionUpdate,
            _,
            _,
        >(
            conn,
            dsl::subscription_id
                .eq(subscription_id.to_owned())
                .and(dsl::merchant_id.eq(merchant_id.to_owned())),
            subscription_update,
        )
        .await?
        .first()
        .cloned()
        .ok_or_else(|| {
            report!(errors::DatabaseError::NotFound)
                .attach_printable("Error while updating subscription entry")
        })
    }
}


pub struct ForteMeta {
    pub auth_id: String,
}


File: crates/diesel_models/src/configs.rs
 Public functions: 1
 Public structs: 3

use std::convert::From;

use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
use serde::{Deserialize, Serialize};

use crate::schema::configs;

#[derive(Default, Clone, Debug, Insertable, Serialize, Deserialize)]
#[diesel(table_name = configs)]
pub struct ConfigNew {
    pub key: String,
    pub config: String,
}

#[derive(Default, Clone, Debug, Identifiable, Queryable, Selectable, Deserialize, Serialize)]
#[diesel(table_name = configs, primary_key(key), check_for_backend(diesel::pg::Pg))]
pub struct Config {
    pub key: String,
    pub config: String,
}

#[derive(Debug)]
pub enum ConfigUpdate {
    Update { config: Option<String> },
}

#[derive(Clone, Debug, AsChangeset, Default)]
#[diesel(table_name = configs)]
pub struct ConfigUpdateInternal {
    config: Option<String>,
}

impl ConfigUpdateInternal {
    pub fn create_config(self, source: Config) -> Config {
        Config { ..source }
    }
}

impl From<ConfigUpdate> for ConfigUpdateInternal {
    fn from(config_update: ConfigUpdate) -> Self {
        match config_update {
            ConfigUpdate::Update { config } => Self { config },
        }
    }
}

impl From<ConfigNew> for Config {
    fn from(config_new: ConfigNew) -> Self {
        Self {
            key: config_new.key,
            config: config_new.config,
        }
    }
}


pub struct HelcimMetaData {
    pub preauth_transaction_id: u64,
}


impl<T: DatabaseStore> PayoutAttemptInterface for RouterStore<T> {}

impl PayoutAttemptInterface for for RouterStore


impl ConnectorSpecifications for CtpMastercard {}

impl ConnectorSpecifications for for CtpMastercard


impl ConnectorCommon for Deutschebank {
    fn id(&self) -> &'static str {
        "deutschebank"
    }

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Minor
    }

    fn common_get_content_type(&self) -> &'static str {
        "application/json"
    }

    fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
        connectors.deutschebank.base_url.as_ref()
    }

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = deutschebank::DeutschebankAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        Ok(vec![(
            headers::MERCHANT_ID.to_string(),
            auth.merchant_id.expose().into_masked(),
        )])
    }

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: deutschebank::PaymentsErrorResponse = res
            .response
            .parse_struct("PaymentsErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.rc,
            message: response.message.clone(),
            reason: Some(response.message),
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorCommon for for Deutschebank


OpenAPI Block Path: components.schemas.AcquirerData
{
  "type": "object",
  "description": "Represents data about the acquirer used in the 3DS decision rule.",
  "required": [
    "country"
  ],
  "properties": {
    "country": {
      "$ref": "#/components/schemas/Country"
    },
    "fraud_rate": {
      "type": "number",
      "format": "double",
      "description": "The fraud rate associated with the acquirer.",
      "nullable": true
    }
  }
}


pub struct CryptopayPaymentsResponse {
    pub data: CryptopayPaymentResponseData,
}


pub struct CardRange {
    pub scheme_id: netcetera_types::SchemeId,
    pub directory_server_id: Option<String>,
    pub acs_protocol_versions: Vec<AcsProtocolVersion>,
    #[serde(rename = "threeDSMethodDataForm")]
    pub three_ds_method_data_form: Option<ThreeDSMethodDataForm>,
    pub highest_common_supported_version: SemanticVersion,
}


impl IncomingWebhook for Gpayments {
    fn get_webhook_object_reference_id(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<ObjectReferenceId, ConnectorError> {
        Err(report!(ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_event_type(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, ConnectorError> {
        Err(report!(ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_resource_object(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, ConnectorError> {
        Err(report!(ConnectorError::WebhooksNotImplemented))
    }
}


pub struct PaymentReceipt {
    pub approved_amount: ApprovedAmount,
    pub processor_response_details: Option<ProcessorResponseDetails>,
}


pub async fn post_payment_frm_core<F, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: &domain::MerchantContext,
    payment_data: &mut D,
    frm_info: &mut FrmInfo<F, D>,
    frm_configs: FrmConfigsObject,
    customer: &Option<domain::Customer>,
    should_continue_capture: &mut bool,
) -> RouterResult<Option<FrmData>>
where
    F: Send + Clone,
    D: payments::OperationSessionGetters<F>
        + payments::OperationSessionSetters<F>
        + Send
        + Sync
        + Clone,
{
    if let Some(frm_data) = &mut frm_info.frm_data {
        // Allow the Post flow only if the payment is authorized,
        // this logic has to be removed if we are going to call /sale or /transaction after failed transaction
        let fraud_check_operation = &mut frm_info.fraud_check_operation;
        if payment_data.get_payment_attempt().status == AttemptStatus::Authorized {
            let frm_router_data_opt = fraud_check_operation
                .to_domain()?
                .post_payment_frm(
                    state,
                    req_state.clone(),
                    payment_data,
                    frm_data,
                    merchant_context,
                    customer,
                )
                .await?;
            if let Some(frm_router_data) = frm_router_data_opt {
                let mut frm_data = fraud_check_operation
                    .to_update_tracker()?
                    .update_tracker(
                        state,
                        merchant_context.get_merchant_key_store(),
                        frm_data.to_owned(),
                        payment_data,
                        None,
                        frm_router_data.to_owned(),
                    )
                    .await?;
                let frm_fraud_check = frm_data.fraud_check.clone();
                let mut frm_suggestion = None;
                payment_data.set_frm_message(frm_fraud_check.clone());
                if matches!(frm_fraud_check.frm_status, FraudCheckStatus::Fraud) {
                    frm_info.suggested_action = Some(FrmSuggestion::FrmCancelTransaction);
                } else if matches!(frm_fraud_check.frm_status, FraudCheckStatus::ManualReview) {
                    frm_info.suggested_action = Some(FrmSuggestion::FrmManualReview);
                }
                fraud_check_operation
                    .to_domain()?
                    .execute_post_tasks(
                        state,
                        req_state,
                        &mut frm_data,
                        merchant_context,
                        frm_configs,
                        &mut frm_suggestion,
                        payment_data,
                        customer,
                        should_continue_capture,
                    )
                    .await?;
                logger::debug!("frm_post_tasks_data: {:?}", frm_data);
                let updated_frm_data = fraud_check_operation
                    .to_update_tracker()?
                    .update_tracker(
                        state,
                        merchant_context.get_merchant_key_store(),
                        frm_data.to_owned(),
                        payment_data,
                        frm_suggestion,
                        frm_router_data.to_owned(),
                    )
                    .await?;
                return Ok(Some(updated_frm_data));
            }
        }

        Ok(Some(frm_data.to_owned()))
    } else {
        Ok(None)
    }
}


pub async fn payouts_confirm(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<payout_types::PayoutCreateRequest>,
    path: web::Path<id_type::PayoutId>,
) -> HttpResponse {
    let flow = Flow::PayoutsConfirm;
    let mut payload = json_payload.into_inner();
    let payout_id = path.into_inner();
    tracing::Span::current().record("payout_id", payout_id.get_string_repr());
    payload.payout_id = Some(payout_id);
    payload.confirm = Some(true);
    let api_auth = auth::ApiKeyAuth::default();

    let (auth_type, _auth_flow) =
        match auth::check_client_secret_and_get_auth(req.headers(), &payload, api_auth) {
            Ok(auth) => auth,
            Err(e) => return api::log_and_return_error_response(e),
        };

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payouts_confirm_core(state, merchant_context, req)
        },
        &*auth_type,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub async fn make_payout_data(
    _state: &SessionState,
    _merchant_context: &domain::MerchantContext,
    _auth_profile_id: Option<id_type::ProfileId>,
    _req: &payouts::PayoutRequest,
    locale: &str,
) -> RouterResult<PayoutData> {
    todo!()
}


pub fn flat_struct_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = parse_macro_input!(input as syn::DeriveInput);
    let name = &input.ident;

    let expanded = quote::quote! {
        impl #name {
            pub fn flat_struct(&self) -> std::collections::HashMap<String, String> {
                use serde_json::Value;
                use std::collections::HashMap;

                fn flatten_value(
                    value: &Value,
                    prefix: &str,
                    result: &mut HashMap<String, String>
                ) {
                    match value {
                        Value::Object(map) => {
                            for (key, val) in map {
                                let new_key = if prefix.is_empty() {
                                    key.to_string()
                                } else {
                                    format!("{}.{}", prefix, key)
                                };
                                flatten_value(val, &new_key, result);
                            }
                        }
                        Value::String(s) => {
                            result.insert(prefix.to_string(), s.clone());
                        }
                        Value::Number(n) => {
                            result.insert(prefix.to_string(), n.to_string());
                        }
                        Value::Bool(b) => {
                            result.insert(prefix.to_string(), b.to_string());
                        }
                        _ => {}
                    }
                }

                let mut result = HashMap::new();
                let value = serde_json::to_value(self).unwrap();
                flatten_value(&value, "", &mut result);
                result
            }
        }
    };

    proc_macro::TokenStream::from(expanded)
}


pub fn into_inner(self) -> FredRedisValue {
        self.inner
    }


pub struct RazorpayPaymentWebhookPayload {
//     pub entity: WebhookPaymentEntity,
// }


pub struct PayboxErrorResponse {
    pub status_code: u16,
    pub code: String,
    pub message: String,
    pub reason: Option<String>,
}


impl<T: FromStr + Display + Default> Default for DBEnumWrapper<T> {
    fn default() -> Self {
        Self(T::default())
    }
}


impl api::Refund for Blackhawknetwork {}

impl api::Refund for for Blackhawknetwork


impl api::PaymentAuthorize for Globepay {}

impl api::PaymentAuthorize for for Globepay


pub async fn delete_surcharge_decision_config(
    state: SessionState,
    merchant_context: domain::MerchantContext,
) -> RouterResponse<()> {
    use common_utils::ext_traits::ValueExt;
    use storage_impl::redis::cache;

    use super::routing::helpers::update_merchant_active_algorithm_ref;

    let db = state.store.as_ref();
    let key = merchant_context
        .get_merchant_account()
        .get_id()
        .get_payment_method_surcharge_routing_id();
    let mut algo_id: api_models::routing::RoutingAlgorithmRef = merchant_context
        .get_merchant_account()
        .routing_algorithm
        .clone()
        .map(|value| value.parse_value("routing algorithm"))
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Could not decode the surcharge conditional_config algorithm")?
        .unwrap_or_default();
    algo_id.surcharge_config_algo_id = None;
    let surcharge_cache_key = merchant_context
        .get_merchant_account()
        .get_id()
        .get_surcharge_dsk_key();
    let config_key = cache::CacheKind::Surcharge(surcharge_cache_key.into());
    update_merchant_active_algorithm_ref(
        &state,
        merchant_context.get_merchant_key_store(),
        config_key,
        algo_id,
    )
    .await
    .change_context(errors::ApiErrorResponse::InternalServerError)
    .attach_printable("Failed to update deleted algorithm ref")?;

    db.delete_config_by_key(&key)
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to delete routing config from DB")?;
    Ok(service_api::ApplicationResponse::StatusOk)
}


pub struct MerchantAccount {
    pub merchant_id: String,
    pub gateway_success_rate_based_decider_input: Option<String>,
}


File: crates/router/src/types/api/connector_onboarding.rs

pub mod paypal;


pub fn to_field_value_pairs(
        &self,
        request_id: String,
        global_id: String,
    ) -> crate::StorageResult<Vec<(&str, String)>> {
        let pushed_at = common_utils::date_time::now_unix_timestamp();

        Ok(vec![
            (
                "typed_sql",
                serde_json::to_string(self)
                    .change_context(errors::DatabaseError::QueryGenerationFailed)?,
            ),
            ("global_id", global_id),
            ("request_id", request_id),
            ("pushed_at", pushed_at.to_string()),
        ])
    }


pub struct CybersourceConsumerAuthInformationEnrollmentResponse {
    access_token: Option<Secret<String>>,
    step_up_url: Option<String>,
    //Added to segregate the three_ds_data in a separate struct
    #[serde(flatten)]
    validate_response: CybersourceConsumerAuthValidateResponse,
}


impl std::ops::DerefMut for PayoutsMandateReference {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl std::ops::DerefMut for for PayoutsMandateReference


File: crates/analytics/src/types.rs
 Public structs: 1

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

use common_utils::{
    errors::{CustomResult, ErrorSwitch, ParsingError},
    events::{ApiEventMetric, ApiEventsType},
    impl_api_event_type,
};
use error_stack::{report, Report, ResultExt};

use super::query::QueryBuildingError;
use crate::errors::AnalyticsError;

#[derive(serde::Deserialize, Debug, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub enum AnalyticsDomain {
    Payments,
    Refunds,
    Frm,
    PaymentIntents,
    AuthEvents,
    SdkEvents,
    ApiEvents,
    Dispute,
    Routing,
}

#[derive(Debug, strum::AsRefStr, strum::Display, Clone, Copy)]
pub enum AnalyticsCollection {
    Payment,
    PaymentSessionized,
    Refund,
    RefundSessionized,
    FraudCheck,
    SdkEvents,
    SdkEventsAnalytics,
    ApiEvents,
    PaymentIntent,
    PaymentIntentSessionized,
    ConnectorEvents,
    OutgoingWebhookEvent,
    Authentications,
    Dispute,
    DisputeSessionized,
    ApiEventsAnalytics,
    ActivePaymentsAnalytics,
    RoutingEvents,
}

#[allow(dead_code)]
#[derive(Debug)]
pub enum TableEngine {
    CollapsingMergeTree { sign: &'static str },
    BasicTree,
}

#[derive(Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
#[serde(transparent)]
pub struct DBEnumWrapper<T: FromStr + Display>(pub T);

impl<T: FromStr + Display> AsRef<T> for DBEnumWrapper<T> {
    fn as_ref(&self) -> &T {
        &self.0
    }
}

impl<T: FromStr + Display + Default> Default for DBEnumWrapper<T> {
    fn default() -> Self {
        Self(T::default())
    }
}

impl<T> FromStr for DBEnumWrapper<T>
where
    T: FromStr + Display,
{
    type Err = Report<ParsingError>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        T::from_str(s)
            .map_err(|_er| report!(ParsingError::EnumParseFailure(std::any::type_name::<T>())))
            .map(DBEnumWrapper)
            .attach_printable_lazy(|| format!("raw_value: {s}"))
    }
}

#[async_trait::async_trait]
pub trait AnalyticsDataSource
where
    Self: Sized + Sync + Send,
{
    type Row;
    async fn load_results<T>(&self, query: &str) -> CustomResult<Vec<T>, QueryExecutionError>
    where
        Self: LoadRow<T>;

    fn get_table_engine(_table: AnalyticsCollection) -> TableEngine {
        TableEngine::BasicTree
    }
}

pub trait LoadRow<T>
where
    Self: AnalyticsDataSource,
    T: Sized,
{
    fn load_row(row: Self::Row) -> CustomResult<T, QueryExecutionError>;
}

#[derive(thiserror::Error, Debug)]
pub enum MetricsError {
    #[error("Error building query")]
    QueryBuildingError,
    #[error("Error running Query")]
    QueryExecutionFailure,
    #[error("Error processing query results")]
    PostProcessingFailure,
    #[allow(dead_code)]
    #[error("Not Implemented")]
    NotImplemented,
}

#[derive(Debug, thiserror::Error)]
pub enum QueryExecutionError {
    #[error("Failed to extract domain rows")]
    RowExtractionFailure,
    #[error("Database error")]
    DatabaseError,
}

pub type MetricsResult<T> = CustomResult<T, MetricsError>;

impl ErrorSwitch<MetricsError> for QueryBuildingError {
    fn switch(&self) -> MetricsError {
        MetricsError::QueryBuildingError
    }
}

pub type FiltersResult<T> = CustomResult<T, FiltersError>;

#[derive(thiserror::Error, Debug)]
pub enum FiltersError {
    #[error("Error building query")]
    QueryBuildingError,
    #[error("Error running Query")]
    QueryExecutionFailure,
    #[allow(dead_code)]
    #[error("Not Implemented: {0}")]
    NotImplemented(&'static str),
}

impl ErrorSwitch<FiltersError> for QueryBuildingError {
    fn switch(&self) -> FiltersError {
        FiltersError::QueryBuildingError
    }
}

impl ErrorSwitch<AnalyticsError> for FiltersError {
    fn switch(&self) -> AnalyticsError {
        match self {
            Self::QueryBuildingError | Self::QueryExecutionFailure => AnalyticsError::UnknownError,
            Self::NotImplemented(a) => AnalyticsError::NotImplemented(a),
        }
    }
}

impl_api_event_type!(Miscellaneous, (AnalyticsDomain));