impl GPayPredecryptData {
    /// Get the four-digit expiration year from the Google Pay pre-decrypt data
    pub fn get_four_digit_expiry_year(&self) -> Result<Secret<String>, errors::ValidationError> {
        let mut year = self.card_exp_year.peek().clone();

        // If it's a 2-digit year, convert to 4-digit
        if year.len() == 2 {
            year = format!("20{year}");
        } else if year.len() != 4 {
            return Err(errors::ValidationError::InvalidValue {
                message: format!(
                    "Invalid expiry year length: {}. Must be 2 or 4 digits",
                    year.len()
                ),
            }
            .into());
        }
        Ok(Secret::new(year))
    }
    /// Get the 2-digit expiration year from the Google Pay pre-decrypt data
    pub fn get_two_digit_expiry_year(&self) -> Result<Secret<String>, errors::ValidationError> {
        let binding = self.card_exp_year.clone();
        let year = binding.peek();
        Ok(Secret::new(
            year.get(year.len() - 2..)
                .ok_or(errors::ValidationError::InvalidValue {
                    message: "Invalid two-digit year".to_string(),
                })?
                .to_string(),
        ))
    }
    /// Get the expiry date in MMYY format from the Google Pay pre-decrypt data
    pub fn get_expiry_date_as_mmyy(&self) -> Result<Secret<String>, errors::ValidationError> {
        let year = self.get_two_digit_expiry_year()?.expose();
        let month = self.get_expiry_month()?.clone().expose();
        Ok(Secret::new(format!("{month}{year}")))
    }

    /// Get the expiration month from the Google Pay pre-decrypt data
    pub fn get_expiry_month(&self) -> Result<Secret<String>, errors::ValidationError> {
        let month_str = self.card_exp_month.peek();
        let month = month_str
            .parse::<u8>()
            .map_err(|_| errors::ValidationError::InvalidValue {
                message: format!("Failed to parse expiry month: {month_str}"),
            })?;

        if !(1..=12).contains(&month) {
            return Err(errors::ValidationError::InvalidValue {
                message: format!("Invalid expiry month: {month}. Must be between 1 and 12"),
            }
            .into());
        }
        Ok(self.card_exp_month.clone())
    }
}


impl api::RefundSync for Moneris {}


pub struct PaymentMethodsSessionUpdateRequest {
    /// The billing address details of the customer. This will also be used for any new payment methods added during the session
    #[schema(value_type = Option<Address>)]
    pub billing: Option<payments::Address>,

    /// The tokenization type to be applied
    #[schema(value_type = Option<PspTokenization>)]
    pub psp_tokenization: Option<common_types::payment_methods::PspTokenization>,

    /// The network tokenization configuration if applicable
    #[schema(value_type = Option<NetworkTokenization>)]
    pub network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,

    /// Contains data to be passed on to tokenization service ( if present ) to create token_id for given JSON data
    #[schema(value_type = Option<serde_json::Value>)]
    pub tokenization_data: Option<pii::SecretSerdeValue>,
}


pub struct BankOfAmericaPaymentInstrument {
    id: Secret<String>,
}


                }
            }
        }

        // Do not remove the `skip_all` as the key would be logged otherwise
        #[instrument(skip_all)]
        async fn batch_decrypt_via_api(
            state: &KeyManagerState,
            encrypted_data: FxHashMap<String, Encryption>,
            identifier: Identifier,
            key: &[u8],
            crypt_algo: V,
        ) -> CustomResult<FxHashMap<String, Self>, errors::CryptoError> {
            // If encryption service is not enabled, fall back to application encryption or else call encryption service
            if !is_encryption_service_enabled(state) {
                Self::batch_decrypt(encrypted_data, key, crypt_algo).await
            } else {
                let result: Result<
                    BatchDecryptDataResponse,
                    error_stack::Report<errors::KeyManagerClientError>,
                > = call_encryption_service(
                    state,
                    Method::POST,
                    "data/decrypt",
                    TransientBatchDecryptDataRequest::from((encrypted_data.clone(), identifier)),
                )
                .await;
                let decrypted = match result {
                    Ok(response) => {
                        ForeignTryFrom::foreign_try_from((encrypted_data.clone(), response))
                    }
                    Err(err) => {
                        logger::error!("Decryption error {:?}", err);
                        Err(err.change_context(errors::CryptoError::DecodingFailed))
                    }
                };
                match decrypted {
                    Ok(de) => Ok(de),
                    Err(_) => {
                        metrics::DECRYPTION_API_FAILURES.add(1, &[]);
                        logger::info!("Fall back to Application Decryption");
                        Self::batch_decrypt(encrypted_data, key, crypt_algo).await
                    }
                }
            }
        }

        // Do not remove the `skip_all` as the key would be logged otherwise
        #[instrument(skip_all)]
        async fn batch_encrypt(
            masked_data: FxHashMap<String, Secret<Vec<u8>, S>>,
            key: &[u8],
            crypt_algo: V,
        ) -> CustomResult<FxHashMap<String, Self>, errors::CryptoError> {
            metrics::APPLICATION_ENCRYPTION_COUNT.add(1, &[]);
            masked_data
                .into_iter()
                .map(|(k, v)| {
                    Ok((
                        k,
                        Self::new(v.clone(), crypt_algo.encode_message(key, v.peek())?.into()),
                    ))
                })
                .collect()
        }

        // Do not remove the `skip_all` as the key would be logged otherwise
        #[instrument(skip_all)]
        async fn batch_decrypt(
            encrypted_data: FxHashMap<String, Encryption>,
            key: &[u8],
            crypt_algo: V,
        ) -> CustomResult<FxHashMap<String, Self>, errors::CryptoError> {
            metrics::APPLICATION_DECRYPTION_COUNT.add(1, &[]);
            encrypted_data
                .into_iter()
                .map(|(k, v)| {
                    Ok((
                        k,
                        Self::new(
                            crypt_algo
                                .decode_message(key, v.clone().into_inner().clone())?
                                .into(),
                            v.into_inner(),
                        ),
                    ))
                })
                .collect()
        }
    }
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct EncryptedJsonType<T>(T);

impl<T> EncryptedJsonType<T> {
    pub fn inner(&self) -> &T {
        &self.0
    }

    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<T> From<T> for EncryptedJsonType<T> {
    fn from(value: T) -> Self {
        Self(value)
    }
}

impl<T> std::ops::Deref for EncryptedJsonType<T> {
    type Target = T;

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

/// Type alias for `Option<Encryptable<Secret<EncryptedJsonType<T>>>>`
pub type OptionalEncryptableJsonType<T> = Option<crypto::Encryptable<Secret<EncryptedJsonType<T>>>>;

pub trait Lift<U> {
    type SelfWrapper<T>;
    type OtherWrapper<T, E>;

    fn lift<Func, E, V>(self, func: Func) -> Self::OtherWrapper<V, E>
    where
        Func: Fn(Self::SelfWrapper<U>) -> Self::OtherWrapper<V, E>;
}

impl<U> Lift<U> for Option<U> {
    type SelfWrapper<T> = Option<T>;
    type OtherWrapper<T, E> = CustomResult<Option<T>, E>;

    fn lift<Func, E, V>(self, func: Func) -> Self::OtherWrapper<V, E>
    where
        Func: Fn(Self::SelfWrapper<U>) -> Self::OtherWrapper<V, E>,
    {
        func(self)
    }
}

#[async_trait]
pub trait AsyncLift<U> {
    type SelfWrapper<T>;
    type OtherWrapper<T, E>;

    async fn async_lift<Func, F, E, V>(self, func: Func) -> Self::OtherWrapper<V, E>
    where
        Func: Fn(Self::SelfWrapper<U>) -> F + Send + Sync,
        F: futures::Future<Output = Self::OtherWrapper<V, E>> + Send;
}

#[async_trait]
impl<U, V: Lift<U> + Lift<U, SelfWrapper<U> = V> + Send> AsyncLift<U> for V {
    type SelfWrapper<T> = <V as Lift<U>>::SelfWrapper<T>;
    type OtherWrapper<T, E> = <V as Lift<U>>::OtherWrapper<T, E>;

    async fn async_lift<Func, F, E, W>(self, func: Func) -> Self::OtherWrapper<W, E>
    where
        Func: Fn(Self::SelfWrapper<U>) -> F + Send + Sync,
        F: futures::Future<Output = Self::OtherWrapper<W, E>> + Send,
    {
        func(self).await
    }
}

#[inline]
async fn encrypt<E: Clone, S>(
    state: &KeyManagerState,
    inner: Secret<E, S>,
    identifier: Identifier,
    key: &[u8],
) -> CustomResult<crypto::Encryptable<Secret<E, S>>, CryptoError>
where
    S: masking::Strategy<E>,
    crypto::Encryptable<Secret<E, S>>: TypeEncryption<E, crypto::GcmAes256, S>,
{
    record_operation_time(
        crypto::Encryptable::encrypt_via_api(state, inner, identifier, key, crypto::GcmAes256),
        &metrics::ENCRYPTION_TIME,
        &[],
    )
    .await
}

#[inline]
async fn batch_encrypt<E: Clone, S>(
    state: &KeyManagerState,
    inner: FxHashMap<String, Secret<E, S>>,
    identifier: Identifier,
    key: &[u8],
) -> CustomResult<FxHashMap<String, crypto::Encryptable<Secret<E, S>>>, CryptoError>
where
    S: masking::Strategy<E>,
    crypto::Encryptable<Secret<E, S>>: TypeEncryption<E, crypto::GcmAes256, S>,
{
    if !inner.is_empty() {
        record_operation_time(
            crypto::Encryptable::batch_encrypt_via_api(
                state,
                inner,
                identifier,
                key,
                crypto::GcmAes256,
            ),
            &metrics::ENCRYPTION_TIME,
            &[],
        )
        .await
    } else {
        Ok(FxHashMap::default())
    }
}

#[inline]
async fn encrypt_optional<E: Clone, S>(
    state: &KeyManagerState,
    inner: Option<Secret<E, S>>,
    identifier: Identifier,
    key: &[u8],
) -> CustomResult<Option<crypto::Encryptable<Secret<E, S>>>, CryptoError>
where
    Secret<E, S>: Send,
    S: masking::Strategy<E>,
    crypto::Encryptable<Secret<E, S>>: TypeEncryption<E, crypto::GcmAes256, S>,
{
    inner
        .async_map(|f| encrypt(state, f, identifier, key))
        .await
        .transpose()
}

#[inline]
async fn decrypt_optional<T: Clone, S: masking::Strategy<T>>(
    state: &KeyManagerState,
    inner: Option<Encryption>,
    identifier: Identifier,
    key: &[u8],
) -> CustomResult<Option<crypto::Encryptable<Secret<T, S>>>, CryptoError>
where
    crypto::Encryptable<Secret<T, S>>: TypeEncryption<T, crypto::GcmAes256, S>,
{
    inner
        .async_map(|item| decrypt(state, item, identifier, key))
        .await
        .transpose()
}

#[inline]
async fn decrypt<T: Clone, S: masking::Strategy<T>>(
    state: &KeyManagerState,
    inner: Encryption,
    identifier: Identifier,
    key: &[u8],
) -> CustomResult<crypto::Encryptable<Secret<T, S>>, CryptoError>
where
    crypto::Encryptable<Secret<T, S>>: TypeEncryption<T, crypto::GcmAes256, S>,
{
    record_operation_time(
        crypto::Encryptable::decrypt_via_api(state, inner, identifier, key, crypto::GcmAes256),
        &metrics::DECRYPTION_TIME,
        &[],
    )
    .await
}

#[inline]
async fn batch_decrypt<E: Clone, S>(
    state: &KeyManagerState,
    inner: FxHashMap<String, Encryption>,
    identifier: Identifier,
    key: &[u8],
) -> CustomResult<FxHashMap<String, crypto::Encryptable<Secret<E, S>>>, CryptoError>
where
    S: masking::Strategy<E>,
    crypto::Encryptable<Secret<E, S>>: TypeEncryption<E, crypto::GcmAes256, S>,
{
    if !inner.is_empty() {
        record_operation_time(
            crypto::Encryptable::batch_decrypt_via_api(
                state,
                inner,
                identifier,
                key,
                crypto::GcmAes256,
            ),
            &metrics::ENCRYPTION_TIME,
            &[],
        )
        .await
    } else {
        Ok(FxHashMap::default())
    }
}

pub enum CryptoOperation<T: Clone, S: masking::Strategy<T>> {
    Encrypt(Secret<T, S>),
    EncryptOptional(Option<Secret<T, S>>),
    Decrypt(Encryption),
    DecryptOptional(Option<Encryption>),
    BatchEncrypt(FxHashMap<String, Secret<T, S>>),
    BatchDecrypt(FxHashMap<String, Encryption>),
}

use errors::CryptoError;

#[derive(router_derive::TryGetEnumVariant)]
#[error(CryptoError::EncodingFailed)]
pub enum CryptoOutput<T: Clone, S: masking::Strategy<T>> {
    Operation(crypto::Encryptable<Secret<T, S>>),
    OptionalOperation(Option<crypto::Encryptable<Secret<T, S>>>),
    BatchOperation(FxHashMap<String, crypto::Encryptable<Secret<T, S>>>),
}

// Do not remove the `skip_all` as the key would be logged otherwise
#[instrument(skip_all, fields(table = table_name))]
pub async fn crypto_operation<T: Clone + Send, S: masking::Strategy<T>>(
    state: &KeyManagerState,
    table_name: &str,
    operation: CryptoOperation<T, S>,
    identifier: Identifier,
    key: &[u8],
) -> CustomResult<CryptoOutput<T, S>, CryptoError>
where
    Secret<T, S>: Send,
    crypto::Encryptable<Secret<T, S>>: TypeEncryption<T, crypto::GcmAes256, S>,
{
    match operation {
        CryptoOperation::Encrypt(data) => {
            let data = encrypt(state, data, identifier, key).await?;
            Ok(CryptoOutput::Operation(data))
        }
        CryptoOperation::EncryptOptional(data) => {
            let data = encrypt_optional(state, data, identifier, key).await?;
            Ok(CryptoOutput::OptionalOperation(data))
        }
        CryptoOperation::Decrypt(data) => {
            let data = decrypt(state, data, identifier, key).await?;
            Ok(CryptoOutput::Operation(data))
        }
        CryptoOperation::DecryptOptional(data) => {
            let data = decrypt_optional(state, data, identifier, key).await?;
            Ok(CryptoOutput::OptionalOperation(data))
        }
        CryptoOperation::BatchEncrypt(data) => {
            let data = batch_encrypt(state, data, identifier, key).await?;
            Ok(CryptoOutput::BatchOperation(data))
        }
        CryptoOperation::BatchDecrypt(data) => {
            let data = batch_decrypt(state, data, identifier, key).await?;
            Ok(CryptoOutput::BatchOperation(data))
        }
    }
}

pub(crate) mod metrics {
    use router_env::{counter_metric, global_meter, histogram_metric_f64};

    global_meter!(GLOBAL_METER, "ROUTER_API");

    // Encryption and Decryption metrics
    histogram_metric_f64!(ENCRYPTION_TIME, GLOBAL_METER);
    histogram_metric_f64!(DECRYPTION_TIME, GLOBAL_METER);
    counter_metric!(ENCRYPTION_API_FAILURES, GLOBAL_METER);
    counter_metric!(DECRYPTION_API_FAILURES, GLOBAL_METER);
    counter_metric!(APPLICATION_ENCRYPTION_COUNT, GLOBAL_METER);
    counter_metric!(APPLICATION_DECRYPTION_COUNT, GLOBAL_METER);
}


impl Refund for Plaid {}


impl super::behaviour::Conversion for MerchantAccount {
    type DstType = diesel_models::merchant_account::MerchantAccount;
    type NewDstType = diesel_models::merchant_account::MerchantAccountNew;
    async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
        let setter = diesel_models::merchant_account::MerchantAccountSetter {
            merchant_id: self.merchant_id,
            return_url: self.return_url,
            enable_payment_response_hash: self.enable_payment_response_hash,
            payment_response_hash_key: self.payment_response_hash_key,
            redirect_to_merchant_with_http_post: self.redirect_to_merchant_with_http_post,
            merchant_name: self.merchant_name.map(|name| name.into()),
            merchant_details: self.merchant_details.map(|details| details.into()),
            webhook_details: self.webhook_details,
            sub_merchants_enabled: self.sub_merchants_enabled,
            parent_merchant_id: self.parent_merchant_id,
            publishable_key: Some(self.publishable_key),
            storage_scheme: self.storage_scheme,
            locker_id: self.locker_id,
            metadata: self.metadata,
            routing_algorithm: self.routing_algorithm,
            primary_business_details: self.primary_business_details,
            created_at: self.created_at,
            modified_at: self.modified_at,
            intent_fulfillment_time: self.intent_fulfillment_time,
            frm_routing_algorithm: self.frm_routing_algorithm,
            payout_routing_algorithm: self.payout_routing_algorithm,
            organization_id: self.organization_id,
            is_recon_enabled: self.is_recon_enabled,
            default_profile: self.default_profile,
            recon_status: self.recon_status,
            payment_link_config: self.payment_link_config,
            pm_collect_link_config: self.pm_collect_link_config,
            version: self.version,
            is_platform_account: self.is_platform_account,
            product_type: self.product_type,
            merchant_account_type: self.merchant_account_type,
        };

        Ok(diesel_models::MerchantAccount::from(setter))
    }

    async fn convert_back(
        state: &keymanager::KeyManagerState,
        item: Self::DstType,
        key: &Secret<Vec<u8>>,
        key_manager_identifier: keymanager::Identifier,
    ) -> CustomResult<Self, ValidationError>
    where
        Self: Sized,
    {
        let merchant_id = item.get_id().to_owned();
        let publishable_key =
            item.publishable_key
                .ok_or(ValidationError::MissingRequiredField {
                    field_name: "publishable_key".to_string(),
                })?;

        async {
            Ok::<Self, error_stack::Report<common_utils::errors::CryptoError>>(Self {
                merchant_id,
                return_url: item.return_url,
                enable_payment_response_hash: item.enable_payment_response_hash,
                payment_response_hash_key: item.payment_response_hash_key,
                redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
                merchant_name: item
                    .merchant_name
                    .async_lift(|inner| async {
                        crypto_operation(
                            state,
                            type_name!(Self::DstType),
                            CryptoOperation::DecryptOptional(inner),
                            key_manager_identifier.clone(),
                            key.peek(),
                        )
                        .await
                        .and_then(|val| val.try_into_optionaloperation())
                    })
                    .await?,
                merchant_details: item
                    .merchant_details
                    .async_lift(|inner| async {
                        crypto_operation(
                            state,
                            type_name!(Self::DstType),
                            CryptoOperation::DecryptOptional(inner),
                            key_manager_identifier.clone(),
                            key.peek(),
                        )
                        .await
                        .and_then(|val| val.try_into_optionaloperation())
                    })
                    .await?,
                webhook_details: item.webhook_details,
                sub_merchants_enabled: item.sub_merchants_enabled,
                parent_merchant_id: item.parent_merchant_id,
                publishable_key,
                storage_scheme: item.storage_scheme,
                locker_id: item.locker_id,
                metadata: item.metadata,
                routing_algorithm: item.routing_algorithm,
                frm_routing_algorithm: item.frm_routing_algorithm,
                primary_business_details: item.primary_business_details,
                created_at: item.created_at,
                modified_at: item.modified_at,
                intent_fulfillment_time: item.intent_fulfillment_time,
                payout_routing_algorithm: item.payout_routing_algorithm,
                organization_id: item.organization_id,
                is_recon_enabled: item.is_recon_enabled,
                default_profile: item.default_profile,
                recon_status: item.recon_status,
                payment_link_config: item.payment_link_config,
                pm_collect_link_config: item.pm_collect_link_config,
                version: item.version,
                is_platform_account: item.is_platform_account,
                product_type: item.product_type,
                merchant_account_type: item.merchant_account_type.unwrap_or_default(),
            })
        }
        .await
        .change_context(ValidationError::InvalidValue {
            message: "Failed while decrypting merchant data".to_string(),
        })
    }

    async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
        let now = date_time::now();
        Ok(diesel_models::merchant_account::MerchantAccountNew {
            id: Some(self.merchant_id.clone()),
            merchant_id: self.merchant_id,
            merchant_name: self.merchant_name.map(Encryption::from),
            merchant_details: self.merchant_details.map(Encryption::from),
            return_url: self.return_url,
            webhook_details: self.webhook_details,
            sub_merchants_enabled: self.sub_merchants_enabled,
            parent_merchant_id: self.parent_merchant_id,
            enable_payment_response_hash: Some(self.enable_payment_response_hash),
            payment_response_hash_key: self.payment_response_hash_key,
            redirect_to_merchant_with_http_post: Some(self.redirect_to_merchant_with_http_post),
            publishable_key: Some(self.publishable_key),
            locker_id: self.locker_id,
            metadata: self.metadata,
            routing_algorithm: self.routing_algorithm,
            primary_business_details: self.primary_business_details,
            created_at: now,
            modified_at: now,
            intent_fulfillment_time: self.intent_fulfillment_time,
            frm_routing_algorithm: self.frm_routing_algorithm,
            payout_routing_algorithm: self.payout_routing_algorithm,
            organization_id: self.organization_id,
            is_recon_enabled: self.is_recon_enabled,
            default_profile: self.default_profile,
            recon_status: self.recon_status,
            payment_link_config: self.payment_link_config,
            pm_collect_link_config: self.pm_collect_link_config,
            version: common_types::consts::API_VERSION,
            is_platform_account: self.is_platform_account,
            product_type: self
                .product_type
                .or(Some(common_enums::MerchantProductType::Orchestration)),
            merchant_account_type: self.merchant_account_type,
        })
    }
}

impl super::behaviour::Conversion for for MerchantAccount


pub async fn invoke_lambda(
    function_name: &str,
    region: &str,
    json_bytes: &[u8],
) -> CustomResult<(), AnalyticsError> {
    get_aws_client(region.to_string())
        .await
        .invoke()
        .function_name(function_name)
        .invocation_type(Event)
        .payload(Blob::new(json_bytes.to_owned()))
        .send()
        .await
        .map_err(|er| {
            let er_rep = format!("{er:?}");
            report!(er).attach_printable(er_rep)
        })
        .change_context(AnalyticsError::UnknownError)
        .attach_printable("Lambda invocation failed")?;
    Ok(())
}


pub struct GooglePayData {
    data: Secret<String>,
    signature: Secret<String>,
    version: String,
    intermediate_signing_key: IntermediateSigningKey,
}


OpenAPI Block Path: components.schemas.ApplePayPaymentData
{
  "oneOf": [
    {
      "$ref": "#/components/schemas/ApplePayPredecryptData"
    },
    {
      "type": "string",
      "description": "This variant contains the encrypted Apple Pay payment data as a string."
    }
  ],
  "description": "This enum is used to represent the Apple Pay payment data, which can either be encrypted or decrypted."
}


pub struct FetchRoutingConfig {
    pub merchant_id: String,
    pub algorithm: AlgorithmType,
}


pub trait FrmMetricAccumulator {
    type MetricOutput;

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

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


pub async fn get_decrypted_response_payload(
    jwekey: &settings::Jwekey,
    jwe_body: encryption::JweBody,
    locker_choice: Option<api_enums::LockerChoice>,
    decryption_scheme: settings::DecryptionScheme,
) -> CustomResult<String, errors::VaultError> {
    let target_locker = locker_choice.unwrap_or(api_enums::LockerChoice::HyperswitchCardVault);

    let public_key = match target_locker {
        api_enums::LockerChoice::HyperswitchCardVault => {
            jwekey.vault_encryption_key.peek().as_bytes()
        }
    };

    let private_key = jwekey.vault_private_key.peek().as_bytes();

    let jwt = get_dotted_jwe(jwe_body);
    let alg = match decryption_scheme {
        settings::DecryptionScheme::RsaOaep => jwe::RSA_OAEP,
        settings::DecryptionScheme::RsaOaep256 => jwe::RSA_OAEP_256,
    };

    let jwe_decrypted = encryption::decrypt_jwe(
        &jwt,
        encryption::KeyIdCheck::SkipKeyIdCheck,
        private_key,
        alg,
    )
    .await
    .change_context(errors::VaultError::SaveCardFailed)
    .attach_printable("Jwe Decryption failed for JweBody for vault")?;

    let jws = jwe_decrypted
        .parse_struct("JwsBody")
        .change_context(errors::VaultError::ResponseDeserializationFailed)?;
    let jws_body = get_dotted_jws(jws);

    encryption::verify_sign(jws_body, public_key)
        .change_context(errors::VaultError::SaveCardFailed)
        .attach_printable("Jws Decryption failed for JwsBody for vault")
}


pub struct MerchantDefinedInformation {
    key: u8,
    value: String,
}


pub struct OutgoingWebhook {
    /// The merchant id of the merchant
    #[schema(value_type = String)]
    pub merchant_id: common_utils::id_type::MerchantId,

    /// The unique event id for each webhook
    pub event_id: String,

    /// The type of event this webhook corresponds to.
    #[schema(value_type = EventType)]
    pub event_type: api_enums::EventType,

    /// This is specific to the flow, for ex: it will be `PaymentsResponse` for payments flow
    pub content: OutgoingWebhookContent,

    /// The time at which webhook was sent
    #[serde(default, with = "custom_serde::iso8601")]
    pub timestamp: PrimitiveDateTime,
}


/// Get the expiration month from the Apple Pay pre-decrypt data
    pub fn get_expiry_month(&self) -> Result<Secret<String>, errors::ValidationError> {
        let month_str = self.application_expiration_month.peek();
        let month = month_str
            .parse::<u8>()
            .map_err(|_| errors::ValidationError::InvalidValue {
                message: format!("Failed to parse expiry month: {month_str}"),
            })?;

        if !(1..=12).contains(&month) {
            return Err(errors::ValidationError::InvalidValue {
                message: format!("Invalid expiry month: {month}. Must be between 1 and 12"),
            }
            .into());
        }
        Ok(self.application_expiration_month.clone())
    }


File: crates/router/tests/connectors/razorpay.rs

use masking::Secret;
use router::types::{self, domain, storage::enums};
use test_utils::connector_auth;

use crate::utils::{self, ConnectorActions};

#[derive(Clone, Copy)]
struct RazorpayTest;
impl ConnectorActions for RazorpayTest {}
impl utils::Connector for RazorpayTest {
    fn get_data(&self) -> types::api::ConnectorData {
        use router::connector::Razorpay;
        utils::construct_connector_data_old(
            Box::new(Razorpay::new()),
            types::Connector::Razorpay,
            types::api::GetToken::Connector,
            None,
        )
    }

    fn get_auth_token(&self) -> types::ConnectorAuthType {
        utils::to_connector_auth_type(
            connector_auth::ConnectorAuthentication::new()
                .razorpay
                .expect("Missing connector authentication configuration")
                .into(),
        )
    }

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

static CONNECTOR: RazorpayTest = RazorpayTest {};

fn get_default_payment_info() -> Option<utils::PaymentInfo> {
    None
}

fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
    None
}

// Cards Positive Tests
// Creates a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_only_authorize_payment() {
    let response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized);
}

// Captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info())
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Partially captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(
            payment_method_details(),
            Some(types::PaymentsCaptureData {
                amount_to_capture: 50,
                ..utils::PaymentCaptureType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_authorized_payment() {
    let authorize_response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Authorized,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("PSync response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
}

// Voids a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_void_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_void_payment(
            payment_method_details(),
            Some(types::PaymentsCancelData {
                connector_transaction_id: String::from(""),
                cancellation_reason: Some("requested_by_customer".to_string()),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Void payment response");
    assert_eq!(response.status, enums::AttemptStatus::Voided);
}

// Refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Synchronizes a refund using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_manually_captured_refund() {
    let refund_response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_make_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_auto_captured_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Charged,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                capture_method: Some(enums::CaptureMethod::Automatic),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(response.status, enums::AttemptStatus::Charged,);
}

// Refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_auto_captured_payment() {
    let response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_succeeded_payment() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        refund_response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_succeeded_payment_multiple_times() {
    CONNECTOR
        .make_payment_and_multiple_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await;
}

// Synchronizes a refund using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_refund() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Cards Negative scenarios
// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_cvc: Secret::new("12345".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's security code is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry month.
#[actix_web::test]
async fn should_fail_payment_for_invalid_exp_month() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_month: Secret::new("20".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration month is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry year.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_expiry_year() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration year is invalid.".to_string(),
    );
}

// Voids a payment using automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_fail_void_payment_for_auto_capture() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let void_response = CONNECTOR
        .void_payment(txn_id.unwrap(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        void_response.response.unwrap_err().message,
        "You cannot cancel this PaymentIntent because it has a status of succeeded."
    );
}

// Captures a payment using invalid connector payment id.
#[actix_web::test]
async fn should_fail_capture_for_invalid_payment() {
    let capture_response = CONNECTOR
        .capture_payment("123456789".to_string(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        capture_response.response.unwrap_err().message,
        String::from("No such payment_intent: '123456789'")
    );
}

// Refunds a payment with refund amount higher than payment amount.
#[actix_web::test]
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
    let response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 150,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Refund amount (₹1.50) is greater than charge amount (₹1.00)",
    );
}

// Connector dependent test cases goes here

// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests


File: crates/openapi/src/routes/api_keys.rs
 Public functions: 10

#[cfg(feature = "v1")]
/// API Key - Create
///
/// Create a new API Key for accessing our APIs from your servers. The plaintext API Key will be
/// displayed only once on creation, so ensure you store it securely.
#[utoipa::path(
    post,
    path = "/api_keys/{merchant_id}",
    params(("merchant_id" = String, Path, description = "The unique identifier for the merchant account")),
    request_body= CreateApiKeyRequest,
    responses(
        (status = 200, description = "API Key created", body = CreateApiKeyResponse),
        (status = 400, description = "Invalid data")
    ),
    tag = "API Key",
    operation_id = "Create an API Key",
    security(("admin_api_key" = []))
)]
pub async fn api_key_create() {}

#[cfg(feature = "v2")]
/// API Key - Create
///
/// Create a new API Key for accessing our APIs from your servers. The plaintext API Key will be
/// displayed only once on creation, so ensure you store it securely.
#[utoipa::path(
    post,
    path = "/v2/api-keys",
    request_body= CreateApiKeyRequest,
    responses(
        (status = 200, description = "API Key created", body = CreateApiKeyResponse),
        (status = 400, description = "Invalid data")
    ),
    tag = "API Key",
    operation_id = "Create an API Key",
    security(("admin_api_key" = []))
)]
pub async fn api_key_create() {}

#[cfg(feature = "v1")]
/// API Key - Retrieve
///
/// Retrieve information about the specified API Key.
#[utoipa::path(
    get,
    path = "/api_keys/{merchant_id}/{key_id}",
    params (
        ("merchant_id" = String, Path, description = "The unique identifier for the merchant account"),
        ("key_id" = String, Path, description = "The unique identifier for the API Key")
    ),
    responses(
        (status = 200, description = "API Key retrieved", body = RetrieveApiKeyResponse),
        (status = 404, description = "API Key not found")
    ),
    tag = "API Key",
    operation_id = "Retrieve an API Key",
    security(("admin_api_key" = []))
)]
pub async fn api_key_retrieve() {}

#[cfg(feature = "v2")]
/// API Key - Retrieve
///
/// Retrieve information about the specified API Key.
#[utoipa::path(
    get,
    path = "/v2/api-keys/{id}",
    params (
        ("id" = String, Path, description = "The unique identifier for the API Key")
    ),
    responses(
        (status = 200, description = "API Key retrieved", body = RetrieveApiKeyResponse),
        (status = 404, description = "API Key not found")
    ),
    tag = "API Key",
    operation_id = "Retrieve an API Key",
    security(("admin_api_key" = []))
)]
pub async fn api_key_retrieve() {}

#[cfg(feature = "v1")]
/// API Key - Update
///
/// Update information for the specified API Key.
#[utoipa::path(
    post,
    path = "/api_keys/{merchant_id}/{key_id}",
    request_body = UpdateApiKeyRequest,
    params (
        ("merchant_id" = String, Path, description = "The unique identifier for the merchant account"),
        ("key_id" = String, Path, description = "The unique identifier for the API Key")
    ),
    responses(
        (status = 200, description = "API Key updated", body = RetrieveApiKeyResponse),
        (status = 404, description = "API Key not found")
    ),
    tag = "API Key",
    operation_id = "Update an API Key",
    security(("admin_api_key" = []))
)]
pub async fn api_key_update() {}

#[cfg(feature = "v2")]
/// API Key - Update
///
/// Update information for the specified API Key.
#[utoipa::path(
    put,
    path = "/v2/api-keys/{id}",
    request_body = UpdateApiKeyRequest,
    params (
        ("id" = String, Path, description = "The unique identifier for the API Key")
    ),
    responses(
        (status = 200, description = "API Key updated", body = RetrieveApiKeyResponse),
        (status = 404, description = "API Key not found")
    ),
    tag = "API Key",
    operation_id = "Update an API Key",
    security(("admin_api_key" = []))
)]
pub async fn api_key_update() {}

#[cfg(feature = "v1")]
/// API Key - Revoke
///
/// Revoke the specified API Key. Once revoked, the API Key can no longer be used for
/// authenticating with our APIs.
#[utoipa::path(
    delete,
    path = "/api_keys/{merchant_id}/{key_id}",
    params (
        ("merchant_id" = String, Path, description = "The unique identifier for the merchant account"),
        ("key_id" = String, Path, description = "The unique identifier for the API Key")
    ),
    responses(
        (status = 200, description = "API Key revoked", body = RevokeApiKeyResponse),
        (status = 404, description = "API Key not found")
    ),
    tag = "API Key",
    operation_id = "Revoke an API Key",
    security(("admin_api_key" = []))
)]
pub async fn api_key_revoke() {}

#[cfg(feature = "v2")]
/// API Key - Revoke
///
/// Revoke the specified API Key. Once revoked, the API Key can no longer be used for
/// authenticating with our APIs.
#[utoipa::path(
    delete,
    path = "/v2/api-keys/{id}",
    params (
        ("id" = String, Path, description = "The unique identifier for the API Key")
    ),
    responses(
        (status = 200, description = "API Key revoked", body = RevokeApiKeyResponse),
        (status = 404, description = "API Key not found")
    ),
    tag = "API Key",
    operation_id = "Revoke an API Key",
    security(("admin_api_key" = []))
)]
pub async fn api_key_revoke() {}

#[cfg(feature = "v1")]
/// API Key - List
///
/// List all the API Keys associated to a merchant account.
#[utoipa::path(
    get,
    path = "/api_keys/{merchant_id}/list",
    params(
        ("merchant_id" = String, Path, description = "The unique identifier for the merchant account"),
        ("limit" = Option<i64>, Query, description = "The maximum number of API Keys to include in the response"),
        ("skip" = Option<i64>, Query, description = "The number of API Keys to skip when retrieving the list of API keys."),
    ),
    responses(
        (status = 200, description = "List of API Keys retrieved successfully", body = Vec<RetrieveApiKeyResponse>),
    ),
    tag = "API Key",
    operation_id = "List all API Keys associated with a merchant account",
    security(("admin_api_key" = []))
)]
pub async fn api_key_list() {}

#[cfg(feature = "v2")]
/// API Key - List
///
/// List all the API Keys associated to a merchant account.
#[utoipa::path(
    get,
    path = "/v2/api-keys/list",
    params(
        ("limit" = Option<i64>, Query, description = "The maximum number of API Keys to include in the response"),
        ("skip" = Option<i64>, Query, description = "The number of API Keys to skip when retrieving the list of API keys."),
    ),
    responses(
        (status = 200, description = "List of API Keys retrieved successfully", body = Vec<RetrieveApiKeyResponse>),
    ),
    tag = "API Key",
    operation_id = "List all API Keys associated with a merchant account",
    security(("admin_api_key" = []))
)]
pub async fn api_key_list() {}


pub fn value_type(input: &str) -> ParseResult<&str, ast::ValueType> {
    error::context(
        "value_type",
        branch::alt((
            number_value,
            enum_variant_value,
            enum_variant_array_value,
            number_array_value,
            number_comparison_array_value,
            str_value,
        )),
    )(input)
}


impl api::PaymentVoid for Billwerk {}


impl RefundSync for Signifyd {}


OpenAPI Block Path: components.schemas.ApplePayRedirectData
{
  "type": "object"
}


pub struct ApplepayGetVerifiedDomainsParam {
    pub merchant_id: id_type::MerchantId,
    pub merchant_connector_account_id: id_type::MerchantConnectorAccountId,
}


/// Performs Payment repeat (MIT - Merchant Initiated Transaction).
    pub async fn payment_repeat(
        &self,
        payment_repeat_request: payments_grpc::PaymentServiceRepeatEverythingRequest,
        connector_auth_metadata: ConnectorAuthMetadata,
        grpc_headers: GrpcHeaders,
    ) -> UnifiedConnectorServiceResult<
        tonic::Response<payments_grpc::PaymentServiceRepeatEverythingResponse>,
    > {
        let mut request = tonic::Request::new(payment_repeat_request);

        let connector_name = connector_auth_metadata.connector_name.clone();
        let metadata = build_unified_connector_service_grpc_headers(
            connector_auth_metadata,
            None,
            grpc_headers,
        )?;
        *request.metadata_mut() = metadata;

        self.client
            .clone()
            .repeat_everything(request)
            .await
            .change_context(UnifiedConnectorServiceError::PaymentRepeatEverythingFailure)
            .inspect_err(|error| {
                logger::error!(
                    grpc_error=?error,
                    method="payment_repeat",
                    connector_name=?connector_name,
                    "UCS payment repeat gRPC call failed"
                )
            })
    }


impl api::PaymentSession for Nexinets {}

impl api::PaymentSession for for Nexinets


pub struct ErrorResponse {
    pub errors: Option<Vec<SubError>>,
    pub error_id: Option<i32>,
}


pub struct BamboraCard {
    name: Secret<String>,
    number: cards::CardNumber,
    expiry_month: Secret<String>,
    expiry_year: Secret<String>,
    cvd: Secret<String>,
    complete: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "3d_secure")]
    three_d_secure: Option<ThreeDSecure>,
}


pub struct AchBankDebitAdditionalData {
    /// Partially masked account number for ach bank debit payment
    #[schema(value_type = String, example = "0001****3456")]
    pub account_number: MaskedBankAccount,

    /// Partially masked routing number for ach bank debit payment
    #[schema(value_type = String, example = "110***000")]
    pub routing_number: MaskedRoutingNumber,

    /// Card holder's name
    #[schema(value_type = Option<String>, example = "John Doe")]
    pub card_holder_name: Option<Secret<String>>,

    /// Bank account's owner name
    #[schema(value_type = Option<String>, example = "John Doe")]
    pub bank_account_holder_name: Option<Secret<String>>,

    /// Name of the bank
    #[schema(value_type = Option<BankNames>, example = "ach")]
    pub bank_name: Option<common_enums::BankNames>,

    /// Bank account type
    #[schema(value_type = Option<BankType>, example = "checking")]
    pub bank_type: Option<common_enums::BankType>,

    /// Bank holder entity type
    #[schema(value_type = Option<BankHolderType>, example = "personal")]
    pub bank_holder_type: Option<common_enums::BankHolderType>,
}


pub async fn payments_create(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    json_payload: web::Json<payment_types::PaymentsRequest>,
) -> impl Responder {
    let flow = Flow::PaymentsCreate;
    let mut payload = json_payload.into_inner();
    if let Err(err) = payload
        .validate()
        .map_err(|message| errors::ApiErrorResponse::InvalidRequestData { message })
    {
        return api::log_and_return_error_response(err.into());
    };

    if let Some(api_enums::CaptureMethod::Scheduled) = payload.capture_method {
        return http_not_implemented();
    };

    if let Err(err) = get_or_generate_payment_id(&mut payload) {
        return api::log_and_return_error_response(err);
    }

    let header_payload = match HeaderPayload::foreign_try_from(req.headers()) {
        Ok(headers) => headers,
        Err(err) => {
            return api::log_and_return_error_response(err);
        }
    };

    tracing::Span::current().record(
        "payment_id",
        payload
            .payment_id
            .as_ref()
            .map(|payment_id_type| payment_id_type.get_payment_intent_id())
            .transpose()
            .unwrap_or_default()
            .as_ref()
            .map(|id| id.get_string_repr())
            .unwrap_or_default(),
    );

    let locking_action = payload.get_locking_input(flow.clone());

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            authorize_verify_select::<_>(
                payments::PaymentCreate,
                state,
                req_state,
                merchant_context,
                auth.profile_id,
                header_payload.clone(),
                req,
                api::AuthFlow::Client,
            )
        },
        match env::which() {
            env::Env::Production => &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: true,
            }),
            _ => auth::auth_type(
                &auth::HeaderAuth(auth::ApiKeyAuth {
                    is_connected_allowed: false,
                    is_platform_allowed: true,
                }),
                &auth::JWTAuth {
                    permission: Permission::ProfilePaymentWrite,
                },
                req.headers(),
            ),
        },
        locking_action,
    ))
    .await
}


File: crates/analytics/src/sdk_events/filters.rs
 Public functions: 1
 Public structs: 1

use api_models::analytics::{sdk_events::SdkEventDimensions, Granularity, TimeRange};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

use crate::{
    query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, ToSql, Window},
    types::{AnalyticsCollection, AnalyticsDataSource, FiltersError, FiltersResult, LoadRow},
};

pub trait SdkEventFilterAnalytics: LoadRow<SdkEventFilter> {}

pub async fn get_sdk_event_filter_for_dimension<T>(
    dimension: SdkEventDimensions,
    publishable_key: &String,
    time_range: &TimeRange,
    pool: &T,
) -> FiltersResult<Vec<SdkEventFilter>>
where
    T: AnalyticsDataSource + SdkEventFilterAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    let mut query_builder: QueryBuilder<T> =
        QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);

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

    query_builder
        .add_filter_clause("merchant_id", publishable_key)
        .switch()?;

    query_builder.set_distinct();

    query_builder
        .execute_query::<SdkEventFilter, _>(pool)
        .await
        .change_context(FiltersError::QueryBuildingError)?
        .change_context(FiltersError::QueryExecutionFailure)
}

#[derive(Debug, serde::Serialize, Eq, PartialEq, serde::Deserialize)]
pub struct SdkEventFilter {
    pub payment_method: Option<String>,
    pub platform: Option<String>,
    pub browser_name: Option<String>,
    pub source: Option<String>,
    pub component: Option<String>,
    pub payment_experience: Option<String>,
}


pub struct UpdateCardInfo {
    pub card_issuer: Option<String>,
    pub card_network: Option<storage_enums::CardNetwork>,
    pub card_type: Option<String>,
    pub card_subtype: Option<String>,
    pub card_issuing_country: Option<String>,
    pub bank_code_id: Option<String>,
    pub bank_code: Option<String>,
    pub country_code: Option<String>,
    pub last_updated: Option<PrimitiveDateTime>,
    pub last_updated_provider: Option<String>,
}


pub async fn authentication_eligibility_core(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    req: AuthenticationEligibilityRequest,
    authentication_id: common_utils::id_type::AuthenticationId,
) -> RouterResponse<AuthenticationEligibilityResponse> {
    let merchant_account = merchant_context.get_merchant_account();
    let merchant_id = merchant_account.get_id();
    let db = &*state.store;
    let authentication = db
        .find_authentication_by_merchant_id_authentication_id(merchant_id, &authentication_id)
        .await
        .to_not_found_response(ApiErrorResponse::AuthenticationNotFound {
            id: authentication_id.get_string_repr().to_owned(),
        })?;

    req.client_secret
        .clone()
        .map(|client_secret| {
            utils::authenticate_authentication_client_secret_and_check_expiry(
                client_secret.peek(),
                &authentication,
            )
        })
        .transpose()?;

    ensure_not_terminal_status(authentication.trans_status.clone())?;

    let key_manager_state = (&state).into();

    let profile_id = core_utils::get_profile_id_from_business_details(
        &key_manager_state,
        None,
        None,
        &merchant_context,
        None,
        db,
        true,
    )
    .await?;

    let business_profile = db
        .find_business_profile_by_profile_id(
            &key_manager_state,
            merchant_context.get_merchant_key_store(),
            &profile_id,
        )
        .await
        .to_not_found_response(ApiErrorResponse::ProfileNotFound {
            id: profile_id.get_string_repr().to_owned(),
        })?;

    let (authentication_connector, three_ds_connector_account) =
        auth_utils::get_authentication_connector_data(
            &state,
            merchant_context.get_merchant_key_store(),
            &business_profile,
            authentication.authentication_connector.clone(),
        )
        .await?;

    let notification_url = match authentication_connector {
        common_enums::AuthenticationConnectors::Juspaythreedsserver => {
            Some(url::Url::parse(&format!(
                "{base_url}/authentication/{merchant_id}/{authentication_id}/sync",
                base_url = state.base_url,
                merchant_id = merchant_id.get_string_repr(),
                authentication_id = authentication_id.get_string_repr()
            )))
            .transpose()
            .change_context(ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to parse notification url")?
        }
        _ => authentication
            .return_url
            .as_ref()
            .map(|url| url::Url::parse(url))
            .transpose()
            .change_context(ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to parse return url")?,
    };

    let authentication_connector_name = authentication_connector.to_string();

    let payment_method_data = domain::PaymentMethodData::from(req.payment_method_data.clone());

    let amount = authentication
        .amount
        .ok_or(ApiErrorResponse::InternalServerError)
        .attach_printable("no amount found in authentication table")?;

    let acquirer_details = authentication
        .profile_acquirer_id
        .clone()
        .and_then(|acquirer_id| {
            business_profile
                .acquirer_config_map
                .and_then(|acquirer_config_map| acquirer_config_map.0.get(&acquirer_id).cloned())
        });

    let metadata: Option<ThreeDsMetaData> = three_ds_connector_account
        .get_metadata()
        .map(|metadata| {
            metadata.expose().parse_value("ThreeDsMetaData").inspect_err(|err| {
            router_env::logger::warn!(parsing_error=?err,"Error while parsing ThreeDsMetaData");
        })
        })
        .transpose()
        .change_context(ApiErrorResponse::InternalServerError)?;

    let merchant_country_code = authentication.acquirer_country_code.clone();

    let merchant_details = Some(hyperswitch_domain_models::router_request_types::unified_authentication_service::MerchantDetails {
        merchant_id: Some(authentication.merchant_id.get_string_repr().to_string()),
        merchant_name: acquirer_details.clone().map(|detail| detail.merchant_name.clone()).or(metadata.clone().and_then(|metadata| metadata.merchant_name)),
        merchant_category_code: business_profile.merchant_category_code.or(metadata.clone().and_then(|metadata| metadata.merchant_category_code)),
        endpoint_prefix: metadata.clone().map(|metadata| metadata.endpoint_prefix),
        three_ds_requestor_url: business_profile.authentication_connector_details.map(|details| details.three_ds_requestor_url),
        three_ds_requestor_id: metadata.clone().and_then(|metadata| metadata.three_ds_requestor_id),
        three_ds_requestor_name: metadata.clone().and_then(|metadata| metadata.three_ds_requestor_name),
        merchant_country_code: merchant_country_code.map(common_types::payments::MerchantCountryCode::new),
        notification_url,
    });

    let domain_address = req
        .billing
        .clone()
        .map(hyperswitch_domain_models::address::Address::from);

    let pre_auth_response =
        <ExternalAuthentication as UnifiedAuthenticationService>::pre_authentication(
            &state,
            merchant_id,
            None,
            Some(&payment_method_data),
            &three_ds_connector_account,
            &authentication_connector_name,
            &authentication_id,
            req.payment_method,
            amount,
            authentication.currency,
            None,
            merchant_details.as_ref(),
            domain_address.as_ref(),
            authentication.acquirer_bin.clone(),
            authentication.acquirer_merchant_id.clone(),
        )
        .await?;

    let billing_details_encoded = req
        .billing
        .clone()
        .map(|billing| {
            common_utils::ext_traits::Encode::encode_to_value(&billing)
                .map(masking::Secret::<serde_json::Value>::new)
        })
        .transpose()
        .change_context(ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to encode billing details to serde_json::Value")?;

    let shipping_details_encoded = req
        .shipping
        .clone()
        .map(|shipping| {
            common_utils::ext_traits::Encode::encode_to_value(&shipping)
                .map(masking::Secret::<serde_json::Value>::new)
        })
        .transpose()
        .change_context(ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to encode shipping details to serde_json::Value")?;

    let encrypted_data = domain::types::crypto_operation(
        &key_manager_state,
        common_utils::type_name!(hyperswitch_domain_models::authentication::Authentication),
        domain::types::CryptoOperation::BatchEncrypt(
            hyperswitch_domain_models::authentication::UpdateEncryptableAuthentication::to_encryptable(
                hyperswitch_domain_models::authentication::UpdateEncryptableAuthentication {
                    billing_address: billing_details_encoded,
                    shipping_address: shipping_details_encoded,
                },
            ),
        ),
        common_utils::types::keymanager::Identifier::Merchant(
            merchant_context
                .get_merchant_key_store()
                .merchant_id
                .clone(),
        ),
        merchant_context.get_merchant_key_store().key.peek(),
    )
    .await
    .and_then(|val| val.try_into_batchoperation())
    .change_context(ApiErrorResponse::InternalServerError)
    .attach_printable("Unable to encrypt authentication data".to_string())?;

    let encrypted_data = hyperswitch_domain_models::authentication::FromRequestEncryptableAuthentication::from_encryptable(encrypted_data)
        .change_context(ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to get encrypted data for authentication after encryption")?;

    let email_encrypted = req
        .email
        .clone()
        .async_lift(|inner| async {
            domain::types::crypto_operation(
                &key_manager_state,
                common_utils::type_name!(Authentication),
                domain::types::CryptoOperation::EncryptOptional(inner.map(|inner| inner.expose())),
                common_utils::types::keymanager::Identifier::Merchant(
                    merchant_context
                        .get_merchant_key_store()
                        .merchant_id
                        .clone(),
                ),
                merchant_context.get_merchant_key_store().key.peek(),
            )
            .await
            .and_then(|val| val.try_into_optionaloperation())
        })
        .await
        .change_context(ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to encrypt email")?;

    let browser_info = req
        .browser_information
        .as_ref()
        .map(common_utils::ext_traits::Encode::encode_to_value)
        .transpose()
        .change_context(ApiErrorResponse::InvalidDataValue {
            field_name: "browser_information",
        })?;

    let updated_authentication = utils::external_authentication_update_trackers(
        &state,
        pre_auth_response,
        authentication.clone(),
        None,
        merchant_context.get_merchant_key_store(),
        encrypted_data
            .billing_address
            .map(common_utils::encryption::Encryption::from),
        encrypted_data
            .shipping_address
            .map(common_utils::encryption::Encryption::from),
        email_encrypted
            .clone()
            .map(common_utils::encryption::Encryption::from),
        browser_info,
    )
    .await?;

    let response = AuthenticationEligibilityResponse::foreign_try_from((
        updated_authentication,
        req.get_next_action_api(
            state.base_url,
            authentication_id.get_string_repr().to_string(),
        )
        .change_context(ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to get next action api")?,
        profile_id,
        req.get_billing_address(),
        req.get_shipping_address(),
        req.get_browser_information(),
        email_encrypted,
    ))?;

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


pub fn is_terminal_status(self) -> bool {
        match self {
            Self::RouterDeclined
            | Self::Charged
            | Self::AutoRefunded
            | Self::Voided
            | Self::VoidedPostCharge
            | Self::VoidFailed
            | Self::CaptureFailed
            | Self::Failure
            | Self::PartialCharged
            | Self::Expired => true,
            Self::Started
            | Self::AuthenticationFailed
            | Self::AuthenticationPending
            | Self::AuthenticationSuccessful
            | Self::Authorized
            | Self::PartiallyAuthorized
            | Self::AuthorizationFailed
            | Self::Authorizing
            | Self::CodInitiated
            | Self::VoidInitiated
            | Self::CaptureInitiated
            | Self::PartialChargedAndChargeable
            | Self::Unresolved
            | Self::Pending
            | Self::PaymentMethodAwaited
            | Self::ConfirmationAwaited
            | Self::DeviceDataCollectionPending
            | Self::IntegrityFailure => false,
        }
    }


OpenAPI Block Path: components.schemas.SepaBankTransferInstructions
{
  "type": "object",
  "required": [
    "account_holder_name",
    "bic",
    "country",
    "iban",
    "reference"
  ],
  "properties": {
    "account_holder_name": {
      "type": "string",
      "example": "Jane Doe"
    },
    "bic": {
      "type": "string",
      "example": "9123456789"
    },
    "country": {
      "type": "string"
    },
    "iban": {
      "type": "string",
      "example": "123456789"
    },
    "reference": {
      "type": "string",
      "example": "U2PVVSEV4V9Y"
    }
  }
}


impl EmailData for ProFeatureRequest {
    async fn get_email_data(&self, _base_url: &str) -> CustomResult<EmailContents, EmailError> {
        let recipient = self.recipient_email.clone().into_inner();

        let body = html::get_html_body(EmailBody::ProFeatureRequest {
            user_name: self.user_name.clone().get_secret().expose(),
            feature_name: self.feature_name.clone(),
            merchant_id: self.merchant_id.clone(),
            user_email: self.user_email.clone().get_secret().expose(),
        });

        Ok(EmailContents {
            subject: self.subject.clone(),
            body: external_services::email::IntermediateString::new(body),
            recipient,
        })
    }
}

impl EmailData for for ProFeatureRequest


pub fn construct_recovery_record_back_router_data(
    state: &SessionState,
    billing_mca: &merchant_connector_account::MerchantConnectorAccount,
    payment_attempt: &PaymentAttempt,
    payment_intent: &PaymentIntent,
) -> RecoveryResult<hyperswitch_domain_models::types::RevenueRecoveryRecordBackRouterData> {
    logger::info!("Entering construct_recovery_record_back_router_data");

    let auth_type: types::ConnectorAuthType =
        helpers::MerchantConnectorAccountType::DbVal(Box::new(billing_mca.clone()))
            .get_connector_account_details()
            .parse_value("ConnectorAuthType")
            .change_context(errors::RecoveryError::RecordBackToBillingConnectorFailed)?;

    let merchant_reference_id = payment_intent
        .merchant_reference_id
        .clone()
        .ok_or(errors::RecoveryError::RecordBackToBillingConnectorFailed)
        .attach_printable(
            "Merchant reference id not found while recording back to billing connector",
        )?;
    let connector_name = billing_mca.get_connector_name_as_string();
    let connector = common_enums::connector_enums::Connector::from_str(connector_name.as_str())
        .change_context(errors::RecoveryError::RecordBackToBillingConnectorFailed)
        .attach_printable("Cannot find connector from the connector_name")?;

    let connector_params =
        hyperswitch_domain_models::connector_endpoints::Connectors::get_connector_params(
            &state.conf.connectors,
            connector,
        )
        .change_context(errors::RecoveryError::RecordBackToBillingConnectorFailed)
        .attach_printable(format!(
            "cannot find connector params for this connector {connector} in this flow",
        ))?;

    let router_data = router_data_v2::RouterDataV2 {
        flow: PhantomData::<router_flow_types::RecoveryRecordBack>,
        tenant_id: state.tenant.tenant_id.clone(),
        resource_common_data: flow_common_types::RevenueRecoveryRecordBackData,
        connector_auth_type: auth_type,
        request: revenue_recovery_request::RevenueRecoveryRecordBackRequest {
            merchant_reference_id,
            amount: payment_attempt.get_total_amount(),
            currency: payment_intent.amount_details.currency,
            payment_method_type: Some(payment_attempt.payment_method_subtype),
            attempt_status: payment_attempt.status,
            connector_transaction_id: payment_attempt
                .connector_payment_id
                .as_ref()
                .map(|id| common_utils::types::ConnectorTransactionId::TxnId(id.clone())),
            connector_params,
        },
        response: Err(types::ErrorResponse::default()),
    };
    let old_router_data =
        flow_common_types::RevenueRecoveryRecordBackData::to_old_router_data(router_data)
            .change_context(errors::RecoveryError::RecordBackToBillingConnectorFailed)
            .attach_printable("Cannot construct record back router data")?;
    Ok(old_router_data)
}


pub fn is_prod_email_required(data: &ProdIntent, user_email: String) -> bool {
    let poc_email_check = not_contains_string(
        data.poc_email.as_ref().map(|email| email.peek().as_str()),
        "juspay",
    );
    let business_website_check = not_contains_string(data.business_website.as_deref(), "juspay")
        && not_contains_string(data.business_website.as_deref(), "hyperswitch");
    let user_email_check = not_contains_string(Some(&user_email), "juspay");

    if (poc_email_check && business_website_check && user_email_check).not() {
        logger::info!(prod_intent_email = poc_email_check);
        logger::info!(prod_intent_email = business_website_check);
        logger::info!(prod_intent_email = user_email_check);
    }

    poc_email_check && business_website_check && user_email_check
}


impl api::Payment for Mpgs {}


pub struct V2AdditionalParams {
    pub challenge_window_size: Option<String>,
    /// Recurring Expiry in format YYYYMMDD. REQUIRED if isRebilling = 0, We recommend setting rebillExpiry to a value of no more than 5 years from the date of the initial transaction processing date.
    pub rebill_expiry: Option<String>,
    /// Recurring Frequency in days
    pub rebill_frequency: Option<String>,
    pub challenge_preference: Option<String>,
}


pub struct KlarnaCaptureRequest {
    captured_amount: MinorUnit,
    reference: Option<String>,
}


Documentation: api-reference/v1/routing/routing--deactivate.mdx
# Type: Doc File

---
openapi: post /routing/deactivate
---


impl Request {
    pub fn new(method: Method, url: &str) -> Self {
        Self {
            method,
            url: String::from(url),
            headers: std::collections::HashSet::new(),
            certificate: None,
            certificate_key: None,
            body: None,
            ca_certificate: None,
        }
    }

    pub fn set_body<T: Into<RequestContent>>(&mut self, body: T) {
        self.body.replace(body.into());
    }

    pub fn add_default_headers(&mut self) {
        self.headers.extend(default_request_headers());
    }

    pub fn add_header(&mut self, header: &str, value: Maskable<String>) {
        self.headers.insert((String::from(header), value));
    }

    pub fn add_certificate(&mut self, certificate: Option<Secret<String>>) {
        self.certificate = certificate;
    }

    pub fn add_certificate_key(&mut self, certificate_key: Option<Secret<String>>) {
        self.certificate = certificate_key;
    }
}


pub async fn call_encryption_service<T, R>(
    state: &KeyManagerState,
    method: Method,
    endpoint: &str,
    request_body: T,
) -> errors::CustomResult<R, errors::KeyManagerClientError>
where
    T: GetKeymanagerTenant + ConvertRaw + Send + Sync + 'static + Debug,
    R: serde::de::DeserializeOwned,
{
    let url = format!("{}/{endpoint}", &state.url);

    logger::info!(key_manager_request=?request_body);
    let mut header = vec![];
    header.push((
        HeaderName::from_str(CONTENT_TYPE)
            .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
        HeaderValue::from_str("application/json")
            .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
    ));
    #[cfg(feature = "km_forward_x_request_id")]
    if let Some(request_id) = state.request_id {
        header.push((
            HeaderName::from_str(X_REQUEST_ID)
                .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
            HeaderValue::from_str(request_id.as_hyphenated().to_string().as_str())
                .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
        ))
    }

    //Add Tenant ID
    header.push((
        HeaderName::from_str(TENANT_HEADER)
            .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
        HeaderValue::from_str(request_body.get_tenant_id(state).get_string_repr())
            .change_context(errors::KeyManagerClientError::FailedtoConstructHeader)?,
    ));

    let response = send_encryption_request(
        state,
        HeaderMap::from_iter(header.into_iter()),
        url,
        method,
        request_body,
    )
    .await
    .map_err(|err| err.change_context(errors::KeyManagerClientError::RequestSendFailed))?;

    logger::info!(key_manager_response=?response);

    match response.status() {
        StatusCode::OK => response
            .json::<R>()
            .await
            .change_context(errors::KeyManagerClientError::ResponseDecodingFailed),
        StatusCode::INTERNAL_SERVER_ERROR => {
            Err(errors::KeyManagerClientError::InternalServerError(
                response
                    .bytes()
                    .await
                    .change_context(errors::KeyManagerClientError::ResponseDecodingFailed)?,
            )
            .into())
        }
        StatusCode::BAD_REQUEST => Err(errors::KeyManagerClientError::BadRequest(
            response
                .bytes()
                .await
                .change_context(errors::KeyManagerClientError::ResponseDecodingFailed)?,
        )
        .into()),
        _ => Err(errors::KeyManagerClientError::Unexpected(
            response
                .bytes()
                .await
                .change_context(errors::KeyManagerClientError::ResponseDecodingFailed)?,
        )
        .into()),
    }
}


pub struct TransactionInteraction {
    origin: TransactionInteractionOrigin,
    eci_indicator: TransactionInteractionEciIndicator,
    pos_condition_code: TransactionInteractionPosConditionCode,
}


pub struct MonerisCancelRequest {
    idempotency_key: String,
    reason: Option<String>,
}


pub fn apply_changeset(self, source: Mandate) -> Mandate {
        let Self {
            mandate_status,
            amount_captured,
            connector_mandate_ids,
            connector_mandate_id,
            payment_method_id,
            original_payment_id,
            updated_by,
        } = self;

        Mandate {
            mandate_status: mandate_status.unwrap_or(source.mandate_status),
            amount_captured: amount_captured.map_or(source.amount_captured, Some),
            connector_mandate_ids: connector_mandate_ids.map_or(source.connector_mandate_ids, Some),
            connector_mandate_id: connector_mandate_id.map_or(source.connector_mandate_id, Some),
            payment_method_id: payment_method_id.unwrap_or(source.payment_method_id),
            original_payment_id: original_payment_id.map_or(source.original_payment_id, Some),
            updated_by: updated_by.map_or(source.updated_by, Some),
            ..source
        }
    }


pub async fn modify_trackers<F, FData, D>(
    state: &routes::SessionState,
    connector: String,
    payment_data: &mut D,
    key_store: &domain::MerchantKeyStore,
    storage_scheme: storage_enums::MerchantStorageScheme,
    router_data: types::RouterData<F, FData, types::PaymentsResponseData>,
    is_step_up: bool,
) -> RouterResult<()>
where
    F: Clone + Send,
    FData: Send + types::Capturable,
    D: payments::OperationSessionGetters<F> + payments::OperationSessionSetters<F> + Send + Sync,
{
    let new_attempt_count = payment_data.get_payment_intent().attempt_count + 1;
    let new_payment_attempt = make_new_payment_attempt(
        connector,
        payment_data.get_payment_attempt().clone(),
        new_attempt_count,
        is_step_up,
        payment_data.get_payment_intent().setup_future_usage,
    );

    let db = &*state.store;
    let key_manager_state = &state.into();
    let additional_payment_method_data =
        payments::helpers::update_additional_payment_data_with_connector_response_pm_data(
            payment_data
                .get_payment_attempt()
                .payment_method_data
                .clone(),
            router_data
                .connector_response
                .clone()
                .and_then(|connector_response| connector_response.additional_payment_method_data),
        )?;

    let debit_routing_savings = payment_data.get_payment_method_data().and_then(|data| {
        payments::helpers::get_debit_routing_savings_amount(
            data,
            payment_data.get_payment_attempt(),
        )
    });

    match router_data.response {
        Ok(types::PaymentsResponseData::TransactionResponse {
            resource_id,
            connector_metadata,
            redirection_data,
            charges,
            ..
        }) => {
            let encoded_data = payment_data.get_payment_attempt().encoded_data.clone();

            let authentication_data = (*redirection_data)
                .as_ref()
                .map(Encode::encode_to_value)
                .transpose()
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Could not parse the connector response")?;

            let payment_attempt_update = storage::PaymentAttemptUpdate::ResponseUpdate {
                status: router_data.status,
                connector: None,
                connector_transaction_id: match resource_id {
                    types::ResponseId::NoResponseId => None,
                    types::ResponseId::ConnectorTransactionId(id)
                    | types::ResponseId::EncodedData(id) => Some(id),
                },
                connector_response_reference_id: payment_data
                    .get_payment_attempt()
                    .connector_response_reference_id
                    .clone(),
                authentication_type: None,
                payment_method_id: payment_data.get_payment_attempt().payment_method_id.clone(),
                mandate_id: payment_data
                    .get_mandate_id()
                    .and_then(|mandate| mandate.mandate_id.clone()),
                connector_metadata,
                payment_token: None,
                error_code: None,
                error_message: None,
                error_reason: None,
                amount_capturable: if router_data.status.is_terminal_status() {
                    Some(MinorUnit::new(0))
                } else {
                    None
                },
                updated_by: storage_scheme.to_string(),
                authentication_data,
                encoded_data,
                unified_code: None,
                unified_message: None,
                capture_before: None,
                extended_authorization_applied: None,
                payment_method_data: additional_payment_method_data,
                connector_mandate_detail: None,
                charges,
                setup_future_usage_applied: None,
                debit_routing_savings,
                network_transaction_id: payment_data
                    .get_payment_attempt()
                    .network_transaction_id
                    .clone(),
            };

            #[cfg(feature = "v1")]
            db.update_payment_attempt_with_attempt_id(
                payment_data.get_payment_attempt().clone(),
                payment_attempt_update,
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

            #[cfg(feature = "v2")]
            db.update_payment_attempt_with_attempt_id(
                key_manager_state,
                key_store,
                payment_data.get_payment_attempt().clone(),
                payment_attempt_update,
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
        }
        Ok(_) => {
            logger::error!("unexpected response: this response was not expected in Retry flow");
            return Ok(());
        }
        Err(ref error_response) => {
            let option_gsm = get_gsm(state, &router_data).await?;
            let auth_update = if Some(router_data.auth_type)
                != payment_data.get_payment_attempt().authentication_type
            {
                Some(router_data.auth_type)
            } else {
                None
            };

            let payment_attempt_update = storage::PaymentAttemptUpdate::ErrorUpdate {
                connector: None,
                error_code: Some(Some(error_response.code.clone())),
                error_message: Some(Some(error_response.message.clone())),
                status: storage_enums::AttemptStatus::Failure,
                error_reason: Some(error_response.reason.clone()),
                amount_capturable: Some(MinorUnit::new(0)),
                updated_by: storage_scheme.to_string(),
                unified_code: option_gsm.clone().map(|gsm| gsm.unified_code),
                unified_message: option_gsm.map(|gsm| gsm.unified_message),
                connector_transaction_id: error_response.connector_transaction_id.clone(),
                payment_method_data: additional_payment_method_data,
                authentication_type: auth_update,
                issuer_error_code: error_response.network_decline_code.clone(),
                issuer_error_message: error_response.network_error_message.clone(),
            };

            #[cfg(feature = "v1")]
            db.update_payment_attempt_with_attempt_id(
                payment_data.get_payment_attempt().clone(),
                payment_attempt_update,
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

            #[cfg(feature = "v2")]
            db.update_payment_attempt_with_attempt_id(
                key_manager_state,
                key_store,
                payment_data.get_payment_attempt().clone(),
                payment_attempt_update,
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
        }
    }

    #[cfg(feature = "v1")]
    let payment_attempt = db
        .insert_payment_attempt(new_payment_attempt, storage_scheme)
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Error inserting payment attempt")?;

    #[cfg(feature = "v2")]
    let payment_attempt = db
        .insert_payment_attempt(
            key_manager_state,
            key_store,
            new_payment_attempt,
            storage_scheme,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Error inserting payment attempt")?;

    // update payment_attempt, connector_response and payment_intent in payment_data
    payment_data.set_payment_attempt(payment_attempt);

    let payment_intent = db
        .update_payment_intent(
            key_manager_state,
            payment_data.get_payment_intent().clone(),
            storage::PaymentIntentUpdate::PaymentAttemptAndAttemptCountUpdate {
                active_attempt_id: payment_data.get_payment_attempt().get_id().to_owned(),
                attempt_count: new_attempt_count,
                updated_by: storage_scheme.to_string(),
            },
            key_store,
            storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

    payment_data.set_payment_intent(payment_intent);

    Ok(())
}


macro_rules! impl_error_type {
    ($name: ident, $arg: tt) => {
        #[derive(Debug)]
        pub struct $name;

        impl_error_display!($name, $arg);

        impl std::error::Error for $name {}
    };
}


pub fn get_next_connector(
    connectors: &mut IntoIter<api::ConnectorRoutingData>,
) -> RouterResult<api::ConnectorRoutingData> {
    connectors
        .next()
        .ok_or(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Connector not found in connectors iterator")
}


impl<T: serde::Serialize> common_utils::events::ApiEventMetric
        for PaymentsGenericRequestWithResourceId<T>
    {
        fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
            Some(common_utils::events::ApiEventsType::Payment {
                payment_id: self.global_payment_id.clone(),
            })
        }
    }

impl common_utils::events::ApiEventMetric
        for for PaymentsGenericRequestWithResourceId


pub fn get_webhook_object_from_body(body: &[u8]) -> CustomResult<Self, errors::ConnectorError> {
        let webhook_body = body
            .parse_struct::<Self>("ChargebeeWebhookBody")
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
        Ok(webhook_body)
    }


pub struct CustomerUpdateRequest {
    /// The customer's name
    #[schema(max_length = 255, value_type = String, example = "Jon Test")]
    pub name: Option<Secret<String>>,
    /// The customer's email address
    #[schema(value_type = String, max_length = 255, example = "JonTest@test.com")]
    pub email: Option<pii::Email>,
    /// The customer's phone number
    #[schema(value_type = Option<String>, max_length = 255, example = "9123456789")]
    pub phone: Option<Secret<String>>,
    /// An arbitrary string that you can attach to a customer object.
    #[schema(max_length = 255, example = "First Customer", value_type = Option<String>)]
    pub description: Option<Description>,
    /// The country code for the customer phone number
    #[schema(max_length = 255, example = "+65")]
    pub phone_country_code: Option<String>,
    /// The default billing address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_billing_address: Option<payments::AddressDetails>,
    /// The default shipping address for the customer
    #[schema(value_type = Option<AddressDetails>)]
    pub default_shipping_address: Option<payments::AddressDetails>,
    /// 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.
    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
    /// The unique identifier of the payment method
    #[schema(value_type = Option<String>, example = "12345_pm_01926c58bc6e77c09e809964e72af8c8")]
    pub default_payment_method_id: Option<id_type::GlobalPaymentMethodId>,
    /// The customer's tax registration number.
    #[schema(max_length = 255, value_type = Option<String>, example = "123456789")]
    pub tax_registration_id: Option<Secret<String>>,
}


impl RuleMigrationResponse {
    pub fn new(
        profile_id: common_utils::id_type::ProfileId,
        euclid_algorithm_id: common_utils::id_type::RoutingId,
        decision_engine_algorithm_id: String,
        is_active_rule: bool,
    ) -> Self {
        Self {
            profile_id,
            euclid_algorithm_id,
            decision_engine_algorithm_id,
            is_active_rule,
        }
    }
}


pub struct BlackhawknetworkAccessTokenRequest {
    pub grant_type: String,
    pub client_id: Secret<String>,
    pub client_secret: Secret<String>,
    pub scope: String,
}


impl api::Refund for Wellsfargopayout {}

impl api::Refund for for Wellsfargopayout


impl api::RefundExecute for Worldpayvantiv {}

impl api::RefundExecute for for Worldpayvantiv


impl OpenSearchConfig {
    pub async fn get_opensearch_client(&self) -> StorageResult<Option<OpenSearchClient>> {
        if !self.enabled {
            return Ok(None);
        }
        Ok(Some(
            OpenSearchClient::create(self)
                .await
                .change_context(StorageError::InitializationError)?,
        ))
    }

    pub fn validate(&self) -> Result<(), ApplicationError> {
        use common_utils::{ext_traits::ConfigExt, fp_utils::when};

        if !self.enabled {
            return Ok(());
        }

        when(self.host.is_default_or_empty(), || {
            Err(ApplicationError::InvalidConfigurationValueError(
                "Opensearch host must not be empty".into(),
            ))
        })?;

        self.indexes.validate()?;

        self.auth.validate()?;

        Ok(())
    }
}


/// Merchant's already created config can be updated and this change will be reflected
/// in DB as well for the particular updated config
pub async fn update_merchant_default_config(
    db: &dyn StorageInterface,
    merchant_id: &str,
    connectors: Vec<routing_types::RoutableConnectorChoice>,
    transaction_type: &storage::enums::TransactionType,
) -> RouterResult<()> {
    let key = get_default_config_key(merchant_id, transaction_type);
    let config_str = connectors
        .encode_to_string_of_json()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to serialize merchant default routing config during update")?;

    let config_update = configs::ConfigUpdate::Update {
        config: Some(config_str),
    };

    db.update_config_by_key(&key, config_update)
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Error updating the default routing config in DB")?;

    Ok(())
}


pub async fn payouts_core(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    payout_data: &mut PayoutData,
    routing_algorithm: Option<serde_json::Value>,
    eligible_connectors: Option<Vec<api_enums::PayoutConnectors>>,
) -> RouterResult<()> {
    todo!()
}


OpenAPI Block Path: components.schemas.DisputeStatus
{
  "type": "string",
  "description": "Status of the dispute",
  "enum": [
    "dispute_opened",
    "dispute_expired",
    "dispute_accepted",
    "dispute_cancelled",
    "dispute_challenged",
    "dispute_won",
    "dispute_lost"
  ]
}


pub struct Card {
    number: cards::CardNumber,
    expiration_month: Secret<String>,
    expiration_year: Secret<String>,
    security_code: Option<Secret<String>>,
    #[serde(rename = "type")]
    card_type: Option<String>,
}