File: crates/storage_impl/src/lib.rs
 Public functions: 7
 Public structs: 1

use std::{fmt::Debug, sync::Arc};

use diesel_models as store;
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    behaviour::{Conversion, ReverseConversion},
    merchant_key_store::MerchantKeyStore,
};
use masking::StrongSecret;
use redis::{kv_store::RedisConnInterface, pub_sub::PubSubInterface, RedisStore};
mod address;
pub mod callback_mapper;
pub mod cards_info;
pub mod config;
pub mod connection;
pub mod customers;
pub mod database;
pub mod errors;
pub mod kv_router_store;
pub mod lookup;
pub mod mandate;
pub mod metrics;
pub mod mock_db;
pub mod payment_method;
pub mod payments;
#[cfg(feature = "payouts")]
pub mod payouts;
pub mod redis;
pub mod refund;
mod reverse_lookup;
pub mod utils;

use common_utils::{errors::CustomResult, types::keymanager::KeyManagerState};
use database::store::PgPool;
pub mod tokenization;
#[cfg(not(feature = "payouts"))]
use hyperswitch_domain_models::{PayoutAttemptInterface, PayoutsInterface};
pub use mock_db::MockDb;
use redis_interface::{errors::RedisError, RedisConnectionPool, SaddReply};

#[cfg(not(feature = "payouts"))]
pub use crate::database::store::Store;
pub use crate::{database::store::DatabaseStore, errors::StorageError};

#[derive(Debug, Clone)]
pub struct RouterStore<T: DatabaseStore> {
    db_store: T,
    cache_store: Arc<RedisStore>,
    master_encryption_key: StrongSecret<Vec<u8>>,
    pub request_id: Option<String>,
}

#[async_trait::async_trait]
impl<T: DatabaseStore> DatabaseStore for RouterStore<T>
where
    T::Config: Send,
{
    type Config = (
        T::Config,
        redis_interface::RedisSettings,
        StrongSecret<Vec<u8>>,
        tokio::sync::oneshot::Sender<()>,
        &'static str,
    );
    async fn new(
        config: Self::Config,
        tenant_config: &dyn config::TenantConfig,
        test_transaction: bool,
    ) -> error_stack::Result<Self, StorageError> {
        let (db_conf, cache_conf, encryption_key, cache_error_signal, inmemory_cache_stream) =
            config;
        if test_transaction {
            Self::test_store(db_conf, tenant_config, &cache_conf, encryption_key)
                .await
                .attach_printable("failed to create test router store")
        } else {
            Self::from_config(
                db_conf,
                tenant_config,
                encryption_key,
                Self::cache_store(&cache_conf, cache_error_signal).await?,
                inmemory_cache_stream,
            )
            .await
            .attach_printable("failed to create store")
        }
    }
    fn get_master_pool(&self) -> &PgPool {
        self.db_store.get_master_pool()
    }
    fn get_replica_pool(&self) -> &PgPool {
        self.db_store.get_replica_pool()
    }

    fn get_accounts_master_pool(&self) -> &PgPool {
        self.db_store.get_accounts_master_pool()
    }

    fn get_accounts_replica_pool(&self) -> &PgPool {
        self.db_store.get_accounts_replica_pool()
    }
}

impl<T: DatabaseStore> RedisConnInterface for RouterStore<T> {
    fn get_redis_conn(&self) -> error_stack::Result<Arc<RedisConnectionPool>, RedisError> {
        self.cache_store.get_redis_conn()
    }
}

impl<T: DatabaseStore> RouterStore<T> {
    pub async fn from_config(
        db_conf: T::Config,
        tenant_config: &dyn config::TenantConfig,
        encryption_key: StrongSecret<Vec<u8>>,
        cache_store: Arc<RedisStore>,
        inmemory_cache_stream: &str,
    ) -> error_stack::Result<Self, StorageError> {
        let db_store = T::new(db_conf, tenant_config, false).await?;
        let redis_conn = cache_store.redis_conn.clone();
        let cache_store = Arc::new(RedisStore {
            redis_conn: Arc::new(RedisConnectionPool::clone(
                &redis_conn,
                tenant_config.get_redis_key_prefix(),
            )),
        });
        cache_store
            .redis_conn
            .subscribe(inmemory_cache_stream)
            .await
            .change_context(StorageError::InitializationError)
            .attach_printable("Failed to subscribe to inmemory cache stream")?;

        Ok(Self {
            db_store,
            cache_store,
            master_encryption_key: encryption_key,
            request_id: None,
        })
    }

    pub async fn cache_store(
        cache_conf: &redis_interface::RedisSettings,
        cache_error_signal: tokio::sync::oneshot::Sender<()>,
    ) -> error_stack::Result<Arc<RedisStore>, StorageError> {
        let cache_store = RedisStore::new(cache_conf)
            .await
            .change_context(StorageError::InitializationError)
            .attach_printable("Failed to create cache store")?;
        cache_store.set_error_callback(cache_error_signal);
        Ok(Arc::new(cache_store))
    }

    pub fn master_key(&self) -> &StrongSecret<Vec<u8>> {
        &self.master_encryption_key
    }

    pub async fn call_database<D, R, M>(
        &self,
        state: &KeyManagerState,
        key_store: &MerchantKeyStore,
        execute_query: R,
    ) -> error_stack::Result<D, StorageError>
    where
        D: Debug + Sync + Conversion,
        R: futures::Future<Output = error_stack::Result<M, diesel_models::errors::DatabaseError>>
            + Send,
        M: ReverseConversion<D>,
    {
        execute_query
            .await
            .map_err(|error| {
                let new_err = diesel_error_to_data_error(*error.current_context());
                error.change_context(new_err)
            })?
            .convert(
                state,
                key_store.key.get_inner(),
                key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(StorageError::DecryptionError)
    }

    pub async fn find_optional_resource<D, R, M>(
        &self,
        state: &KeyManagerState,
        key_store: &MerchantKeyStore,
        execute_query_fut: R,
    ) -> error_stack::Result<Option<D>, StorageError>
    where
        D: Debug + Sync + Conversion,
        R: futures::Future<
                Output = error_stack::Result<Option<M>, diesel_models::errors::DatabaseError>,
            > + Send,
        M: ReverseConversion<D>,
    {
        match execute_query_fut.await.map_err(|error| {
            let new_err = diesel_error_to_data_error(*error.current_context());
            error.change_context(new_err)
        })? {
            Some(resource) => Ok(Some(
                resource
                    .convert(
                        state,
                        key_store.key.get_inner(),
                        key_store.merchant_id.clone().into(),
                    )
                    .await
                    .change_context(StorageError::DecryptionError)?,
            )),
            None => Ok(None),
        }
    }

    pub async fn find_resources<D, R, M>(
        &self,
        state: &KeyManagerState,
        key_store: &MerchantKeyStore,
        execute_query: R,
    ) -> error_stack::Result<Vec<D>, StorageError>
    where
        D: Debug + Sync + Conversion,
        R: futures::Future<
                Output = error_stack::Result<Vec<M>, diesel_models::errors::DatabaseError>,
            > + Send,
        M: ReverseConversion<D>,
    {
        let resource_futures = execute_query
            .await
            .map_err(|error| {
                let new_err = diesel_error_to_data_error(*error.current_context());
                error.change_context(new_err)
            })?
            .into_iter()
            .map(|resource| async {
                resource
                    .convert(
                        state,
                        key_store.key.get_inner(),
                        key_store.merchant_id.clone().into(),
                    )
                    .await
                    .change_context(StorageError::DecryptionError)
            })
            .collect::<Vec<_>>();

        let resources = futures::future::try_join_all(resource_futures).await?;

        Ok(resources)
    }

    /// # Panics
    ///
    /// Will panic if `CONNECTOR_AUTH_FILE_PATH` is not set
    pub async fn test_store(
        db_conf: T::Config,
        tenant_config: &dyn config::TenantConfig,
        cache_conf: &redis_interface::RedisSettings,
        encryption_key: StrongSecret<Vec<u8>>,
    ) -> error_stack::Result<Self, StorageError> {
        // TODO: create an error enum and return proper error here
        let db_store = T::new(db_conf, tenant_config, true).await?;
        let cache_store = RedisStore::new(cache_conf)
            .await
            .change_context(StorageError::InitializationError)
            .attach_printable("failed to create redis cache")?;
        Ok(Self {
            db_store,
            cache_store: Arc::new(cache_store),
            master_encryption_key: encryption_key,
            request_id: None,
        })
    }
}

// TODO: This should not be used beyond this crate
// Remove the pub modified once StorageScheme usage is completed
pub trait DataModelExt {
    type StorageModel;
    fn to_storage_model(self) -> Self::StorageModel;
    fn from_storage_model(storage_model: Self::StorageModel) -> Self;
}

pub(crate) fn diesel_error_to_data_error(
    diesel_error: diesel_models::errors::DatabaseError,
) -> StorageError {
    match diesel_error {
        diesel_models::errors::DatabaseError::DatabaseConnectionError => {
            StorageError::DatabaseConnectionError
        }
        diesel_models::errors::DatabaseError::NotFound => {
            StorageError::ValueNotFound("Value not found".to_string())
        }
        diesel_models::errors::DatabaseError::UniqueViolation => StorageError::DuplicateValue {
            entity: "entity ",
            key: None,
        },
        _ => StorageError::DatabaseError(error_stack::report!(diesel_error)),
    }
}

#[async_trait::async_trait]
pub trait UniqueConstraints {
    fn unique_constraints(&self) -> Vec<String>;
    fn table_name(&self) -> &str;
    async fn check_for_constraints(
        &self,
        redis_conn: &Arc<RedisConnectionPool>,
    ) -> CustomResult<(), RedisError> {
        let constraints = self.unique_constraints();
        let sadd_result = redis_conn
            .sadd(
                &format!("unique_constraint:{}", self.table_name()).into(),
                constraints,
            )
            .await?;

        match sadd_result {
            SaddReply::KeyNotSet => Err(error_stack::report!(RedisError::SetAddMembersFailed)),
            SaddReply::KeySet => Ok(()),
        }
    }
}

impl UniqueConstraints for diesel_models::Address {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!("address_{}", self.address_id)]
    }
    fn table_name(&self) -> &str {
        "Address"
    }
}

#[cfg(feature = "v2")]
impl UniqueConstraints for diesel_models::PaymentIntent {
    fn unique_constraints(&self) -> Vec<String> {
        vec![self.id.get_string_repr().to_owned()]
    }

    fn table_name(&self) -> &str {
        "PaymentIntent"
    }
}

#[cfg(feature = "v1")]
impl UniqueConstraints for diesel_models::PaymentIntent {
    #[cfg(feature = "v1")]
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!(
            "pi_{}_{}",
            self.merchant_id.get_string_repr(),
            self.payment_id.get_string_repr()
        )]
    }

    #[cfg(feature = "v2")]
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!("pi_{}", self.id.get_string_repr())]
    }

    fn table_name(&self) -> &str {
        "PaymentIntent"
    }
}

#[cfg(feature = "v1")]
impl UniqueConstraints for diesel_models::PaymentAttempt {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!(
            "pa_{}_{}_{}",
            self.merchant_id.get_string_repr(),
            self.payment_id.get_string_repr(),
            self.attempt_id
        )]
    }
    fn table_name(&self) -> &str {
        "PaymentAttempt"
    }
}

#[cfg(feature = "v2")]
impl UniqueConstraints for diesel_models::PaymentAttempt {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!("pa_{}", self.id.get_string_repr())]
    }
    fn table_name(&self) -> &str {
        "PaymentAttempt"
    }
}

#[cfg(feature = "v1")]
impl UniqueConstraints for diesel_models::Refund {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!(
            "refund_{}_{}",
            self.merchant_id.get_string_repr(),
            self.refund_id
        )]
    }
    fn table_name(&self) -> &str {
        "Refund"
    }
}

#[cfg(feature = "v2")]
impl UniqueConstraints for diesel_models::Refund {
    fn unique_constraints(&self) -> Vec<String> {
        vec![self.id.get_string_repr().to_owned()]
    }
    fn table_name(&self) -> &str {
        "Refund"
    }
}

impl UniqueConstraints for diesel_models::ReverseLookup {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!("reverselookup_{}", self.lookup_id)]
    }
    fn table_name(&self) -> &str {
        "ReverseLookup"
    }
}

#[cfg(feature = "payouts")]
impl UniqueConstraints for diesel_models::Payouts {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!(
            "po_{}_{}",
            self.merchant_id.get_string_repr(),
            self.payout_id.get_string_repr()
        )]
    }
    fn table_name(&self) -> &str {
        "Payouts"
    }
}

#[cfg(feature = "payouts")]
impl UniqueConstraints for diesel_models::PayoutAttempt {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!(
            "poa_{}_{}",
            self.merchant_id.get_string_repr(),
            self.payout_attempt_id
        )]
    }
    fn table_name(&self) -> &str {
        "PayoutAttempt"
    }
}

#[cfg(feature = "v1")]
impl UniqueConstraints for diesel_models::PaymentMethod {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!("paymentmethod_{}", self.payment_method_id)]
    }
    fn table_name(&self) -> &str {
        "PaymentMethod"
    }
}

#[cfg(feature = "v2")]
impl UniqueConstraints for diesel_models::PaymentMethod {
    fn unique_constraints(&self) -> Vec<String> {
        vec![self.id.get_string_repr().to_owned()]
    }
    fn table_name(&self) -> &str {
        "PaymentMethod"
    }
}

impl UniqueConstraints for diesel_models::Mandate {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!(
            "mand_{}_{}",
            self.merchant_id.get_string_repr(),
            self.mandate_id
        )]
    }
    fn table_name(&self) -> &str {
        "Mandate"
    }
}

#[cfg(feature = "v1")]
impl UniqueConstraints for diesel_models::Customer {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!(
            "customer_{}_{}",
            self.customer_id.get_string_repr(),
            self.merchant_id.get_string_repr(),
        )]
    }
    fn table_name(&self) -> &str {
        "Customer"
    }
}

#[cfg(feature = "v2")]
impl UniqueConstraints for diesel_models::Customer {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!("customer_{}", self.id.get_string_repr())]
    }
    fn table_name(&self) -> &str {
        "Customer"
    }
}

#[cfg(not(feature = "payouts"))]
impl<T: DatabaseStore> PayoutAttemptInterface for RouterStore<T> {}
#[cfg(not(feature = "payouts"))]
impl<T: DatabaseStore> PayoutsInterface for RouterStore<T> {}

#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
impl UniqueConstraints for diesel_models::tokenization::Tokenization {
    fn unique_constraints(&self) -> Vec<String> {
        vec![format!("id_{}", self.id.get_string_repr())]
    }

    fn table_name(&self) -> &str {
        "tokenization"
    }
}


/// set response status code
    pub fn set_status_code(&mut self, code: u16) {
        self.status_code = Some(code);
    }


Web Documentation: 3DS / Strong Customer Authentication | Hyperswitch
# Type: Web Doc

3D Secure (3DS) is a robust security protocol designed to prevent fraud in card-not-present transactions. By employing multi-factor authentication mechanisms such as biometrics or OTPs, 3DS helps issuers verify the authenticity of transactions.
The
Hyperswitch 3DS Decision Manager
allows merchants to define advanced rules based on payment parameters, ensuring that 3DS authentication is selectively enforced for high-risk transactions.
Benefits of Using the 3DS Decision Manager:
Fraud Reduction:
Enforce 3DS on high-risk transactions to mitigate fraudulent activities.
Enhanced Compliance:
Meet regulatory requirements for Strong Customer Authentication (SCA) in regions like the EEA.
Improved Customer Experience:
Apply 3DS only when necessary, minimizing friction during checkout for low-risk transactions.
Hyperswitch 3DS Decision Manager allows the merchant to configure advanced rules using various payment parameters such as amount, currency etc., to enforce 3D Secure authentication for card payments to reduce fraudulent transactions.
How does it work?
3DS Decision Flow:
Hyperswitch integrates with multiple payment processors, enabling seamless 3D Secure authentication.
The
3DS Decision Manager
in the Hyperswitch Control Center provides merchants with a rule-based interface to enforce authentication selectively.
For example: If you wish to enforce 3DS for transactions over $100, you can define a rule that automatically sets
authentication_type
as
three_ds
for such transactions. Payments meeting this rule will trigger 3DS authentication.
Rules set in the
3DS Decision Manager
can be overridden if an explicit value is passed in the
/payments
request using the
authentication_type
parameter. (
API Reference
)
Some processors may mandate 3DS regardless of your configuration.
Get Started with 3DS Decision Manager
Test a payment
10 months ago
Was this helpful?


pub struct NetworkTokenDataForVault {
    pub network_token_data: payment_method_data::NetworkTokenData,
    pub network_token_req_ref_id: String,
}


pub fn payments_post_session_tokens() {}


File: crates/hyperswitch_connectors/src/connectors/hipay/transformers.rs
 Public structs: 14

use std::collections::HashMap;

use common_enums::{enums, CardNetwork};
use common_utils::{
    pii::{self},
    request::Method,
    types::StringMajorUnit,
};
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{
        AdditionalPaymentMethodConnectorResponse, ConnectorAuthType, ConnectorResponseData,
        ErrorResponse, PaymentMethodToken, RouterData,
    },
    router_flow_types::refunds::{Execute, RSync},
    router_request_types::{BrowserInformation, PaymentsAuthorizeData, ResponseId},
    router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData},
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsSyncRouterData, RefundsRouterData, TokenizationRouterData,
    },
};
use hyperswitch_interfaces::{
    consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE},
    errors,
};
use masking::{ExposeInterface, Secret};
use serde::{Deserialize, Serialize};

use crate::{
    types::{
        PaymentsCancelResponseRouterData, PaymentsCaptureResponseRouterData,
        PaymentsSyncResponseRouterData, RefundsResponseRouterData, ResponseRouterData,
    },
    unimplemented_payment_method,
    utils::{self, AddressDetailsData, CardData, PaymentsAuthorizeRequestData, RouterData as _},
};

pub struct HipayRouterData<T> {
    pub amount: StringMajorUnit,
    pub router_data: T,
}

impl<T> From<(StringMajorUnit, T)> for HipayRouterData<T> {
    fn from((amount, item): (StringMajorUnit, T)) -> Self {
        Self {
            amount,
            router_data: item,
        }
    }
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Operation {
    Authorization,
    Sale,
    Capture,
    Refund,
    Cancel,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct HipayBrowserInfo {
    java_enabled: Option<bool>,
    javascript_enabled: Option<bool>,
    ipaddr: Option<std::net::IpAddr>,
    http_accept: String,
    http_user_agent: Option<String>,
    language: Option<String>,
    color_depth: Option<u8>,
    screen_height: Option<u32>,
    screen_width: Option<u32>,
    timezone: Option<i32>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct HipayPaymentsRequest {
    operation: Operation,
    authentication_indicator: u8,
    cardtoken: Secret<String>,
    orderid: String,
    currency: enums::Currency,
    payment_product: String,
    amount: StringMajorUnit,
    description: String,
    decline_url: Option<String>,
    pending_url: Option<String>,
    cancel_url: Option<String>,
    accept_url: Option<String>,
    notify_url: Option<String>,
    #[serde(flatten)]
    #[serde(skip_serializing_if = "Option::is_none")]
    three_ds_data: Option<ThreeDSPaymentData>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ThreeDSPaymentData {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub firstname: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub lastname: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub email: Option<pii::Email>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub streetaddress: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub city: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub zipcode: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state: Option<Secret<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub country: Option<enums::CountryAlpha2>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub browser_info: Option<HipayBrowserInfo>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct HipayMaintenanceRequest {
    operation: Operation,
    currency: Option<enums::Currency>,
    amount: Option<StringMajorUnit>,
}
impl From<BrowserInformation> for HipayBrowserInfo {
    fn from(browser_info: BrowserInformation) -> Self {
        Self {
            java_enabled: browser_info.java_enabled,
            javascript_enabled: browser_info.java_script_enabled,
            ipaddr: browser_info.ip_address,
            http_accept: "*/*".to_string(),
            http_user_agent: browser_info.user_agent,
            language: browser_info.language,
            color_depth: browser_info.color_depth,
            screen_height: browser_info.screen_height,
            screen_width: browser_info.screen_width,
            timezone: browser_info.time_zone,
        }
    }
}

#[derive(Default, Debug, Serialize, Deserialize)]
pub struct HiPayTokenRequest {
    pub card_number: cards::CardNumber,
    pub card_expiry_month: Secret<String>,
    pub card_expiry_year: Secret<String>,
    pub card_holder: Secret<String>,
    pub cvc: Secret<String>,
}
impl TryFrom<&HipayRouterData<&PaymentsAuthorizeRouterData>> for HipayPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(item: &HipayRouterData<&PaymentsAuthorizeRouterData>) -> Result<Self, Self::Error> {
        let (domestic_card_network, domestic_network) = item
            .router_data
            .connector_response
            .clone()
            .and_then(|response| match response.additional_payment_method_data {
                Some(AdditionalPaymentMethodConnectorResponse::Card {
                    card_network,
                    domestic_network,
                    ..
                }) => Some((card_network, domestic_network)),
                _ => None,
            })
            .unwrap_or_default();

        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(req_card) => Ok(Self {
                operation: if item.router_data.request.is_auto_capture()? {
                    Operation::Sale
                } else {
                    Operation::Authorization
                },
                authentication_indicator: if item.router_data.is_three_ds() { 2 } else { 0 },
                cardtoken: match item.router_data.get_payment_method_token()? {
                    PaymentMethodToken::Token(token) => token,
                    PaymentMethodToken::ApplePayDecrypt(_) => {
                        return Err(unimplemented_payment_method!("Apple Pay", "Hipay").into());
                    }
                    PaymentMethodToken::PazeDecrypt(_) => {
                        return Err(unimplemented_payment_method!("Paze", "Hipay").into());
                    }
                    PaymentMethodToken::GooglePayDecrypt(_) => {
                        return Err(unimplemented_payment_method!("Google Pay", "Hipay").into());
                    }
                },
                orderid: item.router_data.connector_request_reference_id.clone(),
                currency: item.router_data.request.currency,
                payment_product: match (domestic_network, domestic_card_network.as_deref()) {
                    (Some(domestic), _) => domestic,
                    (None, Some("VISA")) => "visa".to_string(),
                    (None, Some("MASTERCARD")) => "mastercard".to_string(),
                    (None, Some("MAESTRO")) => "maestro".to_string(),
                    (None, Some("AMERICAN EXPRESS")) => "american-express".to_string(),
                    (None, Some("CB")) => "cb".to_string(),
                    (None, Some("BCMC")) => "bcmc".to_string(),
                    (None, _) => match req_card.card_network {
                        Some(CardNetwork::Visa) => "visa".to_string(),
                        Some(CardNetwork::Mastercard) => "mastercard".to_string(),
                        Some(CardNetwork::AmericanExpress) => "american-express".to_string(),
                        Some(CardNetwork::JCB) => "jcb".to_string(),
                        Some(CardNetwork::DinersClub) => "diners".to_string(),
                        Some(CardNetwork::Discover) => "discover".to_string(),
                        Some(CardNetwork::CartesBancaires) => "cb".to_string(),
                        Some(CardNetwork::UnionPay) => "unionpay".to_string(),
                        Some(CardNetwork::Interac) => "interac".to_string(),
                        Some(CardNetwork::RuPay) => "rupay".to_string(),
                        Some(CardNetwork::Maestro) => "maestro".to_string(),
                        Some(CardNetwork::Star)
                        | Some(CardNetwork::Accel)
                        | Some(CardNetwork::Pulse)
                        | Some(CardNetwork::Nyce)
                        | None => "".to_string(),
                    },
                },
                amount: item.amount.clone(),
                description: item
                    .router_data
                    .get_description()
                    .map(|s| s.to_string())
                    .unwrap_or("Short Description".to_string()),
                decline_url: item.router_data.request.router_return_url.clone(),
                pending_url: item.router_data.request.router_return_url.clone(),
                cancel_url: item.router_data.request.router_return_url.clone(),
                accept_url: item.router_data.request.router_return_url.clone(),
                notify_url: item.router_data.request.router_return_url.clone(),
                three_ds_data: if item.router_data.is_three_ds() {
                    let billing_address = item.router_data.get_billing_address()?;
                    Some(ThreeDSPaymentData {
                        firstname: billing_address.get_optional_first_name(),
                        lastname: billing_address.get_optional_last_name(),
                        email: Some(
                            item.router_data
                                .get_billing_email()
                                .or(item.router_data.request.get_email())?,
                        ),
                        city: billing_address.get_optional_city(),
                        streetaddress: billing_address.get_optional_line1(),
                        zipcode: billing_address.get_optional_zip(),
                        state: billing_address.get_optional_state(),
                        country: billing_address.get_optional_country(),
                        browser_info: Some(HipayBrowserInfo::from(
                            item.router_data.request.get_browser_info()?,
                        )),
                    })
                } else {
                    None
                },
            }),
            _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
        }
    }
}
impl TryFrom<&TokenizationRouterData> for HiPayTokenRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &TokenizationRouterData) -> Result<Self, Self::Error> {
        match item.request.payment_method_data.clone() {
            PaymentMethodData::Card(card_data) => Ok(Self {
                card_number: card_data.card_number.clone(),
                card_expiry_month: card_data.card_exp_month.clone(),
                card_expiry_year: card_data.get_expiry_year_4_digit(),
                card_holder: item.get_billing_full_name()?,
                cvc: card_data.card_cvc,
            }),
            _ => Err(errors::ConnectorError::NotImplemented(
                utils::get_unimplemented_payment_method_error_message("Hipay"),
            )
            .into()),
        }
    }
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct HipayTokenResponse {
    token: Secret<String>,
    brand: String,
    domestic_network: Option<String>,
}

impl From<&HipayTokenResponse> for AdditionalPaymentMethodConnectorResponse {
    fn from(hipay_token_response: &HipayTokenResponse) -> Self {
        Self::Card {
            authentication_data: None,
            payment_checks: None,
            card_network: Some(hipay_token_response.brand.clone()),
            domestic_network: hipay_token_response.domestic_network.clone(),
        }
    }
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct HipayErrorResponse {
    pub code: u8,
    pub message: String,
    pub description: Option<String>,
}

impl<F, T> TryFrom<ResponseRouterData<F, HipayTokenResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, HipayTokenResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(PaymentsResponseData::TokenizationResponse {
                token: item.response.token.clone().expose(),
            }),
            connector_response: Some(ConnectorResponseData::with_additional_payment_method_data(
                AdditionalPaymentMethodConnectorResponse::from(&item.response),
            )),
            ..item.data
        })
    }
}

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

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

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HipayPaymentsResponse {
    status: HipayPaymentStatus,
    message: String,
    order: PaymentOrder,
    forward_url: String,
    transaction_reference: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PaymentOrder {
    id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HipayMaintenanceResponse<S> {
    status: S,
    message: String,
    transaction_reference: String,
}
impl<F>
    TryFrom<
        ResponseRouterData<F, HipayPaymentsResponse, PaymentsAuthorizeData, PaymentsResponseData>,
    > for RouterData<F, PaymentsAuthorizeData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            HipayPaymentsResponse,
            PaymentsAuthorizeData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        let status = common_enums::AttemptStatus::from(item.response.status);
        let response = if status == enums::AttemptStatus::Failure {
            Err(ErrorResponse {
                code: NO_ERROR_CODE.to_string(),
                message: item.response.message.clone(),
                reason: Some(item.response.message.clone()),
                attempt_status: None,
                connector_transaction_id: Some(item.response.transaction_reference),
                status_code: item.http_code,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        } else {
            Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.response.transaction_reference,
                ),
                redirection_data: match item.data.is_three_ds() {
                    true => Box::new(Some(RedirectForm::Form {
                        endpoint: item.response.forward_url,
                        method: Method::Get,
                        form_fields: HashMap::new(),
                    })),
                    false => 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,
            })
        };
        Ok(Self {
            status,
            response,
            ..item.data
        })
    }
}

impl<F> TryFrom<&HipayRouterData<&RefundsRouterData<F>>> for HipayMaintenanceRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &HipayRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: Some(item.amount.to_owned()),
            operation: Operation::Refund,
            currency: Some(item.router_data.request.currency),
        })
    }
}
impl TryFrom<&PaymentsCancelRouterData> for HipayMaintenanceRequest {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(item: &PaymentsCancelRouterData) -> Result<Self, Self::Error> {
        Ok(Self {
            operation: Operation::Cancel,
            currency: item.request.currency,
            amount: None,
        })
    }
}
impl TryFrom<&HipayRouterData<&PaymentsCaptureRouterData>> for HipayMaintenanceRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &HipayRouterData<&PaymentsCaptureRouterData>) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: Some(item.amount.to_owned()),
            operation: Operation::Capture,
            currency: Some(item.router_data.request.currency),
        })
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum RefundStatus {
    #[serde(rename = "124")]
    RefundRequested,
    #[serde(rename = "125")]
    Refunded,
    #[serde(rename = "126")]
    PartiallyRefunded,
    #[serde(rename = "165")]
    RefundRefused,
}

impl From<RefundStatus> for enums::RefundStatus {
    fn from(item: RefundStatus) -> Self {
        match item {
            RefundStatus::RefundRequested => Self::Pending,
            RefundStatus::Refunded | RefundStatus::PartiallyRefunded => Self::Success,
            RefundStatus::RefundRefused => Self::Failure,
        }
    }
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum HipayPaymentStatus {
    #[serde(rename = "109")]
    AuthenticationFailed,
    #[serde(rename = "110")]
    Blocked,
    #[serde(rename = "111")]
    Denied,
    #[serde(rename = "112")]
    AuthorizedAndPending,
    #[serde(rename = "113")]
    Refused,
    #[serde(rename = "114")]
    Expired,
    #[serde(rename = "115")]
    Cancelled,
    #[serde(rename = "116")]
    Authorized,
    #[serde(rename = "117")]
    CaptureRequested,
    #[serde(rename = "118")]
    Captured,
    #[serde(rename = "119")]
    PartiallyCaptured,
    #[serde(rename = "129")]
    ChargedBack,
    #[serde(rename = "173")]
    CaptureRefused,
    #[serde(rename = "174")]
    AwaitingTerminal,
    #[serde(rename = "175")]
    AuthorizationCancellationRequested,
    #[serde(rename = "177")]
    ChallengeRequested,
    #[serde(rename = "178")]
    SoftDeclined,
    #[serde(rename = "200")]
    PendingPayment,
    #[serde(rename = "101")]
    Created,
    #[serde(rename = "105")]
    UnableToAuthenticate,
    #[serde(rename = "106")]
    CardholderAuthenticated,
    #[serde(rename = "107")]
    AuthenticationAttempted,
    #[serde(rename = "108")]
    CouldNotAuthenticate,
    #[serde(rename = "120")]
    Collected,
    #[serde(rename = "121")]
    PartiallyCollected,
    #[serde(rename = "122")]
    Settled,
    #[serde(rename = "123")]
    PartiallySettled,
    #[serde(rename = "140")]
    AuthenticationRequested,
    #[serde(rename = "141")]
    Authenticated,
    #[serde(rename = "151")]
    AcquirerNotFound,
    #[serde(rename = "161")]
    RiskAccepted,
    #[serde(rename = "163")]
    AuthorizationRefused,
}
impl From<HipayPaymentStatus> for common_enums::AttemptStatus {
    fn from(status: HipayPaymentStatus) -> Self {
        match status {
            HipayPaymentStatus::AuthenticationFailed => Self::AuthenticationFailed,
            HipayPaymentStatus::Blocked
            | HipayPaymentStatus::Refused
            | HipayPaymentStatus::Expired
            | HipayPaymentStatus::Denied => Self::Failure,
            HipayPaymentStatus::AuthorizedAndPending => Self::Pending,
            HipayPaymentStatus::Cancelled => Self::Voided,
            HipayPaymentStatus::Authorized => Self::Authorized,
            HipayPaymentStatus::CaptureRequested => Self::CaptureInitiated,
            HipayPaymentStatus::Captured => Self::Charged,
            HipayPaymentStatus::PartiallyCaptured => Self::PartialCharged,
            HipayPaymentStatus::CaptureRefused => Self::CaptureFailed,
            HipayPaymentStatus::AwaitingTerminal => Self::Pending,
            HipayPaymentStatus::AuthorizationCancellationRequested => Self::VoidInitiated,
            HipayPaymentStatus::ChallengeRequested => Self::AuthenticationPending,
            HipayPaymentStatus::SoftDeclined => Self::Failure,
            HipayPaymentStatus::PendingPayment => Self::Pending,
            HipayPaymentStatus::ChargedBack => Self::Failure,
            HipayPaymentStatus::Created => Self::Started,
            HipayPaymentStatus::UnableToAuthenticate | HipayPaymentStatus::CouldNotAuthenticate => {
                Self::AuthenticationFailed
            }
            HipayPaymentStatus::CardholderAuthenticated => Self::Pending,
            HipayPaymentStatus::AuthenticationAttempted => Self::AuthenticationPending,
            HipayPaymentStatus::Collected
            | HipayPaymentStatus::PartiallySettled
            | HipayPaymentStatus::PartiallyCollected
            | HipayPaymentStatus::Settled => Self::Charged,
            HipayPaymentStatus::AuthenticationRequested => Self::AuthenticationPending,
            HipayPaymentStatus::Authenticated => Self::AuthenticationSuccessful,
            HipayPaymentStatus::AcquirerNotFound => Self::Failure,
            HipayPaymentStatus::RiskAccepted => Self::Pending,
            HipayPaymentStatus::AuthorizationRefused => Self::Failure,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RefundResponse {
    id: u64,
    status: u16,
}

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

impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for RefundsRouterData<RSync> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status: match item.response.status {
                    25 | 26 => enums::RefundStatus::Success,
                    65 => enums::RefundStatus::Failure,
                    24 => enums::RefundStatus::Pending,
                    _ => enums::RefundStatus::Pending,
                },
            }),
            ..item.data
        })
    }
}

impl TryFrom<PaymentsCaptureResponseRouterData<HipayMaintenanceResponse<HipayPaymentStatus>>>
    for PaymentsCaptureRouterData
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PaymentsCaptureResponseRouterData<HipayMaintenanceResponse<HipayPaymentStatus>>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: common_enums::AttemptStatus::from(item.response.status),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.response.transaction_reference.clone().to_string(),
                ),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}
impl TryFrom<PaymentsCancelResponseRouterData<HipayMaintenanceResponse<HipayPaymentStatus>>>
    for PaymentsCancelRouterData
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PaymentsCancelResponseRouterData<HipayMaintenanceResponse<HipayPaymentStatus>>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: common_enums::AttemptStatus::from(item.response.status),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.response.transaction_reference.clone().to_string(),
                ),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Reason {
    reason: Option<String>,
    code: Option<u64>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum HipaySyncResponse {
    Response { status: i32, reason: Reason },
    Error { message: String, code: u32 },
}
fn get_sync_status(state: i32) -> enums::AttemptStatus {
    match state {
        9 => enums::AttemptStatus::AuthenticationFailed,
        10 => enums::AttemptStatus::Failure,
        11 => enums::AttemptStatus::Failure,
        12 => enums::AttemptStatus::Pending,
        13 => enums::AttemptStatus::Failure,
        14 => enums::AttemptStatus::Failure,
        15 => enums::AttemptStatus::Voided,
        16 => enums::AttemptStatus::Authorized,
        17 => enums::AttemptStatus::CaptureInitiated,
        18 => enums::AttemptStatus::Charged,
        19 => enums::AttemptStatus::PartialCharged,
        29 => enums::AttemptStatus::Failure,
        73 => enums::AttemptStatus::CaptureFailed,
        74 => enums::AttemptStatus::Pending,
        75 => enums::AttemptStatus::VoidInitiated,
        77 => enums::AttemptStatus::AuthenticationPending,
        78 => enums::AttemptStatus::Failure,
        200 => enums::AttemptStatus::Pending,
        1 => enums::AttemptStatus::Started,
        5 => enums::AttemptStatus::AuthenticationFailed,
        6 => enums::AttemptStatus::Pending,
        7 => enums::AttemptStatus::AuthenticationPending,
        8 => enums::AttemptStatus::AuthenticationFailed,
        20 => enums::AttemptStatus::Charged,
        21 => enums::AttemptStatus::Charged,
        22 => enums::AttemptStatus::Charged,
        23 => enums::AttemptStatus::Charged,
        40 => enums::AttemptStatus::AuthenticationPending,
        41 => enums::AttemptStatus::AuthenticationSuccessful,
        51 => enums::AttemptStatus::Failure,
        61 => enums::AttemptStatus::Pending,
        63 => enums::AttemptStatus::Failure,
        _ => enums::AttemptStatus::Failure,
    }
}

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

    fn try_from(
        item: PaymentsSyncResponseRouterData<HipaySyncResponse>,
    ) -> Result<Self, Self::Error> {
        match item.response {
            HipaySyncResponse::Error { message, code } => {
                let response = Err(ErrorResponse {
                    code: code.to_string(),
                    message: message.clone(),
                    reason: Some(message.clone()),
                    attempt_status: None,
                    connector_transaction_id: None,
                    status_code: item.http_code,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                });
                Ok(Self {
                    status: enums::AttemptStatus::Failure,
                    response,
                    ..item.data
                })
            }
            HipaySyncResponse::Response { status, reason } => {
                let status = get_sync_status(status);
                let response = if status == enums::AttemptStatus::Failure {
                    let error_code = reason
                        .code
                        .map_or(NO_ERROR_CODE.to_string(), |c| c.to_string());
                    let error_message = reason
                        .reason
                        .clone()
                        .unwrap_or_else(|| NO_ERROR_MESSAGE.to_owned());
                    Err(ErrorResponse {
                        code: error_code,
                        message: error_message.clone(),
                        reason: Some(error_message),
                        status_code: item.http_code,
                        attempt_status: None,
                        connector_transaction_id: None,
                        network_advice_code: None,
                        network_decline_code: None,
                        network_error_message: None,
                        connector_metadata: None,
                    })
                } else {
                    Ok(PaymentsResponseData::TransactionResponse {
                        resource_id: ResponseId::NoResponseId,
                        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,
                    })
                };
                Ok(Self {
                    status,
                    response,
                    ..item.data
                })
            }
        }
    }
}


impl api::PaymentAuthorize for Affirm {}

impl api::PaymentAuthorize for for Affirm


File: crates/analytics/src/refunds/distribution/sessionized_distribution.rs

mod refund_error_message;
mod refund_reason;

pub(super) use refund_error_message::RefundErrorMessage;
pub(super) use refund_reason::RefundReason;

pub use super::{RefundDistribution, RefundDistributionAnalytics, RefundDistributionRow};


impl ConnectorValidation for Archipel {
    fn validate_mandate_payment(
        &self,
        pm_type: Option<enums::PaymentMethodType>,
        pm_data: PaymentMethodData,
    ) -> CustomResult<(), errors::ConnectorError> {
        let mandate_supported_pmd = std::collections::HashSet::from([PaymentMethodDataType::Card]);

        is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id())
    }
}

impl ConnectorValidation for for Archipel


impl Responder {
    let flow = Flow::PaymentLinkRetrieve;
    let payload = json_payload.into_inner();
    let api_auth = auth::ApiKeyAuth::default();

    let (auth_type, _) =
        match auth::check_client_secret_and_get_auth(req.headers(), &payload, api_auth) {
            Ok(auth) => auth,
            Err(err) => return api::log_and_return_error_response(error_stack::report!(err)),
        };

    api::server_wrap(
        flow,
        state,
        &req,
        payload.clone(),
        |state, _auth, _, _| retrieve_payment_link(state, path.clone()),
        &*auth_type,
        api_locking::LockAction::NotApplicable,
    )
    .await
}


pub fn server(state: AppState) -> Scope {
        let mut route = web::scope("/v2/payment-method-sessions").app_data(web::Data::new(state));
        route = route.service(
            web::resource("")
                .route(web::post().to(payment_methods::payment_methods_session_create)),
        );

        route =
            route.service(
                web::scope("/{payment_method_session_id}")
                    .service(
                        web::resource("")
                            .route(web::get().to(payment_methods::payment_methods_session_retrieve))
                            .route(web::put().to(payment_methods::payment_methods_session_update))
                            .route(web::delete().to(
                                payment_methods::payment_method_session_delete_saved_payment_method,
                            )),
                    )
                    .service(web::resource("/list-payment-methods").route(
                        web::get().to(payment_methods::payment_method_session_list_payment_methods),
                    ))
                    .service(
                        web::resource("/confirm")
                            .route(web::post().to(payment_methods::payment_method_session_confirm)),
                    )
                    .service(web::resource("/update-saved-payment-method").route(
                        web::put().to(
                            payment_methods::payment_method_session_update_saved_payment_method,
                        ),
                    )),
            );

        route
    }


pub struct SantanderPix {
    pub end_to_end_id: Secret<String>,
    #[serde(rename = "txid")]
    pub transaction_id: Secret<String>,
    #[serde(rename = "valor")]
    pub value: String,
    #[serde(rename = "horario")]
    pub time: String,
    #[serde(rename = "infoPagador")]
    pub info_payer: Option<String>,
}


pub struct JuspaythreedsserverCard {
    number: cards::CardNumber,
    expiry_month: Secret<String>,
    expiry_year: Secret<String>,
    cvc: Secret<String>,
    complete: bool,
}


impl api::Payment for Paysafe {}


impl GetAuthType for ApiKeyAuth {
    fn get_auth_type(&self) -> detached::PayloadType {
        detached::PayloadType::ApiKey
    }
}


pub async fn custom_revenue_recovery_core(
    state: SessionState,
    req_state: ReqState,
    merchant_context: MerchantContext,
    profile: domain::Profile,
    request: api_models::payments::RecoveryPaymentsCreate,
) -> RouterResponse<payments_api::RecoveryPaymentsResponse> {
    let store = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let payment_merchant_connector_account_id = request.payment_merchant_connector_id.to_owned();
    // Find the payment & billing merchant connector id at the top level to avoid multiple DB calls.
    let payment_merchant_connector_account = store
        .find_merchant_connector_account_by_id(
            key_manager_state,
            &payment_merchant_connector_account_id,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: payment_merchant_connector_account_id
                .clone()
                .get_string_repr()
                .to_string(),
        })?;
    let billing_connector_account = store
        .find_merchant_connector_account_by_id(
            key_manager_state,
            &request.billing_merchant_connector_id.clone(),
            merchant_context.get_merchant_key_store(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: request
                .billing_merchant_connector_id
                .clone()
                .get_string_repr()
                .to_string(),
        })?;

    let recovery_intent =
        recovery_incoming::RevenueRecoveryInvoice::get_or_create_custom_recovery_intent(
            request.clone(),
            &state,
            &req_state,
            &merchant_context,
            &profile,
        )
        .await
        .change_context(errors::ApiErrorResponse::GenericNotFoundError {
            message: format!(
                "Failed to load recovery intent for merchant reference id : {:?}",
                request.merchant_reference_id.to_owned()
            )
            .to_string(),
        })?;

    let (revenue_recovery_attempt_data, updated_recovery_intent) =
        recovery_incoming::RevenueRecoveryAttempt::load_recovery_attempt_from_api(
            request.clone(),
            &state,
            &req_state,
            &merchant_context,
            &profile,
            recovery_intent.clone(),
            payment_merchant_connector_account,
        )
        .await
        .change_context(errors::ApiErrorResponse::GenericNotFoundError {
            message: format!(
                "Failed to load recovery attempt for merchant reference id : {:?}",
                request.merchant_reference_id.to_owned()
            )
            .to_string(),
        })?;

    let intent_retry_count = updated_recovery_intent
        .feature_metadata
        .as_ref()
        .and_then(|metadata| metadata.get_retry_count())
        .ok_or(report!(errors::ApiErrorResponse::GenericNotFoundError {
            message: "Failed to fetch retry count from intent feature metadata".to_string(),
        }))?;

    router_env::logger::info!("Intent retry count: {:?}", intent_retry_count);
    let recovery_action = recovery_incoming::RecoveryAction {
        action: request.action.to_owned(),
    };
    let mca_retry_threshold = billing_connector_account
        .get_retry_threshold()
        .ok_or(report!(errors::ApiErrorResponse::GenericNotFoundError {
            message: "Failed to fetch retry threshold from billing merchant connector account"
                .to_string(),
        }))?;

    recovery_action
        .handle_action(
            &state,
            &profile,
            &merchant_context,
            &billing_connector_account,
            mca_retry_threshold,
            intent_retry_count,
            &(
                Some(revenue_recovery_attempt_data),
                updated_recovery_intent.clone(),
            ),
        )
        .await
        .change_context(errors::ApiErrorResponse::GenericNotFoundError {
            message: "Unexpected response from recovery core".to_string(),
        })?;

    let response = api_models::payments::RecoveryPaymentsResponse {
        id: updated_recovery_intent.payment_id.to_owned(),
        intent_status: updated_recovery_intent.status.to_owned(),
        merchant_reference_id: updated_recovery_intent.merchant_reference_id.to_owned(),
    };

    Ok(hyperswitch_domain_models::api::ApplicationResponse::Json(
        response,
    ))
}


pub struct RoutingRetrieveLinkQueryWrapper {
    pub routing_query: RoutingRetrieveQuery,
    pub profile_id: common_utils::id_type::ProfileId,
}


pub struct RoleInfoResponseNew {
    pub role_id: String,
    pub role_name: String,
    pub entity_type: EntityType,
    pub groups: Vec<PermissionGroup>,
    pub scope: RoleScope,
}


impl ConnectorRedirectResponse for Payme {
    fn get_flow_type(
        &self,
        _query_params: &str,
        _json_payload: Option<serde_json::Value>,
        action: enums::PaymentAction,
    ) -> CustomResult<enums::CallConnectorAction, errors::ConnectorError> {
        match action {
            enums::PaymentAction::PSync
            | enums::PaymentAction::CompleteAuthorize
            | enums::PaymentAction::PaymentAuthenticateCompleteAuthorize => {
                Ok(enums::CallConnectorAction::Trigger)
            }
        }
    }
}

impl ConnectorRedirectResponse for for Payme


OpenAPI Block Path: components.schemas.CryptoResponse
{
  "allOf": [
    {
      "allOf": [
        {
          "$ref": "#/components/schemas/CryptoData"
        }
      ],
      "nullable": true
    },
    {
      "type": "object"
    }
  ]
}


pub async fn get_gsm_record(
    state: &SessionState,
    error_code: Option<String>,
    error_message: Option<String>,
    connector_name: Option<String>,
    flow: &str,
) -> Option<hyperswitch_domain_models::gsm::GatewayStatusMap> {
    let connector_name = connector_name.unwrap_or_default();
    let get_gsm = || async {
        state.store.find_gsm_rule(
                connector_name.clone(),
                flow.to_string(),
                "sub_flow".to_string(),
                error_code.clone().unwrap_or_default(), // TODO: make changes in connector to get a mandatory code in case of success or error response
                error_message.clone().unwrap_or_default(),
            )
            .await
            .map_err(|err| {
                if err.current_context().is_db_not_found() {
                    logger::warn!(
                        "GSM miss for connector - {}, flow - {}, error_code - {:?}, error_message - {:?}",
                        connector_name,
                        flow,
                        error_code,
                        error_message
                    );
                    metrics::AUTO_PAYOUT_RETRY_GSM_MISS_COUNT.add( 1, &[]);
                } else {
                    metrics::AUTO_PAYOUT_RETRY_GSM_FETCH_FAILURE_COUNT.add( 1, &[]);
                };
                err.change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("failed to fetch decision from gsm")
            })
    };
    get_gsm()
        .await
        .inspect_err(|err| {
            // warn log should suffice here because we are not propagating this error
            logger::warn!(get_gsm_decision_fetch_error=?err, "error fetching gsm decision");
        })
        .ok()
}


pub struct MerchantId(String);


pub struct RefundsLedger {
    pub amount: f64,
    #[serde(rename = "assoc_transaction_id")]
    pub associated_transaction_id: String, // Connector transaction id
    #[serde(rename = "id")]
    pub ledger_id: Secret<String>,
}


pub fn percentage(input: &str) -> ParseResult<&str, u8> {
    error::context(
        "volume_split_percentage",
        combinator::map_res(
            sequence::terminated(
                complete::take_while_m_n(1, 2, |c: char| c.is_ascii_digit()),
                complete::tag("%"),
            ),
            |o: &str| {
                o.parse::<u8>()
                    .map_err(|_| EuclidError::InvalidPercentage(o.to_string()))
            },
        ),
    )(input)
}


pub struct AuthenticationConnectorData {
    pub connector: ConnectorEnum,
    pub connector_name: enums::AuthenticationConnectors,
}


pub struct SantanderWebhookBody {
    pub message: MessageCode,   // meaning of this enum variant is not clear
    pub function: FunctionType, // event type of the webhook
    pub payment_type: WebhookPaymentType,
    pub issue_date: String,
    pub payment_date: String,
    pub bank_code: String,
    pub payment_channel: PaymentChannel,
    pub payment_kind: PaymentKind,
    pub covenant: String,
    pub type_of_person_agreement: enums::DocumentKind,
    pub agreement_document: String,
    pub bank_number: String,
    pub client_number: String,
    pub participant_code: String,
    pub tx_id: String,
    pub payer_document_type: enums::DocumentKind,
    pub payer_document_number: String,
    pub payer_name: String,
    pub final_beneficiary_document_type: enums::DocumentKind,
    pub final_beneficiary_document_number: String,
    pub final_beneficiary_name: String,
    pub due_date: String,
    pub nominal_value: StringMajorUnit,
    pub payed_value: String,
    pub interest_value: String,
    pub fine: String,
    pub deduction_value: String,
    pub rebate_value: String,
    pub iof_value: String,
}


pub fn validate_dummy_connector_create(self, is_dummy_connector_enabled: bool) -> bool {
        matches!(
            self,
            Self::DummyConnector1
                | Self::DummyConnector2
                | Self::DummyConnector3
                | Self::DummyConnector4
                | Self::DummyConnector5
                | Self::DummyConnector6
                | Self::DummyConnector7
        ) && !is_dummy_connector_enabled
    }


pub fn transform_to_sql_values(&mut self, values: &[impl ToSql<T>]) -> QueryResult<String> {
        let res = values
            .iter()
            .map(|i| i.to_sql(&self.table_engine))
            .collect::<error_stack::Result<Vec<String>, ParsingError>>()
            .change_context(QueryBuildingError::SqlSerializeError)
            .attach_printable("Error serializing range filter value")?
            .join(", ");
        Ok(res)
    }


pub async fn check_if_profile_id_is_present_in_payment_intent(
    payment_id: PaymentId,
    state: &SessionState,
    auth_data: &AuthenticationData,
) -> CustomResult<(), errors::ApiErrorResponse> {
    todo!()
}


pub struct MandateDetails {
    #[serde(rename = "type")]
    pub res_type: String,
    pub alias: String,
    pub expiry_month: Secret<String>,
    pub expiry_year: Secret<String>,
}


pub struct PayboxRsyncRequest {
    #[serde(rename = "DATEQ")]
    pub date: String,

    #[serde(rename = "TYPE")]
    pub transaction_type: String,

    #[serde(rename = "NUMQUESTION")]
    pub paybox_request_number: String,

    #[serde(rename = "VERSION")]
    pub version: String,

    #[serde(rename = "SITE")]
    pub site: Secret<String>,

    #[serde(rename = "RANG")]
    pub rank: Secret<String>,

    #[serde(rename = "CLE")]
    pub key: Secret<String>,

    #[serde(rename = "NUMTRANS")]
    pub transaction_number: String,

    #[serde(rename = "NUMAPPEL")]
    pub paybox_order_id: String,
}


OpenAPI Block Path: components.schemas.PaymentsRequest
{
  "type": "object",
  "properties": {
    "amount": {
      "type": "integer",
      "format": "int64",
      "description": "The primary amount for the payment, provided in the lowest denomination of the specified currency (e.g., 6540 for $65.40 USD). This field is mandatory for creating a payment.",
      "example": 6540,
      "nullable": true,
      "minimum": 0
    },
    "order_tax_amount": {
      "type": "integer",
      "format": "int64",
      "description": "Total tax amount applicable to the order, in the lowest denomination of the currency.",
      "example": 6540,
      "nullable": true
    },
    "currency": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Currency"
        }
      ],
      "nullable": true
    },
    "amount_to_capture": {
      "type": "integer",
      "format": "int64",
      "description": "The amount to be captured from the user's payment method, in the lowest denomination. If not provided, and `capture_method` is `automatic`, the full payment `amount` will be captured. If `capture_method` is `manual`, this can be specified in the `/capture` call. Must be less than or equal to the authorized amount.",
      "example": 6540,
      "nullable": true
    },
    "shipping_cost": {
      "type": "integer",
      "format": "int64",
      "description": "The shipping cost for the payment. This is required for tax calculation in some regions.",
      "example": 6540,
      "nullable": true
    },
    "payment_id": {
      "type": "string",
      "description": "Optional. A merchant-provided unique identifier for the payment, contains 30 characters long (e.g., \"pay_mbabizu24mvu3mela5njyhpit4\"). If provided, it ensures idempotency for the payment creation request. If omitted, Hyperswitch generates a unique ID for the payment.",
      "example": "pay_mbabizu24mvu3mela5njyhpit4",
      "nullable": true,
      "maxLength": 30,
      "minLength": 30
    },
    "merchant_id": {
      "type": "string",
      "description": "This is an identifier for the merchant account. This is inferred from the API key\nprovided during the request",
      "example": "merchant_1668273825",
      "nullable": true,
      "maxLength": 255
    },
    "routing": {
      "allOf": [
        {
          "$ref": "#/components/schemas/StraightThroughAlgorithm"
        }
      ],
      "nullable": true
    },
    "connector": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/Connector"
      },
      "description": "This allows to manually select a connector with which the payment can go through.",
      "example": [
        "stripe",
        "adyen"
      ],
      "nullable": true
    },
    "capture_method": {
      "allOf": [
        {
          "$ref": "#/components/schemas/CaptureMethod"
        }
      ],
      "nullable": true
    },
    "authentication_type": {
      "allOf": [
        {
          "$ref": "#/components/schemas/AuthenticationType"
        }
      ],
      "default": "three_ds",
      "nullable": true
    },
    "billing": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Address"
        }
      ],
      "nullable": true
    },
    "capture_on": {
      "type": "string",
      "format": "date-time",
      "description": "A timestamp (ISO 8601 code) that determines when the payment should be captured.\nProviding this field will automatically set `capture` to true",
      "example": "2022-09-10T10:11:12Z",
      "nullable": true
    },
    "confirm": {
      "type": "boolean",
      "description": "If set to `true`, Hyperswitch attempts to confirm and authorize the payment immediately after creation, provided sufficient payment method details are included. If `false` or omitted (default is `false`), the payment is created with a status such as `requires_payment_method` or `requires_confirmation`, and a separate `POST /payments/{payment_id}/confirm` call is necessary to proceed with authorization.",
      "default": false,
      "example": true,
      "nullable": true
    },
    "customer": {
      "allOf": [
        {
          "$ref": "#/components/schemas/CustomerDetails"
        }
      ],
      "nullable": true
    },
    "customer_id": {
      "type": "string",
      "description": "The identifier for the customer",
      "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44",
      "nullable": true,
      "maxLength": 64,
      "minLength": 1
    },
    "email": {
      "type": "string",
      "description": "The customer's email address.\nThis field will be deprecated soon, use the customer object instead",
      "deprecated": true,
      "example": "johntest@test.com",
      "nullable": true,
      "maxLength": 255
    },
    "name": {
      "type": "string",
      "description": "The customer's name.\nThis field will be deprecated soon, use the customer object instead.",
      "deprecated": true,
      "example": "John Test",
      "nullable": true,
      "maxLength": 255
    },
    "phone": {
      "type": "string",
      "description": "The customer's phone number\nThis field will be deprecated soon, use the customer object instead",
      "deprecated": true,
      "example": "9123456789",
      "nullable": true,
      "maxLength": 255
    },
    "phone_country_code": {
      "type": "string",
      "description": "The country code for the customer phone number\nThis field will be deprecated soon, use the customer object instead",
      "deprecated": true,
      "example": "+1",
      "nullable": true,
      "maxLength": 255
    },
    "off_session": {
      "type": "boolean",
      "description": "Set to true to indicate that the customer is not in your checkout flow during this payment, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. When making a recurring payment by passing a mandate_id, this parameter is mandatory",
      "example": true,
      "nullable": true
    },
    "description": {
      "type": "string",
      "description": "An arbitrary string attached to the payment. Often useful for displaying to users or for your own internal record-keeping.",
      "example": "It's my first payment request",
      "nullable": true
    },
    "return_url": {
      "type": "string",
      "description": "The URL to redirect the customer to after they complete the payment process or authentication. This is crucial for flows that involve off-site redirection (e.g., 3DS, some bank redirects, wallet payments).",
      "example": "https://hyperswitch.io",
      "nullable": true,
      "maxLength": 2048
    },
    "setup_future_usage": {
      "allOf": [
        {
          "$ref": "#/components/schemas/FutureUsage"
        }
      ],
      "nullable": true
    },
    "payment_method_data": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentMethodDataRequest"
        }
      ],
      "nullable": true
    },
    "payment_method": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentMethod"
        }
      ],
      "nullable": true
    },
    "payment_token": {
      "type": "string",
      "description": "As Hyperswitch tokenises the sensitive details about the payments method, it provides the payment_token as a reference to a stored payment method, ensuring that the sensitive details are not exposed in any manner.",
      "example": "187282ab-40ef-47a9-9206-5099ba31e432",
      "nullable": true
    },
    "card_cvc": {
      "type": "string",
      "description": "This is used along with the payment_token field while collecting during saved card payments. This field will be deprecated soon, use the payment_method_data.card_token object instead",
      "deprecated": true,
      "nullable": true
    },
    "shipping": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Address"
        }
      ],
      "nullable": true
    },
    "statement_descriptor_name": {
      "type": "string",
      "description": "For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.",
      "example": "Hyperswitch Router",
      "nullable": true,
      "maxLength": 255
    },
    "statement_descriptor_suffix": {
      "type": "string",
      "description": "Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor.",
      "example": "Payment for shoes purchase",
      "nullable": true,
      "maxLength": 255
    },
    "order_details": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/OrderDetailsWithAmount"
      },
      "description": "Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount",
      "example": "[{\n        \"product_name\": \"Apple iPhone 16\",\n        \"quantity\": 1,\n        \"amount\" : 69000\n        \"product_img_link\" : \"https://dummy-img-link.com\"\n    }]",
      "nullable": true
    },
    "client_secret": {
      "type": "string",
      "description": "It's a token used for client side verification.",
      "example": "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo",
      "nullable": true
    },
    "mandate_data": {
      "allOf": [
        {
          "$ref": "#/components/schemas/MandateData"
        }
      ],
      "nullable": true
    },
    "customer_acceptance": {
      "allOf": [
        {
          "$ref": "#/components/schemas/CustomerAcceptance"
        }
      ],
      "nullable": true
    },
    "mandate_id": {
      "type": "string",
      "description": "A unique identifier to link the payment to a mandate. To do Recurring payments after a mandate has been created, pass the mandate_id instead of payment_method_data",
      "example": "mandate_iwer89rnjef349dni3",
      "nullable": true,
      "maxLength": 64
    },
    "browser_info": {
      "allOf": [
        {
          "$ref": "#/components/schemas/BrowserInformation"
        }
      ],
      "nullable": true
    },
    "payment_experience": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentExperience"
        }
      ],
      "nullable": true
    },
    "payment_method_type": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentMethodType"
        }
      ],
      "nullable": true
    },
    "business_country": {
      "allOf": [
        {
          "$ref": "#/components/schemas/CountryAlpha2"
        }
      ],
      "nullable": true
    },
    "business_label": {
      "type": "string",
      "description": "Business label of the merchant for this payment.\nTo be deprecated soon. Pass the profile_id instead",
      "example": "food",
      "nullable": true
    },
    "merchant_connector_details": {
      "allOf": [
        {
          "$ref": "#/components/schemas/MerchantConnectorDetailsWrap"
        }
      ],
      "nullable": true
    },
    "allowed_payment_method_types": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/PaymentMethodType"
      },
      "description": "Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent",
      "nullable": true
    },
    "business_sub_label": {
      "type": "string",
      "description": "Business sub label for the payment",
      "nullable": true
    },
    "retry_action": {
      "allOf": [
        {
          "$ref": "#/components/schemas/RetryAction"
        }
      ],
      "nullable": true
    },
    "metadata": {
      "type": "object",
      "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.",
      "nullable": true
    },
    "connector_metadata": {
      "allOf": [
        {
          "$ref": "#/components/schemas/ConnectorMetadata"
        }
      ],
      "nullable": true
    },
    "feature_metadata": {
      "allOf": [
        {
          "$ref": "#/components/schemas/FeatureMetadata"
        }
      ],
      "nullable": true
    },
    "payment_link": {
      "type": "boolean",
      "description": "Whether to generate the payment link for this payment or not (if applicable)",
      "default": false,
      "example": true,
      "nullable": true
    },
    "payment_link_config": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentCreatePaymentLinkConfig"
        }
      ],
      "nullable": true
    },
    "payment_link_config_id": {
      "type": "string",
      "description": "Custom payment link config id set at business profile, send only if business_specific_configs is configured",
      "nullable": true
    },
    "profile_id": {
      "type": "string",
      "description": "The business profile to be used for this payment, if not passed the default business profile associated with the merchant account will be used. It is mandatory in case multiple business profiles have been set up.",
      "nullable": true
    },
    "surcharge_details": {
      "allOf": [
        {
          "$ref": "#/components/schemas/RequestSurchargeDetails"
        }
      ],
      "nullable": true
    },
    "payment_type": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentType"
        }
      ],
      "nullable": true
    },
    "request_incremental_authorization": {
      "type": "boolean",
      "description": "Request an incremental authorization, i.e., increase the authorized amount on a confirmed payment before you capture it.",
      "nullable": true
    },
    "session_expiry": {
      "type": "integer",
      "format": "int32",
      "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds\n(900) for 15 mins",
      "example": 900,
      "nullable": true,
      "minimum": 0
    },
    "frm_metadata": {
      "type": "object",
      "description": "Additional data related to some frm(Fraud Risk Management) connectors",
      "nullable": true
    },
    "request_external_three_ds_authentication": {
      "type": "boolean",
      "description": "Whether to perform external authentication (if applicable)",
      "example": true,
      "nullable": true
    },
    "recurring_details": {
      "allOf": [
        {
          "$ref": "#/components/schemas/RecurringDetails"
        }
      ],
      "nullable": true
    },
    "split_payments": {
      "allOf": [
        {
          "$ref": "#/components/schemas/SplitPaymentsRequest"
        }
      ],
      "nullable": true
    },
    "request_extended_authorization": {
      "type": "boolean",
      "description": "Optional boolean value to extent authorization period of this payment\n\ncapture method must be manual or manual_multiple",
      "default": false,
      "nullable": true
    },
    "merchant_order_reference_id": {
      "type": "string",
      "description": "Your unique identifier for this payment or order. This ID helps you reconcile payments on your system. If provided, it is passed to the connector if supported.",
      "example": "Custom_Order_id_123",
      "nullable": true,
      "maxLength": 255
    },
    "skip_external_tax_calculation": {
      "type": "boolean",
      "description": "Whether to calculate tax for this payment intent",
      "nullable": true
    },
    "psd2_sca_exemption_type": {
      "allOf": [
        {
          "$ref": "#/components/schemas/ScaExemptionType"
        }
      ],
      "nullable": true
    },
    "ctp_service_details": {
      "allOf": [
        {
          "$ref": "#/components/schemas/CtpServiceDetails"
        }
      ],
      "nullable": true
    },
    "force_3ds_challenge": {
      "type": "boolean",
      "description": "Indicates if 3ds challenge is forced",
      "nullable": true
    },
    "threeds_method_comp_ind": {
      "allOf": [
        {
          "$ref": "#/components/schemas/ThreeDsCompletionIndicator"
        }
      ],
      "nullable": true
    },
    "is_iframe_redirection_enabled": {
      "type": "boolean",
      "description": "Indicates if the redirection has to open in the iframe",
      "nullable": true
    },
    "all_keys_required": {
      "type": "boolean",
      "description": "If enabled, provides whole connector response",
      "nullable": true
    },
    "payment_channel": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentChannel"
        }
      ],
      "nullable": true
    },
    "tax_status": {
      "allOf": [
        {
          "$ref": "#/components/schemas/TaxStatus"
        }
      ],
      "nullable": true
    },
    "discount_amount": {
      "type": "integer",
      "format": "int64",
      "description": "Total amount of the discount you have applied to the order or transaction.",
      "example": 6540,
      "nullable": true
    },
    "shipping_amount_tax": {
      "allOf": [
        {
          "$ref": "#/components/schemas/MinorUnit"
        }
      ],
      "nullable": true
    },
    "duty_amount": {
      "allOf": [
        {
          "$ref": "#/components/schemas/MinorUnit"
        }
      ],
      "nullable": true
    },
    "order_date": {
      "type": "string",
      "format": "date-time",
      "description": "Date the payer placed the order.",
      "nullable": true
    },
    "enable_partial_authorization": {
      "type": "boolean",
      "description": "Allow partial authorization for this payment",
      "nullable": true
    }
  },
  "additionalProperties": false
}


impl ConnectorCommon for Thunes {
    fn id(&self) -> &'static str {
        "thunes"
    }

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Base
        //    TODO! Check connector documentation, on which unit they are processing the currency.
        //    If the connector accepts amount in lower unit ( i.e cents for USD) then return api::CurrencyUnit::Minor,
        //    if connector accepts amount in base unit (i.e dollars for USD) then return api::CurrencyUnit::Base
    }

    fn common_get_content_type(&self) -> &'static str {
        "application/json"
    }

    fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
        connectors.thunes.base_url.as_ref()
    }

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = thunes::ThunesAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            auth.api_key.expose().into_masked(),
        )])
    }

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: thunes::ThunesErrorResponse = res
            .response
            .parse_struct("ThunesErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.code,
            message: response.message,
            reason: response.reason,
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}


pub struct HyperswitchVaultCustomerCreateResponse {
    id: String,
}


pub struct NovalnetMandate {
    token: Secret<String>,
}


pub struct BarclaycardRefundRequest {
    order_information: OrderInformation,
    client_reference_information: ClientReferenceInformation,
}


pub async fn generate_external_token(
    state: SessionState,
    user: authentication::UserFromToken,
    external_service_type: ExternalServiceType,
) -> RouterResponse<external_service_auth_api::ExternalTokenResponse> {
    let token = ExternalToken::new_token(
        user.user_id.clone(),
        user.merchant_id.clone(),
        &state.conf,
        external_service_type.clone(),
    )
    .await
    .change_context(errors::ApiErrorResponse::InternalServerError)
    .attach_printable_lazy(|| {
        format!(
            "Failed to create external token for params [user_id, mid, external_service_type] [{}, {:?}, {:?}]",
            user.user_id, user.merchant_id, external_service_type,
        )
    })?;

    Ok(service_api::ApplicationResponse::Json(
        external_service_auth_api::ExternalTokenResponse {
            token: token.into(),
        },
    ))
}


impl api::PaymentSession for Custombilling {}

impl api::PaymentSession for for Custombilling


impl api::RefundExecute for Ebanx {}


impl Fiservemea {
    pub fn new() -> &'static Self {
        &Self {
            amount_converter: &StringMajorUnitForConnector,
        }
    }

    pub fn generate_authorization_signature(
        &self,
        auth: fiservemea::FiservemeaAuthType,
        request_id: &str,
        payload: &str,
        timestamp: i128,
    ) -> CustomResult<String, errors::ConnectorError> {
        let fiservemea::FiservemeaAuthType {
            api_key,
            secret_key,
        } = auth;
        let raw_signature = format!("{}{request_id}{timestamp}{payload}", api_key.peek());

        let key = hmac::Key::new(hmac::HMAC_SHA256, secret_key.expose().as_bytes());
        let signature_value = common_utils::consts::BASE64_ENGINE
            .encode(hmac::sign(&key, raw_signature.as_bytes()).as_ref());
        Ok(signature_value)
    }
}


pub struct DisputedAmountAccumulator {
    pub total: Option<i64>,
}


Documentation: api-reference/v1/api-key/api-key--retrieve.mdx
# Type: Doc File

---
openapi: get /api_keys/{merchant_id}/{key_id}
---


impl ConnectorResponseNew {
    #[instrument(skip(conn))]
    pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<ConnectorResponse> {
        let payment_attempt_update = PaymentAttemptUpdate::ConnectorResponse {
            authentication_data: self.authentication_data.clone(),
            encoded_data: self.encoded_data.clone(),
            connector_transaction_id: self.connector_transaction_id.clone(),
            connector: self.connector_name.clone(),
            updated_by: self.updated_by.clone(),
            charge_id: self.charge_id.clone(),
        };

        let _payment_attempt: Result<PaymentAttempt, _> =
            generics::generic_update_with_unique_predicate_get_result::<
                <PaymentAttempt as HasTable>::Table,
                _,
                _,
                _,
            >(
                conn,
                pa_dsl::attempt_id
                    .eq(self.attempt_id.to_owned())
                    .and(pa_dsl::merchant_id.eq(self.merchant_id.to_owned())),
                PaymentAttemptUpdateInternal::from(payment_attempt_update),
            )
            .await
            .inspect_err(|err| {
                logger::error!(
                    "Error while updating payment attempt in connector_response flow {:?}",
                    err
                );
            });

        generics::generic_insert(conn, self).await
    }
}


pub async fn authentication_sync_post_update(
    state: web::Data<app::AppState>,
    req: HttpRequest,
    path: web::Path<(
        common_utils::id_type::MerchantId,
        common_utils::id_type::AuthenticationId,
    )


impl OrganizationId {
    /// Get an organization id from String
    pub fn try_from_string(org_id: String) -> CustomResult<Self, ValidationError> {
        Self::try_from(std::borrow::Cow::from(org_id))
    }
}


pub struct PaymentRedirectCompleteAuthorize;