        }
        api_enums::Country::BonaireSintEustatiusAndSaba => {
            dir::enums::Country::BonaireSintEustatiusAndSaba
        }
        api_enums::Country::BosniaAndHerzegovina => dir::enums::Country::BosniaAndHerzegovina,
        api_enums::Country::Botswana => dir::enums::Country::Botswana,
        api_enums::Country::BouvetIsland => dir::enums::Country::BouvetIsland,
        api_enums::Country::Brazil => dir::enums::Country::Brazil,
        api_enums::Country::BritishIndianOceanTerritory => {
            dir::enums::Country::BritishIndianOceanTerritory
        }
        api_enums::Country::BruneiDarussalam => dir::enums::Country::BruneiDarussalam,
        api_enums::Country::Bulgaria => dir::enums::Country::Bulgaria,
        api_enums::Country::BurkinaFaso => dir::enums::Country::BurkinaFaso,
        api_enums::Country::Burundi => dir::enums::Country::Burundi,
        api_enums::Country::CaboVerde => dir::enums::Country::CaboVerde,
        api_enums::Country::Cambodia => dir::enums::Country::Cambodia,
        api_enums::Country::Cameroon => dir::enums::Country::Cameroon,
        api_enums::Country::Canada => dir::enums::Country::Canada,
        api_enums::Country::CaymanIslands => dir::enums::Country::CaymanIslands,
        api_enums::Country::CentralAfricanRepublic => dir::enums::Country::CentralAfricanRepublic,
        api_enums::Country::Chad => dir::enums::Country::Chad,
        api_enums::Country::Chile => dir::enums::Country::Chile,
        api_enums::Country::China => dir::enums::Country::China,
        api_enums::Country::ChristmasIsland => dir::enums::Country::ChristmasIsland,
        api_enums::Country::CocosKeelingIslands => dir::enums::Country::CocosKeelingIslands,
        api_enums::Country::Colombia => dir::enums::Country::Colombia,
        api_enums::Country::Comoros => dir::enums::Country::Comoros,
        api_enums::Country::Congo => dir::enums::Country::Congo,
        api_enums::Country::CongoDemocraticRepublic => dir::enums::Country::CongoDemocraticRepublic,
        api_enums::Country::CookIslands => dir::enums::Country::CookIslands,
        api_enums::Country::CostaRica => dir::enums::Country::CostaRica,
        api_enums::Country::CotedIvoire => dir::enums::Country::CotedIvoire,
        api_enums::Country::Croatia => dir::enums::Country::Croatia,
        api_enums::Country::Cuba => dir::enums::Country::Cuba,
        api_enums::Country::Curacao => dir::enums::Country::Curacao,
        api_enums::Country::Cyprus => dir::enums::Country::Cyprus,
        api_enums::Country::Czechia => dir::enums::Country::Czechia,
        api_enums::Country::Denmark => dir::enums::Country::Denmark,
        api_enums::Country::Djibouti => dir::enums::Country::Djibouti,
        api_enums::Country::Dominica => dir::enums::Country::Dominica,
        api_enums::Country::DominicanRepublic => dir::enums::Country::DominicanRepublic,
        api_enums::Country::Ecuador => dir::enums::Country::Ecuador,
        api_enums::Country::Egypt => dir::enums::Country::Egypt,
        api_enums::Country::ElSalvador => dir::enums::Country::ElSalvador,
        api_enums::Country::EquatorialGuinea => dir::enums::Country::EquatorialGuinea,
        api_enums::Country::Eritrea => dir::enums::Country::Eritrea,
        api_enums::Country::Estonia => dir::enums::Country::Estonia,
        api_enums::Country::Ethiopia => dir::enums::Country::Ethiopia,
        api_enums::Country::FalklandIslandsMalvinas => dir::enums::Country::FalklandIslandsMalvinas,
        api_enums::Country::FaroeIslands => dir::enums::Country::FaroeIslands,
        api_enums::Country::Fiji => dir::enums::Country::Fiji,
        api_enums::Country::Finland => dir::enums::Country::Finland,
        api_enums::Country::France => dir::enums::Country::France,
        api_enums::Country::FrenchGuiana => dir::enums::Country::FrenchGuiana,
        api_enums::Country::FrenchPolynesia => dir::enums::Country::FrenchPolynesia,
        api_enums::Country::FrenchSouthernTerritories => {
            dir::enums::Country::FrenchSouthernTerritories
        }
        api_enums::Country::Gabon => dir::enums::Country::Gabon,
        api_enums::Country::Gambia => dir::enums::Country::Gambia,
        api_enums::Country::Georgia => dir::enums::Country::Georgia,
        api_enums::Country::Germany => dir::enums::Country::Germany,
        api_enums::Country::Ghana => dir::enums::Country::Ghana,
        api_enums::Country::Gibraltar => dir::enums::Country::Gibraltar,
        api_enums::Country::Greece => dir::enums::Country::Greece,
        api_enums::Country::Greenland => dir::enums::Country::Greenland,
        api_enums::Country::Grenada => dir::enums::Country::Grenada,
        api_enums::Country::Guadeloupe => dir::enums::Country::Guadeloupe,
        api_enums::Country::Guam => dir::enums::Country::Guam,
        api_enums::Country::Guatemala => dir::enums::Country::Guatemala,
        api_enums::Country::Guernsey => dir::enums::Country::Guernsey,
        api_enums::Country::Guinea => dir::enums::Country::Guinea,
        api_enums::Country::GuineaBissau => dir::enums::Country::GuineaBissau,
        api_enums::Country::Guyana => dir::enums::Country::Guyana,
        api_enums::Country::Haiti => dir::enums::Country::Haiti,
        api_enums::Country::HeardIslandAndMcDonaldIslands => {
            dir::enums::Country::HeardIslandAndMcDonaldIslands
        }
        api_enums::Country::HolySee => dir::enums::Country::HolySee,
        api_enums::Country::Honduras => dir::enums::Country::Honduras,
        api_enums::Country::HongKong => dir::enums::Country::HongKong,
        api_enums::Country::Hungary => dir::enums::Country::Hungary,
        api_enums::Country::Iceland => dir::enums::Country::Iceland,
        api_enums::Country::India => dir::enums::Country::India,
        api_enums::Country::Indonesia => dir::enums::Country::Indonesia,
        api_enums::Country::IranIslamicRepublic => dir::enums::Country::IranIslamicRepublic,
        api_enums::Country::Iraq => dir::enums::Country::Iraq,
        api_enums::Country::Ireland => dir::enums::Country::Ireland,
        api_enums::Country::IsleOfMan => dir::enums::Country::IsleOfMan,
        api_enums::Country::Israel => dir::enums::Country::Israel,
        api_enums::Country::Italy => dir::enums::Country::Italy,
        api_enums::Country::Jamaica => dir::enums::Country::Jamaica,
        api_enums::Country::Japan => dir::enums::Country::Japan,
        api_enums::Country::Jersey => dir::enums::Country::Jersey,
        api_enums::Country::Jordan => dir::enums::Country::Jordan,
        api_enums::Country::Kazakhstan => dir::enums::Country::Kazakhstan,
        api_enums::Country::Kenya => dir::enums::Country::Kenya,
        api_enums::Country::Kiribati => dir::enums::Country::Kiribati,
        api_enums::Country::KoreaDemocraticPeoplesRepublic => {
            dir::enums::Country::KoreaDemocraticPeoplesRepublic
        }
        api_enums::Country::KoreaRepublic => dir::enums::Country::KoreaRepublic,
        api_enums::Country::Kuwait => dir::enums::Country::Kuwait,
        api_enums::Country::Kyrgyzstan => dir::enums::Country::Kyrgyzstan,
        api_enums::Country::LaoPeoplesDemocraticRepublic => {
            dir::enums::Country::LaoPeoplesDemocraticRepublic
        }
        api_enums::Country::Latvia => dir::enums::Country::Latvia,
        api_enums::Country::Lebanon => dir::enums::Country::Lebanon,
        api_enums::Country::Lesotho => dir::enums::Country::Lesotho,
        api_enums::Country::Liberia => dir::enums::Country::Liberia,
        api_enums::Country::Libya => dir::enums::Country::Libya,
        api_enums::Country::Liechtenstein => dir::enums::Country::Liechtenstein,
        api_enums::Country::Lithuania => dir::enums::Country::Lithuania,
        api_enums::Country::Luxembourg => dir::enums::Country::Luxembourg,
        api_enums::Country::Macao => dir::enums::Country::Macao,
        api_enums::Country::MacedoniaTheFormerYugoslavRepublic => {
            dir::enums::Country::MacedoniaTheFormerYugoslavRepublic
        }
        api_enums::Country::Madagascar => dir::enums::Country::Madagascar,
        api_enums::Country::Malawi => dir::enums::Country::Malawi,
        api_enums::Country::Malaysia => dir::enums::Country::Malaysia,
        api_enums::Country::Maldives => dir::enums::Country::Maldives,
        api_enums::Country::Mali => dir::enums::Country::Mali,
        api_enums::Country::Malta => dir::enums::Country::Malta,
        api_enums::Country::MarshallIslands => dir::enums::Country::MarshallIslands,
        api_enums::Country::Martinique => dir::enums::Country::Martinique,
        api_enums::Country::Mauritania => dir::enums::Country::Mauritania,
        api_enums::Country::Mauritius => dir::enums::Country::Mauritius,
        api_enums::Country::Mayotte => dir::enums::Country::Mayotte,
        api_enums::Country::Mexico => dir::enums::Country::Mexico,
        api_enums::Country::MicronesiaFederatedStates => {
            dir::enums::Country::MicronesiaFederatedStates
        }
        api_enums::Country::MoldovaRepublic => dir::enums::Country::MoldovaRepublic,
        api_enums::Country::Monaco => dir::enums::Country::Monaco,
        api_enums::Country::Mongolia => dir::enums::Country::Mongolia,
        api_enums::Country::Montenegro => dir::enums::Country::Montenegro,
        api_enums::Country::Montserrat => dir::enums::Country::Montserrat,
        api_enums::Country::Morocco => dir::enums::Country::Morocco,
        api_enums::Country::Mozambique => dir::enums::Country::Mozambique,
        api_enums::Country::Myanmar => dir::enums::Country::Myanmar,
        api_enums::Country::Namibia => dir::enums::Country::Namibia,
        api_enums::Country::Nauru => dir::enums::Country::Nauru,
        api_enums::Country::Nepal => dir::enums::Country::Nepal,
        api_enums::Country::Netherlands => dir::enums::Country::Netherlands,
        api_enums::Country::NewCaledonia => dir::enums::Country::NewCaledonia,
        api_enums::Country::NewZealand => dir::enums::Country::NewZealand,
        api_enums::Country::Nicaragua => dir::enums::Country::Nicaragua,
        api_enums::Country::Niger => dir::enums::Country::Niger,
        api_enums::Country::Nigeria => dir::enums::Country::Nigeria,
        api_enums::Country::Niue => dir::enums::Country::Niue,
        api_enums::Country::NorfolkIsland => dir::enums::Country::NorfolkIsland,
        api_enums::Country::NorthernMarianaIslands => dir::enums::Country::NorthernMarianaIslands,
        api_enums::Country::Norway => dir::enums::Country::Norway,
        api_enums::Country::Oman => dir::enums::Country::Oman,
        api_enums::Country::Pakistan => dir::enums::Country::Pakistan,
        api_enums::Country::Palau => dir::enums::Country::Palau,
        api_enums::Country::PalestineState => dir::enums::Country::PalestineState,
        api_enums::Country::Panama => dir::enums::Country::Panama,
        api_enums::Country::PapuaNewGuinea => dir::enums::Country::PapuaNewGuinea,
        api_enums::Country::Paraguay => dir::enums::Country::Paraguay,
        api_enums::Country::Peru => dir::enums::Country::Peru,
        api_enums::Country::Philippines => dir::enums::Country::Philippines,
        api_enums::Country::Pitcairn => dir::enums::Country::Pitcairn,

        api_enums::Country::Poland => dir::enums::Country::Poland,
        api_enums::Country::Portugal => dir::enums::Country::Portugal,
        api_enums::Country::PuertoRico => dir::enums::Country::PuertoRico,

        api_enums::Country::Qatar => dir::enums::Country::Qatar,
        api_enums::Country::Reunion => dir::enums::Country::Reunion,
        api_enums::Country::Romania => dir::enums::Country::Romania,
        api_enums::Country::RussianFederation => dir::enums::Country::RussianFederation,
        api_enums::Country::Rwanda => dir::enums::Country::Rwanda,
        api_enums::Country::SaintBarthelemy => dir::enums::Country::SaintBarthelemy,
        api_enums::Country::SaintHelenaAscensionAndTristandaCunha => {
            dir::enums::Country::SaintHelenaAscensionAndTristandaCunha
        }
        api_enums::Country::SaintKittsAndNevis => dir::enums::Country::SaintKittsAndNevis,
        api_enums::Country::SaintLucia => dir::enums::Country::SaintLucia,
        api_enums::Country::SaintMartinFrenchpart => dir::enums::Country::SaintMartinFrenchpart,
        api_enums::Country::SaintPierreAndMiquelon => dir::enums::Country::SaintPierreAndMiquelon,
        api_enums::Country::SaintVincentAndTheGrenadines => {
            dir::enums::Country::SaintVincentAndTheGrenadines
        }
        api_enums::Country::Samoa => dir::enums::Country::Samoa,
        api_enums::Country::SanMarino => dir::enums::Country::SanMarino,
        api_enums::Country::SaoTomeAndPrincipe => dir::enums::Country::SaoTomeAndPrincipe,
        api_enums::Country::SaudiArabia => dir::enums::Country::SaudiArabia,
        api_enums::Country::Senegal => dir::enums::Country::Senegal,
        api_enums::Country::Serbia => dir::enums::Country::Serbia,
        api_enums::Country::Seychelles => dir::enums::Country::Seychelles,
        api_enums::Country::SierraLeone => dir::enums::Country::SierraLeone,
        api_enums::Country::Singapore => dir::enums::Country::Singapore,
        api_enums::Country::SintMaartenDutchpart => dir::enums::Country::SintMaartenDutchpart,
        api_enums::Country::Slovakia => dir::enums::Country::Slovakia,
        api_enums::Country::Slovenia => dir::enums::Country::Slovenia,
        api_enums::Country::SolomonIslands => dir::enums::Country::SolomonIslands,
        api_enums::Country::Somalia => dir::enums::Country::Somalia,
        api_enums::Country::SouthAfrica => dir::enums::Country::SouthAfrica,
        api_enums::Country::SouthGeorgiaAndTheSouthSandwichIslands => {
            dir::enums::Country::SouthGeorgiaAndTheSouthSandwichIslands
        }
        api_enums::Country::SouthSudan => dir::enums::Country::SouthSudan,
        api_enums::Country::Spain => dir::enums::Country::Spain,
        api_enums::Country::SriLanka => dir::enums::Country::SriLanka,
        api_enums::Country::Sudan => dir::enums::Country::Sudan,
        api_enums::Country::Suriname => dir::enums::Country::Suriname,
        api_enums::Country::SvalbardAndJanMayen => dir::enums::Country::SvalbardAndJanMayen,
        api_enums::Country::Swaziland => dir::enums::Country::Swaziland,
        api_enums::Country::Sweden => dir::enums::Country::Sweden,
        api_enums::Country::Switzerland => dir::enums::Country::Switzerland,
        api_enums::Country::SyrianArabRepublic => dir::enums::Country::SyrianArabRepublic,
        api_enums::Country::TaiwanProvinceOfChina => dir::enums::Country::TaiwanProvinceOfChina,
        api_enums::Country::Tajikistan => dir::enums::Country::Tajikistan,
        api_enums::Country::TanzaniaUnitedRepublic => dir::enums::Country::TanzaniaUnitedRepublic,
        api_enums::Country::Thailand => dir::enums::Country::Thailand,
        api_enums::Country::TimorLeste => dir::enums::Country::TimorLeste,
        api_enums::Country::Togo => dir::enums::Country::Togo,
        api_enums::Country::Tokelau => dir::enums::Country::Tokelau,
        api_enums::Country::Tonga => dir::enums::Country::Tonga,
        api_enums::Country::TrinidadAndTobago => dir::enums::Country::TrinidadAndTobago,
        api_enums::Country::Tunisia => dir::enums::Country::Tunisia,
        api_enums::Country::Turkey => dir::enums::Country::Turkey,
        api_enums::Country::Turkmenistan => dir::enums::Country::Turkmenistan,
        api_enums::Country::TurksAndCaicosIslands => dir::enums::Country::TurksAndCaicosIslands,
        api_enums::Country::Tuvalu => dir::enums::Country::Tuvalu,
        api_enums::Country::Uganda => dir::enums::Country::Uganda,
        api_enums::Country::Ukraine => dir::enums::Country::Ukraine,
        api_enums::Country::UnitedArabEmirates => dir::enums::Country::UnitedArabEmirates,
        api_enums::Country::UnitedKingdomOfGreatBritainAndNorthernIreland => {
            dir::enums::Country::UnitedKingdomOfGreatBritainAndNorthernIreland
        }
        api_enums::Country::UnitedStatesOfAmerica => dir::enums::Country::UnitedStatesOfAmerica,
        api_enums::Country::UnitedStatesMinorOutlyingIslands => {
            dir::enums::Country::UnitedStatesMinorOutlyingIslands
        }
        api_enums::Country::Uruguay => dir::enums::Country::Uruguay,
        api_enums::Country::Uzbekistan => dir::enums::Country::Uzbekistan,
        api_enums::Country::Vanuatu => dir::enums::Country::Vanuatu,
        api_enums::Country::VenezuelaBolivarianRepublic => {
            dir::enums::Country::VenezuelaBolivarianRepublic
        }
        api_enums::Country::Vietnam => dir::enums::Country::Vietnam,
        api_enums::Country::VirginIslandsBritish => dir::enums::Country::VirginIslandsBritish,
        api_enums::Country::VirginIslandsUS => dir::enums::Country::VirginIslandsUS,
        api_enums::Country::WallisAndFutuna => dir::enums::Country::WallisAndFutuna,
        api_enums::Country::WesternSahara => dir::enums::Country::WesternSahara,
        api_enums::Country::Yemen => dir::enums::Country::Yemen,
        api_enums::Country::Zambia => dir::enums::Country::Zambia,
        api_enums::Country::Zimbabwe => dir::enums::Country::Zimbabwe,
    }
}

pub fn business_country_to_dir_value(c: api_enums::Country) -> dir::DirValue {
    dir::DirValue::BusinessCountry(get_dir_country_dir_value(c))
}

pub fn billing_country_to_dir_value(c: api_enums::Country) -> dir::DirValue {
    dir::DirValue::BillingCountry(get_dir_country_dir_value(c))
}


impl CardInfoBuilder<CardInfoFetch> {
    fn set_card_info(
        self,
        card_info: card_info_models::CardInfo,
    ) -> CardInfoBuilder<CardInfoUpdate> {
        CardInfoBuilder {
            state: std::marker::PhantomData,
            card_info: Some(card_info),
        }
    }

    fn transition(self) -> CardInfoBuilder<CardInfoAdd> {
        CardInfoBuilder {
            state: std::marker::PhantomData,
            card_info: None,
        }
    }
}


File: crates/analytics/src/auth_events/metrics/frictionless_success_count.rs

use std::collections::HashSet;

use api_models::analytics::{
    auth_events::{AuthEventDimensions, AuthEventFilters, AuthEventMetricsBucketIdentifier},
    Granularity, TimeRange,
};
use common_enums::{AuthenticationStatus, DecoupledAuthenticationType};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

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

#[derive(Default)]
pub(super) struct FrictionlessSuccessCount;

#[async_trait::async_trait]
impl<T> super::AuthEventMetric<T> for FrictionlessSuccessCount
where
    T: AnalyticsDataSource + super::AuthEventMetricAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_metrics(
        &self,
        auth: &AuthInfo,
        dimensions: &[AuthEventDimensions],
        filters: &AuthEventFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
        let mut query_builder: QueryBuilder<T> =
            QueryBuilder::new(AnalyticsCollection::Authentications);
        for dim in dimensions.iter() {
            query_builder.add_select_column(dim).switch()?;
        }
        query_builder
            .add_select_column(Aggregate::Count {
                field: None,
                alias: Some("count"),
            })
            .switch()?;

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

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

        query_builder
            .add_filter_clause(
                "authentication_type",
                DecoupledAuthenticationType::Frictionless,
            )
            .switch()?;

        query_builder
            .add_filter_clause("authentication_status", AuthenticationStatus::Success)
            .switch()?;
        filters.set_filter_clause(&mut query_builder).switch()?;
        time_range
            .set_filter_clause(&mut query_builder)
            .attach_printable("Error filtering time range")
            .switch()?;
        auth.set_filter_clause(&mut query_builder).switch()?;

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

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

        query_builder
            .execute_query::<AuthEventMetricRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| {
                Ok((
                    AuthEventMetricsBucketIdentifier::new(
                        i.authentication_status.as_ref().map(|i| i.0),
                        i.trans_status.as_ref().map(|i| i.0.clone()),
                        i.authentication_type.as_ref().map(|i| i.0),
                        i.error_message.clone(),
                        i.authentication_connector.as_ref().map(|i| i.0),
                        i.message_version.clone(),
                        i.acs_reference_number.clone(),
                        i.mcc.clone(),
                        i.currency.as_ref().map(|i| i.0),
                        i.merchant_country.clone(),
                        i.billing_country.clone(),
                        i.shipping_country.clone(),
                        i.issuer_country.clone(),
                        i.earliest_supported_version.clone(),
                        i.latest_supported_version.clone(),
                        i.whitelist_decision,
                        i.device_manufacturer.clone(),
                        i.device_type.clone(),
                        i.device_brand.clone(),
                        i.device_os.clone(),
                        i.device_display.clone(),
                        i.browser_name.clone(),
                        i.browser_version.clone(),
                        i.issuer_id.clone(),
                        i.scheme_name.clone(),
                        i.exemption_requested,
                        i.exemption_accepted,
                        TimeRange {
                            start_time: match (granularity, i.start_bucket) {
                                (Some(g), Some(st)) => g.clip_to_start(st)?,
                                _ => time_range.start_time,
                            },
                            end_time: granularity.as_ref().map_or_else(
                                || Ok(time_range.end_time),
                                |g| i.end_bucket.map(|et| g.clip_to_end(et)).transpose(),
                            )?,
                        },
                    ),
                    i,
                ))
            })
            .collect::<error_stack::Result<
                HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
                crate::query::PostProcessingError,
            >>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


impl ClientSecretId {
    /// Generate a key for redis
    pub fn generate_redis_key(&self) -> String {
        format!("cs_{}", self.get_string_repr())
    }
}


pub struct ApiMetricsBucketResponse {
    #[serde(flatten)]
    pub values: ApiEventMetricsBucketValue,
    #[serde(flatten)]
    pub dimensions: ApiEventMetricsBucketIdentifier,
}


pub fn get_theme_file_key(theme_id: &str) -> PathBuf {
    get_specific_file_key(theme_id, "theme.json")
}


pub fn add_having_clause<R>(
        &mut self,
        aggregate: Aggregate<R>,
        filter_type: FilterTypes,
        value: impl ToSql<T>,
    ) -> QueryResult<()>
    where
        Aggregate<R>: ToSql<T>,
    {
        let aggregate = aggregate
            .to_sql(&self.table_engine)
            .change_context(QueryBuildingError::SqlSerializeError)
            .attach_printable("Error serializing having aggregate")?;
        let value = value
            .to_sql(&self.table_engine)
            .change_context(QueryBuildingError::SqlSerializeError)
            .attach_printable("Error serializing having value")?;
        let entry = (aggregate, filter_type, value);
        if let Some(having) = &mut self.having {
            having.push(entry);
        } else {
            self.having = Some(vec![entry]);
        }
        Ok(())
    }


pub async fn construct_payment_router_data_for_authorize<'a>(
    state: &'a SessionState,
    payment_data: hyperswitch_domain_models::payments::PaymentConfirmData<api::Authorize>,
    connector_id: &str,
    merchant_context: &domain::MerchantContext,
    customer: &'a Option<domain::Customer>,
    merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
    _merchant_recipient_data: Option<types::MerchantRecipientData>,
    header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
) -> RouterResult<types::PaymentsAuthorizeRouterData> {
    use masking::ExposeOptionInterface;

    fp_utils::when(merchant_connector_account.is_disabled(), || {
        Err(errors::ApiErrorResponse::MerchantConnectorAccountDisabled)
    })?;

    let auth_type = merchant_connector_account
        .get_connector_account_details()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed while parsing value for ConnectorAuthType")?;

    // TODO: Take Globalid and convert to connector reference id
    let customer_id = customer
        .to_owned()
        .map(|customer| common_utils::id_type::CustomerId::try_from(customer.id.clone()))
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable(
            "Invalid global customer generated, not able to convert to reference id",
        )?;

    let connector_customer_id =
        payment_data.get_connector_customer_id(customer.as_ref(), merchant_connector_account);

    let payment_method = payment_data.payment_attempt.payment_method_type;

    let router_base_url = &state.base_url;
    let attempt = &payment_data.payment_attempt;

    let complete_authorize_url = Some(helpers::create_complete_authorize_url(
        router_base_url,
        attempt,
        connector_id,
        None,
    ));

    let webhook_url = match merchant_connector_account {
        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorAccount(
            merchant_connector_account,
        ) => Some(helpers::create_webhook_url(
            router_base_url,
            &attempt.merchant_id,
            merchant_connector_account.get_id().get_string_repr(),
        )),
        // TODO: Implement for connectors that require a webhook URL to be included in the request payload.
        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorDetails(_) => None,
    };

    let router_return_url = payment_data
        .payment_intent
        .create_finish_redirection_url(
            router_base_url,
            merchant_context
                .get_merchant_account()
                .publishable_key
                .as_ref(),
        )
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to construct finish redirection url")?
        .to_string();

    let connector_request_reference_id = payment_data
        .payment_attempt
        .connector_request_reference_id
        .clone()
        .ok_or(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("connector_request_reference_id not found in payment_attempt")?;

    let email = customer
        .as_ref()
        .and_then(|customer| customer.email.clone())
        .map(pii::Email::from);

    let browser_info = payment_data
        .payment_attempt
        .browser_info
        .clone()
        .map(types::BrowserInformation::from);
    let additional_payment_method_data: Option<api_models::payments::AdditionalPaymentData> =
            payment_data.payment_attempt
                .payment_method_data
                .as_ref().map(|data| data.clone().parse_value("AdditionalPaymentData"))
                .transpose()
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed to parse AdditionalPaymentData from payment_data.payment_attempt.payment_method_data")?;

    // TODO: few fields are repeated in both routerdata and request
    let request = types::PaymentsAuthorizeData {
        payment_method_data: payment_data
            .payment_method_data
            .get_required_value("payment_method_data")?,
        setup_future_usage: Some(payment_data.payment_intent.setup_future_usage),
        mandate_id: payment_data.mandate_data.clone(),
        off_session: None,
        setup_mandate_details: None,
        confirm: true,
        statement_descriptor_suffix: None,
        statement_descriptor: None,
        capture_method: Some(payment_data.payment_intent.capture_method),
        amount: payment_data
            .payment_attempt
            .amount_details
            .get_net_amount()
            .get_amount_as_i64(),
        minor_amount: payment_data.payment_attempt.amount_details.get_net_amount(),
        order_tax_amount: None,
        currency: payment_data.payment_intent.amount_details.currency,
        browser_info,
        email,
        customer_name: None,
        payment_experience: None,
        order_details: None,
        order_category: None,
        session_token: None,
        enrolled_for_3ds: true,
        related_transaction_id: None,
        payment_method_type: Some(payment_data.payment_attempt.payment_method_subtype),
        router_return_url: Some(router_return_url),
        webhook_url,
        complete_authorize_url,
        customer_id: customer_id.clone(),
        surcharge_details: None,
        request_extended_authorization: None,
        request_incremental_authorization: matches!(
            payment_data
                .payment_intent
                .request_incremental_authorization,
            RequestIncrementalAuthorization::True
        ),
        metadata: payment_data.payment_intent.metadata.expose_option(),
        authentication_data: None,
        customer_acceptance: None,
        split_payments: None,
        merchant_order_reference_id: payment_data
            .payment_intent
            .merchant_reference_id
            .map(|reference_id| reference_id.get_string_repr().to_owned()),
        integrity_object: None,
        shipping_cost: payment_data.payment_intent.amount_details.shipping_cost,
        additional_payment_method_data,
        merchant_account_id: None,
        merchant_config_currency: None,
        connector_testing_data: None,
        order_id: None,
        locale: None,
        payment_channel: None,
        enable_partial_authorization: None,
    };
    let connector_mandate_request_reference_id = payment_data
        .payment_attempt
        .connector_token_details
        .as_ref()
        .and_then(|detail| detail.get_connector_token_request_reference_id());

    // TODO: evaluate the fields in router data, if they are required or not
    let router_data = types::RouterData {
        flow: PhantomData,
        merchant_id: merchant_context.get_merchant_account().get_id().clone(),
        tenant_id: state.tenant.tenant_id.clone(),
        // TODO: evaluate why we need customer id at the connector level. We already have connector customer id.
        customer_id,
        connector: connector_id.to_owned(),
        // TODO: evaluate why we need payment id at the connector level. We already have connector reference id
        payment_id: payment_data
            .payment_attempt
            .payment_id
            .get_string_repr()
            .to_owned(),
        // TODO: evaluate why we need attempt id at the connector level. We already have connector reference id
        attempt_id: payment_data
            .payment_attempt
            .get_id()
            .get_string_repr()
            .to_owned(),
        status: payment_data.payment_attempt.status,
        payment_method,
        connector_auth_type: auth_type,
        description: payment_data
            .payment_intent
            .description
            .as_ref()
            .map(|description| description.get_string_repr())
            .map(ToOwned::to_owned),
        // TODO: Create unified address
        address: payment_data.payment_address.clone(),
        auth_type: payment_data.payment_attempt.authentication_type,
        connector_meta_data: merchant_connector_account.get_metadata(),
        connector_wallets_details: None,
        request,
        response: Err(hyperswitch_domain_models::router_data::ErrorResponse::default()),
        amount_captured: None,
        minor_amount_captured: None,
        access_token: None,
        session_token: None,
        reference_id: None,
        payment_method_status: None,
        payment_method_token: None,
        connector_customer: connector_customer_id,
        recurring_mandate_payment_data: None,
        // TODO: This has to be generated as the reference id based on the connector configuration
        // Some connectros might not accept accept the global id. This has to be done when generating the reference id
        connector_request_reference_id,
        preprocessing_id: payment_data.payment_attempt.preprocessing_step_id,
        #[cfg(feature = "payouts")]
        payout_method_data: None,
        #[cfg(feature = "payouts")]
        quote_id: None,
        // TODO: take this based on the env
        test_mode: Some(true),
        payment_method_balance: 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,
        connector_mandate_request_reference_id,
        authentication_id: None,
        psd2_sca_exemption_type: None,
        raw_connector_response: None,
        is_payment_id_from_merchant: payment_data.payment_intent.is_payment_id_from_merchant,
        l2_l3_data: None,
        minor_amount_capturable: None,
    };

    Ok(router_data)
}


pub fn get_tenants(&self) -> &HashMap<id_type::TenantId, Tenant> {
        &self.tenants.0
    }


impl api::RefundExecute for Phonepe {}


pub async fn proxy_core() {}


pub async fn evaluate_routing_rule() {}


impl Authorization {
    pub async fn update_by_merchant_id_authorization_id(
        conn: &PgPooledConn,
        merchant_id: common_utils::id_type::MerchantId,
        authorization_id: String,
        authorization_update: AuthorizationUpdate,
    ) -> StorageResult<Self> {
        match generics::generic_update_with_unique_predicate_get_result::<
            <Self as HasTable>::Table,
            _,
            _,
            _,
        >(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::authorization_id.eq(authorization_id.to_owned())),
            AuthorizationUpdateInternal::from(authorization_update),
        )
        .await
        {
            Err(error) => match error.current_context() {
                errors::DatabaseError::NotFound => Err(error.attach_printable(
                    "Authorization with the given Authorization ID does not exist",
                )),
                errors::DatabaseError::NoFieldsToUpdate => {
                    generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
                        conn,
                        dsl::merchant_id
                            .eq(merchant_id.to_owned())
                            .and(dsl::authorization_id.eq(authorization_id.to_owned())),
                    )
                    .await
                }
                _ => Err(error),
            },
            result => result,
        }
    }

    pub async fn find_by_merchant_id_payment_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        payment_id: &common_utils::id_type::PaymentId,
    ) -> StorageResult<Vec<Self>> {
        generics::generic_filter::<<Self as HasTable>::Table, _, _, _>(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::payment_id.eq(payment_id.to_owned())),
            None,
            None,
            Some(dsl::created_at.asc()),
        )
        .await
    }
}


pub struct NovalnetAuthType {
    pub(super) product_activation_key: Secret<String>,
    pub(super) payment_access_key: Secret<String>,
    pub(super) tariff_id: Secret<String>,
}


pub struct ResetTrackingIdRequest {
    pub connector_id: id_type::MerchantConnectorAccountId,
    pub connector: enums::Connector,
}


impl OperationsDeriveInputExt for DeriveInput {
    fn get_metadata(&self) -> syn::Result<Vec<OperationsEnumMeta>> {
        helpers::get_metadata_inner("operation", &self.attrs)
    }
}

impl OperationsDeriveInputExt for for DeriveInput


impl super::refunds::filters::RefundFilterAnalytics for ClickhouseClient {}

impl super::refunds::filters::RefundFilterAnalytics for for ClickhouseClient


pub struct CybersourceProcessingInfo {
    business_application_id: CybersourcePayoutBusinessType,
}


pub struct HashedApiKey(String);


impl AuthorizationInterface for KafkaStore {
    async fn insert_authorization(
        &self,
        authorization: storage::AuthorizationNew,
    ) -> CustomResult<storage::Authorization, errors::StorageError> {
        self.diesel_store.insert_authorization(authorization).await
    }

    async fn find_all_authorizations_by_merchant_id_payment_id(
        &self,
        merchant_id: &id_type::MerchantId,
        payment_id: &id_type::PaymentId,
    ) -> CustomResult<Vec<storage::Authorization>, errors::StorageError> {
        self.diesel_store
            .find_all_authorizations_by_merchant_id_payment_id(merchant_id, payment_id)
            .await
    }

    async fn update_authorization_by_merchant_id_authorization_id(
        &self,
        merchant_id: id_type::MerchantId,
        authorization_id: String,
        authorization: storage::AuthorizationUpdate,
    ) -> CustomResult<storage::Authorization, errors::StorageError> {
        self.diesel_store
            .update_authorization_by_merchant_id_authorization_id(
                merchant_id,
                authorization_id,
                authorization,
            )
            .await
    }
}

impl AuthorizationInterface for for KafkaStore


pub struct ExternalAuthentication;


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

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Minor
    }

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

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

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

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

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

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


pub async fn render_pm_collect_link(
    _state: SessionState,
    _merchant_context: domain::MerchantContext,
    _req: payment_methods::PaymentMethodCollectLinkRenderRequest,
) -> RouterResponse<services::GenericLinkFormData> {
    todo!()
}


pub async fn tokenize_in_router_when_confirm_false_or_external_authentication<F, Req, D>(
    state: &SessionState,
    operation: &BoxedOperation<'_, F, Req, D>,
    payment_data: &mut D,
    validate_result: &operations::ValidateResult,
    merchant_key_store: &domain::MerchantKeyStore,
    customer: &Option<domain::Customer>,
    business_profile: &domain::Profile,
) -> RouterResult<D>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    // On confirm is false and only router related
    let is_external_authentication_requested = payment_data
        .get_payment_intent()
        .request_external_three_ds_authentication;
    let payment_data =
        if !is_operation_confirm(operation) || is_external_authentication_requested == Some(true) {
            let (_operation, payment_method_data, pm_id) = operation
                .to_domain()?
                .make_pm_data(
                    state,
                    payment_data,
                    validate_result.storage_scheme,
                    merchant_key_store,
                    customer,
                    business_profile,
                    false,
                )
                .await?;
            payment_data.set_payment_method_data(payment_method_data);
            if let Some(payment_method_id) = pm_id {
                payment_data.set_payment_method_id_in_attempt(Some(payment_method_id));
            }
            payment_data
        } else {
            payment_data
        };
    Ok(payment_data.to_owned())
}


impl api::Refund for Gocardless {}


pub async fn update_by_role_id(
        conn: &PgPooledConn,
        role_id: &str,
        role_update: RoleUpdate,
    ) -> StorageResult<Self> {
        generics::generic_update_with_unique_predicate_get_result::<
            <Self as HasTable>::Table,
            _,
            _,
            _,
        >(
            conn,
            dsl::role_id.eq(role_id.to_owned()),
            RoleUpdateInternal::from(role_update),
        )
        .await
    }


File: crates/hyperswitch_connectors/src/connectors/rapyd.rs
 Public functions: 2
 Public structs: 1

pub mod transformers;
use std::sync::LazyLock;

use api_models::webhooks::IncomingWebhookEvent;
use base64::Engine;
use common_enums::enums;
use common_utils::{
    consts::BASE64_ENGINE_URL_SAFE,
    crypto, date_time,
    errors::CustomResult,
    ext_traits::{ByteSliceExt, BytesExt, Encode, StringExt},
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{
        AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector, StringMinorUnit,
        StringMinorUnitForConnector,
    },
};
use error_stack::{Report, ResultExt};
use hyperswitch_domain_models::{
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorIntegration, ConnectorSpecifications, ConnectorValidation,
    },
    configs::Connectors,
    disputes::DisputePayload,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{self, Response},
    webhooks::{IncomingWebhook, IncomingWebhookRequestDetails},
};
use masking::{ExposeInterface, Mask, PeekInterface, Secret};
use rand::distributions::{Alphanumeric, DistString};
use ring::hmac;
use router_env::logger;
use transformers as rapyd;

use crate::{
    constants::headers,
    types::ResponseRouterData,
    utils::{self, convert_amount, get_header_key_value},
};

#[derive(Clone)]
pub struct Rapyd {
    amount_converter: &'static (dyn AmountConvertor<Output = FloatMajorUnit> + Sync),
    amount_converter_webhooks: &'static (dyn AmountConvertor<Output = StringMinorUnit> + Sync),
}
impl Rapyd {
    pub fn new() -> &'static Self {
        &Self {
            amount_converter: &FloatMajorUnitForConnector,
            amount_converter_webhooks: &StringMinorUnitForConnector,
        }
    }
}
impl Rapyd {
    pub fn generate_signature(
        &self,
        auth: &rapyd::RapydAuthType,
        http_method: &str,
        url_path: &str,
        body: &str,
        timestamp: i64,
        salt: &str,
    ) -> CustomResult<String, errors::ConnectorError> {
        let rapyd::RapydAuthType {
            access_key,
            secret_key,
        } = auth;
        let to_sign = format!(
            "{http_method}{url_path}{salt}{timestamp}{}{}{body}",
            access_key.peek(),
            secret_key.peek()
        );
        let key = hmac::Key::new(hmac::HMAC_SHA256, secret_key.peek().as_bytes());
        let tag = hmac::sign(&key, to_sign.as_bytes());
        let hmac_sign = hex::encode(tag);
        let signature_value = BASE64_ENGINE_URL_SAFE.encode(hmac_sign);
        Ok(signature_value)
    }
}

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

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Base
    }

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

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

    fn get_auth_header(
        &self,
        _auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        Ok(vec![])
    }

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: Result<
            rapyd::RapydPaymentsResponse,
            Report<common_utils::errors::ParsingError>,
        > = res.response.parse_struct("Rapyd ErrorResponse");

        match response {
            Ok(response_data) => {
                event_builder.map(|i| i.set_error_response_body(&response_data));
                router_env::logger::info!(connector_response=?response_data);
                Ok(ErrorResponse {
                    status_code: res.status_code,
                    code: response_data.status.error_code,
                    message: response_data.status.status.unwrap_or_default(),
                    reason: response_data.status.message,
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                })
            }
            Err(error_msg) => {
                event_builder.map(|event| event.set_error(serde_json::json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code})));
                logger::error!(deserialization_error =? error_msg);
                utils::handle_json_response_deserialization_failure(res, "rapyd")
            }
        }
    }
}

impl ConnectorValidation for Rapyd {}

impl api::ConnectorAccessToken for Rapyd {}

impl api::PaymentToken for Rapyd {}

impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
    for Rapyd
{
    // Not Implemented (R)
}

impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Rapyd {}

impl api::PaymentAuthorize for Rapyd {}

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Rapyd {
    fn get_headers(
        &self,
        _req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        Ok(vec![(
            headers::CONTENT_TYPE.to_string(),
            types::PaymentsAuthorizeType::get_content_type(self)
                .to_string()
                .into(),
        )])
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}/v1/payments", self.base_url(connectors)))
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.currency,
        )?;
        let connector_router_data = rapyd::RapydRouterData::from((amount, req));
        let connector_req = rapyd::RapydPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &RouterData<Authorize, PaymentsAuthorizeData, PaymentsResponseData>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let timestamp = date_time::now_unix_timestamp();
        let salt = Alphanumeric.sample_string(&mut rand::thread_rng(), 12);

        let auth: rapyd::RapydAuthType = rapyd::RapydAuthType::try_from(&req.connector_auth_type)?;
        let body = types::PaymentsAuthorizeType::get_request_body(self, req, connectors)?;
        let req_body = body.get_inner_value().expose();
        let signature =
            self.generate_signature(&auth, "post", "/v1/payments", &req_body, timestamp, &salt)?;
        let headers = vec![
            ("access_key".to_string(), auth.access_key.into_masked()),
            ("salt".to_string(), salt.into_masked()),
            ("timestamp".to_string(), timestamp.to_string().into()),
            ("signature".to_string(), signature.into_masked()),
        ];
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&types::PaymentsAuthorizeType::get_url(
                self, req, connectors,
            )?)
            .attach_default_headers()
            .headers(types::PaymentsAuthorizeType::get_headers(
                self, req, connectors,
            )?)
            .headers(headers)
            .set_body(types::PaymentsAuthorizeType::get_request_body(
                self, req, connectors,
            )?)
            .build();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: rapyd::RapydPaymentsResponse = res
            .response
            .parse_struct("Rapyd PaymentResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl api::Payment for Rapyd {}

impl api::MandateSetup for Rapyd {}
impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData> for Rapyd {
    fn build_request(
        &self,
        _req: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        _connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Err(
            errors::ConnectorError::NotImplemented("Setup Mandate flow for Rapyd".to_string())
                .into(),
        )
    }
}

impl api::PaymentVoid for Rapyd {}

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Rapyd {
    fn get_headers(
        &self,
        _req: &PaymentsCancelRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        Ok(vec![(
            headers::CONTENT_TYPE.to_string(),
            types::PaymentsVoidType::get_content_type(self)
                .to_string()
                .into(),
        )])
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}/v1/payments/{}",
            self.base_url(connectors),
            req.request.connector_transaction_id
        ))
    }

    fn build_request(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let timestamp = date_time::now_unix_timestamp();
        let salt = Alphanumeric.sample_string(&mut rand::thread_rng(), 12);

        let auth: rapyd::RapydAuthType = rapyd::RapydAuthType::try_from(&req.connector_auth_type)?;
        let url_path = format!("/v1/payments/{}", req.request.connector_transaction_id);
        let signature =
            self.generate_signature(&auth, "delete", &url_path, "", timestamp, &salt)?;

        let headers = vec![
            ("access_key".to_string(), auth.access_key.into_masked()),
            ("salt".to_string(), salt.into_masked()),
            ("timestamp".to_string(), timestamp.to_string().into()),
            ("signature".to_string(), signature.into_masked()),
        ];
        let request = RequestBuilder::new()
            .method(Method::Delete)
            .url(&types::PaymentsVoidType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?)
            .headers(headers)
            .build();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &PaymentsCancelRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCancelRouterData, errors::ConnectorError> {
        let response: rapyd::RapydPaymentsResponse = res
            .response
            .parse_struct("Rapyd PaymentResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl api::PaymentSync for Rapyd {}
impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Rapyd {
    fn get_headers(
        &self,
        _req: &PaymentsSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        Ok(vec![(
            headers::CONTENT_TYPE.to_string(),
            types::PaymentsSyncType::get_content_type(self)
                .to_string()
                .into(),
        )])
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let id = req.request.connector_transaction_id.clone();
        Ok(format!(
            "{}/v1/payments/{}",
            self.base_url(connectors),
            id.get_connector_transaction_id()
                .change_context(errors::ConnectorError::MissingConnectorTransactionID)?
        ))
    }

    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let timestamp = date_time::now_unix_timestamp();
        let salt = Alphanumeric.sample_string(&mut rand::thread_rng(), 12);

        let auth: rapyd::RapydAuthType = rapyd::RapydAuthType::try_from(&req.connector_auth_type)?;
        let response_id = req.request.connector_transaction_id.clone();
        let url_path = format!(
            "/v1/payments/{}",
            response_id
                .get_connector_transaction_id()
                .change_context(errors::ConnectorError::MissingConnectorTransactionID)?
        );
        let signature = self.generate_signature(&auth, "get", &url_path, "", timestamp, &salt)?;

        let headers = vec![
            ("access_key".to_string(), auth.access_key.into_masked()),
            ("salt".to_string(), salt.into_masked()),
            ("timestamp".to_string(), timestamp.to_string().into()),
            ("signature".to_string(), signature.into_masked()),
        ];
        let request = RequestBuilder::new()
            .method(Method::Get)
            .url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
            .headers(headers)
            .build();
        Ok(Some(request))
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: rapyd::RapydPaymentsResponse = res
            .response
            .parse_struct("Rapyd PaymentResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }
}

impl api::PaymentCapture for Rapyd {}
impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Rapyd {
    fn get_headers(
        &self,
        _req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        Ok(vec![(
            headers::CONTENT_TYPE.to_string(),
            types::PaymentsCaptureType::get_content_type(self)
                .to_string()
                .into(),
        )])
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_request_body(
        &self,
        req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_converter,
            req.request.minor_amount_to_capture,
            req.request.currency,
        )?;
        let connector_router_data = rapyd::RapydRouterData::from((amount, req));
        let connector_req = rapyd::CaptureRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let timestamp = date_time::now_unix_timestamp();
        let salt = Alphanumeric.sample_string(&mut rand::thread_rng(), 12);

        let auth: rapyd::RapydAuthType = rapyd::RapydAuthType::try_from(&req.connector_auth_type)?;
        let url_path = format!(
            "/v1/payments/{}/capture",
            req.request.connector_transaction_id
        );
        let body = types::PaymentsCaptureType::get_request_body(self, req, connectors)?;
        let req_body = body.get_inner_value().expose();
        let signature =
            self.generate_signature(&auth, "post", &url_path, &req_body, timestamp, &salt)?;
        let headers = vec![
            ("access_key".to_string(), auth.access_key.into_masked()),
            ("salt".to_string(), salt.into_masked()),
            ("timestamp".to_string(), timestamp.to_string().into()),
            ("signature".to_string(), signature.into_masked()),
        ];
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(types::PaymentsCaptureType::get_headers(
                self, req, connectors,
            )?)
            .headers(headers)
            .set_body(types::PaymentsCaptureType::get_request_body(
                self, req, connectors,
            )?)
            .build();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &PaymentsCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCaptureRouterData, errors::ConnectorError> {
        let response: rapyd::RapydPaymentsResponse = res
            .response
            .parse_struct("RapydPaymentResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    fn get_url(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}/v1/payments/{}/capture",
            self.base_url(connectors),
            req.request.connector_transaction_id
        ))
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl api::PaymentSession for Rapyd {}

impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Rapyd {
    //TODO: implement sessions flow
}

impl api::Refund for Rapyd {}
impl api::RefundExecute for Rapyd {}
impl api::RefundSync for Rapyd {}

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Rapyd {
    fn get_headers(
        &self,
        _req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        Ok(vec![(
            headers::CONTENT_TYPE.to_string(),
            types::RefundExecuteType::get_content_type(self)
                .to_string()
                .into(),
        )])
    }

    fn get_content_type(&self) -> &'static str {
        ConnectorCommon::common_get_content_type(self)
    }

    fn get_url(
        &self,
        _req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}/v1/refunds", self.base_url(connectors)))
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_converter,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;
        let connector_router_data = rapyd::RapydRouterData::from((amount, req));
        let connector_req = rapyd::RapydRefundRequest::try_from(&connector_router_data)?;

        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let timestamp = date_time::now_unix_timestamp();
        let salt = Alphanumeric.sample_string(&mut rand::thread_rng(), 12);

        let body = types::RefundExecuteType::get_request_body(self, req, connectors)?;
        let req_body = body.get_inner_value().expose();
        let auth: rapyd::RapydAuthType = rapyd::RapydAuthType::try_from(&req.connector_auth_type)?;
        let signature =
            self.generate_signature(&auth, "post", "/v1/refunds", &req_body, timestamp, &salt)?;
        let headers = vec![
            ("access_key".to_string(), auth.access_key.into_masked()),
            ("salt".to_string(), salt.into_masked()),
            ("timestamp".to_string(), timestamp.to_string().into()),
            ("signature".to_string(), signature.into_masked()),
        ];
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&types::RefundExecuteType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(headers)
            .set_body(types::RefundExecuteType::get_request_body(
                self, req, connectors,
            )?)
            .build();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &RefundsRouterData<Execute>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
        let response: rapyd::RefundResponse = res
            .response
            .parse_struct("rapyd RefundResponse")
            .change_context(errors::ConnectorError::RequestEncodingFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Rapyd {
    // default implementation of build_request method will be executed
    fn handle_response(
        &self,
        data: &RefundSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        let response: rapyd::RefundResponse = res
            .response
            .parse_struct("rapyd RefundResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }
}

#[async_trait::async_trait]
impl IncomingWebhook for Rapyd {
    fn get_webhook_source_verification_algorithm(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
        Ok(Box::new(crypto::HmacSha256))
    }

    fn get_webhook_source_verification_signature(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let base64_signature = get_header_key_value("signature", request.headers)?;
        let signature = BASE64_ENGINE_URL_SAFE
            .decode(base64_signature.as_bytes())
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
        Ok(signature)
    }

    fn get_webhook_source_verification_message(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let host = get_header_key_value("host", request.headers)?;
        let connector = self.id();
        let url_path = format!(
            "https://{host}/webhooks/{}/{connector}",
            merchant_id.get_string_repr()
        );
        let salt = get_header_key_value("salt", request.headers)?;
        let timestamp = get_header_key_value("timestamp", request.headers)?;
        let stringify_auth = String::from_utf8(connector_webhook_secrets.secret.to_vec())
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
            .attach_printable("Could not convert secret to UTF-8")?;
        let auth: transformers::RapydAuthType = stringify_auth
            .parse_struct("RapydAuthType")
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
        let access_key = auth.access_key;
        let secret_key = auth.secret_key;
        let body_string = String::from_utf8(request.body.to_vec())
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
            .attach_printable("Could not convert body to UTF-8")?;
        let to_sign = format!(
            "{url_path}{salt}{timestamp}{}{}{body_string}",
            access_key.peek(),
            secret_key.peek()
        );

        Ok(to_sign.into_bytes())
    }

    async fn verify_webhook_source(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
        _connector_account_details: crypto::Encryptable<Secret<serde_json::Value>>,
        connector_label: &str,
    ) -> CustomResult<bool, errors::ConnectorError> {
        let connector_webhook_secrets = self
            .get_webhook_source_verification_merchant_secret(
                merchant_id,
                connector_label,
                connector_webhook_details,
            )
            .await
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
        let signature = self
            .get_webhook_source_verification_signature(request, &connector_webhook_secrets)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
        let message = self
            .get_webhook_source_verification_message(
                request,
                merchant_id,
                &connector_webhook_secrets,
            )
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;

        let stringify_auth = String::from_utf8(connector_webhook_secrets.secret.to_vec())
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
            .attach_printable("Could not convert secret to UTF-8")?;
        let auth: transformers::RapydAuthType = stringify_auth
            .parse_struct("RapydAuthType")
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
        let secret_key = auth.secret_key;
        let key = hmac::Key::new(hmac::HMAC_SHA256, secret_key.peek().as_bytes());
        let tag = hmac::sign(&key, &message);
        let hmac_sign = hex::encode(tag);
        Ok(hmac_sign.as_bytes().eq(&signature))
    }

    fn get_webhook_object_reference_id(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        let webhook: transformers::RapydIncomingWebhook = request
            .body
            .parse_struct("RapydIncomingWebhook")
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;

        Ok(match webhook.data {
            transformers::WebhookData::Payment(payment_data) => {
                api_models::webhooks::ObjectReferenceId::PaymentId(
                    api_models::payments::PaymentIdType::ConnectorTransactionId(payment_data.id),
                )
            }
            transformers::WebhookData::Refund(refund_data) => {
                api_models::webhooks::ObjectReferenceId::RefundId(
                    api_models::webhooks::RefundIdType::ConnectorRefundId(refund_data.id),
                )
            }
            transformers::WebhookData::Dispute(dispute_data) => {
                api_models::webhooks::ObjectReferenceId::PaymentId(
                    api_models::payments::PaymentIdType::ConnectorTransactionId(
                        dispute_data.original_transaction_id,
                    ),
                )
            }
        })
    }

    fn get_webhook_event_type(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
        let webhook: transformers::RapydIncomingWebhook = request
            .body
            .parse_struct("RapydIncomingWebhook")
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
        Ok(match webhook.webhook_type {
            rapyd::RapydWebhookObjectEventType::PaymentCompleted
            | rapyd::RapydWebhookObjectEventType::PaymentCaptured => {
                IncomingWebhookEvent::PaymentIntentSuccess
            }
            rapyd::RapydWebhookObjectEventType::PaymentFailed => {
                IncomingWebhookEvent::PaymentIntentFailure
            }
            rapyd::RapydWebhookObjectEventType::PaymentRefundFailed
            | rapyd::RapydWebhookObjectEventType::PaymentRefundRejected => {
                IncomingWebhookEvent::RefundFailure
            }
            rapyd::RapydWebhookObjectEventType::RefundCompleted => {
                IncomingWebhookEvent::RefundSuccess
            }
            rapyd::RapydWebhookObjectEventType::PaymentDisputeCreated => {
                IncomingWebhookEvent::DisputeOpened
            }
            rapyd::RapydWebhookObjectEventType::Unknown => IncomingWebhookEvent::EventNotSupported,
            rapyd::RapydWebhookObjectEventType::PaymentDisputeUpdated => match webhook.data {
                rapyd::WebhookData::Dispute(data) => IncomingWebhookEvent::from(data.status),
                _ => IncomingWebhookEvent::EventNotSupported,
            },
        })
    }

    fn get_webhook_resource_object(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let webhook: transformers::RapydIncomingWebhook = request
            .body
            .parse_struct("RapydIncomingWebhook")
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
        let res_json = match webhook.data {
            transformers::WebhookData::Payment(payment_data) => {
                let rapyd_response: transformers::RapydPaymentsResponse = payment_data.into();

                rapyd_response
                    .encode_to_value()
                    .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?
            }
            transformers::WebhookData::Refund(refund_data) => refund_data
                .encode_to_value()
                .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?,
            transformers::WebhookData::Dispute(dispute_data) => dispute_data
                .encode_to_value()
                .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?,
        };
        Ok(Box::new(res_json))
    }

    fn get_dispute_details(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<DisputePayload, errors::ConnectorError> {
        let webhook: transformers::RapydIncomingWebhook = request
            .body
            .parse_struct("RapydIncomingWebhook")
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
        let webhook_dispute_data = match webhook.data {
            transformers::WebhookData::Dispute(dispute_data) => Ok(dispute_data),
            _ => Err(errors::ConnectorError::WebhookBodyDecodingFailed),
        }?;
        Ok(DisputePayload {
            amount: convert_amount(
                self.amount_converter_webhooks,
                webhook_dispute_data.amount,
                webhook_dispute_data.currency,
            )?,
            currency: webhook_dispute_data.currency,
            dispute_stage: api_models::enums::DisputeStage::Dispute,
            connector_dispute_id: webhook_dispute_data.token,
            connector_reason: Some(webhook_dispute_data.dispute_reason_description),
            connector_reason_code: None,
            challenge_required_by: webhook_dispute_data.due_date,
            connector_status: webhook_dispute_data.status.to_string(),
            created_at: webhook_dispute_data.created_at,
            updated_at: webhook_dispute_data.updated_at,
        })
    }
}

static RAPYD_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> = LazyLock::new(|| {
    let supported_capture_methods = vec![
        enums::CaptureMethod::Automatic,
        enums::CaptureMethod::Manual,
        enums::CaptureMethod::SequentialAutomatic,
    ];

    let supported_card_network = vec![
        common_enums::CardNetwork::AmericanExpress,
        common_enums::CardNetwork::Visa,
        common_enums::CardNetwork::JCB,
        common_enums::CardNetwork::DinersClub,
        common_enums::CardNetwork::UnionPay,
        common_enums::CardNetwork::Mastercard,
        common_enums::CardNetwork::Discover,
    ];

    let mut rapyd_supported_payment_methods = SupportedPaymentMethods::new();

    rapyd_supported_payment_methods.add(
        enums::PaymentMethod::Wallet,


impl api::PaymentCapture for Celero {}


pub fn headers(mut self, headers: Vec<(String, Maskable<String>)


pub struct NoonRevokeMandateResult {
    subscription: NoonCancelSubscriptionObject,
}


            .to_lowercase();
        let (_, sig_value) = security_header
            .split_once('=')
            .ok_or(errors::ConnectorError::WebhookSourceVerificationFailed)?;
        hex::decode(sig_value).change_context(errors::ConnectorError::WebhookSignatureNotFound)
    }

    fn get_webhook_source_verification_message(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _merchant_id: &common_utils::id_type::MerchantId,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        Ok(request.body.to_vec())
    }

    fn get_webhook_object_reference_id(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        let details: authorizedotnet::AuthorizedotnetWebhookObjectId = request
            .body
            .parse_struct("AuthorizedotnetWebhookObjectId")
            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
        match details.event_type {
            authorizedotnet::AuthorizedotnetWebhookEvent::RefundCreated => {
                Ok(api_models::webhooks::ObjectReferenceId::RefundId(
                    api_models::webhooks::RefundIdType::ConnectorRefundId(
                        authorizedotnet::get_trans_id(&details)?,
                    ),
                ))
            }
            authorizedotnet::AuthorizedotnetWebhookEvent::AuthorizationCreated
            | authorizedotnet::AuthorizedotnetWebhookEvent::PriorAuthCapture
            | authorizedotnet::AuthorizedotnetWebhookEvent::AuthCapCreated
            | authorizedotnet::AuthorizedotnetWebhookEvent::CaptureCreated
            | authorizedotnet::AuthorizedotnetWebhookEvent::VoidCreated => {
                Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
                    api_models::payments::PaymentIdType::ConnectorTransactionId(
                        authorizedotnet::get_trans_id(&details)?,
                    ),
                ))
            }
        }
    }

    fn get_webhook_event_type(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        let details: authorizedotnet::AuthorizedotnetWebhookEventType = request
            .body
            .parse_struct("AuthorizedotnetWebhookEventType")
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
        Ok(api_models::webhooks::IncomingWebhookEvent::from(
            details.event_type,
        ))
    }

    fn get_webhook_resource_object(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let payload: authorizedotnet::AuthorizedotnetWebhookObjectId = request
            .body
            .parse_struct("AuthorizedotnetWebhookObjectId")
            .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;

        Ok(Box::new(
            authorizedotnet::AuthorizedotnetSyncResponse::try_from(payload)?,
        ))
    }
}

#[inline]
fn get_error_response(
    Response {
        response,
        status_code,
        ..
    }: Response,
    event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
    let response: authorizedotnet::AuthorizedotnetPaymentsResponse = response
        .parse_struct("AuthorizedotnetPaymentsResponse")
        .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

    match response.transaction_response {
        Some(authorizedotnet::TransactionResponse::AuthorizedotnetTransactionResponse(
            payment_response,
        )) => Ok(payment_response
            .errors
            .and_then(|errors| {
                errors.into_iter().next().map(|error| ErrorResponse {
                    code: error.error_code,
                    message: error.error_text.to_owned(),
                    reason: Some(error.error_text),
                    status_code,
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                })
            })
            .unwrap_or_else(|| ErrorResponse {
                code: consts::NO_ERROR_CODE.to_string(), // authorizedotnet sends 200 in case of bad request so this are hard coded to NO_ERROR_CODE and NO_ERROR_MESSAGE
                message: consts::NO_ERROR_MESSAGE.to_string(),
                reason: None,
                status_code,
                attempt_status: None,
                connector_transaction_id: None,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })),
        Some(authorizedotnet::TransactionResponse::AuthorizedotnetTransactionResponseError(_))
        | None => {
            let message = &response
                .messages
                .message
                .first()
                .ok_or(errors::ConnectorError::ResponseDeserializationFailed)?
                .text;
            Ok(ErrorResponse {
                code: consts::NO_ERROR_CODE.to_string(),
                message: message.to_string(),
                reason: Some(message.to_string()),
                status_code,
                attempt_status: None,
                connector_transaction_id: None,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        }
    }
}

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

static AUTHORIZEDOTNET_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> =
    LazyLock::new(|| {
        let supported_capture_methods = vec![
            enums::CaptureMethod::Automatic,
            enums::CaptureMethod::Manual,
            enums::CaptureMethod::SequentialAutomatic,
        ];

        let supported_card_network = vec![
            common_enums::CardNetwork::AmericanExpress,
            common_enums::CardNetwork::Discover,
            common_enums::CardNetwork::JCB,
            common_enums::CardNetwork::Mastercard,
            common_enums::CardNetwork::Visa,
        ];

        let mut authorizedotnet_supported_payment_methods = SupportedPaymentMethods::new();

        authorizedotnet_supported_payment_methods.add(
            enums::PaymentMethod::Wallet,
            enums::PaymentMethodType::ApplePay,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        authorizedotnet_supported_payment_methods.add(
            enums::PaymentMethod::Wallet,
            enums::PaymentMethodType::GooglePay,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        authorizedotnet_supported_payment_methods.add(
            enums::PaymentMethod::Wallet,
            enums::PaymentMethodType::Paypal,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        authorizedotnet_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Credit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: Some(
                    api_models::feature_matrix::PaymentMethodSpecificFeatures::Card({
                        api_models::feature_matrix::CardSpecificFeatures {
                            three_ds: common_enums::FeatureStatus::NotSupported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                ),
            },
        );

        authorizedotnet_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Debit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: Some(
                    api_models::feature_matrix::PaymentMethodSpecificFeatures::Card({
                        api_models::feature_matrix::CardSpecificFeatures {
                            three_ds: common_enums::FeatureStatus::NotSupported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                ),
            },
        );
        authorizedotnet_supported_payment_methods
    });

static  AUTHORIZEDOTNET_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Authorize.net",
    description:
        " Authorize.net supports payment processing by helping small businesses accept credit card and eCheck payments online, in person on the go.",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Live,
};

static AUTHORIZEDOTNET_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 2] =
    [enums::EventClass::Payments, enums::EventClass::Refunds];

impl ConnectorSpecifications for Authorizedotnet {
    fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
        Some(&AUTHORIZEDOTNET_CONNECTOR_INFO)
    }

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

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


impl api::Payment for Worldline {}


pub struct RedsysSyncResponse {
    #[serde(rename = "@xmlns:soapenv")]
    xmlns_soapenv: String,
    #[serde(rename = "@xmlns:soapenc")]
    xmlns_soapenc: String,
    #[serde(rename = "@xmlns:xsd")]
    xmlns_xsd: String,
    #[serde(rename = "@xmlns:xsi")]
    xmlns_xsi: String,
    #[serde(rename = "header")]
    header: Option<SoapHeader>,
    #[serde(rename = "body")]
    body: SyncResponseBody,
}


pub struct CardDetailFromLocker {
    pub scheme: Option<String>,
    pub issuer_country: Option<String>,
    pub last4_digits: Option<String>,
    #[serde(skip)]
    #[schema(value_type=Option<String>)]
    pub card_number: Option<CardNumber>,

    #[schema(value_type=Option<String>)]
    pub expiry_month: Option<masking::Secret<String>>,

    #[schema(value_type=Option<String>)]
    pub expiry_year: Option<masking::Secret<String>>,

    #[schema(value_type=Option<String>)]
    pub card_token: Option<masking::Secret<String>>,

    #[schema(value_type=Option<String>)]
    pub card_holder_name: Option<masking::Secret<String>>,

    #[schema(value_type=Option<String>)]
    pub card_fingerprint: Option<masking::Secret<String>>,

    #[schema(value_type=Option<String>)]
    pub nick_name: Option<masking::Secret<String>>,

    #[schema(value_type = Option<CardNetwork>)]
    pub card_network: Option<api_enums::CardNetwork>,

    pub card_isin: Option<String>,
    pub card_issuer: Option<String>,
    pub card_type: Option<String>,
    pub saved_to_locker: bool,
}


pub struct PaymentCaptureRequest {
    domain: String,
    #[serde(rename = "tranID")]
    tran_id: String,
    amount: StringMajorUnit,
    #[serde(rename = "RefID")]
    ref_id: String,
    skey: Secret<String>,
}


impl GetPaymentMethodDetails for DummyConnectorWallet {
    fn get_name(&self) -> &'static str {
        match self {
            Self::GooglePay => "Google Pay",
            Self::Paypal => "PayPal",
            Self::WeChatPay => "WeChat Pay",
            Self::MbWay => "Mb Way",
            Self::AliPay => "Alipay",
            Self::AliPayHK => "Alipay HK",
        }
    }
    fn get_image_link(&self, base_url: &str) -> String {
        let image_name = match self {
            Self::GooglePay => "GOOGLE_PAY.svg",
            Self::Paypal => "PAYPAL.svg",
            Self::WeChatPay => "WECHAT_PAY.svg",
            Self::MbWay => "MBWAY.svg",
            Self::AliPay => "ALIPAY.svg",
            Self::AliPayHK => "ALIPAY.svg",
        };
        format!("{base_url}{image_name}")
    }
}

impl GetPaymentMethodDetails for for DummyConnectorWallet


pub fn is_upstream_timeout(&self) -> bool {
        self == &Self::RequestTimeoutReceived
    }


pub struct ThreeDSecureReqData {
    pub force: bool,
}