        .await
        .to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
            message: "payment methods session does not exist or has expired".to_string(),
        })
        .attach_printable("Failed to retrieve payment methods session from db")?;

    let encrypted_data = request
        .encrypt_data(key_manager_state, merchant_context.get_merchant_key_store())
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to encrypt payment methods session data")?;

    let billing = encrypted_data
        .billing
        .as_ref()
        .map(|data| {
            data.clone()
                .deserialize_inner_value(|value| value.parse_value("Address"))
        })
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to decode billing address")?;

    let payment_method_session_domain_model =
        hyperswitch_domain_models::payment_methods::PaymentMethodsSessionUpdateEnum::GeneralUpdate{
            billing: Box::new(billing),
            psp_tokenization: request.psp_tokenization,
            network_tokenization: request.network_tokenization,
            tokenization_data: request.tokenization_data,
        };

    let update_state_change = db
        .update_payment_method_session(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            &payment_method_session_id,
            payment_method_session_domain_model,
            existing_payment_method_session_state.clone(),
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to update payment methods session in db")?;

    let response = transformers::generate_payment_method_session_response(
        update_state_change,
        Secret::new("CLIENT_SECRET_REDACTED".to_string()),
        None, // TODO: send associated payments response based on the expandable param
        None,
    );

    Ok(services::ApplicationResponse::Json(response))
}
#[cfg(feature = "v2")]
pub async fn payment_methods_session_retrieve(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    payment_method_session_id: id_type::GlobalPaymentMethodSessionId,
) -> RouterResponse<payment_methods::PaymentMethodSessionResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let payment_method_session_domain_model = db
        .get_payment_methods_session(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            &payment_method_session_id,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
            message: "payment methods session does not exist or has expired".to_string(),
        })
        .attach_printable("Failed to retrieve payment methods session from db")?;

    let response = transformers::generate_payment_method_session_response(
        payment_method_session_domain_model,
        Secret::new("CLIENT_SECRET_REDACTED".to_string()),
        None, // TODO: send associated payments response based on the expandable param
        None,
    );

    Ok(services::ApplicationResponse::Json(response))
}

#[cfg(feature = "v2")]
pub async fn payment_methods_session_update_payment_method(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    payment_method_session_id: id_type::GlobalPaymentMethodSessionId,
    request: payment_methods::PaymentMethodSessionUpdateSavedPaymentMethod,
) -> RouterResponse<payment_methods::PaymentMethodResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    // Validate if the session still exists
    db.get_payment_methods_session(
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        &payment_method_session_id,
    )
    .await
    .to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
        message: "payment methods session does not exist or has expired".to_string(),
    })
    .attach_printable("Failed to retrieve payment methods session from db")?;

    let payment_method_update_request = request.payment_method_update_request;

    let updated_payment_method = update_payment_method_core(
        &state,
        &merchant_context,
        &profile,
        payment_method_update_request,
        &request.payment_method_id,
    )
    .await
    .attach_printable("Failed to update saved payment method")?;

    Ok(services::ApplicationResponse::Json(updated_payment_method))
}

#[cfg(feature = "v2")]
pub async fn payment_methods_session_delete_payment_method(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    pm_id: id_type::GlobalPaymentMethodId,
    payment_method_session_id: id_type::GlobalPaymentMethodSessionId,
) -> RouterResponse<api::PaymentMethodDeleteResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    // Validate if the session still exists
    db.get_payment_methods_session(
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        &payment_method_session_id,
    )
    .await
    .to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
        message: "payment methods session does not exist or has expired".to_string(),
    })
    .attach_printable("Failed to retrieve payment methods session from db")?;

    let response = delete_payment_method_core(&state, pm_id, &merchant_context, &profile)
        .await
        .attach_printable("Failed to delete saved payment method")?;

    Ok(services::ApplicationResponse::Json(response))
}

#[cfg(feature = "v2")]
fn construct_zero_auth_payments_request(
    confirm_request: &payment_methods::PaymentMethodSessionConfirmRequest,
    payment_method_session: &hyperswitch_domain_models::payment_methods::PaymentMethodSession,
    payment_method: &payment_methods::PaymentMethodResponse,
) -> RouterResult<api_models::payments::PaymentsRequest> {
    use api_models::payments;

    Ok(payments::PaymentsRequest {
        amount_details: payments::AmountDetails::new_for_zero_auth_payment(
            common_enums::Currency::USD,
        ),
        payment_method_data: confirm_request.payment_method_data.clone(),
        payment_method_type: confirm_request.payment_method_type,
        payment_method_subtype: confirm_request.payment_method_subtype,
        customer_id: Some(payment_method_session.customer_id.clone()),
        customer_present: Some(enums::PresenceOfCustomerDuringPayment::Present),
        setup_future_usage: Some(common_enums::FutureUsage::OffSession),
        payment_method_id: Some(payment_method.id.clone()),
        merchant_reference_id: None,
        routing_algorithm_id: None,
        capture_method: None,
        authentication_type: None,
        // We have already passed payment method billing address
        billing: None,
        shipping: None,
        description: None,
        return_url: payment_method_session.return_url.clone(),
        apply_mit_exemption: None,
        statement_descriptor: None,
        order_details: None,
        allowed_payment_method_types: None,
        metadata: None,
        connector_metadata: None,
        feature_metadata: None,
        payment_link_enabled: None,
        payment_link_config: None,
        request_incremental_authorization: None,
        session_expiry: None,
        frm_metadata: None,
        request_external_three_ds_authentication: None,
        customer_acceptance: None,
        browser_info: None,
        force_3ds_challenge: None,
        is_iframe_redirection_enabled: None,
        merchant_connector_details: None,
        return_raw_connector_response: None,
    })
}

#[cfg(feature = "v2")]
async fn create_zero_auth_payment(
    state: SessionState,
    req_state: routes::app::ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    request: api_models::payments::PaymentsRequest,
) -> RouterResult<api_models::payments::PaymentsResponse> {
    let response = Box::pin(payments_core::payments_create_and_confirm_intent(
        state,
        req_state,
        merchant_context,
        profile,
        request,
        hyperswitch_domain_models::payments::HeaderPayload::default(),
    ))
    .await?;

    logger::info!(associated_payments_response=?response);

    response
        .get_json_body()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unexpected response from payments core")
}

#[cfg(feature = "v2")]
pub async fn payment_methods_session_confirm(
    state: SessionState,
    req_state: routes::app::ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    payment_method_session_id: id_type::GlobalPaymentMethodSessionId,
    request: payment_methods::PaymentMethodSessionConfirmRequest,
) -> RouterResponse<payment_methods::PaymentMethodSessionResponse> {
    let db: &dyn StorageInterface = state.store.as_ref();
    let key_manager_state = &(&state).into();

    // Validate if the session still exists
    let payment_method_session = db
        .get_payment_methods_session(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            &payment_method_session_id,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
            message: "payment methods session does not exist or has expired".to_string(),
        })
        .attach_printable("Failed to retrieve payment methods session from db")?;

    let payment_method_session_billing = payment_method_session
        .billing
        .clone()
        .map(|billing| billing.into_inner())
        .map(From::from);

    // Unify the billing address that we receive from the session and from the confirm request
    let unified_billing_address = request
        .payment_method_data
        .billing
        .clone()
        .map(|payment_method_billing| {
            payment_method_billing.unify_address(payment_method_session_billing.as_ref())
        })
        .or_else(|| payment_method_session_billing.clone());

    let customer_id = payment_method_session.customer_id.clone();

    let create_payment_method_request = get_payment_method_create_request(
        request
            .payment_method_data
            .payment_method_data
            .as_ref()
            .get_required_value("payment_method_data")?,
        request.payment_method_type,
        request.payment_method_subtype,
        customer_id.clone(),
        unified_billing_address.as_ref(),
        Some(&payment_method_session),
    )
    .attach_printable("Failed to create payment method request")?;

    let (payment_method_response, payment_method) = Box::pin(create_payment_method_core(
        &state,
        &req_state,
        create_payment_method_request.clone(),
        &merchant_context,
        &profile,
    ))
    .await?;

    let parent_payment_method_token = generate_id(consts::ID_LENGTH, "token");

    let token_data = get_pm_list_token_data(request.payment_method_type, &payment_method)?;

    let intent_fulfillment_time = common_utils::consts::DEFAULT_INTENT_FULFILLMENT_TIME;

    // insert the token data into redis
    if let Some(token_data) = token_data {
        pm_routes::ParentPaymentMethodToken::create_key_for_token((
            &parent_payment_method_token,
            request.payment_method_type,
        ))
        .insert(intent_fulfillment_time, token_data, &state)
        .await?;
    };

    let update_payment_method_session = hyperswitch_domain_models::payment_methods::PaymentMethodsSessionUpdateEnum::UpdateAssociatedPaymentMethods {
        associated_payment_methods:  Some(vec![parent_payment_method_token.clone()])
    };

    vault::insert_cvc_using_payment_token(
        &state,
        &parent_payment_method_token,
        create_payment_method_request.payment_method_data.clone(),
        request.payment_method_type,
        intent_fulfillment_time,
        merchant_context.get_merchant_key_store().key.get_inner(),
    )
    .await?;

    let payment_method_session = db
        .update_payment_method_session(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            &payment_method_session_id,
            update_payment_method_session,
            payment_method_session,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
            message: "payment methods session does not exist or has expired".to_string(),
        })
        .attach_printable("Failed to update payment methods session from db")?;

    let payments_response = match &payment_method_session.psp_tokenization {
        Some(common_types::payment_methods::PspTokenization {
            tokenization_type: common_enums::TokenizationType::MultiUse,
            ..
        }) => {
            let zero_auth_request = construct_zero_auth_payments_request(
                &request,
                &payment_method_session,
                &payment_method_response,
            )?;
            let payments_response = Box::pin(create_zero_auth_payment(
                state.clone(),
                req_state,
                merchant_context.clone(),
                profile.clone(),
                zero_auth_request,
            ))
            .await?;

            Some(payments_response)
        }
        Some(common_types::payment_methods::PspTokenization {
            tokenization_type: common_enums::TokenizationType::SingleUse,
            ..
        }) => {
            Box::pin(create_single_use_tokenization_flow(
                state.clone(),
                req_state.clone(),
                merchant_context.clone(),
                profile.clone(),
                &create_payment_method_request.clone(),
                &payment_method_response,
                &payment_method_session,
            ))
            .await?;
            None
        }
        None => None,
    };

    let tokenization_response = match payment_method_session.tokenization_data.clone() {
        Some(tokenization_data) => {
            let tokenization_response = tokenization_core::create_vault_token_core(
                state.clone(),
                &merchant_context.get_merchant_account().clone(),
                &merchant_context.get_merchant_key_store().clone(),
                api_models::tokenization::GenericTokenizationRequest {
                    customer_id: customer_id.clone(),
                    token_request: tokenization_data,
                },
            )
            .await?;
            let token = match tokenization_response {
                services::ApplicationResponse::Json(response) => Some(response),
                _ => None,
            };
            Some(token)
        }
        None => None,
    };

    logger::debug!(?tokenization_response, "Tokenization response");

    //TODO: update the payment method session with the payment id and payment method id
    let payment_method_session_response = transformers::generate_payment_method_session_response(
        payment_method_session,
        Secret::new("CLIENT_SECRET_REDACTED".to_string()),
        payments_response,
        (tokenization_response.flatten()),
    );

    Ok(services::ApplicationResponse::Json(
        payment_method_session_response,
    ))
}

#[cfg(feature = "v2")]
impl pm_types::SavedPMLPaymentsInfo {
    pub async fn form_payments_info(
        payment_intent: PaymentIntent,
        merchant_context: &domain::MerchantContext,
        profile: domain::Profile,
        db: &dyn StorageInterface,
        key_manager_state: &util_types::keymanager::KeyManagerState,
    ) -> RouterResult<Self> {
        let collect_cvv_during_payment = profile.should_collect_cvv_during_payment;

        let off_session_payment_flag = matches!(
            payment_intent.setup_future_usage,
            common_enums::FutureUsage::OffSession
        );

        let is_connector_agnostic_mit_enabled =
            profile.is_connector_agnostic_mit_enabled.unwrap_or(false);

        Ok(Self {
            payment_intent,
            profile,
            collect_cvv_during_payment,
            off_session_payment_flag,
            is_connector_agnostic_mit_enabled,
        })
    }

    pub async fn perform_payment_ops(
        &self,
        state: &SessionState,
        parent_payment_method_token: Option<String>,
        pma: &api::CustomerPaymentMethodResponseItem,
        pm_list_context: PaymentMethodListContext,
    ) -> RouterResult<()> {
        let token = parent_payment_method_token
            .as_ref()
            .get_required_value("parent_payment_method_token")?;
        let token_data = pm_list_context
            .get_token_data()
            .get_required_value("PaymentTokenData")?;

        let intent_fulfillment_time = self
            .profile
            .get_order_fulfillment_time()
            .unwrap_or(common_utils::consts::DEFAULT_INTENT_FULFILLMENT_TIME);

        pm_routes::ParentPaymentMethodToken::create_key_for_token((token, pma.payment_method_type))
            .insert(intent_fulfillment_time, token_data, state)
            .await?;

        Ok(())
    }
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
async fn create_single_use_tokenization_flow(
    state: SessionState,
    req_state: routes::app::ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    payment_method_create_request: &payment_methods::PaymentMethodCreate,
    payment_method: &api::PaymentMethodResponse,
    payment_method_session: &domain::payment_methods::PaymentMethodSession,
) -> RouterResult<()> {
    let customer_id = payment_method_create_request.customer_id.to_owned();
    let connector_id = payment_method_create_request
        .get_tokenize_connector_id()
        .change_context(errors::ApiErrorResponse::MissingRequiredField {
            field_name: "psp_tokenization.connector_id",
        })
        .attach_printable("Failed to get tokenize connector id")?;

    let db = &state.store;

    let merchant_connector_account_details = db
        .find_merchant_connector_account_by_id(
            &(&state).into(),
            &connector_id,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: connector_id.get_string_repr().to_owned(),
        })
        .attach_printable("error while fetching merchant_connector_account from connector_id")?;
    let auth_type = merchant_connector_account_details
        .get_connector_account_details()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed while parsing value for ConnectorAuthType")?;

    let payment_method_data_request = types::PaymentMethodTokenizationData {
        payment_method_data: payment_method_data::PaymentMethodData::try_from(
            payment_method_create_request.payment_method_data.clone(),
        )
        .change_context(errors::ApiErrorResponse::MissingRequiredField {
            field_name: "card_cvc",
        })
        .attach_printable(
            "Failed to convert type from Payment Method Create Data to Payment Method Data",
        )?,
        browser_info: None,
        currency: api_models::enums::Currency::default(),
        amount: None,
        split_payments: None,
        mandate_id: None,
        setup_future_usage: None,
        customer_acceptance: None,
        setup_mandate_details: None,
    };

    let payment_method_session_address = types::PaymentAddress::new(
        None,
        payment_method_session
            .billing
            .clone()
            .map(|address| address.into_inner()),
        None,
        None,
    );

    let mut router_data =
        types::RouterData::<api::PaymentMethodToken, _, types::PaymentsResponseData> {
            flow: std::marker::PhantomData,
            merchant_id: merchant_context.get_merchant_account().get_id().clone(),
            customer_id: None,
            connector_customer: None,
            connector: merchant_connector_account_details
                .connector_name
                .to_string(),
            payment_id: consts::IRRELEVANT_PAYMENT_INTENT_ID.to_string(), //Static
            attempt_id: consts::IRRELEVANT_PAYMENT_ATTEMPT_ID.to_string(), //Static
            tenant_id: state.tenant.tenant_id.clone(),
            status: common_enums::enums::AttemptStatus::default(),
            payment_method: common_enums::enums::PaymentMethod::Card,
            connector_auth_type: auth_type,
            description: None,
            address: payment_method_session_address,
            auth_type: common_enums::enums::AuthenticationType::default(),
            connector_meta_data: None,
            connector_wallets_details: None,
            amount_captured: None,
            access_token: None,
            session_token: None,
            reference_id: None,
            payment_method_token: None,
            recurring_mandate_payment_data: None,
            preprocessing_id: None,
            payment_method_balance: None,
            connector_api_version: None,
            request: payment_method_data_request.clone(),
            response: Err(hyperswitch_domain_models::router_data::ErrorResponse::default()),
            connector_request_reference_id: payment_method_session.id.get_string_repr().to_string(),
            #[cfg(feature = "payouts")]
            payout_method_data: None,
            #[cfg(feature = "payouts")]
            quote_id: None,
            test_mode: None,
            connector_http_status_code: None,
            external_latency: None,
            apple_pay_flow: None,
            frm_metadata: None,
            dispute_id: None,
            refund_id: None,
            connector_response: None,
            payment_method_status: None,
            minor_amount_captured: None,
            integrity_check: Ok(()),
            additional_merchant_data: None,
            header_payload: None,
            connector_mandate_request_reference_id: None,
            authentication_id: None,
            psd2_sca_exemption_type: None,
            raw_connector_response: None,
            is_payment_id_from_merchant: None,
            l2_l3_data: None,
            minor_amount_capturable: None,
        };

    let payment_method_token_response = Box::pin(tokenization::add_token_for_payment_method(
        &mut router_data,
        payment_method_data_request.clone(),
        state.clone(),
        &merchant_connector_account_details.clone(),
    ))
    .await?;

    let token_response = payment_method_token_response.token.map_err(|err| {
        errors::ApiErrorResponse::ExternalConnectorError {
            code: err.code,
            message: err.message,
            connector: (merchant_connector_account_details.clone())
                .connector_name
                .to_string(),
            status_code: err.status_code,
            reason: err.reason,
        }
    })?;

    let value = payment_method_data::SingleUsePaymentMethodToken::get_single_use_token_from_payment_method_token(
                                                       token_response.clone().into(),
                                                connector_id.clone()
                                            );

    let key = payment_method_data::SingleUseTokenKey::store_key(&payment_method.id);

    add_single_use_token_to_store(&state, key, value)
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to store single use token")?;

    Ok(())
}

#[cfg(feature = "v2")]
async fn add_single_use_token_to_store(
    state: &SessionState,
    key: payment_method_data::SingleUseTokenKey,
    value: payment_method_data::SingleUsePaymentMethodToken,
) -> CustomResult<(), errors::StorageError> {
    let redis_connection = state
        .store
        .get_redis_conn()
        .map_err(Into::<errors::StorageError>::into)?;

    redis_connection
        .serialize_and_set_key_with_expiry(
            &payment_method_data::SingleUseTokenKey::get_store_key(&key).into(),
            value,
            consts::DEFAULT_PAYMENT_METHOD_STORE_TTL,
        )
        .await
        .change_context(errors::StorageError::KVError)
        .attach_printable("Failed to insert payment method token to redis")?;
    Ok(())
}

#[cfg(feature = "v2")]
async fn get_single_use_token_from_store(
    state: &SessionState,
    key: payment_method_data::SingleUseTokenKey,
) -> CustomResult<Option<payment_method_data::SingleUsePaymentMethodToken>, errors::StorageError> {
    let redis_connection = state
        .store
        .get_redis_conn()
        .map_err(Into::<errors::StorageError>::into)?;

    redis_connection
        .get_and_deserialize_key::<Option<payment_method_data::SingleUsePaymentMethodToken>>(
            &payment_method_data::SingleUseTokenKey::get_store_key(&key).into(),
            "SingleUsePaymentMethodToken",
        )
        .await
        .change_context(errors::StorageError::KVError)
        .attach_printable("Failed to get payment method token from redis")
}


pub fn new(
        dispute_stage: Option<DisputeStage>,
        connector: Option<String>,
        currency: Option<Currency>,
        normalized_time_range: TimeRange,
    ) -> Self {
        Self {
            dispute_stage,
            connector,
            currency,
            time_bucket: normalized_time_range,
            start_time: normalized_time_range.start_time,
        }
    }


File: crates/hyperswitch_connectors/src/connectors/trustpayments/transformers.rs
 Public structs: 8

use common_enums::enums;
use common_utils::types::StringMinorUnit;
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{ConnectorAuthType, RouterData},
    router_flow_types::refunds::{Execute, RSync},
    router_request_types::ResponseId,
    router_response_types::{PaymentsResponseData, RefundsResponseData},
    types::{PaymentsAuthorizeRouterData, RefundsRouterData},
};
use hyperswitch_interfaces::errors;
use masking::Secret;
use serde::{Deserialize, Serialize};

use crate::types::{RefundsResponseRouterData, ResponseRouterData};

//TODO: Fill the struct with respective fields
pub struct TrustpaymentsRouterData<T> {
    pub amount: StringMinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
    pub router_data: T,
}

impl<T> From<(StringMinorUnit, T)> for TrustpaymentsRouterData<T> {
    fn from((amount, item): (StringMinorUnit, T)) -> Self {
        //Todo :  use utils to convert the amount to the type of amount that a connector accepts
        Self {
            amount,
            router_data: item,
        }
    }
}

//TODO: Fill the struct with respective fields
#[derive(Default, Debug, Serialize, PartialEq)]
pub struct TrustpaymentsPaymentsRequest {
    amount: StringMinorUnit,
    card: TrustpaymentsCard,
}

#[derive(Default, Debug, Serialize, Eq, PartialEq)]
pub struct TrustpaymentsCard {
    number: cards::CardNumber,
    expiry_month: Secret<String>,
    expiry_year: Secret<String>,
    cvc: Secret<String>,
    complete: bool,
}

impl TryFrom<&TrustpaymentsRouterData<&PaymentsAuthorizeRouterData>>
    for TrustpaymentsPaymentsRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &TrustpaymentsRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(_) => Err(errors::ConnectorError::NotImplemented(
                "Card payment method not implemented".to_string(),
            )
            .into()),
            _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
        }
    }
}

//TODO: Fill the struct with respective fields
// Auth Struct
pub struct TrustpaymentsAuthType {
    pub(super) api_key: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for TrustpaymentsAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
                api_key: api_key.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}
// PaymentsResponse
//TODO: Append the remaining status flags
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum TrustpaymentsPaymentStatus {
    Succeeded,
    Failed,
    #[default]
    Processing,
}

impl From<TrustpaymentsPaymentStatus> for common_enums::AttemptStatus {
    fn from(item: TrustpaymentsPaymentStatus) -> Self {
        match item {
            TrustpaymentsPaymentStatus::Succeeded => Self::Charged,
            TrustpaymentsPaymentStatus::Failed => Self::Failure,
            TrustpaymentsPaymentStatus::Processing => Self::Authorizing,
        }
    }
}

//TODO: Fill the struct with respective fields
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TrustpaymentsPaymentsResponse {
    status: TrustpaymentsPaymentStatus,
    id: String,
}

impl<F, T> TryFrom<ResponseRouterData<F, TrustpaymentsPaymentsResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, TrustpaymentsPaymentsResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: common_enums::AttemptStatus::from(item.response.status),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

//TODO: Fill the struct with respective fields
// REFUND :
// Type definition for RefundRequest
#[derive(Default, Debug, Serialize)]
pub struct TrustpaymentsRefundRequest {
    pub amount: StringMinorUnit,
}

impl<F> TryFrom<&TrustpaymentsRouterData<&RefundsRouterData<F>>> for TrustpaymentsRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &TrustpaymentsRouterData<&RefundsRouterData<F>>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: item.amount.to_owned(),
        })
    }
}

// Type definition for Refund Response

#[allow(dead_code)]
#[derive(Debug, Copy, Serialize, Default, Deserialize, Clone)]
pub enum RefundStatus {
    Succeeded,
    Failed,
    #[default]
    Processing,
}

impl From<RefundStatus> for enums::RefundStatus {
    fn from(item: RefundStatus) -> Self {
        match item {
            RefundStatus::Succeeded => Self::Success,
            RefundStatus::Failed => Self::Failure,
            RefundStatus::Processing => Self::Pending,
            //TODO: Review mapping
        }
    }
}

//TODO: Fill the struct with respective fields
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct RefundResponse {
    id: String,
    status: RefundStatus,
}

impl TryFrom<RefundsResponseRouterData<Execute, RefundResponse>> for RefundsRouterData<Execute> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status: enums::RefundStatus::from(item.response.status),
            }),
            ..item.data
        })
    }
}

impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for RefundsRouterData<RSync> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status: enums::RefundStatus::from(item.response.status),
            }),
            ..item.data
        })
    }
}

//TODO: Fill the struct with respective fields
#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
pub struct TrustpaymentsErrorResponse {
    pub status_code: u16,
    pub code: String,
    pub message: String,
    pub reason: Option<String>,
    pub network_advice_code: Option<String>,
    pub network_decline_code: Option<String>,
    pub network_error_message: Option<String>,
}


pub struct ClientAuthSetupInfoResponse {
    id: String,
    client_reference_information: ClientReferenceInformation,
    consumer_authentication_information: BarclaycardConsumerAuthInformationResponse,
}


impl<'a> NetworkTokenizationBuilder<'a, CardTokenStored> {
    pub fn set_payment_method_response(
        self,
        payment_method: &'a domain::PaymentMethod,
    ) -> NetworkTokenizationBuilder<'a, PaymentMethodCreated> {
        let card_detail_from_locker = self.card.as_ref().map(|card| api::CardDetailFromLocker {
            scheme: None,
            issuer_country: card.card_issuing_country.clone(),
            last4_digits: Some(card.card_number.clone().get_last4()),
            card_number: None,
            expiry_month: Some(card.card_exp_month.clone().clone()),
            expiry_year: Some(card.card_exp_year.clone().clone()),
            card_token: None,
            card_holder_name: card.card_holder_name.clone(),
            card_fingerprint: None,
            nick_name: card.nick_name.clone(),
            card_network: card.card_network.clone(),
            card_isin: Some(card.card_number.clone().get_card_isin()),
            card_issuer: card.card_issuer.clone(),
            card_type: card.card_type.clone(),
            saved_to_locker: true,
        });
        let payment_method_response = api::PaymentMethodResponse {
            merchant_id: payment_method.merchant_id.clone(),
            customer_id: Some(payment_method.customer_id.clone()),
            payment_method_id: payment_method.payment_method_id.clone(),
            payment_method: payment_method.payment_method,
            payment_method_type: payment_method.payment_method_type,
            card: card_detail_from_locker,
            recurring_enabled: Some(true),
            installment_payment_enabled: Some(false),
            metadata: payment_method.metadata.clone(),
            created: Some(payment_method.created_at),
            last_used_at: Some(payment_method.last_used_at),
            client_secret: payment_method.client_secret.clone(),
            bank_transfer: None,
            payment_experience: None,
        };
        NetworkTokenizationBuilder {
            state: std::marker::PhantomData,
            payment_method_response: Some(payment_method_response),
            customer: self.customer,
            card: self.card,
            card_cvc: self.card_cvc,
            network_token: self.network_token,
            stored_card: self.stored_card,
            stored_token: self.stored_token,
            card_tokenized: self.card_tokenized,
            error_code: self.error_code,
            error_message: self.error_message,
        }
    }
}


pub fn refunds_list() {}


pub struct Transaction;


pub fn filter_ntid_supported_connectors(
    connectors: Vec<api::ConnectorRoutingData>,
    ntid_supported_connectors: &HashSet<enums::Connector>,
) -> Vec<api::ConnectorRoutingData> {
    connectors
        .into_iter()
        .filter(|data| ntid_supported_connectors.contains(&data.connector_data.connector_name))
        .collect()
}


pub struct Error {
    pub code: Option<String>,
    pub property_name: Option<String>,
    pub message: Option<String>,
}


pub fn get_gsm_decision(
    option_gsm: Option<hyperswitch_domain_models::gsm::GatewayStatusMap>,
) -> common_enums::GsmDecision {
    let option_gsm_decision = option_gsm.map(|gsm| gsm.feature_data.get_decision());

    if option_gsm_decision.is_some() {
        metrics::AUTO_PAYOUT_RETRY_GSM_MATCH_COUNT.add(1, &[]);
    }
    option_gsm_decision.unwrap_or_default()
}


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

use masking::Secret;
use router::{
    types::{self, api, storage::enums,
}};

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

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

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

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

static CONNECTOR: CustombillingTest = CustombillingTest {};

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: types::api::PaymentMethodData::Card(api::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: api::PaymentMethodData::Card(api::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: api::PaymentMethodData::Card(api::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 struct PlatformOrgAdminAuthWithMerchantIdFromRoute {
    pub merchant_id_from_route: id_type::MerchantId,
    pub is_admin_auth_allowed: bool,
}


pub struct ApplePayDecryptedData {
    pub data: Secret<String>,
    pub signature: Secret<String>,
    pub version: Secret<String>,
    pub header: ApplePayHeader,
}


impl PartialEq for AuthEventMetricsBucketIdentifier {
    fn eq(&self, other: &Self) -> bool {
        let mut left = DefaultHasher::new();
        self.hash(&mut left);
        let mut right = DefaultHasher::new();
        other.hash(&mut right);
        left.finish() == right.finish()
    }
}

impl PartialEq for for AuthEventMetricsBucketIdentifier


pub struct AuthipayVoidRequest {
    request_type: &'static str,
}


pub async fn payouts_update() {}


pub struct TryGetEnumMeta {
    error_type: syn::Ident,
    variant: syn::Ident,
}


pub struct StaxBankTokenizeData {
    person_name: Secret<String>,
    bank_account: Secret<String>,
    bank_routing: Secret<String>,
    bank_name: common_enums::BankNames,
    bank_type: common_enums::BankType,
    bank_holder_type: common_enums::BankHolderType,
    customer_id: Secret<String>,
}


impl common_utils::events::ApiEventMetric for ProxyResponse {}

impl common_utils::events::ApiEventMetric for for ProxyResponse


File: crates/hyperswitch_interfaces/src/api/vault_v2.rs

//! Vault V2 interface
use hyperswitch_domain_models::{
    router_data_v2::flow_common_types::VaultConnectorFlowData,
    router_flow_types::vault::{
        ExternalVaultCreateFlow, ExternalVaultDeleteFlow, ExternalVaultInsertFlow,
        ExternalVaultRetrieveFlow,
    },
    router_request_types::VaultRequestData,
    router_response_types::VaultResponseData,
};

use super::ConnectorCommon;
use crate::api::ConnectorIntegrationV2;

/// trait ExternalVaultInsertV2
pub trait ExternalVaultInsertV2:
    ConnectorIntegrationV2<
    ExternalVaultInsertFlow,
    VaultConnectorFlowData,
    VaultRequestData,
    VaultResponseData,
>
{
}
/// trait ExternalVaultRetrieveV2
pub trait ExternalVaultRetrieveV2:
    ConnectorIntegrationV2<
    ExternalVaultRetrieveFlow,
    VaultConnectorFlowData,
    VaultRequestData,
    VaultResponseData,
>
{
}

/// trait ExternalVaultDeleteV2
pub trait ExternalVaultDeleteV2:
    ConnectorIntegrationV2<
    ExternalVaultDeleteFlow,
    VaultConnectorFlowData,
    VaultRequestData,
    VaultResponseData,
>
{
}

/// trait ExternalVaultDeleteV2
pub trait ExternalVaultCreateV2:
    ConnectorIntegrationV2<
    ExternalVaultCreateFlow,
    VaultConnectorFlowData,
    VaultRequestData,
    VaultResponseData,
>
{
}

/// trait ExternalVaultV2
pub trait ExternalVaultV2:
    ConnectorCommon
    + ExternalVaultInsertV2
    + ExternalVaultRetrieveV2
    + ExternalVaultDeleteV2
    + ExternalVaultCreateV2
{
}


pub struct GetAuthEventFilterRequest {
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<AuthEventDimensions>,
}


pub struct Dlocal {
    amount_convertor: &'static (dyn AmountConvertor<Output = MinorUnit> + Sync),
}


impl api::Payment for Affirm {}


impl ConnectorAccessToken for Signifyd {}

impl ConnectorAccessToken for for Signifyd


pub struct ChargebeePaymentMethod {
    pub reference_id: String,
    pub gateway: ChargebeeGateway,
}


pub async fn profile_retrieve() {}


pub fn cors(config: settings::CorsSettings) -> actix_cors::Cors {
    let allowed_methods = config.allowed_methods.iter().map(|s| s.as_str());

    let mut cors = actix_cors::Cors::default()
        .allowed_methods(allowed_methods)
        .allow_any_header()
        .expose_any_header()
        .max_age(config.max_age);

    if config.wildcard_origin {
        cors = cors.allow_any_origin()
    } else {
        for origin in &config.origins {
            cors = cors.allowed_origin(origin);
        }
        // Only allow this in case if it's not wildcard origins. ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
        cors = cors.supports_credentials();
    }

    cors
}


pub struct CardCapRes {
    pub card_type: Option<Secret<String>>,
    pub card_type_name: Option<Secret<String>>,
    unmasked_account_number: Option<Secret<String>>,
}


pub struct MerchantAccountIdentifier {
    pub merchant_id: id_type::MerchantId,
    pub org_id: id_type::OrganizationId,
}


pub fn server(state: AppState) -> Scope {
        use super::process_tracker::revenue_recovery;
        // TODO: Deprecated. Remove this in favour of /v2/process-trackers
        web::scope("/v2/process_tracker/revenue_recovery_workflow")
            .app_data(web::Data::new(state.clone()))
            .service(
                web::resource("/{revenue_recovery_id}")
                    .route(web::get().to(revenue_recovery::revenue_recovery_pt_retrieve_api)),
            )
    }


impl api::PaymentVoid for Hipay {}


impl Responder {
    let flow = Flow::PaymentsUpdateMetadata;

    let payment_id = path.into_inner();
    let payload = payment_types::PaymentsUpdateMetadataRequest {
        payment_id,
        ..json_payload.into_inner()
    };
    tracing::Span::current().record("payment_id", payload.payment_id.get_string_repr());
    let header_payload = match HeaderPayload::foreign_try_from(req.headers()) {
        Ok(headers) => headers,
        Err(err) => {
            return api::log_and_return_error_response(err);
        }
    };

    let locking_action = payload.get_locking_input(flow.clone());

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth, req, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payments::payments_core::<
                api_types::UpdateMetadata,
                payment_types::PaymentsUpdateMetadataResponse,
                _,
                _,
                _,
                payments::PaymentData<api_types::UpdateMetadata>,
            >(
                state,
                req_state,
                merchant_context,
                auth.profile_id,
                payments::PaymentUpdateMetadata,
                req,
                api::AuthFlow::Client,
                payments::CallConnectorAction::Trigger,
                None,
                header_payload.clone(),
            )
        },
        &auth::HeaderAuth(auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: true,
        }),
        locking_action,
    ))
    .await
}


pub fn add_certificate(&mut self, certificate: Option<Secret<String>>) {
        self.certificate = certificate;
    }


OpenAPI Block Path: components.schemas.UIWidgetFormLayout
{
  "type": "string",
  "enum": [
    "tabs",
    "journey"
  ]
}


pub struct PayeezyPaymentsRequest {
    pub merchant_ref: String,
    pub transaction_type: PayeezyTransactionType,
    pub method: PayeezyPaymentMethodType,
    pub amount: String,
    pub currency_code: String,
    pub credit_card: PayeezyPaymentMethod,
    pub stored_credentials: Option<StoredCredentials>,
    pub reference: String,
}


    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

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

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

lazy_static! {
    static ref NEXIXPAY_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
        display_name: "Nexixpay",
        description: "Nexixpay is an Italian bank that specialises in payment systems such as Nexi Payments (formerly known as CartaSi).",
        connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
        integration_status: enums::ConnectorIntegrationStatus::Sandbox,
    };

    static ref NEXIXPAY_SUPPORTED_PAYMENT_METHODS: SupportedPaymentMethods = {

        let supported_capture_methods = vec![
                    enums::CaptureMethod::Automatic,
                    enums::CaptureMethod::Manual,
                    enums::CaptureMethod::SequentialAutomatic,
                ];

        let supported_card_network = vec![
                    common_enums::CardNetwork::Visa,
                    common_enums::CardNetwork::Mastercard,
                    common_enums::CardNetwork::AmericanExpress,
                    common_enums::CardNetwork::JCB,
                ];

        let mut nexixpay_supported_payment_methods = SupportedPaymentMethods::new();

        nexixpay_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Credit,
            PaymentMethodDetails {
                mandates: common_enums::FeatureStatus::Supported,
                refunds: common_enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: Some(
                    api_models::feature_matrix::PaymentMethodSpecificFeatures::Card({
                        api_models::feature_matrix::CardSpecificFeatures {
                            three_ds: common_enums::FeatureStatus::Supported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                )
            }
        );
        nexixpay_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Debit,
            PaymentMethodDetails {
                mandates: common_enums::FeatureStatus::Supported,
                refunds: common_enums::FeatureStatus::Supported,
                supported_capture_methods,
                specific_features: Some(
                    api_models::feature_matrix::PaymentMethodSpecificFeatures::Card({
                        api_models::feature_matrix::CardSpecificFeatures {
                            three_ds: common_enums::FeatureStatus::Supported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network,
                        }
                    }),
                )
            }
        );

        nexixpay_supported_payment_methods
    };

    static ref NEXIXPAY_SUPPORTED_WEBHOOK_FLOWS: Vec<enums::EventClass> = Vec::new();
}

impl ConnectorSpecifications for Nexixpay {
    fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
        Some(&*NEXIXPAY_CONNECTOR_INFO)
    }

    fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
        Some(&*NEXIXPAY_SUPPORTED_PAYMENT_METHODS)
    }

    fn get_supported_webhook_flows(&self) -> Option<&'static [enums::EventClass]> {
        Some(&*NEXIXPAY_SUPPORTED_WEBHOOK_FLOWS)
    }
}