// File: crates/hyperswitch_connectors/src/connectors/loonio/transformers.rs
// Module: hyperswitch_connectors
// Public structs: 10

use std::collections::HashMap;

use common_enums::{enums, Currency};
use common_utils::{id_type, pii::Email, request::Method, types::FloatMajorUnit};
use hyperswitch_domain_models::{
    payment_method_data::{BankRedirectData, PaymentMethodData},
    router_data::{ConnectorAuthType, RouterData},
    router_flow_types::refunds::{Execute, RSync},
    router_request_types::ResponseId,
    router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData},
    types::{PaymentsAuthorizeRouterData, RefundsRouterData},
};
use hyperswitch_interfaces::errors;
use masking::Secret;
use serde::{Deserialize, Serialize};

use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    utils::{self, PaymentsAuthorizeRequestData, RouterData as _},
};

pub struct LoonioRouterData<T> {
    pub amount: FloatMajorUnit,
    pub router_data: T,
}

impl<T> From<(FloatMajorUnit, T)> for LoonioRouterData<T> {
    fn from((amount, item): (FloatMajorUnit, T)) -> Self {
        Self {
            amount,
            router_data: item,
        }
    }
}

// Auth Struct
pub struct LoonioAuthType {
    pub(super) merchant_id: Secret<String>,
    pub(super) merchant_token: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for LoonioAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
                merchant_id: api_key.to_owned(),
                merchant_token: key1.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

#[derive(Debug, Serialize)]
pub struct LoonioPaymentRequest {
    pub currency_code: Currency,
    pub customer_profile: LoonioCustomerProfile,
    pub amount: FloatMajorUnit,
    pub customer_id: id_type::CustomerId,
    pub transaction_id: String,
    pub payment_method_type: InteracPaymentMethodType,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub redirect_url: Option<LoonioRedirectUrl>,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum InteracPaymentMethodType {
    InteracEtransfer,
}

#[derive(Debug, Serialize)]
pub struct LoonioCustomerProfile {
    pub first_name: Secret<String>,
    pub last_name: Secret<String>,
    pub email: Email,
}

#[derive(Debug, Serialize)]
pub struct LoonioRedirectUrl {
    pub success_url: String,
    pub failed_url: String,
}

impl TryFrom<&LoonioRouterData<&PaymentsAuthorizeRouterData>> for LoonioPaymentRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &LoonioRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::BankRedirect(BankRedirectData::Interac { .. }) => {
                let transaction_id = item.router_data.connector_request_reference_id.clone();

                let customer_profile = LoonioCustomerProfile {
                    first_name: item.router_data.get_billing_first_name()?,
                    last_name: item.router_data.get_billing_last_name()?,
                    email: item.router_data.get_billing_email()?,
                };

                let redirect_url = LoonioRedirectUrl {
                    success_url: item.router_data.request.get_router_return_url()?,
                    failed_url: item.router_data.request.get_router_return_url()?,
                };

                Ok(Self {
                    currency_code: item.router_data.request.currency,
                    customer_profile,
                    amount: item.amount,
                    customer_id: item.router_data.get_customer_id()?,
                    transaction_id,
                    payment_method_type: InteracPaymentMethodType::InteracEtransfer,
                    redirect_url: Some(redirect_url),
                })
            }
            PaymentMethodData::BankRedirect(_) => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("Loonio"),
            ))?,

            _ => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("Loonio"),
            )
            .into()),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoonioPaymentsResponse {
    pub payment_form: String,
}

impl<F, T> TryFrom<ResponseRouterData<F, LoonioPaymentsResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, LoonioPaymentsResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: enums::AttemptStatus::AuthenticationPending,
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.payment_form.clone()),
                redirection_data: Box::new(Some(RedirectForm::Form {
                    endpoint: item.response.payment_form,
                    method: Method::Get,
                    form_fields: HashMap::new(),
                })),
                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
        })
    }
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum LoonioTransactionStatus {
    Created,
    Prepared,
    Pending,
    Settled,
    Available,
    Abandoned,
    Rejected,
    Failed,
    Rollback,
    Returned,
    Nsf,
}

impl From<LoonioTransactionStatus> for enums::AttemptStatus {
    fn from(item: LoonioTransactionStatus) -> Self {
        match item {
            LoonioTransactionStatus::Created => Self::AuthenticationPending,
            LoonioTransactionStatus::Prepared | LoonioTransactionStatus::Pending => Self::Pending,
            LoonioTransactionStatus::Settled | LoonioTransactionStatus::Available => Self::Charged,
            LoonioTransactionStatus::Abandoned
            | LoonioTransactionStatus::Rejected
            | LoonioTransactionStatus::Failed
            | LoonioTransactionStatus::Returned
            | LoonioTransactionStatus::Nsf => Self::Failure,
            LoonioTransactionStatus::Rollback => Self::Voided,
        }
    }
}

// Sync Response Structures
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoonioTransactionSyncResponse {
    pub transaction_id: String,
    pub state: LoonioTransactionStatus,
}

#[derive(Default, Debug, Serialize)]
pub struct LoonioRefundRequest {
    pub amount: FloatMajorUnit,
}

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

impl<F, T> TryFrom<ResponseRouterData<F, LoonioTransactionSyncResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, LoonioTransactionSyncResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: enums::AttemptStatus::from(item.response.state),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.response.transaction_id.clone(),
                ),
                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
        })
    }
}

// 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)]
pub struct LoonioErrorResponse {
    pub status: u16,
    pub error_code: Option<String>,
    pub message: String,
}


// Struct: ErrorResponseBankRedirect
// File: crates/hyperswitch_connectors/src/connectors/trustpay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ErrorResponseBankRedirect


// Struct: PayloadEventDetails
// File: crates/hyperswitch_connectors/src/connectors/payload/responses.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PayloadEventDetails


// Function: set_response_body
// File: crates/hyperswitch_interfaces/src/events/connector_api_logs.rs
// Module: hyperswitch_interfaces

// Documentation: fn set_response_body

pub fn set_response_body<T: Serialize>(&mut self, response: &T)


// Implementation: impl api::Refund for for Nuvei
// File: crates/hyperswitch_connectors/src/connectors/nuvei.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Refund for for Nuvei


// Struct: ApiKey
// File: crates/diesel_models/src/api_keys.rs
// Module: diesel_models
// Implementations: 0

pub struct ApiKey


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

impl api::PaymentsCompleteAuthorize for for Authorizedotnet


// Struct: ChargebeeListPlansResponse
// File: crates/hyperswitch_connectors/src/connectors/chargebee/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ChargebeeListPlansResponse


// Function: perform_open_routing_for_debit_routing
// File: crates/router/src/core/payments/routing.rs
// Module: router

pub fn perform_open_routing_for_debit_routing<F, D>(
    state: &SessionState,
    co_badged_card_request: or_types::CoBadgedCardRequest,
    card_isin: Option<Secret<String>>,
    old_payment_data: &mut D,
) -> RoutingResult<or_types::DebitRoutingOutput>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,


// Implementation: impl PaymentMethodCreate
// File: crates/api_models/src/payment_methods.rs
// Module: api_models
// Methods: 1 total (1 public)

impl PaymentMethodCreate


// Function: get_string_repr
// File: crates/common_utils/src/id_type/global_id/payment.rs
// Module: common_utils

// Documentation: Get string representation of the id

pub fn get_string_repr(&self) -> &str


// Implementation: impl IncomingWebhook for for Rapyd
// File: crates/hyperswitch_connectors/src/connectors/rapyd.rs
// Module: hyperswitch_connectors
// Methods: 8 total (0 public)

impl IncomingWebhook for for Rapyd


// File: crates/hyperswitch_connectors/src/connectors/iatapay/transformers.rs
// Module: hyperswitch_connectors
// Public structs: 16

use std::collections::HashMap;

use api_models::webhooks::IncomingWebhookEvent;
use common_enums::enums;
use common_utils::{
    errors::CustomResult, ext_traits::Encode, request::Method, types::FloatMajorUnit,
};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    payment_method_data::{BankRedirectData, PaymentMethodData, RealTimePaymentData, UpiData},
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        refunds::{Execute, RSync},
        Authorize,
    },
    router_request_types::{PaymentsAuthorizeData, ResponseId},
    router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData},
    types::{self, RefundsRouterData},
};
use hyperswitch_interfaces::{
    consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE},
    errors,
};
use masking::{Secret, SwitchStrategy};
use serde::{Deserialize, Serialize};

use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    utils::{
        get_unimplemented_payment_method_error_message, is_payment_failure, is_refund_failure,
        PaymentsAuthorizeRequestData, RefundsRequestData,
    },
};

type Error = error_stack::Report<errors::ConnectorError>;

// Every access token will be valid for 5 minutes. It contains grant_type and scope for different type of access, but for our usecases it should be only 'client_credentials' and 'payment' resp(as per doc) for all type of api call.
#[derive(Debug, Serialize)]
pub struct IatapayAuthUpdateRequest {
    grant_type: String,
    scope: String,
}
impl TryFrom<&types::RefreshTokenRouterData> for IatapayAuthUpdateRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(_item: &types::RefreshTokenRouterData) -> Result<Self, Self::Error> {
        Ok(Self {
            grant_type: "client_credentials".to_string(),
            scope: "payment".to_string(),
        })
    }
}
#[derive(Debug, Serialize)]
pub struct IatapayRouterData<T> {
    amount: FloatMajorUnit,
    router_data: T,
}
impl<T> TryFrom<(FloatMajorUnit, T)> for IatapayRouterData<T> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from((amount, item): (FloatMajorUnit, T)) -> Result<Self, Self::Error> {
        Ok(Self {
            amount,
            router_data: item,
        })
    }
}
#[derive(Debug, Deserialize, Serialize)]
pub struct IatapayAuthUpdateResponse {
    pub access_token: Secret<String>,
    pub expires_in: i64,
}

impl<F, T> TryFrom<ResponseRouterData<F, IatapayAuthUpdateResponse, T, AccessToken>>
    for RouterData<F, T, AccessToken>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, IatapayAuthUpdateResponse, T, AccessToken>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(AccessToken {
                token: item.response.access_token,
                expires: item.response.expires_in,
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RedirectUrls {
    success_url: String,
    failure_url: String,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PayerInfo {
    token_id: Secret<String>,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum PreferredCheckoutMethod {
    Vpa, //Passing this in UPI_COLLECT will trigger an S2S payment call which is not required.
    Qr,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct IatapayPaymentsRequest {
    merchant_id: Secret<String>,
    merchant_payment_id: Option<String>,
    amount: FloatMajorUnit,
    currency: common_enums::Currency,
    country: common_enums::CountryAlpha2,
    locale: String,
    redirect_urls: RedirectUrls,
    notification_url: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    payer_info: Option<PayerInfo>,
    #[serde(skip_serializing_if = "Option::is_none")]
    preferred_checkout_method: Option<PreferredCheckoutMethod>,
}

impl
    TryFrom<&IatapayRouterData<&RouterData<Authorize, PaymentsAuthorizeData, PaymentsResponseData>>>
    for IatapayPaymentsRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        item: &IatapayRouterData<
            &RouterData<Authorize, PaymentsAuthorizeData, PaymentsResponseData>,
        >,
    ) -> Result<Self, Self::Error> {
        let return_url = item.router_data.request.get_router_return_url()?;
        // Iatapay processes transactions through the payment method selected based on the country
        let (country, payer_info, preferred_checkout_method) = match item
            .router_data
            .request
            .payment_method_data
            .clone()
        {
            PaymentMethodData::Upi(upi_type) => match upi_type {
                UpiData::UpiCollect(upi_data) => (
                    common_enums::CountryAlpha2::IN,
                    upi_data.vpa_id.map(|id| PayerInfo {
                        token_id: id.switch_strategy(),
                    }),
                    None,
                ),
                UpiData::UpiIntent(_) => (
                    common_enums::CountryAlpha2::IN,
                    None,
                    Some(PreferredCheckoutMethod::Qr),
                ),
            },
            PaymentMethodData::BankRedirect(bank_redirect_data) => match bank_redirect_data {
                BankRedirectData::Ideal { .. } => (common_enums::CountryAlpha2::NL, None, None),
                BankRedirectData::LocalBankRedirect {} => {
                    (common_enums::CountryAlpha2::AT, None, None)
                }
                BankRedirectData::BancontactCard { .. }
                | BankRedirectData::Bizum {}
                | BankRedirectData::Blik { .. }
                | BankRedirectData::Eft { .. }
                | BankRedirectData::Eps { .. }
                | BankRedirectData::Giropay { .. }
                | BankRedirectData::Interac { .. }
                | BankRedirectData::OnlineBankingCzechRepublic { .. }
                | BankRedirectData::OnlineBankingFinland { .. }
                | BankRedirectData::OnlineBankingPoland { .. }
                | BankRedirectData::OnlineBankingSlovakia { .. }
                | BankRedirectData::OpenBankingUk { .. }
                | BankRedirectData::Przelewy24 { .. }
                | BankRedirectData::Sofort { .. }
                | BankRedirectData::Trustly { .. }
                | BankRedirectData::OnlineBankingFpx { .. }
                | BankRedirectData::OnlineBankingThailand { .. } => {
                    Err(errors::ConnectorError::NotImplemented(
                        get_unimplemented_payment_method_error_message("iatapay"),
                    ))?
                }
            },
            PaymentMethodData::RealTimePayment(real_time_payment_data) => {
                match *real_time_payment_data {
                    RealTimePaymentData::DuitNow {} => {
                        (common_enums::CountryAlpha2::MY, None, None)
                    }
                    RealTimePaymentData::Fps {} => (common_enums::CountryAlpha2::HK, None, None),
                    RealTimePaymentData::PromptPay {} => {
                        (common_enums::CountryAlpha2::TH, None, None)
                    }
                    RealTimePaymentData::VietQr {} => (common_enums::CountryAlpha2::VN, None, None),
                }
            }
            PaymentMethodData::Card(_)
            | PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::Wallet(_)
            | PaymentMethodData::PayLater(_)
            | PaymentMethodData::BankDebit(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::Crypto(_)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::MobilePayment(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::NetworkToken(_)
            | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
                Err(errors::ConnectorError::NotImplemented(
                    get_unimplemented_payment_method_error_message("iatapay"),
                ))?
            }
        };
        let payload = Self {
            merchant_id: IatapayAuthType::try_from(&item.router_data.connector_auth_type)?
                .merchant_id,
            merchant_payment_id: Some(item.router_data.connector_request_reference_id.clone()),
            amount: item.amount,
            currency: item.router_data.request.currency,
            country,
            locale: format!("en-{country}"),
            redirect_urls: get_redirect_url(return_url),
            payer_info,
            notification_url: item.router_data.request.get_webhook_url()?,
            preferred_checkout_method,
        };
        Ok(payload)
    }
}

fn get_redirect_url(return_url: String) -> RedirectUrls {
    RedirectUrls {
        success_url: return_url.clone(),
        failure_url: return_url,
    }
}

// Auth Struct
pub struct IatapayAuthType {
    pub(super) client_id: Secret<String>,
    pub(super) merchant_id: Secret<String>,
    pub(super) client_secret: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for IatapayAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::SignatureKey {
                api_key,
                key1,
                api_secret,
            } => Ok(Self {
                client_id: api_key.to_owned(),
                merchant_id: key1.to_owned(),
                client_secret: api_secret.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType)?,
        }
    }
}
// PaymentsResponse
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum IatapayPaymentStatus {
    #[default]
    Created,
    Initiated,
    Authorized,
    Settled,
    Cleared,
    Failed,
    #[serde(rename = "UNEXPECTED SETTLED")]
    UnexpectedSettled,
}

impl From<IatapayPaymentStatus> for enums::AttemptStatus {
    fn from(item: IatapayPaymentStatus) -> Self {
        match item {
            IatapayPaymentStatus::Authorized
            | IatapayPaymentStatus::Settled
            | IatapayPaymentStatus::Cleared => Self::Charged,
            IatapayPaymentStatus::Failed | IatapayPaymentStatus::UnexpectedSettled => Self::Failure,
            IatapayPaymentStatus::Created => Self::AuthenticationPending,
            IatapayPaymentStatus::Initiated => Self::Pending,
        }
    }
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct RedirectUrl {
    pub redirect_url: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CheckoutMethod {
    pub redirect: RedirectUrl,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct IatapayPaymentsResponse {
    pub status: IatapayPaymentStatus,
    pub iata_payment_id: Option<String>,
    pub iata_refund_id: Option<String>,
    pub merchant_id: Option<Secret<String>>,
    pub merchant_payment_id: Option<String>,
    pub amount: FloatMajorUnit,
    pub currency: String,
    pub checkout_methods: Option<CheckoutMethod>,
    pub failure_code: Option<String>,
    pub failure_details: Option<String>,
}

fn get_iatpay_response(
    response: IatapayPaymentsResponse,
    status_code: u16,
) -> CustomResult<
    (
        enums::AttemptStatus,
        Option<ErrorResponse>,
        PaymentsResponseData,
    ),
    errors::ConnectorError,
> {
    let status = enums::AttemptStatus::from(response.status);
    let error = if is_payment_failure(status) {
        Some(ErrorResponse {
            code: response
                .failure_code
                .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
            message: response
                .failure_details
                .clone()
                .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
            reason: response.failure_details,
            status_code,
            attempt_status: Some(status),
            connector_transaction_id: response.iata_payment_id.clone(),
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    } else {
        None
    };
    let form_fields = HashMap::new();
    let id = match response.iata_payment_id.clone() {
        Some(s) => ResponseId::ConnectorTransactionId(s),
        None => ResponseId::NoResponseId,
    };
    let connector_response_reference_id = response.merchant_payment_id.or(response.iata_payment_id);

    let payment_response_data = match response.checkout_methods {
        Some(checkout_methods) => {
            let (connector_metadata, redirection_data) =
                match checkout_methods.redirect.redirect_url.ends_with("qr") {
                    true => {
                        let qr_code_info = api_models::payments::FetchQrCodeInformation {
                            qr_code_fetch_url: url::Url::parse(
                                &checkout_methods.redirect.redirect_url,
                            )
                            .change_context(errors::ConnectorError::ResponseHandlingFailed)?,
                        };
                        (
                            Some(qr_code_info.encode_to_value())
                                .transpose()
                                .change_context(errors::ConnectorError::ResponseHandlingFailed)?,
                            None,
                        )
                    }
                    false => (
                        None,
                        Some(RedirectForm::Form {
                            endpoint: checkout_methods.redirect.redirect_url,
                            method: Method::Get,
                            form_fields,
                        }),
                    ),
                };

            PaymentsResponseData::TransactionResponse {
                resource_id: id,
                redirection_data: Box::new(redirection_data),
                mandate_reference: Box::new(None),
                connector_metadata,
                network_txn_id: None,
                connector_response_reference_id: connector_response_reference_id.clone(),
                incremental_authorization_allowed: None,
                charges: None,
            }
        }
        None => PaymentsResponseData::TransactionResponse {
            resource_id: id.clone(),
            redirection_data: Box::new(None),
            mandate_reference: Box::new(None),
            connector_metadata: None,
            network_txn_id: None,
            connector_response_reference_id: connector_response_reference_id.clone(),
            incremental_authorization_allowed: None,
            charges: None,
        },
    };

    Ok((status, error, payment_response_data))
}

impl<F, T> TryFrom<ResponseRouterData<F, IatapayPaymentsResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = Error;
    fn try_from(
        item: ResponseRouterData<F, IatapayPaymentsResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        let (status, error, payment_response_data) =
            get_iatpay_response(item.response, item.http_code)?;
        Ok(Self {
            status,
            response: error.map_or_else(|| Ok(payment_response_data), Err),
            ..item.data
        })
    }
}

// REFUND :
// Type definition for RefundRequest
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct IatapayRefundRequest {
    pub merchant_id: Secret<String>,
    pub merchant_refund_id: Option<String>,
    pub amount: FloatMajorUnit,
    pub currency: String,
    pub bank_transfer_description: Option<String>,
    pub notification_url: String,
}

impl<F> TryFrom<&IatapayRouterData<&RefundsRouterData<F>>> for IatapayRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &IatapayRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: item.amount,
            merchant_id: IatapayAuthType::try_from(&item.router_data.connector_auth_type)?
                .merchant_id,
            merchant_refund_id: Some(item.router_data.request.refund_id.clone()),
            currency: item.router_data.request.currency.to_string(),
            bank_transfer_description: item.router_data.request.reason.clone(),
            notification_url: item.router_data.request.get_webhook_url()?,
        })
    }
}

// Type definition for Refund Response

#[allow(dead_code)]
#[derive(Debug, Serialize, Default, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum RefundStatus {
    #[default]
    Created,
    Locked,
    Initiated,
    Authorized,
    Settled,
    Cleared,
    Failed,
}

impl From<RefundStatus> for enums::RefundStatus {
    fn from(item: RefundStatus) -> Self {
        match item {
            RefundStatus::Created => Self::Pending,
            RefundStatus::Failed => Self::Failure,
            RefundStatus::Locked => Self::Pending,
            RefundStatus::Initiated => Self::Pending,
            RefundStatus::Authorized => Self::Pending,
            RefundStatus::Settled => Self::Success,
            RefundStatus::Cleared => Self::Success,
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RefundResponse {
    iata_refund_id: String,
    status: RefundStatus,
    merchant_refund_id: String,
    amount: FloatMajorUnit,
    currency: String,
    bank_transfer_description: Option<String>,
    failure_code: Option<String>,
    failure_details: Option<String>,
    lock_reason: Option<String>,
    creation_date_time: Option<String>,
    finish_date_time: Option<String>,
    update_date_time: Option<String>,
    clearance_date_time: Option<String>,
    iata_payment_id: Option<String>,
    merchant_payment_id: Option<String>,
    payment_amount: Option<FloatMajorUnit>,
    merchant_id: Option<Secret<String>>,
    account_country: Option<String>,
}

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> {
        let refund_status = enums::RefundStatus::from(item.response.status);
        let response = if is_refund_failure(refund_status) {
            Err(ErrorResponse {
                code: item
                    .response
                    .failure_code
                    .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
                message: item
                    .response
                    .failure_details
                    .clone()
                    .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
                reason: item.response.failure_details,
                status_code: item.http_code,
                attempt_status: None,
                connector_transaction_id: Some(item.response.iata_refund_id.clone()),
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        } else {
            Ok(RefundsResponseData {
                connector_refund_id: item.response.iata_refund_id.to_string(),
                refund_status,
            })
        };

        Ok(Self {
            response,
            ..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> {
        let refund_status = enums::RefundStatus::from(item.response.status);
        let response = if is_refund_failure(refund_status) {
            Err(ErrorResponse {
                code: item
                    .response
                    .failure_code
                    .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
                message: item
                    .response
                    .failure_details
                    .clone()
                    .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
                reason: item.response.failure_details,
                status_code: item.http_code,
                attempt_status: None,
                connector_transaction_id: Some(item.response.iata_refund_id.clone()),
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        } else {
            Ok(RefundsResponseData {
                connector_refund_id: item.response.iata_refund_id.to_string(),
                refund_status,
            })
        };
        Ok(Self {
            response,
            ..item.data
        })
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct IatapayErrorResponse {
    pub status: Option<u16>,
    pub error: String,
    pub message: Option<String>,
    pub reason: Option<String>,
}

#[derive(Deserialize, Debug, Serialize)]
pub struct IatapayAccessTokenErrorResponse {
    pub error: String,
    pub path: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct IatapayPaymentWebhookBody {
    pub status: IatapayWebhookStatus,
    pub iata_payment_id: String,
    pub merchant_payment_id: Option<String>,
    pub failure_code: Option<String>,
    pub failure_details: Option<String>,
    pub amount: FloatMajorUnit,
    pub currency: String,
    pub checkout_methods: Option<CheckoutMethod>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct IatapayRefundWebhookBody {
    pub status: IatapayRefundWebhookStatus,
    pub iata_refund_id: String,
    pub merchant_refund_id: Option<String>,
    pub failure_code: Option<String>,
    pub failure_details: Option<String>,
    pub amount: FloatMajorUnit,
    pub currency: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum IatapayWebhookResponse {
    IatapayPaymentWebhookBody(IatapayPaymentWebhookBody),
    IatapayRefundWebhookBody(IatapayRefundWebhookBody),
}

impl TryFrom<IatapayWebhookResponse> for IncomingWebhookEvent {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(payload: IatapayWebhookResponse) -> CustomResult<Self, errors::ConnectorError> {
        match payload {
            IatapayWebhookResponse::IatapayPaymentWebhookBody(wh_body) => match wh_body.status {
                IatapayWebhookStatus::Authorized | IatapayWebhookStatus::Settled => {
                    Ok(Self::PaymentIntentSuccess)
                }
                IatapayWebhookStatus::Initiated => Ok(Self::PaymentIntentProcessing),
                IatapayWebhookStatus::Failed => Ok(Self::PaymentIntentFailure),
                IatapayWebhookStatus::Created
                | IatapayWebhookStatus::Cleared
                | IatapayWebhookStatus::Tobeinvestigated
                | IatapayWebhookStatus::Blocked
                | IatapayWebhookStatus::UnexpectedSettled
                | IatapayWebhookStatus::Unknown => Ok(Self::EventNotSupported),
            },
            IatapayWebhookResponse::IatapayRefundWebhookBody(wh_body) => match wh_body.status {
                IatapayRefundWebhookStatus::Cleared
                | IatapayRefundWebhookStatus::Authorized
                | IatapayRefundWebhookStatus::Settled => Ok(Self::RefundSuccess),
                IatapayRefundWebhookStatus::Failed => Ok(Self::RefundFailure),
                IatapayRefundWebhookStatus::Created
                | IatapayRefundWebhookStatus::Locked
                | IatapayRefundWebhookStatus::Initiated
                | IatapayRefundWebhookStatus::Unknown => Ok(Self::EventNotSupported),
            },
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum IatapayWebhookStatus {
    Created,
    Initiated,
    Authorized,
    Settled,
    Cleared,
    Failed,
    Tobeinvestigated,
    Blocked,
    #[serde(rename = "UNEXPECTED SETTLED")]
    UnexpectedSettled,
    #[serde(other)]
    Unknown,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum IatapayRefundWebhookStatus {
    Created,
    Initiated,
    Authorized,
    Settled,
    Failed,
    Cleared,
    Locked,
    #[serde(other)]
    Unknown,
}


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

pub struct AddressDetails


// Implementation: impl api::PaymentAuthorize for for Adyenplatform
// File: crates/hyperswitch_connectors/src/connectors/adyenplatform.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentAuthorize for for Adyenplatform


// Implementation: impl RoutableConnectorChoiceWithBucketName
// File: crates/api_models/src/routing.rs
// Module: api_models
// Methods: 1 total (1 public)

impl RoutableConnectorChoiceWithBucketName


// Struct: EbanxPayoutCreateRequest
// File: crates/hyperswitch_connectors/src/connectors/ebanx/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct EbanxPayoutCreateRequest


// Implementation: impl api::ConnectorAccessToken for for Worldpay
// File: crates/hyperswitch_connectors/src/connectors/worldpay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorAccessToken for for Worldpay


// Struct: PaymentsSessionData
// File: crates/hyperswitch_domain_models/src/router_request_types.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct PaymentsSessionData


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

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

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

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

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

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

static CONNECTOR: AmazonpayTest = AmazonpayTest {};

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


// Struct: TransactionFee
// File: crates/hyperswitch_connectors/src/connectors/nordea/responses.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TransactionFee


// Implementation: impl api::PaymentAuthorize for for Fiuu
// File: crates/hyperswitch_connectors/src/connectors/fiuu.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentAuthorize for for Fiuu


// Struct: ClientAuthCheckInfoResponse
// File: crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ClientAuthCheckInfoResponse


            | PaymentAction::CompleteAuthorize
            | PaymentAction::PaymentAuthenticateCompleteAuthorize => {
                Ok(CallConnectorAction::Trigger)
            }
        }
    }
}

static GLOBALPAY_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> =
    LazyLock::new(|| {
        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::DinersClub,
            common_enums::CardNetwork::Discover,
            common_enums::CardNetwork::Interac,
            common_enums::CardNetwork::JCB,
            common_enums::CardNetwork::CartesBancaires,
            common_enums::CardNetwork::UnionPay,
        ];

        let mut globalpay_supported_payment_methods = SupportedPaymentMethods::new();

        globalpay_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Credit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: 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::NotSupported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                ),
            },
        );

        globalpay_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Debit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: 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::NotSupported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                ),
            },
        );

        globalpay_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Ideal,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        globalpay_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Giropay,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );
        globalpay_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Sofort,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );
        globalpay_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Eps,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        globalpay_supported_payment_methods.add(
            enums::PaymentMethod::Wallet,
            enums::PaymentMethodType::GooglePay,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );
        globalpay_supported_payment_methods.add(
            enums::PaymentMethod::Wallet,
            enums::PaymentMethodType::Paypal,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        globalpay_supported_payment_methods
    });

static GLOBALPAY_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
        display_name: "Globalpay",
        description: "Global Payments is an American multinational financial technology company that provides payment technology and services to merchants, issuers and consumers.",
        connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
        integration_status: enums::ConnectorIntegrationStatus::Sandbox,
    };

static GLOBALPAY_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 1] = [enums::EventClass::Payments];

impl ConnectorSpecifications for Globalpay {
    fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
        Some(&GLOBALPAY_CONNECTOR_INFO)
    }

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

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


// Struct: PlaidBacs
// File: crates/hyperswitch_connectors/src/connectors/plaid/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PlaidBacs


// Function: payments_session_operation_core
// File: crates/router/src/core/payments/session_operation.rs
// Module: router

pub fn payments_session_operation_core<F, Req, Op, FData, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: domain::Profile,
    operation: Op,
    req: Req,
    payment_id: id_type::GlobalPaymentId,
    _call_connector_action: CallConnectorAction,
    header_payload: HeaderPayload,
) -> RouterResult<(D, Req, Option<domain::Customer>, Option<u16>, Option<u128>)>
where
    F: Send + Clone + Sync,
    Req: Send + Sync,
    Op: Operation<F, Req, Data = D> + Send + Sync,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,

    // To create connector flow specific interface data
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    // To construct connector flow specific api
    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,
    FData: Send + Sync + Clone,


// Function: is_update_required
// File: crates/router/src/utils/user/dashboard_metadata.rs
// Module: router

pub fn is_update_required(metadata: &UserResult<DashboardMetadata>) -> bool


// File: crates/analytics/src/refunds/distribution.rs
// Module: analytics
// Public structs: 1

use api_models::analytics::{
    refunds::{
        RefundDimensions, RefundDistributions, RefundFilters, RefundMetricsBucketIdentifier,
        RefundType,
    },
    Granularity, RefundDistributionBody, TimeRange,
};
use diesel_models::enums as storage_enums;
use time::PrimitiveDateTime;

use crate::{
    enums::AuthInfo,
    query::{Aggregate, GroupByClause, ToSql, Window},
    types::{AnalyticsCollection, AnalyticsDataSource, DBEnumWrapper, LoadRow, MetricsResult},
};

mod sessionized_distribution;

#[derive(Debug, PartialEq, Eq, serde::Deserialize)]
pub struct RefundDistributionRow {
    pub currency: Option<DBEnumWrapper<storage_enums::Currency>>,
    pub refund_status: Option<DBEnumWrapper<storage_enums::RefundStatus>>,
    pub connector: Option<String>,
    pub refund_type: Option<DBEnumWrapper<RefundType>>,
    pub profile_id: Option<String>,
    pub total: Option<bigdecimal::BigDecimal>,
    pub count: Option<i64>,
    pub refund_reason: Option<String>,
    pub refund_error_message: Option<String>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub start_bucket: Option<PrimitiveDateTime>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub end_bucket: Option<PrimitiveDateTime>,
}

pub trait RefundDistributionAnalytics: LoadRow<RefundDistributionRow> {}

#[async_trait::async_trait]
pub trait RefundDistribution<T>
where
    T: AnalyticsDataSource + RefundDistributionAnalytics,
{
    #[allow(clippy::too_many_arguments)]
    async fn load_distribution(
        &self,
        distribution: &RefundDistributionBody,
        dimensions: &[RefundDimensions],
        auth: &AuthInfo,
        filters: &RefundFilters,
        granularity: &Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<Vec<(RefundMetricsBucketIdentifier, RefundDistributionRow)>>;
}

#[async_trait::async_trait]
impl<T> RefundDistribution<T> for RefundDistributions
where
    T: AnalyticsDataSource + RefundDistributionAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_distribution(
        &self,
        distribution: &RefundDistributionBody,
        dimensions: &[RefundDimensions],
        auth: &AuthInfo,
        filters: &RefundFilters,
        granularity: &Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<Vec<(RefundMetricsBucketIdentifier, RefundDistributionRow)>> {
        match self {
            Self::SessionizedRefundReason => {
                sessionized_distribution::RefundReason
                    .load_distribution(
                        distribution,
                        dimensions,
                        auth,
                        filters,
                        granularity,
                        time_range,
                        pool,
                    )
                    .await
            }
            Self::SessionizedRefundErrorMessage => {
                sessionized_distribution::RefundErrorMessage
                    .load_distribution(
                        distribution,
                        dimensions,
                        auth,
                        filters,
                        granularity,
                        time_range,
                        pool,
                    )
                    .await
            }
        }
    }
}


// Implementation: impl EphemeralKeyInterface for for KafkaStore
// File: crates/router/src/db/kafka_store.rs
// Module: router
// Methods: 3 total (0 public)

impl EphemeralKeyInterface for for KafkaStore


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

pub fn get_enable_overcapture_bool_if_connector_supports(
        &self,
        connector: common_enums::connector_enums::Connector,
        always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
        capture_method: &Option<common_enums::CaptureMethod>,
    ) -> Option<EnableOvercaptureBool>


// Implementation: impl AnalyticsConfig
// File: crates/analytics/src/lib.rs
// Module: analytics
// Methods: 1 total (1 public)

impl AnalyticsConfig


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

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

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

#[derive(Clone, Copy)]
struct WellsfargopayoutTest;
impl ConnectorActions for WellsfargopayoutTest {}
impl utils::Connector for WellsfargopayoutTest {
    fn get_data(&self) -> api::ConnectorData {
        use router::connector::Wellsfargopayout;
        api::ConnectorData {
            connector: Box::new(Wellsfargopayout::new()),
            connector_name: types::Connector::Wellsfargopayout,
            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()
                .wellsfargopayout
                .expect("Missing connector authentication configuration")
                .into(),
        )
    }

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

static CONNECTOR: WellsfargopayoutTest = WellsfargopayoutTest {};

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


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

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


// Implementation: impl DecisionEngineErrorsInterface for for DeErrorResponse
// File: crates/router/src/core/payments/routing/utils.rs
// Module: router
// Methods: 3 total (0 public)

impl DecisionEngineErrorsInterface for for DeErrorResponse


// Function: is_masked
// File: crates/masking/src/maskable.rs
// Module: masking

// Documentation: returns `false` otherwise.

pub fn is_masked(&self) -> bool


// File: crates/api_models/src/events/user_role.rs
// Module: api_models

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

use crate::user_role::{
    role::{
        CreateRoleRequest, CreateRoleV2Request, GetParentGroupsInfoQueryParams, GetRoleRequest,
        GroupsAndResources, ListRolesAtEntityLevelRequest, ListRolesQueryParams, ListRolesResponse,
        ParentGroupInfoRequest, RoleInfoResponseNew, RoleInfoResponseWithParentsGroup,
        RoleInfoWithGroupsResponse, RoleInfoWithParents, UpdateRoleRequest,
    },
    AuthorizationInfoResponse, DeleteUserRoleRequest, ListUsersInEntityRequest,
    UpdateUserRoleRequest,
};

common_utils::impl_api_event_type!(
    Miscellaneous,
    (
        GetRoleRequest,
        GetParentGroupsInfoQueryParams,
        AuthorizationInfoResponse,
        UpdateUserRoleRequest,
        DeleteUserRoleRequest,
        CreateRoleRequest,
        CreateRoleV2Request,
        UpdateRoleRequest,
        ListRolesAtEntityLevelRequest,
        RoleInfoResponseNew,
        RoleInfoWithGroupsResponse,
        ListUsersInEntityRequest,
        ListRolesQueryParams,
        GroupsAndResources,
        RoleInfoWithParents,
        ParentGroupInfoRequest,
        RoleInfoResponseWithParentsGroup,
        ListRolesResponse
    )
);


// Function: new
// File: crates/hyperswitch_connectors/src/connectors/deutschebank.rs
// Module: hyperswitch_connectors

pub fn new() -> &'static Self


// Function: get_user_from_db
// File: crates/router/src/utils/user.rs
// Module: router

pub fn get_user_from_db(&self, state: &SessionState) -> UserResult<UserFromStorage>


// Implementation: impl ConnectorRedirectResponse for for Nuvei
// File: crates/hyperswitch_connectors/src/connectors/nuvei.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl ConnectorRedirectResponse for for Nuvei


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

pub fn server(config: AppState) -> Scope


// Implementation: impl MerchantConnectorListResponse
// File: crates/api_models/src/admin.rs
// Module: api_models
// Methods: 2 total (2 public)

impl MerchantConnectorListResponse


// Struct: InvoiceRecordBackResponse
// File: crates/hyperswitch_domain_models/src/router_response_types/revenue_recovery.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct InvoiceRecordBackResponse


// Struct: AlwaysRequestExtendedAuthorization
// File: crates/common_types/src/primitive_wrappers.rs
// Module: common_types
// Implementations: 1
// Traits: Deref

pub struct AlwaysRequestExtendedAuthorization


// Struct: DeutschebankThreeDSInitializeRequestCreditCard
// File: crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DeutschebankThreeDSInitializeRequestCreditCard


// Implementation: impl std::fmt::Debug for for RequestContent
// File: crates/common_utils/src/request.rs
// Module: common_utils
// Methods: 1 total (0 public)

impl std::fmt::Debug for for RequestContent


// Struct: PayuAuthType
// File: crates/hyperswitch_connectors/src/connectors/payu/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PayuAuthType


// Implementation: impl RefundSync for for Netcetera
// File: crates/hyperswitch_connectors/src/connectors/netcetera.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl RefundSync for for Netcetera


// Function: check_refund_integrity
// File: crates/router/src/core/refunds.rs
// Module: router

pub fn check_refund_integrity<T, Request>(
    request: &Request,
    refund_response_data: &Result<types::RefundsResponseData, ErrorResponse>,
) -> Result<(), common_utils::errors::IntegrityCheckError>
where
    T: FlowIntegrity,
    Request: GetIntegrityObject<T> + CheckIntegrity<Request, T>,


// Struct: GroupsAndResources
// File: crates/api_models/src/user_role/role.rs
// Module: api_models
// Implementations: 0

pub struct GroupsAndResources


// Function: into_stripe_next_action
// File: crates/router/src/compatibility/stripe/setup_intents/types.rs
// Module: router

pub fn into_stripe_next_action(
    next_action: Option<payments::NextActionData>,
    return_url: Option<String>,
) -> Option<StripeNextAction>


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

pub fn get_api_event_metrics(
        &self,
        metric: &ApiEventMetrics,
        dimensions: &[ApiEventDimensions],
        merchant_id: &common_utils::id_type::MerchantId,
        filters: &ApiEventFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
    ) -> types::MetricsResult<HashSet<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>>


// Implementation: impl webhooks::IncomingWebhook for for Barclaycard
// File: crates/hyperswitch_connectors/src/connectors/barclaycard.rs
// Module: hyperswitch_connectors
// Methods: 3 total (0 public)

impl webhooks::IncomingWebhook for for Barclaycard


// Implementation: impl KafkaPayout
// File: crates/router/src/services/kafka/payout.rs
// Module: router
// Methods: 1 total (1 public)

impl KafkaPayout


// Function: get_billing_processor_id
// File: crates/hyperswitch_domain_models/src/business_profile.rs
// Module: hyperswitch_domain_models

pub fn get_billing_processor_id(
        &self,
    ) -> CustomResult<
        common_utils::id_type::MerchantConnectorAccountId,
        api_error_response::ApiErrorResponse,
    >


// Implementation: impl AuthipayPaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/authipay/transformers.rs
// Module: hyperswitch_connectors
// Methods: 3 total (2 public)

impl AuthipayPaymentsResponse


// File: crates/diesel_models/src/payment_methods_session.rs
// Module: diesel_models
// Public functions: 1
// Public structs: 2

use common_utils::pii;

#[cfg(feature = "v2")]
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct PaymentMethodSession {
    pub id: common_utils::id_type::GlobalPaymentMethodSessionId,
    pub customer_id: common_utils::id_type::GlobalCustomerId,
    pub billing: Option<common_utils::encryption::Encryption>,
    pub psp_tokenization: Option<common_types::payment_methods::PspTokenization>,
    pub network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,
    pub tokenization_data: Option<pii::SecretSerdeValue>,
    pub return_url: Option<common_utils::types::Url>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub expires_at: time::PrimitiveDateTime,
    pub associated_payment_methods: Option<Vec<String>>,
    pub associated_payment: Option<common_utils::id_type::GlobalPaymentId>,
    pub associated_token_id: Option<common_utils::id_type::GlobalTokenId>,
}

#[cfg(feature = "v2")]
impl PaymentMethodSession {
    pub fn apply_changeset(self, update_session: PaymentMethodsSessionUpdateInternal) -> Self {
        let Self {
            id,
            customer_id,
            billing,
            psp_tokenization,
            network_tokenization,
            tokenization_data,
            expires_at,
            return_url,
            associated_payment_methods,
            associated_payment,
            associated_token_id,
        } = self;

        Self {
            id,
            customer_id,
            billing: update_session.billing.or(billing),
            psp_tokenization: update_session.psp_tokenization.or(psp_tokenization),
            network_tokenization: update_session.network_tokenization.or(network_tokenization),
            tokenization_data: update_session.tokenzation_data.or(tokenization_data),
            expires_at,
            return_url,
            associated_payment_methods,
            associated_payment,
            associated_token_id,
        }
    }
}

#[cfg(feature = "v2")]
pub struct PaymentMethodsSessionUpdateInternal {
    pub billing: Option<common_utils::encryption::Encryption>,
    pub psp_tokenization: Option<common_types::payment_methods::PspTokenization>,
    pub network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,
    pub tokenzation_data: Option<masking::Secret<serde_json::Value>>,
}


// Struct: DwollaErrorDetails
// File: crates/hyperswitch_connectors/src/connectors/dwolla/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DwollaErrorDetails


// Struct: ChargebeeMandateDetails
// File: crates/hyperswitch_connectors/src/connectors/chargebee/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ChargebeeMandateDetails


// Struct: PaymentMethodsEnabled
// File: crates/connector_configs/src/common_config.rs
// Module: connector_configs
// Implementations: 0

pub struct PaymentMethodsEnabled


// Function: update_revenue_recovery_algorithm_under_profile
// File: crates/router/src/core/admin.rs
// Module: router

pub fn update_revenue_recovery_algorithm_under_profile(
        self,
        db: &dyn StorageInterface,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        revenue_recovery_retry_algorithm_type: common_enums::RevenueRecoveryAlgorithmType,
    ) -> RouterResult<()>


// Function: start_workflow
// File: crates/scheduler/src/consumer.rs
// Module: scheduler

pub fn start_workflow<T>(
    state: T,
    process: storage::ProcessTracker,
    _pickup_time: PrimitiveDateTime,
    workflow_selector: impl workflows::ProcessTrackerWorkflows<T> + 'static + std::fmt::Debug,
) -> CustomResult<(), errors::ProcessTrackerError>
where
    T: SchedulerSessionState,


// File: crates/api_models/src/organization.rs
// Module: api_models
// Public functions: 1
// Public structs: 6

use common_enums::OrganizationType;
use common_utils::{id_type, pii};
use utoipa::ToSchema;
pub struct OrganizationNew {
    pub org_id: id_type::OrganizationId,
    pub org_type: OrganizationType,
    pub org_name: Option<String>,
}

impl OrganizationNew {
    pub fn new(org_type: OrganizationType, org_name: Option<String>) -> Self {
        Self {
            org_id: id_type::OrganizationId::default(),
            org_type,
            org_name,
        }
    }
}

#[derive(Clone, Debug, serde::Serialize)]
pub struct OrganizationId {
    pub organization_id: id_type::OrganizationId,
}

#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct OrganizationCreateRequest {
    /// Name of the organization
    pub organization_name: String,

    /// Details about the organization
    #[schema(value_type = Option<Object>)]
    pub organization_details: Option<pii::SecretSerdeValue>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>)]
    pub metadata: Option<pii::SecretSerdeValue>,
}

#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct OrganizationUpdateRequest {
    /// Name of the organization
    pub organization_name: Option<String>,

    /// Details about the organization
    #[schema(value_type = Option<Object>)]
    pub organization_details: Option<pii::SecretSerdeValue>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>)]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// Platform merchant id is unique distiguisher for special merchant in the platform org
    #[schema(value_type = String)]
    pub platform_merchant_id: Option<id_type::MerchantId>,
}
#[cfg(feature = "v1")]
#[derive(Debug, serde::Serialize, Clone, ToSchema)]
pub struct OrganizationResponse {
    /// The unique identifier for the Organization
    #[schema(value_type = String, max_length = 64, min_length = 1, example = "org_q98uSGAYbjEwqs0mJwnz")]
    pub organization_id: id_type::OrganizationId,

    /// Name of the Organization
    pub organization_name: Option<String>,

    /// Details about the organization
    #[schema(value_type = Option<Object>)]
    pub organization_details: Option<pii::SecretSerdeValue>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>)]
    pub metadata: Option<pii::SecretSerdeValue>,
    pub modified_at: time::PrimitiveDateTime,
    pub created_at: time::PrimitiveDateTime,

    /// Organization Type of the organization
    #[schema(value_type = Option<OrganizationType>, example = "standard")]
    pub organization_type: Option<OrganizationType>,
}

#[cfg(feature = "v2")]
#[derive(Debug, serde::Serialize, Clone, ToSchema)]
pub struct OrganizationResponse {
    /// The unique identifier for the Organization
    #[schema(value_type = String, max_length = 64, min_length = 1, example = "org_q98uSGAYbjEwqs0mJwnz")]
    pub id: id_type::OrganizationId,

    /// Name of the Organization
    pub organization_name: Option<String>,

    /// Details about the organization
    #[schema(value_type = Option<Object>)]
    pub organization_details: Option<pii::SecretSerdeValue>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>)]
    pub metadata: Option<pii::SecretSerdeValue>,
    pub modified_at: time::PrimitiveDateTime,
    pub created_at: time::PrimitiveDateTime,

    /// Organization Type of the organization
    #[schema(value_type = Option<OrganizationType>, example = "standard")]
    pub organization_type: Option<OrganizationType>,
}


// Function: fetch_payment_method_for_network_token_webhooks
// File: crates/router/src/core/webhooks/network_tokenization_incoming.rs
// Module: router

pub fn fetch_payment_method_for_network_token_webhooks(
    state: &SessionState,
    merchant_account: &domain::MerchantAccount,
    key_store: &domain::MerchantKeyStore,
    payment_method_id: &str,
) -> RouterResult<domain::PaymentMethod>


// Struct: Webhooks
// File: crates/router/src/compatibility/stripe/app.rs
// Module: router
// Implementations: 1

pub struct Webhooks


// Struct: PaytmCard
// File: crates/hyperswitch_connectors/src/connectors/paytm/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaytmCard


// Function: get_payout_webhook_statuses
// File: crates/hyperswitch_domain_models/src/business_profile.rs
// Module: hyperswitch_domain_models

pub fn get_payout_webhook_statuses(&self) -> Cow<'_, [common_enums::PayoutStatus]>


// Struct: NetworkResponse
// File: crates/hyperswitch_connectors/src/connectors/worldpayvantiv/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NetworkResponse