// File: crates/hyperswitch_connectors/src/connectors/bambora/transformers.rs
// Module: hyperswitch_connectors
// Public structs: 26

use base64::Engine;
use common_enums::enums;
use common_utils::{
    ext_traits::ValueExt,
    pii::{Email, IpAddress},
    types::FloatMajorUnit,
};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{ConnectorAuthType, RouterData},
    router_flow_types::refunds::{Execute, RSync},
    router_request_types::{
        CompleteAuthorizeData, PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData,
        PaymentsSyncData, ResponseId,
    },
    router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData},
    types,
};
use hyperswitch_interfaces::errors;
use masking::{ExposeInterface, PeekInterface, Secret};
use serde::{Deserialize, Deserializer, Serialize};

use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    utils::{
        self, AddressDetailsData, BrowserInformationData, CardData as _,
        PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData,
        PaymentsSyncRequestData, RouterData as _,
    },
};

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

impl<T> TryFrom<(FloatMajorUnit, T)> for BamboraRouterData<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(Default, Debug, Serialize, Eq, PartialEq)]
pub struct BamboraCard {
    name: Secret<String>,
    number: cards::CardNumber,
    expiry_month: Secret<String>,
    expiry_year: Secret<String>,
    cvd: Secret<String>,
    complete: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "3d_secure")]
    three_d_secure: Option<ThreeDSecure>,
}

#[derive(Default, Debug, Serialize, Eq, PartialEq)]
pub struct ThreeDSecure {
    browser: Option<BamboraBrowserInfo>, //Needed only in case of 3Ds 2.0. Need to update request for this.
    enabled: bool,
    version: Option<i64>,
    auth_required: Option<bool>,
}

#[derive(Default, Debug, Serialize, Eq, PartialEq)]
pub struct BamboraBrowserInfo {
    accept_header: String,
    java_enabled: bool,
    language: String,
    color_depth: u8,
    screen_height: u32,
    screen_width: u32,
    time_zone: i32,
    user_agent: String,
    javascript_enabled: bool,
}

#[derive(Default, Debug, Serialize)]
pub struct BamboraPaymentsRequest {
    order_number: String,
    amount: FloatMajorUnit,
    payment_method: PaymentMethod,
    customer_ip: Option<Secret<String, IpAddress>>,
    term_url: Option<String>,
    card: BamboraCard,
    billing: AddressData,
}

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

fn get_browser_info(
    item: &types::PaymentsAuthorizeRouterData,
) -> Result<Option<BamboraBrowserInfo>, error_stack::Report<errors::ConnectorError>> {
    if matches!(item.auth_type, enums::AuthenticationType::ThreeDs) {
        item.request
            .browser_info
            .as_ref()
            .map(|info| {
                Ok(BamboraBrowserInfo {
                    accept_header: info.get_accept_header()?,
                    java_enabled: info.get_java_enabled()?,
                    language: info.get_language()?,
                    screen_height: info.get_screen_height()?,
                    screen_width: info.get_screen_width()?,
                    color_depth: info.get_color_depth()?,
                    user_agent: info.get_user_agent()?,
                    time_zone: info.get_time_zone()?,
                    javascript_enabled: info.get_java_script_enabled()?,
                })
            })
            .transpose()
    } else {
        Ok(None)
    }
}

impl TryFrom<&CompleteAuthorizeData> for BamboraThreedsContinueRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(value: &CompleteAuthorizeData) -> Result<Self, Self::Error> {
        let card_response: CardResponse = value
            .redirect_response
            .as_ref()
            .and_then(|f| f.payload.to_owned())
            .ok_or(errors::ConnectorError::MissingRequiredField {
                field_name: "redirect_response.payload",
            })?
            .parse_value("CardResponse")
            .change_context(errors::ConnectorError::ParsingFailed)?;
        let bambora_req = Self {
            payment_method: "credit_card".to_string(),
            card_response,
        };
        Ok(bambora_req)
    }
}

impl TryFrom<BamboraRouterData<&types::PaymentsAuthorizeRouterData>> for BamboraPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: BamboraRouterData<&types::PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(req_card) => {
                let (three_ds, customer_ip) = match item.router_data.auth_type {
                    enums::AuthenticationType::ThreeDs => (
                        Some(ThreeDSecure {
                            enabled: true,
                            browser: get_browser_info(item.router_data)?,
                            version: Some(2),
                            auth_required: Some(true),
                        }),
                        Some(
                            item.router_data
                                .request
                                .get_browser_info()?
                                .get_ip_address()?,
                        ),
                    ),
                    enums::AuthenticationType::NoThreeDs => (None, None),
                };
                let card = BamboraCard {
                    name: item.router_data.get_billing_address()?.get_full_name()?,
                    expiry_year: req_card.get_card_expiry_year_2_digit()?,
                    number: req_card.card_number,
                    expiry_month: req_card.card_exp_month,
                    cvd: req_card.card_cvc,
                    three_d_secure: three_ds,
                    complete: item.router_data.request.is_auto_capture()?,
                };

                let (country, province) = match (
                    item.router_data.get_optional_billing_country(),
                    item.router_data.get_optional_billing_state_2_digit(),
                ) {
                    (Some(billing_country), Some(billing_state)) => {
                        (Some(billing_country), Some(billing_state))
                    }
                    _ => (None, None),
                };

                let billing = AddressData {
                    name: item.router_data.get_optional_billing_full_name(),
                    address_line1: item.router_data.get_optional_billing_line1(),
                    address_line2: item.router_data.get_optional_billing_line2(),
                    city: item.router_data.get_optional_billing_city(),
                    province,
                    country,
                    postal_code: item.router_data.get_optional_billing_zip(),
                    phone_number: item.router_data.get_optional_billing_phone_number(),
                    email_address: item.router_data.get_optional_billing_email(),
                };

                Ok(Self {
                    order_number: item.router_data.connector_request_reference_id.clone(),
                    amount: item.amount,
                    payment_method: PaymentMethod::Card,
                    card,
                    customer_ip,
                    term_url: item.router_data.request.complete_authorize_url.clone(),
                    billing,
                })
            }
            PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::Wallet(_)
            | PaymentMethodData::PayLater(_)
            | PaymentMethodData::BankRedirect(_)
            | PaymentMethodData::BankDebit(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::Crypto(_)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(_)
            | PaymentMethodData::Upi(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::MobilePayment(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::NetworkToken(_)
            | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
                Err(errors::ConnectorError::NotImplemented(
                    utils::get_unimplemented_payment_method_error_message("bambora"),
                )
                .into())
            }
        }
    }
}

impl TryFrom<BamboraRouterData<&types::PaymentsCancelRouterData>> for BamboraVoidRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: BamboraRouterData<&types::PaymentsCancelRouterData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: item.amount,
        })
    }
}

pub struct BamboraAuthType {
    pub(super) api_key: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for BamboraAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        if let ConnectorAuthType::BodyKey { api_key, key1 } = auth_type {
            let auth_key = format!("{}:{}", key1.peek(), api_key.peek());
            let auth_header = format!(
                "Passcode {}",
                common_utils::consts::BASE64_ENGINE.encode(auth_key)
            );
            Ok(Self {
                api_key: Secret::new(auth_header),
            })
        } else {
            Err(errors::ConnectorError::FailedToObtainAuthType)?
        }
    }
}

fn str_or_i32<'de, D>(deserializer: D) -> Result<String, D::Error>
where
    D: Deserializer<'de>,
{
    #[derive(Deserialize)]
    #[serde(untagged)]
    enum StrOrI32 {
        Str(String),
        I32(i32),
    }

    let value = StrOrI32::deserialize(deserializer)?;
    let res = match value {
        StrOrI32::Str(v) => v,
        StrOrI32::I32(v) => v.to_string(),
    };
    Ok(res)
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(untagged)]
pub enum BamboraResponse {
    NormalTransaction(Box<BamboraPaymentsResponse>),
    ThreeDsResponse(Box<Bambora3DsResponse>),
}

#[derive(Default, Debug, Clone, Deserialize, PartialEq, Serialize)]
pub struct BamboraPaymentsResponse {
    #[serde(deserialize_with = "str_or_i32")]
    id: String,
    authorizing_merchant_id: i32,
    #[serde(deserialize_with = "str_or_i32")]
    approved: String,
    #[serde(deserialize_with = "str_or_i32")]
    message_id: String,
    message: String,
    auth_code: String,
    created: String,
    amount: FloatMajorUnit,
    order_number: String,
    #[serde(rename = "type")]
    payment_type: String,
    comments: Option<String>,
    batch_number: Option<String>,
    total_refunds: Option<f32>,
    total_completions: Option<f32>,
    payment_method: String,
    card: CardData,
    billing: Option<AddressData>,
    shipping: Option<AddressData>,
    custom: CustomData,
    adjusted_by: Option<Vec<AdjustedBy>>,
    links: Vec<Links>,
    risk_score: Option<f32>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Bambora3DsResponse {
    #[serde(rename = "3d_session_data")]
    three_d_session_data: Secret<String>,
    contents: String,
}

#[derive(Debug, Serialize, Default, Deserialize)]
pub struct BamboraMeta {
    pub three_d_session_data: String,
}

#[derive(Default, Debug, Serialize, Eq, PartialEq)]
pub struct BamboraThreedsContinueRequest {
    pub(crate) payment_method: String,
    pub card_response: CardResponse,
}

#[derive(Default, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct CardResponse {
    pub(crate) cres: Option<common_utils::pii::SecretSerdeValue>,
}

#[derive(Default, Debug, Clone, Deserialize, PartialEq, Serialize)]
pub struct CardData {
    name: Option<Secret<String>>,
    expiry_month: Option<Secret<String>>,
    expiry_year: Option<Secret<String>>,
    card_type: String,
    last_four: Secret<String>,
    card_bin: Option<Secret<String>>,
    avs_result: String,
    cvd_result: String,
    cavv_result: Option<String>,
    address_match: Option<i32>,
    postal_result: Option<i32>,
    avs: Option<AvsObject>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AvsObject {
    id: String,
    message: String,
    processed: bool,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AddressData {
    name: Option<Secret<String>>,
    address_line1: Option<Secret<String>>,
    address_line2: Option<Secret<String>>,
    city: Option<String>,
    province: Option<Secret<String>>,
    country: Option<enums::CountryAlpha2>,
    postal_code: Option<Secret<String>>,
    phone_number: Option<Secret<String>>,
    email_address: Option<Email>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CustomData {
    ref1: String,
    ref2: String,
    ref3: String,
    ref4: String,
    ref5: String,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AdjustedBy {
    id: i32,
    #[serde(rename = "type")]
    adjusted_by_type: String,
    approval: i32,
    message: String,
    amount: FloatMajorUnit,
    created: String,
    url: String,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Links {
    rel: String,
    href: String,
    method: String,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum PaymentMethod {
    #[default]
    Card,
    Token,
    PaymentProfile,
    Cash,
    Cheque,
    Interac,
    ApplePay,
    AndroidPay,
    #[serde(rename = "3d_secure")]
    ThreeDSecure,
    ProcessorToken,
}

// Capture
#[derive(Default, Debug, Clone, Serialize, PartialEq)]
pub struct BamboraPaymentsCaptureRequest {
    amount: FloatMajorUnit,
    payment_method: PaymentMethod,
}

impl TryFrom<BamboraRouterData<&types::PaymentsCaptureRouterData>>
    for BamboraPaymentsCaptureRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: BamboraRouterData<&types::PaymentsCaptureRouterData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: item.amount,
            payment_method: PaymentMethod::Card,
        })
    }
}

impl<F> TryFrom<ResponseRouterData<F, BamboraResponse, PaymentsAuthorizeData, PaymentsResponseData>>
    for RouterData<F, PaymentsAuthorizeData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, BamboraResponse, PaymentsAuthorizeData, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        match item.response {
            BamboraResponse::NormalTransaction(pg_response) => Ok(Self {
                status: if pg_response.approved.as_str() == "1" {
                    match item.data.request.is_auto_capture()? {
                        true => enums::AttemptStatus::Charged,
                        false => enums::AttemptStatus::Authorized,
                    }
                } else {
                    match item.data.request.is_auto_capture()? {
                        true => enums::AttemptStatus::Failure,
                        false => enums::AttemptStatus::AuthorizationFailed,
                    }
                },
                response: Ok(PaymentsResponseData::TransactionResponse {
                    resource_id: ResponseId::ConnectorTransactionId(pg_response.id.to_string()),
                    redirection_data: Box::new(None),
                    mandate_reference: Box::new(None),
                    connector_metadata: None,
                    network_txn_id: None,
                    connector_response_reference_id: Some(pg_response.order_number.to_string()),
                    incremental_authorization_allowed: None,
                    charges: None,
                }),
                ..item.data
            }),

            BamboraResponse::ThreeDsResponse(response) => {
                let value = url::form_urlencoded::parse(response.contents.as_bytes())
                    .map(|(key, val)| [key, val].concat())
                    .collect();
                let redirection_data = Some(RedirectForm::Html { html_data: value });
                Ok(Self {
                    status: enums::AttemptStatus::AuthenticationPending,
                    response: Ok(PaymentsResponseData::TransactionResponse {
                        resource_id: ResponseId::NoResponseId,
                        redirection_data: Box::new(redirection_data),
                        mandate_reference: Box::new(None),
                        connector_metadata: Some(
                            serde_json::to_value(BamboraMeta {
                                three_d_session_data: response.three_d_session_data.expose(),
                            })
                            .change_context(errors::ConnectorError::ResponseHandlingFailed)?,
                        ),
                        network_txn_id: None,
                        connector_response_reference_id: Some(
                            item.data.connector_request_reference_id.to_string(),
                        ),
                        incremental_authorization_allowed: None,
                        charges: None,
                    }),
                    ..item.data
                })
            }
        }
    }
}

impl<F>
    TryFrom<
        ResponseRouterData<F, BamboraPaymentsResponse, CompleteAuthorizeData, PaymentsResponseData>,
    > for RouterData<F, CompleteAuthorizeData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            BamboraPaymentsResponse,
            CompleteAuthorizeData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: if item.response.approved.as_str() == "1" {
                match item.data.request.is_auto_capture()? {
                    true => enums::AttemptStatus::Charged,
                    false => enums::AttemptStatus::Authorized,
                }
            } else {
                match item.data.request.is_auto_capture()? {
                    true => enums::AttemptStatus::Failure,
                    false => enums::AttemptStatus::AuthorizationFailed,
                }
            },
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id.to_string()),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: Some(item.response.order_number.to_string()),
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

impl<F>
    TryFrom<ResponseRouterData<F, BamboraPaymentsResponse, PaymentsSyncData, PaymentsResponseData>>
    for RouterData<F, PaymentsSyncData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            BamboraPaymentsResponse,
            PaymentsSyncData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: match item.data.request.is_auto_capture()? {
                true => {
                    if item.response.approved.as_str() == "1" {
                        enums::AttemptStatus::Charged
                    } else {
                        enums::AttemptStatus::Failure
                    }
                }
                false => {
                    if item.response.approved.as_str() == "1" {
                        enums::AttemptStatus::Authorized
                    } else {
                        enums::AttemptStatus::AuthorizationFailed
                    }
                }
            },
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id.to_string()),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: Some(item.response.order_number.to_string()),
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

impl<F>
    TryFrom<
        ResponseRouterData<F, BamboraPaymentsResponse, PaymentsCaptureData, PaymentsResponseData>,
    > for RouterData<F, PaymentsCaptureData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            BamboraPaymentsResponse,
            PaymentsCaptureData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: if item.response.approved.as_str() == "1" {
                enums::AttemptStatus::Charged
            } else {
                enums::AttemptStatus::Failure
            },
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id.to_string()),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: Some(item.response.order_number.to_string()),
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

impl<F>
    TryFrom<
        ResponseRouterData<F, BamboraPaymentsResponse, PaymentsCancelData, PaymentsResponseData>,
    > for RouterData<F, PaymentsCancelData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            BamboraPaymentsResponse,
            PaymentsCancelData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: if item.response.approved.as_str() == "1" {
                enums::AttemptStatus::Voided
            } else {
                enums::AttemptStatus::VoidFailed
            },
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id.to_string()),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: Some(item.response.order_number.to_string()),
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

// REFUND :
// Type definition for RefundRequest
#[derive(Default, Debug, Serialize)]
pub struct BamboraRefundRequest {
    amount: FloatMajorUnit,
}

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

// Type definition for Refund Response
#[allow(dead_code)]
#[derive(Debug, 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,
        }
    }
}

#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct RefundResponse {
    #[serde(deserialize_with = "str_or_i32")]
    pub id: String,
    pub authorizing_merchant_id: i32,
    #[serde(deserialize_with = "str_or_i32")]
    pub approved: String,
    #[serde(deserialize_with = "str_or_i32")]
    pub message_id: String,
    pub message: String,
    pub auth_code: String,
    pub created: String,
    pub amount: FloatMajorUnit,
    pub order_number: String,
    #[serde(rename = "type")]
    pub payment_type: String,
    pub comments: Option<String>,
    pub batch_number: Option<String>,
    pub total_refunds: Option<f32>,
    pub total_completions: Option<f32>,
    pub payment_method: String,
    pub card: CardData,
    pub billing: Option<AddressData>,
    pub shipping: Option<AddressData>,
    pub custom: CustomData,
    pub adjusted_by: Option<Vec<AdjustedBy>>,
    pub links: Vec<Links>,
    pub risk_score: Option<f32>,
}

impl TryFrom<RefundsResponseRouterData<Execute, RefundResponse>>
    for types::RefundsRouterData<Execute>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        let refund_status = if item.response.approved.as_str() == "1" {
            enums::RefundStatus::Success
        } else {
            enums::RefundStatus::Failure
        };
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status,
            }),
            ..item.data
        })
    }
}

impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for types::RefundsRouterData<RSync> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        let refund_status = if item.response.approved.as_str() == "1" {
            enums::RefundStatus::Success
        } else {
            enums::RefundStatus::Failure
        };
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status,
            }),
            ..item.data
        })
    }
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct BamboraErrorResponse {
    pub code: i32,
    pub category: i32,
    pub message: String,
    pub reference: String,
    pub details: Option<Vec<ErrorDetail>>,
    pub validation: Option<CardValidation>,
    pub card: Option<CardError>,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CardError {
    pub avs: AVSDetails,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct AVSDetails {
    pub message: String,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ErrorDetail {
    field: String,
    message: String,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CardValidation {
    id: String,
    approved: i32,
    message_id: i32,
    message: String,
    auth_code: String,
    trans_date: String,
    order_number: String,
    type_: String,
    amount: f64,
    cvd_id: i32,
}


// Function: get_verification_days_left
// File: crates/router/src/types/domain/user.rs
// Module: router

pub fn get_verification_days_left(&self, state: &SessionState) -> UserResult<Option<i64>>


// Struct: InespayPaymentsResponseData
// File: crates/hyperswitch_connectors/src/connectors/inespay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct InespayPaymentsResponseData


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

// Documentation: Generate a new GlobalPaymentId from a cell id

pub fn generate(cell_id: &crate::id_type::CellId) -> Self


            error_reason,
            first_attempt,
            total,
            count,
            error_message,
            routing_approach,
            signature_network,
            is_issuer_regulated,
            is_debit_routed,
            start_bucket,
            end_bucket,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::payments::filters::PaymentFilterRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let status: Option<DBEnumWrapper<AttemptStatus>> =
            row.try_get("status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let connector: Option<String> = row.try_get("connector").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let authentication_type: Option<DBEnumWrapper<AuthenticationType>> =
            row.try_get("authentication_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let payment_method: Option<String> =
            row.try_get("payment_method").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let payment_method_type: Option<String> =
            row.try_get("payment_method_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let client_source: Option<String> = row.try_get("client_source").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let client_version: Option<String> =
            row.try_get("client_version").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let profile_id: Option<String> = row.try_get("profile_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_network: Option<String> = row.try_get("card_network").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let merchant_id: Option<String> = row.try_get("merchant_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_last_4: Option<String> = row.try_get("card_last_4").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_issuer: Option<String> = row.try_get("card_issuer").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let error_reason: Option<String> = row.try_get("error_reason").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let first_attempt: Option<bool> = row.try_get("first_attempt").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let routing_approach: Option<DBEnumWrapper<RoutingApproach>> =
            row.try_get("routing_approach").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let signature_network: Option<String> =
            row.try_get("signature_network").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let is_issuer_regulated: Option<bool> =
            row.try_get("is_issuer_regulated").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let is_debit_routed: Option<bool> =
            row.try_get("is_debit_routed").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        Ok(Self {
            currency,
            status,
            connector,
            authentication_type,
            payment_method,
            payment_method_type,
            client_source,
            client_version,
            profile_id,
            card_network,
            merchant_id,
            card_last_4,
            card_issuer,
            error_reason,
            first_attempt,
            routing_approach,
            signature_network,
            is_issuer_regulated,
            is_debit_routed,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::payment_intents::metrics::PaymentIntentMetricRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let status: Option<DBEnumWrapper<IntentStatus>> =
            row.try_get("status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let profile_id: Option<String> = row.try_get("profile_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let connector: Option<String> = row.try_get("connector").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let authentication_type: Option<DBEnumWrapper<AuthenticationType>> =
            row.try_get("authentication_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let payment_method: Option<String> =
            row.try_get("payment_method").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let payment_method_type: Option<String> =
            row.try_get("payment_method_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let card_network: Option<String> = row.try_get("card_network").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let merchant_id: Option<String> = row.try_get("merchant_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_last_4: Option<String> = row.try_get("card_last_4").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_issuer: Option<String> = row.try_get("card_issuer").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let error_reason: Option<String> = row.try_get("error_reason").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let total: Option<bigdecimal::BigDecimal> = row.try_get("total").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let count: Option<i64> = row.try_get("count").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let first_attempt: Option<i64> = row.try_get("first_attempt").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        // Removing millisecond precision to get accurate diffs against clickhouse
        let start_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("start_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        let end_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("end_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        Ok(Self {
            status,
            currency,
            profile_id,
            connector,
            authentication_type,
            payment_method,
            payment_method_type,
            card_network,
            merchant_id,
            card_last_4,
            card_issuer,
            error_reason,
            first_attempt,
            total,
            count,
            start_bucket,
            end_bucket,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::payment_intents::filters::PaymentIntentFilterRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let status: Option<DBEnumWrapper<IntentStatus>> =
            row.try_get("status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let profile_id: Option<String> = row.try_get("profile_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let connector: Option<String> = row.try_get("connector").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let authentication_type: Option<DBEnumWrapper<AuthenticationType>> =
            row.try_get("authentication_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let payment_method: Option<String> =
            row.try_get("payment_method").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let payment_method_type: Option<String> =
            row.try_get("payment_method_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let card_network: Option<String> = row.try_get("card_network").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let merchant_id: Option<String> = row.try_get("merchant_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_last_4: Option<String> = row.try_get("card_last_4").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let card_issuer: Option<String> = row.try_get("card_issuer").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let error_reason: Option<String> = row.try_get("error_reason").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let customer_id: Option<String> = row.try_get("customer_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        Ok(Self {
            status,
            currency,
            profile_id,
            connector,
            authentication_type,
            payment_method,
            payment_method_type,
            card_network,
            merchant_id,
            card_last_4,
            card_issuer,
            error_reason,
            customer_id,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::refunds::filters::RefundFilterRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let refund_status: Option<DBEnumWrapper<RefundStatus>> =
            row.try_get("refund_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let connector: Option<String> = row.try_get("connector").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let refund_type: Option<DBEnumWrapper<RefundType>> =
            row.try_get("refund_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let profile_id: Option<String> = row.try_get("profile_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let refund_reason: Option<String> = row.try_get("refund_reason").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let refund_error_message: Option<String> =
            row.try_get("refund_error_message").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        Ok(Self {
            currency,
            refund_status,
            connector,
            refund_type,
            profile_id,
            refund_reason,
            refund_error_message,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::refunds::distribution::RefundDistributionRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let refund_status: Option<DBEnumWrapper<RefundStatus>> =
            row.try_get("refund_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let connector: Option<String> = row.try_get("connector").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let refund_type: Option<DBEnumWrapper<RefundType>> =
            row.try_get("refund_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let profile_id: Option<String> = row.try_get("profile_id").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let total: Option<bigdecimal::BigDecimal> = row.try_get("total").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let count: Option<i64> = row.try_get("count").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let refund_reason: Option<String> = row.try_get("refund_reason").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let refund_error_message: Option<String> =
            row.try_get("refund_error_message").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        // Removing millisecond precision to get accurate diffs against clickhouse
        let start_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("start_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        let end_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("end_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        Ok(Self {
            currency,
            refund_status,
            connector,
            refund_type,
            profile_id,
            total,
            count,
            refund_reason,
            refund_error_message,
            start_bucket,
            end_bucket,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::frm::filters::FrmFilterRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let frm_name: Option<String> = row.try_get("frm_name").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let frm_status: Option<DBEnumWrapper<FraudCheckStatus>> =
            row.try_get("frm_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let frm_transaction_type: Option<DBEnumWrapper<FrmTransactionType>> =
            row.try_get("frm_transaction_type").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        Ok(Self {
            frm_name,
            frm_status,
            frm_transaction_type,
        })
    }
}

impl<'a> FromRow<'a, PgRow> for super::disputes::filters::DisputeFilterRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let dispute_stage: Option<String> = row.try_get("dispute_stage").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let dispute_status: Option<String> =
            row.try_get("dispute_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let connector: Option<String> = row.try_get("connector").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let connector_status: Option<String> =
            row.try_get("connector_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        Ok(Self {
            dispute_stage,
            dispute_status,
            connector,
            connector_status,
            currency,
        })
    }
}
impl<'a> FromRow<'a, PgRow> for super::disputes::metrics::DisputeMetricRow {
    fn from_row(row: &'a PgRow) -> sqlx::Result<Self> {
        let dispute_stage: Option<DBEnumWrapper<DisputeStage>> =
            row.try_get("dispute_stage").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let dispute_status: Option<DBEnumWrapper<DisputeStatus>> =
            row.try_get("dispute_status").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let connector: Option<String> = row.try_get("connector").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let currency: Option<DBEnumWrapper<Currency>> =
            row.try_get("currency").or_else(|e| match e {
                ColumnNotFound(_) => Ok(Default::default()),
                e => Err(e),
            })?;
        let total: Option<bigdecimal::BigDecimal> = row.try_get("total").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        let count: Option<i64> = row.try_get("count").or_else(|e| match e {
            ColumnNotFound(_) => Ok(Default::default()),
            e => Err(e),
        })?;
        // Removing millisecond precision to get accurate diffs against clickhouse
        let start_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("start_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        let end_bucket: Option<PrimitiveDateTime> = row
            .try_get::<Option<PrimitiveDateTime>, _>("end_bucket")?
            .and_then(|dt| dt.replace_millisecond(0).ok());
        Ok(Self {
            dispute_stage,
            dispute_status,
            connector,
            currency,
            total,
            count,
            start_bucket,
            end_bucket,
        })
    }
}

impl ToSql<SqlxClient> for PrimitiveDateTime {
    fn to_sql(&self, _table_engine: &TableEngine) -> error_stack::Result<String, ParsingError> {
        Ok(self.to_string())
    }
}

impl ToSql<SqlxClient> for AnalyticsCollection {
    fn to_sql(&self, _table_engine: &TableEngine) -> error_stack::Result<String, ParsingError> {
        match self {
            Self::Payment => Ok("payment_attempt".to_string()),
            Self::PaymentSessionized => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("PaymentSessionized table is not implemented for Sqlx"))?,
            Self::Refund => Ok("refund".to_string()),
            Self::RefundSessionized => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("RefundSessionized table is not implemented for Sqlx"))?,
            Self::SdkEvents => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("SdkEventsAudit table is not implemented for Sqlx"))?,
            Self::SdkEventsAnalytics => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("SdkEvents table is not implemented for Sqlx"))?,
            Self::ApiEvents => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("ApiEvents table is not implemented for Sqlx"))?,
            Self::FraudCheck => Ok("fraud_check".to_string()),
            Self::PaymentIntent => Ok("payment_intent".to_string()),
            Self::PaymentIntentSessionized => Err(error_stack::report!(
                ParsingError::UnknownError
            )
            .attach_printable("PaymentIntentSessionized table is not implemented for Sqlx"))?,
            Self::ConnectorEvents => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("ConnectorEvents table is not implemented for Sqlx"))?,
            Self::ApiEventsAnalytics => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("ApiEvents table is not implemented for Sqlx"))?,
            Self::ActivePaymentsAnalytics => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("ActivePaymentsAnalytics table is not implemented for Sqlx"))?,
            Self::OutgoingWebhookEvent => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("OutgoingWebhookEvents table is not implemented for Sqlx"))?,
            Self::Dispute => Ok("dispute".to_string()),
            Self::DisputeSessionized => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("DisputeSessionized table is not implemented for Sqlx"))?,
            Self::Authentications => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("Authentications table is not implemented for Sqlx"))?,
            Self::RoutingEvents => Err(error_stack::report!(ParsingError::UnknownError)
                .attach_printable("RoutingEvents table is not implemented for Sqlx"))?,
        }
    }
}

impl<T> ToSql<SqlxClient> for Aggregate<T>
where
    T: ToSql<SqlxClient>,
{
    fn to_sql(&self, table_engine: &TableEngine) -> error_stack::Result<String, ParsingError> {
        Ok(match self {
            Self::Count { field: _, alias } => {
                format!(
                    "count(*){}",
                    alias.map_or_else(|| "".to_owned(), |alias| format!(" as {alias}"))
                )
            }
            Self::Sum { field, alias } => {
                format!(
                    "sum({}){}",
                    field
                        .to_sql(table_engine)
                        .attach_printable("Failed to sum aggregate")?,
                    alias.map_or_else(|| "".to_owned(), |alias| format!(" as {alias}"))
                )
            }
            Self::Min { field, alias } => {
                format!(
                    "min({}){}",
                    field
                        .to_sql(table_engine)
                        .attach_printable("Failed to min aggregate")?,
                    alias.map_or_else(|| "".to_owned(), |alias| format!(" as {alias}"))
                )
            }
            Self::Max { field, alias } => {
                format!(
                    "max({}){}",
                    field
                        .to_sql(table_engine)
                        .attach_printable("Failed to max aggregate")?,
                    alias.map_or_else(|| "".to_owned(), |alias| format!(" as {alias}"))
                )
            }
            Self::Percentile {
                field,
                alias,
                percentile,
            } => {
                format!(
                    "percentile_cont(0.{}) within group (order by {} asc){}",
                    percentile.map_or_else(|| "50".to_owned(), |percentile| percentile.to_string()),
                    field
                        .to_sql(table_engine)
                        .attach_printable("Failed to percentile aggregate")?,
                    alias.map_or_else(|| "".to_owned(), |alias| format!(" as {alias}"))
                )
            }
            Self::DistinctCount { field, alias } => {
                format!(
                    "count(distinct {}){}",
                    field
                        .to_sql(table_engine)
                        .attach_printable("Failed to distinct count aggregate")?,
                    alias.map_or_else(|| "".to_owned(), |alias| format!(" as {alias}"))
                )
            }
        })
    }
}

impl<T> ToSql<SqlxClient> for Window<T>
where
    T: ToSql<SqlxClient>,
{
    fn to_sql(&self, table_engine: &TableEngine) -> error_stack::Result<String, ParsingError> {
        Ok(match self {
            Self::Sum {
                field,
                partition_by,
                order_by,
                alias,
            } => {
                format!(
                    "sum({}) over ({}{}){}",
                    field
                        .to_sql(table_engine)
                        .attach_printable("Failed to sum window")?,
                    partition_by.as_ref().map_or_else(
                        || "".to_owned(),
                        |partition_by| format!("partition by {}", partition_by.to_owned())
                    ),
                    order_by.as_ref().map_or_else(
                        || "".to_owned(),
                        |(order_column, order)| format!(
                            " order by {} {}",
                            order_column.to_owned(),
                            order
                        )
                    ),
                    alias.map_or_else(|| "".to_owned(), |alias| format!(" as {alias}"))
                )
            }
            Self::RowNumber {
                field: _,
                partition_by,
                order_by,
                alias,
            } => {
                format!(
                    "row_number() over ({}{}){}",
                    partition_by.as_ref().map_or_else(
                        || "".to_owned(),
                        |partition_by| format!("partition by {}", partition_by.to_owned())
                    ),
                    order_by.as_ref().map_or_else(
                        || "".to_owned(),
                        |(order_column, order)| format!(
                            " order by {} {}",
                            order_column.to_owned(),
                            order
                        )
                    ),
                    alias.map_or_else(|| "".to_owned(), |alias| format!(" as {alias}"))
                )
            }
        })
    }
}


// Function: delete_by_profile_id_merchant_id
// File: crates/diesel_models/src/query/business_profile.rs
// Module: diesel_models

pub fn delete_by_profile_id_merchant_id(
        conn: &PgPooledConn,
        profile_id: &common_utils::id_type::ProfileId,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> StorageResult<bool>


// Struct: Token
// File: crates/hyperswitch_connectors/src/connectors/shift4/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct Token


// Struct: ForteCancelRequest
// File: crates/hyperswitch_connectors/src/connectors/forte/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ForteCancelRequest


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

impl api::PaymentVoid for for Chargebee


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

pub struct ChargebeeSubscriptionCreateRequest


// Function: routing_link_config
// File: crates/openapi/src/routes/profile.rs
// Module: openapi

pub fn routing_link_config()


// Function: routing_retrieve_config
// File: crates/router/src/routes/routing.rs
// Module: router

pub fn routing_retrieve_config(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<common_utils::id_type::RoutingId>,
) -> impl Responder


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

impl api::PaymentAuthorize for for Mollie


// File: crates/analytics/src/payments/metrics/payment_count.rs
// Module: analytics

use std::collections::HashSet;

use api_models::analytics::{
    payments::{PaymentDimensions, PaymentFilters, PaymentMetricsBucketIdentifier},
    Granularity, TimeRange,
};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

use super::PaymentMetricRow;
use crate::{
    enums::AuthInfo,
    query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
    types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
};

#[derive(Default)]
pub(super) struct PaymentCount;

#[async_trait::async_trait]
impl<T> super::PaymentMetric<T> for PaymentCount
where
    T: AnalyticsDataSource + super::PaymentMetricAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_metrics(
        &self,
        dimensions: &[PaymentDimensions],
        auth: &AuthInfo,
        filters: &PaymentFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
        let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::Payment);

        for dim in dimensions.iter() {
            query_builder.add_select_column(dim).switch()?;
        }

        query_builder
            .add_select_column(Aggregate::Count {
                field: None,
                alias: Some("count"),
            })
            .switch()?;
        query_builder
            .add_select_column(Aggregate::Min {
                field: "created_at",
                alias: Some("start_bucket"),
            })
            .switch()?;
        query_builder
            .add_select_column(Aggregate::Max {
                field: "created_at",
                alias: Some("end_bucket"),
            })
            .switch()?;

        filters.set_filter_clause(&mut query_builder).switch()?;

        auth.set_filter_clause(&mut query_builder).switch()?;

        time_range
            .set_filter_clause(&mut query_builder)
            .attach_printable("Error filtering time range")
            .switch()?;

        for dim in dimensions.iter() {
            query_builder
                .add_group_by_clause(dim)
                .attach_printable("Error grouping by dimensions")
                .switch()?;
        }

        if let Some(granularity) = granularity {
            granularity
                .set_group_by_clause(&mut query_builder)
                .attach_printable("Error adding granularity")
                .switch()?;
        }

        query_builder
            .execute_query::<PaymentMetricRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| {
                Ok((
                    PaymentMetricsBucketIdentifier::new(
                        i.currency.as_ref().map(|i| i.0),
                        i.status.as_ref().map(|i| i.0),
                        i.connector.clone(),
                        i.authentication_type.as_ref().map(|i| i.0),
                        i.payment_method.clone(),
                        i.payment_method_type.clone(),
                        i.client_source.clone(),
                        i.client_version.clone(),
                        i.profile_id.clone(),
                        i.card_network.clone(),
                        i.merchant_id.clone(),
                        i.card_last_4.clone(),
                        i.card_issuer.clone(),
                        i.error_reason.clone(),
                        i.routing_approach.as_ref().map(|i| i.0.clone()),
                        i.signature_network.clone(),
                        i.is_issuer_regulated,
                        i.is_debit_routed,
                        TimeRange {
                            start_time: match (granularity, i.start_bucket) {
                                (Some(g), Some(st)) => g.clip_to_start(st)?,
                                _ => time_range.start_time,
                            },
                            end_time: granularity.as_ref().map_or_else(
                                || Ok(time_range.end_time),
                                |g| i.end_bucket.map(|et| g.clip_to_end(et)).transpose(),
                            )?,
                        },
                    ),
                    i,
                ))
            })
            .collect::<error_stack::Result<HashSet<_>, crate::query::PostProcessingError>>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


// Struct: PixBankTransferAdditionalData
// File: crates/common_utils/src/payout_method_utils.rs
// Module: common_utils
// Implementations: 0

pub struct PixBankTransferAdditionalData


// Function: generate_hscan_pattern_for_refund
// File: crates/router/src/utils/db_utils.rs
// Module: router

// Documentation: Generates hscan field pattern. Suppose the field is pa_1234_ref_1211 it will generate pa_1234_ref_*

pub fn generate_hscan_pattern_for_refund(sk: &str) -> String


// Struct: Amount
// File: crates/hyperswitch_connectors/src/connectors/moneris/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct Amount


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

impl CardDetailUpdate


// Struct: SecretStateContainer
// File: crates/hyperswitch_interfaces/src/secrets_interface/secret_state.rs
// Module: hyperswitch_interfaces
// Implementations: 2

pub struct SecretStateContainer<T, S: SecretState>


// Implementation: impl api::PaymentSync for for Taxjar
// File: crates/hyperswitch_connectors/src/connectors/taxjar.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentSync for for Taxjar


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

impl api::ConnectorAccessToken for for Gigadat


// 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>>


// Module Structure
// File: crates/payment_methods/src/helpers.rs
// Module: payment_methods

// Public exports:
pub use hyperswitch_domain_models::{errors::api_error_response, payment_methods as domain};


// File: crates/hyperswitch_connectors/src/connectors/gocardless/transformers.rs
// Module: hyperswitch_connectors
// Public structs: 40

use common_enums::{enums, CountryAlpha2, UsStatesAbbreviation};
use common_utils::{
    id_type,
    pii::{self, IpAddress},
    types::MinorUnit,
};
use hyperswitch_domain_models::{
    address::AddressDetails,
    payment_method_data::{BankDebitData, PaymentMethodData},
    router_data::{ConnectorAuthType, PaymentMethodToken, RouterData},
    router_flow_types::refunds::Execute,
    router_request_types::{
        ConnectorCustomerData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsSyncData, ResponseId, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorCustomerResponseData, MandateReference, PaymentsResponseData, RefundsResponseData,
    },
    types,
};
use hyperswitch_interfaces::errors;
use masking::{ExposeInterface, Secret};
use serde::{Deserialize, Serialize};

use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    utils::{
        self, AddressDetailsData, BrowserInformationData, CustomerData, ForeignTryFrom,
        PaymentsAuthorizeRequestData, PaymentsSetupMandateRequestData, RouterData as _,
    },
};

pub struct GocardlessRouterData<T> {
    pub amount: MinorUnit,
    pub router_data: T,
}

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

#[derive(Default, Debug, Serialize)]
pub struct GocardlessCustomerRequest {
    customers: GocardlessCustomer,
}

#[derive(Default, Debug, Serialize)]
pub struct GocardlessCustomer {
    address_line1: Option<Secret<String>>,
    address_line2: Option<Secret<String>>,
    address_line3: Option<Secret<String>>,
    city: Option<Secret<String>>,
    region: Option<Secret<String>>,
    country_code: Option<CountryAlpha2>,
    email: pii::Email,
    given_name: Secret<String>,
    family_name: Secret<String>,
    metadata: CustomerMetaData,
    danish_identity_number: Option<Secret<String>>,
    postal_code: Option<Secret<String>>,
    swedish_identity_number: Option<Secret<String>>,
}

#[derive(Default, Debug, Serialize)]
pub struct CustomerMetaData {
    crm_id: Option<Secret<id_type::CustomerId>>,
}

impl TryFrom<&types::ConnectorCustomerRouterData> for GocardlessCustomerRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &types::ConnectorCustomerRouterData) -> Result<Self, Self::Error> {
        let email = item.request.get_email()?;
        let billing_details_name = item.get_billing_full_name()?.expose();

        let (given_name, family_name) = billing_details_name
            .trim()
            .rsplit_once(' ')
            .unwrap_or((&billing_details_name, &billing_details_name));

        let billing_address = item.get_billing_address()?;

        let metadata = CustomerMetaData {
            crm_id: item.customer_id.clone().map(Secret::new),
        };
        let region = get_region(billing_address)?;
        Ok(Self {
            customers: GocardlessCustomer {
                email,
                given_name: Secret::new(given_name.to_string()),
                family_name: Secret::new(family_name.to_string()),
                metadata,
                address_line1: billing_address.line1.to_owned(),
                address_line2: billing_address.line2.to_owned(),
                address_line3: billing_address.line3.to_owned(),
                country_code: billing_address.country,
                region,
                // Should be populated based on the billing country
                danish_identity_number: None,
                postal_code: billing_address.zip.to_owned(),
                // Should be populated based on the billing country
                swedish_identity_number: None,
                city: billing_address.city.clone().map(Secret::new),
            },
        })
    }
}

fn get_region(
    address_details: &AddressDetails,
) -> Result<Option<Secret<String>>, error_stack::Report<errors::ConnectorError>> {
    match address_details.country {
        Some(CountryAlpha2::US) => {
            let state = address_details.get_state()?.to_owned();
            Ok(Some(Secret::new(
                UsStatesAbbreviation::foreign_try_from(state.expose())?.to_string(),
            )))
        }
        _ => Ok(None),
    }
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct GocardlessCustomerResponse {
    customers: Customers,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Customers {
    id: Secret<String>,
}

impl<F>
    TryFrom<
        ResponseRouterData<
            F,
            GocardlessCustomerResponse,
            ConnectorCustomerData,
            PaymentsResponseData,
        >,
    > for RouterData<F, ConnectorCustomerData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            GocardlessCustomerResponse,
            ConnectorCustomerData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(PaymentsResponseData::ConnectorCustomerResponse(
                ConnectorCustomerResponseData::new_with_customer_id(
                    item.response.customers.id.expose(),
                ),
            )),
            ..item.data
        })
    }
}

#[derive(Debug, Serialize)]
pub struct GocardlessBankAccountRequest {
    customer_bank_accounts: CustomerBankAccounts,
}

#[derive(Debug, Serialize)]
pub struct CustomerBankAccounts {
    #[serde(flatten)]
    accounts: CustomerBankAccount,
    links: CustomerAccountLink,
}

#[derive(Debug, Serialize)]
pub struct CustomerAccountLink {
    customer: Secret<String>,
}

#[derive(Debug, Serialize)]
#[serde(untagged)]
pub enum CustomerBankAccount {
    InternationalBankAccount(InternationalBankAccount),
    AUBankAccount(AUBankAccount),
    USBankAccount(USBankAccount),
}

#[derive(Debug, Serialize)]
pub struct InternationalBankAccount {
    iban: Secret<String>,
    account_holder_name: Secret<String>,
}

#[derive(Debug, Serialize)]
pub struct AUBankAccount {
    country_code: CountryAlpha2,
    account_number: Secret<String>,
    branch_code: Secret<String>,
    account_holder_name: Secret<String>,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "lowercase")]
pub struct USBankAccount {
    country_code: CountryAlpha2,
    account_number: Secret<String>,
    bank_code: Secret<String>,
    account_type: AccountType,
    account_holder_name: Secret<String>,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum AccountType {
    Checking,
    Savings,
}

impl TryFrom<&types::TokenizationRouterData> for GocardlessBankAccountRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &types::TokenizationRouterData) -> Result<Self, Self::Error> {
        let customer = item.get_connector_customer_id()?;
        let accounts = CustomerBankAccount::try_from(item)?;
        let links = CustomerAccountLink {
            customer: Secret::new(customer),
        };
        Ok(Self {
            customer_bank_accounts: CustomerBankAccounts { accounts, links },
        })
    }
}

impl TryFrom<&types::TokenizationRouterData> for CustomerBankAccount {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &types::TokenizationRouterData) -> Result<Self, Self::Error> {
        match &item.request.payment_method_data {
            PaymentMethodData::BankDebit(bank_debit_data) => {
                Self::try_from((bank_debit_data, item))
            }
            PaymentMethodData::Card(_)
            | PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::Wallet(_)
            | PaymentMethodData::PayLater(_)
            | PaymentMethodData::BankRedirect(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::Crypto(_)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(_)
            | PaymentMethodData::MobilePayment(_)
            | PaymentMethodData::Upi(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::NetworkToken(_)
            | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
                Err(errors::ConnectorError::NotImplemented(
                    utils::get_unimplemented_payment_method_error_message("Gocardless"),
                )
                .into())
            }
        }
    }
}

impl TryFrom<(&BankDebitData, &types::TokenizationRouterData)> for CustomerBankAccount {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        (bank_debit_data, item): (&BankDebitData, &types::TokenizationRouterData),
    ) -> Result<Self, Self::Error> {
        match bank_debit_data {
            BankDebitData::AchBankDebit {
                account_number,
                routing_number,
                bank_type,
                ..
            } => {
                let bank_type = bank_type.ok_or_else(utils::missing_field_err("bank_type"))?;
                let country_code = item.get_billing_country()?;
                let account_holder_name = item.get_billing_full_name()?;
                let us_bank_account = USBankAccount {
                    country_code,
                    account_number: account_number.clone(),
                    bank_code: routing_number.clone(),
                    account_type: AccountType::from(bank_type),
                    account_holder_name,
                };
                Ok(Self::USBankAccount(us_bank_account))
            }
            BankDebitData::BecsBankDebit {
                account_number,
                bsb_number,
                ..
            } => {
                let country_code = item.get_billing_country()?;
                let account_holder_name = item.get_billing_full_name()?;
                let au_bank_account = AUBankAccount {
                    country_code,
                    account_number: account_number.clone(),
                    branch_code: bsb_number.clone(),
                    account_holder_name,
                };
                Ok(Self::AUBankAccount(au_bank_account))
            }
            BankDebitData::SepaBankDebit { iban, .. } => {
                let account_holder_name = item.get_billing_full_name()?;
                let international_bank_account = InternationalBankAccount {
                    iban: iban.clone(),
                    account_holder_name,
                };
                Ok(Self::InternationalBankAccount(international_bank_account))
            }
            BankDebitData::BacsBankDebit { .. } => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("Gocardless"),
            )
            .into()),
        }
    }
}

impl From<common_enums::BankType> for AccountType {
    fn from(item: common_enums::BankType) -> Self {
        match item {
            common_enums::BankType::Checking => Self::Checking,
            common_enums::BankType::Savings => Self::Savings,
        }
    }
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct GocardlessBankAccountResponse {
    customer_bank_accounts: CustomerBankAccountResponse,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CustomerBankAccountResponse {
    pub id: Secret<String>,
}

impl<F>
    TryFrom<
        ResponseRouterData<
            F,
            GocardlessBankAccountResponse,
            PaymentMethodTokenizationData,
            PaymentsResponseData,
        >,
    > for RouterData<F, PaymentMethodTokenizationData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            GocardlessBankAccountResponse,
            PaymentMethodTokenizationData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(PaymentsResponseData::TokenizationResponse {
                token: item.response.customer_bank_accounts.id.expose(),
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Serialize)]
pub struct GocardlessMandateRequest {
    mandates: Mandate,
}

#[derive(Debug, Serialize)]
pub struct Mandate {
    scheme: GocardlessScheme,
    metadata: MandateMetaData,
    payer_ip_address: Option<Secret<String, IpAddress>>,
    links: MandateLink,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum GocardlessScheme {
    Becs,
    SepaCore,
    Ach,
    BecsNz,
}

#[derive(Debug, Serialize)]
pub struct MandateMetaData {
    payment_reference: String,
}

#[derive(Debug, Serialize)]
pub struct MandateLink {
    customer_bank_account: Secret<String>,
}

impl TryFrom<&types::SetupMandateRouterData> for GocardlessMandateRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &types::SetupMandateRouterData) -> Result<Self, Self::Error> {
        let (scheme, payer_ip_address) = match &item.request.payment_method_data {
            PaymentMethodData::BankDebit(bank_debit_data) => {
                let payer_ip_address = get_ip_if_required(bank_debit_data, item)?;
                Ok((
                    GocardlessScheme::try_from(bank_debit_data)?,
                    payer_ip_address,
                ))
            }
            PaymentMethodData::Card(_)
            | PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::Wallet(_)
            | PaymentMethodData::PayLater(_)
            | PaymentMethodData::BankRedirect(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::Crypto(_)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(_)
            | PaymentMethodData::MobilePayment(_)
            | PaymentMethodData::Upi(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::NetworkToken(_)
            | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
                Err(errors::ConnectorError::NotImplemented(
                    "Setup Mandate flow for selected payment method through Gocardless".to_string(),
                ))
            }
        }?;
        let payment_method_token = item.get_payment_method_token()?;
        let customer_bank_account = match payment_method_token {
            PaymentMethodToken::Token(token) => Ok(token),
            PaymentMethodToken::ApplePayDecrypt(_)
            | PaymentMethodToken::PazeDecrypt(_)
            | PaymentMethodToken::GooglePayDecrypt(_) => {
                Err(errors::ConnectorError::NotImplemented(
                    "Setup Mandate flow for selected payment method through Gocardless".to_string(),
                ))
            }
        }?;
        Ok(Self {
            mandates: Mandate {
                scheme,
                metadata: MandateMetaData {
                    payment_reference: item.connector_request_reference_id.clone(),
                },
                payer_ip_address,
                links: MandateLink {
                    customer_bank_account,
                },
            },
        })
    }
}

fn get_ip_if_required(
    bank_debit_data: &BankDebitData,
    item: &types::SetupMandateRouterData,
) -> Result<Option<Secret<String, IpAddress>>, error_stack::Report<errors::ConnectorError>> {
    let ip_address = item.request.get_browser_info()?.get_ip_address()?;
    match bank_debit_data {
        BankDebitData::AchBankDebit { .. } => Ok(Some(ip_address)),
        BankDebitData::SepaBankDebit { .. }
        | BankDebitData::BecsBankDebit { .. }
        | BankDebitData::BacsBankDebit { .. } => Ok(None),
    }
}

impl TryFrom<&BankDebitData> for GocardlessScheme {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &BankDebitData) -> Result<Self, Self::Error> {
        match item {
            BankDebitData::AchBankDebit { .. } => Ok(Self::Ach),
            BankDebitData::SepaBankDebit { .. } => Ok(Self::SepaCore),
            BankDebitData::BecsBankDebit { .. } => Ok(Self::Becs),
            BankDebitData::BacsBankDebit { .. } => Err(errors::ConnectorError::NotImplemented(
                "Setup Mandate flow for selected payment method through Gocardless".to_string(),
            )
            .into()),
        }
    }
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct GocardlessMandateResponse {
    mandates: MandateResponse,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MandateResponse {
    id: Secret<String>,
}

impl<F>
    TryFrom<
        ResponseRouterData<
            F,
            GocardlessMandateResponse,
            SetupMandateRequestData,
            PaymentsResponseData,
        >,
    > for RouterData<F, SetupMandateRequestData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            GocardlessMandateResponse,
            SetupMandateRequestData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        let mandate_reference = Some(MandateReference {
            connector_mandate_id: Some(item.response.mandates.id.clone().expose()),
            payment_method_id: None,
            mandate_metadata: None,
            connector_mandate_request_reference_id: None,
        });
        Ok(Self {
            response: Ok(PaymentsResponseData::TransactionResponse {
                connector_metadata: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                resource_id: ResponseId::NoResponseId,
                redirection_data: Box::new(None),
                mandate_reference: Box::new(mandate_reference),
                network_txn_id: None,
                charges: None,
            }),
            status: enums::AttemptStatus::Charged,
            ..item.data
        })
    }
}

#[derive(Debug, Serialize)]
pub struct GocardlessPaymentsRequest {
    payments: GocardlessPayment,
}

#[derive(Debug, Serialize)]
pub struct GocardlessPayment {
    amount: MinorUnit,
    currency: enums::Currency,
    description: Option<String>,
    metadata: PaymentMetaData,
    links: PaymentLink,
}

#[derive(Debug, Serialize)]
pub struct PaymentMetaData {
    payment_reference: String,
}

#[derive(Debug, Serialize)]
pub struct PaymentLink {
    mandate: Secret<String>,
}

impl TryFrom<&GocardlessRouterData<&types::PaymentsAuthorizeRouterData>>
    for GocardlessPaymentsRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &GocardlessRouterData<&types::PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        let mandate_id = if item.router_data.request.is_mandate_payment() {
            item.router_data
                .request
                .connector_mandate_id()
                .ok_or_else(utils::missing_field_err("mandate_id"))
        } else {
            Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("gocardless"),
            )
            .into())
        }?;
        let payments = GocardlessPayment {
            amount: item.router_data.request.minor_amount,
            currency: item.router_data.request.currency,
            description: item.router_data.description.clone(),
            metadata: PaymentMetaData {
                payment_reference: item.router_data.connector_request_reference_id.clone(),
            },
            links: PaymentLink {
                mandate: Secret::new(mandate_id),
            },
        };
        Ok(Self { payments })
    }
}

// Auth Struct
pub struct GocardlessAuthType {
    pub(super) access_token: Secret<String>,
}

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

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GocardlessPaymentStatus {
    PendingCustomerApproval,
    PendingSubmission,
    Submitted,
    Confirmed,
    PaidOut,
    Cancelled,
    CustomerApprovalDenied,
    Failed,
}

impl From<GocardlessPaymentStatus> for enums::AttemptStatus {
    fn from(item: GocardlessPaymentStatus) -> Self {
        match item {
            GocardlessPaymentStatus::PendingCustomerApproval
            | GocardlessPaymentStatus::PendingSubmission
            | GocardlessPaymentStatus::Submitted => Self::Pending,
            GocardlessPaymentStatus::Confirmed | GocardlessPaymentStatus::PaidOut => Self::Charged,
            GocardlessPaymentStatus::Cancelled => Self::Voided,
            GocardlessPaymentStatus::CustomerApprovalDenied => Self::AuthenticationFailed,
            GocardlessPaymentStatus::Failed => Self::Failure,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GocardlessPaymentsResponse {
    payments: PaymentResponse,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PaymentResponse {
    status: GocardlessPaymentStatus,
    id: String,
}

impl<F>
    TryFrom<
        ResponseRouterData<
            F,
            GocardlessPaymentsResponse,
            PaymentsAuthorizeData,
            PaymentsResponseData,
        >,
    > for RouterData<F, PaymentsAuthorizeData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            GocardlessPaymentsResponse,
            PaymentsAuthorizeData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        let mandate_reference = MandateReference {
            connector_mandate_id: Some(item.data.request.get_connector_mandate_id()?),
            payment_method_id: None,
            mandate_metadata: None,
            connector_mandate_request_reference_id: None,
        };
        Ok(Self {
            status: enums::AttemptStatus::from(item.response.payments.status),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.payments.id),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(Some(mandate_reference)),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

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

// REFUND :
#[derive(Default, Debug, Serialize)]
pub struct GocardlessRefundRequest {
    refunds: GocardlessRefund,
}

#[derive(Default, Debug, Serialize)]
pub struct GocardlessRefund {
    amount: MinorUnit,
    metadata: RefundMetaData,
    links: RefundLink,
}

#[derive(Default, Debug, Serialize)]
pub struct RefundMetaData {
    refund_reference: String,
}

#[derive(Default, Debug, Serialize)]
pub struct RefundLink {
    payment: String,
}

impl<F> TryFrom<&GocardlessRouterData<&types::RefundsRouterData<F>>> for GocardlessRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &GocardlessRouterData<&types::RefundsRouterData<F>>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            refunds: GocardlessRefund {
                amount: item.amount.to_owned(),
                metadata: RefundMetaData {
                    refund_reference: item.router_data.connector_request_reference_id.clone(),
                },
                links: RefundLink {
                    payment: item.router_data.request.connector_transaction_id.clone(),
                },
            },
        })
    }
}

#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct RefundResponse {
    id: String,
}

impl TryFrom<RefundsResponseRouterData<Execute, RefundResponse>>
    for types::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::Pending,
            }),
            ..item.data
        })
    }
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GocardlessErrorResponse {
    pub error: GocardlessError,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GocardlessError {
    pub message: String,
    pub code: u16,
    pub errors: Vec<Error>,
    #[serde(rename = "type")]
    pub error_type: String,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Error {
    pub field: Option<String>,
    pub message: String,
}

#[derive(Debug, Deserialize)]
pub struct GocardlessWebhookEvent {
    pub events: Vec<WebhookEvent>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WebhookEvent {
    pub resource_type: WebhookResourceType,
    pub action: WebhookAction,
    pub links: WebhooksLink,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum WebhookResourceType {
    Payments,
    Refunds,
    Mandates,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum WebhookAction {
    PaymentsAction(PaymentsAction),
    RefundsAction(RefundsAction),
    MandatesAction(MandatesAction),
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PaymentsAction {
    Created,
    CustomerApprovalGranted,
    CustomerApprovalDenied,
    Submitted,
    Confirmed,
    PaidOut,
    LateFailureSettled,
    SurchargeFeeDebited,
    Failed,
    Cancelled,
    ResubmissionRequired,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RefundsAction {
    Created,
    Failed,
    Paid,
    // Payout statuses
    RefundSettled,
    FundsReturned,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MandatesAction {
    Created,
    CustomerApprovalGranted,
    CustomerApprovalSkipped,
    Active,
    Cancelled,
    Failed,
    Transferred,
    Expired,
    Submitted,
    ResubmissionRequested,
    Reinstated,
    Replaced,
    Consumed,
    Blocked,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum WebhooksLink {
    PaymentWebhooksLink(PaymentWebhooksLink),
    RefundWebhookLink(RefundWebhookLink),
    MandateWebhookLink(MandateWebhookLink),
}

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

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

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

impl TryFrom<&WebhookEvent> for GocardlessPaymentsResponse {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &WebhookEvent) -> Result<Self, Self::Error> {
        let id = match &item.links {
            WebhooksLink::PaymentWebhooksLink(link) => link.payment.to_owned(),
            WebhooksLink::RefundWebhookLink(_) | WebhooksLink::MandateWebhookLink(_) => {
                Err(errors::ConnectorError::WebhookEventTypeNotFound)?
            }
        };
        Ok(Self {
            payments: PaymentResponse {
                status: GocardlessPaymentStatus::try_from(&item.action)?,
                id,
            },
        })
    }
}

impl TryFrom<&WebhookAction> for GocardlessPaymentStatus {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &WebhookAction) -> Result<Self, Self::Error> {
        match item {
            WebhookAction::PaymentsAction(action) => match action {
                PaymentsAction::CustomerApprovalGranted | PaymentsAction::Submitted => {
                    Ok(Self::Submitted)
                }
                PaymentsAction::CustomerApprovalDenied => Ok(Self::CustomerApprovalDenied),
                PaymentsAction::LateFailureSettled => Ok(Self::Failed),
                PaymentsAction::Failed => Ok(Self::Failed),
                PaymentsAction::Cancelled => Ok(Self::Cancelled),
                PaymentsAction::Confirmed => Ok(Self::Confirmed),
                PaymentsAction::PaidOut => Ok(Self::PaidOut),
                PaymentsAction::SurchargeFeeDebited
                | PaymentsAction::ResubmissionRequired
                | PaymentsAction::Created => Err(errors::ConnectorError::WebhookEventTypeNotFound)?,
            },
            WebhookAction::RefundsAction(_) | WebhookAction::MandatesAction(_) => {
                Err(errors::ConnectorError::WebhookEventTypeNotFound)?
            }
        }
    }
}


// Struct: CompleteThreeDsActionLink
// File: crates/hyperswitch_connectors/src/connectors/worldpay/response.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CompleteThreeDsActionLink


// Implementation: impl std::ops::Deref for for EncryptedJsonType
// File: crates/hyperswitch_domain_models/src/type_encryption.rs
// Module: hyperswitch_domain_models
// Methods: 1 total (0 public)

impl std::ops::Deref for for EncryptedJsonType


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

impl api::ConnectorAccessToken for for Wellsfargo


// Struct: PaymentSessionUpdate
// File: crates/router/src/core/payments/operations/tax_calculation.rs
// Module: router
// Implementations: 0

pub struct PaymentSessionUpdate


// Function: refund_retrieve_with_gateway_creds
// File: crates/router/src/compatibility/stripe/refunds.rs
// Module: router

pub fn refund_retrieve_with_gateway_creds(
    state: web::Data<routes::AppState>,
    qs_config: web::Data<serde_qs::Config>,
    req: HttpRequest,
    form_payload: web::Bytes,
) -> HttpResponse


// File: crates/diesel_models/src/query/callback_mapper.rs
// Module: diesel_models
// Public functions: 2

use diesel::{associations::HasTable, ExpressionMethods};

use super::generics;
use crate::{
    callback_mapper::CallbackMapper, schema::callback_mapper::dsl, PgPooledConn, StorageResult,
};

impl CallbackMapper {
    pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<Self> {
        generics::generic_insert(conn, self).await
    }

    pub async fn find_by_id(conn: &PgPooledConn, id: &str) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::id.eq(id.to_owned()),
        )
        .await
    }
}


// Struct: PayoneRouterData
// File: crates/hyperswitch_connectors/src/connectors/payone/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PayoneRouterData<T>


// Implementation: impl SmithyGenerator
// File: crates/smithy-core/src/generator.rs
// Module: smithy-core
// Methods: 0 total (0 public)

impl SmithyGenerator


// Struct: TokenizePaymentMethodRequest
// File: crates/hyperswitch_domain_models/src/bulk_tokenization.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct TokenizePaymentMethodRequest


// Implementation: impl SingleOrListElement
// File: crates/hyperswitch_connectors/src/connectors/netcetera/netcetera_types.rs
// Module: hyperswitch_connectors
// Methods: 2 total (2 public)

impl SingleOrListElement


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

pub fn get_theme_file_key(theme_id: &str) -> PathBuf