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

pub mod transformers;
use std::{fmt::Write, sync::LazyLock};

use base64::Engine;
use common_enums::{enums, CallConnectorAction, PaymentAction};
use common_utils::{
    consts,
    errors::CustomResult,
    ext_traits::ByteSliceExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{
        AmountConvertor, MinorUnit, StringMajorUnit, StringMajorUnitForConnector, StringMinorUnit,
        StringMinorUnitForConnector,
    },
};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    payment_method_data::{PaymentMethodData, WalletData},
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{
            Authorize, Capture, IncrementalAuthorization, PSync, PaymentMethodToken,
            PostSessionTokens, PreProcessing, SdkSessionUpdate, Session, SetupMandate, Void,
        },
        refunds::{Execute, RSync},
        CompleteAuthorize, VerifyWebhookSource,
    },
    router_request_types::{
        AccessTokenRequestData, CompleteAuthorizeData, PaymentMethodTokenizationData,
        PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData,
        PaymentsIncrementalAuthorizationData, PaymentsPostSessionTokensData,
        PaymentsPreProcessingData, PaymentsSessionData, PaymentsSyncData, RefundsData, ResponseId,
        SdkPaymentsSessionUpdateData, SetupMandateRequestData, VerifyWebhookSourceRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt, VerifyWebhookSourceResponseData,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsCompleteAuthorizeRouterData, PaymentsIncrementalAuthorizationRouterData,
        PaymentsPostSessionTokensRouterData, PaymentsPreProcessingRouterData,
        PaymentsSyncRouterData, RefreshTokenRouterData, RefundSyncRouterData, RefundsRouterData,
        SdkSessionUpdateRouterData, SetupMandateRouterData, VerifyWebhookSourceRouterData,
    },
};
#[cfg(feature = "payouts")]
use hyperswitch_domain_models::{
    router_flow_types::payouts::{PoCreate, PoFulfill, PoSync},
    router_response_types::PayoutsResponseData,
    types::{PayoutsData, PayoutsRouterData},
};
#[cfg(feature = "payouts")]
use hyperswitch_interfaces::types::{PayoutFulfillType, PayoutSyncType};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorRedirectResponse,
        ConnectorSpecifications, ConnectorValidation, PaymentIncrementalAuthorization,
    },
    configs::Connectors,
    consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE},
    disputes, errors,
    events::connector_api_logs::ConnectorEvent,
    types::{
        IncrementalAuthorizationType, PaymentsAuthorizeType, PaymentsCaptureType,
        PaymentsCompleteAuthorizeType, PaymentsPostSessionTokensType, PaymentsPreProcessingType,
        PaymentsSyncType, PaymentsVoidType, RefreshTokenType, RefundExecuteType, RefundSyncType,
        Response, SdkSessionUpdateType, SetupMandateType, VerifyWebhookSourceType,
    },
    webhooks::{IncomingWebhook, IncomingWebhookRequestDetails},
};
use masking::{ExposeInterface, Mask, Maskable, PeekInterface, Secret};
#[cfg(feature = "payouts")]
use router_env::{instrument, tracing};
use transformers::{
    self as paypal, auth_headers, PaypalAuthResponse, PaypalIncrementalAuthResponse, PaypalMeta,
    PaypalWebhookEventType,
};

use crate::{
    constants::{self, headers},
    types::ResponseRouterData,
    utils::{
        self as connector_utils, to_connector_meta, ConnectorErrorType, ConnectorErrorTypeMapping,
        ForeignTryFrom, PaymentMethodDataType, PaymentsAuthorizeRequestData,
        PaymentsCompleteAuthorizeRequestData, RefundsRequestData,
    },
};

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

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

impl api::Payment for Paypal {}
impl api::PaymentSession for Paypal {}
impl api::PaymentToken for Paypal {}
impl api::ConnectorAccessToken for Paypal {}
impl api::MandateSetup for Paypal {}
impl api::PaymentAuthorize for Paypal {}
impl api::PaymentsCompleteAuthorize for Paypal {}
impl api::PaymentSync for Paypal {}
impl api::PaymentCapture for Paypal {}
impl api::PaymentVoid for Paypal {}
impl api::Refund for Paypal {}
impl api::RefundExecute for Paypal {}
impl api::RefundSync for Paypal {}
impl api::ConnectorVerifyWebhookSource for Paypal {}
impl api::PaymentPostSessionTokens for Paypal {}
impl api::PaymentSessionUpdate for Paypal {}

impl api::Payouts for Paypal {}
#[cfg(feature = "payouts")]
impl api::PayoutCreate for Paypal {}
#[cfg(feature = "payouts")]
impl api::PayoutFulfill for Paypal {}
#[cfg(feature = "payouts")]
impl api::PayoutSync for Paypal {}

impl Paypal {
    pub fn get_order_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        //Handled error response separately for Orders as the end point is different for Orders - (Authorize) and Payments - (Capture, void, refund, rsync).
        //Error response have different fields for Orders and Payments.
        let response: paypal::PaypalOrderErrorResponse = res
            .response
            .parse_struct("Paypal ErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

        let error_reason = response.details.clone().map(|order_errors| {
            order_errors
                .iter()
                .map(|error| {
                    let mut reason = format!("description - {}", error.description);
                    if let Some(value) = &error.value {
                        reason.push_str(&format!(", value - {value}"));
                    }
                    if let Some(field) = error
                        .field
                        .as_ref()
                        .and_then(|field| field.split('/').next_back())
                    {
                        reason.push_str(&format!(", field - {field}"));
                    }
                    reason.push(';');
                    reason
                })
                .collect::<String>()
        });
        let errors_list = response.details.unwrap_or_default();
        let option_error_code_message =
            connector_utils::get_error_code_error_message_based_on_priority(
                self.clone(),
                errors_list
                    .into_iter()
                    .map(|errors| errors.into())
                    .collect(),
            );
        Ok(ErrorResponse {
            status_code: res.status_code,
            code: option_error_code_message
                .clone()
                .map(|error_code_message| error_code_message.error_code)
                .unwrap_or(NO_ERROR_CODE.to_string()),
            message: option_error_code_message
                .map(|error_code_message| error_code_message.error_message)
                .unwrap_or(NO_ERROR_MESSAGE.to_string()),
            reason: error_reason.or(Some(response.message)),
            attempt_status: None,
            connector_transaction_id: response.debug_id,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Paypal
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        let access_token = req
            .access_token
            .clone()
            .ok_or(errors::ConnectorError::FailedToObtainAuthType)?;
        let key = &req.connector_request_reference_id;
        let auth = paypal::PaypalAuthType::try_from(&req.connector_auth_type)?;
        let mut headers = vec![
            (
                headers::CONTENT_TYPE.to_string(),
                self.get_content_type().to_string().into(),
            ),
            (
                headers::AUTHORIZATION.to_string(),
                format!("Bearer {}", access_token.token.peek()).into_masked(),
            ),
            (
                auth_headers::PREFER.to_string(),
                "return=representation".to_string().into(),
            ),
            (
                auth_headers::PAYPAL_REQUEST_ID.to_string(),
                key.to_string().into_masked(),
            ),
        ];
        if let Ok(paypal::PaypalConnectorCredentials::PartnerIntegration(credentials)) =
            auth.get_credentials()
        {
            let auth_assertion_header =
                construct_auth_assertion_header(&credentials.payer_id, &credentials.client_id);
            headers.extend(vec![
                (
                    auth_headers::PAYPAL_AUTH_ASSERTION.to_string(),
                    auth_assertion_header.to_string().into_masked(),
                ),
                (
                    auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(),
                    "HyperSwitchPPCP_SP".to_string().into(),
                ),
            ])
        } else {
            headers.extend(vec![(
                auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(),
                "HyperSwitchlegacy_Ecom".to_string().into(),
            )])
        }
        Ok(headers)
    }
}

fn construct_auth_assertion_header(
    payer_id: &Secret<String>,
    client_id: &Secret<String>,
) -> String {
    let algorithm = consts::BASE64_ENGINE
        .encode("{\"alg\":\"none\"}")
        .to_string();
    let merchant_credentials = format!(
        "{{\"iss\":\"{}\",\"payer_id\":\"{}\"}}",
        client_id.clone().expose(),
        payer_id.clone().expose()
    );
    let encoded_credentials = consts::BASE64_ENGINE
        .encode(merchant_credentials)
        .to_string();
    format!("{algorithm}.{encoded_credentials}.")
}

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

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

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

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

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        let auth = paypal::PaypalAuthType::try_from(auth_type)?;
        let credentials = auth.get_credentials()?;

        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            credentials.get_client_secret().into_masked(),
        )])
    }

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

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

        let error_reason = response
            .details
            .clone()
            .map(|error_details| {
                error_details
                    .iter()
                    .try_fold(String::new(), |mut acc, error| {
                        if let Some(description) = &error.description {
                            write!(acc, "description - {description} ;")
                                .change_context(
                                    errors::ConnectorError::ResponseDeserializationFailed,
                                )
                                .attach_printable("Failed to concatenate error details")
                                .map(|_| acc)
                        } else {
                            Ok(acc)
                        }
                    })
            })
            .transpose()?;
        let reason = match error_reason {
            Some(err_reason) => err_reason
                .is_empty()
                .then(|| response.message.to_owned())
                .or(Some(err_reason)),
            None => Some(response.message.to_owned()),
        };
        let errors_list = response.details.unwrap_or_default();
        let option_error_code_message =
            connector_utils::get_error_code_error_message_based_on_priority(
                self.clone(),
                errors_list
                    .into_iter()
                    .map(|errors| errors.into())
                    .collect(),
            );

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: option_error_code_message
                .clone()
                .map(|error_code_message| error_code_message.error_code)
                .unwrap_or(NO_ERROR_CODE.to_string()),
            message: option_error_code_message
                .map(|error_code_message| error_code_message.error_message)
                .unwrap_or(NO_ERROR_MESSAGE.to_string()),
            reason,
            attempt_status: None,
            connector_transaction_id: response.debug_id,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorValidation for Paypal {
    fn validate_mandate_payment(
        &self,
        pm_type: Option<enums::PaymentMethodType>,
        pm_data: PaymentMethodData,
    ) -> CustomResult<(), errors::ConnectorError> {
        let mandate_supported_pmd = std::collections::HashSet::from([
            PaymentMethodDataType::Card,
            PaymentMethodDataType::PaypalRedirect,
            PaymentMethodDataType::PaypalSdk,
        ]);
        connector_utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id())
    }
}

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

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

impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Paypal {
    fn get_url(
        &self,
        _req: &RefreshTokenRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}v1/oauth2/token", self.base_url(connectors)))
    }
    fn get_content_type(&self) -> &'static str {
        "application/x-www-form-urlencoded"
    }
    fn get_headers(
        &self,
        req: &RefreshTokenRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        let auth = paypal::PaypalAuthType::try_from(&req.connector_auth_type)?;
        let credentials = auth.get_credentials()?;
        let auth_val = credentials.generate_authorization_value();

        Ok(vec![
            (
                headers::CONTENT_TYPE.to_string(),
                RefreshTokenType::get_content_type(self).to_string().into(),
            ),
            (headers::AUTHORIZATION.to_string(), auth_val.into_masked()),
        ])
    }
    fn get_request_body(
        &self,
        req: &RefreshTokenRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = paypal::PaypalAuthUpdateRequest::try_from(req)?;

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

    fn build_request(
        &self,
        req: &RefreshTokenRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let req = Some(
            RequestBuilder::new()
                .method(Method::Post)
                .headers(RefreshTokenType::get_headers(self, req, connectors)?)
                .url(&RefreshTokenType::get_url(self, req, connectors)?)
                .set_body(RefreshTokenType::get_request_body(self, req, connectors)?)
                .build(),
        );

        Ok(req)
    }

    fn handle_response(
        &self,
        data: &RefreshTokenRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefreshTokenRouterData, errors::ConnectorError> {
        let response: paypal::PaypalAuthUpdateResponse = res
            .response
            .parse_struct("Paypal PaypalAuthUpdateResponse")
            .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> {
        let response: paypal::PaypalAccessTokenErrorResponse = res
            .response
            .parse_struct("Paypal AccessTokenErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.error.clone(),
            message: response.error.clone(),
            reason: Some(response.error_description),
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

#[cfg(feature = "payouts")]
impl ConnectorIntegration<PoFulfill, PayoutsData, PayoutsResponseData> for Paypal {
    fn get_url(
        &self,
        _req: &PayoutsRouterData<PoFulfill>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}v1/payments/payouts", self.base_url(connectors)))
    }

    fn get_headers(
        &self,
        req: &PayoutsRouterData<PoFulfill>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_request_body(
        &self,
        req: &PayoutsRouterData<PoFulfill>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = connector_utils::convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.destination_currency,
        )?;
        let connector_router_data =
            paypal::PaypalRouterData::try_from((amount, None, None, None, req))?;
        let connector_req = paypal::PaypalFulfillRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PayoutsRouterData<PoFulfill>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&PayoutFulfillType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(PayoutFulfillType::get_headers(self, req, connectors)?)
            .set_body(PayoutFulfillType::get_request_body(self, req, connectors)?)
            .build();

        Ok(Some(request))
    }

    #[instrument(skip_all)]
    fn handle_response(
        &self,
        data: &PayoutsRouterData<PoFulfill>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PayoutsRouterData<PoFulfill>, errors::ConnectorError> {
        let response: paypal::PaypalFulfillResponse = res
            .response
            .parse_struct("PaypalFulfillResponse")
            .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)
    }
}

#[cfg(feature = "payouts")]
impl ConnectorIntegration<PoSync, PayoutsData, PayoutsResponseData> for Paypal {
    fn get_url(
        &self,
        req: &PayoutsRouterData<PoSync>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let batch_id = req.request.connector_payout_id.clone().ok_or(
            errors::ConnectorError::MissingRequiredField {
                field_name: "connector_payout_id",
            },
        )?;
        Ok(format!(
            "{}v1/payments/payouts/{}",
            self.base_url(connectors),
            batch_id
        ))
    }

    fn get_headers(
        &self,
        req: &PayoutsRouterData<PoSync>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn build_request(
        &self,
        req: &PayoutsRouterData<PoSync>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Get)
            .url(&PayoutSyncType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(PayoutSyncType::get_headers(self, req, connectors)?)
            .build();

        Ok(Some(request))
    }

    #[instrument(skip_all)]
    fn handle_response(
        &self,
        data: &PayoutsRouterData<PoSync>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PayoutsRouterData<PoSync>, errors::ConnectorError> {
        let response: paypal::PaypalPayoutSyncResponse = res
            .response
            .parse_struct("PaypalPayoutSyncResponse")
            .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]
#[cfg(feature = "payouts")]
impl ConnectorIntegration<PoCreate, PayoutsData, PayoutsResponseData> for Paypal {
    fn build_request(
        &self,
        _req: &PayoutsRouterData<PoCreate>,
        _connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        // Eligibility check for wallet is not implemented
        Err(
            errors::ConnectorError::NotImplemented("Payout Eligibility for Paypal".to_string())
                .into(),
        )
    }
}

impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData> for Paypal {
    fn get_headers(
        &self,
        req: &SetupMandateRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }
    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }
    fn get_url(
        &self,
        _req: &SetupMandateRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}v3/vault/payment-tokens/",
            self.base_url(connectors)
        ))
    }
    fn get_request_body(
        &self,
        req: &SetupMandateRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = paypal::PaypalZeroMandateRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &SetupMandateRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<SetupMandateRouterData, errors::ConnectorError> {
        let response: paypal::PaypalSetupMandatesResponse = res
            .response
            .parse_struct("PaypalSetupMandatesResponse")
            .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<PostSessionTokens, PaymentsPostSessionTokensData, PaymentsResponseData>
    for Paypal
{
    fn get_headers(
        &self,
        req: &PaymentsPostSessionTokensRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }
    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }
    fn get_url(
        &self,
        _req: &PaymentsPostSessionTokensRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}v2/checkout/orders", self.base_url(connectors)))
    }
    fn build_request(
        &self,
        req: &PaymentsPostSessionTokensRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsPostSessionTokensType::get_url(
                    self, req, connectors,
                )?)
                .attach_default_headers()
                .headers(PaymentsPostSessionTokensType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(PaymentsPostSessionTokensType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsPostSessionTokensRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = connector_utils::convert_amount(
            self.amount_converter,
            req.request.amount,
            req.request.currency,
        )?;
        let shipping_cost = connector_utils::convert_amount(
            self.amount_converter,
            req.request.shipping_cost.unwrap_or(MinorUnit::zero()),
            req.request.currency,
        )?;
        let order_amount = connector_utils::convert_amount(
            self.amount_converter,
            req.request.order_amount,
            req.request.currency,
        )?;
        let connector_router_data = paypal::PaypalRouterData::try_from((
            amount,
            Some(shipping_cost),
            None,
            Some(order_amount),
            req,
        ))?;
        let connector_req = paypal::PaypalPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

impl ConnectorIntegration<SdkSessionUpdate, SdkPaymentsSessionUpdateData, PaymentsResponseData>
    for Paypal
{
    fn get_headers(
        &self,
        req: &SdkSessionUpdateRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

    fn get_url(
        &self,
        req: &SdkSessionUpdateRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let session_id =
            req.request
                .session_id
                .clone()
                .ok_or(errors::ConnectorError::MissingRequiredField {
                    field_name: "session_id",
                })?;
        Ok(format!(
            "{}v2/checkout/orders/{}",
            self.base_url(connectors),
            session_id
        ))
    }

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

    fn get_request_body(
        &self,
        req: &SdkSessionUpdateRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let order_amount = connector_utils::convert_amount(
            self.amount_converter,
            req.request.order_amount,
            req.request.currency,
        )?;
        let amount = connector_utils::convert_amount(
            self.amount_converter,
            req.request.amount,
            req.request.currency,
        )?;
        let order_tax_amount = connector_utils::convert_amount(
            self.amount_converter,
            req.request.order_tax_amount,
            req.request.currency,
        )?;
        let shipping_cost = connector_utils::convert_amount(
            self.amount_converter,
            req.request.shipping_cost.unwrap_or(MinorUnit::zero()),
            req.request.currency,
        )?;
        let connector_router_data = paypal::PaypalRouterData::try_from((
            amount,
            Some(shipping_cost),
            Some(order_tax_amount),
            Some(order_amount),
            req,
        ))?;

        let connector_req = paypal::PaypalUpdateOrderRequest::try_from(&connector_router_data)?;
        // encode only for for urlencoded things.
        Ok(RequestContent::Json(Box::new(
            connector_req.get_inner_value(),
        )))
    }

    fn handle_response(
        &self,
        data: &SdkSessionUpdateRouterData,
        _event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<SdkSessionUpdateRouterData, errors::ConnectorError> {
        router_env::logger::debug!("Expected zero bytes response, skipped parsing of the response");
        // https://developer.paypal.com/docs/api/orders/v2/#orders_patch
        // If 204 status code, then the session was updated successfully.
        let status = if res.status_code == 204 {
            enums::PaymentResourceUpdateStatus::Success
        } else {
            enums::PaymentResourceUpdateStatus::Failure
        };
        Ok(SdkSessionUpdateRouterData {
            response: Ok(PaymentsResponseData::PaymentResourceUpdateResponse { status }),
            ..data.clone()
        })
    }

    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<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Paypal {
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

    fn get_url(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        match &req.request.payment_method_data {
            PaymentMethodData::Wallet(WalletData::PaypalSdk(paypal_wallet_data)) => {
                let authorize_url = if req.request.is_auto_capture()? {
                    "capture".to_string()
                } else {
                    "authorize".to_string()
                };
                Ok(format!(
                    "{}v2/checkout/orders/{}/{authorize_url}",
                    self.base_url(connectors),
                    paypal_wallet_data.token
                ))
            }
            _ => Ok(format!("{}v2/checkout/orders", self.base_url(connectors))),
        }
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = connector_utils::convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.currency,
        )?;
        let shipping_cost = connector_utils::convert_amount(
            self.amount_converter,
            req.request.shipping_cost.unwrap_or(MinorUnit::zero()),
            req.request.currency,
        )?;
        let connector_router_data =
            paypal::PaypalRouterData::try_from((amount, Some(shipping_cost), None, None, req))?;
        let connector_req = paypal::PaypalPaymentsRequest::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> {
        let payment_method_data = req.request.payment_method_data.clone();
        let req = match payment_method_data {
            PaymentMethodData::Wallet(WalletData::PaypalSdk(_)) => RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsAuthorizeType::get_url(self, req, connectors)?)
                .headers(PaymentsAuthorizeType::get_headers(self, req, connectors)?)
                .build(),
            _ => RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsAuthorizeType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsAuthorizeType::get_headers(self, req, connectors)?)
                .set_body(PaymentsAuthorizeType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        };

        Ok(Some(req))
    }

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: PaypalAuthResponse =
            res.response
                .parse_struct("paypal PaypalAuthResponse")
                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        match response {
            PaypalAuthResponse::PaypalOrdersResponse(response) => {
                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,
                })
            }
            PaypalAuthResponse::PaypalRedirectResponse(response) => {
                event_builder.map(|i| i.set_response_body(&response));


pub struct CeleroErrorResponse {
    pub status: CeleroResponseStatus,
    pub msg: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub data: Option<serde_json::Value>,
}


pub struct ConnectorMandateDetails {
    pub connector_mandate_id: masking::Secret<String>,
}


pub struct NuveiRedirectionResponse {
    pub cres: Secret<String>,
}


pub async fn get_role(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
) -> HttpResponse {
    let flow = Flow::GetRole;
    let request_payload = user_role_api::role::GetRoleRequest {
        role_id: path.into_inner(),
    };
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        request_payload,
        |state, user, payload, _| async move {
            role_core::get_role_with_groups(state, user, payload).await
        },
        &auth::JWTAuth {
            permission: Permission::ProfileUserRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub struct ThreedsecureioPostAuthenticationResponse {
    pub authentication_value: Option<Secret<String>>,
    pub trans_status: ThreedsecureioTransStatus,
    pub eci: Option<String>,
}


pub struct PayloadRouterData<T> {
    pub amount: StringMajorUnit,
    pub router_data: T,
}


pub async fn profile_create() {}


pub struct CybersourceAuthEnrollmentRequest {
    payment_information: PaymentInformation,
    client_reference_information: ClientReferenceInformation,
    consumer_authentication_information: CybersourceConsumerAuthInformationRequest,
    order_information: OrderInformationWithBill,
}


pub fn new() -> Self {
        // Do `export CONNECTOR_AUTH_FILE_PATH="/hyperswitch/crates/router/tests/connectors/sample_auth.toml"`
        // before running tests in shell
        let path = env::var("CONNECTOR_AUTH_FILE_PATH")
            .expect("connector authentication file path not set");

        // Read the file contents to a JsonString
        let contents =
            &std::fs::read_to_string(path).expect("Failed to read connector authentication file");

        // Deserialize the JsonString to a HashMap
        let auth_config: HashMap<String, toml::Value> =
            toml::from_str(contents).expect("Failed to deserialize TOML file");

        // auth_config contains the data in below given format:
        // {
        //  "connector_name": Table(
        //      {
        //          "api_key": String(
        //                 "API_Key",
        //          ),
        //          "api_secret": String(
        //              "Secret key",
        //          ),
        //          "key1": String(
        //                  "key1",
        //          ),
        //          "key2": String(
        //              "key2",
        //          ),
        //      },
        //  ),
        // "connector_name": Table(
        //  ...
        // }

        // auth_map refines and extracts required information
        let auth_map = auth_config
            .into_iter()
            .map(|(connector_name, config)| {
                let auth_type = match config {
                    toml::Value::Table(mut table) => {
                        if let Some(auth_key_map_value) = table.remove("auth_key_map") {
                            // This is a CurrencyAuthKey
                            if let toml::Value::Table(auth_key_map_table) = auth_key_map_value {
                                let mut parsed_auth_map = HashMap::new();
                                for (currency, val) in auth_key_map_table {
                                    if let Ok(currency_enum) =
                                        currency.parse::<common_enums::Currency>()
                                    {
                                        parsed_auth_map
                                            .insert(currency_enum, Secret::new(val.to_string()));
                                    }
                                }
                                ConnectorAuthType::CurrencyAuthKey {
                                    auth_key_map: parsed_auth_map,
                                }
                            } else {
                                ConnectorAuthType::NoKey
                            }
                        } else {
                            match (
                                table.get("api_key"),
                                table.get("key1"),
                                table.get("api_secret"),
                                table.get("key2"),
                            ) {
                                (Some(api_key), None, None, None) => ConnectorAuthType::HeaderKey {
                                    api_key: Secret::new(
                                        api_key.as_str().unwrap_or_default().to_string(),
                                    ),
                                },
                                (Some(api_key), Some(key1), None, None) => {
                                    ConnectorAuthType::BodyKey {
                                        api_key: Secret::new(
                                            api_key.as_str().unwrap_or_default().to_string(),
                                        ),
                                        key1: Secret::new(
                                            key1.as_str().unwrap_or_default().to_string(),
                                        ),
                                    }
                                }
                                (Some(api_key), Some(key1), Some(api_secret), None) => {
                                    ConnectorAuthType::SignatureKey {
                                        api_key: Secret::new(
                                            api_key.as_str().unwrap_or_default().to_string(),
                                        ),
                                        key1: Secret::new(
                                            key1.as_str().unwrap_or_default().to_string(),
                                        ),
                                        api_secret: Secret::new(
                                            api_secret.as_str().unwrap_or_default().to_string(),
                                        ),
                                    }
                                }
                                (Some(api_key), Some(key1), Some(api_secret), Some(key2)) => {
                                    ConnectorAuthType::MultiAuthKey {
                                        api_key: Secret::new(
                                            api_key.as_str().unwrap_or_default().to_string(),
                                        ),
                                        key1: Secret::new(
                                            key1.as_str().unwrap_or_default().to_string(),
                                        ),
                                        api_secret: Secret::new(
                                            api_secret.as_str().unwrap_or_default().to_string(),
                                        ),
                                        key2: Secret::new(
                                            key2.as_str().unwrap_or_default().to_string(),
                                        ),
                                    }
                                }
                                _ => ConnectorAuthType::NoKey,
                            }
                        }
                    }
                    _ => ConnectorAuthType::NoKey,
                };
                (connector_name, auth_type)
            })
            .collect();
        Self(auth_map)
    }


pub struct CardNetworkTokenizeRecord {
    // Card details
    pub raw_card_number: Option<CardNumber>,
    pub card_expiry_month: Option<masking::Secret<String>>,
    pub card_expiry_year: Option<masking::Secret<String>>,
    pub card_cvc: Option<masking::Secret<String>>,
    pub card_holder_name: Option<masking::Secret<String>>,
    pub nick_name: Option<masking::Secret<String>>,
    pub card_issuing_country: Option<String>,
    pub card_network: Option<enums::CardNetwork>,
    pub card_issuer: Option<String>,
    pub card_type: Option<payment_methods_api::CardType>,

    // Payment method details
    pub payment_method_id: Option<String>,
    pub payment_method_type: Option<payment_methods_api::CardType>,
    pub payment_method_issuer: Option<String>,

    // Customer details
    pub customer_id: id_type::CustomerId,
    #[serde(rename = "name")]
    pub customer_name: Option<masking::Secret<String>>,
    #[serde(rename = "email")]
    pub customer_email: Option<pii::Email>,
    #[serde(rename = "phone")]
    pub customer_phone: Option<masking::Secret<String>>,
    #[serde(rename = "phone_country_code")]
    pub customer_phone_country_code: Option<String>,
    #[serde(rename = "tax_registration_id")]
    pub customer_tax_registration_id: Option<masking::Secret<String>>,
    // Billing details
    pub billing_address_city: Option<String>,
    pub billing_address_country: Option<enums::CountryAlpha2>,
    pub billing_address_line1: Option<masking::Secret<String>>,
    pub billing_address_line2: Option<masking::Secret<String>>,
    pub billing_address_line3: Option<masking::Secret<String>>,
    pub billing_address_zip: Option<masking::Secret<String>>,
    pub billing_address_state: Option<masking::Secret<String>>,
    pub billing_address_first_name: Option<masking::Secret<String>>,
    pub billing_address_last_name: Option<masking::Secret<String>>,
    pub billing_phone_number: Option<masking::Secret<String>>,
    pub billing_phone_country_code: Option<String>,
    pub billing_email: Option<pii::Email>,

    // Other details
    pub line_number: Option<u64>,
    pub merchant_id: Option<id_type::MerchantId>,
}


pub async fn proxy_create_domain_model(
        payment_intent: &super::PaymentIntent,
        cell_id: id_type::CellId,
        storage_scheme: storage_enums::MerchantStorageScheme,
        request: &api_models::payments::ProxyPaymentsRequest,
        encrypted_data: DecryptedPaymentAttempt,
    ) -> CustomResult<Self, errors::api_error_response::ApiErrorResponse> {
        let id = id_type::GlobalAttemptId::generate(&cell_id);
        let intent_amount_details = payment_intent.amount_details.clone();

        let attempt_amount_details =
            intent_amount_details.proxy_create_attempt_amount_details(request);

        let now = common_utils::date_time::now();
        let payment_method_billing_address = encrypted_data
            .payment_method_billing_address
            .as_ref()
            .map(|data| {
                data.clone()
                    .deserialize_inner_value(|value| value.parse_value("Address"))
            })
            .transpose()
            .change_context(errors::api_error_response::ApiErrorResponse::InternalServerError)
            .attach_printable("Unable to decode billing address")?;
        let connector_token = Some(diesel_models::ConnectorTokenDetails {
            connector_mandate_id: None,
            connector_token_request_reference_id: Some(common_utils::generate_id_with_len(
                consts::CONNECTOR_MANDATE_REQUEST_REFERENCE_ID_LENGTH,
            )),
        });
        let payment_method_type_data = payment_intent.get_payment_method_type();

        let payment_method_subtype_data = payment_intent.get_payment_method_sub_type();
        let authentication_type = payment_intent.authentication_type.unwrap_or_default();
        Ok(Self {
            payment_id: payment_intent.id.clone(),
            merchant_id: payment_intent.merchant_id.clone(),
            amount_details: attempt_amount_details,
            status: common_enums::AttemptStatus::Started,
            connector: Some(request.connector.clone()),
            authentication_type,
            created_at: now,
            modified_at: now,
            last_synced: None,
            cancellation_reason: None,
            browser_info: request.browser_info.clone(),
            payment_token: None,
            connector_metadata: None,
            payment_experience: None,
            payment_method_data: None,
            routing_result: None,
            preprocessing_step_id: None,
            multiple_capture_count: None,
            connector_response_reference_id: None,
            updated_by: storage_scheme.to_string(),
            redirection_data: None,
            encoded_data: None,
            merchant_connector_id: Some(request.merchant_connector_id.clone()),
            external_three_ds_authentication_attempted: None,
            authentication_connector: None,
            authentication_id: None,
            fingerprint_id: None,
            charges: None,
            client_source: None,
            client_version: None,
            customer_acceptance: None,
            profile_id: payment_intent.profile_id.clone(),
            organization_id: payment_intent.organization_id.clone(),
            payment_method_type: payment_method_type_data
                .unwrap_or(common_enums::PaymentMethod::Card),
            payment_method_id: None,
            connector_payment_id: None,
            payment_method_subtype: payment_method_subtype_data
                .unwrap_or(common_enums::PaymentMethodType::Credit),
            authentication_applied: None,
            external_reference_id: None,
            payment_method_billing_address,
            error: None,
            connector_token_details: connector_token,
            feature_metadata: None,
            id,
            card_discovery: None,
            processor_merchant_id: payment_intent.merchant_id.clone(),
            created_by: None,
            connector_request_reference_id: None,
            network_transaction_id: None,
        })
    }


impl KafkaPaymentIntent<'_> {
    #[cfg(feature = "v1")]
    fn get_id(&self) -> &id_type::PaymentId {
        self.payment_id
    }

    #[cfg(feature = "v2")]
    fn get_id(&self) -> &id_type::GlobalPaymentId {
        self.payment_id
    }
}


impl api::RefundSync for Juspaythreedsserver {}

impl api::RefundSync for for Juspaythreedsserver


pub fn make_dsl_input_for_surcharge(
    _payment_attempt: &oss_storage::PaymentAttempt,
    _payment_intent: &oss_storage::PaymentIntent,
    _billing_address: Option<Address>,
) -> RoutingResult<dsl_inputs::BackendInput> {
    todo!()
}


pub fn payment_method_session_create() {}


    fn get_payment_attempt_connector(&self) -> Option<&str> {
        todo!()
    }

    fn get_merchant_connector_id_in_attempt(&self) -> Option<id_type::MerchantConnectorAccountId> {
        todo!()
    }

    fn get_connector_customer_id(&self) -> Option<String> {
        todo!()
    }

    fn get_billing_address(&self) -> Option<hyperswitch_domain_models::address::Address> {
        todo!()
    }

    fn get_payment_method_data(&self) -> Option<&domain::PaymentMethodData> {
        todo!()
    }

    fn get_sessions_token(&self) -> Vec<api::SessionToken> {
        todo!()
    }

    fn get_token_data(&self) -> Option<&storage::PaymentTokenData> {
        todo!()
    }

    fn get_mandate_connector(&self) -> Option<&MandateConnectorDetails> {
        todo!()
    }

    fn get_force_sync(&self) -> Option<bool> {
        todo!()
    }

    fn get_capture_method(&self) -> Option<enums::CaptureMethod> {
        todo!()
    }

    #[cfg(feature = "v2")]
    fn get_optional_payment_attempt(&self) -> Option<&storage::PaymentAttempt> {
        todo!()
    }

    fn get_pre_routing_result(
        &self,
    ) -> Option<HashMap<enums::PaymentMethodType, domain::PreRoutingConnectorChoice>> {
        None
    }
    fn get_merchant_connector_details(
        &self,
    ) -> Option<common_types::domain::MerchantConnectorAuthDetails> {
        todo!()
    }

    fn get_optional_external_vault_session_details(&self) -> Option<api::VaultSessionDetails> {
        todo!()
    }
}


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


pub struct PaymentsMetricsResponse<T> {
    pub query_data: Vec<T>,
    pub meta_data: [PaymentsAnalyticsMetadata; 1],
}


File: crates/router/tests/connectors/worldpayxml.rs

use hyperswitch_domain_models::payment_method_data::{Card, PaymentMethodData};
use masking::Secret;
use router::types::{self, api, storage::enums};
use test_utils::connector_auth;

use crate::utils::{self, ConnectorActions};

#[derive(Clone, Copy)]
struct WorldpayxmlTest;
impl ConnectorActions for WorldpayxmlTest {}
impl utils::Connector for WorldpayxmlTest {
    fn get_data(&self) -> api::ConnectorData {
        use router::connector::Worldpayxml;
        utils::construct_connector_data_old(
            Box::new(Worldpayxml::new()),
            types::Connector::Plaid,
            api::GetToken::Connector,
            None,
        )
    }

    fn get_auth_token(&self) -> types::ConnectorAuthType {
        utils::to_connector_auth_type(
            connector_auth::ConnectorAuthentication::new()
                .worldpayxml
                .expect("Missing connector authentication configuration")
                .into(),
        )
    }

    fn get_name(&self) -> String {
        "Worldpayxml".to_string()
    }
}

static CONNECTOR: WorldpayxmlTest = WorldpayxmlTest {};

fn get_default_payment_info() -> Option<utils::PaymentInfo> {
    None
}

fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
    None
}

// Cards Positive Tests
// Creates a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_only_authorize_payment() {
    let response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized);
}

// Captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info())
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Partially captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(
            payment_method_details(),
            Some(types::PaymentsCaptureData {
                amount_to_capture: 50,
                ..utils::PaymentCaptureType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_authorized_payment() {
    let authorize_response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Authorized,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("PSync response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
}

// Voids a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_void_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_void_payment(
            payment_method_details(),
            Some(types::PaymentsCancelData {
                connector_transaction_id: String::from(""),
                cancellation_reason: Some("requested_by_customer".to_string()),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Void payment response");
    assert_eq!(response.status, enums::AttemptStatus::Voided);
}

// Refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Synchronizes a refund using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_manually_captured_refund() {
    let refund_response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_make_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_auto_captured_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Charged,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                capture_method: Some(enums::CaptureMethod::Automatic),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(response.status, enums::AttemptStatus::Charged,);
}

// Refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_auto_captured_payment() {
    let response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_succeeded_payment() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        refund_response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_succeeded_payment_multiple_times() {
    CONNECTOR
        .make_payment_and_multiple_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await;
}

// Synchronizes a refund using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_refund() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Cards Negative scenarios
// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_cvc: Secret::new("12345".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's security code is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry month.
#[actix_web::test]
async fn should_fail_payment_for_invalid_exp_month() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_month: Secret::new("20".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration month is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry year.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_expiry_year() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration year is invalid.".to_string(),
    );
}

// Voids a payment using automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_fail_void_payment_for_auto_capture() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let void_response = CONNECTOR
        .void_payment(txn_id.unwrap(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        void_response.response.unwrap_err().message,
        "You cannot cancel this PaymentIntent because it has a status of succeeded."
    );
}

// Captures a payment using invalid connector payment id.
#[actix_web::test]
async fn should_fail_capture_for_invalid_payment() {
    let capture_response = CONNECTOR
        .capture_payment("123456789".to_string(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        capture_response.response.unwrap_err().message,
        String::from("No such payment_intent: '123456789'")
    );
}

// Refunds a payment with refund amount higher than payment amount.
#[actix_web::test]
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
    let response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 150,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Refund amount (₹1.50) is greater than charge amount (₹1.00)",
    );
}

// Connector dependent test cases goes here

// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests


pub(crate) fn diesel_error_to_data_error(
    diesel_error: diesel_models::errors::DatabaseError,
) -> StorageError {
    match diesel_error {
        diesel_models::errors::DatabaseError::DatabaseConnectionError => {
            StorageError::DatabaseConnectionError
        }
        diesel_models::errors::DatabaseError::NotFound => {
            StorageError::ValueNotFound("Value not found".to_string())
        }
        diesel_models::errors::DatabaseError::UniqueViolation => StorageError::DuplicateValue {
            entity: "entity ",
            key: None,
        },
        _ => StorageError::DatabaseError(error_stack::report!(diesel_error)),
    }
}


pub struct WellsfargopayoutErrorResponse {
    pub status_code: u16,
    pub code: String,
    pub message: String,
    pub reason: Option<String>,
}


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

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

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

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

    fn get_auth_header(
        &self,
        _auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        // This method is not implemented for Paytm, as it will always call the UCS service which has the logic to create headers.
        Err(errors::ConnectorError::NotImplemented("get_auth_header method".to_string()).into())
    }

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: paytm::PaytmErrorResponse =
            res.response
                .parse_struct("PaytmErrorResponse")
                .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,
        })
    }
}


pub struct ErrorResponseBankRedirect {
    #[serde(rename = "ResultInfo")]
    pub payment_result_info: ResultInfo,
}


OpenAPI Block Path: components.schemas.PaymentsPostSessionTokensRequest
{
  "type": "object",
  "required": [
    "client_secret",
    "payment_method_type",
    "payment_method"
  ],
  "properties": {
    "client_secret": {
      "type": "string",
      "description": "It's a token used for client side verification."
    },
    "payment_method_type": {
      "$ref": "#/components/schemas/PaymentMethodType"
    },
    "payment_method": {
      "$ref": "#/components/schemas/PaymentMethod"
    }
  }
}


pub async fn retrieve_poll_status() {}


pub fn valid_business_statuses() -> Vec<&'static str> {
    vec![storage::business_status::PENDING]
}


pub fn convert_connector_service_status_code(
    status_code: u32,
) -> Result<u16, error_stack::Report<UnifiedConnectorServiceError>> {
    u16::try_from(status_code).map_err(|err| {
        UnifiedConnectorServiceError::RequestEncodingFailedWithReason(format!(
            "Failed to convert connector service status code to u16: {err}"
        ))
        .into()
    })
}


pub fn mk_add_bank_response_hs(
    bank: api::BankPayout,
    bank_reference: String,
    req: api::PaymentMethodCreate,
    merchant_id: &id_type::MerchantId,
) -> api::PaymentMethodResponse {
    api::PaymentMethodResponse {
        merchant_id: merchant_id.to_owned(),
        customer_id: req.customer_id,
        payment_method_id: bank_reference,
        payment_method: req.payment_method,
        payment_method_type: req.payment_method_type,
        bank_transfer: Some(bank),
        card: None,
        metadata: req.metadata,
        created: Some(common_utils::date_time::now()),
        recurring_enabled: Some(false),           // [#256]
        installment_payment_enabled: Some(false), // #[#256]
        payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
        last_used_at: Some(common_utils::date_time::now()),
        client_secret: None,
    }
}


pub async fn find_authentication_by_merchant_id_connector_authentication_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_authentication_id: &str,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::connector_authentication_id.eq(connector_authentication_id.to_owned())),
        )
        .await
    }


File: crates/euclid/src/frontend/dir/transformers.rs

use crate::{dirval, dssa::types::AnalysisErrorType, enums as global_enums, frontend::dir};

pub trait IntoDirValue {
    fn into_dir_value(self) -> Result<dir::DirValue, AnalysisErrorType>;
}
impl IntoDirValue for (global_enums::PaymentMethodType, global_enums::PaymentMethod) {
    fn into_dir_value(self) -> Result<dir::DirValue, AnalysisErrorType> {
        match self.0 {
            global_enums::PaymentMethodType::Credit => Ok(dirval!(CardType = Credit)),
            global_enums::PaymentMethodType::Debit => Ok(dirval!(CardType = Debit)),
            #[cfg(feature = "v2")]
            global_enums::PaymentMethodType::Card => Ok(dirval!(CardType = Card)),
            global_enums::PaymentMethodType::Giropay => Ok(dirval!(BankRedirectType = Giropay)),
            global_enums::PaymentMethodType::Ideal => Ok(dirval!(BankRedirectType = Ideal)),
            global_enums::PaymentMethodType::Sofort => Ok(dirval!(BankRedirectType = Sofort)),
            global_enums::PaymentMethodType::DuitNow => Ok(dirval!(RealTimePaymentType = DuitNow)),
            global_enums::PaymentMethodType::Eps => Ok(dirval!(BankRedirectType = Eps)),
            global_enums::PaymentMethodType::Fps => Ok(dirval!(RealTimePaymentType = Fps)),
            global_enums::PaymentMethodType::Klarna => Ok(dirval!(PayLaterType = Klarna)),
            global_enums::PaymentMethodType::Affirm => Ok(dirval!(PayLaterType = Affirm)),
            global_enums::PaymentMethodType::AfterpayClearpay => {
                Ok(dirval!(PayLaterType = AfterpayClearpay))
            }
            global_enums::PaymentMethodType::AmazonPay => Ok(dirval!(WalletType = AmazonPay)),
            global_enums::PaymentMethodType::Skrill => Ok(dirval!(WalletType = Skrill)),
            global_enums::PaymentMethodType::Paysera => Ok(dirval!(WalletType = Paysera)),
            global_enums::PaymentMethodType::GooglePay => Ok(dirval!(WalletType = GooglePay)),
            global_enums::PaymentMethodType::Bluecode => Ok(dirval!(WalletType = Bluecode)),
            global_enums::PaymentMethodType::ApplePay => Ok(dirval!(WalletType = ApplePay)),
            global_enums::PaymentMethodType::Paypal => Ok(dirval!(WalletType = Paypal)),
            global_enums::PaymentMethodType::RevolutPay => Ok(dirval!(WalletType = RevolutPay)),
            global_enums::PaymentMethodType::CryptoCurrency => {
                Ok(dirval!(CryptoType = CryptoCurrency))
            }
            global_enums::PaymentMethodType::Ach => match self.1 {
                global_enums::PaymentMethod::BankDebit => Ok(dirval!(BankDebitType = Ach)),
                global_enums::PaymentMethod::BankTransfer => Ok(dirval!(BankTransferType = Ach)),
                global_enums::PaymentMethod::PayLater
                | global_enums::PaymentMethod::Card
                | global_enums::PaymentMethod::CardRedirect
                | global_enums::PaymentMethod::Wallet
                | global_enums::PaymentMethod::BankRedirect
                | global_enums::PaymentMethod::Crypto
                | global_enums::PaymentMethod::Reward
                | global_enums::PaymentMethod::RealTimePayment
                | global_enums::PaymentMethod::Upi
                | global_enums::PaymentMethod::Voucher
                | global_enums::PaymentMethod::OpenBanking
                | global_enums::PaymentMethod::MobilePayment
                | global_enums::PaymentMethod::GiftCard => Err(AnalysisErrorType::NotSupported),
            },
            global_enums::PaymentMethodType::Bacs => match self.1 {
                global_enums::PaymentMethod::BankDebit => Ok(dirval!(BankDebitType = Bacs)),
                global_enums::PaymentMethod::BankTransfer => Ok(dirval!(BankTransferType = Bacs)),
                global_enums::PaymentMethod::PayLater
                | global_enums::PaymentMethod::Card
                | global_enums::PaymentMethod::CardRedirect
                | global_enums::PaymentMethod::Wallet
                | global_enums::PaymentMethod::BankRedirect
                | global_enums::PaymentMethod::Crypto
                | global_enums::PaymentMethod::Reward
                | global_enums::PaymentMethod::RealTimePayment
                | global_enums::PaymentMethod::Upi
                | global_enums::PaymentMethod::Voucher
                | global_enums::PaymentMethod::OpenBanking
                | global_enums::PaymentMethod::MobilePayment
                | global_enums::PaymentMethod::GiftCard => Err(AnalysisErrorType::NotSupported),
            },
            global_enums::PaymentMethodType::Becs => Ok(dirval!(BankDebitType = Becs)),
            global_enums::PaymentMethodType::Sepa => Ok(dirval!(BankDebitType = Sepa)),
            global_enums::PaymentMethodType::SepaBankTransfer => {
                Ok(dirval!(BankTransferType = SepaBankTransfer))
            }
            global_enums::PaymentMethodType::AliPay => Ok(dirval!(WalletType = AliPay)),
            global_enums::PaymentMethodType::AliPayHk => Ok(dirval!(WalletType = AliPayHk)),
            global_enums::PaymentMethodType::BancontactCard => {
                Ok(dirval!(BankRedirectType = BancontactCard))
            }
            global_enums::PaymentMethodType::Blik => Ok(dirval!(BankRedirectType = Blik)),
            global_enums::PaymentMethodType::MbWay => Ok(dirval!(WalletType = MbWay)),
            global_enums::PaymentMethodType::MobilePay => Ok(dirval!(WalletType = MobilePay)),
            global_enums::PaymentMethodType::Cashapp => Ok(dirval!(WalletType = Cashapp)),
            global_enums::PaymentMethodType::Multibanco => {
                Ok(dirval!(BankTransferType = Multibanco))
            }
            global_enums::PaymentMethodType::Pix => Ok(dirval!(BankTransferType = Pix)),
            global_enums::PaymentMethodType::Pse => Ok(dirval!(BankTransferType = Pse)),
            global_enums::PaymentMethodType::Interac => Ok(dirval!(BankRedirectType = Interac)),
            global_enums::PaymentMethodType::OnlineBankingCzechRepublic => {
                Ok(dirval!(BankRedirectType = OnlineBankingCzechRepublic))
            }
            global_enums::PaymentMethodType::OnlineBankingFinland => {
                Ok(dirval!(BankRedirectType = OnlineBankingFinland))
            }
            global_enums::PaymentMethodType::OnlineBankingPoland => {
                Ok(dirval!(BankRedirectType = OnlineBankingPoland))
            }
            global_enums::PaymentMethodType::OnlineBankingSlovakia => {
                Ok(dirval!(BankRedirectType = OnlineBankingSlovakia))
            }
            global_enums::PaymentMethodType::Swish => Ok(dirval!(WalletType = Swish)),
            global_enums::PaymentMethodType::Trustly => Ok(dirval!(BankRedirectType = Trustly)),
            global_enums::PaymentMethodType::Bizum => Ok(dirval!(BankRedirectType = Bizum)),

            global_enums::PaymentMethodType::PayBright => Ok(dirval!(PayLaterType = PayBright)),
            global_enums::PaymentMethodType::Flexiti => Ok(dirval!(PayLaterType = Flexiti)),
            global_enums::PaymentMethodType::Walley => Ok(dirval!(PayLaterType = Walley)),
            global_enums::PaymentMethodType::Breadpay => Ok(dirval!(PayLaterType = Breadpay)),
            global_enums::PaymentMethodType::Przelewy24 => {
                Ok(dirval!(BankRedirectType = Przelewy24))
            }
            global_enums::PaymentMethodType::PromptPay => {
                Ok(dirval!(RealTimePaymentType = PromptPay))
            }
            global_enums::PaymentMethodType::WeChatPay => Ok(dirval!(WalletType = WeChatPay)),

            global_enums::PaymentMethodType::ClassicReward => {
                Ok(dirval!(RewardType = ClassicReward))
            }
            global_enums::PaymentMethodType::Evoucher => Ok(dirval!(RewardType = Evoucher)),
            global_enums::PaymentMethodType::UpiCollect => Ok(dirval!(UpiType = UpiCollect)),
            global_enums::PaymentMethodType::UpiIntent => Ok(dirval!(UpiType = UpiIntent)),
            global_enums::PaymentMethodType::SamsungPay => Ok(dirval!(WalletType = SamsungPay)),
            global_enums::PaymentMethodType::GoPay => Ok(dirval!(WalletType = GoPay)),
            global_enums::PaymentMethodType::KakaoPay => Ok(dirval!(WalletType = KakaoPay)),
            global_enums::PaymentMethodType::Twint => Ok(dirval!(WalletType = Twint)),
            global_enums::PaymentMethodType::Gcash => Ok(dirval!(WalletType = Gcash)),
            global_enums::PaymentMethodType::Vipps => Ok(dirval!(WalletType = Vipps)),
            global_enums::PaymentMethodType::VietQr => Ok(dirval!(RealTimePaymentType = VietQr)),
            global_enums::PaymentMethodType::Momo => Ok(dirval!(WalletType = Momo)),
            global_enums::PaymentMethodType::Alma => Ok(dirval!(PayLaterType = Alma)),
            global_enums::PaymentMethodType::Dana => Ok(dirval!(WalletType = Dana)),
            global_enums::PaymentMethodType::OnlineBankingFpx => {
                Ok(dirval!(BankRedirectType = OnlineBankingFpx))
            }
            global_enums::PaymentMethodType::LocalBankRedirect => {
                Ok(dirval!(BankRedirectType = LocalBankRedirect))
            }
            global_enums::PaymentMethodType::OnlineBankingThailand => {
                Ok(dirval!(BankRedirectType = OnlineBankingThailand))
            }
            global_enums::PaymentMethodType::TouchNGo => Ok(dirval!(WalletType = TouchNGo)),
            global_enums::PaymentMethodType::Atome => Ok(dirval!(PayLaterType = Atome)),
            global_enums::PaymentMethodType::Boleto => Ok(dirval!(VoucherType = Boleto)),
            global_enums::PaymentMethodType::Efecty => Ok(dirval!(VoucherType = Efecty)),
            global_enums::PaymentMethodType::PagoEfectivo => {
                Ok(dirval!(VoucherType = PagoEfectivo))
            }
            global_enums::PaymentMethodType::RedCompra => Ok(dirval!(VoucherType = RedCompra)),
            global_enums::PaymentMethodType::RedPagos => Ok(dirval!(VoucherType = RedPagos)),
            global_enums::PaymentMethodType::Alfamart => Ok(dirval!(VoucherType = Alfamart)),
            global_enums::PaymentMethodType::BcaBankTransfer => {
                Ok(dirval!(BankTransferType = BcaBankTransfer))
            }
            global_enums::PaymentMethodType::BniVa => Ok(dirval!(BankTransferType = BniVa)),
            global_enums::PaymentMethodType::BriVa => Ok(dirval!(BankTransferType = BriVa)),
            global_enums::PaymentMethodType::CimbVa => Ok(dirval!(BankTransferType = CimbVa)),
            global_enums::PaymentMethodType::DanamonVa => Ok(dirval!(BankTransferType = DanamonVa)),
            global_enums::PaymentMethodType::Indomaret => Ok(dirval!(VoucherType = Indomaret)),
            global_enums::PaymentMethodType::MandiriVa => Ok(dirval!(BankTransferType = MandiriVa)),
            global_enums::PaymentMethodType::LocalBankTransfer => {
                Ok(dirval!(BankTransferType = LocalBankTransfer))
            }
            global_enums::PaymentMethodType::InstantBankTransfer => {
                Ok(dirval!(BankTransferType = InstantBankTransfer))
            }
            global_enums::PaymentMethodType::InstantBankTransferFinland => {
                Ok(dirval!(BankTransferType = InstantBankTransferFinland))
            }
            global_enums::PaymentMethodType::InstantBankTransferPoland => {
                Ok(dirval!(BankTransferType = InstantBankTransferPoland))
            }
            global_enums::PaymentMethodType::PermataBankTransfer => {
                Ok(dirval!(BankTransferType = PermataBankTransfer))
            }
            global_enums::PaymentMethodType::PaySafeCard => Ok(dirval!(GiftCardType = PaySafeCard)),
            global_enums::PaymentMethodType::SevenEleven => Ok(dirval!(VoucherType = SevenEleven)),
            global_enums::PaymentMethodType::Lawson => Ok(dirval!(VoucherType = Lawson)),
            global_enums::PaymentMethodType::MiniStop => Ok(dirval!(VoucherType = MiniStop)),
            global_enums::PaymentMethodType::FamilyMart => Ok(dirval!(VoucherType = FamilyMart)),
            global_enums::PaymentMethodType::Seicomart => Ok(dirval!(VoucherType = Seicomart)),
            global_enums::PaymentMethodType::PayEasy => Ok(dirval!(VoucherType = PayEasy)),
            global_enums::PaymentMethodType::Givex => Ok(dirval!(GiftCardType = Givex)),
            global_enums::PaymentMethodType::Benefit => Ok(dirval!(CardRedirectType = Benefit)),
            global_enums::PaymentMethodType::Knet => Ok(dirval!(CardRedirectType = Knet)),
            global_enums::PaymentMethodType::OpenBankingUk => {
                Ok(dirval!(BankRedirectType = OpenBankingUk))
            }
            global_enums::PaymentMethodType::MomoAtm => Ok(dirval!(CardRedirectType = MomoAtm)),
            global_enums::PaymentMethodType::Oxxo => Ok(dirval!(VoucherType = Oxxo)),
            global_enums::PaymentMethodType::CardRedirect => {
                Ok(dirval!(CardRedirectType = CardRedirect))
            }
            global_enums::PaymentMethodType::Venmo => Ok(dirval!(WalletType = Venmo)),
            global_enums::PaymentMethodType::Mifinity => Ok(dirval!(WalletType = Mifinity)),
            global_enums::PaymentMethodType::OpenBankingPIS => {
                Ok(dirval!(OpenBankingType = OpenBankingPIS))
            }
            global_enums::PaymentMethodType::Paze => Ok(dirval!(WalletType = Paze)),
            global_enums::PaymentMethodType::DirectCarrierBilling => {
                Ok(dirval!(MobilePaymentType = DirectCarrierBilling))
            }
            global_enums::PaymentMethodType::Eft => Ok(dirval!(BankRedirectType = Eft)),
            global_enums::PaymentMethodType::IndonesianBankTransfer => {
                Ok(dirval!(BankTransferType = IndonesianBankTransfer))
            }
            global_enums::PaymentMethodType::BhnCardNetwork => {
                Ok(dirval!(GiftCardType = BhnCardNetwork))
            }
        }
    }
}


pub struct Authorize;


OpenAPI Block Path: components.schemas.MobilePayRedirection
{
  "type": "object"
}


pub struct CaptureResponseTransactionBody {
    id: String,
    status: BraintreePaymentStatus,
}


impl api::RefundExecute for Chargebee {}

impl api::RefundExecute for for Chargebee


pub struct DwollaRefundsRequest {
    #[serde(rename = "_links")]
    links: DwollaPaymentLinks,
    amount: DwollaAmount,
    correlation_id: String,
}


impl ConnectorValidation for CtpMastercard {}

impl ConnectorValidation for for CtpMastercard


impl api::RefundSync for Stripebilling {}

impl api::RefundSync for for Stripebilling


pub fn generate_authorization_value(&self) -> String {
        let auth_id = format!(
            "{}:{}",
            self.get_client_id().expose(),
            self.get_client_secret().expose(),
        );
        format!("Basic {}", consts::BASE64_ENGINE.encode(auth_id))
    }