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

pub mod transformers;

use std::time::{Duration, SystemTime, UNIX_EPOCH};

use common_utils::{
    errors::CustomResult,
    ext_traits::BytesExt,
    pii,
    request::{Method, RequestContent},
};
#[cfg(feature = "payouts")]
use common_utils::{
    request::{Request, RequestBuilder},
    types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector},
};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentsResponseData, RefundsResponseData, SupportedPaymentMethods,
    },
};
#[cfg(feature = "payouts")]
use hyperswitch_domain_models::{
    router_flow_types::payouts::{
        PoCancel, PoCreate, PoEligibility, PoFulfill, PoQuote, PoRecipient, PoRecipientAccount,
        PoSync,
    },
    router_request_types::PayoutsData,
    router_response_types::PayoutsResponseData,
    types::PayoutsRouterData,
};
#[cfg(feature = "payouts")]
use hyperswitch_interfaces::types;
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorRedirectResponse,
        ConnectorSpecifications, ConnectorValidation,
    },
    configs::Connectors,
    consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE},
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::Response,
    webhooks,
};
use josekit::{
    jws::{self, JwsHeader, ES256},
    jwt::{self, JwtPayload},
    Map, Value,
};
use masking::{ExposeInterface, Mask};
#[cfg(feature = "payouts")]
use router_env::{instrument, tracing};
use serde_json::json;
use transformers as nomupay;

use crate::{constants::headers, utils};
#[cfg(feature = "payouts")]
use crate::{types::ResponseRouterData, utils::RouterData as RouterDataTrait};

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

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

fn get_private_key(
    metadata: &Option<pii::SecretSerdeValue>,
) -> Result<String, errors::ConnectorError> {
    match nomupay::NomupayMetadata::try_from(metadata.as_ref()) {
        Ok(nomupay_metadata) => Ok(nomupay_metadata.private_key.expose()),
        Err(_e) => Err(errors::ConnectorError::NoConnectorMetaData),
    }
}

fn box_to_jwt_payload(
    body: Box<dyn masking::ErasedMaskSerialize + Send>,
) -> CustomResult<JwtPayload, errors::ConnectorError> {
    let str_result = serde_json::to_string(&body)
        .change_context(errors::ConnectorError::ProcessingStepFailed(None))?;

    let parsed_json: Map<String, Value> = serde_json::from_str(&str_result)
        .change_context(errors::ConnectorError::ProcessingStepFailed(None))?;

    let jwt_payload = JwtPayload::from_map(parsed_json)
        .change_context(errors::ConnectorError::ProcessingStepFailed(None))?;

    Ok(jwt_payload)
}

fn get_signature(
    metadata: &Option<pii::SecretSerdeValue>,
    auth: nomupay::NomupayAuthType,
    body: RequestContent,
    method: &str,
    path: String,
) -> CustomResult<String, errors::ConnectorError> {
    match body {
        RequestContent::Json(masked_json) => {
            let expiration_time = SystemTime::now() + Duration::from_secs(4 * 60);
            let expires_in = match expiration_time.duration_since(UNIX_EPOCH) {
                Ok(duration) => duration.as_secs(),
                Err(_e) => 0,
            };

            let mut option_map = Map::new();
            option_map.insert("alg".to_string(), json!(format!("ES256")));
            option_map.insert("aud".to_string(), json!(format!("{} {}", method, path)));
            option_map.insert("exp".to_string(), json!(expires_in));
            option_map.insert("kid".to_string(), json!(auth.kid));

            let header = JwsHeader::from_map(option_map)
                .change_context(errors::ConnectorError::ProcessingStepFailed(None))?;

            let payload = match method {
                "GET" => JwtPayload::new(),
                _ => box_to_jwt_payload(masked_json)
                    .change_context(errors::ConnectorError::ProcessingStepFailed(None))?,
            };

            let private_key = get_private_key(metadata)?;

            let signer = ES256
                .signer_from_pem(&private_key)
                .change_context(errors::ConnectorError::ProcessingStepFailed(None))?;

            let nomupay_jwt = match method {
                "GET" => jws::serialize_compact(b"", &header, &signer)
                    .change_context(errors::ConnectorError::ProcessingStepFailed(None))?,
                _ => jwt::encode_with_signer(&payload, &header, &signer)
                    .change_context(errors::ConnectorError::ProcessingStepFailed(None))?,
            };

            let jws_blocks: Vec<&str> = nomupay_jwt.split('.').collect();

            let jws_detached = jws_blocks
                .first()
                .zip(jws_blocks.get(2))
                .map(|(first, third)| format!("{first}..{third}"))
                .ok_or_else(|| errors::ConnectorError::MissingRequiredField {
                    field_name: "JWS blocks not sufficient for detached payload",
                })?;

            Ok(jws_detached)
        }
        _ => Err(errors::ConnectorError::ProcessingStepFailed(None).into()),
    }
}

impl api::Payment for Nomupay {}
impl api::PaymentSession for Nomupay {}
impl api::ConnectorAccessToken for Nomupay {}
impl api::MandateSetup for Nomupay {}
impl api::PaymentAuthorize for Nomupay {}
impl api::PaymentSync for Nomupay {}
impl api::PaymentCapture for Nomupay {}
impl api::PaymentVoid for Nomupay {}
impl api::Refund for Nomupay {}
impl api::RefundExecute for Nomupay {}
impl api::RefundSync for Nomupay {}
impl api::PaymentToken for Nomupay {}

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

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Nomupay
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 is_post_req = matches!(self.get_http_method(), Method::Post);
        let body = self.get_request_body(req, connectors)?;
        let auth = nomupay::NomupayAuthType::try_from(&req.connector_auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        let base_url = connectors.nomupay.base_url.as_str();
        let path: String = self
            .get_url(req, connectors)?
            .chars()
            .skip(base_url.len())
            .collect();
        let req_method = if is_post_req { "POST" } else { "GET" };

        let sign = get_signature(&req.connector_meta_data, auth, body, req_method, path)?;

        let mut header = vec![(
            headers::CONTENT_TYPE.to_string(),
            self.get_content_type().to_string().into(),
        )];
        header.push((
            headers::X_SIGNATURE.to_string(),
            masking::Maskable::Normal(sign),
        ));

        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);

        Ok(header)
    }
}

impl TryFrom<Option<&pii::SecretSerdeValue>> for nomupay::NomupayMetadata {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(meta_data: Option<&pii::SecretSerdeValue>) -> Result<Self, Self::Error> {
        let metadata: Self = utils::to_connector_meta_from_secret::<Self>(meta_data.cloned())
            .change_context(errors::ConnectorError::InvalidConnectorConfig {
                config: "metadata",
            })?;
        Ok(metadata)
    }
}

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

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

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

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

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

        match (
            response.status,
            response.code,
            response.error,
            response.status_code,
            response.detail,
        ) {
            (Some(status), Some(code), _, _, _) => Ok(ErrorResponse {
                status_code: res.status_code,
                code: code.to_string(),
                message: status,
                reason: None,
                attempt_status: None,
                connector_transaction_id: None,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            }),
            (None, None, Some(nomupay_inner_error), _, _) => {
                match (
                    nomupay_inner_error.error_description,
                    nomupay_inner_error.validation_errors,
                ) {
                    (Some(error_description), _) => Ok(ErrorResponse {
                        status_code: res.status_code,
                        code: nomupay_inner_error.error_code,
                        message: error_description,
                        reason: None,
                        attempt_status: None,
                        connector_transaction_id: None,
                        network_advice_code: None,
                        network_decline_code: None,
                        network_error_message: None,
                        connector_metadata: None,
                    }),
                    (_, Some(validation_errors)) => Ok(ErrorResponse {
                        status_code: res.status_code,
                        code: nomupay_inner_error.error_code,
                        message: validation_errors
                            .first()
                            .map(|m| m.message.clone())
                            .unwrap_or_default(),
                        reason: Some(
                            validation_errors
                                .first()
                                .map(|m| m.field.clone())
                                .unwrap_or_default(),
                        ),
                        attempt_status: None,
                        connector_transaction_id: None,
                        network_advice_code: None,
                        network_decline_code: None,
                        network_error_message: None,
                        connector_metadata: None,
                    }),
                    (None, None) => Ok(ErrorResponse {
                        status_code: res.status_code,
                        code: NO_ERROR_CODE.to_string(),
                        message: NO_ERROR_MESSAGE.to_string(),
                        reason: None,
                        attempt_status: None,
                        connector_transaction_id: None,
                        network_advice_code: None,
                        network_decline_code: None,
                        network_error_message: None,
                        connector_metadata: None,
                    }),
                }
            }
            (None, None, None, Some(status_code), Some(detail)) => Ok(ErrorResponse {
                status_code,
                code: detail
                    .get(1)
                    .map(|d| d.error_type.clone())
                    .unwrap_or_default(),
                message: status_code.to_string(),
                reason: None,
                attempt_status: None,
                connector_transaction_id: None,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            }),
            _ => Ok(ErrorResponse {
                status_code: res.status_code,
                code: NO_ERROR_CODE.to_string(),
                message: NO_ERROR_MESSAGE.to_string(),
                reason: None,
                attempt_status: None,
                connector_transaction_id: None,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            }),
        }
    }
}

impl ConnectorValidation for Nomupay {}
impl ConnectorRedirectResponse for Nomupay {}
impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Nomupay {}

impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Nomupay {}
impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData> for Nomupay {}
impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Nomupay {}
impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Nomupay {}
impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Nomupay {}
impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Nomupay {}
impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Nomupay {}
impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Nomupay {}

#[cfg(feature = "payouts")]
impl ConnectorIntegration<PoQuote, PayoutsData, PayoutsResponseData> for Nomupay {}
#[cfg(feature = "payouts")]
impl ConnectorIntegration<PoCreate, PayoutsData, PayoutsResponseData> for Nomupay {}
#[cfg(feature = "payouts")]
impl ConnectorIntegration<PoCancel, PayoutsData, PayoutsResponseData> for Nomupay {}
#[cfg(feature = "payouts")]
impl ConnectorIntegration<PoEligibility, PayoutsData, PayoutsResponseData> for Nomupay {}

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

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

    fn get_http_method(&self) -> Method {
        Method::Get
    }

    fn build_request(
        &self,
        req: &PayoutsRouterData<PoSync>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Get)
            .url(&types::PayoutSyncType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(types::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: nomupay::NomupayPaymentResponse = res
            .response
            .parse_struct("NomupayPaymentResponse")
            .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 api::Payouts for Nomupay {}
#[cfg(feature = "payouts")]
impl api::PayoutCancel for Nomupay {}
#[cfg(feature = "payouts")]
impl api::PayoutCreate for Nomupay {}
#[cfg(feature = "payouts")]
impl api::PayoutEligibility for Nomupay {}
#[cfg(feature = "payouts")]
impl api::PayoutFulfill for Nomupay {}
#[cfg(feature = "payouts")]
impl api::PayoutQuote for Nomupay {}
#[cfg(feature = "payouts")]
impl api::PayoutRecipient for Nomupay {}
#[cfg(feature = "payouts")]
impl api::PayoutRecipientAccount for Nomupay {}
#[cfg(feature = "payouts")]
impl api::PayoutSync for Nomupay {}

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

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

    fn get_request_body(
        &self,
        req: &PayoutsRouterData<PoRecipient>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nomupay::OnboardSubAccountRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &PayoutsRouterData<PoRecipient>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PayoutsRouterData<PoRecipient>, errors::ConnectorError> {
        let response: nomupay::OnboardSubAccountResponse = res
            .response
            .parse_struct("OnboardSubAccountResponse")
            .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<PoRecipientAccount, PayoutsData, PayoutsResponseData> for Nomupay {
    fn get_url(
        &self,
        req: &PayoutsRouterData<PoRecipientAccount>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let sid = req.get_connector_customer_id()?;

        Ok(format!(
            "{}/v1alpha1/sub-account/{}/transfer-method",
            connectors.nomupay.base_url, sid
        ))
    }

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

    fn get_request_body(
        &self,
        req: &PayoutsRouterData<PoRecipientAccount>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = nomupay::OnboardTransferMethodRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &PayoutsRouterData<PoRecipientAccount>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PayoutsRouterData<PoRecipientAccount>, errors::ConnectorError> {
        let response: nomupay::OnboardTransferMethodResponse = res
            .response
            .parse_struct("OnboardTransferMethodResponse")
            .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<PoFulfill, PayoutsData, PayoutsResponseData> for Nomupay {
    fn get_url(
        &self,
        _req: &PayoutsRouterData<PoFulfill>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}/v1alpha1/payments", connectors.nomupay.base_url))
    }

    fn get_headers(
        &self,
        req: &PayoutsRouterData<PoFulfill>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::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 = utils::convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.destination_currency,
        )?;
        let connector_req = nomupay::NomupayPaymentRequest::try_from((req, amount))?;

        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(&types::PayoutFulfillType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(types::PayoutFulfillType::get_headers(
                self, req, connectors,
            )?)
            .set_body(types::PayoutFulfillType::get_request_body(
                self, req, connectors,
            )?)
            .build();

        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &PayoutsRouterData<PoFulfill>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PayoutsRouterData<PoFulfill>, errors::ConnectorError> {
        let response: nomupay::NomupayPaymentResponse = res
            .response
            .parse_struct("NomupayPaymentResponse")
            .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 Nomupay {
    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 NOMUPAY_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Nomupay",
    description: "Nomupay payouts connector for disbursements to recipients' bank accounts and alternative payment methods in Southeast Asia and the Pacific Islands",
    connector_type: common_enums::HyperswitchConnectorCategory::PayoutProcessor,
    integration_status: common_enums::ConnectorIntegrationStatus::Sandbox,
};

impl ConnectorSpecifications for Nomupay {
    fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
        Some(&NOMUPAY_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
    }
}


// Struct: PaymentResponse
// File: crates/hyperswitch_connectors/src/connectors/gocardless/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentResponse


// Implementation: impl Shift4AuthorizePreprocessingCommon for for PaymentsPreProcessingData
// File: crates/hyperswitch_connectors/src/connectors/shift4/transformers.rs
// Module: hyperswitch_connectors
// Methods: 7 total (0 public)

impl Shift4AuthorizePreprocessingCommon for for PaymentsPreProcessingData


// Struct: PaymentsTokenReference
// File: crates/hyperswitch_domain_models/src/mandates.rs
// Module: hyperswitch_domain_models
// Implementations: 2
// Traits: std::ops::Deref, std::ops::DerefMut

pub struct PaymentsTokenReference


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

// Public submodules:
pub mod transformers;


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

impl Finix


// Struct: HiPayTokenRequest
// File: crates/hyperswitch_connectors/src/connectors/hipay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct HiPayTokenRequest


// Struct: FailDetails
// File: crates/hyperswitch_connectors/src/connectors/datatrans/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FailDetails


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

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


// File: crates/scheduler/src/scheduler.rs
// Module: scheduler
// Public functions: 1

use std::sync::Arc;

use common_utils::{errors::CustomResult, id_type};
#[cfg(feature = "kv_store")]
use storage_impl::kv_router_store::KVRouterStore;
use storage_impl::mock_db::MockDb;
#[cfg(not(feature = "kv_store"))]
use storage_impl::RouterStore;
use tokio::sync::mpsc;

use super::env::logger::error;
pub use crate::{
    configs::settings::SchedulerSettings,
    consumer::{self, workflows},
    db::{process_tracker::ProcessTrackerInterface, queue::QueueInterface},
    errors,
    flow::SchedulerFlow,
    producer,
};

#[cfg(not(feature = "olap"))]
type StoreType = storage_impl::database::store::Store;
#[cfg(feature = "olap")]
type StoreType = storage_impl::database::store::ReplicaStore;

#[cfg(not(feature = "kv_store"))]
pub type Store = RouterStore<StoreType>;
#[cfg(feature = "kv_store")]
pub type Store = KVRouterStore<StoreType>;

pub trait AsSchedulerInterface {
    fn as_scheduler(&self) -> &dyn SchedulerInterface;
}

impl<T: SchedulerInterface> AsSchedulerInterface for T {
    fn as_scheduler(&self) -> &dyn SchedulerInterface {
        self
    }
}

#[async_trait::async_trait]
pub trait SchedulerInterface:
    ProcessTrackerInterface + QueueInterface + AsSchedulerInterface
{
}

#[async_trait::async_trait]
impl SchedulerInterface for Store {}

#[async_trait::async_trait]
impl SchedulerInterface for MockDb {}

#[async_trait::async_trait]
pub trait SchedulerAppState: Send + Sync + Clone {
    fn get_tenants(&self) -> Vec<id_type::TenantId>;
}
#[async_trait::async_trait]
pub trait SchedulerSessionState: Send + Sync + Clone {
    fn get_db(&self) -> Box<dyn SchedulerInterface>;
}
pub async fn start_process_tracker<
    T: SchedulerAppState + 'static,
    U: SchedulerSessionState + 'static,
    F,
>(
    state: &T,
    scheduler_flow: SchedulerFlow,
    scheduler_settings: Arc<SchedulerSettings>,
    channel: (mpsc::Sender<()>, mpsc::Receiver<()>),
    runner_from_task: impl workflows::ProcessTrackerWorkflows<U> + 'static + Copy + std::fmt::Debug,
    app_state_to_session_state: F,
) -> CustomResult<(), errors::ProcessTrackerError>
where
    F: Fn(&T, &id_type::TenantId) -> CustomResult<U, errors::ProcessTrackerError>,
{
    match scheduler_flow {
        SchedulerFlow::Producer => {
            producer::start_producer(
                state,
                scheduler_settings,
                channel,
                app_state_to_session_state,
            )
            .await?
        }
        SchedulerFlow::Consumer => {
            consumer::start_consumer(
                state,
                scheduler_settings,
                runner_from_task,
                channel,
                app_state_to_session_state,
            )
            .await?
        }
        SchedulerFlow::Cleaner => {
            error!("This flow has not been implemented yet!");
        }
    }
    Ok(())
}


// Function: connector_list_profile
// File: crates/router/src/routes/admin.rs
// Module: router

pub fn connector_list_profile(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<common_utils::id_type::MerchantId>,
) -> HttpResponse


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

pub struct XenditSplitRoute


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

pub mod transformers;

use std::sync::LazyLock;

use base64::Engine;
use common_enums::enums;
use common_utils::{
    consts,
    errors::CustomResult,
    ext_traits::BytesExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, MinorUnit, MinorUnitForConnector},
};
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, CompleteAuthorize, PSync, PaymentMethodToken, PreProcessing,
            Session, SetupMandate, Void,
        },
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, CompleteAuthorizeData, PaymentMethodTokenizationData,
        PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData, PaymentsPreProcessingData,
        PaymentsSessionData, PaymentsSyncData, RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
        PaymentsCompleteAuthorizeRouterData, PaymentsPreProcessingRouterData,
        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::{Mask, PeekInterface};
use transformers as paysafe;

use crate::{
    constants::headers,
    types::ResponseRouterData,
    utils::{
        self, PaymentsSyncRequestData, RefundsRequestData as OtherRefundsRequestData,
        RouterData as _,
    },
};

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

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

impl api::Payment for Paysafe {}
impl api::PaymentSession for Paysafe {}
impl api::ConnectorAccessToken for Paysafe {}
impl api::MandateSetup for Paysafe {}
impl api::PaymentAuthorize for Paysafe {}
impl api::PaymentSync for Paysafe {}
impl api::PaymentCapture for Paysafe {}
impl api::PaymentVoid for Paysafe {}
impl api::Refund for Paysafe {}
impl api::RefundExecute for Paysafe {}
impl api::RefundSync for Paysafe {}
impl api::PaymentToken for Paysafe {}

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

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Paysafe
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 Paysafe {
    fn id(&self) -> &'static str {
        "paysafe"
    }

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

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = paysafe::PaysafeAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        let auth_key = format!("{}:{}", auth.username.peek(), auth.password.peek());
        let auth_header = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_key));
        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            auth_header.into_masked(),
        )])
    }

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

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

        let detail_message = response
            .error
            .details
            .as_ref()
            .and_then(|d| d.first().cloned());
        let field_error_message = response
            .error
            .field_errors
            .as_ref()
            .and_then(|f| f.first().map(|fe| fe.error.clone()));

        let reason = match (detail_message, field_error_message) {
            (Some(detail), Some(field)) => Some(format!("{detail}, {field}")),
            (Some(detail), None) => Some(detail),
            (None, Some(field)) => Some(field),
            (None, None) => Some(response.error.message.clone()),
        };

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.error.code,
            message: response.error.message,
            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 Paysafe {
    fn validate_psync_reference_id(
        &self,
        _data: &PaymentsSyncData,
        _is_three_ds: bool,
        _status: enums::AttemptStatus,
        _connector_meta_data: Option<common_utils::pii::SecretSerdeValue>,
    ) -> CustomResult<(), errors::ConnectorError> {
        Ok(())
    }
}

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

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

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

impl api::PaymentsPreProcessing for Paysafe {}

impl ConnectorIntegration<PreProcessing, PaymentsPreProcessingData, PaymentsResponseData>
    for Paysafe
{
    fn get_headers(
        &self,
        req: &PaymentsPreProcessingRouterData,
        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: &PaymentsPreProcessingRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}v1/paymenthandles", self.base_url(connectors),))
    }

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

        let connector_router_data = paysafe::PaysafeRouterData::from((amount, req));
        let connector_req = paysafe::PaysafePaymentHandleRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsPreProcessingRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsPreProcessingRouterData, errors::ConnectorError> {
        let response: paysafe::PaysafePaymentHandleResponse = res
            .response
            .parse_struct("PaysafePaymentHandleResponse")
            .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<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Paysafe {
    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> {
        match req.payment_method {
            enums::PaymentMethod::Card if !req.is_three_ds() => {
                Ok(format!("{}v1/payments", self.base_url(connectors)))
            }
            enums::PaymentMethod::Wallet
                if req.request.payment_method_type == Some(enums::PaymentMethodType::ApplePay) =>
            {
                Ok(format!("{}v1/payments", self.base_url(connectors)))
            }
            _ => Ok(format!("{}v1/paymenthandles", self.base_url(connectors),)),
        }
    }

    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 = paysafe::PaysafeRouterData::from((amount, req));
        match req.payment_method {
            //Card No 3DS
            enums::PaymentMethod::Card if !req.is_three_ds() => {
                let connector_req =
                    paysafe::PaysafePaymentsRequest::try_from(&connector_router_data)?;
                Ok(RequestContent::Json(Box::new(connector_req)))
            }
            enums::PaymentMethod::Wallet
                if req.request.payment_method_type == Some(enums::PaymentMethodType::ApplePay) =>
            {
                let connector_req =
                    paysafe::PaysafePaymentsRequest::try_from(&connector_router_data)?;
                Ok(RequestContent::Json(Box::new(connector_req)))
            }
            _ => {
                let connector_req =
                    paysafe::PaysafePaymentHandleRequest::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> {
        match data.payment_method {
            enums::PaymentMethod::Card if !data.is_three_ds() => {
                let response: paysafe::PaysafePaymentsResponse = res
                    .response
                    .parse_struct("Paysafe 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,
                })
            }
            enums::PaymentMethod::Wallet
                if data.request.payment_method_type == Some(enums::PaymentMethodType::ApplePay) =>
            {
                let response: paysafe::PaysafePaymentsResponse = res
                    .response
                    .parse_struct("Paysafe 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,
                })
            }
            _ => {
                let response: paysafe::PaysafePaymentHandleResponse = res
                    .response
                    .parse_struct("Paysafe PaymentHandleResponse")
                    .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 api::PaymentsCompleteAuthorize for Paysafe {}

impl ConnectorIntegration<CompleteAuthorize, CompleteAuthorizeData, PaymentsResponseData>
    for Paysafe
{
    fn get_headers(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        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: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}v1/payments", self.base_url(connectors),))
    }
    fn get_request_body(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        _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 = paysafe::PaysafeRouterData::from((amount, req));
        let connector_req = paysafe::PaysafePaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }
    fn build_request(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsCompleteAuthorizeType::get_url(
                    self, req, connectors,
                )?)
                .attach_default_headers()
                .headers(types::PaymentsCompleteAuthorizeType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(types::PaymentsCompleteAuthorizeType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }
    fn handle_response(
        &self,
        data: &PaymentsCompleteAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCompleteAuthorizeRouterData, errors::ConnectorError> {
        let response: paysafe::PaysafePaymentsResponse = res
            .response
            .parse_struct("Paysafe PaymentsAuthorizeResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

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

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

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Paysafe {
    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> {
        let connector_payment_id = req.connector_request_reference_id.clone();
        let connector_transaction_id = req.request.get_optional_connector_transaction_id();

        let base_url = self.base_url(connectors);

        let url = if connector_transaction_id.is_some() {
            format!("{base_url}v1/payments?merchantRefNum={connector_payment_id}")
        } else {
            format!("{base_url}v1/paymenthandles?merchantRefNum={connector_payment_id}")
        };

        Ok(url)
    }

    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: paysafe::PaysafeSyncResponse = res
            .response
            .parse_struct("paysafe PaysafeSyncResponse")
            .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 Paysafe {
    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> {
        let connector_payment_id = req.request.connector_transaction_id.clone();
        Ok(format!(
            "{}v1/payments/{}/settlements",
            self.base_url(connectors),
            connector_payment_id
        ))
    }

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

        let connector_router_data = paysafe::PaysafeRouterData::from((amount, req));
        let connector_req = paysafe::PaysafeCaptureRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        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: paysafe::PaysafeSettlementResponse = res
            .response
            .parse_struct("PaysafeSettlementResponse")
            .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 Paysafe {
    fn get_headers(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

        let connector_router_data = paysafe::PaysafeRouterData::from((amount, req));
        let connector_req = paysafe::PaysafeCaptureRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }
    fn build_request(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&types::PaymentsVoidType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?)
                .set_body(types::PaymentsVoidType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

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

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

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Paysafe {
    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> {
        let connector_payment_id = req.request.connector_transaction_id.clone();
        Ok(format!(
            "{}v1/settlements/{}/refunds",
            self.base_url(connectors),
            connector_payment_id
        ))
    }

    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 = paysafe::PaysafeRouterData::from((refund_amount, req));
        let connector_req = paysafe::PaysafeRefundRequest::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: paysafe::RefundResponse = res
            .response
            .parse_struct("paysafe 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 Paysafe {
    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> {
        let connector_refund_id = req.request.get_connector_refund_id()?;
        Ok(format!(
            "{}v1/refunds/{}",
            self.base_url(connectors),
            connector_refund_id
        ))
    }

    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: paysafe::RefundResponse = res
            .response
            .parse_struct("paysafe 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 Paysafe {
    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 PAYSAFE_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> = LazyLock::new(|| {
    let supported_capture_methods = vec![
        enums::CaptureMethod::Automatic,
        enums::CaptureMethod::Manual,
    ];
    let supported_capture_methods2 = vec![enums::CaptureMethod::Automatic];

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

    let mut paysafe_supported_payment_methods = SupportedPaymentMethods::new();

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

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

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

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

    paysafe_supported_payment_methods.add(
        enums::PaymentMethod::BankRedirect,
        enums::PaymentMethodType::Interac,


// Struct: TrustpayAuthType
// File: crates/hyperswitch_connectors/src/connectors/trustpay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TrustpayAuthType


// Struct: PaymentMethod
// File: crates/hyperswitch_connectors/src/connectors/rapyd/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentMethod


// Trait: UnifiedAuthenticationService
// File: crates/router/src/core/unified_authentication_service/types.rs
// Module: router

pub trait UnifiedAuthenticationService


// Function: get_sdk_event_metrics
// File: crates/router/src/analytics.rs
// Module: router

// Documentation: Panics if `json_payload` array does not contain one `GetSdkEventMetricRequest` element.

pub fn get_sdk_event_metrics(
        state: web::Data<AppState>,
        req: actix_web::HttpRequest,
        json_payload: web::Json<[GetSdkEventMetricRequest; 1]>,
    ) -> impl Responder


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

pub fn new() -> &'static Self


// Trait: AuthServiceBankAccountCredentials
// File: crates/pm_auth/src/types/api/auth_service.rs
// Module: pm_auth

pub trait AuthServiceBankAccountCredentials: super::ConnectorIntegration<
    BankAccountCredentials,
    BankAccountCredentialsRequest,
    BankAccountCredentialsResponse,
>


// Struct: ErrorDistributionAccumulator
// File: crates/analytics/src/payment_intents/accumulator.rs
// Module: analytics
// Implementations: 0

pub struct ErrorDistributionAccumulator


// Implementation: impl PaymentToken for for Netcetera
// File: crates/hyperswitch_connectors/src/connectors/netcetera.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl PaymentToken for for Netcetera


// Implementation: impl ApiEventMetric for for RevenueRecoveryDataBackfillResponse
// File: crates/api_models/src/revenue_recovery_data_backfill.rs
// Module: api_models
// Methods: 1 total (0 public)

impl ApiEventMetric for for RevenueRecoveryDataBackfillResponse


// Function: construct_router_data
// File: crates/router/src/core/authentication/transformers.rs
// Module: router

pub fn construct_router_data<F: Clone, Req, Res>(
    state: &SessionState,
    authentication_connector_name: String,
    payment_method: PaymentMethod,
    merchant_id: common_utils::id_type::MerchantId,
    address: types::PaymentAddress,
    request_data: Req,
    merchant_connector_account: &payments_helpers::MerchantConnectorAccountType,
    psd2_sca_exemption_type: Option<common_enums::ScaExemptionType>,
    payment_id: common_utils::id_type::PaymentId,
) -> RouterResult<types::RouterData<F, Req, Res>>


// Struct: SyncDetails
// File: crates/hyperswitch_connectors/src/connectors/datatrans/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SyncDetails


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

pub fn get_merchant_reference_id(&self) -> id_type::MerchantId


// Function: get_additional_amount
// File: crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
// Module: hyperswitch_domain_models

pub fn get_additional_amount(&self) -> MinorUnit


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

pub fn new() -> &'static Self


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

impl api::RefundExecute for for Adyenplatform


// Function: create_domain_model
// File: crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
// Module: hyperswitch_domain_models

pub fn create_domain_model(
        payment_intent: &super::PaymentIntent,
        cell_id: id_type::CellId,
        storage_scheme: storage_enums::MerchantStorageScheme,
        request: &api_models::payments::PaymentsConfirmIntentRequest,
        encrypted_data: DecryptedPaymentAttempt,
    ) -> CustomResult<Self, errors::api_error_response::ApiErrorResponse>


// Function: create_domain_model_using_record_request
// File: crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
// Module: hyperswitch_domain_models

pub fn create_domain_model_using_record_request(
        payment_intent: &super::PaymentIntent,
        cell_id: id_type::CellId,
        storage_scheme: storage_enums::MerchantStorageScheme,
        request: &api_models::payments::PaymentsAttemptRecordRequest,
        encrypted_data: DecryptedPaymentAttempt,
    ) -> CustomResult<Self, errors::api_error_response::ApiErrorResponse>


// Struct: Mandates
// File: crates/router/src/routes/app.rs
// Module: router
// Implementations: 1

pub struct Mandates


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

pub fn new() -> &'static Self


// File: crates/router/src/core/disputes/transformers.rs
// Module: router
// Public functions: 5

use api_models::disputes::EvidenceType;
use common_utils::errors::CustomResult;
use error_stack::ResultExt;

use crate::{
    core::{errors, files::helpers::retrieve_file_and_provider_file_id_from_file_id},
    routes::SessionState,
    types::{
        api::{self, DisputeEvidence},
        domain,
        transformers::ForeignFrom,
        SubmitEvidenceRequestData,
    },
};

pub async fn get_evidence_request_data(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    evidence_request: api_models::disputes::SubmitEvidenceRequest,
    dispute: &diesel_models::dispute::Dispute,
) -> CustomResult<SubmitEvidenceRequestData, errors::ApiErrorResponse> {
    let cancellation_policy_file_info = retrieve_file_and_provider_file_id_from_file_id(
        state,
        evidence_request.cancellation_policy,
        None,
        merchant_context,
        api::FileDataRequired::NotRequired,
    )
    .await?;
    let customer_communication_file_info = retrieve_file_and_provider_file_id_from_file_id(
        state,
        evidence_request.customer_communication,
        None,
        merchant_context,
        api::FileDataRequired::NotRequired,
    )
    .await?;
    let customer_sifnature_file_info = retrieve_file_and_provider_file_id_from_file_id(
        state,
        evidence_request.customer_signature,
        None,
        merchant_context,
        api::FileDataRequired::NotRequired,
    )
    .await?;
    let receipt_file_info = retrieve_file_and_provider_file_id_from_file_id(
        state,
        evidence_request.receipt,
        None,
        merchant_context,
        api::FileDataRequired::NotRequired,
    )
    .await?;
    let refund_policy_file_info = retrieve_file_and_provider_file_id_from_file_id(
        state,
        evidence_request.refund_policy,
        None,
        merchant_context,
        api::FileDataRequired::NotRequired,
    )
    .await?;
    let service_documentation_file_info = retrieve_file_and_provider_file_id_from_file_id(
        state,
        evidence_request.service_documentation,
        None,
        merchant_context,
        api::FileDataRequired::NotRequired,
    )
    .await?;
    let shipping_documentation_file_info = retrieve_file_and_provider_file_id_from_file_id(
        state,
        evidence_request.shipping_documentation,
        None,
        merchant_context,
        api::FileDataRequired::NotRequired,
    )
    .await?;
    let invoice_showing_distinct_transactions_file_info =
        retrieve_file_and_provider_file_id_from_file_id(
            state,
            evidence_request.invoice_showing_distinct_transactions,
            None,
            merchant_context,
            api::FileDataRequired::NotRequired,
        )
        .await?;
    let recurring_transaction_agreement_file_info =
        retrieve_file_and_provider_file_id_from_file_id(
            state,
            evidence_request.recurring_transaction_agreement,
            None,
            merchant_context,
            api::FileDataRequired::NotRequired,
        )
        .await?;
    let uncategorized_file_info = retrieve_file_and_provider_file_id_from_file_id(
        state,
        evidence_request.uncategorized_file,
        None,
        merchant_context,
        api::FileDataRequired::NotRequired,
    )
    .await?;
    Ok(SubmitEvidenceRequestData {
        dispute_id: dispute.dispute_id.clone(),
        dispute_status: dispute.dispute_status,
        connector_dispute_id: dispute.connector_dispute_id.clone(),
        access_activity_log: evidence_request.access_activity_log,
        billing_address: evidence_request.billing_address,
        cancellation_policy: cancellation_policy_file_info.file_data,
        cancellation_policy_provider_file_id: cancellation_policy_file_info.provider_file_id,
        cancellation_policy_disclosure: evidence_request.cancellation_policy_disclosure,
        cancellation_rebuttal: evidence_request.cancellation_rebuttal,
        customer_communication: customer_communication_file_info.file_data,
        customer_communication_provider_file_id: customer_communication_file_info.provider_file_id,
        customer_email_address: evidence_request.customer_email_address,
        customer_name: evidence_request.customer_name,
        customer_purchase_ip: evidence_request.customer_purchase_ip,
        customer_signature: customer_sifnature_file_info.file_data,
        customer_signature_provider_file_id: customer_sifnature_file_info.provider_file_id,
        product_description: evidence_request.product_description,
        receipt: receipt_file_info.file_data,
        receipt_provider_file_id: receipt_file_info.provider_file_id,
        refund_policy: refund_policy_file_info.file_data,
        refund_policy_provider_file_id: refund_policy_file_info.provider_file_id,
        refund_policy_disclosure: evidence_request.refund_policy_disclosure,
        refund_refusal_explanation: evidence_request.refund_refusal_explanation,
        service_date: evidence_request.service_date,
        service_documentation: service_documentation_file_info.file_data,
        service_documentation_provider_file_id: service_documentation_file_info.provider_file_id,
        shipping_address: evidence_request.shipping_address,
        shipping_carrier: evidence_request.shipping_carrier,
        shipping_date: evidence_request.shipping_date,
        shipping_documentation: shipping_documentation_file_info.file_data,
        shipping_documentation_provider_file_id: shipping_documentation_file_info.provider_file_id,
        shipping_tracking_number: evidence_request.shipping_tracking_number,
        invoice_showing_distinct_transactions: invoice_showing_distinct_transactions_file_info
            .file_data,
        invoice_showing_distinct_transactions_provider_file_id:
            invoice_showing_distinct_transactions_file_info.provider_file_id,
        recurring_transaction_agreement: recurring_transaction_agreement_file_info.file_data,
        recurring_transaction_agreement_provider_file_id: recurring_transaction_agreement_file_info
            .provider_file_id,
        uncategorized_file: uncategorized_file_info.file_data,
        uncategorized_file_provider_file_id: uncategorized_file_info.provider_file_id,
        uncategorized_text: evidence_request.uncategorized_text,
        cancellation_policy_file_type: cancellation_policy_file_info.file_type,
        customer_communication_file_type: customer_communication_file_info.file_type,
        customer_signature_file_type: customer_sifnature_file_info.file_type,
        receipt_file_type: receipt_file_info.file_type,
        refund_policy_file_type: refund_policy_file_info.file_type,
        service_documentation_file_type: service_documentation_file_info.file_type,
        shipping_documentation_file_type: shipping_documentation_file_info.file_type,
        invoice_showing_distinct_transactions_file_type:
            invoice_showing_distinct_transactions_file_info.file_type,
        recurring_transaction_agreement_file_type: recurring_transaction_agreement_file_info
            .file_type,
        uncategorized_file_type: uncategorized_file_info.file_type,
    })
}

pub fn update_dispute_evidence(
    dispute_evidence: DisputeEvidence,
    evidence_type: api::EvidenceType,
    file_id: String,
) -> DisputeEvidence {
    match evidence_type {
        api::EvidenceType::CancellationPolicy => DisputeEvidence {
            cancellation_policy: Some(file_id),
            ..dispute_evidence
        },
        api::EvidenceType::CustomerCommunication => DisputeEvidence {
            customer_communication: Some(file_id),
            ..dispute_evidence
        },
        api::EvidenceType::CustomerSignature => DisputeEvidence {
            customer_signature: Some(file_id),
            ..dispute_evidence
        },
        api::EvidenceType::Receipt => DisputeEvidence {
            receipt: Some(file_id),
            ..dispute_evidence
        },
        api::EvidenceType::RefundPolicy => DisputeEvidence {
            refund_policy: Some(file_id),
            ..dispute_evidence
        },
        api::EvidenceType::ServiceDocumentation => DisputeEvidence {
            service_documentation: Some(file_id),
            ..dispute_evidence
        },
        api::EvidenceType::ShippingDocumentation => DisputeEvidence {
            shipping_documentation: Some(file_id),
            ..dispute_evidence
        },
        api::EvidenceType::InvoiceShowingDistinctTransactions => DisputeEvidence {
            invoice_showing_distinct_transactions: Some(file_id),
            ..dispute_evidence
        },
        api::EvidenceType::RecurringTransactionAgreement => DisputeEvidence {
            recurring_transaction_agreement: Some(file_id),
            ..dispute_evidence
        },
        api::EvidenceType::UncategorizedFile => DisputeEvidence {
            uncategorized_file: Some(file_id),
            ..dispute_evidence
        },
    }
}

pub async fn get_dispute_evidence_block(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    evidence_type: EvidenceType,
    file_id: String,
) -> CustomResult<api_models::disputes::DisputeEvidenceBlock, errors::ApiErrorResponse> {
    let file_metadata = state
        .store
        .find_file_metadata_by_merchant_id_file_id(
            merchant_context.get_merchant_account().get_id(),
            &file_id,
        )
        .await
        .change_context(errors::ApiErrorResponse::FileNotFound)
        .attach_printable("Unable to retrieve file_metadata")?;
    let file_metadata_response =
        api_models::files::FileMetadataResponse::foreign_from(file_metadata);
    Ok(api_models::disputes::DisputeEvidenceBlock {
        evidence_type,
        file_metadata_response,
    })
}

pub fn delete_evidence_file(
    dispute_evidence: DisputeEvidence,
    evidence_type: EvidenceType,
) -> DisputeEvidence {
    match evidence_type {
        EvidenceType::CancellationPolicy => DisputeEvidence {
            cancellation_policy: None,
            ..dispute_evidence
        },
        EvidenceType::CustomerCommunication => DisputeEvidence {
            customer_communication: None,
            ..dispute_evidence
        },
        EvidenceType::CustomerSignature => DisputeEvidence {
            customer_signature: None,
            ..dispute_evidence
        },
        EvidenceType::Receipt => DisputeEvidence {
            receipt: None,
            ..dispute_evidence
        },
        EvidenceType::RefundPolicy => DisputeEvidence {
            refund_policy: None,
            ..dispute_evidence
        },
        EvidenceType::ServiceDocumentation => DisputeEvidence {
            service_documentation: None,
            ..dispute_evidence
        },
        EvidenceType::ShippingDocumentation => DisputeEvidence {
            shipping_documentation: None,
            ..dispute_evidence
        },
        EvidenceType::InvoiceShowingDistinctTransactions => DisputeEvidence {
            invoice_showing_distinct_transactions: None,
            ..dispute_evidence
        },
        EvidenceType::RecurringTransactionAgreement => DisputeEvidence {
            recurring_transaction_agreement: None,
            ..dispute_evidence
        },
        EvidenceType::UncategorizedFile => DisputeEvidence {
            uncategorized_file: None,
            ..dispute_evidence
        },
    }
}

pub async fn get_dispute_evidence_vec(
    state: &SessionState,
    merchant_context: domain::MerchantContext,
    dispute_evidence: DisputeEvidence,
) -> CustomResult<Vec<api_models::disputes::DisputeEvidenceBlock>, errors::ApiErrorResponse> {
    let mut dispute_evidence_blocks: Vec<api_models::disputes::DisputeEvidenceBlock> = vec![];
    if let Some(cancellation_policy_block) = dispute_evidence.cancellation_policy {
        dispute_evidence_blocks.push(
            get_dispute_evidence_block(
                state,
                &merchant_context,
                EvidenceType::CancellationPolicy,
                cancellation_policy_block,
            )
            .await?,
        )
    }
    if let Some(customer_communication_block) = dispute_evidence.customer_communication {
        dispute_evidence_blocks.push(
            get_dispute_evidence_block(
                state,
                &merchant_context,
                EvidenceType::CustomerCommunication,
                customer_communication_block,
            )
            .await?,
        )
    }
    if let Some(customer_signature_block) = dispute_evidence.customer_signature {
        dispute_evidence_blocks.push(
            get_dispute_evidence_block(
                state,
                &merchant_context,
                EvidenceType::CustomerSignature,
                customer_signature_block,
            )
            .await?,
        )
    }
    if let Some(receipt_block) = dispute_evidence.receipt {
        dispute_evidence_blocks.push(
            get_dispute_evidence_block(
                state,
                &merchant_context,
                EvidenceType::Receipt,
                receipt_block,
            )
            .await?,
        )
    }
    if let Some(refund_policy_block) = dispute_evidence.refund_policy {
        dispute_evidence_blocks.push(
            get_dispute_evidence_block(
                state,
                &merchant_context,
                EvidenceType::RefundPolicy,
                refund_policy_block,
            )
            .await?,
        )
    }
    if let Some(service_documentation_block) = dispute_evidence.service_documentation {
        dispute_evidence_blocks.push(
            get_dispute_evidence_block(
                state,
                &merchant_context,
                EvidenceType::ServiceDocumentation,
                service_documentation_block,
            )
            .await?,
        )
    }
    if let Some(shipping_documentation_block) = dispute_evidence.shipping_documentation {
        dispute_evidence_blocks.push(
            get_dispute_evidence_block(
                state,
                &merchant_context,
                EvidenceType::ShippingDocumentation,
                shipping_documentation_block,
            )
            .await?,
        )
    }
    if let Some(invoice_showing_distinct_transactions_block) =
        dispute_evidence.invoice_showing_distinct_transactions
    {
        dispute_evidence_blocks.push(
            get_dispute_evidence_block(
                state,
                &merchant_context,
                EvidenceType::InvoiceShowingDistinctTransactions,
                invoice_showing_distinct_transactions_block,
            )
            .await?,
        )
    }
    if let Some(recurring_transaction_agreement_block) =
        dispute_evidence.recurring_transaction_agreement
    {
        dispute_evidence_blocks.push(
            get_dispute_evidence_block(
                state,
                &merchant_context,
                EvidenceType::RecurringTransactionAgreement,
                recurring_transaction_agreement_block,
            )
            .await?,
        )
    }
    if let Some(uncategorized_file_block) = dispute_evidence.uncategorized_file {
        dispute_evidence_blocks.push(
            get_dispute_evidence_block(
                state,
                &merchant_context,
                EvidenceType::UncategorizedFile,
                uncategorized_file_block,
            )
            .await?,
        )
    }
    Ok(dispute_evidence_blocks)
}


// File: crates/diesel_models/src/query/payment_intent.rs
// Module: diesel_models
// Public functions: 9

use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods};

use super::generics;
#[cfg(feature = "v1")]
use crate::schema::payment_intent::dsl;
#[cfg(feature = "v2")]
use crate::schema_v2::payment_intent::dsl;
use crate::{
    errors,
    payment_intent::{self, PaymentIntent, PaymentIntentNew},
    PgPooledConn, StorageResult,
};

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

impl PaymentIntent {
    #[cfg(feature = "v2")]
    pub async fn update(
        self,
        conn: &PgPooledConn,
        payment_intent_update: payment_intent::PaymentIntentUpdateInternal,
    ) -> StorageResult<Self> {
        match generics::generic_update_by_id::<<Self as HasTable>::Table, _, _, _>(
            conn,
            self.id.to_owned(),
            payment_intent_update,
        )
        .await
        {
            Err(error) => match error.current_context() {
                errors::DatabaseError::NoFieldsToUpdate => Ok(self),
                _ => Err(error),
            },
            Ok(payment_intent) => Ok(payment_intent),
        }
    }

    #[cfg(feature = "v2")]
    pub async fn find_by_global_id(
        conn: &PgPooledConn,
        id: &common_utils::id_type::GlobalPaymentId,
    ) -> StorageResult<Self> {
        generics::generic_find_by_id::<<Self as HasTable>::Table, _, _>(conn, id.to_owned()).await
    }

    #[cfg(feature = "v1")]
    pub async fn update(
        self,
        conn: &PgPooledConn,
        payment_intent: payment_intent::PaymentIntentUpdate,
    ) -> StorageResult<Self> {
        match generics::generic_update_with_results::<<Self as HasTable>::Table, _, _, _>(
            conn,
            dsl::payment_id
                .eq(self.payment_id.to_owned())
                .and(dsl::merchant_id.eq(self.merchant_id.to_owned())),
            payment_intent::PaymentIntentUpdateInternal::from(payment_intent),
        )
        .await
        {
            Err(error) => match error.current_context() {
                errors::DatabaseError::NoFieldsToUpdate => Ok(self),
                _ => Err(error),
            },
            Ok(mut payment_intents) => payment_intents
                .pop()
                .ok_or(error_stack::report!(errors::DatabaseError::NotFound)),
        }
    }

    #[cfg(feature = "v2")]
    pub async fn find_by_merchant_reference_id_merchant_id(
        conn: &PgPooledConn,
        merchant_reference_id: &str,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::merchant_reference_id.eq(merchant_reference_id.to_owned())),
        )
        .await
    }

    // This query should be removed in the future because direct queries to the intent table without an intent ID are not allowed.
    // In an active-active setup, a lookup table should be implemented, and the merchant reference ID will serve as the idempotency key.
    #[cfg(feature = "v2")]
    pub async fn find_by_merchant_reference_id_profile_id(
        conn: &PgPooledConn,
        merchant_reference_id: &common_utils::id_type::PaymentReferenceId,
        profile_id: &common_utils::id_type::ProfileId,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::profile_id
                .eq(profile_id.to_owned())
                .and(dsl::merchant_reference_id.eq(merchant_reference_id.to_owned())),
        )
        .await
    }

    #[cfg(feature = "v1")]
    pub async fn find_by_payment_id_merchant_id(
        conn: &PgPooledConn,
        payment_id: &common_utils::id_type::PaymentId,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::payment_id.eq(payment_id.to_owned())),
        )
        .await
    }

    #[cfg(feature = "v2")]
    pub async fn find_optional_by_merchant_reference_id_merchant_id(
        conn: &PgPooledConn,
        merchant_reference_id: &str,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> StorageResult<Option<Self>> {
        generics::generic_find_one_optional::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::merchant_reference_id.eq(merchant_reference_id.to_owned())),
        )
        .await
    }

    #[cfg(feature = "v1")]
    pub async fn find_optional_by_payment_id_merchant_id(
        conn: &PgPooledConn,
        payment_id: &common_utils::id_type::PaymentId,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> StorageResult<Option<Self>> {
        generics::generic_find_one_optional::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::payment_id.eq(payment_id.to_owned())),
        )
        .await
    }
}


// Function: get_link_with_token
// File: crates/router/src/services/email/types.rs
// Module: router

pub fn get_link_with_token(
    base_url: impl std::fmt::Display,
    token: impl std::fmt::Display,
    action: impl std::fmt::Display,
    auth_id: &Option<impl std::fmt::Display>,
    theme_id: &Option<impl std::fmt::Display>,
) -> String


// Function: validate
// File: crates/external_services/src/crm.rs
// Module: external_services

// Documentation: Verifies that the client configuration is usable

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


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

impl api::RefundExecute for for Bambora