                        apple_pay_predecrypt_data
                            .application_primary_account_number
                            .clone(),
                    ),
                    last4_digits: Some(Secret::new(
                        apple_pay_predecrypt_data
                            .application_primary_account_number
                            .get_last4(),
                    )),
                    expiration_month: Some(
                        apple_pay_predecrypt_data
                            .application_expiration_month
                            .clone(),
                    ),
                    expiration_year: Some(
                        apple_pay_predecrypt_data
                            .application_expiration_year
                            .clone(),
                    ),
                    external_token: Some(ExternalToken {
                        external_token_provider: ExternalTokenProvider::ApplePay,
                        mobile_token: None,
                        cryptogram: Some(
                            apple_pay_predecrypt_data
                                .payment_data
                                .online_payment_cryptogram
                                .clone(),
                        ),
                        eci_provider: Some(
                            apple_pay_predecrypt_data
                                .payment_data
                                .eci_indicator.clone()
                                .ok_or_else(missing_field_err(
                                "payment_method_data.wallet.apple_pay.payment_data.eci_indicator",
                            ))?,
                        ),
                    }),
                    ..Default::default()
                }),
                ..Default::default()
            },
            ..Default::default()
        }),
        ApplePayPaymentData::Encrypted(ref encrypted_data) => Ok(NuveiPaymentsRequest {
           is_rebilling,
            payment_option: PaymentOption {
                card: Some(Card {
                    external_token: Some(ExternalToken {
                        external_token_provider: ExternalTokenProvider::ApplePay,
                        mobile_token: {
                            let apple_pay: ApplePayCamelCase = ApplePayCamelCase {
                                payment_data: encrypted_data.to_string().into(),
                                payment_method: ApplePayPaymentMethodCamelCase {
                                    display_name: Secret::new(
                                        apple_pay_data.payment_method.display_name.clone(),
                                    ),
                                    network: Secret::new(
                                        apple_pay_data.payment_method.network.clone(),
                                    ),
                                    pm_type: Secret::new(
                                        apple_pay_data.payment_method.pm_type.clone(),
                                    ),
                                },
                                transaction_identifier: Secret::new(
                                    apple_pay_data.transaction_identifier.clone(),
                                ),
                            };

                            Some(Secret::new(
                                apple_pay.encode_to_string_of_json().change_context(
                                    errors::ConnectorError::RequestEncodingFailed,
                                )?,
                            ))
                        },
                        cryptogram: None,
                        eci_provider: None,
                    }),
                    ..Default::default()
                }),
                ..Default::default()
            },
            ..Default::default()
        }),
    }
}

impl TryFrom<enums::BankNames> for NuveiBIC {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(bank: enums::BankNames) -> Result<Self, Self::Error> {
        match bank {
            enums::BankNames::AbnAmro => Ok(Self::Abnamro),
            enums::BankNames::AsnBank => Ok(Self::ASNBank),
            enums::BankNames::Bunq => Ok(Self::Bunq),
            enums::BankNames::Ing => Ok(Self::Ing),
            enums::BankNames::Knab => Ok(Self::Knab),
            enums::BankNames::Rabobank => Ok(Self::Rabobank),
            enums::BankNames::SnsBank => Ok(Self::SNSBank),
            enums::BankNames::TriodosBank => Ok(Self::TriodosBank),
            enums::BankNames::VanLanschot => Ok(Self::VanLanschotBankiers),
            enums::BankNames::Moneyou => Ok(Self::Moneyou),

            enums::BankNames::AmericanExpress
            | enums::BankNames::AffinBank
            | enums::BankNames::AgroBank
            | enums::BankNames::AllianceBank
            | enums::BankNames::AmBank
            | enums::BankNames::BankOfAmerica
            | enums::BankNames::BankOfChina
            | enums::BankNames::BankIslam
            | enums::BankNames::BankMuamalat
            | enums::BankNames::BankRakyat
            | enums::BankNames::BankSimpananNasional
            | enums::BankNames::Barclays
            | enums::BankNames::BlikPSP
            | enums::BankNames::CapitalOne
            | enums::BankNames::Chase
            | enums::BankNames::Citi
            | enums::BankNames::CimbBank
            | enums::BankNames::Discover
            | enums::BankNames::NavyFederalCreditUnion
            | enums::BankNames::PentagonFederalCreditUnion
            | enums::BankNames::SynchronyBank
            | enums::BankNames::WellsFargo
            | enums::BankNames::Handelsbanken
            | enums::BankNames::HongLeongBank
            | enums::BankNames::HsbcBank
            | enums::BankNames::KuwaitFinanceHouse
            | enums::BankNames::Regiobank
            | enums::BankNames::Revolut
            | enums::BankNames::ArzteUndApothekerBank
            | enums::BankNames::AustrianAnadiBankAg
            | enums::BankNames::BankAustria
            | enums::BankNames::Bank99Ag
            | enums::BankNames::BankhausCarlSpangler
            | enums::BankNames::BankhausSchelhammerUndSchatteraAg
            | enums::BankNames::BankMillennium
            | enums::BankNames::BankPEKAOSA
            | enums::BankNames::BawagPskAg
            | enums::BankNames::BksBankAg
            | enums::BankNames::BrullKallmusBankAg
            | enums::BankNames::BtvVierLanderBank
            | enums::BankNames::CapitalBankGraweGruppeAg
            | enums::BankNames::CeskaSporitelna
            | enums::BankNames::Dolomitenbank
            | enums::BankNames::EasybankAg
            | enums::BankNames::EPlatbyVUB
            | enums::BankNames::ErsteBankUndSparkassen
            | enums::BankNames::FrieslandBank
            | enums::BankNames::HypoAlpeadriabankInternationalAg
            | enums::BankNames::HypoNoeLbFurNiederosterreichUWien
            | enums::BankNames::HypoOberosterreichSalzburgSteiermark
            | enums::BankNames::HypoTirolBankAg
            | enums::BankNames::HypoVorarlbergBankAg
            | enums::BankNames::HypoBankBurgenlandAktiengesellschaft
            | enums::BankNames::KomercniBanka
            | enums::BankNames::MBank
            | enums::BankNames::MarchfelderBank
            | enums::BankNames::Maybank
            | enums::BankNames::OberbankAg
            | enums::BankNames::OsterreichischeArzteUndApothekerbank
            | enums::BankNames::OcbcBank
            | enums::BankNames::PayWithING
            | enums::BankNames::PlaceZIPKO
            | enums::BankNames::PlatnoscOnlineKartaPlatnicza
            | enums::BankNames::PosojilnicaBankEGen
            | enums::BankNames::PostovaBanka
            | enums::BankNames::PublicBank
            | enums::BankNames::RaiffeisenBankengruppeOsterreich
            | enums::BankNames::RhbBank
            | enums::BankNames::SchelhammerCapitalBankAg
            | enums::BankNames::StandardCharteredBank
            | enums::BankNames::SchoellerbankAg
            | enums::BankNames::SpardaBankWien
            | enums::BankNames::SporoPay
            | enums::BankNames::SantanderPrzelew24
            | enums::BankNames::TatraPay
            | enums::BankNames::Viamo
            | enums::BankNames::VolksbankGruppe
            | enums::BankNames::VolkskreditbankAg
            | enums::BankNames::VrBankBraunau
            | enums::BankNames::UobBank
            | enums::BankNames::PayWithAliorBank
            | enums::BankNames::BankiSpoldzielcze
            | enums::BankNames::PayWithInteligo
            | enums::BankNames::BNPParibasPoland
            | enums::BankNames::BankNowySA
            | enums::BankNames::CreditAgricole
            | enums::BankNames::PayWithBOS
            | enums::BankNames::PayWithCitiHandlowy
            | enums::BankNames::PayWithPlusBank
            | enums::BankNames::ToyotaBank
            | enums::BankNames::VeloBank
            | enums::BankNames::ETransferPocztowy24
            | enums::BankNames::PlusBank
            | enums::BankNames::EtransferPocztowy24
            | enums::BankNames::BankiSpbdzielcze
            | enums::BankNames::BankNowyBfgSa
            | enums::BankNames::GetinBank
            | enums::BankNames::Blik
            | enums::BankNames::NoblePay
            | enums::BankNames::IdeaBank
            | enums::BankNames::EnveloBank
            | enums::BankNames::NestPrzelew
            | enums::BankNames::MbankMtransfer
            | enums::BankNames::Inteligo
            | enums::BankNames::PbacZIpko
            | enums::BankNames::BnpParibas
            | enums::BankNames::BankPekaoSa
            | enums::BankNames::VolkswagenBank
            | enums::BankNames::AliorBank
            | enums::BankNames::Boz
            | enums::BankNames::BangkokBank
            | enums::BankNames::KrungsriBank
            | enums::BankNames::KrungThaiBank
            | enums::BankNames::TheSiamCommercialBank
            | enums::BankNames::KasikornBank
            | enums::BankNames::OpenBankSuccess
            | enums::BankNames::OpenBankFailure
            | enums::BankNames::OpenBankCancelled
            | enums::BankNames::Aib
            | enums::BankNames::BankOfScotland
            | enums::BankNames::DanskeBank
            | enums::BankNames::FirstDirect
            | enums::BankNames::FirstTrust
            | enums::BankNames::Halifax
            | enums::BankNames::Lloyds
            | enums::BankNames::Monzo
            | enums::BankNames::NatWest
            | enums::BankNames::NationwideBank
            | enums::BankNames::RoyalBankOfScotland
            | enums::BankNames::Starling
            | enums::BankNames::TsbBank
            | enums::BankNames::TescoBank
            | enums::BankNames::Yoursafe
            | enums::BankNames::N26
            | enums::BankNames::NationaleNederlanden
            | enums::BankNames::UlsterBank => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("Nuvei"),
            ))?,
        }
    }
}

impl<F, Req>
    ForeignTryFrom<(
        AlternativePaymentMethodType,
        Option<BankRedirectData>,
        &RouterData<F, Req, PaymentsResponseData>,
    )> for NuveiPaymentsRequest
where
    Req: NuveiAuthorizePreprocessingCommon,
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(
        data: (
            AlternativePaymentMethodType,
            Option<BankRedirectData>,
            &RouterData<F, Req, PaymentsResponseData>,
        ),
    ) -> Result<Self, Self::Error> {
        let (payment_method, redirect, item) = data;
        let bank_id = match (&payment_method, redirect) {
            (AlternativePaymentMethodType::Expresscheckout, _) => None,
            (AlternativePaymentMethodType::Giropay, _) => None,
            (AlternativePaymentMethodType::Sofort, _) | (AlternativePaymentMethodType::Eps, _) => {
                let address = item.get_billing_address()?;
                address.get_first_name()?;
                item.request.get_email_required()?;
                item.get_billing_country()?;
                None
            }
            (
                AlternativePaymentMethodType::Ideal,
                Some(BankRedirectData::Ideal { bank_name, .. }),
            ) => {
                let address = item.get_billing_address()?;
                address.get_first_name()?;
                item.request.get_email_required()?;
                item.get_billing_country()?;
                bank_name.map(NuveiBIC::try_from).transpose()?
            }
            _ => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("Nuvei"),
            ))?,
        };
        let billing_address: Option<BillingAddress> =
            item.get_billing().ok().map(|billing| billing.into());
        Ok(Self {
            payment_option: PaymentOption {
                alternative_payment_method: Some(AlternativePaymentMethod {
                    payment_method,
                    bank_id,
                }),
                ..Default::default()
            },
            billing_address,
            ..Default::default()
        })
    }
}

fn get_pay_later_info<F, Req>(
    payment_method_type: AlternativePaymentMethodType,
    item: &RouterData<F, Req, PaymentsResponseData>,
) -> Result<NuveiPaymentsRequest, error_stack::Report<errors::ConnectorError>>
where
    Req: NuveiAuthorizePreprocessingCommon,
{
    let address = item
        .get_billing()?
        .address
        .as_ref()
        .ok_or_else(missing_field_err("billing.address"))?;
    address.get_first_name()?;
    let payment_method = payment_method_type;
    address.get_country()?; //country is necessary check
    item.request.get_email_required()?;
    Ok(NuveiPaymentsRequest {
        payment_option: PaymentOption {
            alternative_payment_method: Some(AlternativePaymentMethod {
                payment_method,
                ..Default::default()
            }),
            billing_address: item.get_billing().ok().map(|billing| billing.into()),
            ..Default::default()
        },
        ..Default::default()
    })
}

fn get_ntid_card_info<F, Req>(
    router_data: &RouterData<F, Req, PaymentsResponseData>,
    data: CardDetailsForNetworkTransactionId,
) -> Result<NuveiPaymentsRequest, error_stack::Report<errors::ConnectorError>>
where
    Req: NuveiAuthorizePreprocessingCommon,
{
    let external_scheme_details = Some(ExternalSchemeDetails {
        transaction_id: router_data
            .request
            .get_ntid()
            .ok_or_else(missing_field_err("network_transaction_id"))
            .attach_printable("Nuvei unable to find NTID for MIT")?
            .into(),
        brand: Some(
            data.card_network
                .ok_or_else(missing_field_err("recurring_details.data.card_network"))?,
        ),
    });
    let payment_option: PaymentOption = PaymentOption {
        card: Some(Card {
            card_number: Some(data.card_number),
            card_holder_name: data.card_holder_name,
            expiration_month: Some(data.card_exp_month),
            expiration_year: Some(data.card_exp_year),
            ..Default::default() // CVV should be disabled by nuvei fo
        }),
        redirect_url: None,
        user_payment_option_id: None,
        alternative_payment_method: None,
        billing_address: None,
        shipping_address: None,
    };
    let is_rebilling = if router_data.request.is_customer_initiated_mandate_payment() {
        Some("0".to_string())
    } else {
        None
    };
    Ok(NuveiPaymentsRequest {
        external_scheme_details,
        payment_option,
        is_rebilling,
        ..Default::default()
    })
}

impl<F, Req> TryFrom<(&RouterData<F, Req, PaymentsResponseData>, String)> for NuveiPaymentsRequest
where
    Req: NuveiAuthorizePreprocessingCommon,
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        data: (&RouterData<F, Req, PaymentsResponseData>, String),
    ) -> Result<Self, Self::Error> {
        let item = data.0;
        let request_data = match item.request.get_payment_method_data_required()?.clone() {
            PaymentMethodData::Card(card) => get_card_info(item, &card),
            PaymentMethodData::MandatePayment => Self::try_from(item),
            PaymentMethodData::CardDetailsForNetworkTransactionId(data) => {
                get_ntid_card_info(item, data)
            }
            PaymentMethodData::Wallet(wallet) => match wallet {
                WalletData::GooglePay(gpay_data) => get_googlepay_info(item, &gpay_data),
                WalletData::ApplePay(apple_pay_data) => get_applepay_info(item, &apple_pay_data),
                WalletData::PaypalRedirect(_) => Self::foreign_try_from((
                    AlternativePaymentMethodType::Expresscheckout,
                    None,
                    item,
                )),
                WalletData::AliPayQr(_)
                | WalletData::AliPayRedirect(_)
                | WalletData::AliPayHkRedirect(_)
                | WalletData::AmazonPay(_)
                | WalletData::AmazonPayRedirect(_)
                | WalletData::Paysera(_)
                | WalletData::Skrill(_)
                | WalletData::BluecodeRedirect {}
                | WalletData::MomoRedirect(_)
                | WalletData::KakaoPayRedirect(_)
                | WalletData::GoPayRedirect(_)
                | WalletData::GcashRedirect(_)
                | WalletData::ApplePayRedirect(_)
                | WalletData::ApplePayThirdPartySdk(_)
                | WalletData::DanaRedirect {}
                | WalletData::GooglePayRedirect(_)
                | WalletData::GooglePayThirdPartySdk(_)
                | WalletData::MbWayRedirect(_)
                | WalletData::MobilePayRedirect(_)
                | WalletData::PaypalSdk(_)
                | WalletData::Paze(_)
                | WalletData::SamsungPay(_)
                | WalletData::TwintRedirect {}
                | WalletData::VippsRedirect {}
                | WalletData::TouchNGoRedirect(_)
                | WalletData::WeChatPayRedirect(_)
                | WalletData::CashappQr(_)
                | WalletData::SwishQr(_)
                | WalletData::WeChatPayQr(_)
                | WalletData::RevolutPay(_)
                | WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented(
                    utils::get_unimplemented_payment_method_error_message("nuvei"),
                )
                .into()),
            },
            PaymentMethodData::BankRedirect(redirect) => match redirect {
                BankRedirectData::Eps { .. } => Self::foreign_try_from((
                    AlternativePaymentMethodType::Eps,
                    Some(redirect),
                    item,
                )),
                BankRedirectData::Giropay { .. } => Self::foreign_try_from((
                    AlternativePaymentMethodType::Giropay,
                    Some(redirect),
                    item,
                )),
                BankRedirectData::Ideal { .. } => Self::foreign_try_from((
                    AlternativePaymentMethodType::Ideal,
                    Some(redirect),
                    item,
                )),
                BankRedirectData::Sofort { .. } => Self::foreign_try_from((
                    AlternativePaymentMethodType::Sofort,
                    Some(redirect),
                    item,
                )),
                BankRedirectData::BancontactCard { .. }
                | BankRedirectData::Bizum {}
                | BankRedirectData::Blik { .. }
                | BankRedirectData::Eft { .. }
                | BankRedirectData::Interac { .. }
                | BankRedirectData::OnlineBankingCzechRepublic { .. }
                | BankRedirectData::OnlineBankingFinland { .. }
                | BankRedirectData::OnlineBankingPoland { .. }
                | BankRedirectData::OnlineBankingSlovakia { .. }
                | BankRedirectData::Przelewy24 { .. }
                | BankRedirectData::Trustly { .. }
                | BankRedirectData::OnlineBankingFpx { .. }
                | BankRedirectData::OnlineBankingThailand { .. }
                | BankRedirectData::OpenBankingUk { .. }
                | BankRedirectData::LocalBankRedirect {} => {
                    Err(errors::ConnectorError::NotImplemented(
                        utils::get_unimplemented_payment_method_error_message("nuvei"),
                    )
                    .into())
                }
            },
            PaymentMethodData::PayLater(pay_later_data) => match pay_later_data {
                PayLaterData::KlarnaRedirect { .. } => {
                    get_pay_later_info(AlternativePaymentMethodType::Klarna, item)
                }
                PayLaterData::AfterpayClearpayRedirect { .. } => {
                    get_pay_later_info(AlternativePaymentMethodType::AfterPay, item)
                }
                PayLaterData::KlarnaSdk { .. }
                | PayLaterData::FlexitiRedirect {}
                | PayLaterData::AffirmRedirect {}
                | PayLaterData::PayBrightRedirect {}
                | PayLaterData::WalleyRedirect {}
                | PayLaterData::AlmaRedirect {}
                | PayLaterData::AtomeRedirect {}
                | PayLaterData::BreadpayRedirect {} => Err(errors::ConnectorError::NotImplemented(
                    utils::get_unimplemented_payment_method_error_message("nuvei"),
                )
                .into()),
            },
            PaymentMethodData::BankDebit(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::Crypto(_)
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(_)
            | PaymentMethodData::MobilePayment(_)
            | PaymentMethodData::Upi(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::NetworkToken(_) => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("nuvei"),
            )
            .into()),
        }?;
        let currency = item.request.get_currency_required()?;
        let request = Self::try_from(NuveiPaymentRequestData {
            amount: convert_amount(
                NUVEI_AMOUNT_CONVERTOR,
                item.request.get_minor_amount_required()?,
                currency,
            )?,
            currency,
            connector_auth_type: item.connector_auth_type.clone(),
            client_request_id: item.connector_request_reference_id.clone(),
            session_token: Secret::new(data.1),
            capture_method: item.request.get_capture_method(),

            ..Default::default()
        })?;
        let return_url = item.request.get_return_url_required()?;

        let amount_details = match item.request.get_order_tax_amount()? {
            Some(tax) => Some(NuvieAmountDetails {
                total_tax: Some(convert_amount(NUVEI_AMOUNT_CONVERTOR, tax, currency)?),
            }),
            None => None,
        };
        let address = {
            if let Some(billing_address) = item.get_optional_billing() {
                let mut billing_address = billing_address.clone();
                item.get_billing_first_name()?;
                billing_address.email = match item.get_billing_email() {
                    Ok(email) => Some(email),
                    Err(_) => Some(item.request.get_email_required()?),
                };
                item.get_billing_country()?;

                Some(billing_address)
            } else {
                None
            }
        };

        let shipping_address: Option<ShippingAddress> =
            item.get_optional_shipping().map(|address| address.into());

        let billing_address: Option<BillingAddress> = address.map(|ref address| address.into());

        let device_details = if request_data
            .device_details
            .ip_address
            .clone()
            .expose()
            .is_empty()
        {
            DeviceDetails::foreign_try_from(&item.request.get_browser_info())?
        } else {
            request_data.device_details.clone()
        };

        Ok(Self {
            is_rebilling: request_data.is_rebilling,
            user_token_id: item.customer_id.clone(),
            related_transaction_id: request_data.related_transaction_id,
            payment_option: request_data.payment_option,
            billing_address,
            shipping_address,
            device_details,
            url_details: Some(UrlDetails {
                success_url: return_url.clone(),
                failure_url: return_url.clone(),
                pending_url: return_url.clone(),
            }),
            amount_details,
            is_partial_approval: item.request.get_is_partial_approval(),
            ..request
        })
    }
}

fn get_card_info<F, Req>(
    item: &RouterData<F, Req, PaymentsResponseData>,
    card_details: &payment_method_data::Card,
) -> Result<NuveiPaymentsRequest, error_stack::Report<errors::ConnectorError>>
where
    Req: NuveiAuthorizePreprocessingCommon,
{
    let browser_information = item.request.get_browser_info().clone();
    let related_transaction_id = if item.is_three_ds() {
        item.request.get_related_transaction_id().clone()
    } else {
        None
    };

    let address = item
        .get_optional_billing()
        .and_then(|billing_details| billing_details.address.as_ref());

    if let Some(address) = address {
        // mandatory fields check
        address.get_first_name()?;
        item.request.get_email_required()?;
        item.get_billing_country()?;
    }

    let (is_rebilling, additional_params, user_token_id) =
        match item.request.is_customer_initiated_mandate_payment() {
            true => {
                (
                    Some("0".to_string()), // In case of first installment, rebilling should be 0
                    Some(V2AdditionalParams {
                        rebill_expiry: Some(
                            time::OffsetDateTime::now_utc()
                                .replace_year(time::OffsetDateTime::now_utc().year() + 5)
                                .map_err(|_| errors::ConnectorError::DateFormattingFailed)?
                                .date()
                                .format(&time::macros::format_description!("[year][month][day]"))
                                .map_err(|_| errors::ConnectorError::DateFormattingFailed)?,
                        ),
                        rebill_frequency: Some("0".to_string()),
                        challenge_window_size: Some(CHALLENGE_WINDOW_SIZE.to_string()),
                        challenge_preference: Some(CHALLENGE_PREFERENCE.to_string()),
                    }),
                    item.request.get_customer_id_required(),
                )
            }
            // non mandate transactions
            false => (
                None,
                Some(V2AdditionalParams {
                    rebill_expiry: None,
                    rebill_frequency: None,
                    challenge_window_size: Some(CHALLENGE_WINDOW_SIZE.to_string()),
                    challenge_preference: Some(CHALLENGE_PREFERENCE.to_string()),
                }),
                None,
            ),
        };
    let three_d = if item.is_three_ds() {
        let browser_details = match &browser_information {
            Some(browser_info) => Some(BrowserDetails {
                accept_header: browser_info.get_accept_header()?,
                ip: browser_info.get_ip_address()?,
                java_enabled: browser_info.get_java_enabled()?.to_string().to_uppercase(),
                java_script_enabled: browser_info
                    .get_java_script_enabled()?
                    .to_string()
                    .to_uppercase(),
                language: browser_info.get_language()?,
                screen_height: browser_info.get_screen_height()?,
                screen_width: browser_info.get_screen_width()?,
                color_depth: browser_info.get_color_depth()?,
                user_agent: browser_info.get_user_agent()?,
                time_zone: browser_info.get_time_zone()?,
            }),
            None => None,
        };
        Some(ThreeD {
            browser_details,
            v2_additional_params: additional_params,
            notification_url: item.request.get_complete_authorize_url().clone(),
            merchant_url: Some(item.request.get_return_url_required()?),
            platform_type: Some(PlatformType::Browser),
            method_completion_ind: Some(MethodCompletion::Unavailable),
            ..Default::default()
        })
    } else {
        None
    };
    let is_moto = item.request.get_is_moto();
    Ok(NuveiPaymentsRequest {
        related_transaction_id,
        is_rebilling,
        user_token_id,
        device_details: DeviceDetails::foreign_try_from(&item.request.get_browser_info().clone())?,
        payment_option: PaymentOption::from(NuveiCardDetails {
            card: card_details.clone(),
            three_d,
            card_holder_name: item.get_optional_billing_full_name(),
        }),
        is_moto,
        ..Default::default()
    })
}
impl From<NuveiCardDetails> for PaymentOption {
    fn from(card_details: NuveiCardDetails) -> Self {
        let card = card_details.card;
        Self {
            card: Some(Card {
                card_number: Some(card.card_number),
                card_holder_name: card_details.card_holder_name,
                expiration_month: Some(card.card_exp_month),
                expiration_year: Some(card.card_exp_year),
                three_d: card_details.three_d,
                cvv: Some(card.card_cvc),
                ..Default::default()
            }),
            ..Default::default()
        }
    }
}

impl TryFrom<(&types::PaymentsCompleteAuthorizeRouterData, Secret<String>)>
    for NuveiPaymentsRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        data: (&types::PaymentsCompleteAuthorizeRouterData, Secret<String>),
    ) -> Result<Self, Self::Error> {
        let item = data.0;
        let request_data = match item.request.payment_method_data.clone() {
            Some(PaymentMethodData::Card(card)) => {
                let device_details = DeviceDetails::foreign_try_from(&item.request.browser_info)?;
                Ok(Self {
                    payment_option: PaymentOption::from(NuveiCardDetails {
                        card,
                        three_d: None,
                        card_holder_name: item.get_optional_billing_full_name(),
                    }),
                    device_details,
                    ..Default::default()
                })
            }
            Some(PaymentMethodData::Wallet(..))
            | Some(PaymentMethodData::PayLater(..))
            | Some(PaymentMethodData::BankDebit(..))
            | Some(PaymentMethodData::BankRedirect(..))
            | Some(PaymentMethodData::BankTransfer(..))
            | Some(PaymentMethodData::Crypto(..))
            | Some(PaymentMethodData::MandatePayment)
            | Some(PaymentMethodData::GiftCard(..))
            | Some(PaymentMethodData::Voucher(..))
            | Some(PaymentMethodData::CardRedirect(..))
            | Some(PaymentMethodData::Reward)
            | Some(PaymentMethodData::RealTimePayment(..))
            | Some(PaymentMethodData::MobilePayment(..))
            | Some(PaymentMethodData::Upi(..))
            | Some(PaymentMethodData::OpenBanking(_))
            | Some(PaymentMethodData::CardToken(..))
            | Some(PaymentMethodData::NetworkToken(..))
            | Some(PaymentMethodData::CardDetailsForNetworkTransactionId(_))
            | None => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("nuvei"),
            )),
        }?;
        let request = Self::try_from(NuveiPaymentRequestData {
            amount: convert_amount(
                NUVEI_AMOUNT_CONVERTOR,
                item.request.minor_amount,
                item.request.currency,
            )?,
            currency: item.request.currency,
            connector_auth_type: item.connector_auth_type.clone(),
            client_request_id: item.connector_request_reference_id.clone(),
            session_token: data.1,
            capture_method: item.request.capture_method,
            ..Default::default()
        })?;
        Ok(Self {
            related_transaction_id: request_data.related_transaction_id,
            payment_option: request_data.payment_option,
            device_details: request_data.device_details,
            ..request
        })
    }
}

impl TryFrom<NuveiPaymentRequestData> for NuveiPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(request: NuveiPaymentRequestData) -> Result<Self, Self::Error> {
        let session_token = request.session_token;
        fp_utils::when(session_token.clone().expose().is_empty(), || {
            Err(errors::ConnectorError::FailedToObtainAuthType)
        })?;
        let connector_meta: NuveiAuthType = NuveiAuthType::try_from(&request.connector_auth_type)?;
        let merchant_id = connector_meta.merchant_id;
        let merchant_site_id = connector_meta.merchant_site_id;
        let client_request_id = request.client_request_id;
        let time_stamp =
            date_time::format_date(date_time::now(), date_time::DateFormat::YYYYMMDDHHmmss)
                .change_context(errors::ConnectorError::RequestEncodingFailed)?;
        let merchant_secret = connector_meta.merchant_secret;
        let transaction_type = TransactionType::get_from_capture_method_and_amount_string(
            request.capture_method.unwrap_or_default(),
            &request.amount.get_amount_as_string(),
        );
        Ok(Self {
            merchant_id: merchant_id.clone(),
            merchant_site_id: merchant_site_id.clone(),
            client_request_id: Secret::new(client_request_id.clone()),
            time_stamp: time_stamp.clone(),
            session_token,
            transaction_type,
            checksum: Secret::new(encode_payload(&[
                merchant_id.peek(),
                merchant_site_id.peek(),
                &client_request_id,
                &request.amount.get_amount_as_string(),
                &request.currency.to_string(),
                &time_stamp,
                merchant_secret.peek(),
            ])?),
            amount: request.amount,
            user_token_id: None,
            currency: request.currency,
            ..Default::default()
        })
    }
}

impl TryFrom<NuveiPaymentRequestData> for NuveiPaymentFlowRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(request: NuveiPaymentRequestData) -> Result<Self, Self::Error> {
        let connector_meta: NuveiAuthType = NuveiAuthType::try_from(&request.connector_auth_type)?;
        let merchant_id = connector_meta.merchant_id;
        let merchant_site_id = connector_meta.merchant_site_id;
        let client_request_id = request.client_request_id;
        let time_stamp =
            date_time::format_date(date_time::now(), date_time::DateFormat::YYYYMMDDHHmmss)
                .change_context(errors::ConnectorError::RequestEncodingFailed)?;
        let merchant_secret = connector_meta.merchant_secret;
        Ok(Self {
            merchant_id: merchant_id.to_owned(),
            merchant_site_id: merchant_site_id.to_owned(),
            client_request_id: client_request_id.clone(),
            time_stamp: time_stamp.clone(),
            checksum: Secret::new(encode_payload(&[
                merchant_id.peek(),
                merchant_site_id.peek(),
                &client_request_id,
                &request.amount.get_amount_as_string(),
                &request.currency.to_string(),
                &request.related_transaction_id.clone().unwrap_or_default(),
                &time_stamp,
                merchant_secret.peek(),
            ])?),
            amount: request.amount,
            currency: request.currency,
            related_transaction_id: request.related_transaction_id,
        })
    }
}

#[derive(Debug, Clone, Default)]
pub struct NuveiPaymentRequestData {
    pub amount: StringMajorUnit,
    pub currency: enums::Currency,
    pub related_transaction_id: Option<String>,
    pub client_request_id: String,
    pub connector_auth_type: ConnectorAuthType,
    pub session_token: Secret<String>,
    pub capture_method: Option<CaptureMethod>,
}

impl TryFrom<&types::PaymentsCaptureRouterData> for NuveiPaymentFlowRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> {
        Self::try_from(NuveiPaymentRequestData {
            client_request_id: item.connector_request_reference_id.clone(),
            connector_auth_type: item.connector_auth_type.clone(),
            amount: convert_amount(
                NUVEI_AMOUNT_CONVERTOR,
                item.request.minor_amount_to_capture,
                item.request.currency,
            )?,
            currency: item.request.currency,
            related_transaction_id: Some(item.request.connector_transaction_id.clone()),
            ..Default::default()
        })
    }
}
impl TryFrom<&types::RefundExecuteRouterData> for NuveiPaymentFlowRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &types::RefundExecuteRouterData) -> Result<Self, Self::Error> {
        Self::try_from(NuveiPaymentRequestData {
            client_request_id: item.connector_request_reference_id.clone(),
            connector_auth_type: item.connector_auth_type.clone(),
            amount: convert_amount(
                NUVEI_AMOUNT_CONVERTOR,
                item.request.minor_refund_amount,
                item.request.currency,
            )?,
            currency: item.request.currency,
            related_transaction_id: Some(item.request.connector_transaction_id.clone()),
            ..Default::default()
        })
    }
}

impl TryFrom<&types::PaymentsSyncRouterData> for NuveiPaymentSyncRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(value: &types::PaymentsSyncRouterData) -> Result<Self, Self::Error> {
        let meta: NuveiMeta = utils::to_connector_meta(value.request.connector_meta.clone())?;
        Ok(Self {
            session_token: meta.session_token,
        })
    }
}

#[derive(Debug, Serialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct NuveiVoidRequest {
    pub merchant_id: Secret<String>,
    pub merchant_site_id: Secret<String>,
    pub client_unique_id: String,
    pub related_transaction_id: String,
    pub time_stamp: String,
    pub checksum: Secret<String>,
    pub client_request_id: String,
}

impl TryFrom<&types::PaymentsCancelPostCaptureRouterData> for NuveiVoidRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &types::PaymentsCancelPostCaptureRouterData) -> Result<Self, Self::Error> {
        let connector_meta: NuveiAuthType = NuveiAuthType::try_from(&item.connector_auth_type)?;
        let merchant_id = connector_meta.merchant_id.clone();
        let merchant_site_id = connector_meta.merchant_site_id.clone();


pub struct NuveiInitPaymentRequest {
    pub session_token: Secret<String>,
    pub merchant_id: Secret<String>,
    pub merchant_site_id: Secret<String>,
    pub client_request_id: String,
    pub amount: StringMajorUnit,
    pub currency: String,
    pub payment_option: PaymentOption,
    pub checksum: Secret<String>,
}


pub fn get_default_customer_billing_address(&self) -> Option<payments::AddressDetails> {
        self.default_billing_address.clone()
    }


pub struct RequestPaymentMethodTypes {
    /// The payment method subtype
    #[schema(value_type = PaymentMethodType)]
    pub payment_method_subtype: common_enums::PaymentMethodType,

    /// The payment experience for the payment method
    #[schema(value_type = Option<PaymentExperience>)]
    pub payment_experience: Option<common_enums::PaymentExperience>,

    /// List of cards networks that are enabled for this payment method, applicable for credit and debit payment method subtypes only
    #[schema(value_type = Option<Vec<CardNetwork>>)]
    pub card_networks: Option<Vec<common_enums::CardNetwork>>,
    /// List of currencies accepted or has the processing capabilities of the processor
    #[schema(example = json!(
        {
            "type": "enable_only",
            "list": ["USD", "INR"]
        }
    ), value_type = Option<AcceptedCurrencies>)]
    pub accepted_currencies: Option<AcceptedCurrencies>,

    ///  List of Countries accepted or has the processing capabilities of the processor
    #[schema(example = json!(
        {
            "type": "enable_only",
            "list": ["UK", "AU"]
        }
    ), value_type = Option<AcceptedCountries>)]
    pub accepted_countries: Option<AcceptedCountries>,

    /// Minimum amount supported by the processor. To be represented in the lowest denomination of the target currency (For example, for USD it should be in cents)
    #[schema(example = 1)]
    pub minimum_amount: Option<common_utils::types::MinorUnit>,

    /// Maximum amount supported by the processor. To be represented in the lowest denomination of
    /// the target currency (For example, for USD it should be in cents)
    #[schema(example = 1313)]
    pub maximum_amount: Option<common_utils::types::MinorUnit>,

    /// Indicates whether the payment method supports recurring payments. Optional.
    #[schema(example = true)]
    pub recurring_enabled: Option<bool>,

    /// Indicates whether the payment method is eligible for installment payments (e.g., EMI, BNPL). Optional.
    #[schema(example = true)]
    pub installment_payment_enabled: Option<bool>,
}


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

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

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

impl ConnectorSpecifications for for Bambora


pub trait PaymentIntentMetricAccumulator {
    type MetricOutput;

    fn add_metrics_bucket(&mut self, metrics: &PaymentIntentMetricRow);

    fn collect(self) -> Self::MetricOutput;
}


pub trait RemoveNewLine {
    fn remove_new_line(&self) -> Self;
}


pub struct VersionResponseData {
    #[serde(rename = "@ds_version")]
    ds_version: String,
    message: MessageResponseType,
}


impl api::PaymentVoid for Gpayments {}


pub struct SubmitEvidenceResponse {
    pub dispute_status: api_models::enums::DisputeStatus,
    pub connector_status: Option<String>,
}


pub struct SantanderBoletoPaymentsResponse {
    pub environment: Environment,
    pub nsu_code: String,
    pub nsu_date: String,
    pub covenant_code: String,
    pub bank_number: String,
    pub client_number: Option<id_type::CustomerId>,
    pub due_date: String,
    pub issue_date: String,
    pub participant_code: Option<String>,
    pub nominal_value: StringMajorUnit,
    pub payer: Payer,
    pub beneficiary: Option<Beneficiary>,
    pub document_kind: BoletoDocumentKind,
    pub discount: Option<Discount>,
    pub fine_percentage: Option<String>,
    pub fine_quantity_days: Option<String>,
    pub interest_percentage: Option<String>,
    pub deduction_value: Option<FloatMajorUnit>,
    pub protest_type: Option<ProtestType>,
    pub protest_quantity_days: Option<i64>,
    pub write_off_quantity_days: Option<String>,
    pub payment_type: PaymentType,
    pub parcels_quantity: Option<i64>,
    pub value_type: Option<String>,
    pub min_value_or_percentage: Option<f64>,
    pub max_value_or_percentage: Option<f64>,
    pub iof_percentage: Option<f64>,
    pub sharing: Option<Sharing>,
    pub key: Option<Key>,
    pub tx_id: Option<String>,
    pub messages: Option<Vec<String>>,
    pub barcode: Option<String>,
    pub digitable_line: Option<Secret<String>>,
    pub entry_date: Option<String>,
    pub qr_code_pix: Option<String>,
    pub qr_code_url: Option<String>,
}


File: crates/router/src/routes/ephemeral_key.rs
 Public functions: 4

use actix_web::{web, HttpRequest, HttpResponse};
use router_env::{instrument, tracing, Flow};

use super::AppState;
#[cfg(feature = "v2")]
use crate::types::domain;
use crate::{
    core::{api_locking, payments::helpers},
    services::{api, authentication as auth},
};

#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::EphemeralKeyCreate))]
pub async fn ephemeral_key_create(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<api_models::ephemeral_key::EphemeralKeyCreateRequest>,
) -> HttpResponse {
    let flow = Flow::EphemeralKeyCreate;
    let payload = json_payload.into_inner();
    api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, payload, _| {
            helpers::make_ephemeral_key(
                state,
                payload.customer_id,
                auth.merchant_account.get_id().to_owned(),
            )
        },
        &auth::HeaderAuth(auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        }),
        api_locking::LockAction::NotApplicable,
    )
    .await
}

#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::EphemeralKeyDelete))]
pub async fn ephemeral_key_delete(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
) -> HttpResponse {
    let flow = Flow::EphemeralKeyDelete;
    let payload = path.into_inner();
    api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _: auth::AuthenticationData, req, _| helpers::delete_ephemeral_key(state, req),
        &auth::HeaderAuth(auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        }),
        api_locking::LockAction::NotApplicable,
    )
    .await
}

#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::EphemeralKeyCreate))]
pub async fn client_secret_create(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<api_models::ephemeral_key::ClientSecretCreateRequest>,
) -> HttpResponse {
    let flow = Flow::EphemeralKeyCreate;
    let payload = json_payload.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, payload, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            helpers::make_client_secret(
                state,
                payload.resource_id.to_owned(),
                merchant_context,
                req.headers(),
            )
        },
        &auth::V2ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::EphemeralKeyDelete))]
pub async fn client_secret_delete(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
) -> HttpResponse {
    let flow = Flow::EphemeralKeyDelete;
    let payload = path.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _: auth::AuthenticationData, req, _| helpers::delete_client_secret(state, req),
        &auth::V2ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub fn collect(self) -> FrmMetricsBucketValue {
        FrmMetricsBucketValue {
            frm_blocked_rate: self.frm_blocked_rate.collect(),
            frm_triggered_attempts: self.frm_triggered_attempts.collect(),
        }
    }


pub fn new(base_currency: Currency, conversion: HashMap<Currency, CurrencyFactors>) -> Self {
        Self {
            base_currency,
            conversion,
        }
    }


pub struct ArchipelWalletAuthorizationRequest {
    order: ArchipelOrderRequest,
    card: ArchipelTokenizedCard,
    cardholder: Option<ArchipelCardHolder>,
    wallet: ArchipelWalletInformation,
    #[serde(rename = "3DS")]
    three_ds: Option<Archipel3DS>,
    credential_indicator: Option<ArchipelCredentialIndicator>,
    stored_on_file: bool,
    tenant_id: ArchipelTenantId,
}


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


pub struct IssuerInformation {
    country: Option<enums::CountryAlpha2>,
    discretionary_data: Option<String>,
    country_specific_discretionary_data: Option<String>,
    response_code: Option<String>,
    pin_request_indicator: Option<String>,
}


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

impl common_utils::events::ApiEventMetric for for TotalPaymentMethodCountResponse


impl api::ConnectorAccessToken for Payload {}

impl api::ConnectorAccessToken for for Payload


pub async fn get_card_details_from_locker(
    state: &routes::SessionState,
    pm: &domain::PaymentMethod,
) -> errors::RouterResult<api::CardDetailFromLocker> {
    let card = get_card_from_locker(
        state,
        &pm.customer_id,
        &pm.merchant_id,
        pm.locker_id.as_ref().unwrap_or(pm.get_id()),
    )
    .await
    .change_context(errors::ApiErrorResponse::InternalServerError)
    .attach_printable("Error getting card from card vault")?;

    payment_methods::get_card_detail(pm, card)
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Get Card Details Failed")
}


pub struct SESConfig {
    /// The arn of email role
    pub email_role_arn: String,

    /// The name of sts_session role
    pub sts_role_session_name: String,
}


OpenAPI Block Path: components.schemas.GsmUpdateRequest
{
  "type": "object",
  "required": [
    "connector",
    "flow",
    "sub_flow",
    "code",
    "message"
  ],
  "properties": {
    "connector": {
      "type": "string",
      "description": "The connector through which payment has gone through"
    },
    "flow": {
      "type": "string",
      "description": "The flow in which the code and message occurred for a connector"
    },
    "sub_flow": {
      "type": "string",
      "description": "The sub_flow in which the code and message occurred  for a connector"
    },
    "code": {
      "type": "string",
      "description": "code received from the connector"
    },
    "message": {
      "type": "string",
      "description": "message received from the connector"
    },
    "status": {
      "type": "string",
      "description": "status provided by the router",
      "nullable": true
    },
    "router_error": {
      "type": "string",
      "description": "optional error provided by the router",
      "nullable": true
    },
    "decision": {
      "allOf": [
        {
          "$ref": "#/components/schemas/GsmDecision"
        }
      ],
      "nullable": true
    },
    "step_up_possible": {
      "type": "boolean",
      "description": "indicates if step_up retry is possible\n**Deprecated**: This field is now included as part of `feature_data` under the `Retry` variant.",
      "deprecated": true,
      "nullable": true
    },
    "unified_code": {
      "type": "string",
      "description": "error code unified across the connectors",
      "nullable": true
    },
    "unified_message": {
      "type": "string",
      "description": "error message unified across the connectors",
      "nullable": true
    },
    "error_category": {
      "allOf": [
        {
          "$ref": "#/components/schemas/ErrorCategory"
        }
      ],
      "nullable": true
    },
    "clear_pan_possible": {
      "type": "boolean",
      "description": "indicates if retry with pan is possible\n**Deprecated**: This field is now included as part of `feature_data` under the `Retry` variant.",
      "deprecated": true,
      "nullable": true
    },
    "feature": {
      "allOf": [
        {
          "$ref": "#/components/schemas/GsmFeature"
        }
      ],
      "nullable": true
    },
    "feature_data": {
      "allOf": [
        {
          "$ref": "#/components/schemas/GsmFeatureData"
        }
      ],
      "nullable": true
    }
  }
}


impl ConnectorValidation for Square {}


pub fn to_redis_field_value_pairs(
        &self,
    ) -> CustomResult<Vec<(&str, String)>, errors::ProcessTrackerError> {
        Ok(vec![
            ("id", self.id.to_string()),
            ("group_name", self.group_name.to_string()),
            ("stream_name", self.stream_name.to_string()),
            ("connection_name", self.connection_name.to_string()),
            (
                "created_time",
                self.created_time.assume_utc().unix_timestamp().to_string(),
            ),
            ("rule", self.rule.to_string()),
            (
                "trackers",
                serde_json::to_string(&self.trackers)
                    .change_context(errors::ProcessTrackerError::SerializationFailed)
                    .attach_printable_lazy(|| {
                        format!("Unable to stringify trackers: {:?}", self.trackers)
                    })?,
            ),
        ])
    }


pub struct EventNew {
    pub event_id: String,
    pub event_type: storage_enums::EventType,
    pub event_class: storage_enums::EventClass,
    pub is_webhook_notified: bool,
    pub primary_object_id: String,
    pub primary_object_type: storage_enums::EventObjectType,
    pub created_at: PrimitiveDateTime,
    pub merchant_id: Option<common_utils::id_type::MerchantId>,
    pub business_profile_id: Option<common_utils::id_type::ProfileId>,
    pub primary_object_created_at: Option<PrimitiveDateTime>,
    pub idempotent_event_id: Option<String>,
    pub initial_attempt_id: Option<String>,
    pub request: Option<Encryption>,
    pub response: Option<Encryption>,
    pub delivery_attempt: Option<storage_enums::WebhookDeliveryAttempt>,
    pub metadata: Option<EventMetadata>,
    pub is_overall_delivery_successful: Option<bool>,
}


pub struct ChargebackRetrievalResponse {
    #[serde(rename = "@xmlns")]
    pub xmlns: String,
    pub transaction_id: String,
    pub chargeback_case: Option<Vec<ChargebackCase>>,
}


pub struct PayoutLinkStatusDetails {
    pub payout_link_id: String,
    pub payout_id: id_type::PayoutId,
    pub customer_id: id_type::CustomerId,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub session_expiry: PrimitiveDateTime,
    pub return_url: Option<url::Url>,
    pub status: api_enums::PayoutStatus,
    pub error_code: Option<UnifiedCode>,
    pub error_message: Option<UnifiedMessage>,
    #[serde(flatten)]
    pub ui_config: link_utils::GenericLinkUiConfigFormData,
    pub test_mode: bool,
}


pub struct NoonWebhookSignature {
    pub signature: String,
}


impl<F: Clone> PaymentConfirmData<F> {
    pub fn get_connector_customer_id(
        &self,
        customer: Option<&customer::Customer>,
        merchant_connector_account: &MerchantConnectorAccountTypeDetails,
    ) -> Option<String> {
        match merchant_connector_account {
            MerchantConnectorAccountTypeDetails::MerchantConnectorAccount(_) => customer
                .and_then(|customer| customer.get_connector_customer_id(merchant_connector_account))
                .map(|id| id.to_string())
                .or_else(|| {
                    self.payment_intent
                        .get_connector_customer_id_from_feature_metadata()
                }),
            MerchantConnectorAccountTypeDetails::MerchantConnectorDetails(_) => None,
        }
    }

    pub fn update_payment_method_data(
        &mut self,
        payment_method_data: payment_method_data::PaymentMethodData,
    ) {
        self.payment_method_data = Some(payment_method_data);
    }

    pub fn update_payment_method_and_pm_id(
        &mut self,
        payment_method_id: id_type::GlobalPaymentMethodId,
        payment_method: payment_methods::PaymentMethod,
    ) {
        self.payment_attempt.payment_method_id = Some(payment_method_id);
        self.payment_method = Some(payment_method);
    }
}


File: crates/analytics/src/payments/metrics/sessionized_metrics/failure_reasons.rs

use std::collections::HashSet;

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

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

#[derive(Default)]
pub(crate) struct FailureReasons;

#[async_trait::async_trait]
impl<T> super::PaymentMetric<T> for FailureReasons
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 inner_query_builder: QueryBuilder<T> =
            QueryBuilder::new(AnalyticsCollection::PaymentSessionized);
        inner_query_builder
            .add_select_column("sum(sign_flag)")
            .switch()?;

        inner_query_builder
            .add_custom_filter_clause(
                PaymentDimensions::ErrorReason,
                "NULL",
                FilterTypes::IsNotNull,
            )
            .switch()?;

        time_range
            .set_filter_clause(&mut inner_query_builder)
            .attach_printable("Error filtering time range for inner query")
            .switch()?;

        let inner_query_string = inner_query_builder
            .build_query()
            .attach_printable("Error building inner query")
            .change_context(MetricsError::QueryBuildingError)?;

        let mut outer_query_builder: QueryBuilder<T> =
            QueryBuilder::new(AnalyticsCollection::PaymentSessionized);

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

        outer_query_builder
            .add_select_column("sum(sign_flag) AS count")
            .switch()?;

        outer_query_builder
            .add_select_column(format!("({inner_query_string}) AS total"))
            .switch()?;

        outer_query_builder
            .add_select_column("first_attempt")
            .switch()?;

        outer_query_builder
            .add_select_column(Aggregate::Min {
                field: "created_at",
                alias: Some("start_bucket"),
            })
            .switch()?;

        outer_query_builder
            .add_select_column(Aggregate::Max {
                field: "created_at",
                alias: Some("end_bucket"),
            })
            .switch()?;

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

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

        time_range
            .set_filter_clause(&mut outer_query_builder)
            .attach_printable("Error filtering time range for outer query")
            .switch()?;

        outer_query_builder
            .add_filter_clause(
                PaymentDimensions::PaymentStatus,
                storage_enums::AttemptStatus::Failure,
            )
            .switch()?;

        outer_query_builder
            .add_custom_filter_clause(
                PaymentDimensions::ErrorReason,
                "NULL",
                FilterTypes::IsNotNull,
            )
            .switch()?;

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

        outer_query_builder
            .add_group_by_clause("first_attempt")
            .attach_printable("Error grouping by first_attempt")
            .switch()?;

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

        outer_query_builder
            .add_order_by_clause("count", Order::Descending)
            .attach_printable("Error adding order by clause")
            .switch()?;

        let filtered_dimensions: Vec<&PaymentDimensions> = dimensions
            .iter()
            .filter(|&&dim| dim != PaymentDimensions::ErrorReason)
            .collect();

        for dim in &filtered_dimensions {
            outer_query_builder
                .add_order_by_clause(*dim, Order::Ascending)
                .attach_printable("Error adding order by clause")
                .switch()?;
        }

        outer_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),
                        None,
                        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<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
                crate::query::PostProcessingError,
            >>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


OpenAPI Block Path: components.schemas.AcceptedCurrencies
{
  "oneOf": [
    {
      "type": "object",
      "required": [
        "type",
        "list"
      ],
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "enable_only"
          ]
        },
        "list": {
          "type": "array",
          "items": {
            "$ref": "#/components/schemas/Currency"
          }
        }
      }
    },
    {
      "type": "object",
      "required": [
        "type",
        "list"
      ],
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "disable_only"
          ]
        },
        "list": {
          "type": "array",
          "items": {
            "$ref": "#/components/schemas/Currency"
          }
        }
      }
    },
    {
      "type": "object",
      "required": [
        "type"
      ],
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "all_accepted"
          ]
        }
      }
    }
  ],
  "discriminator": {
    "propertyName": "type"
  }
}


pub struct GooglePayPaymentProcessingDetails {
    pub google_pay_private_key: Secret<String>,
    pub google_pay_root_signing_keys: Secret<String>,
    pub google_pay_recipient_id: Secret<String>,
}


OpenAPI Block Path: paths."/routing/default"
{
  "post": {
    "tags": [
      "Routing"
    ],
    "summary": "Routing - Update Default Config",
    "description": "Update default fallback config",
    "operationId": "Update default fallback config",
    "requestBody": {
      "content": {
        "application/json": {
          "schema": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RoutableConnectorChoice"
            }
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "description": "Successfully updated default config",
        "content": {
          "application/json": {
            "schema": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/RoutableConnectorChoice"
              }
            }
          }
        }
      },
      "400": {
        "description": "Malformed request"
      },
      "422": {
        "description": "Unprocessable request"
      },
      "500": {
        "description": "Internal server error"
      }
    },
    "security": [
      {
        "api_key": []
      },
      {
        "jwt_key": []
      }
    ]
  },
  "get": {
    "tags": [
      "Routing"
    ],
    "summary": "Routing - Retrieve Default Config",
    "description": "Retrieve default fallback config",
    "operationId": "Retrieve default fallback config",
    "responses": {
      "200": {
        "description": "Successfully retrieved default config",
        "content": {
          "application/json": {
            "schema": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/RoutableConnectorChoice"
              }
            }
          }
        }
      },
      "500": {
        "description": "Internal server error"
      }
    },
    "security": [
      {
        "api_key": []
      },
      {
        "jwt_key": []
      }
    ]
  }
}