            AuthorizedotnetIncomingWebhookEventType::AuthorizationCreated
            | AuthorizedotnetIncomingWebhookEventType::PriorAuthCapture
            | AuthorizedotnetIncomingWebhookEventType::AuthCapCreated
            | AuthorizedotnetIncomingWebhookEventType::CaptureCreated
            | AuthorizedotnetIncomingWebhookEventType::VoidCreated => Self::PaymentIntentSuccess,
            AuthorizedotnetIncomingWebhookEventType::RefundCreated => Self::RefundSuccess,
            AuthorizedotnetIncomingWebhookEventType::Unknown => Self::EventNotSupported,
        }
    }
}

impl From<AuthorizedotnetWebhookEvent> for SyncStatus {
    // status mapping reference https://developer.authorize.net/api/reference/features/webhooks.html#Event_Types_and_Payloads
    fn from(event_type: AuthorizedotnetWebhookEvent) -> Self {
        match event_type {
            AuthorizedotnetWebhookEvent::AuthorizationCreated => Self::AuthorizedPendingCapture,
            AuthorizedotnetWebhookEvent::CaptureCreated
            | AuthorizedotnetWebhookEvent::AuthCapCreated => Self::CapturedPendingSettlement,
            AuthorizedotnetWebhookEvent::PriorAuthCapture => Self::SettledSuccessfully,
            AuthorizedotnetWebhookEvent::VoidCreated => Self::Voided,
            AuthorizedotnetWebhookEvent::RefundCreated => Self::RefundSettledSuccessfully,
        }
    }
}

pub fn get_trans_id(
    details: &AuthorizedotnetWebhookObjectId,
) -> Result<String, errors::ConnectorError> {
    details
        .payload
        .id
        .clone()
        .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)
}

impl TryFrom<AuthorizedotnetWebhookObjectId> for AuthorizedotnetSyncResponse {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: AuthorizedotnetWebhookObjectId) -> Result<Self, Self::Error> {
        Ok(Self {
            transaction: Some(SyncTransactionResponse {
                transaction_id: get_trans_id(&item)?,
                transaction_status: SyncStatus::from(item.event_type),
            }),
            messages: ResponseMessages {
                ..Default::default()
            },
        })
    }
}

fn get_wallet_data(
    wallet_data: &WalletData,
    return_url: &Option<String>,
) -> CustomResult<PaymentDetails, errors::ConnectorError> {
    match wallet_data {
        WalletData::GooglePay(_) => Ok(PaymentDetails::OpaqueData(WalletDetails {
            data_descriptor: WalletMethod::Googlepay,
            data_value: Secret::new(wallet_data.get_encoded_wallet_token()?),
        })),
        WalletData::ApplePay(applepay_token) => {
            let apple_pay_encrypted_data = applepay_token
                .payment_data
                .get_encrypted_apple_pay_payment_data_mandatory()
                .change_context(errors::ConnectorError::MissingRequiredField {
                    field_name: "Apple pay encrypted data",
                })?;
            Ok(PaymentDetails::OpaqueData(WalletDetails {
                data_descriptor: WalletMethod::Applepay,
                data_value: Secret::new(apple_pay_encrypted_data.clone()),
            }))
        }
        WalletData::PaypalRedirect(_) => Ok(PaymentDetails::PayPal(PayPalDetails {
            success_url: return_url.to_owned(),
            cancel_url: return_url.to_owned(),
        })),
        WalletData::AliPayQr(_)
        | WalletData::AliPayRedirect(_)
        | WalletData::AliPayHkRedirect(_)
        | WalletData::AmazonPay(_)
        | WalletData::AmazonPayRedirect(_)
        | WalletData::Paysera(_)
        | WalletData::Skrill(_)
        | WalletData::BluecodeRedirect {}
        | WalletData::MomoRedirect(_)
        | WalletData::KakaoPayRedirect(_)
        | WalletData::GoPayRedirect(_)
        | WalletData::GcashRedirect(_)
        | WalletData::ApplePayRedirect(_)
        | WalletData::ApplePayThirdPartySdk(_)
        | WalletData::DanaRedirect {}
        | WalletData::GooglePayRedirect(_)
        | WalletData::GooglePayThirdPartySdk(_)
        | WalletData::MbWayRedirect(_)
        | WalletData::MobilePayRedirect(_)
        | WalletData::PaypalSdk(_)
        | WalletData::Paze(_)
        | WalletData::SamsungPay(_)
        | WalletData::TwintRedirect {}
        | WalletData::VippsRedirect {}
        | WalletData::TouchNGoRedirect(_)
        | WalletData::WeChatPayRedirect(_)
        | WalletData::WeChatPayQr(_)
        | WalletData::CashappQr(_)
        | WalletData::SwishQr(_)
        | WalletData::Mifinity(_)
        | WalletData::RevolutPay(_) => Err(errors::ConnectorError::NotImplemented(
            utils::get_unimplemented_payment_method_error_message("authorizedotnet"),
        ))?,
    }
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AuthorizedotnetQueryParams {
    payer_id: String,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PaypalConfirmRequest {
    create_transaction_request: PaypalConfirmTransactionRequest,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PaypalConfirmTransactionRequest {
    merchant_authentication: AuthorizedotnetAuthType,
    transaction_request: TransactionConfirmRequest,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionConfirmRequest {
    transaction_type: TransactionType,
    payment: PaypalPaymentConfirm,
    ref_trans_id: Option<String>,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PaypalPaymentConfirm {
    pay_pal: Paypal,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Paypal {
    #[serde(rename = "payerID")]
    payer_id: Option<Secret<String>>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct PaypalQueryParams {
    #[serde(rename = "PayerID")]
    payer_id: Option<Secret<String>>,
}

impl TryFrom<&AuthorizedotnetRouterData<&PaymentsCompleteAuthorizeRouterData>>
    for PaypalConfirmRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &AuthorizedotnetRouterData<&PaymentsCompleteAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        let params = item
            .router_data
            .request
            .redirect_response
            .as_ref()
            .and_then(|redirect_response| redirect_response.params.as_ref())
            .ok_or(errors::ConnectorError::ResponseDeserializationFailed)?;

        let query_params: PaypalQueryParams = serde_urlencoded::from_str(params.peek())
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)
            .attach_printable("Failed to parse connector response")?;

        let payer_id = query_params.payer_id;

        let transaction_type = match item.router_data.request.capture_method {
            Some(enums::CaptureMethod::Manual) => Ok(TransactionType::ContinueAuthorization),
            Some(enums::CaptureMethod::SequentialAutomatic)
            | Some(enums::CaptureMethod::Automatic)
            | None => Ok(TransactionType::ContinueCapture),
            Some(enums::CaptureMethod::ManualMultiple) => {
                Err(errors::ConnectorError::NotSupported {
                    message: enums::CaptureMethod::ManualMultiple.to_string(),
                    connector: "authorizedotnet",
                })
            }
            Some(enums::CaptureMethod::Scheduled) => Err(errors::ConnectorError::NotSupported {
                message: enums::CaptureMethod::Scheduled.to_string(),
                connector: "authorizedotnet",
            }),
        }?;
        let transaction_request = TransactionConfirmRequest {
            transaction_type,
            payment: PaypalPaymentConfirm {
                pay_pal: Paypal { payer_id },
            },
            ref_trans_id: item.router_data.request.connector_transaction_id.clone(),
        };

        let merchant_authentication =
            AuthorizedotnetAuthType::try_from(&item.router_data.connector_auth_type)?;

        Ok(Self {
            create_transaction_request: PaypalConfirmTransactionRequest {
                merchant_authentication,
                transaction_request,
            },
        })
    }
}


// Function: validate
// File: crates/router/src/configs/validations.rs
// Module: router

pub fn validate(&self) -> Result<(), ApplicationError>


// Struct: BokuErrorResponse
// File: crates/hyperswitch_connectors/src/connectors/boku/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BokuErrorResponse


// Function: resolve_billing_address_for_payout
// File: crates/router/src/core/payouts/helpers.rs
// Module: router

pub fn resolve_billing_address_for_payout(
    state: &SessionState,
    req_billing: Option<&api_models::payments::Address>,
    existing_address_id: Option<&String>,
    payment_method: Option<&hyperswitch_domain_models::payment_methods::PaymentMethod>,
    merchant_context: &domain::MerchantContext,
    customer_id: Option<&id_type::CustomerId>,
    payout_id: &id_type::PayoutId,
) -> RouterResult<(
    Option<hyperswitch_domain_models::address::Address>,
    Option<String>,
)>


// Module Structure
// File: crates/external_services/src/grpc_client.rs
// Module: external_services

// Public submodules:
pub mod dynamic_routing;
pub mod health_check_client;
pub mod revenue_recovery;
pub mod unified_connector_service;

// Public exports:
pub use self::revenue_recovery::{
    recovery_decider_client::{
        DeciderRequest, DeciderResponse, RecoveryDeciderClientConfig,
        RecoveryDeciderClientInterface, RecoveryDeciderError, RecoveryDeciderResult,
    },
    GrpcRecoveryHeaders,
};


// Struct: XenditRedirectionResponse
// File: crates/hyperswitch_connectors/src/connectors/xendit/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct XenditRedirectionResponse


// Struct: AuditEvent
// File: crates/router/src/events/audit_events.rs
// Module: router
// Implementations: 3
// Traits: Event, EventInfo

pub struct AuditEvent


// Struct: KatapultPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/katapult/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct KatapultPaymentsRequest


// Function: get_or_create_key_store
// File: crates/router/src/types/domain/user.rs
// Module: router

pub fn get_or_create_key_store(&self, state: &SessionState) -> UserResult<UserKeyStore>


// Struct: CardInfo
// File: crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CardInfo


// Implementation: impl DummyConnectorPaymentAttempt
// File: crates/router/src/routes/dummy_connector/types.rs
// Module: router
// Methods: 1 total (1 public)

impl DummyConnectorPaymentAttempt


// Implementation: impl RefundNew
// File: crates/diesel_models/src/query/refund.rs
// Module: diesel_models
// Methods: 1 total (0 public)

impl RefundNew


// Implementation: impl Default for for ConnectorAuthenticationMap
// File: crates/test_utils/src/connector_auth.rs
// Module: test_utils
// Methods: 1 total (0 public)

impl Default for for ConnectorAuthenticationMap


// File: crates/hyperswitch_connectors/src/connectors/opennode.rs
// Module: hyperswitch_connectors
// Public functions: 1
// Public structs: 1

pub mod transformers;

use std::sync::LazyLock;

use common_enums::enums;
use common_utils::{
    crypto,
    errors::CustomResult,
    ext_traits::BytesExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, MinorUnit, MinorUnitForConnector},
};
use error_stack::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, PaymentsCaptureRouterData, PaymentsSyncRouterData,
        RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    consts, errors,
    events::connector_api_logs::ConnectorEvent,
    types::{PaymentsAuthorizeType, PaymentsSyncType, Response},
    webhooks::{self, IncomingWebhook},
};
use masking::{Mask, Maskable};
use transformers as opennode;

use self::opennode::OpennodeWebhookDetails;
use crate::{
    connectors::opennode::transformers::OpennodeRouterData, constants::headers,
    types::ResponseRouterData, utils::convert_amount,
};

#[derive(Clone)]
pub struct Opennode {
    amount_convertor: &'static (dyn AmountConvertor<Output = MinorUnit> + Sync),
}

impl Opennode {
    pub fn new() -> &'static Self {
        &Self {
            amount_convertor: &MinorUnitForConnector,
        }
    }
}

impl api::Payment for Opennode {}
impl api::PaymentSession for Opennode {}
impl api::PaymentToken for Opennode {}
impl api::ConnectorAccessToken for Opennode {}

impl api::MandateSetup for Opennode {}
impl api::PaymentAuthorize for Opennode {}
impl api::PaymentSync for Opennode {}
impl api::PaymentCapture for Opennode {}
impl api::PaymentVoid for Opennode {}
impl api::Refund for Opennode {}
impl api::RefundExecute for Opennode {}
impl api::RefundSync for Opennode {}

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Opennode
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        let mut header = vec![
            (
                headers::CONTENT_TYPE.to_string(),
                self.common_get_content_type().to_string().into(),
            ),
            (
                headers::ACCEPT.to_string(),
                self.common_get_content_type().to_string().into(),
            ),
        ];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);
        Ok(header)
    }
}

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

    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.opennode.base_url.as_ref()
    }

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

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

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

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

impl ConnectorValidation for Opennode {}

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

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

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

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

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Opennode {
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    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/charges", self.base_url(_connectors)))
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_convertor,
            req.request.minor_amount,
            req.request.currency,
        )?;

        let connector_router_data = OpennodeRouterData::try_from((amount, req))?;
        let connector_req = opennode::OpennodePaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsAuthorizeType::get_url(self, req, connectors)?)
                .headers(PaymentsAuthorizeType::get_headers(self, req, connectors)?)
                .set_body(PaymentsAuthorizeType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: opennode::OpennodePaymentsResponse = res
            .response
            .parse_struct("Opennode PaymentsAuthorizeResponse")
            .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 ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Opennode {
    fn get_headers(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    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 connector_id = _req
            .request
            .connector_transaction_id
            .get_connector_transaction_id()
            .change_context(errors::ConnectorError::MissingConnectorTransactionID)?;
        Ok(format!(
            "{}/v2/charge/{}",
            self.base_url(_connectors),
            connector_id
        ))
    }

    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&PaymentsSyncType::get_url(self, req, connectors)?)
                .headers(PaymentsSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: opennode::OpennodePaymentsResponse = res
            .response
            .parse_struct("opennode PaymentsSyncResponse")
            .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 ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Opennode {
    fn build_request(
        &self,
        _req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Err(errors::ConnectorError::FlowNotSupported {
            flow: "Capture".to_string(),
            connector: "Opennode".to_string(),
        }
        .into())
    }
}

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Opennode {}

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Opennode {
    fn build_request(
        &self,
        _req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Err(
            errors::ConnectorError::NotImplemented("Refund flow not Implemented".to_string())
                .into(),
        )
    }
}

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Opennode {
    // default implementation of build_request method will be executed
}

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

    fn get_webhook_source_verification_signature(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let notif = serde_urlencoded::from_bytes::<OpennodeWebhookDetails>(request.body)
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
        let base64_signature = notif.hashed_order;
        hex::decode(base64_signature)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
    }

    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> {
        let message = std::str::from_utf8(request.body)
            .change_context(errors::ConnectorError::ParsingFailed)?;
        Ok(message.to_string().into_bytes())
    }

    fn get_webhook_object_reference_id(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        let notif = serde_urlencoded::from_bytes::<OpennodeWebhookDetails>(request.body)
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
        Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
            api_models::payments::PaymentIdType::ConnectorTransactionId(notif.id),
        ))
    }

    fn get_webhook_event_type(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        let notif = serde_urlencoded::from_bytes::<OpennodeWebhookDetails>(request.body)
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;

        match notif.status {
            opennode::OpennodePaymentStatus::Paid => {
                Ok(api_models::webhooks::IncomingWebhookEvent::PaymentIntentSuccess)
            }
            opennode::OpennodePaymentStatus::Underpaid
            | opennode::OpennodePaymentStatus::Expired => {
                Ok(api_models::webhooks::IncomingWebhookEvent::PaymentActionRequired)
            }
            opennode::OpennodePaymentStatus::Processing => {
                Ok(api_models::webhooks::IncomingWebhookEvent::PaymentIntentProcessing)
            }
            _ => Ok(api_models::webhooks::IncomingWebhookEvent::EventNotSupported),
        }
    }

    fn get_webhook_resource_object(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let notif = serde_urlencoded::from_bytes::<OpennodeWebhookDetails>(request.body)
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;

        Ok(Box::new(notif.status))
    }
}

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

        let mut opennode_supported_payment_methods = SupportedPaymentMethods::new();

        opennode_supported_payment_methods.add(
            enums::PaymentMethod::Crypto,
            enums::PaymentMethodType::CryptoCurrency,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::NotSupported,
                supported_capture_methods,
                specific_features: None,
            },
        );

        opennode_supported_payment_methods
    });

static OPENNODE_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Opennode",
    description:
        "OpenNode offers accessible way for e-commerce businesses to process bitcoin payments.",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Beta,
};

static OPENNODE_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 1] = [enums::EventClass::Payments];

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

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

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


// Struct: AnalyticsRequest
// File: crates/api_models/src/analytics.rs
// Module: api_models
// Implementations: 1

pub struct AnalyticsRequest


// Struct: NuveiACSResponse
// File: crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NuveiACSResponse


// Implementation: impl ConnectorRedirectResponse for for Nomupay
// File: crates/hyperswitch_connectors/src/connectors/nomupay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl ConnectorRedirectResponse for for Nomupay


// File: crates/router/src/types/domain/event.rs
// Module: router
// Public structs: 1

use common_utils::{
    crypto::{Encryptable, OptionalEncryptableSecretString},
    encryption::Encryption,
    type_name,
    types::keymanager::{KeyManagerState, ToEncryptable},
};
use diesel_models::{
    enums::{EventClass, EventObjectType, EventType, WebhookDeliveryAttempt},
    events::{EventMetadata, EventUpdateInternal},
};
use error_stack::ResultExt;
use masking::{PeekInterface, Secret};
use rustc_hash::FxHashMap;

use crate::{
    errors::{CustomResult, ValidationError},
    types::domain::types,
};

#[derive(Clone, Debug, router_derive::ToEncryption)]
pub struct Event {
    /// A string that uniquely identifies the event.
    pub event_id: String,

    /// Represents the type of event for the webhook.
    pub event_type: EventType,

    /// Represents the class of event for the webhook.
    pub event_class: EventClass,

    /// Indicates whether the current webhook delivery was successful.
    pub is_webhook_notified: bool,

    /// Reference to the object for which the webhook was created.
    pub primary_object_id: String,

    /// Type of the object type for which the webhook was created.
    pub primary_object_type: EventObjectType,

    /// The timestamp when the webhook was created.
    pub created_at: time::PrimitiveDateTime,

    /// Merchant Account identifier to which the object is associated with.
    pub merchant_id: Option<common_utils::id_type::MerchantId>,

    /// Business Profile identifier to which the object is associated with.
    pub business_profile_id: Option<common_utils::id_type::ProfileId>,

    /// The timestamp when the primary object was created.
    pub primary_object_created_at: Option<time::PrimitiveDateTime>,

    /// This allows the event to be uniquely identified to prevent multiple processing.
    pub idempotent_event_id: Option<String>,

    /// Links to the initial attempt of the event.
    pub initial_attempt_id: Option<String>,

    /// This field contains the encrypted request data sent as part of the event.
    #[encrypt]
    pub request: Option<Encryptable<Secret<String>>>,

    /// This field contains the encrypted response data received as part of the event.
    #[encrypt]
    pub response: Option<Encryptable<Secret<String>>>,

    /// Represents the event delivery type.
    pub delivery_attempt: Option<WebhookDeliveryAttempt>,

    /// Holds any additional data related to the event.
    pub metadata: Option<EventMetadata>,

    /// Indicates whether the event was ultimately delivered.
    pub is_overall_delivery_successful: Option<bool>,
}

#[derive(Debug)]
pub enum EventUpdate {
    UpdateResponse {
        is_webhook_notified: bool,
        response: OptionalEncryptableSecretString,
    },
    OverallDeliveryStatusUpdate {
        is_overall_delivery_successful: bool,
    },
}

impl From<EventUpdate> for EventUpdateInternal {
    fn from(event_update: EventUpdate) -> Self {
        match event_update {
            EventUpdate::UpdateResponse {
                is_webhook_notified,
                response,
            } => Self {
                is_webhook_notified: Some(is_webhook_notified),
                response: response.map(Into::into),
                is_overall_delivery_successful: None,
            },
            EventUpdate::OverallDeliveryStatusUpdate {
                is_overall_delivery_successful,
            } => Self {
                is_webhook_notified: None,
                response: None,
                is_overall_delivery_successful: Some(is_overall_delivery_successful),
            },
        }
    }
}

#[async_trait::async_trait]
impl super::behaviour::Conversion for Event {
    type DstType = diesel_models::events::Event;
    type NewDstType = diesel_models::events::EventNew;

    async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
        Ok(diesel_models::events::Event {
            event_id: self.event_id,
            event_type: self.event_type,
            event_class: self.event_class,
            is_webhook_notified: self.is_webhook_notified,
            primary_object_id: self.primary_object_id,
            primary_object_type: self.primary_object_type,
            created_at: self.created_at,
            merchant_id: self.merchant_id,
            business_profile_id: self.business_profile_id,
            primary_object_created_at: self.primary_object_created_at,
            idempotent_event_id: self.idempotent_event_id,
            initial_attempt_id: self.initial_attempt_id,
            request: self.request.map(Into::into),
            response: self.response.map(Into::into),
            delivery_attempt: self.delivery_attempt,
            metadata: self.metadata,
            is_overall_delivery_successful: self.is_overall_delivery_successful,
        })
    }

    async fn convert_back(
        state: &KeyManagerState,
        item: Self::DstType,
        key: &Secret<Vec<u8>>,
        key_manager_identifier: common_utils::types::keymanager::Identifier,
    ) -> CustomResult<Self, ValidationError>
    where
        Self: Sized,
    {
        let decrypted = types::crypto_operation(
            state,
            type_name!(Self::DstType),
            types::CryptoOperation::BatchDecrypt(EncryptedEvent::to_encryptable(EncryptedEvent {
                request: item.request.clone(),
                response: item.response.clone(),
            })),
            key_manager_identifier,
            key.peek(),
        )
        .await
        .and_then(|val| val.try_into_batchoperation())
        .change_context(ValidationError::InvalidValue {
            message: "Failed while decrypting event data".to_string(),
        })?;
        let encryptable_event = EncryptedEvent::from_encryptable(decrypted).change_context(
            ValidationError::InvalidValue {
                message: "Failed while decrypting event data".to_string(),
            },
        )?;
        Ok(Self {
            event_id: item.event_id,
            event_type: item.event_type,
            event_class: item.event_class,
            is_webhook_notified: item.is_webhook_notified,
            primary_object_id: item.primary_object_id,
            primary_object_type: item.primary_object_type,
            created_at: item.created_at,
            merchant_id: item.merchant_id,
            business_profile_id: item.business_profile_id,
            primary_object_created_at: item.primary_object_created_at,
            idempotent_event_id: item.idempotent_event_id,
            initial_attempt_id: item.initial_attempt_id,
            request: encryptable_event.request,
            response: encryptable_event.response,
            delivery_attempt: item.delivery_attempt,
            metadata: item.metadata,
            is_overall_delivery_successful: item.is_overall_delivery_successful,
        })
    }

    async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
        Ok(diesel_models::events::EventNew {
            event_id: self.event_id,
            event_type: self.event_type,
            event_class: self.event_class,
            is_webhook_notified: self.is_webhook_notified,
            primary_object_id: self.primary_object_id,
            primary_object_type: self.primary_object_type,
            created_at: self.created_at,
            merchant_id: self.merchant_id,
            business_profile_id: self.business_profile_id,
            primary_object_created_at: self.primary_object_created_at,
            idempotent_event_id: self.idempotent_event_id,
            initial_attempt_id: self.initial_attempt_id,
            request: self.request.map(Into::into),
            response: self.response.map(Into::into),
            delivery_attempt: self.delivery_attempt,
            metadata: self.metadata,
            is_overall_delivery_successful: self.is_overall_delivery_successful,
        })
    }
}


// Implementation: impl api::RefundExecute for for Redsys
// File: crates/hyperswitch_connectors/src/connectors/redsys.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundExecute for for Redsys


// Module Structure
// File: crates/hyperswitch_connectors/src/connectors/checkbook.rs
// Module: hyperswitch_connectors

// Public submodules:
pub mod transformers;


// Implementation: impl api::MandateSetup for for Thunes
// File: crates/hyperswitch_connectors/src/connectors/thunes.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::MandateSetup for for Thunes


// Trait: SchedulerSessionState
// File: crates/scheduler/src/scheduler.rs
// Module: scheduler

pub trait SchedulerSessionState: Send + Sync + Clone


// File: crates/common_utils/src/types/keymanager.rs
// Module: common_utils
// Public functions: 3
// Public structs: 18

#![allow(missing_docs)]

use core::fmt;

use base64::Engine;
use masking::{ExposeInterface, PeekInterface, Secret, Strategy, StrongSecret};
#[cfg(feature = "encryption_service")]
use router_env::logger;
#[cfg(feature = "km_forward_x_request_id")]
use router_env::tracing_actix_web::RequestId;
use rustc_hash::FxHashMap;
use serde::{
    de::{self, Unexpected, Visitor},
    ser, Deserialize, Deserializer, Serialize,
};

use crate::{
    consts::BASE64_ENGINE,
    crypto::Encryptable,
    encryption::Encryption,
    errors::{self, CustomResult},
    id_type,
    transformers::{ForeignFrom, ForeignTryFrom},
};

macro_rules! impl_get_tenant_for_request {
    ($ty:ident) => {
        impl GetKeymanagerTenant for $ty {
            fn get_tenant_id(&self, state: &KeyManagerState) -> id_type::TenantId {
                match self.identifier {
                    Identifier::User(_) | Identifier::UserAuth(_) => state.global_tenant_id.clone(),
                    Identifier::Merchant(_) => state.tenant_id.clone(),
                }
            }
        }
    };
}

#[derive(Debug, Clone)]
pub struct KeyManagerState {
    pub tenant_id: id_type::TenantId,
    pub global_tenant_id: id_type::TenantId,
    pub enabled: bool,
    pub url: String,
    pub client_idle_timeout: Option<u64>,
    #[cfg(feature = "km_forward_x_request_id")]
    pub request_id: Option<RequestId>,
    #[cfg(feature = "keymanager_mtls")]
    pub ca: Secret<String>,
    #[cfg(feature = "keymanager_mtls")]
    pub cert: Secret<String>,
    pub infra_values: Option<serde_json::Value>,
}

impl KeyManagerState {
    pub fn add_confirm_value_in_infra_values(
        &self,
        is_confirm_operation: bool,
    ) -> Option<serde_json::Value> {
        self.infra_values.clone().map(|mut infra_values| {
            if is_confirm_operation {
                infra_values.as_object_mut().map(|obj| {
                    obj.insert(
                        "is_confirm_operation".to_string(),
                        serde_json::Value::Bool(true),
                    )
                });
            }
            infra_values
        })
    }
}

pub trait GetKeymanagerTenant {
    fn get_tenant_id(&self, state: &KeyManagerState) -> id_type::TenantId;
}

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
#[serde(tag = "data_identifier", content = "key_identifier")]
pub enum Identifier {
    User(String),
    Merchant(id_type::MerchantId),
    UserAuth(String),
}

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct EncryptionCreateRequest {
    #[serde(flatten)]
    pub identifier: Identifier,
}

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct EncryptionTransferRequest {
    #[serde(flatten)]
    pub identifier: Identifier,
    pub key: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct DataKeyCreateResponse {
    #[serde(flatten)]
    pub identifier: Identifier,
    pub key_version: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct BatchEncryptDataRequest {
    #[serde(flatten)]
    pub identifier: Identifier,
    pub data: DecryptedDataGroup,
}

impl_get_tenant_for_request!(EncryptionCreateRequest);
impl_get_tenant_for_request!(EncryptionTransferRequest);
impl_get_tenant_for_request!(BatchEncryptDataRequest);

impl<S> From<(Secret<Vec<u8>, S>, Identifier)> for EncryptDataRequest
where
    S: Strategy<Vec<u8>>,
{
    fn from((secret, identifier): (Secret<Vec<u8>, S>, Identifier)) -> Self {
        Self {
            identifier,
            data: DecryptedData(StrongSecret::new(secret.expose())),
        }
    }
}

impl<S> From<(FxHashMap<String, Secret<Vec<u8>, S>>, Identifier)> for BatchEncryptDataRequest
where
    S: Strategy<Vec<u8>>,
{
    fn from((map, identifier): (FxHashMap<String, Secret<Vec<u8>, S>>, Identifier)) -> Self {
        let group = map
            .into_iter()
            .map(|(key, value)| (key, DecryptedData(StrongSecret::new(value.expose()))))
            .collect();
        Self {
            identifier,
            data: DecryptedDataGroup(group),
        }
    }
}

impl<S> From<(Secret<String, S>, Identifier)> for EncryptDataRequest
where
    S: Strategy<String>,
{
    fn from((secret, identifier): (Secret<String, S>, Identifier)) -> Self {
        Self {
            data: DecryptedData(StrongSecret::new(secret.expose().as_bytes().to_vec())),
            identifier,
        }
    }
}

impl<S> From<(Secret<serde_json::Value, S>, Identifier)> for EncryptDataRequest
where
    S: Strategy<serde_json::Value>,
{
    fn from((secret, identifier): (Secret<serde_json::Value, S>, Identifier)) -> Self {
        Self {
            data: DecryptedData(StrongSecret::new(
                secret.expose().to_string().as_bytes().to_vec(),
            )),
            identifier,
        }
    }
}

impl<S> From<(FxHashMap<String, Secret<serde_json::Value, S>>, Identifier)>
    for BatchEncryptDataRequest
where
    S: Strategy<serde_json::Value>,
{
    fn from(
        (map, identifier): (FxHashMap<String, Secret<serde_json::Value, S>>, Identifier),
    ) -> Self {
        let group = map
            .into_iter()
            .map(|(key, value)| {
                (
                    key,
                    DecryptedData(StrongSecret::new(
                        value.expose().to_string().as_bytes().to_vec(),
                    )),
                )
            })
            .collect();
        Self {
            data: DecryptedDataGroup(group),
            identifier,
        }
    }
}

impl<S> From<(FxHashMap<String, Secret<String, S>>, Identifier)> for BatchEncryptDataRequest
where
    S: Strategy<String>,
{
    fn from((map, identifier): (FxHashMap<String, Secret<String, S>>, Identifier)) -> Self {
        let group = map
            .into_iter()
            .map(|(key, value)| {
                (
                    key,
                    DecryptedData(StrongSecret::new(value.expose().as_bytes().to_vec())),
                )
            })
            .collect();
        Self {
            data: DecryptedDataGroup(group),
            identifier,
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncryptDataRequest {
    #[serde(flatten)]
    pub identifier: Identifier,
    pub data: DecryptedData,
}

#[derive(Debug, Serialize, serde::Deserialize)]
pub struct DecryptedDataGroup(pub FxHashMap<String, DecryptedData>);

#[derive(Debug, Serialize, Deserialize)]
pub struct BatchEncryptDataResponse {
    pub data: EncryptedDataGroup,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct EncryptDataResponse {
    pub data: EncryptedData,
}

#[derive(Debug, Serialize, serde::Deserialize)]
pub struct EncryptedDataGroup(pub FxHashMap<String, EncryptedData>);
#[derive(Debug)]
pub struct TransientBatchDecryptDataRequest {
    pub identifier: Identifier,
    pub data: FxHashMap<String, StrongSecret<Vec<u8>>>,
}

#[derive(Debug)]
pub struct TransientDecryptDataRequest {
    pub identifier: Identifier,
    pub data: StrongSecret<Vec<u8>>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct BatchDecryptDataRequest {
    #[serde(flatten)]
    pub identifier: Identifier,
    pub data: FxHashMap<String, StrongSecret<String>>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct DecryptDataRequest {
    #[serde(flatten)]
    pub identifier: Identifier,
    pub data: StrongSecret<String>,
}

impl_get_tenant_for_request!(EncryptDataRequest);
impl_get_tenant_for_request!(TransientBatchDecryptDataRequest);
impl_get_tenant_for_request!(TransientDecryptDataRequest);
impl_get_tenant_for_request!(BatchDecryptDataRequest);
impl_get_tenant_for_request!(DecryptDataRequest);

impl<T, S> ForeignFrom<(FxHashMap<String, Secret<T, S>>, BatchEncryptDataResponse)>
    for FxHashMap<String, Encryptable<Secret<T, S>>>
where
    T: Clone,
    S: Strategy<T> + Send,
{
    fn foreign_from(
        (mut masked_data, response): (FxHashMap<String, Secret<T, S>>, BatchEncryptDataResponse),
    ) -> Self {
        response
            .data
            .0
            .into_iter()
            .flat_map(|(k, v)| {
                masked_data.remove(&k).map(|inner| {
                    (
                        k,
                        Encryptable::new(inner.clone(), v.data.peek().clone().into()),
                    )
                })
            })
            .collect()
    }
}

impl<T, S> ForeignFrom<(Secret<T, S>, EncryptDataResponse)> for Encryptable<Secret<T, S>>
where
    T: Clone,
    S: Strategy<T> + Send,
{
    fn foreign_from((masked_data, response): (Secret<T, S>, EncryptDataResponse)) -> Self {
        Self::new(masked_data, response.data.data.peek().clone().into())
    }
}

pub trait DecryptedDataConversion<T: Clone, S: Strategy<T> + Send>: Sized {
    fn convert(
        value: &DecryptedData,
        encryption: Encryption,
    ) -> CustomResult<Self, errors::CryptoError>;
}

impl<S: Strategy<String> + Send> DecryptedDataConversion<String, S>
    for Encryptable<Secret<String, S>>
{
    fn convert(
        value: &DecryptedData,
        encryption: Encryption,
    ) -> CustomResult<Self, errors::CryptoError> {
        let string = String::from_utf8(value.clone().inner().peek().clone()).map_err(|_err| {
            #[cfg(feature = "encryption_service")]
            logger::error!("Decryption error {:?}", _err);
            errors::CryptoError::DecodingFailed
        })?;
        Ok(Self::new(Secret::new(string), encryption.into_inner()))
    }
}

impl<S: Strategy<serde_json::Value> + Send> DecryptedDataConversion<serde_json::Value, S>
    for Encryptable<Secret<serde_json::Value, S>>
{
    fn convert(
        value: &DecryptedData,
        encryption: Encryption,
    ) -> CustomResult<Self, errors::CryptoError> {
        let val = serde_json::from_slice(value.clone().inner().peek()).map_err(|_err| {
            #[cfg(feature = "encryption_service")]
            logger::error!("Decryption error {:?}", _err);
            errors::CryptoError::DecodingFailed
        })?;
        Ok(Self::new(Secret::new(val), encryption.clone().into_inner()))
    }
}

impl<S: Strategy<Vec<u8>> + Send> DecryptedDataConversion<Vec<u8>, S>
    for Encryptable<Secret<Vec<u8>, S>>
{
    fn convert(
        value: &DecryptedData,
        encryption: Encryption,
    ) -> CustomResult<Self, errors::CryptoError> {
        Ok(Self::new(
            Secret::new(value.clone().inner().peek().clone()),
            encryption.clone().into_inner(),
        ))
    }
}

impl<T, S> ForeignTryFrom<(Encryption, DecryptDataResponse)> for Encryptable<Secret<T, S>>
where
    T: Clone,
    S: Strategy<T> + Send,
    Self: DecryptedDataConversion<T, S>,
{
    type Error = error_stack::Report<errors::CryptoError>;
    fn foreign_try_from(
        (encrypted_data, response): (Encryption, DecryptDataResponse),
    ) -> Result<Self, Self::Error> {
        Self::convert(&response.data, encrypted_data)
    }
}

impl<T, S> ForeignTryFrom<(FxHashMap<String, Encryption>, BatchDecryptDataResponse)>
    for FxHashMap<String, Encryptable<Secret<T, S>>>
where
    T: Clone,
    S: Strategy<T> + Send,
    Encryptable<Secret<T, S>>: DecryptedDataConversion<T, S>,
{
    type Error = error_stack::Report<errors::CryptoError>;
    fn foreign_try_from(
        (mut encrypted_data, response): (FxHashMap<String, Encryption>, BatchDecryptDataResponse),
    ) -> Result<Self, Self::Error> {
        response
            .data
            .0
            .into_iter()
            .map(|(k, v)| match encrypted_data.remove(&k) {
                Some(encrypted) => Ok((k.clone(), Encryptable::convert(&v, encrypted.clone())?)),
                None => Err(errors::CryptoError::DecodingFailed)?,
            })
            .collect()
    }
}

impl From<(Encryption, Identifier)> for TransientDecryptDataRequest {
    fn from((encryption, identifier): (Encryption, Identifier)) -> Self {
        Self {
            data: StrongSecret::new(encryption.clone().into_inner().expose()),
            identifier,
        }
    }
}

impl From<(FxHashMap<String, Encryption>, Identifier)> for TransientBatchDecryptDataRequest {
    fn from((map, identifier): (FxHashMap<String, Encryption>, Identifier)) -> Self {
        let data = map
            .into_iter()
            .map(|(k, v)| (k, StrongSecret::new(v.clone().into_inner().expose())))
            .collect();
        Self { data, identifier }
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct BatchDecryptDataResponse {
    pub data: DecryptedDataGroup,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct DecryptDataResponse {
    pub data: DecryptedData,
}

#[derive(Clone, Debug)]
pub struct DecryptedData(StrongSecret<Vec<u8>>);

impl Serialize for DecryptedData {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let data = BASE64_ENGINE.encode(self.0.peek());
        serializer.serialize_str(&data)
    }
}

impl<'de> Deserialize<'de> for DecryptedData {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct DecryptedDataVisitor;

        impl Visitor<'_> for DecryptedDataVisitor {
            type Value = DecryptedData;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                formatter.write_str("string of the format {version}:{base64_encoded_data}'")
            }

            fn visit_str<E>(self, value: &str) -> Result<DecryptedData, E>
            where
                E: de::Error,
            {
                let dec_data = BASE64_ENGINE.decode(value).map_err(|err| {
                    let err = err.to_string();
                    E::invalid_value(Unexpected::Str(value), &err.as_str())
                })?;

                Ok(DecryptedData(dec_data.into()))
            }
        }

        deserializer.deserialize_str(DecryptedDataVisitor)
    }
}

impl DecryptedData {
    pub fn from_data(data: StrongSecret<Vec<u8>>) -> Self {
        Self(data)
    }

    pub fn inner(self) -> StrongSecret<Vec<u8>> {
        self.0
    }
}

#[derive(Debug)]
pub struct EncryptedData {
    pub data: StrongSecret<Vec<u8>>,
}

impl Serialize for EncryptedData {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let data = String::from_utf8(self.data.peek().clone()).map_err(ser::Error::custom)?;
        serializer.serialize_str(data.as_str())
    }
}

impl<'de> Deserialize<'de> for EncryptedData {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct EncryptedDataVisitor;

        impl Visitor<'_> for EncryptedDataVisitor {
            type Value = EncryptedData;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                formatter.write_str("string of the format {version}:{base64_encoded_data}'")
            }

            fn visit_str<E>(self, value: &str) -> Result<EncryptedData, E>
            where
                E: de::Error,
            {
                Ok(EncryptedData {
                    data: StrongSecret::new(value.as_bytes().to_vec()),
                })
            }
        }

        deserializer.deserialize_str(EncryptedDataVisitor)
    }
}

/// A trait which converts the struct to Hashmap required for encryption and back to struct
pub trait ToEncryptable<T, S: Clone, E>: Sized {
    /// Serializes the type to a hashmap
    fn to_encryptable(self) -> FxHashMap<String, E>;
    /// Deserializes the hashmap back to the type
    fn from_encryptable(
        hashmap: FxHashMap<String, Encryptable<S>>,
    ) -> CustomResult<T, errors::ParsingError>;
}


// Struct: DashboardMetadataNew
// File: crates/diesel_models/src/user/dashboard_metadata.rs
// Module: diesel_models
// Implementations: 0

pub struct DashboardMetadataNew


// Struct: RedsysOperationRequest
// File: crates/hyperswitch_connectors/src/connectors/redsys/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 1
// Traits: SignatureCalculationData

pub struct RedsysOperationRequest


// Struct: StoreConfig
// File: crates/drainer/src/services.rs
// Module: drainer
// Implementations: 0

pub struct StoreConfig


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

impl Redsys


// Struct: TesouroCard
// File: crates/hyperswitch_connectors/src/connectors/tesouro/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TesouroCard


// Implementation: impl PaymentMetricAccumulator for for DebitRoutingAccumulator
// File: crates/analytics/src/payments/accumulator.rs
// Module: analytics
// Methods: 2 total (0 public)

impl PaymentMetricAccumulator for for DebitRoutingAccumulator


// Module Structure
// File: crates/router/src/routes/app.rs
// Module: router

// Public exports:
pub use crate::analytics::opensearch::OpenSearchClient;
pub use crate::{
    configs::settings,
    db::{
        AccountsStorageInterface, CommonStorageInterface, GlobalStorageInterface, StorageImpl,
        StorageInterface,
    },
    events::EventsHandler,
    services::{get_cache_store, get_store},
};


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

pub struct RSyncResponseData


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

pub fn new() -> &'static Self


// Struct: RefundReasonDistributionRow
// File: crates/analytics/src/refunds/accumulator.rs
// Module: analytics
// Implementations: 0

pub struct RefundReasonDistributionRow


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

pub struct RoutingEventsRequest


// Implementation: impl NetworkTokenizationBuilder
// File: crates/router/src/core/payment_methods/tokenize/card_executor.rs
// Module: router
// Methods: 1 total (1 public)

impl NetworkTokenizationBuilder


// Struct: OrganizationUpdateInternal
// File: crates/diesel_models/src/organization.rs
// Module: diesel_models
// Implementations: 0

pub struct OrganizationUpdateInternal


// Function: delete_sample_data_for_user
// File: crates/router/src/core/user/sample_data.rs
// Module: router

pub fn delete_sample_data_for_user(
    state: SessionState,
    user_from_token: UserFromToken,
    _req: SampleDataRequest,
    _req_state: ReqState,
) -> SampleDataApiResponse<()>


// Module Structure
// File: crates/hyperswitch_connectors/src/connectors/noon.rs
// Module: hyperswitch_connectors

// Public submodules:
pub mod transformers;


// Struct: PaymentMethodListResponseForSession
// File: crates/api_models/src/payment_methods.rs
// Module: api_models
// Implementations: 0

pub struct PaymentMethodListResponseForSession


// Struct: TryGetEnumMeta
// File: crates/router_derive/src/macros/try_get_enum.rs
// Module: router_derive
// Implementations: 2
// Traits: Parse, ToTokens

pub struct TryGetEnumMeta


// Struct: PayloadCardsRequestData
// File: crates/hyperswitch_connectors/src/connectors/payload/requests.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PayloadCardsRequestData


// Struct: RecurlyRecordBackResponse
// File: crates/hyperswitch_connectors/src/connectors/recurly/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RecurlyRecordBackResponse


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

impl api::MandateSetup for for Celero


// Trait: SupportedPaymentMethodsExt
// File: crates/hyperswitch_domain_models/src/router_response_types.rs
// Module: hyperswitch_domain_models

pub trait SupportedPaymentMethodsExt


// Implementation: impl api::RefundExecute for for Paystack
// File: crates/hyperswitch_connectors/src/connectors/paystack.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundExecute for for Paystack


// File: crates/diesel_models/src/ephemeral_key.rs
// Module: diesel_models
// Public functions: 1
// Public structs: 4

#[cfg(feature = "v2")]
use masking::{PeekInterface, Secret};

#[cfg(feature = "v2")]
pub struct ClientSecretTypeNew {
    pub id: common_utils::id_type::ClientSecretId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub secret: Secret<String>,
    pub resource_id: common_utils::types::authentication::ResourceId,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct ClientSecretType {
    pub id: common_utils::id_type::ClientSecretId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub resource_id: common_utils::types::authentication::ResourceId,
    pub created_at: time::PrimitiveDateTime,
    pub expires: time::PrimitiveDateTime,
    pub secret: Secret<String>,
}

#[cfg(feature = "v2")]
impl ClientSecretType {
    pub fn generate_secret_key(&self) -> String {
        format!("cs_{}", self.secret.peek())
    }
}

pub struct EphemeralKeyNew {
    pub id: String,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub customer_id: common_utils::id_type::CustomerId,
    pub secret: String,
}

#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct EphemeralKey {
    pub id: String,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub customer_id: common_utils::id_type::CustomerId,
    pub created_at: i64,
    pub expires: i64,
    pub secret: String,
}

impl common_utils::events::ApiEventMetric for EphemeralKey {
    fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
        Some(common_utils::events::ApiEventsType::Miscellaneous)
    }
}


// Function: payments_finish_redirection
// File: crates/router/src/routes/payments.rs
// Module: router

pub fn payments_finish_redirection(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    json_payload: Option<web::Form<serde_json::Value>>,
    path: web::Path<(
        common_utils::id_type::GlobalPaymentId,
        String,
        common_utils::id_type::ProfileId,
    )


// Module Structure
// File: crates/router/src/core/verification.rs
// Module: router

// Public submodules:
pub mod utils;


// Function: create_payout_link
// File: crates/router/src/core/payouts.rs
// Module: router

pub fn create_payout_link(
    state: &SessionState,
    business_profile: &domain::Profile,
    customer_id: &id_type::CustomerId,
    merchant_id: &id_type::MerchantId,
    req: &payouts::PayoutCreateRequest,
    payout_id: &id_type::PayoutId,
    locale: &str,
) -> RouterResult<PayoutLink>


// Implementation: impl Node
// File: crates/hyperswitch_constraint_graph/src/types.rs
// Module: hyperswitch_constraint_graph
// Methods: 1 total (0 public)

impl Node


// Function: create_new_routing_algorithm
// File: crates/router/src/core/routing.rs
// Module: router

pub fn create_new_routing_algorithm(
        request: &routing_types::RoutingConfigRequest,
        merchant_id: &common_utils::id_type::MerchantId,
        profile_id: common_utils::id_type::ProfileId,
        transaction_type: enums::TransactionType,
    ) -> Self


// Struct: Avs
// File: crates/hyperswitch_connectors/src/connectors/wellsfargo/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct Avs


// Implementation: impl CustomerNew
// File: crates/diesel_models/src/customers.rs
// Module: diesel_models
// Methods: 1 total (1 public)

impl CustomerNew


// Function: delete_user_theme
// File: crates/router/src/core/user/theme.rs
// Module: router

pub fn delete_user_theme(
    state: SessionState,
    user_from_token: UserFromToken,
    theme_id: String,
) -> UserResponse<()>


// Implementation: impl api::Refund for for Thunes
// File: crates/hyperswitch_connectors/src/connectors/thunes.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Refund for for Thunes


// Struct: NordeaOriginalRequest
// File: crates/hyperswitch_connectors/src/connectors/nordea/responses.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NordeaOriginalRequest


// Struct: SmithyModel
// File: crates/smithy-core/src/types.rs
// Module: smithy-core
// Implementations: 0

pub struct SmithyModel


// Implementation: impl ConnectorCommon for for Gigadat
// File: crates/hyperswitch_connectors/src/connectors/gigadat.rs
// Module: hyperswitch_connectors
// Methods: 6 total (0 public)

impl ConnectorCommon for for Gigadat


// Function: create_connector_request
// File: crates/connector_configs/src/transformer.rs
// Module: connector_configs

pub fn create_connector_request(
        request: Self,
        api_response: ConnectorApiIntegrationPayload,
    ) -> ConnectorApiIntegrationPayload


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

impl Responder


// Implementation: impl api::PaymentSync for for Sift
// File: crates/hyperswitch_connectors/src/connectors/sift.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentSync for for Sift


            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods: supported_capture_methods.clone(),
            specific_features: None,
        },
    );

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

    paysafe_supported_payment_methods.add(
        enums::PaymentMethod::BankRedirect,
        enums::PaymentMethodType::Interac,
        PaymentMethodDetails {
            mandates: enums::FeatureStatus::NotSupported,
            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods: supported_capture_methods2.clone(),
            specific_features: None,
        },
    );

    paysafe_supported_payment_methods.add(
        enums::PaymentMethod::GiftCard,
        enums::PaymentMethodType::PaySafeCard,
        PaymentMethodDetails {
            mandates: enums::FeatureStatus::NotSupported,
            refunds: enums::FeatureStatus::Supported,
            supported_capture_methods: supported_capture_methods2.clone(),
            specific_features: None,
        },
    );

    paysafe_supported_payment_methods
});

static PAYSAFE_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Paysafe",
    description: "Paysafe gives ambitious businesses a launchpad with safe, secure online payment solutions, and gives consumers the ability to turn their transactions into meaningful experiences.",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Sandbox,
};

static PAYSAFE_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 0] = [];

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

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

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


// Function: business_country_to_dir_value
// File: crates/kgraph_utils/src/transformers.rs
// Module: kgraph_utils

pub fn business_country_to_dir_value(c: api_enums::Country) -> dir::DirValue


// Struct: PhoneDetails
// File: crates/hyperswitch_domain_models/src/address.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct PhoneDetails


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

pub struct BluesnapWebhookBody


// Struct: NotAvailableFlows
// File: crates/kgraph_utils/src/types.rs
// Module: kgraph_utils
// Implementations: 0

pub struct NotAvailableFlows


// Implementation: impl ConnectorValidation for for Fiuu
// File: crates/hyperswitch_connectors/src/connectors/fiuu.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl ConnectorValidation for for Fiuu


// Struct: CheckoutOptions
// File: crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CheckoutOptions


// Struct: WeChatPayInfo
// File: crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct WeChatPayInfo


// Struct: ParentGroupInfo
// File: crates/api_models/src/user_role/role.rs
// Module: api_models
// Implementations: 0

pub struct ParentGroupInfo


// Function: rust_locker_migration
// File: crates/router/src/core/locker_migration.rs
// Module: router

pub fn rust_locker_migration(
    _state: SessionState,
    _merchant_id: &id_type::MerchantId,
) -> CustomResult<services::ApplicationResponse<MigrateCardResponse>, errors::ApiErrorResponse>


// Struct: RefundResponse
// File: crates/hyperswitch_connectors/src/connectors/payu/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RefundResponse


// Struct: MandateToken
// File: crates/hyperswitch_connectors/src/connectors/worldpay/response.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct MandateToken


// Struct: AuthorizedotnetWebhookPayload
// File: crates/hyperswitch_connectors/src/connectors/authorizedotnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AuthorizedotnetWebhookPayload


// Implementation: impl api::Refund for for Datatrans
// File: crates/hyperswitch_connectors/src/connectors/datatrans.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Refund for for Datatrans


// File: crates/router/src/services/email/types.rs
// Module: router
// Public functions: 9
// Public structs: 11

use api_models::user::dashboard_metadata::ProdIntent;
use common_enums::{EntityType, MerchantProductType};
use common_utils::{errors::CustomResult, pii, types::user::EmailThemeConfig};
use error_stack::ResultExt;
use external_services::email::{EmailContents, EmailData, EmailError};
use masking::{ExposeInterface, Secret};

use crate::{configs, consts, routes::SessionState};
#[cfg(feature = "olap")]
use crate::{
    core::errors::{UserErrors, UserResult},
    services::jwt,
    types::domain,
};

pub enum EmailBody {
    Verify {
        link: String,
        entity_name: String,
        entity_logo_url: String,
        primary_color: String,
        background_color: String,
        foreground_color: String,
    },
    Reset {
        link: String,
        user_name: String,
        entity_name: String,
        entity_logo_url: String,
        primary_color: String,
        background_color: String,
        foreground_color: String,
    },
    MagicLink {
        link: String,
        user_name: String,
        entity_name: String,
        entity_logo_url: String,
        primary_color: String,
        background_color: String,
        foreground_color: String,
    },
    InviteUser {
        link: String,
        user_name: String,
        entity_name: String,
        entity_logo_url: String,
        primary_color: String,
        background_color: String,
        foreground_color: String,
    },
    AcceptInviteFromEmail {
        link: String,
        user_name: String,
        entity_name: String,
        entity_logo_url: String,
        primary_color: String,
        background_color: String,
        foreground_color: String,
    },
    BizEmailProd {
        user_name: String,
        poc_email: String,
        legal_business_name: String,
        business_location: String,
        business_website: String,
        product_type: MerchantProductType,
    },
    ReconActivation {
        user_name: String,
    },
    ProFeatureRequest {
        feature_name: String,
        merchant_id: common_utils::id_type::MerchantId,
        user_name: String,
        user_email: String,
    },
    ApiKeyExpiryReminder {
        expires_in: u8,
        api_key_name: String,
        prefix: String,
    },
    WelcomeToCommunity,
}

pub mod html {
    use crate::services::email::types::EmailBody;

    pub fn get_html_body(email_body: EmailBody) -> String {
        match email_body {
            EmailBody::Verify {
                link,
                entity_name,
                entity_logo_url,
                primary_color,
                background_color,
                foreground_color,
            } => {
                format!(
                    include_str!("assets/verify.html"),
                    link = link,
                    entity_name = entity_name,
                    entity_logo_url = entity_logo_url,
                    primary_color = primary_color,
                    background_color = background_color,
                    foreground_color = foreground_color
                )
            }
            EmailBody::Reset {
                link,
                user_name,
                entity_name,
                entity_logo_url,
                primary_color,
                background_color,
                foreground_color,
            } => {
                format!(
                    include_str!("assets/reset.html"),
                    link = link,
                    username = user_name,
                    entity_name = entity_name,
                    entity_logo_url = entity_logo_url,
                    primary_color = primary_color,
                    background_color = background_color,
                    foreground_color = foreground_color
                )
            }
            EmailBody::MagicLink {
                link,
                user_name,
                entity_name,
                entity_logo_url,
                primary_color,
                background_color,
                foreground_color,
            } => {
                format!(
                    include_str!("assets/magic_link.html"),
                    username = user_name,
                    link = link,
                    entity_name = entity_name,
                    entity_logo_url = entity_logo_url,
                    primary_color = primary_color,
                    background_color = background_color,
                    foreground_color = foreground_color
                )
            }

            EmailBody::InviteUser {
                link,
                user_name,
                entity_name,
                entity_logo_url,
                primary_color,
                background_color,
                foreground_color,
            } => {
                format!(
                    include_str!("assets/invite.html"),
                    username = user_name,
                    link = link,
                    entity_name = entity_name,
                    entity_logo_url = entity_logo_url,
                    primary_color = primary_color,
                    background_color = background_color,
                    foreground_color = foreground_color
                )
            }
            // TODO: Change the linked html for accept invite from email
            EmailBody::AcceptInviteFromEmail {
                link,
                user_name,
                entity_name,
                entity_logo_url,
                primary_color,
                background_color,
                foreground_color,
            } => {
                format!(
                    include_str!("assets/invite.html"),
                    username = user_name,
                    link = link,
                    entity_name = entity_name,
                    entity_logo_url = entity_logo_url,
                    primary_color = primary_color,
                    background_color = background_color,
                    foreground_color = foreground_color
                )
            }
            EmailBody::ReconActivation { user_name } => {
                format!(
                    include_str!("assets/recon_activation.html"),
                    username = user_name,
                )
            }
            EmailBody::BizEmailProd {
                user_name,
                poc_email,
                legal_business_name,
                business_location,
                business_website,
                product_type,
            } => {
                format!(
                    include_str!("assets/bizemailprod.html"),
                    poc_email = poc_email,
                    legal_business_name = legal_business_name,
                    business_location = business_location,
                    business_website = business_website,
                    username = user_name,
                    product_type = product_type
                )
            }
            EmailBody::ProFeatureRequest {
                feature_name,
                merchant_id,
                user_name,
                user_email,
            } => format!(
                "Dear Hyperswitch Support Team,

Dashboard Pro Feature Request,
Feature name  : {feature_name}
Merchant ID   : {}
Merchant Name : {user_name}
Email         : {user_email}

(note: This is an auto generated email. Use merchant email for any further communications)",
                merchant_id.get_string_repr()
            ),
            EmailBody::ApiKeyExpiryReminder {
                expires_in,
                api_key_name,
                prefix,
            } => format!(
                include_str!("assets/api_key_expiry_reminder.html"),
                api_key_name = api_key_name,
                prefix = prefix,
                expires_in = expires_in,
            ),
            EmailBody::WelcomeToCommunity => {
                include_str!("assets/welcome_to_community.html").to_string()
            }
        }
    }
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct EmailToken {
    email: String,
    flow: domain::Origin,
    exp: u64,
    entity: Option<Entity>,
}

#[derive(serde::Serialize, serde::Deserialize, Clone)]
pub struct Entity {
    pub entity_id: String,
    pub entity_type: EntityType,
}

impl Entity {
    pub fn get_entity_type(&self) -> EntityType {
        self.entity_type
    }

    pub fn get_entity_id(&self) -> &str {
        &self.entity_id
    }
}

impl EmailToken {
    pub async fn new_token(
        email: domain::UserEmail,
        entity: Option<Entity>,
        flow: domain::Origin,
        settings: &configs::Settings,
    ) -> UserResult<String> {
        let expiration_duration = std::time::Duration::from_secs(consts::EMAIL_TOKEN_TIME_IN_SECS);
        let exp = jwt::generate_exp(expiration_duration)?.as_secs();
        let token_payload = Self {
            email: email.get_secret().expose(),
            flow,
            exp,
            entity,
        };
        jwt::generate_jwt(&token_payload, settings).await
    }

    pub fn get_email(&self) -> UserResult<domain::UserEmail> {
        pii::Email::try_from(self.email.clone())
            .change_context(UserErrors::InternalServerError)
            .and_then(domain::UserEmail::from_pii_email)
    }

    pub fn get_entity(&self) -> Option<&Entity> {
        self.entity.as_ref()
    }

    pub fn get_flow(&self) -> domain::Origin {
        self.flow.clone()
    }
}

pub fn get_link_with_token(
    base_url: impl std::fmt::Display,
    token: impl std::fmt::Display,
    action: impl std::fmt::Display,
    auth_id: &Option<impl std::fmt::Display>,
    theme_id: &Option<impl std::fmt::Display>,
) -> String {
    let mut email_url = format!("{base_url}/user/{action}?token={token}");
    if let Some(auth_id) = auth_id {
        email_url = format!("{email_url}&auth_id={auth_id}");
    }
    if let Some(theme_id) = theme_id {
        email_url = format!("{email_url}&theme_id={theme_id}");
    }

    email_url
}
pub struct VerifyEmail {
    pub recipient_email: domain::UserEmail,
    pub settings: std::sync::Arc<configs::Settings>,
    pub auth_id: Option<String>,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
}

/// Currently only HTML is supported
#[async_trait::async_trait]
impl EmailData for VerifyEmail {
    async fn get_email_data(&self, base_url: &str) -> CustomResult<EmailContents, EmailError> {
        let token = EmailToken::new_token(
            self.recipient_email.clone(),
            None,
            domain::Origin::VerifyEmail,
            &self.settings,
        )
        .await
        .change_context(EmailError::TokenGenerationFailure)?;

        let verify_email_link = get_link_with_token(
            base_url,
            token,
            "verify_email",
            &self.auth_id,
            &self.theme_id,
        );

        let body = html::get_html_body(EmailBody::Verify {
            link: verify_email_link,
            entity_name: self.theme_config.entity_name.clone(),
            entity_logo_url: self.theme_config.entity_logo_url.clone(),
            primary_color: self.theme_config.primary_color.clone(),
            background_color: self.theme_config.background_color.clone(),
            foreground_color: self.theme_config.foreground_color.clone(),
        });

        Ok(EmailContents {
            subject: format!(
                "Welcome to the {} community!",
                self.theme_config.entity_name
            ),
            body: external_services::email::IntermediateString::new(body),
            recipient: self.recipient_email.clone().into_inner(),
        })
    }
}

pub struct ResetPassword {
    pub recipient_email: domain::UserEmail,
    pub user_name: domain::UserName,
    pub settings: std::sync::Arc<configs::Settings>,
    pub auth_id: Option<String>,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
}

#[async_trait::async_trait]
impl EmailData for ResetPassword {
    async fn get_email_data(&self, base_url: &str) -> CustomResult<EmailContents, EmailError> {
        let token = EmailToken::new_token(
            self.recipient_email.clone(),
            None,
            domain::Origin::ResetPassword,
            &self.settings,
        )
        .await
        .change_context(EmailError::TokenGenerationFailure)?;

        let reset_password_link = get_link_with_token(
            base_url,
            token,
            "set_password",
            &self.auth_id,
            &self.theme_id,
        );

        let body = html::get_html_body(EmailBody::Reset {
            link: reset_password_link,
            user_name: self.user_name.clone().get_secret().expose(),
            entity_name: self.theme_config.entity_name.clone(),
            entity_logo_url: self.theme_config.entity_logo_url.clone(),
            primary_color: self.theme_config.primary_color.clone(),
            background_color: self.theme_config.background_color.clone(),
            foreground_color: self.theme_config.foreground_color.clone(),
        });

        Ok(EmailContents {
            subject: format!(
                "Get back to {} - Reset Your Password Now!",
                self.theme_config.entity_name
            ),
            body: external_services::email::IntermediateString::new(body),
            recipient: self.recipient_email.clone().into_inner(),
        })
    }
}

pub struct MagicLink {
    pub recipient_email: domain::UserEmail,
    pub user_name: domain::UserName,
    pub settings: std::sync::Arc<configs::Settings>,
    pub auth_id: Option<String>,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
}

#[async_trait::async_trait]
impl EmailData for MagicLink {
    async fn get_email_data(&self, base_url: &str) -> CustomResult<EmailContents, EmailError> {
        let token = EmailToken::new_token(
            self.recipient_email.clone(),
            None,
            domain::Origin::MagicLink,
            &self.settings,
        )
        .await
        .change_context(EmailError::TokenGenerationFailure)?;

        let magic_link_login = get_link_with_token(
            base_url,
            token,
            "verify_email",
            &self.auth_id,
            &self.theme_id,
        );

        let body = html::get_html_body(EmailBody::MagicLink {
            link: magic_link_login,
            user_name: self.user_name.clone().get_secret().expose(),
            entity_name: self.theme_config.entity_name.clone(),
            entity_logo_url: self.theme_config.entity_logo_url.clone(),
            primary_color: self.theme_config.primary_color.clone(),
            background_color: self.theme_config.background_color.clone(),
            foreground_color: self.theme_config.foreground_color.clone(),
        });

        Ok(EmailContents {
            subject: format!(
                "Unlock {}: Use Your Magic Link to Sign In",
                self.theme_config.entity_name
            ),
            body: external_services::email::IntermediateString::new(body),
            recipient: self.recipient_email.clone().into_inner(),
        })
    }
}

pub struct InviteUser {
    pub recipient_email: domain::UserEmail,
    pub user_name: domain::UserName,
    pub settings: std::sync::Arc<configs::Settings>,
    pub entity: Entity,
    pub auth_id: Option<String>,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
}

#[async_trait::async_trait]
impl EmailData for InviteUser {
    async fn get_email_data(&self, base_url: &str) -> CustomResult<EmailContents, EmailError> {
        let token = EmailToken::new_token(
            self.recipient_email.clone(),
            Some(self.entity.clone()),
            domain::Origin::AcceptInvitationFromEmail,
            &self.settings,
        )
        .await
        .change_context(EmailError::TokenGenerationFailure)?;

        let invite_user_link = get_link_with_token(
            base_url,
            token,
            "accept_invite_from_email",
            &self.auth_id,
            &self.theme_id,
        );
        let body = html::get_html_body(EmailBody::AcceptInviteFromEmail {
            link: invite_user_link,
            user_name: self.user_name.clone().get_secret().expose(),
            entity_name: self.theme_config.entity_name.clone(),
            entity_logo_url: self.theme_config.entity_logo_url.clone(),
            primary_color: self.theme_config.primary_color.clone(),
            background_color: self.theme_config.background_color.clone(),
            foreground_color: self.theme_config.foreground_color.clone(),
        });

        Ok(EmailContents {
            subject: format!(
                "You have been invited to join {} Community!",
                self.theme_config.entity_name
            ),
            body: external_services::email::IntermediateString::new(body),
            recipient: self.recipient_email.clone().into_inner(),
        })
    }
}

pub struct ReconActivation {
    pub recipient_email: domain::UserEmail,
    pub user_name: domain::UserName,
    pub subject: &'static str,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
}

#[async_trait::async_trait]
impl EmailData for ReconActivation {
    async fn get_email_data(&self, _base_url: &str) -> CustomResult<EmailContents, EmailError> {
        let body = html::get_html_body(EmailBody::ReconActivation {
            user_name: self.user_name.clone().get_secret().expose(),
        });

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

pub struct BizEmailProd {
    pub recipient_email: domain::UserEmail,
    pub user_name: Secret<String>,
    pub poc_email: Secret<String>,
    pub legal_business_name: String,
    pub business_location: String,
    pub business_website: String,
    pub settings: std::sync::Arc<configs::Settings>,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
    pub product_type: MerchantProductType,
}

impl BizEmailProd {
    pub fn new(
        state: &SessionState,
        data: ProdIntent,
        theme_id: Option<String>,
        theme_config: EmailThemeConfig,
    ) -> UserResult<Self> {
        Ok(Self {
            recipient_email: domain::UserEmail::from_pii_email(
                state.conf.email.prod_intent_recipient_email.clone(),
            )?,
            settings: state.conf.clone(),
            user_name: data.poc_name.unwrap_or_default(),
            poc_email: data.poc_email.unwrap_or_default(),
            legal_business_name: data.legal_business_name.unwrap_or_default(),
            business_location: data
                .business_location
                .unwrap_or(common_enums::CountryAlpha2::AD)
                .to_string(),
            business_website: data.business_website.unwrap_or_default(),
            theme_id,
            theme_config,
            product_type: data.product_type,
        })
    }
}

#[async_trait::async_trait]
impl EmailData for BizEmailProd {
    async fn get_email_data(&self, _base_url: &str) -> CustomResult<EmailContents, EmailError> {
        let body = html::get_html_body(EmailBody::BizEmailProd {
            user_name: self.user_name.clone().expose(),
            poc_email: self.poc_email.clone().expose(),
            legal_business_name: self.legal_business_name.clone(),
            business_location: self.business_location.clone(),
            business_website: self.business_website.clone(),
            product_type: self.product_type,
        });

        Ok(EmailContents {
            subject: "New Prod Intent".to_string(),
            body: external_services::email::IntermediateString::new(body),
            recipient: self.recipient_email.clone().into_inner(),
        })
    }
}

pub struct ProFeatureRequest {
    pub recipient_email: domain::UserEmail,
    pub feature_name: String,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub user_name: domain::UserName,
    pub user_email: domain::UserEmail,
    pub subject: String,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
}

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

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

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

pub struct ApiKeyExpiryReminder {
    pub recipient_email: domain::UserEmail,
    pub subject: &'static str,
    pub expires_in: u8,
    pub api_key_name: String,
    pub prefix: String,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
}

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

        let body = html::get_html_body(EmailBody::ApiKeyExpiryReminder {
            expires_in: self.expires_in,
            api_key_name: self.api_key_name.clone(),
            prefix: self.prefix.clone(),
        });

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

pub struct WelcomeToCommunity {
    pub recipient_email: domain::UserEmail,
}

#[async_trait::async_trait]
impl EmailData for WelcomeToCommunity {
    async fn get_email_data(&self, _base_url: &str) -> CustomResult<EmailContents, EmailError> {
        let body = html::get_html_body(EmailBody::WelcomeToCommunity);

        Ok(EmailContents {
            subject: "Thank you for signing up on Hyperswitch Dashboard!".to_string(),
            body: external_services::email::IntermediateString::new(body),
            recipient: self.recipient_email.clone().into_inner(),
        })
    }
}


// Struct: PaymentMethodCreate
// File: crates/api_models/src/payment_methods.rs
// Module: api_models
// Implementations: 2

pub struct PaymentMethodCreate


// File: crates/analytics/src/outgoing_webhook_event/core.rs
// Module: analytics
// Public functions: 1

use api_models::analytics::outgoing_webhook_event::OutgoingWebhookLogsRequest;
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;

use super::events::{get_outgoing_webhook_event, OutgoingWebhookLogsResult};
use crate::{errors::AnalyticsResult, types::FiltersError, AnalyticsProvider};

pub async fn outgoing_webhook_events_core(
    pool: &AnalyticsProvider,
    req: OutgoingWebhookLogsRequest,
    merchant_id: &common_utils::id_type::MerchantId,
) -> AnalyticsResult<Vec<OutgoingWebhookLogsResult>> {
    let data = match pool {
        AnalyticsProvider::Sqlx(_) => Err(FiltersError::NotImplemented(
            "Outgoing Webhook Events Logs not implemented for SQLX",
        ))
        .attach_printable("SQL Analytics is not implemented for Outgoing Webhook Events"),
        AnalyticsProvider::Clickhouse(ckh_pool)
        | AnalyticsProvider::CombinedSqlx(_, ckh_pool)
        | AnalyticsProvider::CombinedCkh(_, ckh_pool) => {
            get_outgoing_webhook_event(merchant_id, req, ckh_pool).await
        }
    }
    .switch()?;
    Ok(data)
}


// Implementation: impl PaymentIntentMetricAccumulator for for SmartRetriedAmountAccumulator
// File: crates/analytics/src/payment_intents/accumulator.rs
// Module: analytics
// Methods: 2 total (0 public)

impl PaymentIntentMetricAccumulator for for SmartRetriedAmountAccumulator


// Function: create
// File: crates/external_services/src/email/ses.rs
// Module: external_services

// Documentation: Constructs a new AwsSes client

pub fn create(
        conf: &EmailSettings,
        ses_config: &SESConfig,
        proxy_url: Option<impl AsRef<str>>,
    ) -> Self


// Implementation: impl ConnectorSpecifications for for Nmi
// File: crates/hyperswitch_connectors/src/connectors/nmi.rs
// Module: hyperswitch_connectors
// Methods: 3 total (0 public)

impl ConnectorSpecifications for for Nmi


// Function: get_psync_revenue_recovery_id
// File: crates/common_utils/src/id_type/global_id/payment.rs
// Module: common_utils

// Documentation: Generate the id for Revenue Recovery Psync PT workflow

pub fn get_psync_revenue_recovery_id(
        &self,
        task: &str,
        runner: enums::ProcessTrackerRunner,
    ) -> String


// Struct: CardSource
// File: crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CardSource