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

pub mod transformers;

use common_utils::{
    errors::CustomResult,
    ext_traits::BytesExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, 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},
        Authenticate, AuthenticationConfirmation, PostAuthenticate, PreAuthenticate,
    },
    router_request_types::{
        unified_authentication_service::{
            UasAuthenticationRequestData, UasAuthenticationResponseData,
            UasConfirmationRequestData, UasPostAuthenticationRequestData,
            UasPreAuthenticationRequestData,
        },
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentsResponseData, RefundsResponseData, SupportedPaymentMethods,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData,
        RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{self, Response},
    webhooks,
};
use masking::{ExposeInterface, Mask};
use transformers as juspaythreedsserver;

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

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

impl Juspaythreedsserver {
    pub fn new() -> &'static Self {
        &Self {
            amount_converter: &StringMinorUnitForConnector,
        }
    }
}

impl api::Payment for Juspaythreedsserver {}
impl api::PaymentSession for Juspaythreedsserver {}
impl api::ConnectorAccessToken for Juspaythreedsserver {}
impl api::MandateSetup for Juspaythreedsserver {}
impl api::PaymentAuthorize for Juspaythreedsserver {}
impl api::PaymentSync for Juspaythreedsserver {}
impl api::PaymentCapture for Juspaythreedsserver {}
impl api::PaymentVoid for Juspaythreedsserver {}
impl api::Refund for Juspaythreedsserver {}
impl api::RefundExecute for Juspaythreedsserver {}
impl api::RefundSync for Juspaythreedsserver {}
impl api::PaymentToken for Juspaythreedsserver {}
impl api::UnifiedAuthenticationService for Juspaythreedsserver {}
impl api::UasPreAuthentication for Juspaythreedsserver {}
impl api::UasPostAuthentication for Juspaythreedsserver {}
impl api::UasAuthenticationConfirmation for Juspaythreedsserver {}
impl api::UasAuthentication for Juspaythreedsserver {}

impl
    ConnectorIntegration<
        PreAuthenticate,
        UasPreAuthenticationRequestData,
        UasAuthenticationResponseData,
    > for Juspaythreedsserver
{
}

impl
    ConnectorIntegration<
        PostAuthenticate,
        UasPostAuthenticationRequestData,
        UasAuthenticationResponseData,
    > for Juspaythreedsserver
{
}

impl
    ConnectorIntegration<
        AuthenticationConfirmation,
        UasConfirmationRequestData,
        UasAuthenticationResponseData,
    > for Juspaythreedsserver
{
}

impl ConnectorIntegration<Authenticate, UasAuthenticationRequestData, UasAuthenticationResponseData>
    for Juspaythreedsserver
{
}

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

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Juspaythreedsserver
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let mut header = vec![(
            headers::CONTENT_TYPE.to_string(),
            self.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 Juspaythreedsserver {
    fn id(&self) -> &'static str {
        "juspaythreedsserver"
    }

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Base
        //    TODO! Check connector documentation, on which unit they are processing the currency.
        //    If the connector accepts amount in lower unit ( i.e cents for USD) then return api::CurrencyUnit::Minor,
        //    if connector accepts amount in base unit (i.e dollars for USD) then return api::CurrencyUnit::Base
    }

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

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

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

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.code,
            message: response.message,
            reason: response.reason,
            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 Juspaythreedsserver {
    //TODO: implement functions when support enabled
}

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

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

impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
    for Juspaythreedsserver
{
}

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData>
    for Juspaythreedsserver
{
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::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> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

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

        let connector_router_data =
            juspaythreedsserver::JuspaythreedsserverRouterData::from((amount, req));
        let connector_req = juspaythreedsserver::JuspaythreedsserverPaymentsRequest::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(&types::PaymentsAuthorizeType::get_url(
                    self, req, connectors,
                )?)
                .attach_default_headers()
                .headers(types::PaymentsAuthorizeType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(types::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: juspaythreedsserver::JuspaythreedsserverPaymentsResponse = res
            .response
            .parse_struct("Juspaythreedsserver 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,
        })
    }

    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 Juspaythreedsserver {
    fn get_headers(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::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> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::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: juspaythreedsserver::JuspaythreedsserverPaymentsResponse = res
            .response
            .parse_struct("juspaythreedsserver 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,
        })
    }

    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 Juspaythreedsserver
{
    fn get_headers(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::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: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

    fn get_request_body(
        &self,
        _req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into())
    }

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

    fn handle_response(
        &self,
        data: &PaymentsCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCaptureRouterData, errors::ConnectorError> {
        let response: juspaythreedsserver::JuspaythreedsserverPaymentsResponse = res
            .response
            .parse_struct("Juspaythreedsserver PaymentsCaptureResponse")
            .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,
        })
    }

    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<Void, PaymentsCancelData, PaymentsResponseData> for Juspaythreedsserver {}

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Juspaythreedsserver {
    fn get_headers(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::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: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let refund_amount = utils::convert_amount(
            self.amount_converter,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;

        let connector_router_data =
            juspaythreedsserver::JuspaythreedsserverRouterData::from((refund_amount, req));
        let connector_req = juspaythreedsserver::JuspaythreedsserverRefundRequest::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 request = RequestBuilder::new()
            .method(Method::Post)
            .url(&types::RefundExecuteType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(types::RefundExecuteType::get_headers(
                self, req, connectors,
            )?)
            .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: juspaythreedsserver::RefundResponse = res
            .response
            .parse_struct("juspaythreedsserver 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,
        })
    }

    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 Juspaythreedsserver {
    fn get_headers(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::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: &RefundSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

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

    fn handle_response(
        &self,
        data: &RefundSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        let response: juspaythreedsserver::RefundResponse = res
            .response
            .parse_struct("juspaythreedsserver RefundSyncResponse")
            .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,
        })
    }

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

#[async_trait::async_trait]
impl webhooks::IncomingWebhook for Juspaythreedsserver {
    fn get_webhook_object_reference_id(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_event_type(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_resource_object(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }
}

static JUSPAYTHREEDSSERVER_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Juspay 3Ds Server",
    description: "Juspay 3DS Server provider for comprehensive 3-Domain Secure authentication, cardholder verification, and fraud prevention across card networks",
    connector_type: common_enums::HyperswitchConnectorCategory::AuthenticationProvider,
    integration_status: common_enums::ConnectorIntegrationStatus::Alpha,
};

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

    fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
        None
    }

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


pub struct ChargebeeMetadata {
    pub(super) site: Secret<String>,
}


pub async fn complete_create_recipient(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    connector_data: &api::ConnectorData,
    payout_data: &mut PayoutData,
) -> RouterResult<()> {
    if !payout_data.should_terminate
        && matches!(
            payout_data.payout_attempt.status,
            common_enums::PayoutStatus::RequiresCreation
                | common_enums::PayoutStatus::RequiresConfirmation
                | common_enums::PayoutStatus::RequiresPayoutMethodData
        )
        && connector_data
            .connector_name
            .supports_create_recipient(payout_data.payouts.payout_type)
    {
        Box::pin(create_recipient(
            state,
            merchant_context,
            connector_data,
            payout_data,
        ))
        .await
        .attach_printable("Creation of customer failed")?;
    }

    Ok(())
}


pub fn set_limit_by(&mut self, limit: u64, columns: &[impl ToSql<T>]) -> QueryResult<()> {
        let columns = columns
            .iter()
            .map(|col| col.to_sql(&self.table_engine))
            .collect::<Result<Vec<String>, _>>()
            .change_context(QueryBuildingError::SqlSerializeError)
            .attach_printable("Error serializing LIMIT BY columns")?;

        self.limit_by = Some(LimitByClause { limit, columns });
        Ok(())
    }


pub fn validate(&self) -> Result<(), ApplicationError> {
        common_utils::fp_utils::when(self.lock_key.is_default_or_empty(), || {
            Err(ApplicationError::InvalidConfigurationValueError(
                "producer lock key must not be empty".into(),
            ))
        })
    }


File: crates/router/src/utils/ext_traits.rs

pub use hyperswitch_domain_models::ext_traits::OptionExt;

use crate::core::errors::{self, CustomResult};

pub trait ValidateCall<T, F> {
    fn validate_opt(self, func: F) -> CustomResult<(), errors::ValidationError>;
}

impl<T, F> ValidateCall<T, F> for Option<&T>
where
    F: Fn(&T) -> CustomResult<(), errors::ValidationError>,
{
    fn validate_opt(self, func: F) -> CustomResult<(), errors::ValidationError> {
        match self {
            Some(val) => func(val),
            None => Ok(()),
        }
    }
}


pub async fn send_request_to_key_service_for_merchant(
    state: &SessionState,
    keys: Vec<MerchantKeyStore>,
) -> errors::CustomResult<usize, errors::ApiErrorResponse> {
    let total = keys.len();
    for key in keys {
        let key_encoded = BASE64_ENGINE.encode(key.key.clone().into_inner().expose());
        let req = EncryptionTransferRequest {
            identifier: Identifier::Merchant(key.merchant_id.clone()),
            key: key_encoded,
        };
        transfer_key_to_key_manager(&state.into(), req)
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)?;
    }
    Ok(total)
}


OpenAPI Block Path: components.schemas.FrmMessage
{
  "type": "object",
  "description": "frm message is an object sent inside the payments response...when frm is invoked, its value is Some(...), else its None",
  "required": [
    "frm_name"
  ],
  "properties": {
    "frm_name": {
      "type": "string"
    },
    "frm_transaction_id": {
      "type": "string",
      "nullable": true
    },
    "frm_transaction_type": {
      "type": "string",
      "nullable": true
    },
    "frm_status": {
      "type": "string",
      "nullable": true
    },
    "frm_score": {
      "type": "integer",
      "format": "int32",
      "nullable": true
    },
    "frm_reason": {
      "nullable": true
    },
    "frm_error": {
      "type": "string",
      "nullable": true
    }
  }
}


pub async fn payment_data(
    state: SessionState,
    req: types::DummyConnectorPaymentRetrieveRequest,
) -> types::DummyConnectorResponse<types::DummyConnectorPaymentResponse> {
    utils::tokio_mock_sleep(
        state.conf.dummy_connector.payment_retrieve_duration,
        state.conf.dummy_connector.payment_retrieve_tolerance,
    )
    .await;

    let payment_data = utils::get_payment_data_from_payment_id(&state, req.payment_id).await?;
    Ok(api::ApplicationResponse::Json(payment_data.into()))
}


pub fn supports_vendor_disburse_account_create_for_payout(self) -> bool {
        matches!(self, Self::Stripe | Self::Nomupay)
    }


impl api::MandateSetup for Payeezy {}


pub struct Tsys {
    amount_converter: &'static (dyn AmountConvertor<Output = StringMinorUnit> + Sync),
}


impl Dwolla {
    pub fn new() -> &'static Self {
        &Self {
            amount_converter: &StringMajorUnitForConnector,
        }
    }
}


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

    fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
        None
    }

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

impl ConnectorSpecifications for for Thunes


File: crates/hyperswitch_connectors/src/connectors/custombilling/transformers.rs
 Public structs: 7

use common_enums::enums;
use common_utils::types::StringMinorUnit;
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::RouterData,
    router_flow_types::refunds::{Execute, RSync},
    router_request_types::ResponseId,
    router_response_types::{PaymentsResponseData, RefundsResponseData},
    types::{PaymentsAuthorizeRouterData, RefundsRouterData},
};
use hyperswitch_interfaces::errors;
use masking::Secret;
use serde::{Deserialize, Serialize};

use crate::{
    types::{RefundsResponseRouterData, ResponseRouterData},
    utils::PaymentsAuthorizeRequestData,
};

//TODO: Fill the struct with respective fields
pub struct CustombillingRouterData<T> {
    pub amount: StringMinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
    pub router_data: T,
}

impl<T> From<(StringMinorUnit, T)> for CustombillingRouterData<T> {
    fn from((amount, item): (StringMinorUnit, T)) -> Self {
        //Todo :  use utils to convert the amount to the type of amount that a connector accepts
        Self {
            amount,
            router_data: item,
        }
    }
}

//TODO: Fill the struct with respective fields
#[derive(Default, Debug, Serialize, PartialEq)]
pub struct CustombillingPaymentsRequest {
    amount: StringMinorUnit,
    card: CustombillingCard,
}

#[derive(Default, Debug, Serialize, Eq, PartialEq)]
pub struct CustombillingCard {
    number: cards::CardNumber,
    expiry_month: Secret<String>,
    expiry_year: Secret<String>,
    cvc: Secret<String>,
    complete: bool,
}

impl TryFrom<&CustombillingRouterData<&PaymentsAuthorizeRouterData>>
    for CustombillingPaymentsRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &CustombillingRouterData<&PaymentsAuthorizeRouterData>,
    ) -> Result<Self, Self::Error> {
        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(req_card) => {
                let card = CustombillingCard {
                    number: req_card.card_number,
                    expiry_month: req_card.card_exp_month,
                    expiry_year: req_card.card_exp_year,
                    cvc: req_card.card_cvc,
                    complete: item.router_data.request.is_auto_capture()?,
                };
                Ok(Self {
                    amount: item.amount.clone(),
                    card,
                })
            }
            _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
        }
    }
}

// PaymentsResponse
//TODO: Append the remaining status flags
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum CustombillingPaymentStatus {
    Succeeded,
    Failed,
    #[default]
    Processing,
}

impl From<CustombillingPaymentStatus> for common_enums::AttemptStatus {
    fn from(item: CustombillingPaymentStatus) -> Self {
        match item {
            CustombillingPaymentStatus::Succeeded => Self::Charged,
            CustombillingPaymentStatus::Failed => Self::Failure,
            CustombillingPaymentStatus::Processing => Self::Authorizing,
        }
    }
}

//TODO: Fill the struct with respective fields
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CustombillingPaymentsResponse {
    status: CustombillingPaymentStatus,
    id: String,
}

impl<F, T> TryFrom<ResponseRouterData<F, CustombillingPaymentsResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, CustombillingPaymentsResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: common_enums::AttemptStatus::from(item.response.status),
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(item.response.id),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

//TODO: Fill the struct with respective fields
// REFUND :
// Type definition for RefundRequest
#[derive(Default, Debug, Serialize)]
pub struct CustombillingRefundRequest {
    pub amount: StringMinorUnit,
}

impl<F> TryFrom<&CustombillingRouterData<&RefundsRouterData<F>>> for CustombillingRefundRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &CustombillingRouterData<&RefundsRouterData<F>>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: item.amount.to_owned(),
        })
    }
}

// Type definition for Refund Response

#[allow(dead_code)]
#[derive(Debug, Serialize, Default, Deserialize, Clone)]
pub enum RefundStatus {
    Succeeded,
    Failed,
    #[default]
    Processing,
}

impl From<RefundStatus> for enums::RefundStatus {
    fn from(item: RefundStatus) -> Self {
        match item {
            RefundStatus::Succeeded => Self::Success,
            RefundStatus::Failed => Self::Failure,
            RefundStatus::Processing => Self::Pending,
            //TODO: Review mapping
        }
    }
}

//TODO: Fill the struct with respective fields
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct RefundResponse {
    id: String,
    status: RefundStatus,
}

impl TryFrom<RefundsResponseRouterData<Execute, RefundResponse>> for RefundsRouterData<Execute> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<Execute, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status: enums::RefundStatus::from(item.response.status),
            }),
            ..item.data
        })
    }
}

impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for RefundsRouterData<RSync> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: RefundsResponseRouterData<RSync, RefundResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(RefundsResponseData {
                connector_refund_id: item.response.id.to_string(),
                refund_status: enums::RefundStatus::from(item.response.status),
            }),
            ..item.data
        })
    }
}

//TODO: Fill the struct with respective fields
#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
pub struct CustombillingErrorResponse {
    pub status_code: u16,
    pub code: String,
    pub message: String,
    pub reason: Option<String>,
}


OpenAPI Block Path: components.schemas.DecideGatewayResponse
{
  "type": "object",
  "properties": {
    "decided_gateway": {
      "type": "string",
      "nullable": true
    },
    "gateway_priority_map": {
      "nullable": true
    },
    "filter_wise_gateways": {
      "nullable": true
    },
    "priority_logic_tag": {
      "type": "string",
      "nullable": true
    },
    "routing_approach": {
      "type": "string",
      "nullable": true
    },
    "gateway_before_evaluation": {
      "type": "string",
      "nullable": true
    },
    "priority_logic_output": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PriorityLogicOutput"
        }
      ],
      "nullable": true
    },
    "reset_approach": {
      "type": "string",
      "nullable": true
    },
    "routing_dimension": {
      "type": "string",
      "nullable": true
    },
    "routing_dimension_level": {
      "type": "string",
      "nullable": true
    },
    "is_scheduled_outage": {
      "type": "boolean",
      "nullable": true
    },
    "is_dynamic_mga_enabled": {
      "type": "boolean",
      "nullable": true
    },
    "gateway_mga_id_map": {
      "nullable": true
    }
  }
}


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

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

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

impl ConnectorSpecifications for for Authipay


pub struct ClientRiskInformation {
    rules: Option<Vec<ClientRiskInformationRules>>,
}


pub struct StripeChargeResponseData {
    /// Identifier for charge created for the payment
    pub charge_id: Option<String>,

    /// Type of charge (connector specific)
    #[schema(value_type = PaymentChargeType, example = "direct")]
    pub charge_type: enums::PaymentChargeType,

    /// Platform fees collected on the payment
    #[schema(value_type = i64, example = 6540)]
    pub application_fees: Option<MinorUnit>,

    /// Identifier for the reseller's account where the funds were transferred
    pub transfer_account_id: String,
}


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

impl api::ConnectorRedirectResponse for for Checkout


impl DisputeInterface for KafkaStore {
    async fn insert_dispute(
        &self,
        dispute_new: storage::DisputeNew,
    ) -> CustomResult<storage::Dispute, errors::StorageError> {
        let dispute = self.diesel_store.insert_dispute(dispute_new).await?;

        if let Err(er) = self
            .kafka_producer
            .log_dispute(&dispute, None, self.tenant_id.clone())
            .await
        {
            logger::error!(message="Failed to add analytics entry for Dispute {dispute:?}", error_message=?er);
        };

        Ok(dispute)
    }

    async fn find_by_merchant_id_payment_id_connector_dispute_id(
        &self,
        merchant_id: &id_type::MerchantId,
        payment_id: &id_type::PaymentId,
        connector_dispute_id: &str,
    ) -> CustomResult<Option<storage::Dispute>, errors::StorageError> {
        self.diesel_store
            .find_by_merchant_id_payment_id_connector_dispute_id(
                merchant_id,
                payment_id,
                connector_dispute_id,
            )
            .await
    }

    async fn find_dispute_by_merchant_id_dispute_id(
        &self,
        merchant_id: &id_type::MerchantId,
        dispute_id: &str,
    ) -> CustomResult<storage::Dispute, errors::StorageError> {
        self.diesel_store
            .find_dispute_by_merchant_id_dispute_id(merchant_id, dispute_id)
            .await
    }

    async fn find_disputes_by_constraints(
        &self,
        merchant_id: &id_type::MerchantId,
        dispute_constraints: &disputes::DisputeListConstraints,
    ) -> CustomResult<Vec<storage::Dispute>, errors::StorageError> {
        self.diesel_store
            .find_disputes_by_constraints(merchant_id, dispute_constraints)
            .await
    }

    async fn update_dispute(
        &self,
        this: storage::Dispute,
        dispute: storage::DisputeUpdate,
    ) -> CustomResult<storage::Dispute, errors::StorageError> {
        let dispute_new = self
            .diesel_store
            .update_dispute(this.clone(), dispute)
            .await?;
        if let Err(er) = self
            .kafka_producer
            .log_dispute(&dispute_new, Some(this), self.tenant_id.clone())
            .await
        {
            logger::error!(message="Failed to add analytics entry for Dispute {dispute_new:?}", error_message=?er);
        };

        Ok(dispute_new)
    }

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

    async fn get_dispute_status_with_count(
        &self,
        merchant_id: &id_type::MerchantId,
        profile_id_list: Option<Vec<id_type::ProfileId>>,
        time_range: &common_utils::types::TimeRange,
    ) -> CustomResult<Vec<(common_enums::DisputeStatus, i64)>, errors::StorageError> {
        self.diesel_store
            .get_dispute_status_with_count(merchant_id, profile_id_list, time_range)
            .await
    }
}

impl DisputeInterface for for KafkaStore


OpenAPI Block Path: components.schemas.ApplePayBillingContactFields
{
  "type": "array",
  "items": {
    "$ref": "#/components/schemas/ApplePayAddressParameters"
  }
}


pub struct MifinityErrorResponse {
    pub errors: Vec<MifinityErrorList>,
}


pub async fn set_role_info_in_cache_by_role_id_org_id(
    state: &SessionState,
    role_id: &str,
    org_id: &id_type::OrganizationId,
    tenant_id: &id_type::TenantId,
) -> bool {
    set_role_info_in_cache_if_required(state, role_id, org_id, tenant_id)
        .await
        .map_err(|e| logger::error!("Error setting permissions in cache {:?}", e))
        .is_ok()
}


pub struct InstructionNarrative {
    pub line1: String,
}


impl ConnectorSelection {
    pub fn get_connector_list(&self) -> Vec<RoutableConnectorChoice> {
        match self {
            Self::Priority(list) => list.clone(),
            Self::VolumeSplit(splits) => {
                splits.iter().map(|split| split.connector.clone()).collect()
            }
        }
    }
}


pub struct Silverflow;


/// get step up enabled key
    pub fn get_step_up_enabled_key(&self) -> String {
        format!("step_up_enabled_{}", self.get_string_repr())
    }


Documentation: api-reference/locker-api-reference/key-custodian/provide-key-1.mdx
# Type: Doc File

---
openapi: rust_locker_open_api_spec post /custodian/key1
---


Documentation: api-reference/v1/organization/organization--retrieve.mdx
# Type: Doc File

---
openapi: get /organization/{id}
---


impl api::MandateSetup for Itaubank {}


pub struct CardHolder {
    cardholder_name: Secret<String>,
    email: Email,
}


pub struct PaymentsStoredCredentials {
    cardbrand_original_transaction_id: Secret<String>,
}


File: crates/external_services/src/hashicorp_vault.rs

//! Interactions with the HashiCorp Vault

pub mod core;

pub mod implementers;


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

pub mod transformers;
#[cfg(feature = "frm")]
use api_models::webhooks::{ConnectorWebhookSecrets, IncomingWebhookEvent, ObjectReferenceId};
#[cfg(feature = "frm")]
use base64::Engine;
#[cfg(feature = "frm")]
use common_utils::types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector};
#[cfg(feature = "frm")]
use common_utils::{
    consts::BASE64_ENGINE,
    request::{Method, RequestBuilder},
    types::MinorUnit,
};
#[cfg(feature = "frm")]
use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent};
use common_utils::{errors::CustomResult, request::Request};
#[cfg(feature = "frm")]
use error_stack::ResultExt;
#[cfg(feature = "frm")]
use hyperswitch_domain_models::{
    router_data::ErrorResponse,
    router_flow_types::{Checkout, Fulfillment, RecordReturn, Sale, Transaction},
    router_request_types::fraud_check::{
        FraudCheckCheckoutData, FraudCheckFulfillmentData, FraudCheckRecordReturnData,
        FraudCheckSaleData, FraudCheckTransactionData,
    },
    router_response_types::fraud_check::FraudCheckResponseData,
};
use hyperswitch_domain_models::{
    router_data::{AccessToken, RouterData},
    router_flow_types::{
        AccessTokenAuth, Authorize, Capture, Execute, PSync, PaymentMethodToken, RSync, Session,
        SetupMandate, Void,
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentsResponseData, RefundsResponseData, SupportedPaymentMethods,
    },
};
use hyperswitch_interfaces::{
    api::{
        ConnectorAccessToken, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration,
        ConnectorSpecifications, ConnectorValidation, MandateSetup, Payment, PaymentAuthorize,
        PaymentCapture, PaymentSession, PaymentSync, PaymentToken, PaymentVoid, Refund,
        RefundExecute, RefundSync,
    },
    configs::Connectors,
    errors::ConnectorError,
};
#[cfg(feature = "frm")]
use hyperswitch_interfaces::{
    api::{
        FraudCheck, FraudCheckCheckout, FraudCheckFulfillment, FraudCheckRecordReturn,
        FraudCheckSale, FraudCheckTransaction,
    },
    events::connector_api_logs::ConnectorEvent,
    types::Response,
    webhooks::{IncomingWebhook, IncomingWebhookRequestDetails},
};
#[cfg(feature = "frm")]
use masking::Maskable;
#[cfg(feature = "frm")]
use masking::{ExposeInterface, Mask, PeekInterface, Secret};
#[cfg(feature = "frm")]
use ring::hmac;
#[cfg(feature = "frm")]
use transformers as riskified;

#[cfg(feature = "frm")]
use crate::constants::headers;
#[cfg(feature = "frm")]
use crate::utils::convert_amount;
#[cfg(feature = "frm")]
use crate::{
    types::{
        FrmCheckoutRouterData, FrmCheckoutType, FrmFulfillmentRouterData, FrmFulfillmentType,
        FrmTransactionRouterData, FrmTransactionType, ResponseRouterData,
    },
    utils::FrmTransactionRouterDataRequest,
};

#[derive(Clone)]
pub struct Riskified {
    #[cfg(feature = "frm")]
    amount_converter: &'static (dyn AmountConvertor<Output = StringMajorUnit> + Sync),
}

impl Riskified {
    pub fn new() -> &'static Self {
        &Self {
            #[cfg(feature = "frm")]
            amount_converter: &StringMajorUnitForConnector,
        }
    }

    #[cfg(feature = "frm")]
    pub fn generate_authorization_signature(
        &self,
        auth: &riskified::RiskifiedAuthType,
        payload: &str,
    ) -> CustomResult<String, ConnectorError> {
        let key = hmac::Key::new(
            hmac::HMAC_SHA256,
            auth.secret_token.clone().expose().as_bytes(),
        );

        let signature_value = hmac::sign(&key, payload.as_bytes());

        let digest = signature_value.as_ref();

        Ok(hex::encode(digest))
    }
}

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Riskified
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    #[cfg(feature = "frm")]
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        let auth: riskified::RiskifiedAuthType =
            riskified::RiskifiedAuthType::try_from(&req.connector_auth_type)?;

        let riskified_req = self.get_request_body(req, connectors)?;

        let binding = riskified_req.get_inner_value();
        let payload = binding.peek();

        let digest = self
            .generate_authorization_signature(&auth, payload)
            .change_context(ConnectorError::RequestEncodingFailed)?;

        let header = vec![
            (
                headers::CONTENT_TYPE.to_string(),
                self.get_content_type().to_string().into(),
            ),
            (
                "X-RISKIFIED-SHOP-DOMAIN".to_string(),
                auth.domain_name.clone().into(),
            ),
            (
                "X-RISKIFIED-HMAC-SHA256".to_string(),
                Mask::into_masked(digest),
            ),
            (
                "Accept".to_string(),
                "application/vnd.riskified.com; version=2".into(),
            ),
        ];

        Ok(header)
    }
}

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

    fn common_get_content_type(&self) -> &'static str {
        "application/json"
    }
    fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
        connectors.riskified.base_url.as_ref()
    }

    #[cfg(feature = "frm")]
    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, ConnectorError> {
        use hyperswitch_interfaces::consts::NO_ERROR_CODE;

        let response: riskified::ErrorResponse = res
            .response
            .parse_struct("ErrorResponse")
            .change_context(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,
            attempt_status: None,
            code: NO_ERROR_CODE.to_string(),
            message: response.error.message.clone(),
            reason: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

#[cfg(feature = "frm")]
impl ConnectorIntegration<Checkout, FraudCheckCheckoutData, FraudCheckResponseData> for Riskified {
    fn get_headers(
        &self,
        req: &FrmCheckoutRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

    fn get_request_body(
        &self,
        req: &FrmCheckoutRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, ConnectorError> {
        let amount = convert_amount(
            self.amount_converter,
            MinorUnit::new(req.request.amount),
            req.request
                .currency
                .ok_or(ConnectorError::MissingRequiredField {
                    field_name: "currency",
                })?,
        )?;
        let req_data = riskified::RiskifiedRouterData::from((amount, req));
        let req_obj = riskified::RiskifiedPaymentsCheckoutRequest::try_from(&req_data)?;
        Ok(RequestContent::Json(Box::new(req_obj)))
    }

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

    fn handle_response(
        &self,
        data: &FrmCheckoutRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<FrmCheckoutRouterData, ConnectorError> {
        let response: riskified::RiskifiedPaymentsResponse = res
            .response
            .parse_struct("RiskifiedPaymentsResponse Checkout")
            .change_context(ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        <FrmCheckoutRouterData>::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }
    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl Payment for Riskified {}
impl PaymentAuthorize for Riskified {}
impl PaymentSync for Riskified {}
impl PaymentVoid for Riskified {}
impl PaymentCapture for Riskified {}
impl MandateSetup for Riskified {}
impl ConnectorAccessToken for Riskified {}
impl PaymentToken for Riskified {}
impl Refund for Riskified {}
impl RefundExecute for Riskified {}
impl RefundSync for Riskified {}
impl ConnectorValidation for Riskified {}

#[cfg(feature = "frm")]
impl ConnectorIntegration<Sale, FraudCheckSaleData, FraudCheckResponseData> for Riskified {}

#[cfg(feature = "frm")]
impl ConnectorIntegration<Transaction, FraudCheckTransactionData, FraudCheckResponseData>
    for Riskified
{
    fn get_headers(
        &self,
        req: &FrmTransactionRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        self.build_headers(req, connectors)
    }

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

    fn get_url(
        &self,
        req: &FrmTransactionRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, ConnectorError> {
        match req.is_payment_successful() {
            Some(false) => Ok(format!(
                "{}{}",
                self.base_url(connectors),
                "/checkout_denied"
            )),
            _ => Ok(format!("{}{}", self.base_url(connectors), "/decision")),
        }
    }

    fn get_request_body(
        &self,
        req: &FrmTransactionRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, ConnectorError> {
        match req.is_payment_successful() {
            Some(false) => {
                let req_obj = riskified::TransactionFailedRequest::try_from(req)?;
                Ok(RequestContent::Json(Box::new(req_obj)))
            }
            _ => {
                let amount = convert_amount(
                    self.amount_converter,
                    MinorUnit::new(req.request.amount),
                    req.request
                        .currency
                        .ok_or(ConnectorError::MissingRequiredField {
                            field_name: "currency",
                        })?,
                )?;
                let req_data = riskified::RiskifiedRouterData::from((amount, req));
                let req_obj = riskified::TransactionSuccessRequest::try_from(&req_data)?;
                Ok(RequestContent::Json(Box::new(req_obj)))
            }
        }
    }

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

    fn handle_response(
        &self,
        data: &FrmTransactionRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<FrmTransactionRouterData, ConnectorError> {
        let response: riskified::RiskifiedTransactionResponse = res
            .response
            .parse_struct("RiskifiedPaymentsResponse Transaction")
            .change_context(ConnectorError::ResponseDeserializationFailed)?;

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

        match response {
            riskified::RiskifiedTransactionResponse::FailedResponse(response_data) => {
                <FrmTransactionRouterData>::try_from(ResponseRouterData {
                    response: response_data,
                    data: data.clone(),
                    http_code: res.status_code,
                })
            }
            riskified::RiskifiedTransactionResponse::SuccessResponse(response_data) => {
                <FrmTransactionRouterData>::try_from(ResponseRouterData {
                    response: response_data,
                    data: data.clone(),
                    http_code: res.status_code,
                })
            }
        }
    }
    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

#[cfg(feature = "frm")]
impl ConnectorIntegration<Fulfillment, FraudCheckFulfillmentData, FraudCheckResponseData>
    for Riskified
{
    fn get_headers(
        &self,
        req: &FrmFulfillmentRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

    fn get_request_body(
        &self,
        req: &FrmFulfillmentRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, ConnectorError> {
        let req_obj = riskified::RiskifiedFulfillmentRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(req_obj)))
    }

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

    fn handle_response(
        &self,
        data: &FrmFulfillmentRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<FrmFulfillmentRouterData, ConnectorError> {
        let response: riskified::RiskifiedFulfilmentResponse = res
            .response
            .parse_struct("RiskifiedFulfilmentResponse fulfilment")
            .change_context(ConnectorError::ResponseDeserializationFailed)?;

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

        FrmFulfillmentRouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

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

#[cfg(feature = "frm")]
impl ConnectorIntegration<RecordReturn, FraudCheckRecordReturnData, FraudCheckResponseData>
    for Riskified
{
}

impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
    for Riskified
{
}

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

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

impl PaymentSession for Riskified {}

impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Riskified {}

impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Riskified {}

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Riskified {}

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Riskified {}

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

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Riskified {}

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Riskified {}

#[cfg(feature = "frm")]
impl FraudCheck for Riskified {}
#[cfg(feature = "frm")]
impl FraudCheckSale for Riskified {}
#[cfg(feature = "frm")]
impl FraudCheckCheckout for Riskified {}
#[cfg(feature = "frm")]
impl FraudCheckTransaction for Riskified {}
#[cfg(feature = "frm")]
impl FraudCheckFulfillment for Riskified {}
#[cfg(feature = "frm")]
impl FraudCheckRecordReturn for Riskified {}

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

    fn get_webhook_source_verification_signature(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        _connector_webhook_secrets: &ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, ConnectorError> {
        let header_value =
            crate::utils::get_header_key_value("x-riskified-hmac-sha256", request.headers)?;
        Ok(header_value.as_bytes().to_vec())
    }

    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, ConnectorError> {
        let connector_webhook_secrets = self
            .get_webhook_source_verification_merchant_secret(
                merchant_id,
                connector_label,
                connector_webhook_details,
            )
            .await
            .change_context(ConnectorError::WebhookSourceVerificationFailed)?;

        let signature = self
            .get_webhook_source_verification_signature(request, &connector_webhook_secrets)
            .change_context(ConnectorError::WebhookSourceVerificationFailed)?;

        let message = self
            .get_webhook_source_verification_message(
                request,
                merchant_id,
                &connector_webhook_secrets,
            )
            .change_context(ConnectorError::WebhookSourceVerificationFailed)?;

        let signing_key = hmac::Key::new(hmac::HMAC_SHA256, &connector_webhook_secrets.secret);
        let signed_message = hmac::sign(&signing_key, &message);
        let payload_sign = BASE64_ENGINE.encode(signed_message.as_ref());
        Ok(payload_sign.as_bytes().eq(&signature))
    }

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

    fn get_webhook_object_reference_id(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<ObjectReferenceId, ConnectorError> {
        let resource: riskified::RiskifiedWebhookBody = request
            .body
            .parse_struct("RiskifiedWebhookBody")
            .change_context(ConnectorError::WebhookReferenceIdNotFound)?;
        Ok(ObjectReferenceId::PaymentId(
            api_models::payments::PaymentIdType::PaymentAttemptId(resource.id),
        ))
    }

    fn get_webhook_event_type(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, ConnectorError> {
        let resource: riskified::RiskifiedWebhookBody = request
            .body
            .parse_struct("RiskifiedWebhookBody")
            .change_context(ConnectorError::WebhookEventTypeNotFound)?;
        Ok(IncomingWebhookEvent::from(resource.status))
    }

    fn get_webhook_resource_object(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, ConnectorError> {
        let resource: riskified::RiskifiedWebhookBody = request
            .body
            .parse_struct("RiskifiedWebhookBody")
            .change_context(ConnectorError::WebhookResourceObjectNotFound)?;
        Ok(Box::new(resource))
    }
}

static RISKIFIED_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Riskified",
    description: "Riskified fraud and risk management provider with guaranteed real-time decisions and machine learning-powered ecommerce fraud prevention",
    connector_type: common_enums::HyperswitchConnectorCategory::FraudAndRiskManagementProvider,
    integration_status: common_enums::ConnectorIntegrationStatus::Sandbox,
};

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

    fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
        None
    }

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


pub async fn link_de_euclid_routing_algorithm(
    state: &SessionState,
    routing_request: ActivateRoutingConfigRequest,
) -> RoutingResult<()> {
    logger::debug!("decision_engine_euclid: link api call for euclid routing algorithm");

    EuclidApiClient::send_decision_engine_request::<_, String>(
        state,
        services::Method::Post,
        "routing/activate",
        Some(routing_request.clone()),
        Some(EUCLID_API_TIMEOUT),
        None,
    )
    .await?;

    logger::debug!(decision_engine_euclid_activated=?routing_request, "decision_engine_euclid: link_de_euclid_routing_algorithm completed");
    Ok(())
}


                    message: error_code.clone(),
                    reason: Some(error_code),
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                });
                (item.data.status, response)
            }
            (Some(_), Some(_)) | (None, None) => {
                Err(errors::ConnectorError::ResponseHandlingFailed)?
            }
        };

        Ok(Self {
            status,
            response,
            ..item.data
        })
    }
}

pub fn build_refund_sync_request(item: &RefundSyncRouterData) -> Result<Vec<u8>, Error> {
    let transaction_type = transaction_type::REFUND.to_owned();
    let auth = RedsysAuthType::try_from(&item.connector_auth_type)?;
    let connector_transaction_id = item.request.connector_transaction_id.clone();
    construct_sync_request(connector_transaction_id, transaction_type, auth)
}

impl TryFrom<RefundsResponseRouterData<RSync, RedsysSyncResponse>> for RefundsRouterData<RSync> {
    type Error = Error;
    fn try_from(
        item: RefundsResponseRouterData<RSync, RedsysSyncResponse>,
    ) -> Result<Self, Self::Error> {
        let message_data = item
            .response
            .body
            .consultaoperacionesresponse
            .consultaoperacionesreturn
            .messages
            .version
            .message;
        let response = match (message_data.response, message_data.errormsg) {
            (None, Some(errormsg)) => {
                let error_code = errormsg.ds_errorcode.clone();
                Err(ErrorResponse {
                    code: error_code.clone(),
                    message: error_code.clone(),
                    reason: Some(error_code),
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                })
            }
            (Some(response), None) => {
                if let Some(ds_response) = response.ds_response {
                    let refund_status = enums::RefundStatus::try_from(ds_response.clone())?;

                    if connector_utils::is_refund_failure(refund_status) {
                        Err(ErrorResponse {
                            status_code: item.http_code,
                            code: ds_response.0.clone(),
                            message: ds_response.0.clone(),
                            reason: Some(ds_response.0.clone()),
                            attempt_status: None,
                            connector_transaction_id: None,
                            network_advice_code: None,
                            network_decline_code: None,
                            network_error_message: None,
                            connector_metadata: None,
                        })
                    } else {
                        Ok(RefundsResponseData {
                            connector_refund_id: response.ds_order,
                            refund_status,
                        })
                    }
                } else {
                    // When the refund is pending
                    Ok(RefundsResponseData {
                        connector_refund_id: response.ds_order,
                        refund_status: enums::RefundStatus::Pending,
                    })
                }
            }
            (Some(_), Some(_)) | (None, None) => {
                Err(errors::ConnectorError::ResponseHandlingFailed)?
            }
        };

        Ok(Self {
            response,
            ..item.data
        })
    }
}


pub struct CryptopayPaymentsRequest {
    price_amount: StringMajorUnit,
    price_currency: enums::Currency,
    pay_currency: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    network: Option<String>,
    success_redirect_url: Option<String>,
    unsuccess_redirect_url: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    metadata: Option<pii::SecretSerdeValue>,
    custom_id: String,
}


pub async fn convert_forex(
    state: web::Data<AppState>,
    req: HttpRequest,
    params: web::Query<api_models::currency::CurrencyConversionParams>,
) -> HttpResponse {
    let flow = Flow::RetrieveForexFlow;
    let amount = params.amount;
    let to_currency = &params.to_currency;
    let from_currency = &params.from_currency;
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        (),
        |state, _: auth::AuthenticationData, _, _| {
            currency::convert_forex(
                state,
                amount.get_amount_as_i64(),
                to_currency.to_string(),
                from_currency.to_string(),
            )
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::DashboardNoPermissionAuth,
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl Responder {
    Box::pin(oss_api::server_wrap(
        Flow::RoutingRetrieveDefaultConfig,
        state,
        &req,
        (),
        |state, auth: auth::AuthenticationData, _, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            routing::retrieve_default_routing_config_for_profiles(
                state,
                merchant_context,
                transaction_type,
            )
        },
        #[cfg(not(feature = "release"))]
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuth {
                permission: Permission::MerchantRoutingRead,
            },
            req.headers(),
        ),
        #[cfg(feature = "release")]
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuth {
                permission: Permission::MerchantRoutingRead,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub async fn find_payment_intent_from_mandate_id_type(
    state: &SessionState,
    mandate_id_type: webhooks::MandateIdType,
    merchant_context: &domain::MerchantContext,
) -> CustomResult<PaymentIntent, errors::ApiErrorResponse> {
    let db = &*state.store;
    let mandate = match mandate_id_type {
        webhooks::MandateIdType::MandateId(mandate_id) => db
            .find_mandate_by_merchant_id_mandate_id(
                merchant_context.get_merchant_account().get_id(),
                mandate_id.as_str(),
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::MandateNotFound)?,
        webhooks::MandateIdType::ConnectorMandateId(connector_mandate_id) => db
            .find_mandate_by_merchant_id_connector_mandate_id(
                merchant_context.get_merchant_account().get_id(),
                connector_mandate_id.as_str(),
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::MandateNotFound)?,
    };
    db.find_payment_intent_by_payment_id_merchant_id(
        &state.into(),
        &mandate
            .original_payment_id
            .ok_or(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("original_payment_id not present in mandate record")?,
        merchant_context.get_merchant_account().get_id(),
        merchant_context.get_merchant_key_store(),
        merchant_context.get_merchant_account().storage_scheme,
    )
    .await
    .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
}


impl api::PaymentCapture for Checkout {}

impl api::PaymentCapture for for Checkout


pub struct ConnectorParamsWithThreeUrls {
    /// base url
    pub base_url: String,
    /// secondary base url
    pub secondary_base_url: String,
    /// third base url
    pub third_base_url: String,
}


pub fn server(state: AppState) -> Scope {
        web::scope("/account/{account_id}/profile").app_data(web::Data::new(state))
    }


pub struct Error {
    pub code: String,
    pub message: String,
}


pub struct WebhookRefundEntity {
//     pub id: String,
//     pub status: RazorpayWebhookRefundEvent,
// }


pub fn from_bytes(val: Vec<u8>) -> Self {
        Self {
            inner: FredRedisValue::Bytes(val.into()),
        }
    }


pub async fn retrieve_routing_config_under_profile(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    query_params: RoutingRetrieveQuery,
    profile_id: common_utils::id_type::ProfileId,
    transaction_type: &enums::TransactionType,
) -> RouterResponse<routing_types::LinkedRoutingConfigRetrieveResponse> {
    metrics::ROUTING_RETRIEVE_LINK_CONFIG.add(1, &[]);
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let business_profile = core_utils::validate_and_get_business_profile(
        db,
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        Some(&profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")?;

    let record = db
        .list_routing_algorithm_metadata_by_profile_id(
            business_profile.get_id(),
            i64::from(query_params.limit.unwrap_or_default()),
            i64::from(query_params.offset.unwrap_or_default()),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;

    let active_algorithms = record
        .into_iter()
        .filter(|routing_rec| &routing_rec.algorithm_for == transaction_type)
        .map(|routing_algo| routing_algo.foreign_into())
        .collect::<Vec<_>>();

    metrics::ROUTING_RETRIEVE_LINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
    Ok(service_api::ApplicationResponse::Json(
        routing_types::LinkedRoutingConfigRetrieveResponse::ProfileBased(active_algorithms),
    ))
}


impl api::PaymentSession for Boku {}


pub struct GatewayStatusMapperUpdateInternal {
    pub connector: Option<String>,
    pub flow: Option<String>,
    pub sub_flow: Option<String>,
    pub code: Option<String>,
    pub message: Option<String>,
    pub status: Option<String>,
    pub router_error: Option<Option<String>>,
    pub decision: Option<String>,
    pub step_up_possible: Option<bool>,
    pub unified_code: Option<String>,
    pub unified_message: Option<String>,
    pub error_category: Option<ErrorCategory>,
    pub last_modified: PrimitiveDateTime,
    pub clear_pan_possible: Option<bool>,
    pub feature_data: Option<common_types::domain::GsmFeatureData>,
    pub feature: Option<common_enums::GsmFeature>,
}


impl<Secret: ZeroizableSecret, MaskingStrategy> Drop for StrongSecret<Secret, MaskingStrategy> {
    fn drop(&mut self) {
        self.inner_secret.zeroize();
    }
}


pub fn new() -> &'static Self {
        &Self {
            amount_converter: &StringMajorUnitForConnector,
        }
    }


pub struct CreateDynamicRoutingWrapper {
    pub profile_id: common_utils::id_type::ProfileId,
    pub feature_to_enable: DynamicRoutingFeatures,
    pub payload: DynamicRoutingPayload,
}


Web Documentation: Intelligent Routing | Hyperswitch
# Type: Web Doc

The Hyperswitch Intelligent Routing module augments your payment processing by dynamically switching between processors in real-time for every transaction to optimally maximise first attempt auth rates and minimise processing cost.
Types of Intelligent Routing
Hyperswitch supports four intelligent routing strategies:
Auth Rate Based Routing:
Uses real-time success rates and ML-driven optimisation to route transactions to the best-performing gateway.
The Auth Rates for the payments are tracked at a granular level of payment parameters like payment method, payment method type, amount, currency, authentication type, card network etc.
The model
uses a Multi-Armed Bandit (MAB) problem with Delayed Feedback, where each Gateway is an "arm" with fluctuating success rates and varying latency for success and failure. The approach used to solve this problem is driven by
explore-exploit
strategy.
Exploration:
We continuously evaluate all gateways by sending a small percentage of traffic to ensure up-to-date performance data.
Exploitation:
We continuously route most traffic to the best-performing Gateway to maximise the overall success rate.
The sensitivity of the system can be tweaked by the merchants by configuring settings such as Bucket Sizes, Parameters to be considered and Hedging Percentage
The hedging percentage decides the exploration factor of the model
Least Cost Routing:
Picks the least cost network for every transaction basis the availability of back-of-the-card network and processor compatibility
Elimination Routing:
Tracks acute incidents such as downtimes and technical errors to de-prioritise gateways. This will be used as a final check after other routing logics are applied.
Contracts-Based Routing:
Distributes payments across processors to meet contractual volume commitments. [BETA FEATURE]
Architecture Diagram
Self Deploy the Routing Engine
Using Auth Rate based Routing for Hyperswitch
29 days ago
Was this helpful?

Intelligent Routing | Hyperswitch


pub struct HelcimLineItems {
    description: String,
    quantity: u8,
    price: FloatMajorUnit,
    total: FloatMajorUnit,
}


pub async fn perform_surcharge_decision_management_for_saved_cards(
//     state: &SessionState,
//     algorithm_ref: routing::RoutingAlgorithmRef,
//     payment_attempt: &storage::PaymentAttempt,
//     payment_intent: &storage::PaymentIntent,
//     customer_payment_method_list: &mut [api_models::payment_methods::CustomerPaymentMethod],
// ) -> ConditionalConfigResult<types::SurchargeMetadata> {
//     // let mut surcharge_metadata = types::SurchargeMetadata::new(payment_attempt.id.clone());
//     let mut surcharge_metadata = todo!();

//     let surcharge_source = match (
//         payment_attempt.get_surcharge_details(),
//         algorithm_ref.surcharge_config_algo_id,
//     ) {
//         (Some(request_surcharge_details), _) => {
//             SurchargeSource::Predetermined(request_surcharge_details)
//         }
//         (None, Some(algorithm_id)) => {
//             let cached_algo = ensure_algorithm_cached(
//                 &*state.store,
//                 &payment_attempt.merchant_id,
//                 algorithm_id.as_str(),
//             )
//             .await?;

//             SurchargeSource::Generate(cached_algo)
//         }
//         (None, None) => return Ok(surcharge_metadata),
//     };
//     let surcharge_source_log_message = match &surcharge_source {
//         SurchargeSource::Generate(_) => "Surcharge was calculated through surcharge rules",
//         SurchargeSource::Predetermined(_) => "Surcharge was sent in payment create request",
//     };
//     logger::debug!(customer_saved_card_list_surcharge_source = surcharge_source_log_message);
//     let mut backend_input = make_dsl_input_for_surcharge(payment_attempt, payment_intent, None)
//         .change_context(ConfigError::InputConstructionError)?;

//     for customer_payment_method in customer_payment_method_list.iter_mut() {
//         let payment_token = customer_payment_method
//             .payment_token
//             .clone()
//             .get_required_value("payment_token")
//             .change_context(ConfigError::InputConstructionError)?;

//         backend_input.payment_method.payment_method =
//             Some(customer_payment_method.payment_method_type);
//         backend_input.payment_method.payment_method_type =
//             customer_payment_method.payment_method_subtype;

//         let card_network = match customer_payment_method.payment_method_data.as_ref() {
//             Some(api_models::payment_methods::PaymentMethodListData::Card(card)) => {
//                 card.card_network.clone()
//             }
//             _ => None,
//         };
//         backend_input.payment_method.card_network = card_network;

//         let surcharge_details = surcharge_source
//             .generate_surcharge_details_and_populate_surcharge_metadata(
//                 &backend_input,
//                 payment_attempt,
//                 (
//                     &mut surcharge_metadata,
//                     types::SurchargeKey::Token(payment_token),
//                 ),
//             )?;
//         customer_payment_method.surcharge_details = surcharge_details
//             .map(|surcharge_details| {
//                 SurchargeDetailsResponse::foreign_try_from((&surcharge_details, payment_attempt))
//                     .change_context(ConfigError::DslParsingError)
//             })
//             .transpose()?;
//     }
//     Ok(surcharge_metadata)
// }


impl ToTokens for SchemaParameterVariant {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            Self::ValueType { keyword, .. } => keyword.to_tokens(tokens),
            Self::MinLength { keyword, .. } => keyword.to_tokens(tokens),
            Self::MaxLength { keyword, .. } => keyword.to_tokens(tokens),
            Self::Example { keyword, .. } => keyword.to_tokens(tokens),
        }
    }
}

impl ToTokens for for SchemaParameterVariant


pub struct NovalnetPaymentsResponseTransactionData {
    pub amount: Option<MinorUnit>,
    pub currency: Option<common_enums::Currency>,
    pub date: Option<String>,
    pub order_no: Option<String>,
    pub payment_data: Option<NovalnetResponsePaymentData>,
    pub payment_type: Option<String>,
    pub status_code: Option<u64>,
    pub txn_secret: Option<Secret<String>>,
    pub tid: Option<Secret<i64>>,
    pub test_mode: Option<i8>,
    pub status: Option<NovalnetTransactionStatus>,
    pub authorization: Option<NovalnetAuthorizationResponse>,
}


pub struct ConnectorResponseData {
    pub additional_payment_method_data: Option<AdditionalPaymentMethodConnectorResponse>,
    extended_authorization_response_data: Option<ExtendedAuthorizationResponseData>,
}


OpenAPI Block Path: paths."/routing/feedback"
{
  "post": {
    "tags": [
      "Routing"
    ],
    "summary": "Routing - Feedback",
    "description": "Update gateway scores for dynamic routing",
    "operationId": "Update gateway scores",
    "requestBody": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/UpdateScorePayload"
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "description": "Gateway score updated successfully",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UpdateScoreResponse"
            }
          }
        }
      },
      "400": {
        "description": "Request body is malformed"
      },
      "403": {
        "description": "Forbidden"
      },
      "404": {
        "description": "Resource missing"
      },
      "422": {
        "description": "Unprocessable request"
      },
      "500": {
        "description": "Internal server error"
      }
    },
    "security": [
      {
        "api_key": []
      }
    ]
  }
}


impl Nmi {
    pub const fn new() -> &'static Self {
        &Self {
            amount_converter: &FloatMajorUnitForConnector,
        }
    }
}


File: crates/openapi/src/routes/refunds.rs
 Public functions: 11

/// Refunds - Create
///
/// Creates a refund against an already processed payment. In case of some processors, you can even opt to refund only a partial amount multiple times until the original charge amount has been refunded
#[utoipa::path(
    post,
    path = "/refunds",
    request_body(
        content = RefundRequest,
        examples(
            (
                "Create an instant refund to refund the whole amount" = (
                    value = json!({
                        "payment_id": "{{payment_id}}",
                        "refund_type": "instant"
                      })
                )
            ),
            (
                "Create an instant refund to refund partial amount" = (
                    value = json!({
                        "payment_id": "{{payment_id}}",
                        "refund_type": "instant",
                        "amount": 654
                      })
                )
            ),
            (
                "Create an instant refund with reason" = (
                    value = json!({
                        "payment_id": "{{payment_id}}",
                        "refund_type": "instant",
                        "amount": 6540,
                        "reason": "Customer returned product"
                      })
                )
            ),
        )
    ),
    responses(
        (status = 200, description = "Refund created", body = RefundResponse),
        (status = 400, description = "Missing Mandatory fields", body = GenericErrorResponseOpenApi)
    ),
    tag = "Refunds",
    operation_id = "Create a Refund",
    security(("api_key" = []))
)]
#[cfg(feature = "v1")]
pub async fn refunds_create() {}

/// Refunds - Retrieve
///
/// Retrieves a Refund. This may be used to get the status of a previously initiated refund
#[utoipa::path(
    get,
    path = "/refunds/{refund_id}",
    params(
        ("refund_id" = String, Path, description = "The identifier for refund")
    ),
    responses(
        (status = 200, description = "Refund retrieved", body = RefundResponse),
        (status = 404, description = "Refund does not exist in our records")
    ),
    tag = "Refunds",
    operation_id = "Retrieve a Refund",
    security(("api_key" = []))
)]
#[cfg(feature = "v1")]
pub async fn refunds_retrieve() {}

/// Refunds - Retrieve (POST)
///
/// To retrieve the properties of a Refund. This may be used to get the status of a previously initiated payment or next action for an ongoing payment
#[utoipa::path(
    get,
    path = "/refunds/sync",
    responses(
        (status = 200, description = "Refund retrieved", body = RefundResponse),
        (status = 404, description = "Refund does not exist in our records")
    ),
    tag = "Refunds",
    operation_id = "Retrieve a Refund",
    security(("api_key" = []))
)]
pub async fn refunds_retrieve_with_body() {}

/// Refunds - Update
///
/// Updates the properties of a Refund object. This API can be used to attach a reason for the refund or metadata fields
#[utoipa::path(
    post,
    path = "/refunds/{refund_id}",
    params(
        ("refund_id" = String, Path, description = "The identifier for refund")
    ),
    request_body(
        content = RefundUpdateRequest,
        examples(
            (
                "Update refund reason" = (
                    value = json!({
                        "reason": "Paid by mistake"
                      })
                )
            ),
        )
    ),
    responses(
        (status = 200, description = "Refund updated", body = RefundResponse),
        (status = 400, description = "Missing Mandatory fields", body = GenericErrorResponseOpenApi)
    ),
    tag = "Refunds",
    operation_id = "Update a Refund",
    security(("api_key" = []))
)]
#[cfg(feature = "v1")]
pub async fn refunds_update() {}

/// Refunds - List
///
/// Lists all the refunds associated with the merchant, or for a specific payment if payment_id is provided
#[utoipa::path(
    post,
    path = "/refunds/list",
    request_body=RefundListRequest,
    responses(
        (status = 200, description = "List of refunds", body = RefundListResponse),
    ),
    tag = "Refunds",
    operation_id = "List all Refunds",
    security(("api_key" = []))
)]
#[cfg(feature = "v1")]
pub fn refunds_list() {}

/// Refunds - List For the Given profiles
///
/// Lists all the refunds associated with the merchant or a payment_id if payment_id is not provided
#[utoipa::path(
    post,
    path = "/refunds/profile/list",
    request_body=RefundListRequest,
    responses(
        (status = 200, description = "List of refunds", body = RefundListResponse),
    ),
    tag = "Refunds",
    operation_id = "List all Refunds for the given Profiles",
    security(("api_key" = []))
)]
pub fn refunds_list_profile() {}

/// Refunds - Filter
///
/// To list the refunds filters associated with list of connectors, currencies and payment statuses
#[utoipa::path(
    post,
    path = "/refunds/filter",
    request_body=TimeRange,
    responses(
        (status = 200, description = "List of filters", body = RefundListMetaData),
    ),
    tag = "Refunds",
    operation_id = "List all filters for Refunds",
    security(("api_key" = []))
)]
pub async fn refunds_filter_list() {}

/// Refunds - Create
///
/// Creates a refund against an already processed payment. In case of some processors, you can even opt to refund only a partial amount multiple times until the original charge amount has been refunded
#[utoipa::path(
    post,
    path = "/v2/refunds",
    request_body(
        content = RefundsCreateRequest,
        examples(
            (
                "Create an instant refund to refund the whole amount" = (
                    value = json!({
                        "payment_id": "{{payment_id}}",
                        "merchant_reference_id": "ref_123",
                        "refund_type": "instant"
                      })
                )
            ),
            (
                "Create an instant refund to refund partial amount" = (
                    value = json!({
                        "payment_id": "{{payment_id}}",
                        "merchant_reference_id": "ref_123",
                        "refund_type": "instant",
                        "amount": 654
                      })
                )
            ),
            (
                "Create an instant refund with reason" = (
                    value = json!({
                        "payment_id": "{{payment_id}}",
                        "merchant_reference_id": "ref_123",
                        "refund_type": "instant",
                        "amount": 6540,
                        "reason": "Customer returned product"
                      })
                )
            ),
        )
    ),
    responses(
        (status = 200, description = "Refund created", body = RefundResponse),
        (status = 400, description = "Missing Mandatory fields", body = GenericErrorResponseOpenApi)
    ),
    tag = "Refunds",
    operation_id = "Create a Refund",
    security(("api_key" = []))
)]
#[cfg(feature = "v2")]
pub async fn refunds_create() {}

/// Refunds - Metadata Update
///
/// Updates the properties of a Refund object. This API can be used to attach a reason for the refund or metadata fields
#[utoipa::path(
    put,
    path = "/v2/refunds/{id}/update-metadata",
    params(
        ("id" = String, Path, description = "The identifier for refund")
    ),
    request_body(
        content = RefundMetadataUpdateRequest,
        examples(
            (
                "Update refund reason" = (
                    value = json!({
                        "reason": "Paid by mistake"
                      })
                )
            )
        )
    ),
    responses(
        (status = 200, description = "Refund updated", body = RefundResponse),
        (status = 400, description = "Missing Mandatory fields", body = GenericErrorResponseOpenApi)
    ),
    tag = "Refunds",
    operation_id = "Update Refund Metadata and Reason",
    security(("api_key" = []))
)]
#[cfg(feature = "v2")]
pub async fn refunds_metadata_update() {}

/// Refunds - Retrieve
///
/// Retrieves a Refund. This may be used to get the status of a previously initiated refund
#[utoipa::path(
    get,
    path = "/v2/refunds/{id}",
    params(
        ("id" = String, Path, description = "The identifier for refund")
    ),
    responses(
        (status = 200, description = "Refund retrieved", body = RefundResponse),
        (status = 404, description = "Refund does not exist in our records")
    ),
    tag = "Refunds",
    operation_id = "Retrieve a Refund",
    security(("api_key" = []))
)]
#[cfg(feature = "v2")]
pub async fn refunds_retrieve() {}

/// Refunds - List
///
/// To list the refunds associated with a payment_id or with the merchant, if payment_id is not provided
#[utoipa::path(
    post,
    path = "/v2/refunds/list",
    request_body=RefundListRequest,
    responses(
        (status = 200, description = "List of refunds", body = RefundListResponse),
    ),
    tag = "Refunds",
    operation_id = "List all Refunds",
    security(("api_key" = []))
)]
#[cfg(feature = "v2")]
pub fn refunds_list() {}


pub struct Address {
///     line1: String,
///     line2: String,
///     zip: String,
/// }


impl TotalEventsResponse {
    pub fn new(total_count: i64, events: Vec<EventListItemResponse>) -> Self {
        Self {
            events,
            total_count,
        }
    }
}


impl api::PaymentCapture for Breadpay {}

impl api::PaymentCapture for for Breadpay