    deserializer: D,
) -> Result<Option<enums::Currency>, D::Error>
where
    D: serde::Deserializer<'de>,
{
    let string_data: Option<String> = Option::deserialize(deserializer)?;
    match string_data {
        Some(ref value) if !value.is_empty() => value
            .clone()
            .parse_enum("Currency")
            .map(Some)
            .map_err(|_| serde::de::Error::custom(format!("Invalid currency code: {value}"))),
        _ => Ok(None),
    }
}
#[cfg(feature = "payouts")]
pub trait CustomerDetails {
    fn get_customer_id(&self) -> Result<id_type::CustomerId, errors::ConnectorError>;
    fn get_customer_name(
        &self,
    ) -> Result<Secret<String, masking::WithType>, errors::ConnectorError>;
    fn get_customer_email(&self) -> Result<Email, errors::ConnectorError>;
    fn get_customer_phone(
        &self,
    ) -> Result<Secret<String, masking::WithType>, errors::ConnectorError>;
    fn get_customer_phone_country_code(&self) -> Result<String, errors::ConnectorError>;
}

#[cfg(feature = "payouts")]
impl CustomerDetails for hyperswitch_domain_models::router_request_types::CustomerDetails {
    fn get_customer_id(&self) -> Result<id_type::CustomerId, errors::ConnectorError> {
        self.customer_id
            .clone()
            .ok_or(errors::ConnectorError::MissingRequiredField {
                field_name: "customer_id",
            })
    }

    fn get_customer_name(
        &self,
    ) -> Result<Secret<String, masking::WithType>, errors::ConnectorError> {
        self.name
            .clone()
            .ok_or(errors::ConnectorError::MissingRequiredField {
                field_name: "customer_name",
            })
    }

    fn get_customer_email(&self) -> Result<Email, errors::ConnectorError> {
        self.email
            .clone()
            .ok_or(errors::ConnectorError::MissingRequiredField {
                field_name: "customer_email",
            })
    }

    fn get_customer_phone(
        &self,
    ) -> Result<Secret<String, masking::WithType>, errors::ConnectorError> {
        self.phone
            .clone()
            .ok_or(errors::ConnectorError::MissingRequiredField {
                field_name: "customer_phone",
            })
    }

    fn get_customer_phone_country_code(&self) -> Result<String, errors::ConnectorError> {
        self.phone_country_code
            .clone()
            .ok_or(errors::ConnectorError::MissingRequiredField {
                field_name: "customer_phone_country_code",
            })
    }
}

pub fn get_card_details(
    payment_method_data: PaymentMethodData,
    connector_name: &'static str,
) -> Result<Card, errors::ConnectorError> {
    match payment_method_data {
        PaymentMethodData::Card(details) => Ok(details),
        _ => Err(errors::ConnectorError::NotSupported {
            message: SELECTED_PAYMENT_METHOD.to_string(),
            connector: connector_name,
        })?,
    }
}

pub fn get_authorise_integrity_object<T>(
    amount_convertor: &dyn AmountConvertor<Output = T>,
    amount: T,
    currency: String,
) -> Result<AuthoriseIntegrityObject, error_stack::Report<errors::ConnectorError>> {
    let currency_enum = enums::Currency::from_str(currency.to_uppercase().as_str())
        .change_context(errors::ConnectorError::ParsingFailed)?;

    let amount_in_minor_unit =
        convert_back_amount_to_minor_units(amount_convertor, amount, currency_enum)?;

    Ok(AuthoriseIntegrityObject {
        amount: amount_in_minor_unit,
        currency: currency_enum,
    })
}

pub fn get_sync_integrity_object<T>(
    amount_convertor: &dyn AmountConvertor<Output = T>,
    amount: T,
    currency: String,
) -> Result<SyncIntegrityObject, error_stack::Report<errors::ConnectorError>> {
    let currency_enum = enums::Currency::from_str(currency.to_uppercase().as_str())
        .change_context(errors::ConnectorError::ParsingFailed)?;
    let amount_in_minor_unit =
        convert_back_amount_to_minor_units(amount_convertor, amount, currency_enum)?;

    Ok(SyncIntegrityObject {
        amount: Some(amount_in_minor_unit),
        currency: Some(currency_enum),
    })
}

pub fn get_capture_integrity_object<T>(
    amount_convertor: &dyn AmountConvertor<Output = T>,
    capture_amount: Option<T>,
    currency: String,
) -> Result<CaptureIntegrityObject, error_stack::Report<errors::ConnectorError>> {
    let currency_enum = enums::Currency::from_str(currency.to_uppercase().as_str())
        .change_context(errors::ConnectorError::ParsingFailed)?;

    let capture_amount_in_minor_unit = capture_amount
        .map(|amount| convert_back_amount_to_minor_units(amount_convertor, amount, currency_enum))
        .transpose()?;

    Ok(CaptureIntegrityObject {
        capture_amount: capture_amount_in_minor_unit,
        currency: currency_enum,
    })
}

pub fn get_refund_integrity_object<T>(
    amount_convertor: &dyn AmountConvertor<Output = T>,
    refund_amount: T,
    currency: String,
) -> Result<RefundIntegrityObject, error_stack::Report<errors::ConnectorError>> {
    let currency_enum = enums::Currency::from_str(currency.to_uppercase().as_str())
        .change_context(errors::ConnectorError::ParsingFailed)?;

    let refund_amount_in_minor_unit =
        convert_back_amount_to_minor_units(amount_convertor, refund_amount, currency_enum)?;

    Ok(RefundIntegrityObject {
        currency: currency_enum,
        refund_amount: refund_amount_in_minor_unit,
    })
}

#[cfg(feature = "frm")]
pub trait FraudCheckSaleRequest {
    fn get_order_details(&self) -> Result<Vec<OrderDetailsWithAmount>, Error>;
}
#[cfg(feature = "frm")]
impl FraudCheckSaleRequest for FraudCheckSaleData {
    fn get_order_details(&self) -> Result<Vec<OrderDetailsWithAmount>, Error> {
        self.order_details
            .clone()
            .ok_or_else(missing_field_err("order_details"))
    }
}

#[cfg(feature = "frm")]
pub trait FraudCheckRecordReturnRequest {
    fn get_currency(&self) -> Result<enums::Currency, Error>;
}
#[cfg(feature = "frm")]
impl FraudCheckRecordReturnRequest for FraudCheckRecordReturnData {
    fn get_currency(&self) -> Result<enums::Currency, Error> {
        self.currency.ok_or_else(missing_field_err("currency"))
    }
}

pub trait SplitPaymentData {
    fn get_split_payment_data(&self) -> Option<common_types::payments::SplitPaymentsRequest>;
}

impl SplitPaymentData for PaymentsCaptureData {
    fn get_split_payment_data(&self) -> Option<common_types::payments::SplitPaymentsRequest> {
        None
    }
}

impl SplitPaymentData for PaymentsAuthorizeData {
    fn get_split_payment_data(&self) -> Option<common_types::payments::SplitPaymentsRequest> {
        self.split_payments.clone()
    }
}

impl SplitPaymentData for PaymentsSyncData {
    fn get_split_payment_data(&self) -> Option<common_types::payments::SplitPaymentsRequest> {
        self.split_payments.clone()
    }
}

impl SplitPaymentData for PaymentsCancelData {
    fn get_split_payment_data(&self) -> Option<common_types::payments::SplitPaymentsRequest> {
        None
    }
}

impl SplitPaymentData for SetupMandateRequestData {
    fn get_split_payment_data(&self) -> Option<common_types::payments::SplitPaymentsRequest> {
        None
    }
}
impl SplitPaymentData for ExternalVaultProxyPaymentsData {
    fn get_split_payment_data(&self) -> Option<common_types::payments::SplitPaymentsRequest> {
        None
    }
}

pub struct XmlSerializer;
impl XmlSerializer {
    pub fn serialize_to_xml_bytes<T: Serialize>(
        item: &T,
        xml_version: &str,
        xml_encoding: Option<&str>,
        xml_standalone: Option<&str>,
        xml_doc_type: Option<&str>,
    ) -> Result<Vec<u8>, error_stack::Report<errors::ConnectorError>> {
        let mut xml_bytes = Vec::new();
        let mut writer = Writer::new(std::io::Cursor::new(&mut xml_bytes));

        writer
            .write_event(Event::Decl(BytesDecl::new(
                xml_version,
                xml_encoding,
                xml_standalone,
            )))
            .change_context(errors::ConnectorError::RequestEncodingFailed)
            .attach_printable("Failed to write XML declaration")?;

        if let Some(xml_doc_type_data) = xml_doc_type {
            writer
                .write_event(Event::DocType(BytesText::from_escaped(xml_doc_type_data)))
                .change_context(errors::ConnectorError::RequestEncodingFailed)
                .attach_printable("Failed to write the XML declaration")?;
        };

        let xml_body = quick_xml::se::to_string(&item)
            .change_context(errors::ConnectorError::RequestEncodingFailed)
            .attach_printable("Failed to serialize the XML body")?;

        writer
            .write_event(Event::Text(BytesText::from_escaped(xml_body)))
            .change_context(errors::ConnectorError::RequestEncodingFailed)
            .attach_printable("Failed to serialize the XML body")?;

        Ok(xml_bytes)
    }
}

pub fn deserialize_zero_minor_amount_as_none<'de, D>(
    deserializer: D,
) -> Result<Option<MinorUnit>, D::Error>
where
    D: serde::de::Deserializer<'de>,
{
    let amount = Option::<MinorUnit>::deserialize(deserializer)?;
    match amount {
        Some(value) if value.get_amount_as_i64() == 0 => Ok(None),
        _ => Ok(amount),
    }
}


// Implementation: impl Responder
// File: crates/router/src/routes/webhook_events.rs
// Module: router
// Methods: 0 total (0 public)

impl Responder


// Struct: PaymentCaptureRequest
// File: crates/hyperswitch_connectors/src/connectors/payme/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentCaptureRequest


// File: crates/masking/src/serde.rs
// Module: masking
// Public functions: 1

//! Serde-related.

pub use erased_serde::Serialize as ErasedSerialize;
pub use serde::{de, Deserialize, Serialize, Serializer};
use serde_json::{value::Serializer as JsonValueSerializer, Value};

use crate::{Secret, Strategy, StrongSecret, ZeroizableSecret};

/// Marker trait for secret types which can be [`Serialize`]-d by [`serde`].
///
/// When the `serde` feature of this crate is enabled and types are marked with
/// this trait, they receive a [`Serialize` impl] for `Secret<T>`.
/// (NOTE: all types which impl `DeserializeOwned` receive a [`Deserialize`]
/// impl)
///
/// This is done deliberately to prevent accidental exfiltration of secrets
/// via `serde` serialization.
#[cfg_attr(docsrs, cfg(feature = "serde"))]
pub trait SerializableSecret: Serialize {}
// #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
// pub trait NonSerializableSecret: Serialize {}

impl SerializableSecret for Value {}
impl SerializableSecret for u8 {}
impl SerializableSecret for u16 {}
impl SerializableSecret for i8 {}
impl SerializableSecret for i32 {}
impl SerializableSecret for i64 {}
impl SerializableSecret for url::Url {}

#[cfg(feature = "time")]
impl SerializableSecret for time::Date {}

impl<T: SerializableSecret> SerializableSecret for &T {}

impl<'de, T, I> Deserialize<'de> for Secret<T, I>
where
    T: Clone + de::DeserializeOwned + Sized,
    I: Strategy<T>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        T::deserialize(deserializer).map(Self::new)
    }
}

impl<T, I> Serialize for Secret<T, I>
where
    T: SerializableSecret + Serialize + Sized,
    I: Strategy<T>,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        pii_serializer::pii_serialize(self, serializer)
    }
}

impl<'de, T, I> Deserialize<'de> for StrongSecret<T, I>
where
    T: Clone + de::DeserializeOwned + Sized + ZeroizableSecret,
    I: Strategy<T>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        T::deserialize(deserializer).map(Self::new)
    }
}

impl<T, I> Serialize for StrongSecret<T, I>
where
    T: SerializableSecret + Serialize + ZeroizableSecret + Sized,
    I: Strategy<T>,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        pii_serializer::pii_serialize(self, serializer)
    }
}

/// Masked serialization.
///
/// the default behaviour for secrets is to serialize in exposed format since the common use cases
/// for storing the secret to database or sending it over the network requires the secret to be exposed
/// This method allows to serialize the secret in masked format if needed for logs or other insecure exposures
pub fn masked_serialize<T: Serialize>(value: &T) -> Result<Value, serde_json::Error> {
    value.serialize(PIISerializer {
        inner: JsonValueSerializer,
    })
}

/// Masked serialization.
///
/// Trait object for supporting serialization to Value while accounting for masking
/// The usual Serde Serialize trait cannot be used as trait objects
/// like &dyn Serialize or boxed trait objects like Box<dyn Serialize> because of Rust's "object safety" rules.
/// In particular, the trait contains generic methods which cannot be made into a trait object.
/// In this case we remove the generic for assuming the serialization to be of 2 types only raw json or masked json
pub trait ErasedMaskSerialize: ErasedSerialize {
    /// Masked serialization.
    fn masked_serialize(&self) -> Result<Value, serde_json::Error>;
}

impl<T: Serialize + ErasedSerialize> ErasedMaskSerialize for T {
    fn masked_serialize(&self) -> Result<Value, serde_json::Error> {
        masked_serialize(self)
    }
}

impl Serialize for dyn ErasedMaskSerialize + '_ {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        erased_serde::serialize(self, serializer)
    }
}

impl Serialize for dyn ErasedMaskSerialize + '_ + Send {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        erased_serde::serialize(self, serializer)
    }
}

use pii_serializer::PIISerializer;

mod pii_serializer {
    use std::fmt::Display;

    pub(super) fn pii_serialize<
        V: Serialize,
        T: std::fmt::Debug + PeekInterface<V>,
        S: Serializer,
    >(
        value: &T,
        serializer: S,
    ) -> Result<S::Ok, S::Error> {
        // Mask the value if the serializer is of type PIISerializer
        // or send empty map if the serializer is of type FlatMapSerializer over PiiSerializer
        if std::any::type_name::<S>() == std::any::type_name::<PIISerializer>() {
            format!("{value:?}").serialize(serializer)
        } else if std::any::type_name::<S>()
            == std::any::type_name::<
                serde::__private::ser::FlatMapSerializer<'_, SerializeMap<PIISerializer>>,
            >()
        {
            std::collections::HashMap::<String, String>::from([]).serialize(serializer)
        } else {
            value.peek().serialize(serializer)
        }
    }

    use serde::{Serialize, Serializer};
    use serde_json::{value::Serializer as JsonValueSerializer, Map, Value};

    use crate::PeekInterface;

    pub(super) struct PIISerializer {
        pub inner: JsonValueSerializer,
    }

    impl Clone for PIISerializer {
        fn clone(&self) -> Self {
            Self {
                inner: JsonValueSerializer,
            }
        }
    }

    impl Serializer for PIISerializer {
        type Ok = Value;
        type Error = serde_json::Error;

        type SerializeSeq = SerializeVec<Self>;
        type SerializeTuple = SerializeVec<Self>;
        type SerializeTupleStruct = SerializeVec<Self>;
        type SerializeTupleVariant = SerializeTupleVariant<Self>;
        type SerializeMap = SerializeMap<Self>;
        type SerializeStruct = SerializeMap<Self>;
        type SerializeStructVariant = SerializeStructVariant<Self>;

        #[inline]
        fn serialize_bool(self, value: bool) -> Result<Self::Ok, Self::Error> {
            self.inner.serialize_bool(value)
        }

        #[inline]
        fn serialize_i8(self, value: i8) -> Result<Self::Ok, Self::Error> {
            self.serialize_i64(value.into())
        }

        #[inline]
        fn serialize_i16(self, value: i16) -> Result<Self::Ok, Self::Error> {
            self.serialize_i64(value.into())
        }

        #[inline]
        fn serialize_i32(self, value: i32) -> Result<Self::Ok, Self::Error> {
            self.serialize_i64(value.into())
        }

        fn serialize_i64(self, value: i64) -> Result<Self::Ok, Self::Error> {
            self.inner.serialize_i64(value)
        }

        fn serialize_i128(self, value: i128) -> Result<Self::Ok, Self::Error> {
            self.inner.serialize_i128(value)
        }

        #[inline]
        fn serialize_u8(self, value: u8) -> Result<Self::Ok, Self::Error> {
            self.serialize_u64(value.into())
        }

        #[inline]
        fn serialize_u16(self, value: u16) -> Result<Self::Ok, Self::Error> {
            self.serialize_u64(value.into())
        }

        #[inline]
        fn serialize_u32(self, value: u32) -> Result<Self::Ok, Self::Error> {
            self.serialize_u64(value.into())
        }

        #[inline]
        fn serialize_u64(self, value: u64) -> Result<Self::Ok, Self::Error> {
            Ok(Value::Number(value.into()))
        }

        fn serialize_u128(self, value: u128) -> Result<Self::Ok, Self::Error> {
            self.inner.serialize_u128(value)
        }

        #[inline]
        fn serialize_f32(self, float: f32) -> Result<Self::Ok, Self::Error> {
            Ok(Value::from(float))
        }

        #[inline]
        fn serialize_f64(self, float: f64) -> Result<Self::Ok, Self::Error> {
            Ok(Value::from(float))
        }

        #[inline]
        fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
            let mut s = String::new();
            s.push(value);
            Ok(Value::String(s))
        }

        #[inline]
        fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
            Ok(Value::String(value.to_owned()))
        }

        fn serialize_bytes(self, value: &[u8]) -> Result<Self::Ok, Self::Error> {
            let vec = value.iter().map(|&b| Value::Number(b.into())).collect();
            Ok(Value::Array(vec))
        }

        #[inline]
        fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
            Ok(Value::Null)
        }

        #[inline]
        fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
            self.serialize_unit()
        }

        #[inline]
        fn serialize_unit_variant(
            self,
            _name: &'static str,
            _variant_index: u32,
            variant: &'static str,
        ) -> Result<Self::Ok, Self::Error> {
            self.serialize_str(variant)
        }

        #[inline]
        fn serialize_newtype_struct<T>(
            self,
            _name: &'static str,
            value: &T,
        ) -> Result<Self::Ok, Self::Error>
        where
            T: ?Sized + Serialize,
        {
            value.serialize(self)
        }

        fn serialize_newtype_variant<T>(
            self,
            _name: &'static str,
            _variant_index: u32,
            variant: &'static str,
            value: &T,
        ) -> Result<Self::Ok, Self::Error>
        where
            T: ?Sized + Serialize,
        {
            let mut values = Map::new();
            values.insert(String::from(variant), value.serialize(self)?);
            Ok(Value::Object(values))
        }

        #[inline]
        fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
            self.serialize_unit()
        }

        #[inline]
        fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
        where
            T: ?Sized + Serialize,
        {
            value.serialize(self)
        }

        fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
            Ok(SerializeVec {
                vec: Vec::with_capacity(len.unwrap_or(0)),
                ser: self,
            })
        }

        fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
            self.serialize_seq(Some(len))
        }

        fn serialize_tuple_struct(
            self,
            _name: &'static str,
            len: usize,
        ) -> Result<Self::SerializeTupleStruct, Self::Error> {
            self.serialize_seq(Some(len))
        }

        fn serialize_tuple_variant(
            self,
            _name: &'static str,
            _variant_index: u32,
            variant: &'static str,
            len: usize,
        ) -> Result<Self::SerializeTupleVariant, Self::Error> {
            Ok(SerializeTupleVariant {
                name: String::from(variant),
                vec: Vec::with_capacity(len),
                ser: self,
            })
        }

        fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
            Ok(SerializeMap {
                inner: self.clone().inner.serialize_map(len)?,
                ser: self,
            })
        }

        fn serialize_struct(
            self,
            _name: &'static str,
            len: usize,
        ) -> Result<Self::SerializeStruct, Self::Error> {
            self.serialize_map(Some(len))
        }

        fn serialize_struct_variant(
            self,
            _name: &'static str,
            _variant_index: u32,
            variant: &'static str,
            _len: usize,
        ) -> Result<Self::SerializeStructVariant, Self::Error> {
            Ok(SerializeStructVariant {
                name: String::from(variant),
                map: Map::new(),
                ser: self,
            })
        }

        fn collect_str<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
        where
            T: ?Sized + Display,
        {
            self.inner.collect_str(value)
        }
    }

    pub(super) struct SerializeVec<T: Serializer> {
        vec: Vec<Value>,
        ser: T,
    }

    impl<T: Serializer<Ok = Value> + Clone> serde::ser::SerializeSeq for SerializeVec<T> {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_element<V>(&mut self, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            self.vec.push(value.serialize(self.ser.clone())?);
            Ok(())
        }

        fn end(self) -> Result<Self::Ok, Self::Error> {
            Ok(Value::Array(self.vec))
        }
    }

    impl<T: Serializer<Ok = Value> + Clone> serde::ser::SerializeTuple for SerializeVec<T> {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_element<V>(&mut self, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            serde::ser::SerializeSeq::serialize_element(self, value)
        }

        fn end(self) -> Result<Self::Ok, Self::Error> {
            serde::ser::SerializeSeq::end(self)
        }
    }

    impl<T: Serializer<Ok = Value> + Clone> serde::ser::SerializeTupleStruct for SerializeVec<T> {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_field<V>(&mut self, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            serde::ser::SerializeSeq::serialize_element(self, value)
        }

        fn end(self) -> Result<Self::Ok, Self::Error> {
            serde::ser::SerializeSeq::end(self)
        }
    }

    pub(super) struct SerializeStructVariant<T: Serializer> {
        name: String,
        map: Map<String, Value>,
        ser: T,
    }

    impl<T: Serializer<Ok = Value> + Clone> serde::ser::SerializeStructVariant
        for SerializeStructVariant<T>
    {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_field<V>(&mut self, key: &'static str, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            self.map
                .insert(String::from(key), value.serialize(self.ser.clone())?);
            Ok(())
        }

        fn end(self) -> Result<Self::Ok, Self::Error> {
            let mut object = Map::new();

            object.insert(self.name, Value::Object(self.map));

            Ok(Value::Object(object))
        }
    }

    pub(super) struct SerializeTupleVariant<T: Serializer> {
        name: String,
        vec: Vec<Value>,
        ser: T,
    }

    impl<T: Serializer<Ok = Value> + Clone> serde::ser::SerializeTupleVariant
        for SerializeTupleVariant<T>
    {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_field<V>(&mut self, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            self.vec.push(value.serialize(self.ser.clone())?);
            Ok(())
        }

        fn end(self) -> Result<Value, Self::Error> {
            let mut object = Map::new();

            object.insert(self.name, Value::Array(self.vec));

            Ok(Value::Object(object))
        }
    }

    pub(super) struct SerializeMap<T: Serializer> {
        inner: <serde_json::value::Serializer as Serializer>::SerializeMap,
        ser: T,
    }

    impl<T: Serializer<Ok = Value, Error = serde_json::Error> + Clone> serde::ser::SerializeMap
        for SerializeMap<T>
    {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_key<V>(&mut self, key: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            self.inner.serialize_key(key)?;
            Ok(())
        }

        fn serialize_value<V>(&mut self, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            let value = value.serialize(self.ser.clone())?;
            self.inner.serialize_value(&value)?;
            Ok(())
        }

        fn end(self) -> Result<Value, Self::Error> {
            self.inner.end()
        }
    }

    impl<T: Serializer<Ok = Value, Error = serde_json::Error> + Clone> serde::ser::SerializeStruct
        for SerializeMap<T>
    {
        type Ok = Value;
        type Error = T::Error;

        fn serialize_field<V>(&mut self, key: &'static str, value: &V) -> Result<(), Self::Error>
        where
            V: ?Sized + Serialize,
        {
            serde::ser::SerializeMap::serialize_entry(self, key, value)
        }

        fn end(self) -> Result<Value, Self::Error> {
            serde::ser::SerializeMap::end(self)
        }
    }
}


// File: crates/common_types/src/three_ds_decision_rule_engine.rs
// Module: common_types
// Public functions: 2
// Public structs: 1

use common_utils::impl_to_sql_from_sql_json;
use diesel::{sql_types::Jsonb, AsExpression, FromSqlRow};
use euclid::frontend::dir::{DirKeyKind, EuclidDirFilter};
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

/// Enum representing the possible outcomes of the 3DS Decision Rule Engine.
#[derive(
    Serialize,
    Deserialize,
    Debug,
    Clone,
    Copy,
    PartialEq,
    Eq,
    FromSqlRow,
    AsExpression,
    ToSchema,
    Default,
)]
#[diesel(sql_type = Jsonb)]
#[serde(rename_all = "snake_case")]
pub enum ThreeDSDecision {
    /// No 3DS authentication required
    #[default]
    NoThreeDs,
    /// Mandate 3DS Challenge
    ChallengeRequested,
    /// Prefer 3DS Challenge
    ChallengePreferred,
    /// Request 3DS Exemption, Type: Transaction Risk Analysis (TRA)
    ThreeDsExemptionRequestedTra,
    /// Request 3DS Exemption, Type: Low Value Transaction
    ThreeDsExemptionRequestedLowValue,
    /// No challenge requested by merchant (e.g., delegated authentication)
    IssuerThreeDsExemptionRequested,
}
impl_to_sql_from_sql_json!(ThreeDSDecision);

impl ThreeDSDecision {
    /// Checks if the decision is to mandate a 3DS challenge
    pub fn should_force_3ds_challenge(self) -> bool {
        matches!(self, Self::ChallengeRequested)
    }
}

/// Struct representing the output configuration for the 3DS Decision Rule Engine.
#[derive(
    Serialize, Default, Deserialize, Debug, Clone, PartialEq, Eq, FromSqlRow, AsExpression, ToSchema,
)]
#[diesel(sql_type = Jsonb)]
pub struct ThreeDSDecisionRule {
    /// The decided 3DS action based on the rules
    pub decision: ThreeDSDecision,
}

impl ThreeDSDecisionRule {
    /// Returns the decision
    pub fn get_decision(&self) -> ThreeDSDecision {
        self.decision
    }
}

impl_to_sql_from_sql_json!(ThreeDSDecisionRule);

impl EuclidDirFilter for ThreeDSDecisionRule {
    const ALLOWED: &'static [DirKeyKind] = &[
        DirKeyKind::CardNetwork,
        DirKeyKind::PaymentAmount,
        DirKeyKind::PaymentCurrency,
        DirKeyKind::IssuerName,
        DirKeyKind::IssuerCountry,
        DirKeyKind::CustomerDevicePlatform,
        DirKeyKind::CustomerDeviceType,
        DirKeyKind::CustomerDeviceDisplaySize,
        DirKeyKind::AcquirerCountry,
        DirKeyKind::AcquirerFraudRate,
    ];
}


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

pub fn get_role_info_from_db(&self, state: &SessionState) -> UserResult<RoleInfo>


// Struct: GetPaymentMetricRequest
// File: crates/api_models/src/analytics.rs
// Module: api_models
// Implementations: 0

pub struct GetPaymentMetricRequest


// Implementation: impl WebhookDetails
// File: crates/api_models/src/admin.rs
// Module: api_models
// Methods: 2 total (1 public)

impl WebhookDetails


// Struct: DashboardRequestPayload
// File: crates/connector_configs/src/common_config.rs
// Module: connector_configs
// Implementations: 0

pub struct DashboardRequestPayload


// Implementation: impl AcceptDispute for for Worldpayvantiv
// File: crates/hyperswitch_connectors/src/connectors/worldpayvantiv.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl AcceptDispute for for Worldpayvantiv


// Implementation: impl Responder
// File: crates/router/src/analytics.rs
// Module: router
// Methods: 0 total (0 public)

impl Responder


// Struct: AnalysisError
// File: crates/euclid/src/dssa/types.rs
// Module: euclid
// Implementations: 1
// Traits: fmt::Display

pub struct AnalysisError


// Function: into_stripe_next_action
// File: crates/router/src/compatibility/stripe/payment_intents/types.rs
// Module: router

pub fn into_stripe_next_action(
    next_action: Option<payments::NextActionData>,
    return_url: Option<String>,
) -> Option<StripeNextAction>


// File: crates/router/src/core/payments/operations/external_vault_proxy_payment_intent.rs
// Module: router
// Public structs: 1

use api_models::payments::ExternalVaultProxyPaymentsRequest;
use async_trait::async_trait;
use common_enums::enums;
use common_utils::{
    crypto::Encryptable,
    ext_traits::{AsyncExt, ValueExt},
    types::keymanager::ToEncryptable,
};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData, payments::PaymentConfirmData,
};
use hyperswitch_interfaces::api::ConnectorSpecifications;
use masking::PeekInterface;
use router_env::{instrument, tracing};

use super::{Domain, GetTracker, Operation, PostUpdateTracker, UpdateTracker, ValidateRequest};
use crate::{
    core::{
        errors::{self, CustomResult, RouterResult, StorageErrorExt},
        payment_methods::{self, PaymentMethodExt},
        payments::{
            self,
            operations::{self, ValidateStatusForOperation},
            OperationSessionGetters, OperationSessionSetters,
        },
    },
    routes::{app::ReqState, SessionState},
    types::{
        self,
        api::{self, ConnectorCallType},
        domain::{self, types as domain_types},
        storage::{self, enums as storage_enums},
    },
    utils::OptionExt,
};

#[derive(Debug, Clone, Copy)]
pub struct ExternalVaultProxyPaymentIntent;

impl ValidateStatusForOperation for ExternalVaultProxyPaymentIntent {
    /// Validate if the current operation can be performed on the current status of the payment intent
    fn validate_status_for_operation(
        &self,
        intent_status: common_enums::IntentStatus,
    ) -> Result<(), errors::ApiErrorResponse> {
        match intent_status {
            common_enums::IntentStatus::RequiresPaymentMethod
            | common_enums::IntentStatus::Failed
            | common_enums::IntentStatus::Processing => Ok(()),
            common_enums::IntentStatus::Conflicted
            | common_enums::IntentStatus::Succeeded
            | common_enums::IntentStatus::Cancelled
            | common_enums::IntentStatus::RequiresCustomerAction
            | common_enums::IntentStatus::RequiresMerchantAction
            | common_enums::IntentStatus::RequiresCapture
            | common_enums::IntentStatus::PartiallyCaptured
            | common_enums::IntentStatus::RequiresConfirmation
            | common_enums::IntentStatus::PartiallyCapturedAndCapturable
            | common_enums::IntentStatus::CancelledPostCapture
            | common_enums::IntentStatus::PartiallyAuthorizedAndRequiresCapture
            | common_enums::IntentStatus::Expired => {
                Err(errors::ApiErrorResponse::PaymentUnexpectedState {
                    current_flow: format!("{self:?}"),
                    field_name: "status".to_string(),
                    current_value: intent_status.to_string(),
                    states: ["requires_payment_method", "failed", "processing"].join(", "),
                })
            }
        }
    }
}

type BoxedConfirmOperation<'b, F> =
    super::BoxedOperation<'b, F, ExternalVaultProxyPaymentsRequest, PaymentConfirmData<F>>;

impl<F: Send + Clone + Sync> Operation<F, ExternalVaultProxyPaymentsRequest>
    for &ExternalVaultProxyPaymentIntent
{
    type Data = PaymentConfirmData<F>;
    fn to_validate_request(
        &self,
    ) -> RouterResult<
        &(dyn ValidateRequest<F, ExternalVaultProxyPaymentsRequest, Self::Data> + Send + Sync),
    > {
        Ok(*self)
    }
    fn to_get_tracker(
        &self,
    ) -> RouterResult<
        &(dyn GetTracker<F, Self::Data, ExternalVaultProxyPaymentsRequest> + Send + Sync),
    > {
        Ok(*self)
    }
    fn to_domain(
        &self,
    ) -> RouterResult<&(dyn Domain<F, ExternalVaultProxyPaymentsRequest, Self::Data>)> {
        Ok(*self)
    }
    fn to_update_tracker(
        &self,
    ) -> RouterResult<
        &(dyn UpdateTracker<F, Self::Data, ExternalVaultProxyPaymentsRequest> + Send + Sync),
    > {
        Ok(*self)
    }
}

#[automatically_derived]
impl<F: Send + Clone + Sync> Operation<F, ExternalVaultProxyPaymentsRequest>
    for ExternalVaultProxyPaymentIntent
{
    type Data = PaymentConfirmData<F>;
    fn to_validate_request(
        &self,
    ) -> RouterResult<
        &(dyn ValidateRequest<F, ExternalVaultProxyPaymentsRequest, Self::Data> + Send + Sync),
    > {
        Ok(self)
    }
    fn to_get_tracker(
        &self,
    ) -> RouterResult<
        &(dyn GetTracker<F, Self::Data, ExternalVaultProxyPaymentsRequest> + Send + Sync),
    > {
        Ok(self)
    }
    fn to_domain(
        &self,
    ) -> RouterResult<&dyn Domain<F, ExternalVaultProxyPaymentsRequest, Self::Data>> {
        Ok(self)
    }
    fn to_update_tracker(
        &self,
    ) -> RouterResult<
        &(dyn UpdateTracker<F, Self::Data, ExternalVaultProxyPaymentsRequest> + Send + Sync),
    > {
        Ok(self)
    }
}

impl<F: Send + Clone + Sync>
    ValidateRequest<F, ExternalVaultProxyPaymentsRequest, PaymentConfirmData<F>>
    for ExternalVaultProxyPaymentIntent
{
    #[instrument(skip_all)]
    fn validate_request<'a, 'b>(
        &'b self,
        _request: &ExternalVaultProxyPaymentsRequest,
        merchant_context: &'a domain::MerchantContext,
    ) -> RouterResult<operations::ValidateResult> {
        let validate_result = operations::ValidateResult {
            merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
            storage_scheme: merchant_context.get_merchant_account().storage_scheme,
            requeue: false,
        };

        Ok(validate_result)
    }
}

#[async_trait]
impl<F: Send + Clone + Sync> GetTracker<F, PaymentConfirmData<F>, ExternalVaultProxyPaymentsRequest>
    for ExternalVaultProxyPaymentIntent
{
    #[instrument(skip_all)]
    async fn get_trackers<'a>(
        &'a self,
        state: &'a SessionState,
        payment_id: &common_utils::id_type::GlobalPaymentId,
        request: &ExternalVaultProxyPaymentsRequest,
        merchant_context: &domain::MerchantContext,
        _profile: &domain::Profile,
        header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
    ) -> RouterResult<operations::GetTrackerResponse<PaymentConfirmData<F>>> {
        let db = &*state.store;
        let key_manager_state = &state.into();

        let storage_scheme = merchant_context.get_merchant_account().storage_scheme;

        let payment_intent = db
            .find_payment_intent_by_id(
                key_manager_state,
                payment_id,
                merchant_context.get_merchant_key_store(),
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

        self.validate_status_for_operation(payment_intent.status)?;

        let cell_id = state.conf.cell_information.id.clone();

        let batch_encrypted_data = domain_types::crypto_operation(
            key_manager_state,
            common_utils::type_name!(hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt),
            domain_types::CryptoOperation::BatchEncrypt(
                hyperswitch_domain_models::payments::payment_attempt::FromRequestEncryptablePaymentAttempt::to_encryptable(
                    hyperswitch_domain_models::payments::payment_attempt::FromRequestEncryptablePaymentAttempt {
                        payment_method_billing_address: None,
                    },
                ),
            ),
            common_utils::types::keymanager::Identifier::Merchant(merchant_context.get_merchant_account().get_id().to_owned()),
            merchant_context.get_merchant_key_store().key.peek(),
        )
        .await
        .and_then(|val| val.try_into_batchoperation())
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed while encrypting payment intent details".to_string())?;

        let encrypted_data =
             hyperswitch_domain_models::payments::payment_attempt::FromRequestEncryptablePaymentAttempt::from_encryptable(batch_encrypted_data)
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed while encrypting payment intent details")?;

        let payment_attempt = match payment_intent.active_attempt_id.clone() {
            Some(ref active_attempt_id) => db
                .find_payment_attempt_by_id(
                    key_manager_state,
                    merchant_context.get_merchant_key_store(),
                    active_attempt_id,
                    storage_scheme,
                )
                .await
                .change_context(errors::ApiErrorResponse::PaymentNotFound)
                .attach_printable("Could not find payment attempt")?,

            None => {
                // TODO: Implement external vault specific payment attempt creation logic
                let payment_attempt_domain_model: hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt =
                hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt::external_vault_proxy_create_domain_model(
                    &payment_intent,
                    cell_id,
                    storage_scheme,
                    request,
                    encrypted_data
                )
                .await?;
                db.insert_payment_attempt(
                    key_manager_state,
                    merchant_context.get_merchant_key_store(),
                    payment_attempt_domain_model,
                    storage_scheme,
                )
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Could not insert payment attempt")?
            }
        };

        // TODO: Extract external vault specific token/credentials from request
        let processor_payment_token = None; // request.external_vault_details.processor_payment_token.clone();

        let payment_address = hyperswitch_domain_models::payment_address::PaymentAddress::new(
            payment_intent
                .shipping_address
                .clone()
                .map(|address| address.into_inner()),
            payment_intent
                .billing_address
                .clone()
                .map(|address| address.into_inner()),
            payment_attempt
                .payment_method_billing_address
                .clone()
                .map(|address| address.into_inner()),
            Some(true),
        );

        // TODO: Implement external vault specific mandate data handling
        let mandate_data_input = api_models::payments::MandateIds {
            mandate_id: None,
            mandate_reference_id: processor_payment_token.map(|token| {
                api_models::payments::MandateReferenceId::ConnectorMandateId(
                    api_models::payments::ConnectorMandateReferenceId::new(
                        Some(token),
                        None,
                        None,
                        None,
                        None,
                    ),
                )
            }),
        };
        let payment_method_data = request.payment_method_data.payment_method_data.clone().map(
            hyperswitch_domain_models::payment_method_data::ExternalVaultPaymentMethodData::from,
        );

        let payment_data = PaymentConfirmData {
            flow: std::marker::PhantomData,
            payment_intent,
            payment_attempt,
            payment_method_data: None, // TODO: Review for external vault
            payment_address,
            mandate_data: Some(mandate_data_input),
            payment_method: None,
            merchant_connector_details: None,
            external_vault_pmd: payment_method_data,
        };

        let get_trackers_response = operations::GetTrackerResponse { payment_data };

        Ok(get_trackers_response)
    }
}

#[async_trait]
impl<F: Clone + Send + Sync> Domain<F, ExternalVaultProxyPaymentsRequest, PaymentConfirmData<F>>
    for ExternalVaultProxyPaymentIntent
{
    async fn get_customer_details<'a>(
        &'a self,
        state: &SessionState,
        payment_data: &mut PaymentConfirmData<F>,
        merchant_key_store: &domain::MerchantKeyStore,
        storage_scheme: storage_enums::MerchantStorageScheme,
    ) -> CustomResult<(BoxedConfirmOperation<'a, F>, Option<domain::Customer>), errors::StorageError>
    {
        match payment_data.payment_intent.customer_id.clone() {
            Some(id) => {
                let customer = state
                    .store
                    .find_customer_by_global_id(
                        &state.into(),
                        &id,
                        merchant_key_store,
                        storage_scheme,
                    )
                    .await?;

                Ok((Box::new(self), Some(customer)))
            }
            None => Ok((Box::new(self), None)),
        }
    }

    #[instrument(skip_all)]
    async fn make_pm_data<'a>(
        &'a self,
        _state: &'a SessionState,
        _payment_data: &mut PaymentConfirmData<F>,
        _storage_scheme: storage_enums::MerchantStorageScheme,
        _key_store: &domain::MerchantKeyStore,
        _customer: &Option<domain::Customer>,
        _business_profile: &domain::Profile,
        _should_retry_with_pan: bool,
    ) -> RouterResult<(
        BoxedConfirmOperation<'a, F>,
        Option<PaymentMethodData>,
        Option<String>,
    )> {
        // TODO: Implement external vault specific payment method data creation
        Ok((Box::new(self), None, None))
    }

    async fn create_or_fetch_payment_method<'a>(
        &'a self,
        state: &SessionState,
        merchant_context: &domain::MerchantContext,
        business_profile: &domain::Profile,
        payment_data: &mut PaymentConfirmData<F>,
    ) -> CustomResult<(), errors::ApiErrorResponse> {
        match (
            payment_data.payment_intent.customer_id.clone(),
            payment_data.external_vault_pmd.clone(),
            payment_data.payment_attempt.customer_acceptance.clone(),
            payment_data.payment_attempt.payment_token.clone(),
        ) {
            (Some(customer_id), Some(hyperswitch_domain_models::payment_method_data::ExternalVaultPaymentMethodData::Card(card_details)), Some(_), None) => {

                let payment_method_data =
                    api::PaymentMethodCreateData::ProxyCard(api::ProxyCardDetails::from(*card_details));
                let billing = payment_data
                    .payment_address
                    .get_payment_method_billing()
                    .cloned()
                    .map(From::from);

                let req = api::PaymentMethodCreate {
                    payment_method_type: payment_data.payment_attempt.payment_method_type,
                    payment_method_subtype: payment_data.payment_attempt.payment_method_subtype,
                    metadata: None,
                    customer_id,
                    payment_method_data,
                    billing,
                    psp_tokenization: None,
                    network_tokenization: None,
                };

                let (_pm_response, payment_method) = Box::pin(payment_methods::create_payment_method_core(
                    state,
                    &state.get_req_state(),
                    req,
                    merchant_context,
                    business_profile,
                ))
                .await?;

                payment_data.payment_method = Some(payment_method);
            }
            (_, Some(hyperswitch_domain_models::payment_method_data::ExternalVaultPaymentMethodData::VaultToken(vault_token)), None, Some(payment_token)) => {
                payment_data.external_vault_pmd = Some(payment_methods::get_external_vault_token(
                    state,
                    merchant_context.get_merchant_key_store(),
                    merchant_context.get_merchant_account().storage_scheme,
                    payment_token.clone(),
                    vault_token.clone(),
                    &payment_data.payment_attempt.payment_method_type
                )
                .await?);
            }
            _ => {
                router_env::logger::debug!(
                    "No payment method to create or fetch for external vault proxy payment intent"
                );
            }
        }

        Ok(())
    }

    #[cfg(feature = "v2")]
    async fn update_payment_method<'a>(
        &'a self,
        state: &SessionState,
        merchant_context: &domain::MerchantContext,
        payment_data: &mut PaymentConfirmData<F>,
    ) {
        if let (true, Some(payment_method)) = (
            payment_data.payment_attempt.customer_acceptance.is_some(),
            payment_data.payment_method.as_ref(),
        ) {
            payment_methods::update_payment_method_status_internal(
                state,
                merchant_context.get_merchant_key_store(),
                merchant_context.get_merchant_account().storage_scheme,
                common_enums::PaymentMethodStatus::Active,
                payment_method.get_id(),
            )
            .await
            .map_err(|err| router_env::logger::error!(err=?err));
        };
    }

    #[instrument(skip_all)]
    async fn populate_payment_data<'a>(
        &'a self,
        _state: &SessionState,
        payment_data: &mut PaymentConfirmData<F>,
        _merchant_context: &domain::MerchantContext,
        _business_profile: &domain::Profile,
        connector_data: &api::ConnectorData,
    ) -> CustomResult<(), errors::ApiErrorResponse> {
        let connector_request_reference_id = connector_data
            .connector
            .generate_connector_request_reference_id(
                &payment_data.payment_intent,
                &payment_data.payment_attempt,
            );
        payment_data.set_connector_request_reference_id(Some(connector_request_reference_id));
        Ok(())
    }

    async fn perform_routing<'a>(
        &'a self,
        merchant_context: &domain::MerchantContext,
        business_profile: &domain::Profile,
        state: &SessionState,
        payment_data: &mut PaymentConfirmData<F>,
    ) -> CustomResult<ConnectorCallType, errors::ApiErrorResponse> {
        payments::connector_selection(
            state,
            merchant_context,
            business_profile,
            payment_data,
            None,
        )
        .await
    }
}

#[async_trait]
impl<F: Clone + Sync> UpdateTracker<F, PaymentConfirmData<F>, ExternalVaultProxyPaymentsRequest>
    for ExternalVaultProxyPaymentIntent
{
    #[instrument(skip_all)]
    async fn update_trackers<'b>(
        &'b self,
        state: &'b SessionState,
        _req_state: ReqState,
        mut payment_data: PaymentConfirmData<F>,
        _customer: Option<domain::Customer>,
        storage_scheme: storage_enums::MerchantStorageScheme,
        _updated_customer: Option<storage::CustomerUpdate>,
        key_store: &domain::MerchantKeyStore,
        _frm_suggestion: Option<api_models::enums::FrmSuggestion>,
        _header_payload: hyperswitch_domain_models::payments::HeaderPayload,
    ) -> RouterResult<(BoxedConfirmOperation<'b, F>, PaymentConfirmData<F>)>
    where
        F: 'b + Send,
    {
        let db = &*state.store;
        let key_manager_state = &state.into();

        let intent_status = common_enums::IntentStatus::Processing;
        let attempt_status = common_enums::AttemptStatus::Pending;

        let connector = payment_data
            .payment_attempt
            .connector
            .clone()
            .get_required_value("connector")
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Connector is none when constructing response")?;

        let merchant_connector_id = Some(
            payment_data
                .payment_attempt
                .merchant_connector_id
                .clone()
                .get_required_value("merchant_connector_id")
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Merchant connector id is none when constructing response")?,
        );

        let payment_intent_update =
            hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::ConfirmIntent {
                status: intent_status,
                updated_by: storage_scheme.to_string(),
                active_attempt_id: Some(payment_data.payment_attempt.id.clone()),
            };

        let authentication_type = payment_data
            .payment_intent
            .authentication_type
            .unwrap_or_default();

        let connector_request_reference_id = payment_data
            .payment_attempt
            .connector_request_reference_id
            .clone();

        let connector_response_reference_id = payment_data
            .payment_attempt
            .connector_response_reference_id
            .clone();

        let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntent {
            status: attempt_status,
            updated_by: storage_scheme.to_string(),
            connector,
            merchant_connector_id,
            authentication_type,
            connector_request_reference_id,
            connector_response_reference_id,
        };

        let updated_payment_intent = db
            .update_payment_intent(
                key_manager_state,
                payment_data.payment_intent.clone(),
                payment_intent_update,
                key_store,
                storage_scheme,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Unable to update payment intent")?;

        payment_data.payment_intent = updated_payment_intent;

        let updated_payment_attempt = db
            .update_payment_attempt(
                key_manager_state,
                key_store,
                payment_data.payment_attempt.clone(),
                payment_attempt_update,
                storage_scheme,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Unable to update payment attempt")?;

        payment_data.payment_attempt = updated_payment_attempt;

        Ok((Box::new(self), payment_data))
    }
}

#[cfg(feature = "v2")]
#[async_trait]
impl<F: Clone> PostUpdateTracker<F, PaymentConfirmData<F>, types::PaymentsAuthorizeData>
    for ExternalVaultProxyPaymentIntent
{
    async fn update_tracker<'b>(
        &'b self,
        state: &'b SessionState,
        mut payment_data: PaymentConfirmData<F>,
        response: types::RouterData<F, types::PaymentsAuthorizeData, types::PaymentsResponseData>,
        key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> RouterResult<PaymentConfirmData<F>>
    where
        F: 'b + Send + Sync,
        types::RouterData<F, types::PaymentsAuthorizeData, types::PaymentsResponseData>:
            hyperswitch_domain_models::router_data::TrackerPostUpdateObjects<
                F,
                types::PaymentsAuthorizeData,
                PaymentConfirmData<F>,
            >,
    {
        use hyperswitch_domain_models::router_data::TrackerPostUpdateObjects;

        let db = &*state.store;
        let key_manager_state = &state.into();

        let response_router_data = response;

        let payment_intent_update =
            response_router_data.get_payment_intent_update(&payment_data, storage_scheme);
        let payment_attempt_update =
            response_router_data.get_payment_attempt_update(&payment_data, storage_scheme);

        let updated_payment_intent = db
            .update_payment_intent(
                key_manager_state,
                payment_data.payment_intent,
                payment_intent_update,
                key_store,
                storage_scheme,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Unable to update payment intent")?;

        let updated_payment_attempt = db
            .update_payment_attempt(
                key_manager_state,
                key_store,
                payment_data.payment_attempt,
                payment_attempt_update,
                storage_scheme,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Unable to update payment attempt")?;

        payment_data.payment_intent = updated_payment_intent;
        payment_data.payment_attempt = updated_payment_attempt;

        // TODO: Add external vault specific post-update logic

        Ok(payment_data)
    }
}


// Function: parse_evidence_type
// File: crates/router/src/routes/disputes/utils.rs
// Module: router

pub fn parse_evidence_type(
    field: &mut Field,
) -> CustomResult<Option<disputes::EvidenceType>, errors::ApiErrorResponse>


// Struct: StripeBillingDetails
// File: crates/router/src/compatibility/stripe/payment_intents/types.rs
// Module: router
// Implementations: 0

pub struct StripeBillingDetails


// Struct: CaptureResponseData
// File: crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CaptureResponseData


// Function: retry_webhook_delivery_attempt
// File: crates/router/src/routes/webhook_events.rs
// Module: router

pub fn retry_webhook_delivery_attempt(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<(common_utils::id_type::MerchantId, String)


// Function: authenticate_authentication_client_secret_and_check_expiry
// File: crates/router/src/core/unified_authentication_service/utils.rs
// Module: router

pub fn authenticate_authentication_client_secret_and_check_expiry(
    req_client_secret: &String,
    authentication: &diesel_models::authentication::Authentication,
) -> RouterResult<()>


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

impl api::PaymentVoid for for Celero


// Struct: AuthMethodDetails
// File: crates/api_models/src/user.rs
// Module: api_models
// Implementations: 0

pub struct AuthMethodDetails


// Struct: PartnerFlowCredentials
// File: crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PartnerFlowCredentials


// Implementation: impl Worldpayxml
// File: crates/hyperswitch_connectors/src/connectors/worldpayxml.rs
// Module: hyperswitch_connectors
// Methods: 1 total (1 public)

impl Worldpayxml


// Function: new
// File: crates/hyperswitch_connectors/src/connectors/thunes.rs
// Module: hyperswitch_connectors

pub fn new() -> &'static Self


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

pub fn profile_retrieve()


// Implementation: impl AuthorizationInterface for for KafkaStore
// File: crates/router/src/db/kafka_store.rs
// Module: router
// Methods: 3 total (0 public)

impl AuthorizationInterface for for KafkaStore


// Struct: ApplepayPaymentMethod
// File: crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ApplepayPaymentMethod


// Implementation: impl PaymentToken for for Riskified
// File: crates/hyperswitch_connectors/src/connectors/riskified.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl PaymentToken for for Riskified


// File: crates/router/src/core/webhooks/utils.rs
// Module: router
// Public functions: 5

use std::marker::PhantomData;

use base64::Engine;
use common_utils::{
    consts,
    crypto::{self, GenerateDigest},
    errors::CustomResult,
    ext_traits::ValueExt,
};
use error_stack::{Report, ResultExt};
use redis_interface as redis;
use router_env::tracing;

use super::MERCHANT_ID;
use crate::{
    core::{
        errors::{self},
        metrics,
        payments::helpers,
    },
    db::{get_and_deserialize_key, StorageInterface},
    errors::RouterResult,
    routes::app::SessionStateInfo,
    services::logger,
    types::{self, api, domain, PaymentAddress},
    SessionState,
};

const IRRELEVANT_ATTEMPT_ID_IN_SOURCE_VERIFICATION_FLOW: &str =
    "irrelevant_attempt_id_in_source_verification_flow";
const IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_SOURCE_VERIFICATION_FLOW: &str =
    "irrelevant_connector_request_reference_id_in_source_verification_flow";

/// Check whether the merchant has configured to disable the webhook `event` for the `connector`
/// First check for the key "whconf_{merchant_id}_{connector_id}" in redis,
/// if not found, fetch from configs table in database
pub async fn is_webhook_event_disabled(
    db: &dyn StorageInterface,
    connector_id: &str,
    merchant_id: &common_utils::id_type::MerchantId,
    event: &api::IncomingWebhookEvent,
) -> bool {
    let redis_key = merchant_id.get_webhook_config_disabled_events_key(connector_id);
    let merchant_webhook_disable_config_result: CustomResult<
        api::MerchantWebhookConfig,
        redis_interface::errors::RedisError,
    > = get_and_deserialize_key(db, &redis_key, "MerchantWebhookConfig").await;

    match merchant_webhook_disable_config_result {
        Ok(merchant_webhook_config) => merchant_webhook_config.contains(event),
        Err(..) => {
            //if failed to fetch from redis. fetch from db and populate redis
            db.find_config_by_key(&redis_key)
                .await
                .map(|config| {
                    match serde_json::from_str::<api::MerchantWebhookConfig>(&config.config) {
                        Ok(set) => set.contains(event),
                        Err(err) => {
                            logger::warn!(?err, "error while parsing merchant webhook config");
                            false
                        }
                    }
                })
                .unwrap_or_else(|err| {
                    logger::warn!(?err, "error while fetching merchant webhook config");
                    false
                })
        }
    }
}

pub async fn construct_webhook_router_data(
    state: &SessionState,
    connector_name: &str,
    merchant_connector_account: domain::MerchantConnectorAccount,
    merchant_context: &domain::MerchantContext,
    connector_wh_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    request_details: &api::IncomingWebhookRequestDetails<'_>,
) -> CustomResult<types::VerifyWebhookSourceRouterData, errors::ApiErrorResponse> {
    let auth_type: types::ConnectorAuthType =
        helpers::MerchantConnectorAccountType::DbVal(Box::new(merchant_connector_account.clone()))
            .get_connector_account_details()
            .parse_value("ConnectorAuthType")
            .change_context(errors::ApiErrorResponse::InternalServerError)?;

    let router_data = types::RouterData {
        flow: PhantomData,
        merchant_id: merchant_context.get_merchant_account().get_id().clone(),
        connector: connector_name.to_string(),
        customer_id: None,
        tenant_id: state.tenant.tenant_id.clone(),
        payment_id: common_utils::id_type::PaymentId::get_irrelevant_id("source_verification_flow")
            .get_string_repr()
            .to_owned(),
        attempt_id: IRRELEVANT_ATTEMPT_ID_IN_SOURCE_VERIFICATION_FLOW.to_string(),
        status: diesel_models::enums::AttemptStatus::default(),
        payment_method: diesel_models::enums::PaymentMethod::default(),
        connector_auth_type: auth_type,
        description: None,
        address: PaymentAddress::default(),
        auth_type: diesel_models::enums::AuthenticationType::default(),
        connector_meta_data: None,
        connector_wallets_details: None,
        amount_captured: None,
        minor_amount_captured: None,
        request: types::VerifyWebhookSourceRequestData {
            webhook_headers: request_details.headers.clone(),
            webhook_body: request_details.body.to_vec().clone(),
            merchant_secret: connector_wh_secrets.to_owned(),
        },
        response: Err(types::ErrorResponse::default()),
        access_token: None,
        session_token: None,
        reference_id: None,
        payment_method_token: None,
        connector_customer: None,
        recurring_mandate_payment_data: None,
        preprocessing_id: None,
        connector_request_reference_id:
            IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_SOURCE_VERIFICATION_FLOW.to_string(),
        #[cfg(feature = "payouts")]
        payout_method_data: None,
        #[cfg(feature = "payouts")]
        quote_id: None,
        test_mode: None,
        payment_method_balance: None,
        payment_method_status: None,
        connector_api_version: None,
        connector_http_status_code: None,
        external_latency: None,
        apple_pay_flow: None,
        frm_metadata: None,
        refund_id: None,
        dispute_id: None,
        connector_response: None,
        integrity_check: Ok(()),
        additional_merchant_data: None,
        header_payload: None,
        connector_mandate_request_reference_id: None,
        authentication_id: None,
        psd2_sca_exemption_type: None,
        raw_connector_response: None,
        is_payment_id_from_merchant: None,
        l2_l3_data: None,
        minor_amount_capturable: None,
    };
    Ok(router_data)
}

#[inline]
pub(crate) fn get_idempotent_event_id(
    primary_object_id: &str,
    event_type: types::storage::enums::EventType,
    delivery_attempt: types::storage::enums::WebhookDeliveryAttempt,
) -> Result<String, Report<errors::WebhooksFlowError>> {
    use crate::types::storage::enums::WebhookDeliveryAttempt;

    const EVENT_ID_SUFFIX_LENGTH: usize = 8;

    let common_prefix = format!("{primary_object_id}_{event_type}");

    // Hash the common prefix with SHA256 and encode with URL-safe base64 without padding
    let digest = crypto::Sha256
        .generate_digest(common_prefix.as_bytes())
        .change_context(errors::WebhooksFlowError::IdGenerationFailed)
        .attach_printable("Failed to generate idempotent event ID")?;
    let base_encoded = consts::BASE64_ENGINE_URL_SAFE_NO_PAD.encode(digest);

    let result = match delivery_attempt {
        WebhookDeliveryAttempt::InitialAttempt => base_encoded,
        WebhookDeliveryAttempt::AutomaticRetry | WebhookDeliveryAttempt::ManualRetry => {
            common_utils::generate_id(EVENT_ID_SUFFIX_LENGTH, &base_encoded)
        }
    };

    Ok(result)
}

#[inline]
pub(crate) fn generate_event_id() -> String {
    common_utils::generate_time_ordered_id("evt")
}

pub fn increment_webhook_outgoing_received_count(merchant_id: &common_utils::id_type::MerchantId) {
    metrics::WEBHOOK_OUTGOING_RECEIVED_COUNT.add(
        1,
        router_env::metric_attributes!((MERCHANT_ID, merchant_id.clone())),
    )
}

pub fn increment_webhook_outgoing_not_received_count(
    merchant_id: &common_utils::id_type::MerchantId,
) {
    metrics::WEBHOOK_OUTGOING_NOT_RECEIVED_COUNT.add(
        1,
        router_env::metric_attributes!((MERCHANT_ID, merchant_id.clone())),
    );
}

pub fn is_outgoing_webhook_disabled(
    state: &SessionState,
    webhook_url_result: &Result<String, Report<errors::WebhooksFlowError>>,
    business_profile: &domain::Profile,
    idempotent_event_id: &str,
) -> bool {
    if !state.conf.webhooks.outgoing_enabled
        || webhook_url_result.is_err()
        || webhook_url_result.as_ref().is_ok_and(String::is_empty)
    {
        logger::debug!(
            business_profile_id=?business_profile.get_id(),
            %idempotent_event_id,
            "Outgoing webhooks are disabled in application configuration, or merchant webhook URL \
             could not be obtained; skipping outgoing webhooks for event"
        );
        return true;
    }
    false
}

const WEBHOOK_LOCK_PREFIX: &str = "WEBHOOK_LOCK";

pub(super) async fn perform_redis_lock<A>(
    state: &A,
    unique_locking_key: &str,
    merchant_id: common_utils::id_type::MerchantId,
) -> RouterResult<Option<String>>
where
    A: SessionStateInfo,
{
    let lock_value: String = uuid::Uuid::new_v4().to_string();
    let redis_conn = state
        .store()
        .get_redis_conn()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Error connecting to redis")?;

    let redis_locking_key = format!(
        "{}_{}_{}",
        WEBHOOK_LOCK_PREFIX,
        merchant_id.get_string_repr(),
        unique_locking_key
    );
    let redis_lock_expiry_seconds = state.conf().webhooks.redis_lock_expiry_seconds;

    let redis_lock_result = redis_conn
        .set_key_if_not_exists_with_expiry(
            &redis_locking_key.as_str().into(),
            lock_value.clone(),
            Some(i64::from(redis_lock_expiry_seconds)),
        )
        .await;

    match redis_lock_result {
        Ok(redis::SetnxReply::KeySet) => {
            logger::info!("Lock acquired for for {redis_locking_key}");
            Ok(Some(lock_value))
        }
        Ok(redis::SetnxReply::KeyNotSet) => {
            logger::info!("Lock already held for {redis_locking_key}");
            Ok(None)
        }
        Err(err) => Err(err
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Error acquiring redis lock")),
    }
}

pub(super) async fn free_redis_lock<A>(
    state: &A,
    unique_locking_key: &str,
    merchant_id: common_utils::id_type::MerchantId,
    lock_value: Option<String>,
) -> RouterResult<()>
where
    A: SessionStateInfo,
{
    let redis_conn = state
        .store()
        .get_redis_conn()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Error connecting to redis")?;

    let redis_locking_key = format!(
        "{}_{}_{}",
        WEBHOOK_LOCK_PREFIX,
        merchant_id.get_string_repr(),
        unique_locking_key
    );
    match redis_conn
        .get_key::<Option<String>>(&redis_locking_key.as_str().into())
        .await
    {
        Ok(val) => {
            if val == lock_value {
                match redis_conn
                    .delete_key(&redis_locking_key.as_str().into())
                    .await
                {
                    Ok(redis::types::DelReply::KeyDeleted) => {
                        logger::info!("Lock freed {redis_locking_key}");
                        tracing::Span::current().record("redis_lock_released", redis_locking_key);
                        Ok(())
                    }
                    Ok(redis::types::DelReply::KeyNotDeleted) => Err(
                        errors::ApiErrorResponse::InternalServerError,
                    )
                    .attach_printable("Status release lock called but key is not found in redis"),
                    Err(error) => Err(error)
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Error while deleting redis key"),
                }
            } else {
                Err(errors::ApiErrorResponse::InternalServerError)
                            .attach_printable("The redis value which acquired the lock is not equal to the redis value requesting for releasing the lock")
            }
        }
        Err(error) => Err(error)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Error while deleting redis key"),
    }
}