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

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

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

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

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

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

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

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

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

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

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

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

impl ConnectorValidation for Rapyd {}

impl api::ConnectorAccessToken for Rapyd {}

impl api::PaymentToken for Rapyd {}

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

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

impl api::PaymentAuthorize for Rapyd {}

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

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

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

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

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

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

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

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

impl api::Payment for Rapyd {}

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

impl api::PaymentVoid for Rapyd {}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

impl api::PaymentSession for Rapyd {}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        Ok(to_sign.into_bytes())
    }

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

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

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

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

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

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

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

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

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

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

    let mut rapyd_supported_payment_methods = SupportedPaymentMethods::new();

    rapyd_supported_payment_methods.add(


        Err(errors::ConnectorError::NotSupported {
            message: format!("{} for {}", $capture_method, $payment_method_type),
            connector: $connector,
        }
        .into())
    };
}
#[macro_export]
macro_rules! get_formatted_date_time {
    ($date_format:tt) => {{
        let format = time::macros::format_description!($date_format);
        time::OffsetDateTime::now_utc()
            .format(&format)
            .change_context(ConnectorError::InvalidDateFormat)
    }};
}

#[macro_export]
macro_rules! unimplemented_payment_method {
    ($payment_method:expr, $connector:expr) => {
        hyperswitch_interfaces::errors::ConnectorError::NotImplemented(format!(
            "{} through {}",
            $payment_method, $connector
        ))
    };
    ($payment_method:expr, $flow:expr, $connector:expr) => {
        hyperswitch_interfaces::errors::ConnectorError::NotImplemented(format!(
            "{} {} through {}",
            $payment_method, $flow, $connector
        ))
    };
}

impl ForeignTryFrom<String> for UsStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state_abbreviation_check =
            StringExt::<Self>::parse_enum(value.to_uppercase().clone(), "UsStatesAbbreviation");

        match state_abbreviation_check {
            Ok(state_abbreviation) => Ok(state_abbreviation),
            Err(_) => {
                let binding = value.as_str().to_lowercase();
                let state = binding.as_str();
                match state {
                    "alabama" => Ok(Self::AL),
                    "alaska" => Ok(Self::AK),
                    "american samoa" => Ok(Self::AS),
                    "arizona" => Ok(Self::AZ),
                    "arkansas" => Ok(Self::AR),
                    "california" => Ok(Self::CA),
                    "colorado" => Ok(Self::CO),
                    "connecticut" => Ok(Self::CT),
                    "delaware" => Ok(Self::DE),
                    "district of columbia" | "columbia" => Ok(Self::DC),
                    "federated states of micronesia" | "micronesia" => Ok(Self::FM),
                    "florida" => Ok(Self::FL),
                    "georgia" => Ok(Self::GA),
                    "guam" => Ok(Self::GU),
                    "hawaii" => Ok(Self::HI),
                    "idaho" => Ok(Self::ID),
                    "illinois" => Ok(Self::IL),
                    "indiana" => Ok(Self::IN),
                    "iowa" => Ok(Self::IA),
                    "kansas" => Ok(Self::KS),
                    "kentucky" => Ok(Self::KY),
                    "louisiana" => Ok(Self::LA),
                    "maine" => Ok(Self::ME),
                    "marshall islands" => Ok(Self::MH),
                    "maryland" => Ok(Self::MD),
                    "massachusetts" => Ok(Self::MA),
                    "michigan" => Ok(Self::MI),
                    "minnesota" => Ok(Self::MN),
                    "mississippi" => Ok(Self::MS),
                    "missouri" => Ok(Self::MO),
                    "montana" => Ok(Self::MT),
                    "nebraska" => Ok(Self::NE),
                    "nevada" => Ok(Self::NV),
                    "new hampshire" => Ok(Self::NH),
                    "new jersey" => Ok(Self::NJ),
                    "new mexico" => Ok(Self::NM),
                    "new york" => Ok(Self::NY),
                    "north carolina" => Ok(Self::NC),
                    "north dakota" => Ok(Self::ND),
                    "northern mariana islands" => Ok(Self::MP),
                    "ohio" => Ok(Self::OH),
                    "oklahoma" => Ok(Self::OK),
                    "oregon" => Ok(Self::OR),
                    "palau" => Ok(Self::PW),
                    "pennsylvania" => Ok(Self::PA),
                    "puerto rico" => Ok(Self::PR),
                    "rhode island" => Ok(Self::RI),
                    "south carolina" => Ok(Self::SC),
                    "south dakota" => Ok(Self::SD),
                    "tennessee" => Ok(Self::TN),
                    "texas" => Ok(Self::TX),
                    "utah" => Ok(Self::UT),
                    "vermont" => Ok(Self::VT),
                    "virgin islands" => Ok(Self::VI),
                    "virginia" => Ok(Self::VA),
                    "washington" => Ok(Self::WA),
                    "west virginia" => Ok(Self::WV),
                    "wisconsin" => Ok(Self::WI),
                    "wyoming" => Ok(Self::WY),
                    _ => Err(errors::ConnectorError::InvalidDataFormat {
                        field_name: "address.state",
                    }
                    .into()),
                }
            }
        }
    }
}

impl ForeignTryFrom<String> for CanadaStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state_abbreviation_check =
            StringExt::<Self>::parse_enum(value.to_uppercase().clone(), "CanadaStatesAbbreviation");
        match state_abbreviation_check {
            Ok(state_abbreviation) => Ok(state_abbreviation),
            Err(_) => {
                let binding = value.as_str().to_lowercase();
                let state = binding.as_str();
                match state {
                    "alberta" => Ok(Self::AB),
                    "british columbia" => Ok(Self::BC),
                    "manitoba" => Ok(Self::MB),
                    "new brunswick" => Ok(Self::NB),
                    "newfoundland and labrador" | "newfoundland & labrador" => Ok(Self::NL),
                    "northwest territories" => Ok(Self::NT),
                    "nova scotia" => Ok(Self::NS),
                    "nunavut" => Ok(Self::NU),
                    "ontario" => Ok(Self::ON),
                    "prince edward island" => Ok(Self::PE),
                    "quebec" => Ok(Self::QC),
                    "saskatchewan" => Ok(Self::SK),
                    "yukon" => Ok(Self::YT),
                    _ => Err(errors::ConnectorError::InvalidDataFormat {
                        field_name: "address.state",
                    }
                    .into()),
                }
            }
        }
    }
}

impl ForeignTryFrom<String> for AustraliaStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state =
            parse_state_enum::<Self>(value, "AustraliaStatesAbbreviation", "address.state")?;
        match state.as_str() {
            "newsouthwales" => Ok(Self::NSW),
            "queensland" => Ok(Self::QLD),
            "southaustralia" => Ok(Self::SA),
            "westernaustralia" => Ok(Self::WA),
            "victoria" => Ok(Self::VIC),
            "northernterritory" => Ok(Self::NT),
            "australiancapitalterritory" => Ok(Self::ACT),
            "tasmania" => Ok(Self::TAS),
            _ => Err(errors::ConnectorError::InvalidDataFormat {
                field_name: "address.state",
            }
            .into()),
        }
    }
}

impl ForeignTryFrom<String> for PolandStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state_abbreviation_check =
            StringExt::<Self>::parse_enum(value.clone(), "PolandStatesAbbreviation");
        match state_abbreviation_check {
            Ok(state_abbreviation) => Ok(state_abbreviation),
            Err(_) => match value.as_str() {
                "Greater Poland" => Ok(Self::GreaterPoland),
                "Holy Cross" => Ok(Self::HolyCross),
                "Kuyavia-Pomerania" => Ok(Self::KuyaviaPomerania),
                "Lesser Poland" => Ok(Self::LesserPoland),
                "Lower Silesia" => Ok(Self::LowerSilesia),
                "Lublin" => Ok(Self::Lublin),
                "Lubusz" => Ok(Self::Lubusz),
                "Łódź" => Ok(Self::Łódź),
                "Mazovia" => Ok(Self::Mazovia),
                "Podlaskie" => Ok(Self::Podlaskie),
                "Pomerania" => Ok(Self::Pomerania),
                "Silesia" => Ok(Self::Silesia),
                "Subcarpathia" => Ok(Self::Subcarpathia),
                "Upper Silesia" => Ok(Self::UpperSilesia),
                "Warmia-Masuria" => Ok(Self::WarmiaMasuria),
                "West Pomerania" => Ok(Self::WestPomerania),
                _ => Err(errors::ConnectorError::InvalidDataFormat {
                    field_name: "address.state",
                }
                .into()),
            },
        }
    }
}

impl ForeignTryFrom<String> for FranceStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state_abbreviation_check =
            StringExt::<Self>::parse_enum(value.clone(), "FranceStatesAbbreviation");
        match state_abbreviation_check {
            Ok(state_abbreviation) => Ok(state_abbreviation),
            Err(_) => match value.as_str() {
                "Ain" => Ok(Self::Ain),
                "Aisne" => Ok(Self::Aisne),
                "Allier" => Ok(Self::Allier),
                "Alpes-de-Haute-Provence" => Ok(Self::AlpesDeHauteProvence),
                "Alpes-Maritimes" => Ok(Self::AlpesMaritimes),
                "Alsace" => Ok(Self::Alsace),
                "Ardèche" => Ok(Self::Ardeche),
                "Ardennes" => Ok(Self::Ardennes),
                "Ariège" => Ok(Self::Ariege),
                "Aube" => Ok(Self::Aube),
                "Aude" => Ok(Self::Aude),
                "Auvergne-Rhône-Alpes" => Ok(Self::AuvergneRhoneAlpes),
                "Aveyron" => Ok(Self::Aveyron),
                "Bas-Rhin" => Ok(Self::BasRhin),
                "Bouches-du-Rhône" => Ok(Self::BouchesDuRhone),
                "Bourgogne-Franche-Comté" => Ok(Self::BourgogneFrancheComte),
                "Bretagne" => Ok(Self::Bretagne),
                "Calvados" => Ok(Self::Calvados),
                "Cantal" => Ok(Self::Cantal),
                "Centre-Val de Loire" => Ok(Self::CentreValDeLoire),
                "Charente" => Ok(Self::Charente),
                "Charente-Maritime" => Ok(Self::CharenteMaritime),
                "Cher" => Ok(Self::Cher),
                "Clipperton" => Ok(Self::Clipperton),
                "Corrèze" => Ok(Self::Correze),
                "Corse" => Ok(Self::Corse),
                "Corse-du-Sud" => Ok(Self::CorseDuSud),
                "Côte-d'Or" => Ok(Self::CoteDor),
                "Côtes-d'Armor" => Ok(Self::CotesDarmor),
                "Creuse" => Ok(Self::Creuse),
                "Deux-Sèvres" => Ok(Self::DeuxSevres),
                "Dordogne" => Ok(Self::Dordogne),
                "Doubs" => Ok(Self::Doubs),
                "Drôme" => Ok(Self::Drome),
                "Essonne" => Ok(Self::Essonne),
                "Eure" => Ok(Self::Eure),
                "Eure-et-Loir" => Ok(Self::EureEtLoir),
                "Finistère" => Ok(Self::Finistere),
                "French Guiana" => Ok(Self::FrenchGuiana),
                "French Polynesia" => Ok(Self::FrenchPolynesia),
                "French Southern and Antarctic Lands" => Ok(Self::FrenchSouthernAndAntarcticLands),
                "Gard" => Ok(Self::Gard),
                "Gers" => Ok(Self::Gers),
                "Gironde" => Ok(Self::Gironde),
                "Grand-Est" => Ok(Self::GrandEst),
                "Guadeloupe" => Ok(Self::Guadeloupe),
                "Haut-Rhin" => Ok(Self::HautRhin),
                "Haute-Corse" => Ok(Self::HauteCorse),
                "Haute-Garonne" => Ok(Self::HauteGaronne),
                "Haute-Loire" => Ok(Self::HauteLoire),
                "Haute-Marne" => Ok(Self::HauteMarne),
                "Haute-Saône" => Ok(Self::HauteSaone),
                "Haute-Savoie" => Ok(Self::HauteSavoie),
                "Haute-Vienne" => Ok(Self::HauteVienne),
                "Hautes-Alpes" => Ok(Self::HautesAlpes),
                "Hautes-Pyrénées" => Ok(Self::HautesPyrenees),
                "Hauts-de-France" => Ok(Self::HautsDeFrance),
                "Hauts-de-Seine" => Ok(Self::HautsDeSeine),
                "Hérault" => Ok(Self::Herault),
                "Île-de-France" => Ok(Self::IleDeFrance),
                "Ille-et-Vilaine" => Ok(Self::IlleEtVilaine),
                "Indre" => Ok(Self::Indre),
                "Indre-et-Loire" => Ok(Self::IndreEtLoire),
                "Isère" => Ok(Self::Isere),
                "Jura" => Ok(Self::Jura),
                "La Réunion" => Ok(Self::LaReunion),
                "Landes" => Ok(Self::Landes),
                "Loir-et-Cher" => Ok(Self::LoirEtCher),
                "Loire" => Ok(Self::Loire),
                "Loire-Atlantique" => Ok(Self::LoireAtlantique),
                "Loiret" => Ok(Self::Loiret),
                "Lot" => Ok(Self::Lot),
                "Lot-et-Garonne" => Ok(Self::LotEtGaronne),
                "Lozère" => Ok(Self::Lozere),
                "Maine-et-Loire" => Ok(Self::MaineEtLoire),
                "Manche" => Ok(Self::Manche),
                "Marne" => Ok(Self::Marne),
                "Martinique" => Ok(Self::Martinique),
                "Mayenne" => Ok(Self::Mayenne),
                "Mayotte" => Ok(Self::Mayotte),
                "Métropole de Lyon" => Ok(Self::MetropoleDeLyon),
                "Meurthe-et-Moselle" => Ok(Self::MeurtheEtMoselle),
                "Meuse" => Ok(Self::Meuse),
                "Morbihan" => Ok(Self::Morbihan),
                "Moselle" => Ok(Self::Moselle),
                "Nièvre" => Ok(Self::Nievre),
                "Nord" => Ok(Self::Nord),
                "Normandie" => Ok(Self::Normandie),
                "Nouvelle-Aquitaine" => Ok(Self::NouvelleAquitaine),
                "Occitanie" => Ok(Self::Occitanie),
                "Oise" => Ok(Self::Oise),
                "Orne" => Ok(Self::Orne),
                "Paris" => Ok(Self::Paris),
                "Pas-de-Calais" => Ok(Self::PasDeCalais),
                "Pays-de-la-Loire" => Ok(Self::PaysDeLaLoire),
                "Provence-Alpes-Côte-d'Azur" => Ok(Self::ProvenceAlpesCoteDazur),
                "Puy-de-Dôme" => Ok(Self::PuyDeDome),
                "Pyrénées-Atlantiques" => Ok(Self::PyreneesAtlantiques),
                "Pyrénées-Orientales" => Ok(Self::PyreneesOrientales),
                "Rhône" => Ok(Self::Rhone),
                "Saint Pierre and Miquelon" => Ok(Self::SaintPierreAndMiquelon),
                "Saint-Barthélemy" => Ok(Self::SaintBarthelemy),
                "Saint-Martin" => Ok(Self::SaintMartin),
                "Saône-et-Loire" => Ok(Self::SaoneEtLoire),
                "Sarthe" => Ok(Self::Sarthe),
                "Savoie" => Ok(Self::Savoie),
                "Seine-et-Marne" => Ok(Self::SeineEtMarne),
                "Seine-Maritime" => Ok(Self::SeineMaritime),
                "Seine-Saint-Denis" => Ok(Self::SeineSaintDenis),
                "Somme" => Ok(Self::Somme),
                "Tarn" => Ok(Self::Tarn),
                "Tarn-et-Garonne" => Ok(Self::TarnEtGaronne),
                "Territoire de Belfort" => Ok(Self::TerritoireDeBelfort),
                "Val-d'Oise" => Ok(Self::ValDoise),
                "Val-de-Marne" => Ok(Self::ValDeMarne),
                "Var" => Ok(Self::Var),
                "Vaucluse" => Ok(Self::Vaucluse),
                "Vendée" => Ok(Self::Vendee),
                "Vienne" => Ok(Self::Vienne),
                "Vosges" => Ok(Self::Vosges),
                "Wallis and Futuna" => Ok(Self::WallisAndFutuna),
                "Yonne" => Ok(Self::Yonne),
                "Yvelines" => Ok(Self::Yvelines),
                _ => Err(errors::ConnectorError::InvalidDataFormat {
                    field_name: "address.state",
                }
                .into()),
            },
        }
    }
}

impl ForeignTryFrom<String> for GermanyStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state_abbreviation_check =
            StringExt::<Self>::parse_enum(value.clone(), "GermanyStatesAbbreviation");
        match state_abbreviation_check {
            Ok(state_abbreviation) => Ok(state_abbreviation),
            Err(_) => match value.as_str() {
                "Baden-Württemberg" => Ok(Self::BW),
                "Bavaria" => Ok(Self::BY),
                "Berlin" => Ok(Self::BE),
                "Brandenburg" => Ok(Self::BB),
                "Bremen" => Ok(Self::HB),
                "Hamburg" => Ok(Self::HH),
                "Hessen" => Ok(Self::HE),
                "Lower Saxony" => Ok(Self::NI),
                "Mecklenburg-Vorpommern" => Ok(Self::MV),
                "North Rhine-Westphalia" => Ok(Self::NW),
                "Rhineland-Palatinate" => Ok(Self::RP),
                "Saarland" => Ok(Self::SL),
                "Saxony" => Ok(Self::SN),
                "Saxony-Anhalt" => Ok(Self::ST),
                "Schleswig-Holstein" => Ok(Self::SH),
                "Thuringia" => Ok(Self::TH),
                _ => Err(errors::ConnectorError::InvalidDataFormat {
                    field_name: "address.state",
                }
                .into()),
            },
        }
    }
}

impl ForeignTryFrom<String> for SpainStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state_abbreviation_check =
            StringExt::<Self>::parse_enum(value.clone(), "SpainStatesAbbreviation");
        match state_abbreviation_check {
            Ok(state_abbreviation) => Ok(state_abbreviation),
            Err(_) => match value.as_str() {
                "A Coruña Province" => Ok(Self::ACorunaProvince),
                "Albacete Province" => Ok(Self::AlbaceteProvince),
                "Alicante Province" => Ok(Self::AlicanteProvince),
                "Almería Province" => Ok(Self::AlmeriaProvince),
                "Andalusia" => Ok(Self::Andalusia),
                "Araba / Álava" => Ok(Self::ArabaAlava),
                "Aragon" => Ok(Self::Aragon),
                "Badajoz Province" => Ok(Self::BadajozProvince),
                "Balearic Islands" => Ok(Self::BalearicIslands),
                "Barcelona Province" => Ok(Self::BarcelonaProvince),
                "Basque Country" => Ok(Self::BasqueCountry),
                "Biscay" => Ok(Self::Biscay),
                "Burgos Province" => Ok(Self::BurgosProvince),
                "Canary Islands" => Ok(Self::CanaryIslands),
                "Cantabria" => Ok(Self::Cantabria),
                "Castellón Province" => Ok(Self::CastellonProvince),
                "Castile and León" => Ok(Self::CastileAndLeon),
                "Castilla-La Mancha" => Ok(Self::CastileLaMancha),
                "Catalonia" => Ok(Self::Catalonia),
                "Ceuta" => Ok(Self::Ceuta),
                "Ciudad Real Province" => Ok(Self::CiudadRealProvince),
                "Community of Madrid" => Ok(Self::CommunityOfMadrid),
                "Cuenca Province" => Ok(Self::CuencaProvince),
                "Cáceres Province" => Ok(Self::CaceresProvince),
                "Cádiz Province" => Ok(Self::CadizProvince),
                "Córdoba Province" => Ok(Self::CordobaProvince),
                "Extremadura" => Ok(Self::Extremadura),
                "Galicia" => Ok(Self::Galicia),
                "Gipuzkoa" => Ok(Self::Gipuzkoa),
                "Girona Province" => Ok(Self::GironaProvince),
                "Granada Province" => Ok(Self::GranadaProvince),
                "Guadalajara Province" => Ok(Self::GuadalajaraProvince),
                "Huelva Province" => Ok(Self::HuelvaProvince),
                "Huesca Province" => Ok(Self::HuescaProvince),
                "Jaén Province" => Ok(Self::JaenProvince),
                "La Rioja" => Ok(Self::LaRioja),
                "Las Palmas Province" => Ok(Self::LasPalmasProvince),
                "León Province" => Ok(Self::LeonProvince),
                "Lleida Province" => Ok(Self::LleidaProvince),
                "Lugo Province" => Ok(Self::LugoProvince),
                "Madrid Province" => Ok(Self::MadridProvince),
                "Melilla" => Ok(Self::Melilla),
                "Murcia Province" => Ok(Self::MurciaProvince),
                "Málaga Province" => Ok(Self::MalagaProvince),
                "Navarre" => Ok(Self::Navarre),
                "Ourense Province" => Ok(Self::OurenseProvince),
                "Palencia Province" => Ok(Self::PalenciaProvince),
                "Pontevedra Province" => Ok(Self::PontevedraProvince),
                "Province of Asturias" => Ok(Self::ProvinceOfAsturias),
                "Province of Ávila" => Ok(Self::ProvinceOfAvila),
                "Region of Murcia" => Ok(Self::RegionOfMurcia),
                "Salamanca Province" => Ok(Self::SalamancaProvince),
                "Santa Cruz de Tenerife Province" => Ok(Self::SantaCruzDeTenerifeProvince),
                "Segovia Province" => Ok(Self::SegoviaProvince),
                "Seville Province" => Ok(Self::SevilleProvince),
                "Soria Province" => Ok(Self::SoriaProvince),
                "Tarragona Province" => Ok(Self::TarragonaProvince),
                "Teruel Province" => Ok(Self::TeruelProvince),
                "Toledo Province" => Ok(Self::ToledoProvince),
                "Valencia Province" => Ok(Self::ValenciaProvince),
                "Valencian Community" => Ok(Self::ValencianCommunity),
                "Valladolid Province" => Ok(Self::ValladolidProvince),
                "Zamora Province" => Ok(Self::ZamoraProvince),
                "Zaragoza Province" => Ok(Self::ZaragozaProvince),
                _ => Err(errors::ConnectorError::InvalidDataFormat {
                    field_name: "address.state",
                }
                .into()),
            },
        }
    }
}

impl ForeignTryFrom<String> for ItalyStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state_abbreviation_check =
            StringExt::<Self>::parse_enum(value.clone(), "ItalyStatesAbbreviation");
        match state_abbreviation_check {
            Ok(state_abbreviation) => Ok(state_abbreviation),
            Err(_) => match value.as_str() {
                "Abruzzo" => Ok(Self::Abruzzo),
                "Aosta Valley" => Ok(Self::AostaValley),
                "Apulia" => Ok(Self::Apulia),
                "Basilicata" => Ok(Self::Basilicata),
                "Benevento Province" => Ok(Self::BeneventoProvince),
                "Calabria" => Ok(Self::Calabria),
                "Campania" => Ok(Self::Campania),
                "Emilia-Romagna" => Ok(Self::EmiliaRomagna),
                "Friuli–Venezia Giulia" => Ok(Self::FriuliVeneziaGiulia),
                "Lazio" => Ok(Self::Lazio),
                "Liguria" => Ok(Self::Liguria),
                "Lombardy" => Ok(Self::Lombardy),
                "Marche" => Ok(Self::Marche),
                "Molise" => Ok(Self::Molise),
                "Piedmont" => Ok(Self::Piedmont),
                "Sardinia" => Ok(Self::Sardinia),
                "Sicily" => Ok(Self::Sicily),
                "Trentino-South Tyrol" => Ok(Self::TrentinoSouthTyrol),
                "Tuscany" => Ok(Self::Tuscany),
                "Umbria" => Ok(Self::Umbria),
                "Veneto" => Ok(Self::Veneto),
                "Libero consorzio comunale di Agrigento" => Ok(Self::Agrigento),
                "Libero consorzio comunale di Caltanissetta" => Ok(Self::Caltanissetta),
                "Libero consorzio comunale di Enna" => Ok(Self::Enna),
                "Libero consorzio comunale di Ragusa" => Ok(Self::Ragusa),
                "Libero consorzio comunale di Siracusa" => Ok(Self::Siracusa),
                "Libero consorzio comunale di Trapani" => Ok(Self::Trapani),
                "Metropolitan City of Bari" => Ok(Self::Bari),
                "Metropolitan City of Bologna" => Ok(Self::Bologna),
                "Metropolitan City of Cagliari" => Ok(Self::Cagliari),
                "Metropolitan City of Catania" => Ok(Self::Catania),
                "Metropolitan City of Florence" => Ok(Self::Florence),
                "Metropolitan City of Genoa" => Ok(Self::Genoa),
                "Metropolitan City of Messina" => Ok(Self::Messina),
                "Metropolitan City of Milan" => Ok(Self::Milan),
                "Metropolitan City of Naples" => Ok(Self::Naples),
                "Metropolitan City of Palermo" => Ok(Self::Palermo),
                "Metropolitan City of Reggio Calabria" => Ok(Self::ReggioCalabria),
                "Metropolitan City of Rome" => Ok(Self::Rome),
                "Metropolitan City of Turin" => Ok(Self::Turin),
                "Metropolitan City of Venice" => Ok(Self::Venice),
                _ => Err(errors::ConnectorError::InvalidDataFormat {
                    field_name: "address.state",
                }
                .into()),
            },
        }
    }
}

impl ForeignTryFrom<String> for JapanStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state = parse_state_enum::<Self>(value, "JapanStatesAbbreviation", "address.state")?;
        match state.as_str() {
            "aichi" => Ok(Self::Aichi),
            "akita" => Ok(Self::Akita),
            "aomori" => Ok(Self::Aomori),
            "chiba" => Ok(Self::Chiba),
            "ehime" => Ok(Self::Ehime),
            "fukui" => Ok(Self::Fukui),
            "fukuoka" => Ok(Self::Fukuoka),
            "fukushima" | "hukusima" => Ok(Self::Fukushima),
            "gifu" => Ok(Self::Gifu),
            "gunma" => Ok(Self::Gunma),
            "hiroshima" => Ok(Self::Hiroshima),
            "hokkaido" => Ok(Self::Hokkaido),
            "hyogo" => Ok(Self::Hyogo),
            "ibaraki" => Ok(Self::Ibaraki),
            "ishikawa" => Ok(Self::Ishikawa),
            "iwate" => Ok(Self::Iwate),
            "kagawa" => Ok(Self::Kagawa),
            "kagoshima" => Ok(Self::Kagoshima),
            "kanagawa" => Ok(Self::Kanagawa),
            "kochi" => Ok(Self::Kochi),
            "kumamoto" => Ok(Self::Kumamoto),
            "kyoto" => Ok(Self::Kyoto),
            "mie" => Ok(Self::Mie),
            "miyagi" => Ok(Self::Miyagi),
            "miyazaki" => Ok(Self::Miyazaki),
            "nagano" => Ok(Self::Nagano),
            "nagasaki" => Ok(Self::Nagasaki),
            "nara" => Ok(Self::Nara),
            "niigata" => Ok(Self::Niigata),
            "oita" => Ok(Self::Oita),
            "okayama" => Ok(Self::Okayama),
            "okinawa" => Ok(Self::Okinawa),
            "osaka" => Ok(Self::Osaka),
            "saga" => Ok(Self::Saga),
            "saitama" => Ok(Self::Saitama),
            "shiga" => Ok(Self::Shiga),
            "shimane" => Ok(Self::Shimane),
            "shizuoka" => Ok(Self::Shizuoka),
            "tochigi" => Ok(Self::Tochigi),
            "tokushima" | "tokusima" => Ok(Self::Tokusima),
            "tokyo" => Ok(Self::Tokyo),
            "tottori" => Ok(Self::Tottori),
            "toyama" => Ok(Self::Toyama),
            "wakayama" => Ok(Self::Wakayama),
            "yamagata" => Ok(Self::Yamagata),
            "yamaguchi" => Ok(Self::Yamaguchi),
            "yamanashi" => Ok(Self::Yamanashi),
            _ => Err(errors::ConnectorError::InvalidDataFormat {
                field_name: "address.state",
            }
            .into()),
        }
    }
}

impl ForeignTryFrom<String> for ThailandStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state = parse_state_enum::<Self>(value, "ThailandStatesAbbreviation", "address.state")?;
        match state.as_str() {
            "amnatcharoen" => Ok(Self::AmnatCharoen),
            "angthong" => Ok(Self::AngThong),
            "bangkok" => Ok(Self::Bangkok),
            "buengkan" => Ok(Self::BuengKan),
            "buriram" => Ok(Self::BuriRam),
            "chachoengsao" => Ok(Self::Chachoengsao),
            "chainat" => Ok(Self::ChaiNat),
            "chaiyaphum" => Ok(Self::Chaiyaphum),
            "chanthaburi" => Ok(Self::Chanthaburi),
            "chiangmai" => Ok(Self::ChiangMai),
            "chiangrai" => Ok(Self::ChiangRai),
            "chonburi" => Ok(Self::ChonBuri),
            "chumphon" => Ok(Self::Chumphon),
            "kalasin" => Ok(Self::Kalasin),
            "kamphaengphet" => Ok(Self::KamphaengPhet),
            "kanchanaburi" => Ok(Self::Kanchanaburi),
            "khonkaen" => Ok(Self::KhonKaen),
            "krabi" => Ok(Self::Krabi),
            "lampang" => Ok(Self::Lampang),
            "lamphun" => Ok(Self::Lamphun),
            "loei" => Ok(Self::Loei),
            "lopburi" => Ok(Self::LopBuri),
            "maehongson" => Ok(Self::MaeHongSon),
            "mahasarakham" => Ok(Self::MahaSarakham),
            "mukdahan" => Ok(Self::Mukdahan),
            "nakhonnayok" => Ok(Self::NakhonNayok),
            "nakhonpathom" => Ok(Self::NakhonPathom),
            "nakhonphanom" => Ok(Self::NakhonPhanom),
            "nakhonratchasima" => Ok(Self::NakhonRatchasima),
            "nakhonsawan" => Ok(Self::NakhonSawan),
            "nakhonsithammarat" => Ok(Self::NakhonSiThammarat),
            "nan" => Ok(Self::Nan),
            "narathiwat" => Ok(Self::Narathiwat),
            "nongbualamphu" => Ok(Self::NongBuaLamPhu),
            "nongkhai" => Ok(Self::NongKhai),
            "nonthaburi" => Ok(Self::Nonthaburi),
            "pathumthani" => Ok(Self::PathumThani),
            "pattani" => Ok(Self::Pattani),
            "phangnga" => Ok(Self::Phangnga),
            "phatthalung" => Ok(Self::Phatthalung),
            "phayao" => Ok(Self::Phayao),
            "phatthaya" => Ok(Self::Phatthaya),
            "phetchabun" => Ok(Self::Phetchabun),
            "phetchaburi" => Ok(Self::Phetchaburi),
            "phichit" => Ok(Self::Phichit),
            "phitsanulok" => Ok(Self::Phitsanulok),
            "phrae" => Ok(Self::Phrae),
            "phuket" => Ok(Self::Phuket),
            "prachinburi" => Ok(Self::PrachinBuri),
            "phranakhonsiayutthaya" => Ok(Self::PhraNakhonSiAyutthaya),
            "prachuapkhirikhan" => Ok(Self::PrachuapKhiriKhan),
            "ranong" => Ok(Self::Ranong),
            "ratchaburi" => Ok(Self::Ratchaburi),
            "rayong" => Ok(Self::Rayong),
            "roiet" => Ok(Self::RoiEt),
            "sakaeo" => Ok(Self::SaKaeo),
            "sakonnakhon" => Ok(Self::SakonNakhon),
            "samutprakan" => Ok(Self::SamutPrakan),
            "samutsakhon" => Ok(Self::SamutSakhon),
            "samutsongkhram" => Ok(Self::SamutSongkhram),
            "saraburi" => Ok(Self::Saraburi),
            "satun" => Ok(Self::Satun),
            "sisaket" => Ok(Self::SiSaKet),
            "singburi" => Ok(Self::SingBuri),
            "songkhla" => Ok(Self::Songkhla),
            "sukhothai" => Ok(Self::Sukhothai),


// Struct: DeutschebankThreeDSInitializeRequestCreditCardExpiry
// File: crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DeutschebankThreeDSInitializeRequestCreditCardExpiry


// Function: generate_digest
// File: crates/hyperswitch_connectors/src/connectors/bankofamerica.rs
// Module: hyperswitch_connectors

pub fn generate_digest(&self, payload: &[u8]) -> String


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

impl ConnectorCommon for for Multisafepay


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

impl ConnectorCommon for for Recurly


// Function: get_or_create_custom_recovery_intent
// File: crates/router/src/core/webhooks/recovery_incoming.rs
// Module: router

pub fn get_or_create_custom_recovery_intent(
        data: api_models::payments::RecoveryPaymentsCreate,
        state: &SessionState,
        req_state: &ReqState,
        merchant_context: &domain::MerchantContext,
        profile: &domain::Profile,
    ) -> CustomResult<revenue_recovery::RecoveryPaymentIntent, errors::RevenueRecoveryError>


// Implementation: impl GetPaymentMethodType for for PayLaterData
// File: crates/hyperswitch_domain_models/src/payment_method_data.rs
// Module: hyperswitch_domain_models
// Methods: 1 total (0 public)

impl GetPaymentMethodType for for PayLaterData


// Struct: WebhookDeliveryRetryRequestInternal
// File: crates/api_models/src/webhook_events.rs
// Module: api_models
// Implementations: 1
// Traits: common_utils::events::ApiEventMetric

pub struct WebhookDeliveryRetryRequestInternal


// Function: get_refunds_aggregates
// File: crates/router/src/routes/refunds.rs
// Module: router

pub fn get_refunds_aggregates(
    state: web::Data<AppState>,
    req: HttpRequest,
    query_params: web::Query<common_utils::types::TimeRange>,
) -> HttpResponse


// Implementation: impl Parse for for FieldMeta
// File: crates/router_derive/src/macros/to_encryptable.rs
// Module: router_derive
// Methods: 1 total (0 public)

impl Parse for for FieldMeta


// Function: get_payout_connector_config
// File: crates/euclid_wasm/src/lib.rs
// Module: euclid_wasm

pub fn get_payout_connector_config(key: &str) -> JsResult


// Function: get_frm_config_as_secret
// File: crates/api_models/src/admin.rs
// Module: api_models

pub fn get_frm_config_as_secret(&self) -> Option<Vec<Secret<serde_json::Value>>>


// File: crates/diesel_models/src/configs.rs
// Module: diesel_models
// Public functions: 1
// Public structs: 3

use std::convert::From;

use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
use serde::{Deserialize, Serialize};

use crate::schema::configs;

#[derive(Default, Clone, Debug, Insertable, Serialize, Deserialize)]
#[diesel(table_name = configs)]
pub struct ConfigNew {
    pub key: String,
    pub config: String,
}

#[derive(Default, Clone, Debug, Identifiable, Queryable, Selectable, Deserialize, Serialize)]
#[diesel(table_name = configs, primary_key(key), check_for_backend(diesel::pg::Pg))]
pub struct Config {
    pub key: String,
    pub config: String,
}

#[derive(Debug)]
pub enum ConfigUpdate {
    Update { config: Option<String> },
}

#[derive(Clone, Debug, AsChangeset, Default)]
#[diesel(table_name = configs)]
pub struct ConfigUpdateInternal {
    config: Option<String>,
}

impl ConfigUpdateInternal {
    pub fn create_config(self, source: Config) -> Config {
        Config { ..source }
    }
}

impl From<ConfigUpdate> for ConfigUpdateInternal {
    fn from(config_update: ConfigUpdate) -> Self {
        match config_update {
            ConfigUpdate::Update { config } => Self { config },
        }
    }
}

impl From<ConfigNew> for Config {
    fn from(config_new: ConfigNew) -> Self {
        Self {
            key: config_new.key,
            config: config_new.config,
        }
    }
}


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

impl api::RefundExecute for for Facilitapay


// Struct: ActivePaymentsMetricsBucketIdentifier
// File: crates/api_models/src/analytics/active_payments.rs
// Module: api_models
// Implementations: 3
// Traits: Hash, PartialEq

pub struct ActivePaymentsMetricsBucketIdentifier


// Function: find_by_global_customer_id
// File: crates/diesel_models/src/query/mandate.rs
// Module: diesel_models

pub fn find_by_global_customer_id(
        conn: &PgPooledConn,
        customer_id: &common_utils::id_type::GlobalCustomerId,
    ) -> StorageResult<Vec<Self>>


// Function: customers_list
// File: crates/openapi/src/routes/customers.rs
// Module: openapi

pub fn customers_list()


// Function: server
// File: crates/router/src/routes/app.rs
// Module: router

pub fn server(state: AppState) -> Scope


// Implementation: impl Profile
// File: crates/hyperswitch_domain_models/src/business_profile.rs
// Module: hyperswitch_domain_models
// Methods: 2 total (2 public)

impl Profile


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

impl api::Payment for for Fiuu


// Struct: ChargebeeSubscriptionEstimateRequest
// File: crates/hyperswitch_connectors/src/connectors/chargebee/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ChargebeeSubscriptionEstimateRequest


// Struct: PaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/klarna/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentsResponse


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

impl CustomerResponse


// File: crates/diesel_models/src/query/role.rs
// Module: diesel_models
// Public functions: 8

use async_bb8_diesel::AsyncRunQueryDsl;
use common_enums::EntityType;
use common_utils::id_type;
use diesel::{
    associations::HasTable, debug_query, pg::Pg, result::Error as DieselError,
    BoolExpressionMethods, ExpressionMethods, QueryDsl,
};
use error_stack::{report, ResultExt};
use strum::IntoEnumIterator;

use crate::{
    enums::RoleScope, errors, query::generics, role::*, schema::roles::dsl, PgPooledConn,
    StorageResult,
};

impl RoleNew {
    pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<Role> {
        generics::generic_insert(conn, self).await
    }
}

impl Role {
    fn get_entity_list(
        current_entity: EntityType,
        is_lineage_data_required: bool,
    ) -> Vec<EntityType> {
        is_lineage_data_required
            .then(|| {
                EntityType::iter()
                    .filter(|variant| *variant <= current_entity)
                    .collect()
            })
            .unwrap_or(vec![current_entity])
    }

    pub async fn find_by_role_id(conn: &PgPooledConn, role_id: &str) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::role_id.eq(role_id.to_owned()),
        )
        .await
    }

    pub async fn find_by_role_id_in_lineage(
        conn: &PgPooledConn,
        role_id: &str,
        merchant_id: &id_type::MerchantId,
        org_id: &id_type::OrganizationId,
        profile_id: &id_type::ProfileId,
        tenant_id: &id_type::TenantId,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::role_id
                .eq(role_id.to_owned())
                .and(dsl::tenant_id.eq(tenant_id.to_owned()))
                .and(dsl::org_id.eq(org_id.to_owned()))
                .and(
                    dsl::scope
                        .eq(RoleScope::Organization)
                        .or(dsl::merchant_id
                            .eq(merchant_id.to_owned())
                            .and(dsl::scope.eq(RoleScope::Merchant)))
                        .or(dsl::profile_id
                            .eq(profile_id.to_owned())
                            .and(dsl::scope.eq(RoleScope::Profile))),
                ),
        )
        .await
    }

    pub async fn find_by_role_id_org_id_tenant_id(
        conn: &PgPooledConn,
        role_id: &str,
        org_id: &id_type::OrganizationId,
        tenant_id: &id_type::TenantId,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::role_id
                .eq(role_id.to_owned())
                .and(dsl::tenant_id.eq(tenant_id.to_owned()))
                .and(dsl::org_id.eq(org_id.to_owned())),
        )
        .await
    }

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

    pub async fn delete_by_role_id(conn: &PgPooledConn, role_id: &str) -> StorageResult<Self> {
        generics::generic_delete_one_with_result::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::role_id.eq(role_id.to_owned()),
        )
        .await
    }

    //TODO: Remove once generic_list_roles_by_entity_type is stable
    pub async fn generic_roles_list_for_org(
        conn: &PgPooledConn,
        tenant_id: id_type::TenantId,
        org_id: id_type::OrganizationId,
        merchant_id: Option<id_type::MerchantId>,
        entity_type: Option<EntityType>,
        limit: Option<u32>,
    ) -> StorageResult<Vec<Self>> {
        let mut query = <Self as HasTable>::table()
            .filter(dsl::tenant_id.eq(tenant_id).and(dsl::org_id.eq(org_id)))
            .into_boxed();

        if let Some(merchant_id) = merchant_id {
            query = query.filter(
                (dsl::merchant_id
                    .eq(merchant_id)
                    .and(dsl::scope.eq(RoleScope::Merchant)))
                .or(dsl::scope.eq(RoleScope::Organization)),
            );
        }

        if let Some(entity_type) = entity_type {
            query = query.filter(dsl::entity_type.eq(entity_type))
        }

        if let Some(limit) = limit {
            query = query.limit(limit.into());
        }

        router_env::logger::debug!(query = %debug_query::<Pg,_>(&query).to_string());

        match generics::db_metrics::track_database_call::<Self, _, _>(
            query.get_results_async(conn),
            generics::db_metrics::DatabaseOperation::Filter,
        )
        .await
        {
            Ok(value) => Ok(value),
            Err(err) => match err {
                DieselError::NotFound => {
                    Err(report!(err)).change_context(errors::DatabaseError::NotFound)
                }
                _ => Err(report!(err)).change_context(errors::DatabaseError::Others),
            },
        }
    }

    pub async fn generic_list_roles_by_entity_type(
        conn: &PgPooledConn,
        payload: ListRolesByEntityPayload,
        is_lineage_data_required: bool,
        tenant_id: id_type::TenantId,
        org_id: id_type::OrganizationId,
    ) -> StorageResult<Vec<Self>> {
        let mut query = <Self as HasTable>::table()
            .into_boxed()
            .filter(dsl::tenant_id.eq(tenant_id))
            .filter(dsl::org_id.eq(org_id));

        match payload {
            ListRolesByEntityPayload::Organization => {
                let entity_in_vec =
                    Self::get_entity_list(EntityType::Organization, is_lineage_data_required);
                query = query.filter(dsl::entity_type.eq_any(entity_in_vec))
            }

            ListRolesByEntityPayload::Merchant(merchant_id) => {
                let entity_in_vec =
                    Self::get_entity_list(EntityType::Merchant, is_lineage_data_required);
                query = query
                    .filter(
                        dsl::scope
                            .eq(RoleScope::Organization)
                            .or(dsl::merchant_id.eq(merchant_id)),
                    )
                    .filter(dsl::entity_type.eq_any(entity_in_vec))
            }

            ListRolesByEntityPayload::Profile(merchant_id, profile_id) => {
                let entity_in_vec =
                    Self::get_entity_list(EntityType::Profile, is_lineage_data_required);
                query = query
                    .filter(
                        dsl::scope
                            .eq(RoleScope::Organization)
                            .or(dsl::scope
                                .eq(RoleScope::Merchant)
                                .and(dsl::merchant_id.eq(merchant_id.clone())))
                            .or(dsl::profile_id.eq(profile_id)),
                    )
                    .filter(dsl::entity_type.eq_any(entity_in_vec))
            }
        };

        router_env::logger::debug!(query = %debug_query::<Pg,_>(&query).to_string());

        match generics::db_metrics::track_database_call::<Self, _, _>(
            query.get_results_async(conn),
            generics::db_metrics::DatabaseOperation::Filter,
        )
        .await
        {
            Ok(value) => Ok(value),
            Err(err) => Err(report!(err)).change_context(errors::DatabaseError::Others),
        }
    }
}


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

impl MerchantConnectorAccount


// Function: list_payment_method_api
// File: crates/openapi/src/routes/payment_method.rs
// Module: openapi

pub fn list_payment_method_api()


// Struct: ExecutePcrWorkflow
// File: crates/router/src/workflows/revenue_recovery.rs
// Module: router
// Implementations: 0

pub struct ExecutePcrWorkflow


// Implementation: impl api::Payment for for Noon
// File: crates/hyperswitch_connectors/src/connectors/noon.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Payment for for Noon


// Trait: ConnectorIntegrationInterface
// File: crates/hyperswitch_interfaces/src/connector_integration_interface.rs
// Module: hyperswitch_interfaces

// Documentation: Trait representing the connector integration interface  This trait defines the methods required for a connector integration interface.

pub trait ConnectorIntegrationInterface<F, ResourceCommonData, Req, Resp>: Send + Sync


// Function: insert
// File: crates/diesel_models/src/query/merchant_connector_account.rs
// Module: diesel_models

pub fn insert(self, conn: &PgPooledConn) -> StorageResult<MerchantConnectorAccount>


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

impl MerchantKeyStoreInterface for for KafkaStore


// Struct: UpdateNexixpayConnectorMetaData
// File: crates/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct UpdateNexixpayConnectorMetaData


// Implementation: impl StripebillingWebhookBody
// File: crates/hyperswitch_connectors/src/connectors/stripebilling/transformers.rs
// Module: hyperswitch_connectors
// Methods: 1 total (1 public)

impl StripebillingWebhookBody


// Struct: CustomerInfo
// File: crates/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CustomerInfo


// Function: create_cards_info
// File: crates/router/src/routes/cards_info.rs
// Module: router

pub fn create_cards_info(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<cards_info_api_types::CardInfoCreateRequest>,
) -> impl Responder


// Function: contract_based_routing_update_configs
// File: crates/openapi/src/routes/routing.rs
// Module: openapi

pub fn contract_based_routing_update_configs()


// Implementation: impl OutgoingWebhookEventMetric for for OutgoingWebhookContent
// File: crates/router/src/events/outgoing_webhook_logs.rs
// Module: router
// Methods: 1 total (0 public)

impl OutgoingWebhookEventMetric for for OutgoingWebhookContent


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

pub struct CancelInputData


// Struct: BankAccountDetail
// File: crates/hyperswitch_connectors/src/connectors/facilitapay/responses.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BankAccountDetail


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

pub fn create_payout(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    connector_data: &api::ConnectorData,
    payout_data: &mut PayoutData,
) -> RouterResult<()>


// Function: profiles_list
// File: crates/openapi/src/routes/merchant_account.rs
// Module: openapi

pub fn profiles_list()


// Function: add_nested_filter_clause
// File: crates/analytics/src/query.rs
// Module: analytics

pub fn add_nested_filter_clause(&mut self, filter: Filter)


// Struct: MolliePaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct MolliePaymentsResponse


// Trait: NodeViz
// File: crates/hyperswitch_constraint_graph/src/types.rs
// Module: hyperswitch_constraint_graph

pub trait NodeViz


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

pub struct PayuRefundResponseData


// Struct: CybersourceAccountInfo
// File: crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CybersourceAccountInfo


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

impl CustomerResponse


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

impl api::Refund for for Bamboraapac


// Implementation: impl SeriesBucket for for Granularity
// File: crates/analytics/src/query.rs
// Module: analytics
// Methods: 4 total (0 public)

impl SeriesBucket for for Granularity


// Struct: PaymentResponseData
// File: crates/hyperswitch_connectors/src/connectors/getnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentResponseData


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

pub struct CloneConnectorRequest


// Function: make_value_node
// File: crates/hyperswitch_constraint_graph/src/builder.rs
// Module: hyperswitch_constraint_graph

pub fn make_value_node<M: Metadata>(
        &mut self,
        value: NodeValue<V>,
        info: Option<&'static str>,
        metadata: Option<M>,
    ) -> NodeId


// Implementation: impl webhooks::IncomingWebhook for for Breadpay
// File: crates/hyperswitch_connectors/src/connectors/breadpay.rs
// Module: hyperswitch_connectors
// Methods: 3 total (0 public)

impl webhooks::IncomingWebhook for for Breadpay


// Implementation: impl ApiEventMetric for for GatewayStatusMap
// File: crates/diesel_models/src/gsm.rs
// Module: diesel_models
// Methods: 1 total (0 public)

impl ApiEventMetric for for GatewayStatusMap


// Function: new
// File: crates/test_utils/src/connector_auth.rs
// Module: test_utils

pub fn new() -> Self


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

impl DerefMut for for CycleCheck


// Struct: FiuuSyncStatus
// File: crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FiuuSyncStatus


// Struct: ApplePayCryptogramDataInternal
// File: crates/hyperswitch_domain_models/src/router_data.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct ApplePayCryptogramDataInternal


// Implementation: impl api::PaymentSession for for Payme
// File: crates/hyperswitch_connectors/src/connectors/payme.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentSession for for Payme


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

impl api::PaymentSync for for Datatrans


// Struct: PaymentAddress
// File: crates/hyperswitch_domain_models/src/payment_address.rs
// Module: hyperswitch_domain_models
// Implementations: 1

pub struct PaymentAddress