File: crates/euclid_wasm/src/lib.rs
 Public functions: 29

#![allow(non_upper_case_globals)]
mod types;
mod utils;
use std::{
    collections::{HashMap, HashSet},
    str::FromStr,
    sync::OnceLock,
};

use api_models::{
    enums as api_model_enums, routing::ConnectorSelection,
    surcharge_decision_configs::SurchargeDecisionConfigs,
};
use common_enums::RoutableConnectors;
use common_types::three_ds_decision_rule_engine::ThreeDSDecisionRule;
use connector_configs::{
    common_config::{ConnectorApiIntegrationPayload, DashboardRequestPayload},
    connector,
};
use currency_conversion::{
    conversion::convert as convert_currency, types as currency_conversion_types,
};
use euclid::{
    backend::{inputs, interpreter::InterpreterBackend, EuclidBackend},
    dssa::{self, analyzer, graph::CgraphExt, state_machine},
    frontend::{
        ast,
        dir::{self, enums as dir_enums, EuclidDirFilter},
    },
};
use strum::{EnumMessage, EnumProperty, VariantNames};
use wasm_bindgen::prelude::*;

use crate::utils::JsResultExt;
type JsResult = Result<JsValue, JsValue>;
use api_models::payment_methods::CountryCodeWithName;
#[cfg(feature = "payouts")]
use common_enums::PayoutStatus;
use common_enums::{
    CountryAlpha2, DisputeStatus, EventClass, EventType, IntentStatus, MandateStatus,
    MerchantCategoryCode, MerchantCategoryCodeWithName, RefundStatus,
};
use strum::IntoEnumIterator;

struct SeedData {
    cgraph: hyperswitch_constraint_graph::ConstraintGraph<dir::DirValue>,
    connectors: Vec<ast::ConnectorChoice>,
}

static SEED_DATA: OnceLock<SeedData> = OnceLock::new();
static SEED_FOREX: OnceLock<currency_conversion_types::ExchangeRates> = OnceLock::new();

/// This function can be used by the frontend to educate wasm about the forex rates data.
/// The input argument is a struct fields base_currency and conversion where later is all the conversions associated with the base_currency
/// to all different currencies present.
#[wasm_bindgen(js_name = setForexData)]
pub fn seed_forex(forex: JsValue) -> JsResult {
    let forex: currency_conversion_types::ExchangeRates = serde_wasm_bindgen::from_value(forex)?;
    SEED_FOREX
        .set(forex)
        .map_err(|_| "Forex has already been seeded".to_string())
        .err_to_js()?;

    Ok(JsValue::NULL)
}

/// This function can be used to perform currency_conversion on the input amount, from_currency,
/// to_currency which are all expected to be one of currencies we already have in our Currency
/// enum.
#[wasm_bindgen(js_name = convertCurrency)]
pub fn convert_forex_value(amount: i64, from_currency: JsValue, to_currency: JsValue) -> JsResult {
    let forex_data = SEED_FOREX
        .get()
        .ok_or("Forex Data not seeded")
        .err_to_js()?;
    let from_currency: common_enums::Currency = serde_wasm_bindgen::from_value(from_currency)?;
    let to_currency: common_enums::Currency = serde_wasm_bindgen::from_value(to_currency)?;
    let converted_amount = convert_currency(forex_data, from_currency, to_currency, amount)
        .map_err(|_| "conversion not possible for provided values")
        .err_to_js()?;

    Ok(serde_wasm_bindgen::to_value(&converted_amount)?)
}

/// This function can be used by the frontend to get all the two letter country codes
/// along with their country names.
#[wasm_bindgen(js_name=getTwoLetterCountryCode)]
pub fn get_two_letter_country_code() -> JsResult {
    let country_code_with_name = CountryAlpha2::iter()
        .map(|country_code| CountryCodeWithName {
            code: country_code,
            name: common_enums::Country::from_alpha2(country_code),
        })
        .collect::<Vec<_>>();

    Ok(serde_wasm_bindgen::to_value(&country_code_with_name)?)
}

/// This function can be used by the frontend to get all the merchant category codes
/// along with their names.
#[wasm_bindgen(js_name=getMerchantCategoryCodeWithName)]
pub fn get_merchant_category_code_with_name() -> JsResult {
    let merchant_category_codes_with_name = MerchantCategoryCode::iter()
        .map(|mcc_value| MerchantCategoryCodeWithName {
            code: mcc_value,
            name: mcc_value.to_merchant_category_name(),
        })
        .collect::<Vec<_>>();

    Ok(serde_wasm_bindgen::to_value(
        &merchant_category_codes_with_name,
    )?)
}

/// This function can be used by the frontend to provide the WASM with information about
/// all the merchant's connector accounts. The input argument is a vector of all the merchant's
/// connector accounts from the API.
#[cfg(feature = "v1")]
#[wasm_bindgen(js_name = seedKnowledgeGraph)]
pub fn seed_knowledge_graph(mcas: JsValue) -> JsResult {
    let mcas: Vec<api_models::admin::MerchantConnectorResponse> =
        serde_wasm_bindgen::from_value(mcas)?;
    let connectors: Vec<ast::ConnectorChoice> = mcas
        .iter()
        .map(|mca| {
            Ok::<_, strum::ParseError>(ast::ConnectorChoice {
                connector: RoutableConnectors::from_str(&mca.connector_name)?,
            })
        })
        .collect::<Result<_, _>>()
        .map_err(|_| "invalid connector name received")
        .err_to_js()?;
    let pm_filter = kgraph_utils::types::PaymentMethodFilters(HashMap::new());
    let config = kgraph_utils::types::CountryCurrencyFilter {
        connector_configs: HashMap::new(),
        default_configs: Some(pm_filter),
    };
    let mca_graph = kgraph_utils::mca::make_mca_graph(mcas, &config).err_to_js()?;
    let analysis_graph = hyperswitch_constraint_graph::ConstraintGraph::combine(
        &mca_graph,
        &dssa::truth::ANALYSIS_GRAPH,
    )
    .err_to_js()?;

    SEED_DATA
        .set(SeedData {
            cgraph: analysis_graph,
            connectors,
        })
        .map_err(|_| "Knowledge Graph has been already seeded".to_string())
        .err_to_js()?;

    Ok(JsValue::NULL)
}

/// This function allows the frontend to get all the merchant's configured
/// connectors that are valid for a rule based on the conditions specified in
/// the rule
#[wasm_bindgen(js_name = getValidConnectorsForRule)]
pub fn get_valid_connectors_for_rule(rule: JsValue) -> JsResult {
    let seed_data = SEED_DATA.get().ok_or("Data not seeded").err_to_js()?;

    let rule: ast::Rule<ConnectorSelection> = serde_wasm_bindgen::from_value(rule)?;
    let dir_rule = ast::lowering::lower_rule(rule).err_to_js()?;
    let mut valid_connectors: Vec<(ast::ConnectorChoice, dir::DirValue)> = seed_data
        .connectors
        .iter()
        .cloned()
        .map(|choice| (choice.clone(), dir::DirValue::Connector(Box::new(choice))))
        .collect();
    let mut invalid_connectors: HashSet<ast::ConnectorChoice> = HashSet::new();

    let mut ctx_manager = state_machine::RuleContextManager::new(&dir_rule, &[]);

    let dummy_meta = HashMap::new();

    // For every conjunctive context in the Rule, verify validity of all still-valid connectors
    // using the knowledge graph
    while let Some(ctx) = ctx_manager.advance_mut().err_to_js()? {
        // Standalone conjunctive context analysis to ensure the context itself is valid before
        // checking it against merchant's connectors
        seed_data
            .cgraph
            .perform_context_analysis(
                ctx,
                &mut hyperswitch_constraint_graph::Memoization::new(),
                None,
            )
            .err_to_js()?;

        // Update conjunctive context and run analysis on all of merchant's connectors.
        for (conn, choice) in &valid_connectors {
            if invalid_connectors.contains(conn) {
                continue;
            }

            let ctx_val = dssa::types::ContextValue::assertion(choice, &dummy_meta);
            ctx.push(ctx_val);
            let analysis_result = seed_data.cgraph.perform_context_analysis(
                ctx,
                &mut hyperswitch_constraint_graph::Memoization::new(),
                None,
            );
            if analysis_result.is_err() {
                invalid_connectors.insert(conn.clone());
            }
            ctx.pop();
        }
    }

    valid_connectors.retain(|(k, _)| !invalid_connectors.contains(k));

    let valid_connectors: Vec<ast::ConnectorChoice> =
        valid_connectors.into_iter().map(|c| c.0).collect();

    Ok(serde_wasm_bindgen::to_value(&valid_connectors)?)
}

#[wasm_bindgen(js_name = analyzeProgram)]
pub fn analyze_program(js_program: JsValue) -> JsResult {
    let program: ast::Program<ConnectorSelection> = serde_wasm_bindgen::from_value(js_program)?;
    analyzer::analyze(program, SEED_DATA.get().map(|sd| &sd.cgraph)).err_to_js()?;
    Ok(JsValue::NULL)
}

#[wasm_bindgen(js_name = runProgram)]
pub fn run_program(program: JsValue, input: JsValue) -> JsResult {
    let program: ast::Program<ConnectorSelection> = serde_wasm_bindgen::from_value(program)?;
    let input: inputs::BackendInput = serde_wasm_bindgen::from_value(input)?;

    let backend = InterpreterBackend::with_program(program).err_to_js()?;

    let res: euclid::backend::BackendOutput<ConnectorSelection> =
        backend.execute(input).err_to_js()?;

    Ok(serde_wasm_bindgen::to_value(&res)?)
}

#[wasm_bindgen(js_name = getAllConnectors)]
pub fn get_all_connectors() -> JsResult {
    Ok(serde_wasm_bindgen::to_value(RoutableConnectors::VARIANTS)?)
}

#[wasm_bindgen(js_name = getAllKeys)]
pub fn get_all_keys() -> JsResult {
    let excluded_keys = [
        "Connector",
        // 3DS Decision Rule Keys should not be included in the payument routing keys
        "issuer_name",
        "issuer_country",
        "customer_device_platform",
        "customer_device_type",
        "customer_device_display_size",
        "acquirer_country",
        "acquirer_fraud_rate",
    ];

    let keys: Vec<&'static str> = dir::DirKeyKind::VARIANTS
        .iter()
        .copied()
        .filter(|s| !excluded_keys.contains(s))
        .collect();
    Ok(serde_wasm_bindgen::to_value(&keys)?)
}

#[wasm_bindgen(js_name = getKeyType)]
pub fn get_key_type(key: &str) -> Result<String, String> {
    let key = dir::DirKeyKind::from_str(key).map_err(|_| "Invalid key received".to_string())?;
    let key_str = key.get_type().to_string();
    Ok(key_str)
}

#[wasm_bindgen(js_name = getThreeDsKeys)]
pub fn get_three_ds_keys() -> JsResult {
    let keys = <common_types::payments::ConditionalConfigs as EuclidDirFilter>::ALLOWED;
    Ok(serde_wasm_bindgen::to_value(keys)?)
}

#[wasm_bindgen(js_name= getSurchargeKeys)]
pub fn get_surcharge_keys() -> JsResult {
    let keys = <SurchargeDecisionConfigs as EuclidDirFilter>::ALLOWED;
    Ok(serde_wasm_bindgen::to_value(keys)?)
}

#[wasm_bindgen(js_name= getThreeDsDecisionRuleKeys)]
pub fn get_three_ds_decision_rule_keys() -> JsResult {
    let keys = <ThreeDSDecisionRule as EuclidDirFilter>::ALLOWED;
    Ok(serde_wasm_bindgen::to_value(keys)?)
}

#[wasm_bindgen(js_name=parseToString)]
pub fn parser(val: String) -> String {
    ron_parser::my_parse(val)
}

#[wasm_bindgen(js_name = getVariantValues)]
pub fn get_variant_values(key: &str) -> Result<JsValue, JsValue> {
    let key = dir::DirKeyKind::from_str(key).map_err(|_| "Invalid key received".to_string())?;

    let variants: &[&str] = match key {
        dir::DirKeyKind::PaymentMethod => dir_enums::PaymentMethod::VARIANTS,
        dir::DirKeyKind::CardType => dir_enums::CardType::VARIANTS,
        dir::DirKeyKind::CardNetwork => dir_enums::CardNetwork::VARIANTS,
        dir::DirKeyKind::PayLaterType => dir_enums::PayLaterType::VARIANTS,
        dir::DirKeyKind::WalletType => dir_enums::WalletType::VARIANTS,
        dir::DirKeyKind::BankRedirectType => dir_enums::BankRedirectType::VARIANTS,
        dir::DirKeyKind::CryptoType => dir_enums::CryptoType::VARIANTS,
        dir::DirKeyKind::RewardType => dir_enums::RewardType::VARIANTS,
        dir::DirKeyKind::AuthenticationType => dir_enums::AuthenticationType::VARIANTS,
        dir::DirKeyKind::CaptureMethod => dir_enums::CaptureMethod::VARIANTS,
        dir::DirKeyKind::PaymentCurrency => dir_enums::PaymentCurrency::VARIANTS,
        dir::DirKeyKind::BusinessCountry => dir_enums::Country::VARIANTS,
        dir::DirKeyKind::BillingCountry => dir_enums::Country::VARIANTS,
        dir::DirKeyKind::BankTransferType => dir_enums::BankTransferType::VARIANTS,
        dir::DirKeyKind::UpiType => dir_enums::UpiType::VARIANTS,
        dir::DirKeyKind::SetupFutureUsage => dir_enums::SetupFutureUsage::VARIANTS,
        dir::DirKeyKind::PaymentType => dir_enums::PaymentType::VARIANTS,
        dir::DirKeyKind::MandateType => dir_enums::MandateType::VARIANTS,
        dir::DirKeyKind::MandateAcceptanceType => dir_enums::MandateAcceptanceType::VARIANTS,
        dir::DirKeyKind::CardRedirectType => dir_enums::CardRedirectType::VARIANTS,
        dir::DirKeyKind::GiftCardType => dir_enums::GiftCardType::VARIANTS,
        dir::DirKeyKind::VoucherType => dir_enums::VoucherType::VARIANTS,
        dir::DirKeyKind::BankDebitType => dir_enums::BankDebitType::VARIANTS,
        dir::DirKeyKind::RealTimePaymentType => dir_enums::RealTimePaymentType::VARIANTS,
        dir::DirKeyKind::OpenBankingType => dir_enums::OpenBankingType::VARIANTS,
        dir::DirKeyKind::MobilePaymentType => dir_enums::MobilePaymentType::VARIANTS,
        dir::DirKeyKind::IssuerCountry => dir_enums::Country::VARIANTS,
        dir::DirKeyKind::AcquirerCountry => dir_enums::Country::VARIANTS,
        dir::DirKeyKind::CustomerDeviceType => dir_enums::CustomerDeviceType::VARIANTS,
        dir::DirKeyKind::CustomerDevicePlatform => dir_enums::CustomerDevicePlatform::VARIANTS,
        dir::DirKeyKind::CustomerDeviceDisplaySize => {
            dir_enums::CustomerDeviceDisplaySize::VARIANTS
        }

        dir::DirKeyKind::PaymentAmount
        | dir::DirKeyKind::Connector
        | dir::DirKeyKind::CardBin
        | dir::DirKeyKind::BusinessLabel
        | dir::DirKeyKind::MetaData
        | dir::DirKeyKind::IssuerName
        | dir::DirKeyKind::AcquirerFraudRate => Err("Key does not have variants".to_string())?,
    };

    Ok(serde_wasm_bindgen::to_value(variants)?)
}

#[wasm_bindgen(js_name = addTwo)]
pub fn add_two(n1: i64, n2: i64) -> i64 {
    n1 + n2
}

#[wasm_bindgen(js_name = getDescriptionCategory)]
pub fn get_description_category() -> JsResult {
    let keys = dir::DirKeyKind::VARIANTS
        .iter()
        .copied()
        .filter(|s| s != &"Connector")
        .collect::<Vec<&'static str>>();
    let mut category: HashMap<Option<&str>, Vec<types::Details<'_>>> = HashMap::new();
    for key in keys {
        let dir_key =
            dir::DirKeyKind::from_str(key).map_err(|_| "Invalid key received".to_string())?;
        let details = types::Details {
            description: dir_key.get_detailed_message(),
            kind: dir_key.clone(),
        };
        category
            .entry(dir_key.get_str("Category"))
            .and_modify(|val| val.push(details.clone()))
            .or_insert(vec![details]);
    }

    Ok(serde_wasm_bindgen::to_value(&category)?)
}

#[wasm_bindgen(js_name = getConnectorConfig)]
pub fn get_connector_config(key: &str) -> JsResult {
    let key = api_model_enums::Connector::from_str(key)
        .map_err(|_| "Invalid key received".to_string())?;
    let res = connector::ConnectorConfig::get_connector_config(key)?;
    Ok(serde_wasm_bindgen::to_value(&res)?)
}

#[cfg(feature = "payouts")]
#[wasm_bindgen(js_name = getPayoutConnectorConfig)]
pub fn get_payout_connector_config(key: &str) -> JsResult {
    let key = api_model_enums::PayoutConnectors::from_str(key)
        .map_err(|_| "Invalid key received".to_string())?;
    let res = connector::ConnectorConfig::get_payout_connector_config(key)?;
    Ok(serde_wasm_bindgen::to_value(&res)?)
}

#[wasm_bindgen(js_name = getAuthenticationConnectorConfig)]
pub fn get_authentication_connector_config(key: &str) -> JsResult {
    let key = api_model_enums::AuthenticationConnectors::from_str(key)
        .map_err(|_| "Invalid key received".to_string())?;
    let res = connector::ConnectorConfig::get_authentication_connector_config(key)?;
    Ok(serde_wasm_bindgen::to_value(&res)?)
}

#[wasm_bindgen(js_name = getTaxProcessorConfig)]
pub fn get_tax_processor_config(key: &str) -> JsResult {
    let key = api_model_enums::TaxConnectors::from_str(key)
        .map_err(|_| "Invalid key received".to_string())?;
    let res = connector::ConnectorConfig::get_tax_processor_config(key)?;
    Ok(serde_wasm_bindgen::to_value(&res)?)
}

#[wasm_bindgen(js_name = getPMAuthenticationProcessorConfig)]
pub fn get_pm_authentication_processor_config(key: &str) -> JsResult {
    let key: api_model_enums::PmAuthConnectors = api_model_enums::PmAuthConnectors::from_str(key)
        .map_err(|_| "Invalid key received".to_string())?;
    let res = connector::ConnectorConfig::get_pm_authentication_processor_config(key)?;
    Ok(serde_wasm_bindgen::to_value(&res)?)
}

#[wasm_bindgen(js_name = getRequestPayload)]
pub fn get_request_payload(input: JsValue, response: JsValue) -> JsResult {
    let input: DashboardRequestPayload = serde_wasm_bindgen::from_value(input)?;
    let api_response: ConnectorApiIntegrationPayload = serde_wasm_bindgen::from_value(response)?;
    let result = DashboardRequestPayload::create_connector_request(input, api_response);
    Ok(serde_wasm_bindgen::to_value(&result)?)
}

#[wasm_bindgen(js_name = getResponsePayload)]
pub fn get_response_payload(input: JsValue) -> JsResult {
    let input: ConnectorApiIntegrationPayload = serde_wasm_bindgen::from_value(input)?;
    let result = ConnectorApiIntegrationPayload::get_transformed_response_payload(input);
    Ok(serde_wasm_bindgen::to_value(&result)?)
}

#[cfg(feature = "payouts")]
#[wasm_bindgen(js_name = getAllPayoutKeys)]
pub fn get_all_payout_keys() -> JsResult {
    let keys: Vec<&'static str> = dir::PayoutDirKeyKind::VARIANTS.to_vec();
    Ok(serde_wasm_bindgen::to_value(&keys)?)
}

#[cfg(feature = "payouts")]
#[wasm_bindgen(js_name = getPayoutVariantValues)]
pub fn get_payout_variant_values(key: &str) -> Result<JsValue, JsValue> {
    let key =
        dir::PayoutDirKeyKind::from_str(key).map_err(|_| "Invalid key received".to_string())?;

    let variants: &[&str] = match key {
        dir::PayoutDirKeyKind::BusinessCountry => dir_enums::BusinessCountry::VARIANTS,
        dir::PayoutDirKeyKind::BillingCountry => dir_enums::BillingCountry::VARIANTS,
        dir::PayoutDirKeyKind::PayoutType => dir_enums::PayoutType::VARIANTS,
        dir::PayoutDirKeyKind::WalletType => dir_enums::PayoutWalletType::VARIANTS,
        dir::PayoutDirKeyKind::BankTransferType => dir_enums::PayoutBankTransferType::VARIANTS,

        dir::PayoutDirKeyKind::PayoutAmount | dir::PayoutDirKeyKind::BusinessLabel => {
            Err("Key does not have variants".to_string())?
        }
    };

    Ok(serde_wasm_bindgen::to_value(variants)?)
}

#[cfg(feature = "payouts")]
#[wasm_bindgen(js_name = getPayoutDescriptionCategory)]
pub fn get_payout_description_category() -> JsResult {
    let keys = dir::PayoutDirKeyKind::VARIANTS.to_vec();
    let mut category: HashMap<Option<&str>, Vec<types::PayoutDetails<'_>>> = HashMap::new();
    for key in keys {
        let dir_key =
            dir::PayoutDirKeyKind::from_str(key).map_err(|_| "Invalid key received".to_string())?;
        let details = types::PayoutDetails {
            description: dir_key.get_detailed_message(),
            kind: dir_key.clone(),
        };
        category
            .entry(dir_key.get_str("Category"))
            .and_modify(|val| val.push(details.clone()))
            .or_insert(vec![details]);
    }

    Ok(serde_wasm_bindgen::to_value(&category)?)
}

#[wasm_bindgen(js_name = getValidWebhookStatus)]
pub fn get_valid_webhook_status(key: &str) -> JsResult {
    let event_class = EventClass::from_str(key)
        .map_err(|_| "Invalid webhook event type received".to_string())
        .err_to_js()?;

    match event_class {
        EventClass::Payments => {
            let statuses: Vec<IntentStatus> = IntentStatus::iter()
                .filter(|intent_status| Into::<Option<EventType>>::into(*intent_status).is_some())
                .collect();
            Ok(serde_wasm_bindgen::to_value(&statuses)?)
        }
        EventClass::Refunds => {
            let statuses: Vec<RefundStatus> = RefundStatus::iter()
                .filter(|status| Into::<Option<EventType>>::into(*status).is_some())
                .collect();
            Ok(serde_wasm_bindgen::to_value(&statuses)?)
        }
        EventClass::Disputes => {
            let statuses: Vec<DisputeStatus> = DisputeStatus::iter().collect();
            Ok(serde_wasm_bindgen::to_value(&statuses)?)
        }
        EventClass::Mandates => {
            let statuses: Vec<MandateStatus> = MandateStatus::iter()
                .filter(|status| Into::<Option<EventType>>::into(*status).is_some())
                .collect();
            Ok(serde_wasm_bindgen::to_value(&statuses)?)
        }
        #[cfg(feature = "payouts")]
        EventClass::Payouts => {
            let statuses: Vec<PayoutStatus> = PayoutStatus::iter()
                .filter(|status| Into::<Option<EventType>>::into(*status).is_some())
                .collect();
            Ok(serde_wasm_bindgen::to_value(&statuses)?)
        }
    }
}


File: crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs
 Public functions: 3
 Public structs: 35

use common_enums::enums::{self, AttemptStatus};
use common_utils::{
    errors::{CustomResult, ParsingError},
    ext_traits::ByteSliceExt,
    request::Method,
    types::MinorUnit,
};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    payment_method_data::{PaymentMethodData, WalletData},
    router_data::{ConnectorAuthType, ErrorResponse, PaymentMethodToken, RouterData},
    router_flow_types::{Execute, RSync},
    router_request_types::ResponseId,
    router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData},
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsSyncRouterData, RefundsRouterData, TokenizationRouterData,
    },
};
use hyperswitch_interfaces::{consts, errors, webhooks};
use masking::{ExposeInterface, Secret};
use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;
use url::Url;

use crate::{
    types::{
        PaymentsCancelResponseRouterData, PaymentsCaptureResponseRouterData,
        PaymentsResponseRouterData, PaymentsSyncResponseRouterData, RefundsResponseRouterData,
        ResponseRouterData, SubmitEvidenceRouterData, UploadFileRouterData,
    },
    unimplemented_payment_method,
    utils::{
        self, PaymentsCaptureRequestData, RouterData as OtherRouterData,
        WalletData as OtherWalletData,
    },
};

#[derive(Debug, Serialize)]
pub struct CheckoutRouterData<T> {
    pub amount: MinorUnit,
    pub router_data: T,
}

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

#[derive(Debug, Serialize)]
#[serde(rename_all = "lowercase")]
#[serde(tag = "type", content = "token_data")]
pub enum TokenRequest {
    Googlepay(CheckoutGooglePayData),
    Applepay(CheckoutApplePayData),
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "lowercase")]
#[serde(tag = "type", content = "token_data")]
pub enum PreDecryptedTokenRequest {
    Applepay(Box<CheckoutApplePayData>),
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CheckoutGooglePayData {
    protocol_version: Secret<String>,
    signature: Secret<String>,
    signed_message: Secret<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CheckoutApplePayData {
    version: Secret<String>,
    data: Secret<String>,
    signature: Secret<String>,
    header: CheckoutApplePayHeader,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CheckoutApplePayHeader {
    ephemeral_public_key: Secret<String>,
    public_key_hash: Secret<String>,
    transaction_id: Secret<String>,
}

impl TryFrom<&TokenizationRouterData> for TokenRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &TokenizationRouterData) -> Result<Self, Self::Error> {
        match item.request.payment_method_data.clone() {
            PaymentMethodData::Wallet(wallet_data) => match wallet_data.clone() {
                WalletData::GooglePay(_data) => {
                    let json_wallet_data: CheckoutGooglePayData =
                        wallet_data.get_wallet_token_as_json("Google Pay".to_string())?;
                    Ok(Self::Googlepay(json_wallet_data))
                }
                WalletData::ApplePay(_data) => {
                    let json_wallet_data: CheckoutApplePayData =
                        wallet_data.get_wallet_token_as_json("Apple Pay".to_string())?;
                    Ok(Self::Applepay(json_wallet_data))
                }
                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::PaypalRedirect(_)
                | WalletData::PaypalSdk(_)
                | WalletData::Paze(_)
                | WalletData::SamsungPay(_)
                | WalletData::TwintRedirect {}
                | WalletData::VippsRedirect {}
                | WalletData::TouchNGoRedirect(_)
                | WalletData::WeChatPayRedirect(_)
                | WalletData::CashappQr(_)
                | WalletData::SwishQr(_)
                | WalletData::WeChatPayQr(_)
                | WalletData::Mifinity(_)
                | WalletData::RevolutPay(_) => Err(errors::ConnectorError::NotImplemented(
                    utils::get_unimplemented_payment_method_error_message("checkout"),
                )
                .into()),
            },
            PaymentMethodData::Card(_)
            | PaymentMethodData::PayLater(_)
            | PaymentMethodData::BankRedirect(_)
            | PaymentMethodData::BankDebit(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::Crypto(_)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(_)
            | PaymentMethodData::MobilePayment(_)
            | PaymentMethodData::Upi(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::NetworkToken(_)
            | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
                Err(errors::ConnectorError::NotImplemented(
                    utils::get_unimplemented_payment_method_error_message("checkout"),
                )
                .into())
            }
        }
    }
}

#[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct CheckoutTokenResponse {
    token: Secret<String>,
}

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

#[derive(Debug, Serialize)]
pub struct CardSource {
    #[serde(rename = "type")]
    pub source_type: CheckoutSourceTypes,
    pub number: cards::CardNumber,
    pub expiry_month: Secret<String>,
    pub expiry_year: Secret<String>,
    pub cvv: Secret<String>,
}

#[derive(Debug, Serialize)]
pub struct WalletSource {
    #[serde(rename = "type")]
    pub source_type: CheckoutSourceTypes,
    pub token: Secret<String>,
}

#[derive(Debug, Serialize)]
#[serde(untagged)]
pub enum PaymentSource {
    Card(CardSource),
    Wallets(WalletSource),
    ApplePayPredecrypt(Box<ApplePayPredecrypt>),
}

#[derive(Debug, Serialize)]
pub struct ApplePayPredecrypt {
    token: cards::CardNumber,
    #[serde(rename = "type")]
    decrypt_type: String,
    token_type: String,
    expiry_month: Secret<String>,
    expiry_year: Secret<String>,
    eci: Option<String>,
    cryptogram: Secret<String>,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum CheckoutSourceTypes {
    Card,
    Token,
}

pub struct CheckoutAuthType {
    pub(super) api_key: Secret<String>,
    pub(super) processing_channel_id: Secret<String>,
    pub(super) api_secret: Secret<String>,
}

#[derive(Debug, Serialize)]
pub struct ReturnUrl {
    pub success_url: Option<String>,
    pub failure_url: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct PaymentsRequest {
    pub source: PaymentSource,
    pub amount: MinorUnit,
    pub currency: String,
    pub processing_channel_id: Secret<String>,
    #[serde(rename = "3ds")]
    pub three_ds: CheckoutThreeDS,
    #[serde(flatten)]
    pub return_url: ReturnUrl,
    pub capture: bool,
    pub reference: String,
    pub metadata: Option<Secret<serde_json::Value>>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CheckoutMeta {
    pub psync_flow: CheckoutPaymentIntent,
}

#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub enum CheckoutPaymentIntent {
    Capture,
    Authorize,
}

#[derive(Debug, Serialize)]
pub struct CheckoutThreeDS {
    enabled: bool,
    force_3ds: bool,
    eci: Option<String>,
    cryptogram: Option<Secret<String>>,
    xid: Option<String>,
    version: Option<String>,
}

impl TryFrom<&ConnectorAuthType> for CheckoutAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        if let ConnectorAuthType::SignatureKey {
            api_key,
            api_secret,
            key1,
        } = auth_type
        {
            Ok(Self {
                api_key: api_key.to_owned(),
                api_secret: api_secret.to_owned(),
                processing_channel_id: key1.to_owned(),
            })
        } else {
            Err(errors::ConnectorError::FailedToObtainAuthType.into())
        }
    }
}
impl TryFrom<&CheckoutRouterData<&PaymentsAuthorizeRouterData>> for PaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &CheckoutRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        let source_var = match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(ccard) => {
                let a = PaymentSource::Card(CardSource {
                    source_type: CheckoutSourceTypes::Card,
                    number: ccard.card_number.clone(),
                    expiry_month: ccard.card_exp_month.clone(),
                    expiry_year: ccard.card_exp_year.clone(),
                    cvv: ccard.card_cvc,
                });
                Ok(a)
            }
            PaymentMethodData::Wallet(wallet_data) => match wallet_data {
                WalletData::GooglePay(_) => Ok(PaymentSource::Wallets(WalletSource {
                    source_type: CheckoutSourceTypes::Token,
                    token: match item.router_data.get_payment_method_token()? {
                        PaymentMethodToken::Token(token) => token,
                        PaymentMethodToken::ApplePayDecrypt(_) => Err(
                            unimplemented_payment_method!("Apple Pay", "Simplified", "Checkout"),
                        )?,
                        PaymentMethodToken::PazeDecrypt(_) => {
                            Err(unimplemented_payment_method!("Paze", "Checkout"))?
                        }
                        PaymentMethodToken::GooglePayDecrypt(_) => {
                            Err(unimplemented_payment_method!("Google Pay", "Checkout"))?
                        }
                    },
                })),
                WalletData::ApplePay(_) => {
                    let payment_method_token = item.router_data.get_payment_method_token()?;
                    match payment_method_token {
                        PaymentMethodToken::Token(apple_pay_payment_token) => {
                            Ok(PaymentSource::Wallets(WalletSource {
                                source_type: CheckoutSourceTypes::Token,
                                token: apple_pay_payment_token,
                            }))
                        }
                        PaymentMethodToken::ApplePayDecrypt(decrypt_data) => {
                            let exp_month = decrypt_data.get_expiry_month().change_context(
                                errors::ConnectorError::InvalidDataFormat {
                                    field_name: "expiration_month",
                                },
                            )?;
                            let expiry_year_4_digit = decrypt_data.get_four_digit_expiry_year();
                            Ok(PaymentSource::ApplePayPredecrypt(Box::new(
                                ApplePayPredecrypt {
                                    token: decrypt_data.application_primary_account_number,
                                    decrypt_type: "network_token".to_string(),
                                    token_type: "applepay".to_string(),
                                    expiry_month: exp_month,
                                    expiry_year: expiry_year_4_digit,
                                    eci: decrypt_data.payment_data.eci_indicator,
                                    cryptogram: decrypt_data.payment_data.online_payment_cryptogram,
                                },
                            )))
                        }
                        PaymentMethodToken::PazeDecrypt(_) => {
                            Err(unimplemented_payment_method!("Paze", "Checkout"))?
                        }
                        PaymentMethodToken::GooglePayDecrypt(_) => {
                            Err(unimplemented_payment_method!("Google Pay", "Checkout"))?
                        }
                    }
                }
                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::PaypalRedirect(_)
                | WalletData::PaypalSdk(_)
                | WalletData::Paze(_)
                | WalletData::SamsungPay(_)
                | WalletData::TwintRedirect {}
                | WalletData::VippsRedirect {}
                | WalletData::TouchNGoRedirect(_)
                | WalletData::WeChatPayRedirect(_)
                | WalletData::CashappQr(_)
                | WalletData::SwishQr(_)
                | WalletData::WeChatPayQr(_)
                | WalletData::Mifinity(_)
                | WalletData::RevolutPay(_) => Err(errors::ConnectorError::NotImplemented(
                    utils::get_unimplemented_payment_method_error_message("checkout"),
                )),
            },

            PaymentMethodData::PayLater(_)
            | PaymentMethodData::BankRedirect(_)
            | PaymentMethodData::BankDebit(_)
            | PaymentMethodData::BankTransfer(_)
            | PaymentMethodData::Crypto(_)
            | PaymentMethodData::MandatePayment
            | PaymentMethodData::Reward
            | PaymentMethodData::RealTimePayment(_)
            | PaymentMethodData::MobilePayment(_)
            | PaymentMethodData::Upi(_)
            | PaymentMethodData::Voucher(_)
            | PaymentMethodData::CardRedirect(_)
            | PaymentMethodData::GiftCard(_)
            | PaymentMethodData::OpenBanking(_)
            | PaymentMethodData::CardToken(_)
            | PaymentMethodData::NetworkToken(_)
            | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
                Err(errors::ConnectorError::NotImplemented(
                    utils::get_unimplemented_payment_method_error_message("checkout"),
                ))
            }
        }?;

        let authentication_data = item.router_data.request.authentication_data.as_ref();

        let three_ds = match item.router_data.auth_type {
            enums::AuthenticationType::ThreeDs => CheckoutThreeDS {
                enabled: true,
                force_3ds: true,
                eci: authentication_data.and_then(|auth| auth.eci.clone()),
                cryptogram: authentication_data.map(|auth| auth.cavv.clone()),
                xid: authentication_data
                    .and_then(|auth| auth.threeds_server_transaction_id.clone()),
                version: authentication_data.and_then(|auth| {
                    auth.message_version
                        .clone()
                        .map(|version| version.to_string())
                }),
            },
            enums::AuthenticationType::NoThreeDs => CheckoutThreeDS {
                enabled: false,
                force_3ds: false,
                eci: None,
                cryptogram: None,
                xid: None,
                version: None,
            },
        };

        let return_url = ReturnUrl {
            success_url: item
                .router_data
                .request
                .router_return_url
                .as_ref()
                .map(|return_url| format!("{return_url}?status=success")),
            failure_url: item
                .router_data
                .request
                .router_return_url
                .as_ref()
                .map(|return_url| format!("{return_url}?status=failure")),
        };

        let capture = matches!(
            item.router_data.request.capture_method,
            Some(enums::CaptureMethod::Automatic)
        );

        let connector_auth = &item.router_data.connector_auth_type;
        let auth_type: CheckoutAuthType = connector_auth.try_into()?;
        let processing_channel_id = auth_type.processing_channel_id;
        let metadata = item.router_data.request.metadata.clone().map(Into::into);
        Ok(Self {
            source: source_var,
            amount: item.amount.to_owned(),
            currency: item.router_data.request.currency.to_string(),
            processing_channel_id,
            three_ds,
            return_url,
            capture,
            reference: item.router_data.connector_request_reference_id.clone(),
            metadata,
        })
    }
}

#[derive(Default, Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub enum CheckoutPaymentStatus {
    Authorized,
    #[default]
    Pending,
    #[serde(rename = "Card Verified")]
    CardVerified,
    Declined,
    Captured,
    #[serde(rename = "Retry Scheduled")]
    RetryScheduled,
    Voided,
    #[serde(rename = "Partially Captured")]
    PartiallyCaptured,
    #[serde(rename = "Partially Refunded")]
    PartiallyRefunded,
    Refunded,
    Canceled,
    Expired,
}

impl TryFrom<CheckoutWebhookEventType> for CheckoutPaymentStatus {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(value: CheckoutWebhookEventType) -> Result<Self, Self::Error> {
        match value {
            CheckoutWebhookEventType::PaymentApproved => Ok(Self::Authorized),
            CheckoutWebhookEventType::PaymentCaptured => Ok(Self::Captured),
            CheckoutWebhookEventType::PaymentDeclined => Ok(Self::Declined),
            CheckoutWebhookEventType::AuthenticationStarted
            | CheckoutWebhookEventType::AuthenticationApproved
            | CheckoutWebhookEventType::AuthenticationAttempted => Ok(Self::Pending),
            CheckoutWebhookEventType::AuthenticationExpired
            | CheckoutWebhookEventType::AuthenticationFailed
            | CheckoutWebhookEventType::PaymentAuthenticationFailed
            | CheckoutWebhookEventType::PaymentCaptureDeclined => Ok(Self::Declined),
            CheckoutWebhookEventType::PaymentCanceled => Ok(Self::Canceled),
            CheckoutWebhookEventType::PaymentVoided => Ok(Self::Voided),
            CheckoutWebhookEventType::PaymentRefunded
            | CheckoutWebhookEventType::PaymentRefundDeclined
            | CheckoutWebhookEventType::DisputeReceived
            | CheckoutWebhookEventType::DisputeExpired
            | CheckoutWebhookEventType::DisputeAccepted
            | CheckoutWebhookEventType::DisputeCanceled
            | CheckoutWebhookEventType::DisputeEvidenceSubmitted
            | CheckoutWebhookEventType::DisputeEvidenceAcknowledgedByScheme
            | CheckoutWebhookEventType::DisputeEvidenceRequired
            | CheckoutWebhookEventType::DisputeArbitrationLost
            | CheckoutWebhookEventType::DisputeArbitrationWon
            | CheckoutWebhookEventType::DisputeWon
            | CheckoutWebhookEventType::DisputeLost
            | CheckoutWebhookEventType::Unknown => {
                Err(errors::ConnectorError::WebhookEventTypeNotFound.into())
            }
        }
    }
}

fn get_attempt_status_cap(
    item: (CheckoutPaymentStatus, Option<enums::CaptureMethod>),
) -> AttemptStatus {
    let (status, capture_method) = item;
    match status {
        CheckoutPaymentStatus::Authorized => {
            if capture_method == Some(enums::CaptureMethod::Automatic) || capture_method.is_none() {
                AttemptStatus::Pending
            } else {
                AttemptStatus::Authorized
            }
        }
        CheckoutPaymentStatus::Captured
        | CheckoutPaymentStatus::PartiallyRefunded
        | CheckoutPaymentStatus::Refunded => AttemptStatus::Charged,
        CheckoutPaymentStatus::PartiallyCaptured => AttemptStatus::PartialCharged,
        CheckoutPaymentStatus::Declined
        | CheckoutPaymentStatus::Expired
        | CheckoutPaymentStatus::Canceled => AttemptStatus::Failure,
        CheckoutPaymentStatus::Pending => AttemptStatus::AuthenticationPending,
        CheckoutPaymentStatus::CardVerified | CheckoutPaymentStatus::RetryScheduled => {
            AttemptStatus::Pending
        }
        CheckoutPaymentStatus::Voided => AttemptStatus::Voided,
    }
}

fn get_attempt_status_intent(
    item: (CheckoutPaymentStatus, CheckoutPaymentIntent),
) -> AttemptStatus {
    let (status, psync_flow) = item;

    match status {
        CheckoutPaymentStatus::Authorized => {
            if psync_flow == CheckoutPaymentIntent::Capture {
                AttemptStatus::Pending
            } else {
                AttemptStatus::Authorized
            }
        }
        CheckoutPaymentStatus::Captured
        | CheckoutPaymentStatus::PartiallyRefunded
        | CheckoutPaymentStatus::Refunded => AttemptStatus::Charged,
        CheckoutPaymentStatus::PartiallyCaptured => AttemptStatus::PartialCharged,
        CheckoutPaymentStatus::Declined
        | CheckoutPaymentStatus::Expired
        | CheckoutPaymentStatus::Canceled => AttemptStatus::Failure,
        CheckoutPaymentStatus::Pending => AttemptStatus::AuthenticationPending,
        CheckoutPaymentStatus::CardVerified | CheckoutPaymentStatus::RetryScheduled => {
            AttemptStatus::Pending
        }
        CheckoutPaymentStatus::Voided => AttemptStatus::Voided,
    }
}

fn get_attempt_status_bal(item: (CheckoutPaymentStatus, Option<Balances>)) -> AttemptStatus {
    let (status, balances) = item;

    match status {
        CheckoutPaymentStatus::Authorized => {
            if let Some(Balances {
                available_to_capture: 0,
            }) = balances
            {
                AttemptStatus::Charged
            } else {
                AttemptStatus::Authorized
            }
        }
        CheckoutPaymentStatus::Captured
        | CheckoutPaymentStatus::PartiallyRefunded
        | CheckoutPaymentStatus::Refunded => AttemptStatus::Charged,
        CheckoutPaymentStatus::PartiallyCaptured => AttemptStatus::PartialCharged,
        CheckoutPaymentStatus::Declined
        | CheckoutPaymentStatus::Expired
        | CheckoutPaymentStatus::Canceled => AttemptStatus::Failure,
        CheckoutPaymentStatus::Pending => AttemptStatus::AuthenticationPending,
        CheckoutPaymentStatus::CardVerified | CheckoutPaymentStatus::RetryScheduled => {
            AttemptStatus::Pending
        }
        CheckoutPaymentStatus::Voided => AttemptStatus::Voided,
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct Href {
    #[serde(rename = "href")]
    redirection_url: Url,
}

#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct Links {
    redirect: Option<Href>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct PaymentsResponse {
    id: String,
    amount: Option<MinorUnit>,
    currency: Option<String>,
    action_id: Option<String>,
    status: CheckoutPaymentStatus,
    #[serde(rename = "_links")]
    links: Links,
    balances: Option<Balances>,
    reference: Option<String>,
    response_code: Option<String>,
    response_summary: Option<String>,
    approved: Option<bool>,
    processed_on: Option<String>,
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum PaymentsResponseEnum {
    ActionResponse(Vec<ActionResponse>),
    PaymentResponse(Box<PaymentsResponse>),
}

#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct Balances {
    available_to_capture: i32,
}

fn get_connector_meta(
    capture_method: enums::CaptureMethod,
) -> CustomResult<serde_json::Value, errors::ConnectorError> {
    match capture_method {
        enums::CaptureMethod::Automatic | enums::CaptureMethod::SequentialAutomatic => {
            Ok(serde_json::json!(CheckoutMeta {
                psync_flow: CheckoutPaymentIntent::Capture,
            }))
        }
        enums::CaptureMethod::Manual | enums::CaptureMethod::ManualMultiple => {
            Ok(serde_json::json!(CheckoutMeta {
                psync_flow: CheckoutPaymentIntent::Authorize,
            }))
        }
        enums::CaptureMethod::Scheduled => {
            Err(errors::ConnectorError::CaptureMethodNotSupported.into())
        }
    }
}

impl TryFrom<PaymentsResponseRouterData<PaymentsResponse>> for PaymentsAuthorizeRouterData {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: PaymentsResponseRouterData<PaymentsResponse>) -> Result<Self, Self::Error> {
        let connector_meta =
            get_connector_meta(item.data.request.capture_method.unwrap_or_default())?;

        let redirection_data = item
            .response
            .links
            .redirect
            .map(|href| RedirectForm::from((href.redirection_url, Method::Get)));
        let status =
            get_attempt_status_cap((item.response.status, item.data.request.capture_method));
        let error_response = if status == AttemptStatus::Failure {
            Some(ErrorResponse {
                status_code: item.http_code,
                code: item
                    .response
                    .response_code
                    .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()),
                message: item
                    .response
                    .response_summary
                    .clone()
                    .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
                reason: item.response.response_summary,
                attempt_status: None,
                connector_transaction_id: Some(item.response.id.clone()),
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        } else {
            None
        };
        let payments_response_data = PaymentsResponseData::TransactionResponse {
            resource_id: ResponseId::ConnectorTransactionId(item.response.id.clone()),
            redirection_data: Box::new(redirection_data),
            mandate_reference: Box::new(None),
            connector_metadata: Some(connector_meta),
            network_txn_id: None,
            connector_response_reference_id: Some(
                item.response.reference.unwrap_or(item.response.id),
            ),
            incremental_authorization_allowed: None,
            charges: None,
        };
        Ok(Self {
            status,
            response: error_response.map_or_else(|| Ok(payments_response_data), Err),
            ..item.data
        })
    }
}

impl TryFrom<PaymentsSyncResponseRouterData<PaymentsResponse>> for PaymentsSyncRouterData {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PaymentsSyncResponseRouterData<PaymentsResponse>,
    ) -> Result<Self, Self::Error> {
        let redirection_data = item
            .response
            .links
            .redirect
            .map(|href| RedirectForm::from((href.redirection_url, Method::Get)));
        let checkout_meta: CheckoutMeta =
            utils::to_connector_meta(item.data.request.connector_meta.clone())?;
        let status = get_attempt_status_intent((item.response.status, checkout_meta.psync_flow));
        let error_response = if status == AttemptStatus::Failure {
            Some(ErrorResponse {
                status_code: item.http_code,
                code: item
                    .response
                    .response_code
                    .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()),
                message: item
                    .response
                    .response_summary
                    .clone()
                    .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
                reason: item.response.response_summary,
                attempt_status: None,
                connector_transaction_id: Some(item.response.id.clone()),
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        } else {
            None
        };
        let payments_response_data = PaymentsResponseData::TransactionResponse {
            resource_id: ResponseId::ConnectorTransactionId(item.response.id.clone()),
            redirection_data: Box::new(redirection_data),
            mandate_reference: Box::new(None),
            connector_metadata: None,
            network_txn_id: None,
            connector_response_reference_id: Some(
                item.response.reference.unwrap_or(item.response.id),
            ),
            incremental_authorization_allowed: None,
            charges: None,
        };
        Ok(Self {
            status,
            response: error_response.map_or_else(|| Ok(payments_response_data), Err),
            ..item.data
        })
    }
}

impl TryFrom<PaymentsSyncResponseRouterData<PaymentsResponseEnum>> for PaymentsSyncRouterData {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        item: PaymentsSyncResponseRouterData<PaymentsResponseEnum>,
    ) -> Result<Self, Self::Error> {
        let capture_sync_response_list = match item.response {
            PaymentsResponseEnum::PaymentResponse(payments_response) => {
                // for webhook consumption flow
                utils::construct_captures_response_hashmap(vec![payments_response])?
            }
            PaymentsResponseEnum::ActionResponse(action_list) => {
                // for captures sync
                utils::construct_captures_response_hashmap(action_list)?
            }
        };
        Ok(Self {
            response: Ok(PaymentsResponseData::MultipleCaptureResponse {
                capture_sync_response_list,
            }),
            ..item.data
        })
    }
}

#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize)]
pub struct PaymentVoidRequest {
    reference: String,
}
#[derive(Clone, Default, Debug, Eq, PartialEq, Deserialize, Serialize)]
pub struct PaymentVoidResponse {
    #[serde(skip)]
    pub(super) status: u16,
    action_id: String,
    reference: String,
}

impl From<&PaymentVoidResponse> for AttemptStatus {
    fn from(item: &PaymentVoidResponse) -> Self {
        if item.status == 202 {
            Self::Voided
        } else {
            Self::VoidFailed
        }
    }
}

impl TryFrom<PaymentsCancelResponseRouterData<PaymentVoidResponse>> for PaymentsCancelRouterData {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PaymentsCancelResponseRouterData<PaymentVoidResponse>,
    ) -> Result<Self, Self::Error> {
        let response = &item.response;
        Ok(Self {
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(response.action_id.clone()),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            status: response.into(),
            ..item.data
        })
    }
}

impl TryFrom<&PaymentsCancelRouterData> for PaymentVoidRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PaymentsCancelRouterData) -> Result<Self, Self::Error> {
        Ok(Self {
            reference: item.request.connector_transaction_id.clone(),
        })
    }
}

#[derive(Debug, Serialize)]
pub enum CaptureType {
    Final,
    NonFinal,
}

#[derive(Debug, Serialize)]
pub struct PaymentCaptureRequest {
    pub amount: Option<MinorUnit>,
    pub capture_type: Option<CaptureType>,
    pub processing_channel_id: Secret<String>,
    pub reference: Option<String>,
}

impl TryFrom<&CheckoutRouterData<&PaymentsCaptureRouterData>> for PaymentCaptureRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &CheckoutRouterData<&PaymentsCaptureRouterData>,
    ) -> Result<Self, Self::Error> {
        let connector_auth = &item.router_data.connector_auth_type;
        let auth_type: CheckoutAuthType = connector_auth.try_into()?;
        let processing_channel_id = auth_type.processing_channel_id;
        let capture_type = if item.router_data.request.is_multiple_capture() {
            CaptureType::NonFinal
        } else {
            CaptureType::Final
        };
        let reference = item
            .router_data
            .request
            .multiple_capture_data
            .as_ref()
            .map(|multiple_capture_data| multiple_capture_data.capture_reference.clone());
        Ok(Self {
            amount: Some(item.amount.to_owned()),
            capture_type: Some(capture_type),
            processing_channel_id,
            reference, // hyperswitch's reference for this capture
        })
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct PaymentCaptureResponse {
    pub action_id: String,
    pub reference: Option<String>,
}

impl TryFrom<PaymentsCaptureResponseRouterData<PaymentCaptureResponse>>
    for PaymentsCaptureRouterData
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PaymentsCaptureResponseRouterData<PaymentCaptureResponse>,
    ) -> Result<Self, Self::Error> {
        let connector_meta = serde_json::json!(CheckoutMeta {
            psync_flow: CheckoutPaymentIntent::Capture,
        });
        let (status, amount_captured) = if item.http_code == 202 {
            (
                AttemptStatus::Charged,
                Some(item.data.request.amount_to_capture),
            )
        } else {
            (AttemptStatus::Pending, None)
        };

        // if multiple capture request, return capture action_id so that it will be updated in the captures table.
        // else return previous connector_transaction_id.
        let resource_id = if item.data.request.is_multiple_capture() {
            item.response.action_id
        } else {
            item.data.request.connector_transaction_id.to_owned()
        };

        Ok(Self {
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(resource_id),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: Some(connector_meta),
                network_txn_id: None,
                connector_response_reference_id: item.response.reference,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            status,
            amount_captured,
            ..item.data
        })
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RefundRequest {
    amount: Option<MinorUnit>,
    reference: String,
}

impl<F> TryFrom<&CheckoutRouterData<&RefundsRouterData<F>>> for RefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &CheckoutRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        let reference = item.router_data.request.refund_id.clone();
        Ok(Self {
            amount: Some(item.amount.to_owned()),
            reference,
        })
    }
}
#[allow(dead_code)]
#[derive(Deserialize, Debug, Serialize)]
pub struct RefundResponse {
    action_id: String,
    reference: String,
}

#[derive(Deserialize)]
pub struct CheckoutRefundResponse {
    pub(super) status: u16,
    pub(super) response: RefundResponse,
}

impl From<&CheckoutRefundResponse> for enums::RefundStatus {
    fn from(item: &CheckoutRefundResponse) -> Self {
        if item.status == 202 {
            Self::Success
        } else {
            Self::Failure
        }
    }
}

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

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

#[derive(Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct CheckoutErrorResponse {
    pub request_id: Option<String>,
    pub error_type: Option<String>,
    pub error_codes: Option<Vec<String>>,
}

#[derive(Deserialize, Debug, PartialEq, Serialize)]
pub enum ActionType {
    Authorization,
    Void,
    Capture,
    Refund,
    Payout,
    Return,
    #[serde(rename = "Card Verification")]
    CardVerification,
}

#[derive(Deserialize, Debug, Serialize)]
pub struct ActionResponse {
    #[serde(rename = "id")]
    pub action_id: String,
    pub amount: MinorUnit,
    #[serde(rename = "type")]
    pub action_type: ActionType,
    pub approved: Option<bool>,
    pub reference: Option<String>,
}

impl From<&ActionResponse> for enums::RefundStatus {
    fn from(item: &ActionResponse) -> Self {
        match item.approved {
            Some(true) => Self::Success,
            Some(false) => Self::Failure,
            None => Self::Pending,
        }


pub struct MetadataValue {
    pub key: String,
    pub value: String,
}


pub struct DeutschebankThreeDSInitializeResponseChallengeRequired {
    acs_url: String,
    creq: String,
}


impl FetchDisputes for Worldpayvantiv {}

impl FetchDisputes for for Worldpayvantiv


File: crates/router/src/services/api/request.rs

pub use common_utils::request::ContentType;
pub use masking::{Mask, Maskable};


impl api::PaymentSync for Authipay {}


Documentation: api-reference/v1/payments/payments--list.mdx
# Type: Doc File

---
openapi: get /payments/list
---


Documentation: crates/router/src/utils/user/blocker_emails.txt
# Type: Doc File

020.co.uk
123.com
123box.net
123india.com
123mail.cl
123mail.org
123qwe.co.uk
138mail.com
141.ro
150mail.com
150ml.com
16mail.com
1963chevrolet.com
1963pontiac.com
1netdrive.com
1st-website.com
1stpd.net
2-mail.com
20after4.com
21cn.com
24h.co.jp
24horas.com
271soundview.com
2die4.com
2mydns.com
2net.us
3000.it
3ammagazine.com
3email.com
3xl.net
444.net
4email.com
4email.net
4newyork.com
50mail.com
55mail.cc
5fm.za.com
6210.hu
6sens.com
702mail.co.za
7110.hu
8848.net
8m.com
8m.net
8x.com.br
8u8.com
8u8.hk
8u8.tw
a-topmail.at
about.com
abv.bg
acceso.or.cr
access4less.net
accessgcc.com
acmemail.net
adiga.com
adinet.com.uy
adres.nl
advalvas.be
aeiou.pt
aeneasmail.com
afrik.com
afropoets.com
aggies.com
ahaa.dk
aichi.com
aim.com
airpost.net
aiutamici.com
aklan.com
aknet.kg
alabama.usa.com
alaska.usa.com
alavatotal.com
albafind.com
albawaba.com
alburaq.net
aldeax.com
aldeax.com.ar
alex4all.com
aliyun.com
alexandria.cc
algeria.com
alice.it
allmail.net
alskens.dk
altavista.se
altbox.org
alternativagratis.com
alum.com
alunos.unipar.br
alvilag.hu
amenworld.com
america.hm
americamail.com
amnetsal.com
amorous.com
ananzi.co.za
anet.ne.jp
anfmail.com
angelfire.com
animail.net
aniverse.com
anjungcafe.com
another.com
antedoonsub.com
antwerpen.com
anunciador.net
anytimenow.com
aon.at
apexmail.com
apollo.lv
approvers.net
aprava.com
apropo.ro
arcor.de
argentina.com
arizona.usa.com
arkansas.usa.com
armmail.com
army.com
arnet.com.ar
aroma.com
arrl.net
aruba.it
asheville.com
asia-links.com
asiamail.com
assala.com
assamesemail.com
asurfer.com
atl.lv
atlas.cz
atlas.sk
atozasia.com
atreillou.com
att.net
au.ru
aubenin.com
aus-city.com
aussiemail.com.au
avasmail.com.mv
axarnet.com
ayna.com
azet.sk
babbalu.com
badgers.com
bakpaka.com
bakpaka.net
balochistan.org
baluch.com
bama-fan.com
bancora.net
bankersmail.com
barlick.net
beeebank.com
beehive.org
been-there.com
beirut.com
belizehome.com
belizemail.net
belizeweb.com
bellsouth.net
berlin.de
bestmail.us
bflomail.com
bgnmail.com
bharatmail.com
big-orange.com
bigboss.cz
bigfoot.com
bigger.com
bigmailbox.com
bigmir.net
bigstring.com
bip.net
bigpond.com
bitwiser.com
biz.by
bizhosting.com
black-sea.ro
blackburnmail.com
blackglobalnetwork.net
blink182.net
blue.devils.com
bluebottle.com
bluemail.ch
blumail.org
blvds.com
bol.com.br
bolando.com
bollywood2000.com
bollywoodz.com
bombka.dyn.pl
bonbon.net
boom.com
bootmail.com
bostonoffice.com
box.az
boxbg.com
boxemail.com
brain.com.pk
brasilia.net
bravanese.com
brazilmail.com.br
breathe.com
brestonline.com
brfree.com.br
brujula.net
btcc.org
buffaloes.com
bulgaria.com
bulldogs.com
bumerang.ro
burntmail.com
butch-femme.net
buzy.com
buzzjakkerz.com
c-box.cz
c3.hu
c4.com
cadinfo.net
calcfacil.com.br
calcware.org
california.usa.com
callnetuk.com
camaroclubsweden.com
canada-11.com
canada.com
canal21.com
canoemail.com
caramail.com
cardblvd.com
care-mail.com
care2.com
caress.com
carioca.net
cashette.com
casino.com
casinomail.com
cataloniamail.com
catalunyamail.com
cataz.com
catcha.com
catholic.org
caths.co.uk
caxess.net
cbrmail.com
cc.lv
cemelli.com
centoper.it
centralpets.com
centrum.cz
centrum.sk
centurylink.net
cercaziende.it
cgac.es
chaiyo.com
chaiyomail.com
chance2mail.com
channelonetv.com
charter.net
chattown.com
checkitmail.at
chelny.com
cheshiremail.com
chil-e.com
chillimail.com
china.com
christianmail.org
ciaoweb.it
cine.com
ciphercom.net
circlemail.com
cititrustbank1.cjb.net
citromail.hu
citynetusa.com
ciudad.com.ar
claramail.com
classicmail.co.za
cliffhanger.com
clix.pt
close2you.net
cluemail.com
clujnapoca.ro
collegeclub.com
colombia.com
colorado.usa.com
comcast.net
comfortable.com
compaqnet.fr
compuserve.com
computer.net
computermail.net
computhouse.com
conevyt.org.mx
connect4free.net
connecticut.usa.com
coolgoose.com
coolkiwi.com
coollist.com
coxinet.net
coolmail.com
coolmail.net
coolsend.com
cooltoad.com
cooperation.net
copacabana.com
copticmail.com
corporateattorneys.com
corporation.net
correios.net.br
correomagico.com
cosmo.com
cosmosurf.net
cougars.com
count.com
countrybass.com
couple.com
criticalpath.net
critterpost.com
crosspaths.net
crosswinds.net
cryingmail.com
cs.com
csucsposta.hu
cumbriamail.com
curio-city.com
custmail.com
cwazy.co.uk
cwazy.net
cww.de
cyberaccess.com.pk
cybergirls.dk
cyberguys.dk
cybernet.it
cymail.net
dabsol.net
dada.net
dadanet.it
dailypioneer.com
damuc.org.br
dansegulvet.com
darkhorsefan.net
data54.com
davegracey.com
dayzers.com
daum.net
dbmail.com
dcemail.com
dcsi.net
deacons.com
deadlymob.org
deal-maker.com
dearriba.com
degoo.com
delajaonline.org
delaware.usa.com
delfi.lv
delhimail.com
demon.deacons.com
desertonline.com
desidrivers.com
deskpilot.com
despammed.com
detik.com
devils.com
dexara.net
dhmail.net
di-ve.com
didamail.com
digitaltrue.com
direccion.com
director-general.com
diri.com
discardmail.com
discoverymail.net
disinfo.net
djmillenium.com
dmailman.com
dnsmadeeasy.com
do.net.ar
dodgeit.com
dogmail.co.uk
doityourself.com
domaindiscover.com
domainmanager.com
doneasy.com
dontexist.org
dores.com
dostmail.com
dot5hosting.com
dotcom.fr
dotnow.com
dott.it
doubt.com
dplanet.ch
dragoncon.net
dragonfans.com
dropzone.com
dserver.org
dubaiwebcity.com
dublin.ie
dustdevil.com
dynamitemail.com
dyndns.org
e-apollo.lv
e-hkma.com
e-mail.cz
e-mail.ph
e-mailanywhere.com
e-milio.com
e-tapaal.com
e-webtec.com
earthalliance.com
earthling.net
eastmail.com
eastrolog.com
easy-pages.com
easy.com
easyinfomail.co.za
easypeasy.com
echina.com
ecn.org
ecplaza.net
eircom.net
edsamail.com.ph
educacao.te.pt
edumail.co.za
eeism.com
ego.co.th
ekolay.net
elforotv.com.ar
elitemail.org
elsitio.com
eltimon.com
elvis.com
email.com.br
email.cz
email.bg
email.it
email.lu
email.lviv.ua
email.nu
email.ro
email.si
email2me.com
emailacc.com
emailaccount.com
emailaddresses.com
emailchoice.com
emailcorner.net
emailn.de
emailengine.net
emailengine.org
emailgaul.com
emailgroups.net
emailhut.net
emailpinoy.com
emailplanet.com
emailplus.org
emailuser.net
ematic.com
embarqmail.com
embroideryforums.com
eml.cc
emoka.ro
emptymail.com
enel.net
enelpunto.net
england.com
enterate.com.ar
entryweb.it
entusiastisk.com
enusmail.com
epatra.com
epix.net
epomail.com
epost.de
eprompter.com
eqqu.com
eramail.co.za
eresmas.com
eriga.lv
ertelecom.ru
esde-s.org
esfera.cl
estadao.com.br
etllao.com
euromail.net
euroseek.com
euskalmail.com
evafan.com
everyday.com.kh
everymail.net
everyone.net
execs2k.com
executivemail.co.za
expn.com
ezilon.com
ezrs.com
f-m.fm
facilmail.com
fadrasha.net
fadrasha.org
faithhighway.com
faithmail.com
familymailbox.com
familyroll.com
familysafeweb.net
fan.com
fan.net
faroweb.com
fast-email.com
fast-mail.org
fastem.com
fastemail.us
fastemailer.com
fastermail.com
fastest.cc
fastimap.com
fastmailbox.net
fastmessaging.com
fastwebmail.it
fawz.net
fea.st
federalcontractors.com
fedxmail.com
feelings.com
female.ru
fepg.net
ffanet.com
fiberia.com
filipinolinks.com
financesource.com
findmail.com
fiscal.net
flashmail.com
flipcode.com
florida.usa.com
floridagators.com
fmail.co.uk
fmailbox.com
fmgirl.com
fmguy.com
fnmail.com
footballer.com
foxmail.com
forfree.at
forsythmissouri.org
fortuncity.com
forum.dk
free.com.pe
free.fr
free.net.nz
freeaccess.nl
freegates.be
freeghana.com
freehosting.nl
freei.co.th
freeler.nl
freemail.globalsite.com.br
freemuslim.net
freenet.de
freenet.kg
freeola.net
freepgs.com
freesbee.fr
freeservers.com
freestart.hu
freesurf.ch
freesurf.fr
freesurf.nl
freeuk.com
freeuk.net
freeweb.it
freewebemail.com
freeyellow.com
frisurf.no
frontiernet.net
fsmail.net
fsnet.co.uk
ftml.net
fuelie.org
fun-greetings-jokes.com
fun.21cn.com
fusemail.com
fut.es
gala.net
galmail.co.za
gamebox.net
gamecocks.com
gawab.com
gay.com
gaymailbox.com
gaza.net
gazeta.pl
gci.net
gdi.net
geeklife.com
gemari.or.id
genxemail.com
geopia.com
georgia.usa.com
getmail.no
ggaweb.ch
giga4u.de
gjk.dk
glay.org
glendale.net
globalfree.it
globomail.com
globalpinoy.com
globalsite.com.br
globalum.com
globetrotter.net
go-bama.com
go-cavs.com
go-chargers.com
go-dawgs.com
go-gators.com
go-hogs.com
go-irish.com
go-spartans.com
go-tigers.com
go.aggies.com
go.air-force.com
go.badgers.com
go.big-orange.com
go.blue.devils.com
go.buffaloes.com
go.bulldogs.com
go.com
go.cougars.com
go.dores.com
go.gamecocks.com
go.huskies.com
go.longhorns.com
go.mustangs.com
go.rebels.com
go.ro
go.ru
go.terrapins.com
go.wildcats.com
go.wolverines.com
go.yellow-jackets.com
go2net.com
go4.it
gofree.co.uk
golfemail.com
goliadtexas.com
gomail.com.ua
gonowmail.com
gonuts4free.com
googlemail.com
goplay.com
gorontalo.net
gotmail.com
gotomy.com
govzone.com
grad.com
graffiti.net
gratisweb.com
gtechnics.com
guate.net
guessmail.com
gwalla.com
h-mail.us
haberx.com
hailmail.net
halejob.com
hamptonroads.com
handbag.com
hanmail.net
happemail.com
happycounsel.com
hawaii.com
hawaii.usa.com
hayahaya.tg
hedgeai.com
heesun.net
heremail.com
hetnet.nl
highveldmail.co.za
hildebrands.de
hingis.org
hispavista.com
hitmanrecords.com
hockeyghiaccio.com
hockeymail.com
holapuravida.com
home.no.net
home.ro
home.se
homelocator.com
homemail.co.za
homenetmail.com
homestead.com
homosexual.net
hongkong.com
hong-kong-1.com
hopthu.com
hosanna.net
hot.ee
hotbot.com
hotbox.ru
hotcoolmail.com
hotdak.com
hotfire.net
hotinbox.com
hotpop.com
hotvoice.com
hour.com
howling.com
huhmail.com
humour.com
hurra.de
hush.ai
hush.com
hushmail.com
huskies.com
hutchcity.com
i-france.com
i-p.com
i12.com
i2828.com
ibatam.com
ibest.com.br
ibizdns.com
icafe.com
ice.is
icestorm.com
icq.com
icqmail.com
icrazy.com
id.ru
idaho.usa.com
idirect.com
idncafe.com
ieg.com.br
iespalomeras.net
iespana.es
ifrance.com
ig.com.br
ignazio.it
illinois.usa.com
ilse.net
ilse.nl
imail.ru
imailbox.com
imap-mail.com
imap.cc
imapmail.org
imel.org
in-box.net
inbox.com
inbox.ge
inbox.lv
inbox.net
inbox.ru
in.com
incamail.com
indexa.fr
india.com
indiamail.com
indiana.usa.com
indiatimes.com
induquimica.org
inet.com.ua
infinito.it
infoapex.com
infohq.com
infomail.es
infomart.or.jp
infosat.net
infovia.com.ar
inicia.es
inmail.sk
inmail24.com
inoutbox.com
intelnet.net.gt
intelnett.com
interblod.com
interfree.it
interia.pl
interlap.com.ar
intermail.hu
internet-e-mail.com
internet-mail.org
internet.lu
internetegypt.com
internetemails.net
internetkeno.com
internetmailing.net
inwind.it
iobox.com
iobox.fi
iol.it
iol.pt
iowa.usa.com
ip3.com
ipermitmail.com
iqemail.com
iquebec.com
iran.com
irangate.net
iscool.net
islandmama.com
ismart.net
isonews2.com
isonfire.com
isp9.net
ispey.com
itelgua.com
itloox.com
itmom.com
ivenus.com
iwan-fals.com
iwon.com
ixp.net
japan.com
jaydemail.com
jedrzejow.pl
jetemail.net
jingjo.net
jippii.fi
jmail.co.za
jojomail.com
jovem.te.pt
joymail.com
jubii.dk
jubiipost.dk
jumpy.it
juno.com
justemail.net
justmailz.com
k.ro
kaazoo.com
kabissa.org
kaixo.com
kalluritimes.com
kalpoint.com
kansas.usa.com
katamail.com
kataweb.it
kayafmmail.co.za
keko.com.ar
kentucky.usa.com
keptprivate.com
kimo.com
kiwitown.com
klik.it
klikni.cz
kmtn.ru
koko.com
kolozsvar.ro
kombud.com
koreanmail.com
kotaksuratku.info
krunis.com
kukamail.com
kuronowish.com
kyokodate.com
kyokofukada.net
ladymail.cz
lagoon.nc
lahaonline.com
lamalla.net
lancsmail.com
land.ru
laposte.net
latinmail.com
lawyer.com
lawyersmail.com
lawyerzone.com
lebanonatlas.com
leehom.net
leonardo.it
leonlai.net
letsjam.com
letterbox.org
letterboxes.org
levele.com
lexpress.net
libero.it
liberomail.com
libertysurf.net
libre.net
lightwines.org
linkmaster.com
linuxfreemail.com
lionsfan.com.au
livedoor.com
llandudno.com
llangollen.com
lmxmail.sk
loggain.net
loggain.nu
lolnetwork.net
london.com
longhorns.com
look.com
looksmart.co.uk
looksmart.com
looksmart.com.au
loteria.net
lotonazo.com
louisiana.usa.com
louiskoo.com
loveable.com
lovemail.com
lovingjesus.com
lpemail.com
luckymail.com
luso.pt
lusoweb.pt
luukku.com
lycosmail.com
mac.com
machinecandy.com
macmail.com
mad.scientist.com
madcrazy.com
madonno.com
madrid.com
mag2.com
magicmail.co.za
magik-net.com
mail-atlas.net
mail-awu.de
mail-box.cz
mail.by
mail-center.com
mail-central.com
mail-jp.org
mail-online.dk
mail-page.com
mail-x-change.com
mail.austria.com
mail.az
mail.de
mail.be
mail.bg
mail.bulgaria.com
mail.co.za
mail.dk
mail.ee
mail.goo.ne.jp
mail.gr
mail.lawguru.com
mail.md
mail.mn
mail.org
mail.pf
mail.pt
mail.ru
mail.yahoo.co.jp
mail15.com
mail3000.com
mail333.com
mail8.com
mailandftp.com
mailandnews.com
mailas.com
mailasia.com
mailbg.com
mailblocks.com
mailbolt.com
mailbox.as
mailbox.co.za
mailbox.gr
mailbox.hu
mailbox.sk
mailc.net
mailcan.com
mailcircuit.com
mailclub.fr
mailclub.net
maildozy.com
mailfly.com
mailforce.net
mailftp.com
mailglobal.net
mailhaven.com
mailinator.com
mailingaddress.org
mailingweb.com
mailisent.com
mailite.com
mailme.dk
mailmight.com
mailmij.nl
mailnew.com
mailops.com
mailpanda.com
mailpersonal.com
mailroom.com
mailru.com
mails.de
mailsent.net
mailserver.dk
mailservice.ms
mailsnare.net
mailsurf.com
mailup.net
mailvault.com
mailworks.org
maine.usa.com
majorana.martina-franca.ta.it
maktoob.com
malayalamtelevision.net
malayalapathram.com
male.ru
manager.de
manlymail.net
mantrafreenet.com
mantramail.com
mantraonline.com
marihuana.ro
marijuana.nl
marketweighton.com
maryland.usa.com
masrawy.com
massachusetts.usa.com
mauimail.com
mbox.com.au
mcrmail.com
me.by
me.com
medicinatv.com
meetingmall.com
megamail.pt
menara.ma
merseymail.com
mesra.net
messagez.com
metacrawler.com
mexico.com
miaoweb.net
michigan.usa.com
micro2media.com
miesto.sk
mighty.co.za
milacamn.net
milmail.com
mindless.com
mindviz.com
minnesota.usa.com
mississippi.usa.com
missouri.usa.com
mixmail.com
ml1.net
ml2clan.com
mlanime.com
mm.st
mmail.com
mobimail.mn
mobsters.com
mobstop.com
modemnet.net
modomail.com
moldova.com
moldovacc.com
monarchy.com
montana.usa.com
montevideo.com.uy
moomia.com
moose-mail.com
mosaicfx.com
motormania.com
movemail.com
mr.outblaze.com
mrspender.com
mscold.com
msnzone.cn
mundo-r.com
muslimsonline.com
mustangs.com
mxs.de
myblue.cc
mycabin.com
mycity.com
mycommail.com
mycool.com
mydomain.com
myeweb.com
myfastmail.com
myfunnymail.com
mygrande.net
mykolab.com
mygamingconsoles.com
myiris.com
myjazzmail.com
mymacmail.com
mymail.dk
mymail.ph.inter.net
mymail.ro
mynet.com
mynet.com.tr
myotw.net
myopera.com
myownemail.com
mypersonalemail.com
myplace.com
myrealbox.com
myspace.com
myt.mu
myway.com
mzgchaos.de
n2.com
n2business.com
n2mail.com
n2software.com
nabble.com
name.com
nameplanet.com
nanamail.co.il
nanaseaikawa.com
nandomail.com
naseej.com
nastything.com
national-champs.com
nativeweb.net
narod.ru
nate.com
naveganas.com
naver.com
nebraska.usa.com
nemra1.com
nenter.com
nerdshack.com
nervhq.org
net.hr
net4b.pt
net4jesus.com
net4you.at
netbounce.com
netcabo.pt
netcape.net
netcourrier.com
netexecutive.com
netfirms.com
netkushi.com
netmongol.com
netpiper.com
netposta.net
netscape.com
netscape.net
netscapeonline.co.uk
netsquare.com
nettaxi.com
netti.fi
networld.com
netzero.com
netzero.net
neustreet.com
nevada.usa.com
newhampshire.usa.com
newjersey.usa.com
newmail.com
newmail.net
newmail.ok.com
newmail.ru
newmexico.usa.com
newspaperemail.com
newyork.com
newyork.usa.com
newyorkcity.com
nfmail.com
nicegal.com
nightimeuk.com
nightly.com
nightmail.com
nightmail.ru
noavar.com
noemail.com
nonomail.com
nokiamail.com
noolhar.com
northcarolina.usa.com
northdakota.usa.com
nospammail.net
nowzer.com
ny.com
nyc.com
nz11.com
nzoomail.com
o2.pl
oceanfree.net
ocsnet.net
oddpost.com
odeon.pl
odmail.com
offshorewebmail.com
ofir.dk
ohio.usa.com
oicexchange.com
ok.ru
oklahoma.usa.com
ole.com
oleco.net
olympist.net
omaninfo.com
onatoo.com
ondikoi.com
onebox.com
onenet.com.ar
onet.pl
ongc.net
oninet.pt
online.ie
online.ru
onlinewiz.com
onobox.com
open.by
openbg.com
openforyou.com
opentransfer.com
operamail.com
oplusnet.com
orange.fr
orangehome.co.uk
orange.es
orange.jo
orange.pl
orbitel.bg
orcon.net.nz
oregon.usa.com
oreka.com
organizer.net
orgio.net
orthodox.com
osite.com.br
oso.com
ourbrisbane.com
ournet.md
ourprofile.net
ourwest.com
outgun.com
ownmail.net
oxfoot.com
ozu.es
pacer.com
paginasamarillas.com
pakistanmail.com
pandawa.com
pando.com
pandora.be
paris.com
parsimail.com
parspage.com
patmail.com
pattayacitythailand.com
pc4me.us
pcpostal.com
penguinmaster.com
pennsylvania.usa.com
peoplepc.com
peopleweb.com
personal.ro
personales.com
peru.com
petml.com
phreaker.net
pigeonportal.com
pilu.com
pimagop.com
pinoymail.com
pipni.cz
pisem.net
planet-school.de
planetaccess.com
planetout.com
plasa.com
playersodds.com
playful.com
pluno.com
plusmail.com.br
pmail.net
pnetmail.co.za
pobox.ru
pobox.sk
pochtamt.ru
pochta.ru
poczta.fm
poetic.com
pogowave.com
polbox.com
pop3.ru
pop.co.th
popmail.com
poppymail.com
popsmail.com
popstar.com
portafree.com
portaldosalunos.com
portugalmail.com
portugalmail.pt
post.cz
post.expart.ne.jp
post.pl
post.sk
posta.ge
postaccesslite.com
postiloota.net
postinbox.com
postino.ch
postino.it
postmaster.co.uk
postpro.net
praize.com
press.co.jp
primposta.com
printesamargareta.ro
private.21cn.com
probemail.com
profesional.com
profession.freemail.com.br
proinbox.com
promessage.com
prontomail.com
provincial.net
publicaccounting.com
punkass.com
puppy.com.my
q.com
qatar.io
qlmail.com
qq.com
qrio.com
qsl.net
qudsmail.com
queerplaces.com
quepasa.com
quick.cz
quickwebmail.com
r-o-o-t.com
r320.hu
raakim.com
rbcmail.ru
racingseat.com
radicalz.com
radiojobbank.com
ragingbull.com
raisingadaughter.com
rallye-webmail.com
rambler.ru
ranmamail.com
ravearena.com
ravemail.co.za
razormail.com
real.ro
realemail.net
reallyfast.biz
reallyfast.info
rebels.com
recife.net
recme.net
rediffmailpro.com
redseven.de
redwhitearmy.com
relia.com
revenue.com
rexian.com
rhodeisland.usa.com
ritmes.net
rn.com
roanokemail.com
rochester-mail.com
rock.com
rocketmail.com
rockfan.com
rockinghamgateway.com
rojname.com
rol.ro
rollin.com
rome.com
romymichele.com
royal.net
rpharmacist.com
rt.nl
ru.ru
rushpost.com
russiamail.com
rxpost.net
s-mail.com
saabnet.com
sacbeemail.com
sacmail.com
safe-mail.net
safe-mailbox.com
saigonnet.vn
saint-mike.org
samilan.net
sandiego.com
sanook.com
sanriotown.com
sapibon.com
sapo.pt
saturnfans.com
sayhi.net
sbcglobal.com
scfn.net
schweiz.org
sci.fi
sciaga.pl
scrapbookscrapbook.com
seapole.com
search417.com
seark.com
sebil.com
secretservices.net
secure-jlnet.com
seductive.com
sendmail.ru
sendme.cz
sent.as
sent.at
sent.com
serga.com.ar
sermix.com
server4free.de
serverwench.com
sesmail.com
sexmagnet.com
seznam.cz
shadango.com
she.com
shuf.com
siamlocalhost.com
siamnow.net
sify.com
sinamail.com
singapore.com
singmail.com
singnet.com.sg
siraj.org
sirindia.com
sirunet.com
sister.com
sina.com
sina.cn
sinanail.com
sistersbrothers.com
sizzling.com
slamdunkfan.com
slickriffs.co.uk
slingshot.com
slo.net
slomusic.net
smartemail.co.uk
smtp.ru
snail-mail.net
sndt.net
sneakemail.com
snoopymail.com
snowboarding.com
so-simple.org
socamail.com
softhome.net
sohu.com
sol.dk
solidmail.com
soon.com
sos.lv
soundvillage.org
southcarolina.usa.com
southdakota.usa.com
space.com
spacetowns.com
spamex.com
spartapiet.com
speed-racer.com
speedpost.net
speedymail.org
spils.com
spinfinder.com
sportemail.com
spray.net
spray.no
spray.se
spymac.com
srbbs.com
srilankan.net
ssan.com
ssl-mail.com
stade.fr
stalag13.com
stampmail.com
starbuzz.com
starline.ee
starmail.com
starmail.org
starmedia.com
starspath.com
start.com.au
start.no
stribmail.com
student.com
student.ednet.ns.ca
studmail.com
sudanmail.net
suisse.org
sunbella.net
sunmail1.com
sunpoint.net
sunrise.ch
sunumail.sn
sunuweb.net
suomi24.fi
superdada.it
supereva.com
supereva.it
supermailbox.com
superposta.com
surf3.net
surfassistant.com
surfsupnet.net
surfy.net
surimail.com
surnet.cl
sverige.nu
svizzera.org
sweb.cz
swift-mail.com
swissinfo.org
swissmail.net
switzerland.org
syom.com
syriamail.com
t-mail.com
t-net.net.ve
t2mail.com
tabasheer.com
talk21.com
talkcity.com
tangmonkey.com
tatanova.com
taxcutadvice.com
techemail.com
technisamail.co.za
teenmail.co.uk
teenmail.co.za
tejary.com
telebot.com
telefonica.net
telegraf.by
teleline.es
telinco.net
telkom.net
telpage.net
telstra.com
telenet.be
telusplanet.net
tempting.com
tenchiclub.com
tennessee.usa.com
terrapins.com
texas.usa.com
texascrossroads.com
tfz.net
thai.com
thaimail.com
thaimail.net
the-fastest.net
the-quickest.com
thegame.com
theinternetemail.com
theoffice.net
thepostmaster.net
theracetrack.com
theserverbiz.com
thewatercooler.com
thewebpros.co.uk
thinkpost.net
thirdage.com
thundermail.com
tim.it
timemail.com
tin.it
tinati.net
tiscalinet.it
tjohoo.se
tkcity.com
tlcfan.com
tlen.pl
tmicha.net
todito.com
todoperros.com
tokyo.com
topchat.com
topmail.com.ar
topmail.dk
topmail.co.ie
topmail.co.in
topmail.co.nz
topmail.co.uk
topmail.co.za
topsurf.com
toquedequeda.com
torba.com
torchmail.com
totalmail.com
totalsurf.com
totonline.net
tough.com
toughguy.net
trav.se
trevas.net
tripod-mail.com
triton.net
trmailbox.com
tsamail.co.za
turbonett.com
turkey.com
tvnet.lv
twc.com
typemail.com
u2club.com
uae.ac
ubbi.com
ubbi.com.br
uboot.com
ugeek.com
uk2.net
uk2net.com
ukr.net
ukrpost.net
ukrpost.ua
uku.co.uk
ulimit.com
ummah.org
unbounded.com
unicum.de
unimail.mn
unitedemailsystems.com
universal.pt
universia.cl
universia.edu.ve
universia.es
universia.net.co
universia.net.mx
universia.pr
universia.pt
universiabrasil.net
unofree.it
uol.com.ar
uol.com.br
uole.com
uolmail.com
uomail.com
uraniomail.com
urbi.com.br
ureach.com
usanetmail.com
userbeam.com
utah.usa.com
uyuyuy.com
v-sexi.com
v3mail.com
valanides.com
vegetarisme.be
velnet.com
velocall.com
vercorreo.com
verizonmail.com
vermont.usa.com
verticalheaven.com
veryfast.biz
veryspeedy.net
vfemail.net
vietmedia.com
vip.gr
virgilio.it
virgin.net
virginia.usa.com
virtual-mail.com
visitmail.com
visto.com
vivelared.com
vjtimail.com
vnn.vn
vsnl.com
vsnl.net
vodamail.co.za
voila.fr
volkermord.com
vosforums.com
w.cn
walla.com
walla.co.il
wallet.com
wam.co.za
wanex.ge
wap.hu
wapda.com
wapicode.com
wappi.com
warpmail.net
washington.usa.com
wassup.com
waterloo.com
waumail.com
wazmail.com
wearab.net
web-mail.com.ar
web.de
web.nl
web2mail.com
webaddressbook.com
webbworks.com
webcity.ca
webdream.com
webemaillist.com
webindia123.com
webinfo.fi
webjump.com
webl-3.br.inter.net
webmail.co.yu
webmail.co.za
webmails.com
webmailv.com
webpim.cc
webspawner.com
webstation.com
websurfer.co.za
webtopmail.com
webtribe.net
webtv.net
weedmail.com


pub async fn update_connector(
    state: SessionState,
    merchant_id: &id_type::MerchantId,
    profile_id: Option<id_type::ProfileId>,
    merchant_connector_id: &id_type::MerchantConnectorAccountId,
    req: api_models::admin::MerchantConnectorUpdate,
) -> RouterResponse<api_models::admin::MerchantConnectorResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let key_store = db
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            merchant_id,
            &db.get_master_key().to_vec().into(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let merchant_account = db
        .find_merchant_account_by_merchant_id(key_manager_state, merchant_id, &key_store)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let mca = req
        .clone()
        .get_merchant_connector_account_from_id(
            db,
            merchant_id,
            merchant_connector_id,
            &key_store,
            key_manager_state,
        )
        .await?;
    core_utils::validate_profile_id_from_auth_layer(profile_id, &mca)?;

    let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(domain::Context(
        merchant_account.clone(),
        key_store.clone(),
    )));
    let payment_connector = req
        .clone()
        .create_domain_model_from_request(&state, &mca, key_manager_state, &merchant_context)
        .await?;

    // Profile id should always be present
    let profile_id = mca.profile_id.clone();

    let request_connector_label = req.connector_label;

    let updated_mca = db
        .update_merchant_connector_account(
            key_manager_state,
            mca,
            payment_connector.into(),
            &key_store,
        )
        .await
        .change_context(
            errors::ApiErrorResponse::DuplicateMerchantConnectorAccount {
                profile_id: profile_id.get_string_repr().to_owned(),
                connector_label: request_connector_label.unwrap_or_default(),
            },
        )
        .attach_printable_lazy(|| {
            format!(
                "Failed while updating MerchantConnectorAccount: id: {merchant_connector_id:?}",

            )
        })?;

    let response = updated_mca.foreign_try_into()?;

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


pub async fn refunds_filter_list() {}


pub async fn from_role_id_in_lineage(
        state: &SessionState,
        role_id: &str,
        merchant_id: &id_type::MerchantId,
        org_id: &id_type::OrganizationId,
        profile_id: &id_type::ProfileId,
        tenant_id: &id_type::TenantId,
    ) -> CustomResult<Self, errors::StorageError> {
        if let Some(role) = predefined_roles::PREDEFINED_ROLES.get(role_id) {
            Ok(role.clone())
        } else {
            state
                .global_store
                .find_role_by_role_id_in_lineage(
                    role_id,
                    merchant_id,
                    org_id,
                    profile_id,
                    tenant_id,
                )
                .await
                .map(Self::from)
        }
    }


....
  Processors(BREADPAY),
  Processors(BLUECODE),
  Processors(YourNewConnector)
]
// Add display name mapping at the bottom
let getConnectorNameString = (connectorName: connectorName) =>
  switch connectorName {
  | BREADPAY => "breadpay"
  | BLUECODE => "bluecode"
  | YourNewConnector => "Your New Connector"
  }
// Add connector description at the bottom
let getProcessorInfo = (connector: ConnectorTypes.processorTypes) => {
  switch connectorName {
  | BREADPAY => breadpayInfo
  | BLUECODE => bluecodeInfo
  | YourNewConnector => YourNewConnectorInfo
  }
```
After [`bluecodeinfo`](https://github.com/juspay/hyperswitch-control-center/blob/e984254b68511728b6b37890fd0c7c7e90c22f57/src/screens/Connectors/ConnectorUtils.res#L693) definition, add the definition of your connector in a similar format:

```js
let YourNewConnectorInfo = {
  description: "Info for the connector.",
}
```

### Add Connector Icon
1. Prepare Icon Asset
- Create an SVG icon for your connector
- Name it in uppercase format: YOURCONNECTOR.SVG
- Ensure the icon follows the design guidelines (typically 24x24px or 32x32px)
2. Add to Assets Directory
Place your icon in the Control Center's gateway assets folder:

```text
public/
└── hyperswitch/
    └── Gateway/
        └── YOURCONNECTOR.SVG
```
The icon will be automatically loaded by the frontend based on the connector name mapping.

---
## Test the Connector Integration
After successfully creating your connector using the `add_connector.sh` script, you need to configure authentication credentials and test the integration. This section covers the complete testing setup process.

### Authentication Setup
1. **Obtain PSP Credentials**

First, obtain sandbox/UAT API credentials from your payment service provider. These are typically available through their developer portal or dashboard.

2. **Create Authentication File**

Copy the sample authentication template and create your credentials file:

```bash
cp crates/router/tests/connectors/sample_auth.toml auth.toml
```

The sample file `crates/router/tests/connectors/sample_auth.toml` contains templates for all supported connectors. Edit your `auth.toml` file to include your connector's credentials:

**Example for the Billwerk connector**

```text
[billewerk]
api_key = "sk_test_your_actual_billwerk_test_key_here"
```

3. **Configure Environment Variables**

Set the path to your authentication file:

```bash
export CONNECTOR_AUTH_FILE_PATH="/absolute/path/to/your/auth.toml"
```

4. **Use `direnv` for Environment Management (recommended)**

For better environment variable management, use `direnv` with a `.envrc` file in the `cypress-tests` directory.

5. **Create `.envrc` in the `cypress-tests` directory**

```bash
cd cypress-tests
```
**Create a `.envrc` file with the following content**:

```bash
export CONNECTOR_AUTH_FILE_PATH="/absolute/path/to/your/auth.toml"
export CYPRESS_CONNECTOR="your_connector_name"
export CYPRESS_BASEURL="http://localhost:8080"
export CYPRESS_ADMINAPIKEY="test_admin"
export DEBUG=cypress:cli
```

6. **Allow `direnv` to load the variables inside the `cypress-tests` directory**:

``` bash
direnv allow
```

### Test the Connector Integration

1. **Start the Hyperswitch Router Service locally**:

```bash
cargo r
```

2. **Verify Server Health**

```bash
curl --head --request GET 'http://localhost:8080/health'
```
**Detailed health check**

```bash
curl --request GET 'http://localhost:8080/health/ready'
```

3. **Run Connector Tests for Your Connector**

```bash
cargo test --package router --test connectors -- your_connector_name --test-threads=1
```

The authentication system will load your credentials from the specified path and use them for testing.

> **⚠ Important Notes**
>
> * **Never commit `auth.toml`** – It contains sensitive credentials and should never be added to version control
> * **Use absolute paths** – This avoids issues when running tests from different directories
> * **Populate with real test credentials** – Replace the placeholder values from the sample file with actual sandbox/UAT credentials from your payment processors. Please don't use production credentials.
> * **Rotate credentials regularly** – Update test keys periodically for security.


pub struct Worldpayxml {
    amount_converter: &'static (dyn AmountConvertor<Output = StringMinorUnit> + Sync),
}


File: crates/router/src/types/api/verify_connector/stripe.rs

use error_stack::ResultExt;
use router_env::env;

use super::VerifyConnector;
use crate::{
    connector, core::errors, services, types,
    types::api::verify_connector::BoxedConnectorIntegrationInterface,
};

#[async_trait::async_trait]
impl VerifyConnector for connector::Stripe {
    async fn handle_payment_error_response<F, ResourceCommonData, Req, Resp>(
        connector: BoxedConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp>,
        error_response: types::Response,
    ) -> errors::RouterResponse<()> {
        let error = connector
            .get_error_response(error_response, None)
            .change_context(errors::ApiErrorResponse::InternalServerError)?;
        match (env::which(), error.code.as_str()) {
            // In situations where an attempt is made to process a payment using a
            // Stripe production key along with a test card (which verify_connector is using),
            // Stripe will respond with a "card_declined" error. In production,
            // when this scenario occurs we will send back an "Ok" response.
            (env::Env::Production, "card_declined") => Ok(services::ApplicationResponse::StatusOk),
            _ => Err(errors::ApiErrorResponse::InvalidRequestData {
                message: error.reason.unwrap_or(error.message),
            }
            .into()),
        }
    }
}


pub struct MerchantId {
    pub merchant_id: id_type::MerchantId,
}


pub async fn create_payment_method_api() {}


pub struct PaystackPSyncResponseData {
    status: bool,
    message: String,
    data: PaystackPSyncData,
}


pub fn new() -> Self {
        Self(FxHashMap::default())
    }


impl Default for NetworkTokenizationBuilder<'_, TokenizeWithCard> {
    fn default() -> Self {
        Self::new()
    }
}

impl Default for for NetworkTokenizationBuilder


/// 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 {
    sk.split('_')
        .take(3)
        .chain(["*"])
        .collect::<Vec<&str>>()
        .join("_")
}


pub fn get_payment_method_type(&self) -> Option<common_enums::PaymentMethod> {
        self.payment_revenue_recovery_metadata
            .as_ref()
            .map(|recovery_metadata| recovery_metadata.payment_method_type)
    }


File: crates/router/src/types/storage/mandate.rs

use async_bb8_diesel::AsyncRunQueryDsl;
use common_utils::errors::CustomResult;
use diesel::{associations::HasTable, ExpressionMethods, QueryDsl};
pub use diesel_models::mandate::{
    Mandate, MandateNew, MandateUpdate, MandateUpdateInternal, SingleUseMandate,
};
use diesel_models::{errors, schema::mandate::dsl};
use error_stack::ResultExt;

use crate::{connection::PgPooledConn, logger};

#[async_trait::async_trait]
pub trait MandateDbExt: Sized {
    async fn filter_by_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        mandate_list_constraints: api_models::mandates::MandateListConstraints,
    ) -> CustomResult<Vec<Self>, errors::DatabaseError>;
}

#[async_trait::async_trait]
impl MandateDbExt for Mandate {
    async fn filter_by_constraints(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        mandate_list_constraints: api_models::mandates::MandateListConstraints,
    ) -> CustomResult<Vec<Self>, errors::DatabaseError> {
        let mut filter = <Self as HasTable>::table()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .order(dsl::created_at.desc())
            .into_boxed();

        if let Some(created_time) = mandate_list_constraints.created_time {
            filter = filter.filter(dsl::created_at.eq(created_time));
        }
        if let Some(created_time_lt) = mandate_list_constraints.created_time_lt {
            filter = filter.filter(dsl::created_at.lt(created_time_lt));
        }
        if let Some(created_time_gt) = mandate_list_constraints.created_time_gt {
            filter = filter.filter(dsl::created_at.gt(created_time_gt));
        }
        if let Some(created_time_lte) = mandate_list_constraints.created_time_lte {
            filter = filter.filter(dsl::created_at.le(created_time_lte));
        }
        if let Some(created_time_gte) = mandate_list_constraints.created_time_gte {
            filter = filter.filter(dsl::created_at.ge(created_time_gte));
        }
        if let Some(connector) = mandate_list_constraints.connector {
            filter = filter.filter(dsl::connector.eq(connector));
        }
        if let Some(mandate_status) = mandate_list_constraints.mandate_status {
            filter = filter.filter(dsl::mandate_status.eq(mandate_status));
        }
        if let Some(limit) = mandate_list_constraints.limit {
            filter = filter.limit(limit);
        }
        if let Some(offset) = mandate_list_constraints.offset {
            filter = filter.offset(offset);
        }

        logger::debug!(query = %diesel::debug_query::<diesel::pg::Pg, _>(&filter).to_string());

        filter
            .get_results_async(conn)
            .await
            // The query built here returns an empty Vec when no records are found, and if any error does occur,
            // it would be an internal database error, due to which we are raising a DatabaseError::Unknown error
            .change_context(errors::DatabaseError::Others)
            .attach_printable("Error filtering mandates by specified constraints")
    }
}


OpenAPI Block Path: components.schemas.ConnectorSelection
{
  "oneOf": [
    {
      "type": "object",
      "required": [
        "type",
        "data"
      ],
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "priority"
          ]
        },
        "data": {
          "type": "array",
          "items": {
            "$ref": "#/components/schemas/RoutableConnectorChoice"
          }
        }
      }
    },
    {
      "type": "object",
      "required": [
        "type",
        "data"
      ],
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "volume_split"
          ]
        },
        "data": {
          "type": "array",
          "items": {
            "$ref": "#/components/schemas/ConnectorVolumeSplit"
          }
        }
      }
    }
  ],
  "discriminator": {
    "propertyName": "type"
  }
}


impl PaymentVoid for Netcetera {}


pub struct BillwerkCaptureRequest {
    amount: MinorUnit,
}


pub fn into_inner(self) -> Secret<Vec<u8>, EncryptionStrategy> {
        self.inner
    }