// File: crates/hyperswitch_connectors/src/connectors/ebanx/transformers.rs
// Module: hyperswitch_connectors
// Public structs: 12

#[cfg(feature = "payouts")]
use api_models::enums::Currency;
#[cfg(feature = "payouts")]
use api_models::payouts::{Bank, PayoutMethodData};
#[cfg(feature = "payouts")]
use common_enums::{PayoutStatus, PayoutType};
#[cfg(feature = "payouts")]
use common_utils::pii::Email;
use common_utils::types::FloatMajorUnit;
use hyperswitch_domain_models::router_data::ConnectorAuthType;
#[cfg(feature = "payouts")]
use hyperswitch_domain_models::router_flow_types::PoCreate;
#[cfg(feature = "payouts")]
use hyperswitch_domain_models::types::{PayoutsResponseData, PayoutsRouterData};
use hyperswitch_interfaces::errors::ConnectorError;
#[cfg(feature = "payouts")]
use masking::ExposeInterface;
use masking::Secret;
use serde::{Deserialize, Serialize};

#[cfg(feature = "payouts")]
use crate::types::PayoutsResponseRouterData;
#[cfg(feature = "payouts")]
use crate::utils::{
    AddressDetailsData as _, CustomerDetails as _, PayoutsData as _, RouterData as _,
};

pub struct EbanxRouterData<T> {
    pub amount: FloatMajorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
    pub router_data: T,
}

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

#[cfg(feature = "payouts")]
#[derive(Debug, Serialize, Clone)]
pub struct EbanxPayoutCreateRequest {
    integration_key: Secret<String>,
    external_reference: String,
    country: String,
    amount: FloatMajorUnit,
    currency: Currency,
    target: EbanxPayoutType,
    target_account: Secret<String>,
    payee: EbanxPayoutDetails,
}

#[cfg(feature = "payouts")]
#[derive(Debug, Serialize, Clone)]
pub enum EbanxPayoutType {
    BankAccount,
    Mercadopago,
    EwalletNequi,
    PixKey,
}

#[cfg(feature = "payouts")]
#[derive(Debug, Serialize, Clone)]
pub struct EbanxPayoutDetails {
    name: Secret<String>,
    email: Option<Email>,
    document: Option<Secret<String>>,
    document_type: Option<EbanxDocumentType>,
    bank_info: EbanxBankDetails,
}

#[cfg(feature = "payouts")]
#[derive(Debug, Serialize, Clone)]
pub enum EbanxDocumentType {
    #[serde(rename = "CPF")]
    NaturalPersonsRegister,
    #[serde(rename = "CNPJ")]
    NationalRegistryOfLegalEntities,
}

#[cfg(feature = "payouts")]
#[derive(Debug, Serialize, Clone)]
pub struct EbanxBankDetails {
    bank_name: Option<String>,
    bank_branch: Option<String>,
    bank_account: Option<Secret<String>>,
    account_type: Option<EbanxBankAccountType>,
}

#[cfg(feature = "payouts")]
#[derive(Debug, Serialize, Clone)]
pub enum EbanxBankAccountType {
    #[serde(rename = "C")]
    CheckingAccount,
}

#[cfg(feature = "payouts")]
impl TryFrom<&EbanxRouterData<&PayoutsRouterData<PoCreate>>> for EbanxPayoutCreateRequest {
    type Error = error_stack::Report<ConnectorError>;
    fn try_from(item: &EbanxRouterData<&PayoutsRouterData<PoCreate>>) -> Result<Self, Self::Error> {
        let ebanx_auth_type = EbanxAuthType::try_from(&item.router_data.connector_auth_type)?;
        match item.router_data.get_payout_method_data()? {
            PayoutMethodData::Bank(Bank::Pix(pix_data)) => {
                let bank_info = EbanxBankDetails {
                    bank_account: Some(pix_data.bank_account_number),
                    bank_branch: pix_data.bank_branch,
                    bank_name: pix_data.bank_name,
                    account_type: Some(EbanxBankAccountType::CheckingAccount),
                };

                let billing_address = item.router_data.get_billing_address()?;
                let customer_details = item.router_data.request.get_customer_details()?;

                let document_type = pix_data.tax_id.clone().map(|tax_id| {
                    if tax_id.clone().expose().len() == 11 {
                        EbanxDocumentType::NaturalPersonsRegister
                    } else {
                        EbanxDocumentType::NationalRegistryOfLegalEntities
                    }
                });

                let payee = EbanxPayoutDetails {
                    name: billing_address.get_full_name()?,
                    email: customer_details.email.clone(),
                    bank_info,
                    document_type,
                    document: pix_data.tax_id.to_owned(),
                };
                Ok(Self {
                    amount: item.amount,
                    integration_key: ebanx_auth_type.integration_key,
                    country: customer_details.get_customer_phone_country_code()?,
                    currency: item.router_data.request.source_currency,
                    external_reference: item.router_data.connector_request_reference_id.to_owned(),
                    target: EbanxPayoutType::PixKey,
                    target_account: pix_data.pix_key,
                    payee,
                })
            }
            PayoutMethodData::Card(_) | PayoutMethodData::Bank(_) | PayoutMethodData::Wallet(_) => {
                Err(ConnectorError::NotSupported {
                    message: "Payment Method Not Supported".to_string(),
                    connector: "Ebanx",
                })?
            }
        }
    }
}

pub struct EbanxAuthType {
    pub integration_key: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for EbanxAuthType {
    type Error = error_stack::Report<ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
                integration_key: api_key.to_owned(),
            }),
            _ => Err(ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

#[cfg(feature = "payouts")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EbanxPayoutStatus {
    #[serde(rename = "PA")]
    Succeeded,
    #[serde(rename = "CA")]
    Cancelled,
    #[serde(rename = "PE")]
    Processing,
    #[serde(rename = "OP")]
    RequiresFulfillment,
}

#[cfg(feature = "payouts")]
impl From<EbanxPayoutStatus> for PayoutStatus {
    fn from(item: EbanxPayoutStatus) -> Self {
        match item {
            EbanxPayoutStatus::Succeeded => Self::Success,
            EbanxPayoutStatus::Cancelled => Self::Cancelled,
            EbanxPayoutStatus::Processing => Self::Pending,
            EbanxPayoutStatus::RequiresFulfillment => Self::RequiresFulfillment,
        }
    }
}

#[cfg(feature = "payouts")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EbanxPayoutResponse {
    payout: EbanxPayoutResponseDetails,
}

#[cfg(feature = "payouts")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EbanxPayoutResponseDetails {
    uid: String,
    status: EbanxPayoutStatus,
}

#[cfg(feature = "payouts")]
impl<F> TryFrom<PayoutsResponseRouterData<F, EbanxPayoutResponse>> for PayoutsRouterData<F> {
    type Error = error_stack::Report<ConnectorError>;
    fn try_from(
        item: PayoutsResponseRouterData<F, EbanxPayoutResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(PayoutsResponseData {
                status: Some(PayoutStatus::from(item.response.payout.status)),
                connector_payout_id: Some(item.response.payout.uid),
                payout_eligible: None,
                should_add_next_step_to_process_tracker: false,
                error_code: None,
                error_message: None,
            }),
            ..item.data
        })
    }
}

#[cfg(feature = "payouts")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EbanxPayoutFulfillRequest {
    integration_key: Secret<String>,
    uid: String,
}

#[cfg(feature = "payouts")]
impl<F> TryFrom<&EbanxRouterData<&PayoutsRouterData<F>>> for EbanxPayoutFulfillRequest {
    type Error = error_stack::Report<ConnectorError>;
    fn try_from(item: &EbanxRouterData<&PayoutsRouterData<F>>) -> Result<Self, Self::Error> {
        let request = item.router_data.request.to_owned();
        let ebanx_auth_type = EbanxAuthType::try_from(&item.router_data.connector_auth_type)?;
        let payout_type = request.get_payout_type()?;
        match payout_type {
            PayoutType::Bank => Ok(Self {
                integration_key: ebanx_auth_type.integration_key,
                uid: request
                    .connector_payout_id
                    .to_owned()
                    .ok_or(ConnectorError::MissingRequiredField { field_name: "uid" })?,
            }),
            PayoutType::Card | PayoutType::Wallet => Err(ConnectorError::NotSupported {
                message: "Payout Method Not Supported".to_string(),
                connector: "Ebanx",
            })?,
        }
    }
}

#[cfg(feature = "payouts")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EbanxFulfillResponse {
    #[serde(rename = "type")]
    status: EbanxFulfillStatus,
    message: String,
}

#[cfg(feature = "payouts")]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EbanxFulfillStatus {
    Success,
    ApiError,
    AuthenticationError,
    InvalidRequestError,
    RequestError,
}

#[cfg(feature = "payouts")]
impl From<EbanxFulfillStatus> for PayoutStatus {
    fn from(item: EbanxFulfillStatus) -> Self {
        match item {
            EbanxFulfillStatus::Success => Self::Success,
            EbanxFulfillStatus::ApiError
            | EbanxFulfillStatus::AuthenticationError
            | EbanxFulfillStatus::InvalidRequestError
            | EbanxFulfillStatus::RequestError => Self::Failed,
        }
    }
}

#[cfg(feature = "payouts")]
impl<F> TryFrom<PayoutsResponseRouterData<F, EbanxFulfillResponse>> for PayoutsRouterData<F> {
    type Error = error_stack::Report<ConnectorError>;
    fn try_from(
        item: PayoutsResponseRouterData<F, EbanxFulfillResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(PayoutsResponseData {
                status: Some(PayoutStatus::from(item.response.status)),
                connector_payout_id: Some(item.data.request.get_transfer_id()?),
                payout_eligible: None,
                should_add_next_step_to_process_tracker: false,
                error_code: None,
                error_message: None,
            }),
            ..item.data
        })
    }
}

#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
pub struct EbanxErrorResponse {
    pub code: String,
    pub status_code: String,
    pub message: Option<String>,
}

#[cfg(feature = "payouts")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EbanxPayoutCancelRequest {
    integration_key: Secret<String>,
    uid: String,
}

#[cfg(feature = "payouts")]
impl<F> TryFrom<&PayoutsRouterData<F>> for EbanxPayoutCancelRequest {
    type Error = error_stack::Report<ConnectorError>;
    fn try_from(item: &PayoutsRouterData<F>) -> Result<Self, Self::Error> {
        let request = item.request.to_owned();
        let ebanx_auth_type = EbanxAuthType::try_from(&item.connector_auth_type)?;
        let payout_type = request.get_payout_type()?;
        match payout_type {
            PayoutType::Bank => Ok(Self {
                integration_key: ebanx_auth_type.integration_key,
                uid: request
                    .connector_payout_id
                    .to_owned()
                    .ok_or(ConnectorError::MissingRequiredField { field_name: "uid" })?,
            }),
            PayoutType::Card | PayoutType::Wallet => Err(ConnectorError::NotSupported {
                message: "Payout Method Not Supported".to_string(),
                connector: "Ebanx",
            })?,
        }
    }
}

#[cfg(feature = "payouts")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EbanxCancelResponse {
    #[serde(rename = "type")]
    status: EbanxCancelStatus,
    message: String,
}

#[cfg(feature = "payouts")]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EbanxCancelStatus {
    Success,
    ApiError,
    AuthenticationError,
    InvalidRequestError,
    RequestError,
}

#[cfg(feature = "payouts")]
impl From<EbanxCancelStatus> for PayoutStatus {
    fn from(item: EbanxCancelStatus) -> Self {
        match item {
            EbanxCancelStatus::Success => Self::Cancelled,
            EbanxCancelStatus::ApiError
            | EbanxCancelStatus::AuthenticationError
            | EbanxCancelStatus::InvalidRequestError
            | EbanxCancelStatus::RequestError => Self::Failed,
        }
    }
}

#[cfg(feature = "payouts")]
impl<F> TryFrom<PayoutsResponseRouterData<F, EbanxCancelResponse>> for PayoutsRouterData<F> {
    type Error = error_stack::Report<ConnectorError>;
    fn try_from(
        item: PayoutsResponseRouterData<F, EbanxCancelResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(PayoutsResponseData {
                status: Some(PayoutStatus::from(item.response.status)),
                connector_payout_id: item.data.request.connector_payout_id.clone(),
                payout_eligible: None,
                should_add_next_step_to_process_tracker: false,
                error_code: None,
                error_message: None,
            }),
            ..item.data
        })
    }
}


// Function: set_routable_connectors
// File: crates/hyperswitch_interfaces/src/events/routing_api_logs.rs
// Module: hyperswitch_interfaces

// Documentation: set response status code

pub fn set_routable_connectors(&mut self, connectors: Vec<RoutableConnectorChoice>)


// File: crates/router/tests/connectors/elavon.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 ElavonTest;
impl ConnectorActions for ElavonTest {}
impl utils::Connector for ElavonTest {
    fn get_data(&self) -> api::ConnectorData {
        use router::connector::Elavon;
        utils::construct_connector_data_old(
            Box::new(Elavon::new()),
            types::Connector::Plaid,
            api::GetToken::Connector,
            None,
        )
        // api::ConnectorData {
        //     connector: Box::new(Elavon::new()),
        //     connector_name: types::Connector::Elavon,
        //     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()
                .elavon
                .expect("Missing connector authentication configuration")
                .into(),
        )
    }

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

static CONNECTOR: ElavonTest = ElavonTest {};

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


// Implementation: impl UserFromToken
// File: crates/router/src/utils/user.rs
// Module: router
// Methods: 3 total (0 public)

impl UserFromToken


// Function: new
// File: crates/hyperswitch_constraint_graph/src/types.rs
// Module: hyperswitch_constraint_graph

pub fn new() -> Self


// Struct: GooglePayPaymentProcessingDetails
// File: crates/router/src/core/payments.rs
// Module: router
// Implementations: 0

pub struct GooglePayPaymentProcessingDetails


// Struct: PowertranzBaseRequest
// File: crates/hyperswitch_connectors/src/connectors/powertranz/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PowertranzBaseRequest


// Struct: BillwerkRouterData
// File: crates/hyperswitch_connectors/src/connectors/billwerk/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BillwerkRouterData<T>


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

pub fn get_billing_merchant_connector_account_id(
        &self,
    ) -> Option<id_type::MerchantConnectorAccountId>


// File: crates/router/src/core/health_check.rs
// Module: router

#[cfg(feature = "olap")]
use analytics::health_check::HealthCheck;
#[cfg(feature = "dynamic_routing")]
use api_models::health_check::HealthCheckMap;
use api_models::health_check::HealthState;
use error_stack::ResultExt;
use router_env::logger;

use crate::{
    consts,
    core::errors::{self, CustomResult},
    routes::app,
    services::api as services,
};

#[async_trait::async_trait]
pub trait HealthCheckInterface {
    async fn health_check_db(&self) -> CustomResult<HealthState, errors::HealthCheckDBError>;
    async fn health_check_redis(&self) -> CustomResult<HealthState, errors::HealthCheckRedisError>;
    async fn health_check_locker(
        &self,
    ) -> CustomResult<HealthState, errors::HealthCheckLockerError>;
    async fn health_check_outgoing(&self)
        -> CustomResult<HealthState, errors::HealthCheckOutGoing>;
    #[cfg(feature = "olap")]
    async fn health_check_analytics(&self)
        -> CustomResult<HealthState, errors::HealthCheckDBError>;

    #[cfg(feature = "olap")]
    async fn health_check_opensearch(
        &self,
    ) -> CustomResult<HealthState, errors::HealthCheckDBError>;

    #[cfg(feature = "dynamic_routing")]
    async fn health_check_grpc(
        &self,
    ) -> CustomResult<HealthCheckMap, errors::HealthCheckGRPCServiceError>;

    #[cfg(feature = "dynamic_routing")]
    async fn health_check_decision_engine(
        &self,
    ) -> CustomResult<HealthState, errors::HealthCheckDecisionEngineError>;

    async fn health_check_unified_connector_service(
        &self,
    ) -> CustomResult<HealthState, errors::HealthCheckUnifiedConnectorServiceError>;
}

#[async_trait::async_trait]
impl HealthCheckInterface for app::SessionState {
    async fn health_check_db(&self) -> CustomResult<HealthState, errors::HealthCheckDBError> {
        let db = &*self.store;
        db.health_check_db().await?;
        Ok(HealthState::Running)
    }

    async fn health_check_redis(&self) -> CustomResult<HealthState, errors::HealthCheckRedisError> {
        let db = &*self.store;
        let redis_conn = db
            .get_redis_conn()
            .change_context(errors::HealthCheckRedisError::RedisConnectionError)?;

        redis_conn
            .serialize_and_set_key_with_expiry(&"test_key".into(), "test_value", 30)
            .await
            .change_context(errors::HealthCheckRedisError::SetFailed)?;

        logger::debug!("Redis set_key was successful");

        redis_conn
            .get_key::<()>(&"test_key".into())
            .await
            .change_context(errors::HealthCheckRedisError::GetFailed)?;

        logger::debug!("Redis get_key was successful");

        redis_conn
            .delete_key(&"test_key".into())
            .await
            .change_context(errors::HealthCheckRedisError::DeleteFailed)?;

        logger::debug!("Redis delete_key was successful");

        Ok(HealthState::Running)
    }

    async fn health_check_locker(
        &self,
    ) -> CustomResult<HealthState, errors::HealthCheckLockerError> {
        let locker = &self.conf.locker;
        if !locker.mock_locker {
            let mut url = locker.host_rs.to_owned();
            url.push_str(consts::LOCKER_HEALTH_CALL_PATH);
            let request = services::Request::new(services::Method::Get, &url);
            services::call_connector_api(self, request, "health_check_for_locker")
                .await
                .change_context(errors::HealthCheckLockerError::FailedToCallLocker)?
                .map_err(|_| {
                    error_stack::report!(errors::HealthCheckLockerError::FailedToCallLocker)
                })?;
            Ok(HealthState::Running)
        } else {
            Ok(HealthState::NotApplicable)
        }
    }

    #[cfg(feature = "olap")]
    async fn health_check_analytics(
        &self,
    ) -> CustomResult<HealthState, errors::HealthCheckDBError> {
        let analytics = &self.pool;
        match analytics {
            analytics::AnalyticsProvider::Sqlx(client) => client
                .deep_health_check()
                .await
                .change_context(errors::HealthCheckDBError::SqlxAnalyticsError),
            analytics::AnalyticsProvider::Clickhouse(client) => client
                .deep_health_check()
                .await
                .change_context(errors::HealthCheckDBError::ClickhouseAnalyticsError),
            analytics::AnalyticsProvider::CombinedCkh(sqlx_client, ckh_client) => {
                sqlx_client
                    .deep_health_check()
                    .await
                    .change_context(errors::HealthCheckDBError::SqlxAnalyticsError)?;
                ckh_client
                    .deep_health_check()
                    .await
                    .change_context(errors::HealthCheckDBError::ClickhouseAnalyticsError)
            }
            analytics::AnalyticsProvider::CombinedSqlx(sqlx_client, ckh_client) => {
                sqlx_client
                    .deep_health_check()
                    .await
                    .change_context(errors::HealthCheckDBError::SqlxAnalyticsError)?;
                ckh_client
                    .deep_health_check()
                    .await
                    .change_context(errors::HealthCheckDBError::ClickhouseAnalyticsError)
            }
        }?;

        Ok(HealthState::Running)
    }

    #[cfg(feature = "olap")]
    async fn health_check_opensearch(
        &self,
    ) -> CustomResult<HealthState, errors::HealthCheckDBError> {
        if let Some(client) = self.opensearch_client.as_ref() {
            client
                .deep_health_check()
                .await
                .change_context(errors::HealthCheckDBError::OpensearchError)?;
            Ok(HealthState::Running)
        } else {
            Ok(HealthState::NotApplicable)
        }
    }

    async fn health_check_outgoing(
        &self,
    ) -> CustomResult<HealthState, errors::HealthCheckOutGoing> {
        let request = services::Request::new(services::Method::Get, consts::OUTGOING_CALL_URL);
        services::call_connector_api(self, request, "outgoing_health_check")
            .await
            .map_err(|err| errors::HealthCheckOutGoing::OutGoingFailed {
                message: err.to_string(),
            })?
            .map_err(|err| errors::HealthCheckOutGoing::OutGoingFailed {
                message: format!(
                    "Got a non 200 status while making outgoing request. Error {:?}",
                    err.response
                ),
            })?;

        logger::debug!("Outgoing request successful");
        Ok(HealthState::Running)
    }

    #[cfg(feature = "dynamic_routing")]
    async fn health_check_grpc(
        &self,
    ) -> CustomResult<HealthCheckMap, errors::HealthCheckGRPCServiceError> {
        let health_client = &self.grpc_client.health_client;
        let grpc_config = &self.conf.grpc_client;

        let health_check_map = health_client
            .perform_health_check(grpc_config)
            .await
            .change_context(errors::HealthCheckGRPCServiceError::FailedToCallService)?;

        logger::debug!("Health check successful");
        Ok(health_check_map)
    }

    #[cfg(feature = "dynamic_routing")]
    async fn health_check_decision_engine(
        &self,
    ) -> CustomResult<HealthState, errors::HealthCheckDecisionEngineError> {
        if self.conf.open_router.dynamic_routing_enabled {
            let url = format!("{}/{}", &self.conf.open_router.url, "health");
            let request = services::Request::new(services::Method::Get, &url);
            let _ = services::call_connector_api(self, request, "health_check_for_decision_engine")
                .await
                .change_context(
                    errors::HealthCheckDecisionEngineError::FailedToCallDecisionEngineService,
                )?;

            logger::debug!("Decision engine health check successful");
            Ok(HealthState::Running)
        } else {
            logger::debug!("Decision engine health check not applicable");
            Ok(HealthState::NotApplicable)
        }
    }

    async fn health_check_unified_connector_service(
        &self,
    ) -> CustomResult<HealthState, errors::HealthCheckUnifiedConnectorServiceError> {
        if let Some(_ucs_client) = &self.grpc_client.unified_connector_service_client {
            // For now, we'll just check if the client exists and is configured
            // In the future, this could be enhanced to make an actual health check call
            // to the unified connector service if it supports health check endpoints
            logger::debug!("Unified Connector Service client is configured and available");
            Ok(HealthState::Running)
        } else {
            logger::debug!("Unified Connector Service client not configured");
            Ok(HealthState::NotApplicable)
        }
    }
}


// Implementation: impl CaptureSyncResponse
// File: crates/hyperswitch_domain_models/src/router_response_types.rs
// Module: hyperswitch_domain_models
// Methods: 2 total (2 public)

impl CaptureSyncResponse


// File: crates/storage_impl/src/mock_db.rs
// Module: storage_impl
// Public functions: 5
// Public structs: 1

use std::sync::Arc;

use common_utils::{errors::CustomResult, types::keymanager::KeyManagerState};
use diesel_models as store;
use error_stack::ResultExt;
use futures::lock::{Mutex, MutexGuard};
use hyperswitch_domain_models::{
    behaviour::{Conversion, ReverseConversion},
    merchant_key_store::MerchantKeyStore,
    payments::{payment_attempt::PaymentAttempt, PaymentIntent},
};
use redis_interface::RedisSettings;

use crate::{errors::StorageError, redis::RedisStore};

pub mod payment_attempt;
pub mod payment_intent;
#[cfg(feature = "payouts")]
pub mod payout_attempt;
#[cfg(feature = "payouts")]
pub mod payouts;
pub mod redis_conn;
#[cfg(not(feature = "payouts"))]
use hyperswitch_domain_models::{PayoutAttemptInterface, PayoutsInterface};

#[derive(Clone)]
pub struct MockDb {
    pub addresses: Arc<Mutex<Vec<store::Address>>>,
    pub configs: Arc<Mutex<Vec<store::Config>>>,
    pub merchant_accounts: Arc<Mutex<Vec<store::MerchantAccount>>>,
    pub merchant_connector_accounts: Arc<Mutex<Vec<store::MerchantConnectorAccount>>>,
    pub payment_attempts: Arc<Mutex<Vec<PaymentAttempt>>>,
    pub payment_intents: Arc<Mutex<Vec<PaymentIntent>>>,
    pub payment_methods: Arc<Mutex<Vec<store::PaymentMethod>>>,
    pub customers: Arc<Mutex<Vec<store::Customer>>>,
    pub refunds: Arc<Mutex<Vec<store::Refund>>>,
    pub processes: Arc<Mutex<Vec<store::ProcessTracker>>>,
    pub redis: Arc<RedisStore>,
    pub api_keys: Arc<Mutex<Vec<store::ApiKey>>>,
    pub ephemeral_keys: Arc<Mutex<Vec<store::EphemeralKey>>>,
    pub cards_info: Arc<Mutex<Vec<store::CardInfo>>>,
    pub events: Arc<Mutex<Vec<store::Event>>>,
    pub disputes: Arc<Mutex<Vec<store::Dispute>>>,
    pub lockers: Arc<Mutex<Vec<store::LockerMockUp>>>,
    pub mandates: Arc<Mutex<Vec<store::Mandate>>>,
    pub captures: Arc<Mutex<Vec<store::capture::Capture>>>,
    pub merchant_key_store: Arc<Mutex<Vec<store::merchant_key_store::MerchantKeyStore>>>,
    #[cfg(all(feature = "v2", feature = "tokenization_v2"))]
    pub tokenizations: Arc<Mutex<Vec<store::tokenization::Tokenization>>>,
    pub business_profiles: Arc<Mutex<Vec<store::business_profile::Profile>>>,
    pub reverse_lookups: Arc<Mutex<Vec<store::ReverseLookup>>>,
    pub payment_link: Arc<Mutex<Vec<store::payment_link::PaymentLink>>>,
    pub organizations: Arc<Mutex<Vec<store::organization::Organization>>>,
    pub users: Arc<Mutex<Vec<store::user::User>>>,
    pub user_roles: Arc<Mutex<Vec<store::user_role::UserRole>>>,
    pub authorizations: Arc<Mutex<Vec<store::authorization::Authorization>>>,
    pub dashboard_metadata: Arc<Mutex<Vec<store::user::dashboard_metadata::DashboardMetadata>>>,
    #[cfg(feature = "payouts")]
    pub payout_attempt: Arc<Mutex<Vec<store::payout_attempt::PayoutAttempt>>>,
    #[cfg(feature = "payouts")]
    pub payouts: Arc<Mutex<Vec<store::payouts::Payouts>>>,
    pub authentications: Arc<Mutex<Vec<store::authentication::Authentication>>>,
    pub roles: Arc<Mutex<Vec<store::role::Role>>>,
    pub user_key_store: Arc<Mutex<Vec<store::user_key_store::UserKeyStore>>>,
    pub user_authentication_methods:
        Arc<Mutex<Vec<store::user_authentication_method::UserAuthenticationMethod>>>,
    pub themes: Arc<Mutex<Vec<store::user::theme::Theme>>>,
    pub hyperswitch_ai_interactions:
        Arc<Mutex<Vec<store::hyperswitch_ai_interaction::HyperswitchAiInteraction>>>,
}

impl MockDb {
    pub async fn new(redis: &RedisSettings) -> error_stack::Result<Self, StorageError> {
        Ok(Self {
            addresses: Default::default(),
            configs: Default::default(),
            merchant_accounts: Default::default(),
            merchant_connector_accounts: Default::default(),
            payment_attempts: Default::default(),
            payment_intents: Default::default(),
            payment_methods: Default::default(),
            customers: Default::default(),
            refunds: Default::default(),
            processes: Default::default(),
            redis: Arc::new(
                RedisStore::new(redis)
                    .await
                    .change_context(StorageError::InitializationError)?,
            ),
            api_keys: Default::default(),
            ephemeral_keys: Default::default(),
            cards_info: Default::default(),
            events: Default::default(),
            disputes: Default::default(),
            lockers: Default::default(),
            mandates: Default::default(),
            captures: Default::default(),
            merchant_key_store: Default::default(),
            #[cfg(all(feature = "v2", feature = "tokenization_v2"))]
            tokenizations: Default::default(),
            business_profiles: Default::default(),
            reverse_lookups: Default::default(),
            payment_link: Default::default(),
            organizations: Default::default(),
            users: Default::default(),
            user_roles: Default::default(),
            authorizations: Default::default(),
            dashboard_metadata: Default::default(),
            #[cfg(feature = "payouts")]
            payout_attempt: Default::default(),
            #[cfg(feature = "payouts")]
            payouts: Default::default(),
            authentications: Default::default(),
            roles: Default::default(),
            user_key_store: Default::default(),
            user_authentication_methods: Default::default(),
            themes: Default::default(),
            hyperswitch_ai_interactions: Default::default(),
        })
    }

    /// Returns an option of the resource if it exists
    pub async fn find_resource<D, R>(
        &self,
        state: &KeyManagerState,
        key_store: &MerchantKeyStore,
        resources: MutexGuard<'_, Vec<D>>,
        filter_fn: impl Fn(&&D) -> bool,
    ) -> CustomResult<Option<R>, StorageError>
    where
        D: Sync + ReverseConversion<R> + Clone,
        R: Conversion,
    {
        let resource = resources.iter().find(filter_fn).cloned();
        match resource {
            Some(res) => Ok(Some(
                res.convert(
                    state,
                    key_store.key.get_inner(),
                    key_store.merchant_id.clone().into(),
                )
                .await
                .change_context(StorageError::DecryptionError)?,
            )),
            None => Ok(None),
        }
    }

    /// Throws errors when the requested resource is not found
    pub async fn get_resource<D, R>(
        &self,
        state: &KeyManagerState,
        key_store: &MerchantKeyStore,
        resources: MutexGuard<'_, Vec<D>>,
        filter_fn: impl Fn(&&D) -> bool,
        error_message: String,
    ) -> CustomResult<R, StorageError>
    where
        D: Sync + ReverseConversion<R> + Clone,
        R: Conversion,
    {
        match self
            .find_resource(state, key_store, resources, filter_fn)
            .await?
        {
            Some(res) => Ok(res),
            None => Err(StorageError::ValueNotFound(error_message).into()),
        }
    }

    pub async fn get_resources<D, R>(
        &self,
        state: &KeyManagerState,
        key_store: &MerchantKeyStore,
        resources: MutexGuard<'_, Vec<D>>,
        filter_fn: impl Fn(&&D) -> bool,
        error_message: String,
    ) -> CustomResult<Vec<R>, StorageError>
    where
        D: Sync + ReverseConversion<R> + Clone,
        R: Conversion,
    {
        let resources: Vec<_> = resources.iter().filter(filter_fn).cloned().collect();
        if resources.is_empty() {
            Err(StorageError::ValueNotFound(error_message).into())
        } else {
            let pm_futures = resources
                .into_iter()
                .map(|pm| async {
                    pm.convert(
                        state,
                        key_store.key.get_inner(),
                        key_store.merchant_id.clone().into(),
                    )
                    .await
                    .change_context(StorageError::DecryptionError)
                })
                .collect::<Vec<_>>();

            let domain_resources = futures::future::try_join_all(pm_futures).await?;

            Ok(domain_resources)
        }
    }

    pub async fn update_resource<D, R>(
        &self,
        state: &KeyManagerState,
        key_store: &MerchantKeyStore,
        mut resources: MutexGuard<'_, Vec<D>>,
        resource_updated: D,
        filter_fn: impl Fn(&&mut D) -> bool,
        error_message: String,
    ) -> CustomResult<R, StorageError>
    where
        D: Sync + ReverseConversion<R> + Clone,
        R: Conversion,
    {
        if let Some(pm) = resources.iter_mut().find(filter_fn) {
            *pm = resource_updated.clone();
            let result = resource_updated
                .convert(
                    state,
                    key_store.key.get_inner(),
                    key_store.merchant_id.clone().into(),
                )
                .await
                .change_context(StorageError::DecryptionError)?;
            Ok(result)
        } else {
            Err(StorageError::ValueNotFound(error_message).into())
        }
    }
}

#[cfg(not(feature = "payouts"))]
impl PayoutsInterface for MockDb {}

#[cfg(not(feature = "payouts"))]
impl PayoutAttemptInterface for MockDb {}


// Function: validate
// File: crates/router/src/services/kafka.rs
// Module: router

pub fn validate(&self) -> Result<(), crate::core::errors::ApplicationError>


// Struct: ReturnUrl
// File: crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ReturnUrl


// Struct: MerchantAccountSetter
// File: crates/diesel_models/src/merchant_account.rs
// Module: diesel_models
// Implementations: 0

pub struct MerchantAccountSetter


// Implementation: impl SecretsManagementConfig
// File: crates/external_services/src/managers/secrets_management.rs
// Module: external_services
// Methods: 2 total (1 public)

impl SecretsManagementConfig


// Struct: PaymentFilterRow
// File: crates/analytics/src/payments/filters.rs
// Module: analytics
// Implementations: 0

pub struct PaymentFilterRow


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

impl api::RefundExecute for for Vgs


// Implementation: impl super::active_payments::metrics::ActivePaymentsMetricAnalytics for for ClickhouseClient
// File: crates/analytics/src/clickhouse.rs
// Module: analytics
// Methods: 0 total (0 public)

impl super::active_payments::metrics::ActivePaymentsMetricAnalytics for for ClickhouseClient


// Function: config_key_update
// File: crates/router/src/routes/configs.rs
// Module: router

pub fn config_key_update(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
    json_payload: web::Json<api_types::ConfigUpdate>,
) -> impl Responder


// Struct: StoreCardReq
// File: crates/router/src/core/payment_methods/transformers.rs
// Module: router
// Implementations: 0

pub struct StoreCardReq


// Function: call_to_locker
// File: crates/router/src/core/locker_migration.rs
// Module: router

pub fn call_to_locker(
    _state: &SessionState,
    _payment_methods: Vec<domain::PaymentMethod>,
    _customer_id: &id_type::CustomerId,
    _merchant_id: &id_type::MerchantId,
    _merchant_context: &domain::MerchantContext,
) -> CustomResult<usize, errors::ApiErrorResponse>


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

// Public submodules:
pub mod transformers;


// Function: organization_create
// File: crates/router/src/routes/admin.rs
// Module: router

pub fn organization_create(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<admin::OrganizationCreateRequest>,
) -> HttpResponse


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

impl api::PaymentToken for for Nomupay


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

pub fn add_payment_method_to_vault(
    state: &routes::SessionState,
    merchant_context: &domain::MerchantContext,
    pmd: &domain::PaymentMethodVaultingData,
    existing_vault_id: Option<domain::VaultId>,
    customer_id: &id_type::GlobalCustomerId,
) -> CustomResult<pm_types::AddVaultResponse, errors::VaultError>


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

impl api::ConnectorAccessToken for for Moneris


// Implementation: impl api::PaymentVoid for for Nomupay
// File: crates/hyperswitch_connectors/src/connectors/nomupay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentVoid for for Nomupay


// File: crates/api_models/src/process_tracker.rs
// Module: api_models

#[cfg(feature = "v2")]
pub mod revenue_recovery;


// Function: list_multiple_merchant_accounts
// File: crates/diesel_models/src/query/merchant_account.rs
// Module: diesel_models

pub fn list_multiple_merchant_accounts(
        conn: &PgPooledConn,
        merchant_ids: Vec<common_utils::id_type::MerchantId>,
    ) -> StorageResult<Vec<Self>>


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

impl ConnectorRedirectResponse for for Mollie


// Function: spawn_tracked_job
// File: crates/router/src/services/authentication/decision.rs
// Module: router

pub fn spawn_tracked_job<E, F>(future: F, request_type: &'static str)


// Function: transform_to_sql_values
// File: crates/analytics/src/query.rs
// Module: analytics

pub fn transform_to_sql_values(&mut self, values: &[impl ToSql<T>]) -> QueryResult<String>


// Struct: JpmorganMerchantSoftware
// File: crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct JpmorganMerchantSoftware


// Struct: StaxRefundRequest
// File: crates/hyperswitch_connectors/src/connectors/stax/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct StaxRefundRequest


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

pub struct References


// Function: get_or_generate_payment_id
// File: crates/router/src/routes/payments.rs
// Module: router

pub fn get_or_generate_payment_id(
    payload: &mut payment_types::PaymentsRequest,
) -> errors::RouterResult<()>


// Function: update_user_details
// File: crates/router/src/core/user.rs
// Module: router

pub fn update_user_details(
    state: SessionState,
    user_token: auth::UserFromToken,
    req: user_api::UpdateUserAccountDetailsRequest,
    _req_state: ReqState,
) -> UserResponse<()>


// File: crates/common_types/src/primitive_wrappers.rs
// Module: common_types
// Public functions: 4
// Public structs: 9

pub use bool_wrappers::*;
pub use u32_wrappers::*;
mod bool_wrappers {
    use std::ops::Deref;

    use serde::{Deserialize, Serialize};
    /// Bool that represents if Extended Authorization is Applied or not
    #[derive(
        Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, diesel::expression::AsExpression,
    )]
    #[diesel(sql_type = diesel::sql_types::Bool)]
    pub struct ExtendedAuthorizationAppliedBool(bool);
    impl Deref for ExtendedAuthorizationAppliedBool {
        type Target = bool;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl From<bool> for ExtendedAuthorizationAppliedBool {
        fn from(value: bool) -> Self {
            Self(value)
        }
    }
    impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB> for ExtendedAuthorizationAppliedBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
    {
        fn to_sql<'b>(
            &'b self,
            out: &mut diesel::serialize::Output<'b, '_, DB>,
        ) -> diesel::serialize::Result {
            self.0.to_sql(out)
        }
    }
    impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>
        for ExtendedAuthorizationAppliedBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
    {
        fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
            bool::from_sql(value).map(Self)
        }
    }

    /// Bool that represents if Extended Authorization is Requested or not
    #[derive(
        Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, diesel::expression::AsExpression,
    )]
    #[diesel(sql_type = diesel::sql_types::Bool)]
    pub struct RequestExtendedAuthorizationBool(bool);
    impl Deref for RequestExtendedAuthorizationBool {
        type Target = bool;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl From<bool> for RequestExtendedAuthorizationBool {
        fn from(value: bool) -> Self {
            Self(value)
        }
    }
    impl RequestExtendedAuthorizationBool {
        /// returns the inner bool value
        pub fn is_true(&self) -> bool {
            self.0
        }
    }
    impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB> for RequestExtendedAuthorizationBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
    {
        fn to_sql<'b>(
            &'b self,
            out: &mut diesel::serialize::Output<'b, '_, DB>,
        ) -> diesel::serialize::Result {
            self.0.to_sql(out)
        }
    }
    impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>
        for RequestExtendedAuthorizationBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
    {
        fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
            bool::from_sql(value).map(Self)
        }
    }

    /// Bool that represents if Enable Partial Authorization is Requested or not
    #[derive(
        Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, diesel::expression::AsExpression,
    )]
    #[diesel(sql_type = diesel::sql_types::Bool)]
    pub struct EnablePartialAuthorizationBool(bool);
    impl Deref for EnablePartialAuthorizationBool {
        type Target = bool;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl From<bool> for EnablePartialAuthorizationBool {
        fn from(value: bool) -> Self {
            Self(value)
        }
    }
    impl EnablePartialAuthorizationBool {
        /// returns the inner bool value
        pub fn is_true(&self) -> bool {
            self.0
        }
    }
    impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB> for EnablePartialAuthorizationBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
    {
        fn to_sql<'b>(
            &'b self,
            out: &mut diesel::serialize::Output<'b, '_, DB>,
        ) -> diesel::serialize::Result {
            self.0.to_sql(out)
        }
    }
    impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>
        for EnablePartialAuthorizationBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
    {
        fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
            bool::from_sql(value).map(Self)
        }
    }

    /// Bool that represents if Extended Authorization is always Requested or not
    #[derive(
        Clone, Copy, Debug, Eq, PartialEq, diesel::expression::AsExpression, Serialize, Deserialize,
    )]
    #[diesel(sql_type = diesel::sql_types::Bool)]
    pub struct AlwaysRequestExtendedAuthorization(bool);
    impl Deref for AlwaysRequestExtendedAuthorization {
        type Target = bool;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB>
        for AlwaysRequestExtendedAuthorization
    where
        DB: diesel::backend::Backend,
        bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
    {
        fn to_sql<'b>(
            &'b self,
            out: &mut diesel::serialize::Output<'b, '_, DB>,
        ) -> diesel::serialize::Result {
            self.0.to_sql(out)
        }
    }
    impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>
        for AlwaysRequestExtendedAuthorization
    where
        DB: diesel::backend::Backend,
        bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
    {
        fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
            bool::from_sql(value).map(Self)
        }
    }
    /// Bool that represents if Cvv should be collected during payment or not. Default is true
    #[derive(
        Clone, Copy, Debug, Eq, PartialEq, diesel::expression::AsExpression, Serialize, Deserialize,
    )]
    #[diesel(sql_type = diesel::sql_types::Bool)]
    pub struct ShouldCollectCvvDuringPayment(bool);
    impl Deref for ShouldCollectCvvDuringPayment {
        type Target = bool;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB> for ShouldCollectCvvDuringPayment
    where
        DB: diesel::backend::Backend,
        bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
    {
        fn to_sql<'b>(
            &'b self,
            out: &mut diesel::serialize::Output<'b, '_, DB>,
        ) -> diesel::serialize::Result {
            self.0.to_sql(out)
        }
    }
    impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB> for ShouldCollectCvvDuringPayment
    where
        DB: diesel::backend::Backend,
        bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
    {
        fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
            bool::from_sql(value).map(Self)
        }
    }

    impl Default for ShouldCollectCvvDuringPayment {
        /// Default for `ShouldCollectCvvDuringPayment` is `true`
        fn default() -> Self {
            Self(true)
        }
    }

    /// Bool that represents if overcapture should always be requested
    #[derive(
        Clone, Copy, Debug, Eq, PartialEq, diesel::expression::AsExpression, Serialize, Deserialize,
    )]
    #[diesel(sql_type = diesel::sql_types::Bool)]
    pub struct AlwaysEnableOvercaptureBool(bool);
    impl AlwaysEnableOvercaptureBool {
        /// returns the inner bool value
        pub fn is_true(&self) -> bool {
            self.0
        }
    }
    impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB> for AlwaysEnableOvercaptureBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
    {
        fn to_sql<'b>(
            &'b self,
            out: &mut diesel::serialize::Output<'b, '_, DB>,
        ) -> diesel::serialize::Result {
            self.0.to_sql(out)
        }
    }
    impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB> for AlwaysEnableOvercaptureBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
    {
        fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
            bool::from_sql(value).map(Self)
        }
    }

    impl Default for AlwaysEnableOvercaptureBool {
        /// Default for `AlwaysEnableOvercaptureBool` is `false`
        fn default() -> Self {
            Self(false)
        }
    }

    /// Bool that represents if overcapture is requested for this payment
    #[derive(
        Clone, Copy, Debug, Eq, PartialEq, diesel::expression::AsExpression, Serialize, Deserialize,
    )]
    #[diesel(sql_type = diesel::sql_types::Bool)]
    pub struct EnableOvercaptureBool(bool);

    impl From<bool> for EnableOvercaptureBool {
        fn from(value: bool) -> Self {
            Self(value)
        }
    }

    impl From<AlwaysEnableOvercaptureBool> for EnableOvercaptureBool {
        fn from(item: AlwaysEnableOvercaptureBool) -> Self {
            Self(item.is_true())
        }
    }

    impl Deref for EnableOvercaptureBool {
        type Target = bool;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB> for EnableOvercaptureBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
    {
        fn to_sql<'b>(
            &'b self,
            out: &mut diesel::serialize::Output<'b, '_, DB>,
        ) -> diesel::serialize::Result {
            self.0.to_sql(out)
        }
    }
    impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB> for EnableOvercaptureBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
    {
        fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
            bool::from_sql(value).map(Self)
        }
    }

    impl Default for EnableOvercaptureBool {
        /// Default for `EnableOvercaptureBool` is `false`
        fn default() -> Self {
            Self(false)
        }
    }

    /// Bool that represents if overcapture is applied for a payment by the connector
    #[derive(
        Clone, Copy, Debug, Eq, PartialEq, diesel::expression::AsExpression, Serialize, Deserialize,
    )]
    #[diesel(sql_type = diesel::sql_types::Bool)]
    pub struct OvercaptureEnabledBool(bool);

    impl OvercaptureEnabledBool {
        /// Creates a new instance of `OvercaptureEnabledBool`
        pub fn new(value: bool) -> Self {
            Self(value)
        }
    }

    impl Default for OvercaptureEnabledBool {
        /// Default for `OvercaptureEnabledBool` is `false`
        fn default() -> Self {
            Self(false)
        }
    }

    impl Deref for OvercaptureEnabledBool {
        type Target = bool;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB> for OvercaptureEnabledBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
    {
        fn to_sql<'b>(
            &'b self,
            out: &mut diesel::serialize::Output<'b, '_, DB>,
        ) -> diesel::serialize::Result {
            self.0.to_sql(out)
        }
    }
    impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB> for OvercaptureEnabledBool
    where
        DB: diesel::backend::Backend,
        bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
    {
        fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
            bool::from_sql(value).map(Self)
        }
    }
}

mod u32_wrappers {
    use std::ops::Deref;

    use serde::{de::Error, Deserialize, Serialize};

    use crate::consts::{
        DEFAULT_DISPUTE_POLLING_INTERVAL_IN_HOURS, MAX_DISPUTE_POLLING_INTERVAL_IN_HOURS,
    };
    /// Time interval in hours for polling disputes
    #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, diesel::expression::AsExpression)]
    #[diesel(sql_type = diesel::sql_types::Integer)]
    pub struct DisputePollingIntervalInHours(i32);

    impl Deref for DisputePollingIntervalInHours {
        type Target = i32;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    impl<'de> Deserialize<'de> for DisputePollingIntervalInHours {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: serde::Deserializer<'de>,
        {
            let val = i32::deserialize(deserializer)?;
            if val < 0 {
                Err(D::Error::custom(
                    "DisputePollingIntervalInHours cannot be negative",
                ))
            } else if val > MAX_DISPUTE_POLLING_INTERVAL_IN_HOURS {
                Err(D::Error::custom(
                    "DisputePollingIntervalInHours exceeds the maximum allowed value of 24",
                ))
            } else {
                Ok(Self(val))
            }
        }
    }

    impl diesel::deserialize::FromSql<diesel::sql_types::Integer, diesel::pg::Pg>
        for DisputePollingIntervalInHours
    {
        fn from_sql(value: diesel::pg::PgValue<'_>) -> diesel::deserialize::Result<Self> {
            i32::from_sql(value).map(Self)
        }
    }

    impl diesel::serialize::ToSql<diesel::sql_types::Integer, diesel::pg::Pg>
        for DisputePollingIntervalInHours
    {
        fn to_sql<'b>(
            &'b self,
            out: &mut diesel::serialize::Output<'b, '_, diesel::pg::Pg>,
        ) -> diesel::serialize::Result {
            <i32 as diesel::serialize::ToSql<diesel::sql_types::Integer, diesel::pg::Pg>>::to_sql(
                &self.0, out,
            )
        }
    }

    impl Default for DisputePollingIntervalInHours {
        /// Default for `DisputePollingIntervalInHours` is `24`
        fn default() -> Self {
            Self(DEFAULT_DISPUTE_POLLING_INTERVAL_IN_HOURS)
        }
    }
}


// Struct: CoingateRefundRequest
// File: crates/hyperswitch_connectors/src/connectors/coingate/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CoingateRefundRequest


// Implementation: impl api::subscriptions_v2::SubscriptionsV2 for for Recurly
// File: crates/hyperswitch_connectors/src/connectors/recurly.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::subscriptions_v2::SubscriptionsV2 for for Recurly