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

pub mod transformers;

use base64::Engine;
use common_utils::{
    errors::CustomResult,
    ext_traits::BytesExt,
    request::{Method, Request, RequestBuilder, RequestContent},
};
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},
        ExternalVaultInsertFlow, ExternalVaultRetrieveFlow,
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData, VaultRequestData,
    },
    router_response_types::{PaymentsResponseData, RefundsResponseData, VaultResponseData},
    types::VaultRouterData,
};
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;
use transformers as vgs;

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

#[derive(Clone)]
pub struct Vgs;

impl api::Payment for Vgs {}
impl api::PaymentSession for Vgs {}
impl api::ConnectorAccessToken for Vgs {}
impl api::MandateSetup for Vgs {}
impl api::PaymentAuthorize for Vgs {}
impl api::PaymentSync for Vgs {}
impl api::PaymentCapture for Vgs {}
impl api::PaymentVoid for Vgs {}
impl api::Refund for Vgs {}
impl api::RefundExecute for Vgs {}
impl api::RefundSync for Vgs {}
impl api::PaymentToken for Vgs {}
impl api::ExternalVaultInsert for Vgs {}
impl api::ExternalVault for Vgs {}
impl api::ExternalVaultRetrieve for Vgs {}

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

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Vgs
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 auth = vgs::VgsAuthType::try_from(&req.connector_auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        let auth_value = auth
            .username
            .zip(auth.password)
            .map(|(username, password)| {
                format!(
                    "Basic {}",
                    common_utils::consts::BASE64_ENGINE.encode(format!("{username}:{password}"))
                )
            });
        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            auth_value.into_masked(),
        )])
    }
}

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

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

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

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

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

        let error = response
            .errors
            .first()
            .ok_or(errors::ConnectorError::ResponseHandlingFailed)?;

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

impl ConnectorValidation for Vgs {}

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

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

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

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

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

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

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

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

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

impl ConnectorIntegration<ExternalVaultInsertFlow, VaultRequestData, VaultResponseData> for Vgs {
    fn get_url(
        &self,
        _req: &VaultRouterData<ExternalVaultInsertFlow>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}aliases", self.base_url(connectors)))
    }

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

    fn get_request_body(
        &self,
        req: &VaultRouterData<ExternalVaultInsertFlow>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = vgs::VgsInsertRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &VaultRouterData<ExternalVaultInsertFlow>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<VaultRouterData<ExternalVaultInsertFlow>, errors::ConnectorError> {
        let response: vgs::VgsInsertResponse = res
            .response
            .parse_struct("VgsInsertResponse")
            .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<ExternalVaultRetrieveFlow, VaultRequestData, VaultResponseData> for Vgs {
    fn get_url(
        &self,
        req: &VaultRouterData<ExternalVaultRetrieveFlow>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let alias = req.request.connector_vault_id.clone().ok_or(
            errors::ConnectorError::MissingRequiredField {
                field_name: "connector_vault_id",
            },
        )?;

        Ok(format!("{}aliases/{alias}", self.base_url(connectors)))
    }

    fn get_headers(
        &self,
        req: &VaultRouterData<ExternalVaultRetrieveFlow>,
        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: &VaultRouterData<ExternalVaultRetrieveFlow>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&types::ExternalVaultRetrieveType::get_url(
                    self, req, connectors,
                )?)
                .attach_default_headers()
                .headers(types::ExternalVaultRetrieveType::get_headers(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &VaultRouterData<ExternalVaultRetrieveFlow>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<VaultRouterData<ExternalVaultRetrieveFlow>, errors::ConnectorError> {
        let response: vgs::VgsRetrieveResponse =
            res.response
                .parse_struct("VgsRetrieveResponse")
                .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 Vgs {
    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))
    }
}

impl ConnectorSpecifications for Vgs {}


                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsIncrementalAuthorizationRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<
        RouterData<
            IncrementalAuthorization,
            PaymentsIncrementalAuthorizationData,
            PaymentsResponseData,
        >,
        ConnectorError,
    > {
        let response: stripe::PaymentIntentResponse = res
            .response
            .parse_struct("PaymentIntentResponse")
            .change_context(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(ConnectorError::ResponseHandlingFailed)
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, ConnectorError> {
        let response: stripe::ErrorResponse = res
            .response
            .parse_struct("ErrorResponse")
            .change_context(ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_error_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response
                .error
                .code
                .clone()
                .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
            message: response
                .error
                .message
                .clone()
                .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
            reason: response.error.message.map(|message| {
                response
                    .error
                    .decline_code
                    .clone()
                    .map(|decline_code| {
                        format!("message - {message}, decline_code - {decline_code}")
                    })
                    .unwrap_or(message)
            }),
            attempt_status: None,
            connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
            network_advice_code: response.error.network_advice_code,
            network_decline_code: response.error.network_decline_code,
            network_error_message: response.error.decline_code.or(response.error.advice_code),
            connector_metadata: None,
        })
    }
}

impl ConnectorIntegration<UpdateMetadata, PaymentsUpdateMetadataData, PaymentsResponseData>
    for Stripe
{
    fn get_headers(
        &self,
        req: &RouterData<UpdateMetadata, PaymentsUpdateMetadataData, PaymentsResponseData>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        "application/x-www-form-urlencoded"
    }

    fn get_url(
        &self,
        req: &PaymentsUpdateMetadataRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, ConnectorError> {
        let payment_id = &req.request.connector_transaction_id;
        Ok(format!(
            "{}v1/payment_intents/{}",
            self.base_url(connectors),
            payment_id
        ))
    }

    fn get_request_body(
        &self,
        req: &PaymentsUpdateMetadataRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, ConnectorError> {
        let connector_req = stripe::UpdateMetadataRequest::try_from(req)?;
        Ok(RequestContent::FormUrlEncoded(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsUpdateMetadataRouterData,
        _event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsUpdateMetadataRouterData, ConnectorError> {
        router_env::logger::debug!("skipped parsing of the response");
        // If 200 status code, then metadata was updated successfully.
        let status = if res.status_code == 200 {
            PaymentResourceUpdateStatus::Success
        } else {
            PaymentResourceUpdateStatus::Failure
        };
        Ok(PaymentsUpdateMetadataRouterData {
            response: Ok(PaymentsResponseData::PaymentResourceUpdateResponse { status }),
            ..data.clone()
        })
    }

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

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Stripe {
    fn get_headers(
        &self,
        req: &PaymentsCancelRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        let mut header = vec![(
            CONTENT_TYPE.to_string(),
            PaymentsVoidType::get_content_type(self).to_string().into(),
        )];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);
        Ok(header)
    }

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

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

    fn get_request_body(
        &self,
        req: &PaymentsCancelRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, ConnectorError> {
        let connector_req = stripe::CancelRequest::try_from(req)?;
        Ok(RequestContent::FormUrlEncoded(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsCancelRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCancelRouterData, ConnectorError> {
        let response: stripe::PaymentIntentResponse = res
            .response
            .parse_struct("PaymentIntentResponse")
            .change_context(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(ConnectorError::ResponseHandlingFailed)
    }

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response
                .error
                .code
                .clone()
                .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
            message: response
                .error
                .code
                .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
            reason: response.error.message.map(|message| {
                response
                    .error
                    .decline_code
                    .clone()
                    .map(|decline_code| {
                        format!("message - {message}, decline_code - {decline_code}")
                    })
                    .unwrap_or(message)
            }),
            attempt_status: None,
            connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
            network_advice_code: response.error.network_advice_code,
            network_decline_code: response.error.network_decline_code,
            network_error_message: response.error.decline_code.or(response.error.advice_code),
            connector_metadata: None,
        })
    }
}

type Verify = dyn ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>;
impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData> for Stripe {
    fn get_headers(
        &self,
        req: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        let mut header = vec![(
            CONTENT_TYPE.to_string(),
            Verify::get_content_type(self).to_string().into(),
        )];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);
        Ok(header)
    }

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

    fn get_url(
        &self,
        _req: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        connectors: &Connectors,
    ) -> CustomResult<String, ConnectorError> {
        Ok(format!(
            "{}{}",
            self.base_url(connectors),
            "v1/setup_intents"
        ))
    }

    fn get_request_body(
        &self,
        req: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, ConnectorError> {
        let connector_req = stripe::SetupIntentRequest::try_from(req)?;
        Ok(RequestContent::FormUrlEncoded(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<
        RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
        ConnectorError,
    >
    where
        SetupMandate: Clone,
        SetupMandateRequestData: Clone,
        PaymentsResponseData: Clone,
    {
        let response: stripe::SetupIntentResponse = res
            .response
            .parse_struct("SetupIntentResponse")
            .change_context(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(ConnectorError::ResponseHandlingFailed)
    }

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response
                .error
                .code
                .clone()
                .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
            message: response
                .error
                .code
                .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
            reason: response.error.message.map(|message| {
                response
                    .error
                    .decline_code
                    .clone()
                    .map(|decline_code| {
                        format!("message - {message}, decline_code - {decline_code}")
                    })
                    .unwrap_or(message)
            }),
            attempt_status: None,
            connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
            network_advice_code: response.error.network_advice_code,
            network_decline_code: response.error.network_decline_code,
            network_error_message: response.error.decline_code.or(response.error.advice_code),
            connector_metadata: None,
        })
    }
}

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

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Stripe {
    fn get_headers(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        let mut header = vec![(
            CONTENT_TYPE.to_string(),
            RefundExecuteType::get_content_type(self).to_string().into(),
        )];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);

        if let Some(SplitRefundsRequest::StripeSplitRefund(ref stripe_split_refund)) =
            req.request.split_refunds.as_ref()
        {
            match &stripe_split_refund.charge_type {
                PaymentChargeType::Stripe(stripe_charge) => {
                    if stripe_charge == &StripeChargeType::Direct {
                        let mut customer_account_header = vec![(
                            STRIPE_COMPATIBLE_CONNECT_ACCOUNT.to_string(),
                            stripe_split_refund
                                .transfer_account_id
                                .clone()
                                .into_masked(),
                        )];
                        header.append(&mut customer_account_header);
                    }
                }
            }
        }
        Ok(header)
    }

    fn get_content_type(&self) -> &'static str {
        "application/x-www-form-urlencoded"
    }

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

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, ConnectorError> {
        let refund_amount = utils::convert_amount(
            self.amount_converter,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;
        let request_body = match req.request.split_refunds.as_ref() {
            Some(SplitRefundsRequest::StripeSplitRefund(_)) => RequestContent::FormUrlEncoded(
                Box::new(stripe::ChargeRefundRequest::try_from(req)?),
            ),
            _ => RequestContent::FormUrlEncoded(Box::new(stripe::RefundRequest::try_from((
                req,
                refund_amount,
            ))?)),
        };
        Ok(request_body)
    }

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

    #[instrument(skip_all)]
    fn handle_response(
        &self,
        data: &RefundsRouterData<Execute>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundsRouterData<Execute>, ConnectorError> {
        let response: stripe::RefundResponse =
            res.response
                .parse_struct("Stripe RefundResponse")
                .change_context(ConnectorError::ResponseDeserializationFailed)?;

        let response_integrity_object = get_refund_integrity_object(
            self.amount_converter,
            response.amount,
            response.currency.clone(),
        )?;

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

        let new_router_data = RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        });

        new_router_data
            .map(|mut router_data| {
                router_data.request.integrity_object = Some(response_integrity_object);
                router_data
            })
            .change_context(ConnectorError::ResponseHandlingFailed)
    }

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response
                .error
                .code
                .clone()
                .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
            message: response
                .error
                .code
                .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
            reason: response.error.message.map(|message| {
                response
                    .error
                    .decline_code
                    .clone()
                    .map(|decline_code| {
                        format!("message - {message}, decline_code - {decline_code}")
                    })
                    .unwrap_or(message)
            }),
            attempt_status: None,
            connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
            network_advice_code: response.error.network_advice_code,
            network_decline_code: response.error.network_decline_code,
            network_error_message: response.error.decline_code.or(response.error.advice_code),
            connector_metadata: None,
        })
    }
}

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Stripe {
    fn get_headers(
        &self,
        req: &RouterData<RSync, RefundsData, RefundsResponseData>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        let mut header = vec![(
            CONTENT_TYPE.to_string(),
            RefundSyncType::get_content_type(self).to_string().into(),
        )];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);

        if let Some(SplitRefundsRequest::StripeSplitRefund(ref stripe_refund)) =
            req.request.split_refunds.as_ref()
        {
            transformers::transform_headers_for_connect_platform(
                stripe_refund.charge_type.clone(),
                stripe_refund.transfer_account_id.clone(),
                &mut header,
            );
        }
        Ok(header)
    }

    fn get_content_type(&self) -> &'static str {
        "application/x-www-form-urlencoded"
    }

    fn get_url(
        &self,
        req: &RefundsRouterData<RSync>,
        connectors: &Connectors,
    ) -> CustomResult<String, ConnectorError> {
        let id = req.request.get_connector_refund_id()?;
        Ok(format!("{}v1/refunds/{}", self.base_url(connectors), id))
    }

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

    #[instrument(skip_all)]
    fn handle_response(
        &self,
        data: &RefundsRouterData<RSync>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RouterData<RSync, RefundsData, RefundsResponseData>, ConnectorError> {
        let response: stripe::RefundResponse =
            res.response
                .parse_struct("Stripe RefundResponse")
                .change_context(ConnectorError::ResponseDeserializationFailed)?;

        let response_integrity_object = get_refund_integrity_object(
            self.amount_converter,
            response.amount,
            response.currency.clone(),
        )?;

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

        let new_router_data = RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        });

        new_router_data
            .map(|mut router_data| {
                router_data.request.integrity_object = Some(response_integrity_object);
                router_data
            })
            .change_context(ConnectorError::ResponseHandlingFailed)
    }

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response
                .error
                .code
                .clone()
                .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
            message: response
                .error
                .code
                .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
            reason: response.error.message.map(|message| {
                response
                    .error
                    .decline_code
                    .clone()
                    .map(|decline_code| {
                        format!("message - {message}, decline_code - {decline_code}")
                    })
                    .unwrap_or(message)
            }),
            attempt_status: None,
            connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
            network_advice_code: response.error.network_advice_code,
            network_decline_code: response.error.network_decline_code,
            network_error_message: response.error.decline_code.or(response.error.advice_code),
            connector_metadata: None,
        })
    }
}

impl UploadFile for Stripe {}

#[async_trait::async_trait]
impl FileUpload for Stripe {
    fn validate_file_upload(
        &self,
        purpose: FilePurpose,
        file_size: i32,
        file_type: mime::Mime,
    ) -> CustomResult<(), ConnectorError> {
        match purpose {
            FilePurpose::DisputeEvidence => {
                let supported_file_types = ["image/jpeg", "image/png", "application/pdf"];
                // 5 Megabytes (MB)
                if file_size > 5000000 {
                    Err(ConnectorError::FileValidationFailed {
                        reason: "file_size exceeded the max file size of 5MB".to_owned(),
                    })?
                }
                if !supported_file_types.contains(&file_type.to_string().as_str()) {
                    Err(ConnectorError::FileValidationFailed {
                        reason: "file_type does not match JPEG, JPG, PNG, or PDF format".to_owned(),
                    })?
                }
            }
        }
        Ok(())
    }
}

impl ConnectorIntegration<Upload, UploadFileRequestData, UploadFileResponse> for Stripe {
    fn get_headers(
        &self,
        req: &RouterData<Upload, UploadFileRequestData, UploadFileResponse>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        self.get_auth_header(&req.connector_auth_type)
    }

    fn get_content_type(&self) -> &'static str {
        "multipart/form-data"
    }

    fn get_url(
        &self,
        _req: &UploadFileRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, ConnectorError> {
        Ok(format!(
            "{}{}",
            connectors.stripe.base_url_file_upload, "v1/files"
        ))
    }

    fn get_request_body(
        &self,
        req: &UploadFileRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, ConnectorError> {
        let connector_req = transformers::construct_file_upload_request(req.clone())?;
        Ok(RequestContent::FormData(connector_req))
    }

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

    #[instrument(skip_all)]
    fn handle_response(
        &self,
        data: &UploadFileRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RouterData<Upload, UploadFileRequestData, UploadFileResponse>, ConnectorError>
    {
        let response: stripe::FileUploadResponse = res
            .response
            .parse_struct("Stripe FileUploadResponse")
            .change_context(ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        Ok(UploadFileRouterData {
            response: Ok(UploadFileResponse {
                provider_file_id: response.file_id,
            }),
            ..data.clone()
        })
    }

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response
                .error
                .code
                .clone()
                .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
            message: response
                .error
                .code
                .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
            reason: response.error.message.map(|message| {
                response
                    .error
                    .decline_code
                    .clone()
                    .map(|decline_code| {
                        format!("message - {message}, decline_code - {decline_code}")
                    })
                    .unwrap_or(message)
            }),
            attempt_status: None,
            connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
            network_advice_code: response.error.network_advice_code,
            network_decline_code: response.error.network_decline_code,
            network_error_message: response.error.decline_code.or(response.error.advice_code),
            connector_metadata: None,
        })
    }
}

impl RetrieveFile for Stripe {}

impl ConnectorIntegration<Retrieve, RetrieveFileRequestData, RetrieveFileResponse> for Stripe {
    fn get_headers(
        &self,
        req: &RouterData<Retrieve, RetrieveFileRequestData, RetrieveFileResponse>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        self.get_auth_header(&req.connector_auth_type)
    }

    fn get_url(
        &self,
        req: &RetrieveFileRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, ConnectorError> {
        Ok(format!(
            "{}v1/files/{}/contents",
            connectors.stripe.base_url_file_upload, req.request.provider_file_id
        ))
    }

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

    #[instrument(skip_all)]
    fn handle_response(
        &self,
        data: &RetrieveFileRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RetrieveFileRouterData, ConnectorError> {
        let response = res.response;

        event_builder.map(|event| event.set_response_body(&serde_json::json!({"connector_response_type": "file", "status_code": res.status_code})));
        router_env::logger::info!(connector_response_type=?"file");

        Ok(RetrieveFileRouterData {
            response: Ok(RetrieveFileResponse {
                file_data: response.to_vec(),
            }),
            ..data.clone()
        })
    }

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response
                .error
                .code
                .clone()
                .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
            message: response
                .error
                .code
                .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
            reason: response.error.message.map(|message| {
                response
                    .error
                    .decline_code
                    .clone()
                    .map(|decline_code| {
                        format!("message - {message}, decline_code - {decline_code}")
                    })
                    .unwrap_or(message)
            }),
            attempt_status: None,
            connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
            network_advice_code: response.error.network_advice_code,
            network_decline_code: response.error.network_decline_code,
            network_error_message: response.error.decline_code.or(response.error.advice_code),
            connector_metadata: None,
        })
    }
}

impl SubmitEvidence for Stripe {}

impl ConnectorIntegration<Evidence, SubmitEvidenceRequestData, SubmitEvidenceResponse> for Stripe {
    fn get_headers(
        &self,
        req: &SubmitEvidenceRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, ConnectorError> {
        let mut header = vec![(
            CONTENT_TYPE.to_string(),
            SubmitEvidenceType::get_content_type(self)
                .to_string()
                .into(),
        )];
        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);
        Ok(header)
    }

    fn get_content_type(&self) -> &'static str {
        "application/x-www-form-urlencoded"
    }

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

    fn get_request_body(
        &self,
        req: &SubmitEvidenceRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, ConnectorError> {
        let connector_req = stripe::Evidence::try_from(req)?;
        Ok(RequestContent::FormUrlEncoded(Box::new(connector_req)))
    }

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

    #[instrument(skip_all)]
    fn handle_response(
        &self,
        data: &SubmitEvidenceRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<SubmitEvidenceRouterData, ConnectorError> {
        let response: stripe::DisputeObj = res
            .response
            .parse_struct("Stripe DisputeObj")
            .change_context(ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        Ok(SubmitEvidenceRouterData {
            response: Ok(SubmitEvidenceResponse {
                dispute_status: api_models::enums::DisputeStatus::DisputeChallenged,
                connector_status: Some(response.status),
            }),
            ..data.clone()
        })
    }

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response
                .error
                .code
                .clone()
                .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
            message: response
                .error
                .code
                .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
            reason: response.error.message.map(|message| {
                response
                    .error
                    .decline_code
                    .clone()
                    .map(|decline_code| {
                        format!("message - {message}, decline_code - {decline_code}")
                    })
                    .unwrap_or(message)
            }),
            attempt_status: None,
            connector_transaction_id: response.error.payment_intent.map(|pi| pi.id),
            network_advice_code: response.error.network_advice_code,
            network_decline_code: response.error.network_decline_code,
            network_error_message: response.error.decline_code.or(response.error.advice_code),
            connector_metadata: None,
        })
    }
}

fn get_signature_elements_from_header(
    headers: &actix_web::http::header::HeaderMap,
) -> CustomResult<HashMap<String, Vec<u8>>, ConnectorError> {
    let security_header = headers
        .get("Stripe-Signature")
        .map(|header_value| {
            header_value
                .to_str()
                .map(String::from)
                .map_err(|_| ConnectorError::WebhookSignatureNotFound)
        })
        .ok_or(ConnectorError::WebhookSignatureNotFound)??;

    let props = security_header.split(',').collect::<Vec<&str>>();
    let mut security_header_kvs: HashMap<String, Vec<u8>> = HashMap::with_capacity(props.len());

    for prop_str in &props {
        let (prop_key, prop_value) = prop_str
            .split_once('=')
            .ok_or(ConnectorError::WebhookSourceVerificationFailed)?;

        security_header_kvs.insert(prop_key.to_string(), prop_value.bytes().collect());
    }

    Ok(security_header_kvs)
}

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


impl Parse for Conversion {
    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
        let text = input.parse::<syn::LitStr>()?;
        let value = text.value();

        value.as_str().parse().map_err(|_| {
            syn::Error::new_spanned(
                &text,
                format!(
                    "Unexpected value for operation: `{value}`. Possible values are `{}`",
                    helpers::get_possible_values_for_enum::<Self>()
                ),
            )
        })
    }
}


impl api::PayoutCreate for Wise {}


impl IncomingWebhook for Bamboraapac {
    fn get_webhook_object_reference_id(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

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

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

impl IncomingWebhook for for Bamboraapac


pub struct RoutingDictionary {
    #[schema(value_type = String)]
    pub merchant_id: common_utils::id_type::MerchantId,
    pub active_id: Option<String>,
    pub records: Vec<RoutingDictionaryRecord>,
}


impl GetPaymentMethodType for BankDebitData {
    fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
        match self {
            Self::AchBankDebit { .. } => api_enums::PaymentMethodType::Ach,
            Self::SepaBankDebit { .. } => api_enums::PaymentMethodType::Sepa,
            Self::BecsBankDebit { .. } => api_enums::PaymentMethodType::Becs,
            Self::BacsBankDebit { .. } => api_enums::PaymentMethodType::Bacs,
        }
    }
}

impl GetPaymentMethodType for for BankDebitData


OpenAPI Block Path: components.schemas.EliminationAnalyserConfig
{
  "type": "object",
  "properties": {
    "bucket_size": {
      "type": "integer",
      "format": "int64",
      "nullable": true,
      "minimum": 0
    },
    "bucket_leak_interval_in_secs": {
      "type": "integer",
      "format": "int64",
      "nullable": true,
      "minimum": 0
    }
  },
  "additionalProperties": false
}


File: crates/analytics/src/active_payments.rs

pub mod accumulator;
mod core;
pub mod metrics;
pub use accumulator::{ActivePaymentsMetricAccumulator, ActivePaymentsMetricsAccumulator};

pub use self::core::get_metrics;


OpenAPI Block Path: components.schemas.NoThirdPartySdkSessionResponse
{
  "type": "object",
  "required": [
    "epoch_timestamp",
    "expires_at",
    "merchant_session_identifier",
    "nonce",
    "merchant_identifier",
    "domain_name",
    "display_name",
    "signature",
    "operational_analytics_identifier",
    "retries",
    "psp_id"
  ],
  "properties": {
    "epoch_timestamp": {
      "type": "integer",
      "format": "int64",
      "description": "Timestamp at which session is requested",
      "minimum": 0
    },
    "expires_at": {
      "type": "integer",
      "format": "int64",
      "description": "Timestamp at which session expires",
      "minimum": 0
    },
    "merchant_session_identifier": {
      "type": "string",
      "description": "The identifier for the merchant session"
    },
    "nonce": {
      "type": "string",
      "description": "Apple pay generated unique ID (UUID) value"
    },
    "merchant_identifier": {
      "type": "string",
      "description": "The identifier for the merchant"
    },
    "domain_name": {
      "type": "string",
      "description": "The domain name of the merchant which is registered in Apple Pay"
    },
    "display_name": {
      "type": "string",
      "description": "The name to be displayed on Apple Pay button"
    },
    "signature": {
      "type": "string",
      "description": "A string which represents the properties of a payment"
    },
    "operational_analytics_identifier": {
      "type": "string",
      "description": "The identifier for the operational analytics"
    },
    "retries": {
      "type": "integer",
      "format": "int32",
      "description": "The number of retries to get the session response",
      "minimum": 0
    },
    "psp_id": {
      "type": "string",
      "description": "The identifier for the connector transaction"
    }
  }
}


pub async fn find_by_merchant_id_connector_transaction_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_transaction_id: &str,
    ) -> StorageResult<Vec<Self>> {
        generics::generic_filter::<
            <Self as HasTable>::Table,
            _,
            <<Self as HasTable>::Table as Table>::PrimaryKey,
            _,
        >(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::connector_transaction_id.eq(connector_transaction_id.to_owned())),
            None,
            None,
            None,
        )
        .await
    }


impl api::PaymentCapture for Payeezy {}

impl api::PaymentCapture for for Payeezy


pub struct PSyncResponse {
    data: PSyncResponseData,
}


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

    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.fiserv.base_url.as_ref()
    }
    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = fiserv::FiservAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        Ok(vec![(
            headers::API_KEY.to_string(),
            auth.api_key.into_masked(),
        )])
    }
    fn build_error_response(
        &self,
        res: types::Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: fiserv::ErrorResponse = res
            .response
            .parse_struct("Fiserv ErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

        let error_details_opt = response.error.as_ref().and_then(|v| v.first());

        let (code, message, reason) = if let Some(first_error) = error_details_opt {
            let code = first_error
                .code
                .clone()
                .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string());

            let message = first_error
                .message
                .clone()
                .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string());

            let reason = first_error.additional_info.clone();

            (code, message, reason)
        } else {
            (
                consts::NO_ERROR_CODE.to_string(),
                consts::NO_ERROR_MESSAGE.to_string(),
                None,
            )
        };

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


File: crates/router/src/core/payments/operations/payment_get_intent.rs
 Public structs: 1

use std::marker::PhantomData;

use api_models::{enums::FrmSuggestion, payments::PaymentsGetIntentRequest};
use async_trait::async_trait;
use common_utils::errors::CustomResult;
use router_env::{instrument, tracing};

use super::{BoxedOperation, Domain, GetTracker, Operation, UpdateTracker, ValidateRequest};
use crate::{
    core::{
        errors::{self, RouterResult},
        payments::{self, helpers, operations},
    },
    db::errors::StorageErrorExt,
    routes::{app::ReqState, SessionState},
    types::{
        api, domain,
        storage::{self, enums},
    },
};

#[derive(Debug, Clone, Copy)]
pub struct PaymentGetIntent;

impl<F: Send + Clone + Sync> Operation<F, PaymentsGetIntentRequest> for &PaymentGetIntent {
    type Data = payments::PaymentIntentData<F>;
    fn to_validate_request(
        &self,
    ) -> RouterResult<&(dyn ValidateRequest<F, PaymentsGetIntentRequest, Self::Data> + Send + Sync)>
    {
        Ok(*self)
    }
    fn to_get_tracker(
        &self,
    ) -> RouterResult<&(dyn GetTracker<F, Self::Data, PaymentsGetIntentRequest> + Send + Sync)>
    {
        Ok(*self)
    }
    fn to_domain(&self) -> RouterResult<&(dyn Domain<F, PaymentsGetIntentRequest, Self::Data>)> {
        Ok(*self)
    }
    fn to_update_tracker(
        &self,
    ) -> RouterResult<&(dyn UpdateTracker<F, Self::Data, PaymentsGetIntentRequest> + Send + Sync)>
    {
        Ok(*self)
    }
}

impl<F: Send + Clone + Sync> Operation<F, PaymentsGetIntentRequest> for PaymentGetIntent {
    type Data = payments::PaymentIntentData<F>;
    fn to_validate_request(
        &self,
    ) -> RouterResult<&(dyn ValidateRequest<F, PaymentsGetIntentRequest, Self::Data> + Send + Sync)>
    {
        Ok(self)
    }
    fn to_get_tracker(
        &self,
    ) -> RouterResult<&(dyn GetTracker<F, Self::Data, PaymentsGetIntentRequest> + Send + Sync)>
    {
        Ok(self)
    }
    fn to_domain(&self) -> RouterResult<&dyn Domain<F, PaymentsGetIntentRequest, Self::Data>> {
        Ok(self)
    }
    fn to_update_tracker(
        &self,
    ) -> RouterResult<&(dyn UpdateTracker<F, Self::Data, PaymentsGetIntentRequest> + Send + Sync)>
    {
        Ok(self)
    }
}

type PaymentsGetIntentOperation<'b, F> =
    BoxedOperation<'b, F, PaymentsGetIntentRequest, payments::PaymentIntentData<F>>;

#[async_trait]
impl<F: Send + Clone + Sync> GetTracker<F, payments::PaymentIntentData<F>, PaymentsGetIntentRequest>
    for PaymentGetIntent
{
    #[instrument(skip_all)]
    async fn get_trackers<'a>(
        &'a self,
        state: &'a SessionState,
        _payment_id: &common_utils::id_type::GlobalPaymentId,
        request: &PaymentsGetIntentRequest,
        merchant_context: &domain::MerchantContext,
        _profile: &domain::Profile,
        _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
    ) -> RouterResult<operations::GetTrackerResponse<payments::PaymentIntentData<F>>> {
        let db = &*state.store;
        let key_manager_state = &state.into();
        let storage_scheme = merchant_context.get_merchant_account().storage_scheme;
        let payment_intent = db
            .find_payment_intent_by_id(
                key_manager_state,
                &request.id,
                merchant_context.get_merchant_key_store(),
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

        let payment_data = payments::PaymentIntentData {
            flow: PhantomData,
            payment_intent,
            // todo : add a way to fetch client secret if required
            client_secret: None,
            sessions_token: vec![],
            vault_session_details: None,
            connector_customer_id: None,
        };

        let get_trackers_response = operations::GetTrackerResponse { payment_data };

        Ok(get_trackers_response)
    }
}

#[async_trait]
impl<F: Clone + Sync> UpdateTracker<F, payments::PaymentIntentData<F>, PaymentsGetIntentRequest>
    for PaymentGetIntent
{
    #[instrument(skip_all)]
    async fn update_trackers<'b>(
        &'b self,
        _state: &'b SessionState,
        _req_state: ReqState,
        payment_data: payments::PaymentIntentData<F>,
        _customer: Option<domain::Customer>,
        _storage_scheme: enums::MerchantStorageScheme,
        _updated_customer: Option<storage::CustomerUpdate>,
        _key_store: &domain::MerchantKeyStore,
        _frm_suggestion: Option<FrmSuggestion>,
        _header_payload: hyperswitch_domain_models::payments::HeaderPayload,
    ) -> RouterResult<(
        PaymentsGetIntentOperation<'b, F>,
        payments::PaymentIntentData<F>,
    )>
    where
        F: 'b + Send,
    {
        Ok((Box::new(self), payment_data))
    }
}

impl<F: Send + Clone + Sync>
    ValidateRequest<F, PaymentsGetIntentRequest, payments::PaymentIntentData<F>>
    for PaymentGetIntent
{
    #[instrument(skip_all)]
    fn validate_request<'a, 'b>(
        &'b self,
        _request: &PaymentsGetIntentRequest,
        merchant_context: &'a domain::MerchantContext,
    ) -> RouterResult<operations::ValidateResult> {
        Ok(operations::ValidateResult {
            merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
            storage_scheme: merchant_context.get_merchant_account().storage_scheme,
            requeue: false,
        })
    }
}

#[async_trait]
impl<F: Clone + Send + Sync> Domain<F, PaymentsGetIntentRequest, payments::PaymentIntentData<F>>
    for PaymentGetIntent
{
    #[instrument(skip_all)]
    async fn get_customer_details<'a>(
        &'a self,
        state: &SessionState,
        payment_data: &mut payments::PaymentIntentData<F>,
        merchant_key_store: &domain::MerchantKeyStore,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<
        (
            BoxedOperation<'a, F, PaymentsGetIntentRequest, payments::PaymentIntentData<F>>,
            Option<domain::Customer>,
        ),
        errors::StorageError,
    > {
        Ok((Box::new(self), None))
    }

    #[instrument(skip_all)]
    async fn make_pm_data<'a>(
        &'a self,
        _state: &'a SessionState,
        _payment_data: &mut payments::PaymentIntentData<F>,
        _storage_scheme: enums::MerchantStorageScheme,
        _merchant_key_store: &domain::MerchantKeyStore,
        _customer: &Option<domain::Customer>,
        _business_profile: &domain::Profile,
        _should_retry_with_pan: bool,
    ) -> RouterResult<(
        PaymentsGetIntentOperation<'a, F>,
        Option<domain::PaymentMethodData>,
        Option<String>,
    )> {
        Ok((Box::new(self), None, None))
    }

    #[instrument(skip_all)]
    async fn perform_routing<'a>(
        &'a self,
        merchant_context: &domain::MerchantContext,
        business_profile: &domain::Profile,
        state: &SessionState,
        // TODO: do not take the whole payment data here
        payment_data: &mut payments::PaymentIntentData<F>,
    ) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
        Ok(api::ConnectorCallType::Skip)
    }

    #[instrument(skip_all)]
    async fn guard_payment_against_blocklist<'a>(
        &'a self,
        _state: &SessionState,
        _merchant_context: &domain::MerchantContext,
        _payment_data: &mut payments::PaymentIntentData<F>,
    ) -> CustomResult<bool, errors::ApiErrorResponse> {
        Ok(false)
    }
}


pub struct FrmFulfillmentSignifydApiResponse {
    ///unique order_id for the transaction
    #[schema(max_length = 255, example = "pay_qiYfHcDou1ycIaxVXKHF")]
    pub order_id: String,
    ///shipment_ids used in the fulfillment overall...also data from previous fulfillments for the same transactions/order is sent
    #[schema(example = r#"["ship_101","ship_102"]"#)]
    pub shipment_ids: Vec<String>,
}


pub struct PayoutAttemptNew {
    pub payout_attempt_id: String,
    pub payout_id: common_utils::id_type::PayoutId,
    pub customer_id: Option<common_utils::id_type::CustomerId>,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub address_id: Option<String>,
    pub connector: Option<String>,
    pub connector_payout_id: Option<String>,
    pub payout_token: Option<String>,
    pub status: storage_enums::PayoutStatus,
    pub is_eligible: Option<bool>,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub business_country: Option<storage_enums::CountryAlpha2>,
    pub business_label: Option<String>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub last_modified_at: PrimitiveDateTime,
    pub profile_id: common_utils::id_type::ProfileId,
    pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
    pub routing_info: Option<serde_json::Value>,
    pub unified_code: Option<UnifiedCode>,
    pub unified_message: Option<UnifiedMessage>,
    pub additional_payout_method_data: Option<payout_method_utils::AdditionalPayoutMethodData>,
    pub merchant_order_reference_id: Option<String>,
}


pub struct CalContractScoreEventRequest {
    pub id: String,
    pub params: String,
    pub labels: Vec<String>,
    pub config: Option<api_routing::ContractBasedRoutingConfig>,
}


File: crates/common_types/src/payment_methods.rs
 Public functions: 3
 Public structs: 4

//! Common types to be used in payment methods

use diesel::{
    backend::Backend,
    deserialize,
    deserialize::FromSql,
    serialize::ToSql,
    sql_types::{Json, Jsonb},
    AsExpression, Queryable,
};
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

/// Details of all the payment methods enabled for the connector for the given merchant account

// sql_type for this can be json instead of jsonb. This is because validation at database is not required since it will always be written by the application.
// This is a performance optimization to avoid json validation at database level.
// jsonb enables faster querying on json columns, but it doesn't justify here since we are not querying on this column.
// https://docs.rs/diesel/latest/diesel/sql_types/struct.Jsonb.html
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, AsExpression)]
#[serde(deny_unknown_fields)]
#[diesel(sql_type = Json)]
pub struct PaymentMethodsEnabled {
    /// Type of payment method.
    #[schema(value_type = PaymentMethod,example = "card")]
    pub payment_method_type: common_enums::PaymentMethod,

    /// Payment method configuration, this includes all the filters associated with the payment method
    pub payment_method_subtypes: Option<Vec<RequestPaymentMethodTypes>>,
}

// Custom FromSql implementation to handle deserialization of v1 data format
impl FromSql<Json, diesel::pg::Pg> for PaymentMethodsEnabled {
    fn from_sql(bytes: <diesel::pg::Pg as Backend>::RawValue<'_>) -> deserialize::Result<Self> {
        let helper: PaymentMethodsEnabledHelper = serde_json::from_slice(bytes.as_bytes())
            .map_err(|e| Box::new(diesel::result::Error::DeserializationError(Box::new(e))))?;
        Ok(helper.into())
    }
}

// In this ToSql implementation, we are directly serializing the PaymentMethodsEnabled struct to JSON
impl ToSql<Json, diesel::pg::Pg> for PaymentMethodsEnabled {
    fn to_sql<'b>(
        &'b self,
        out: &mut diesel::serialize::Output<'b, '_, diesel::pg::Pg>,
    ) -> diesel::serialize::Result {
        let value = serde_json::to_value(self)?;
        // the function `reborrow` only works in case of `Pg` backend. But, in case of other backends
        // please refer to the diesel migration blog:
        // https://github.com/Diesel-rs/Diesel/blob/master/guide_drafts/migration_guide.md#changed-tosql-implementations
        <serde_json::Value as ToSql<Json, diesel::pg::Pg>>::to_sql(&value, &mut out.reborrow())
    }
}

// Intermediate type to handle deserialization of v1 data format of PaymentMethodsEnabled
#[derive(serde::Deserialize)]
#[serde(untagged)]
enum PaymentMethodsEnabledHelper {
    V2 {
        payment_method_type: common_enums::PaymentMethod,
        payment_method_subtypes: Option<Vec<RequestPaymentMethodTypes>>,
    },
    V1 {
        payment_method: common_enums::PaymentMethod,
        payment_method_types: Option<Vec<RequestPaymentMethodTypesV1>>,
    },
}

impl From<PaymentMethodsEnabledHelper> for PaymentMethodsEnabled {
    fn from(helper: PaymentMethodsEnabledHelper) -> Self {
        match helper {
            PaymentMethodsEnabledHelper::V2 {
                payment_method_type,
                payment_method_subtypes,
            } => Self {
                payment_method_type,
                payment_method_subtypes,
            },
            PaymentMethodsEnabledHelper::V1 {
                payment_method,
                payment_method_types,
            } => Self {
                payment_method_type: payment_method,
                payment_method_subtypes: payment_method_types.map(|subtypes| {
                    subtypes
                        .into_iter()
                        .map(RequestPaymentMethodTypes::from)
                        .collect()
                }),
            },
        }
    }
}

impl PaymentMethodsEnabled {
    /// Get payment_method_type
    #[cfg(feature = "v2")]
    pub fn get_payment_method(&self) -> Option<common_enums::PaymentMethod> {
        Some(self.payment_method_type)
    }

    /// Get payment_method_subtypes
    #[cfg(feature = "v2")]
    pub fn get_payment_method_type(&self) -> Option<&Vec<RequestPaymentMethodTypes>> {
        self.payment_method_subtypes.as_ref()
    }
}

/// Details of a specific payment method subtype enabled for the connector for the given merchant account
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema, PartialEq, Eq, Hash)]
pub struct RequestPaymentMethodTypes {
    /// The payment method subtype
    #[schema(value_type = PaymentMethodType)]
    pub payment_method_subtype: common_enums::PaymentMethodType,

    /// The payment experience for the payment method
    #[schema(value_type = Option<PaymentExperience>)]
    pub payment_experience: Option<common_enums::PaymentExperience>,

    /// List of cards networks that are enabled for this payment method, applicable for credit and debit payment method subtypes only
    #[schema(value_type = Option<Vec<CardNetwork>>)]
    pub card_networks: Option<Vec<common_enums::CardNetwork>>,
    /// List of currencies accepted or has the processing capabilities of the processor
    #[schema(example = json!(
        {
            "type": "enable_only",
            "list": ["USD", "INR"]
        }
    ), value_type = Option<AcceptedCurrencies>)]
    pub accepted_currencies: Option<AcceptedCurrencies>,

    ///  List of Countries accepted or has the processing capabilities of the processor
    #[schema(example = json!(
        {
            "type": "enable_only",
            "list": ["UK", "AU"]
        }
    ), value_type = Option<AcceptedCountries>)]
    pub accepted_countries: Option<AcceptedCountries>,

    /// Minimum amount supported by the processor. To be represented in the lowest denomination of the target currency (For example, for USD it should be in cents)
    #[schema(example = 1)]
    pub minimum_amount: Option<common_utils::types::MinorUnit>,

    /// Maximum amount supported by the processor. To be represented in the lowest denomination of
    /// the target currency (For example, for USD it should be in cents)
    #[schema(example = 1313)]
    pub maximum_amount: Option<common_utils::types::MinorUnit>,

    /// Indicates whether the payment method supports recurring payments. Optional.
    #[schema(example = true)]
    pub recurring_enabled: Option<bool>,

    /// Indicates whether the payment method is eligible for installment payments (e.g., EMI, BNPL). Optional.
    #[schema(example = true)]
    pub installment_payment_enabled: Option<bool>,
}

impl From<RequestPaymentMethodTypesV1> for RequestPaymentMethodTypes {
    fn from(value: RequestPaymentMethodTypesV1) -> Self {
        Self {
            payment_method_subtype: value.payment_method_type,
            payment_experience: value.payment_experience,
            card_networks: value.card_networks,
            accepted_currencies: value.accepted_currencies,
            accepted_countries: value.accepted_countries,
            minimum_amount: value.minimum_amount,
            maximum_amount: value.maximum_amount,
            recurring_enabled: value.recurring_enabled,
            installment_payment_enabled: value.installment_payment_enabled,
        }
    }
}

#[derive(serde::Deserialize)]
struct RequestPaymentMethodTypesV1 {
    pub payment_method_type: common_enums::PaymentMethodType,
    pub payment_experience: Option<common_enums::PaymentExperience>,
    pub card_networks: Option<Vec<common_enums::CardNetwork>>,
    pub accepted_currencies: Option<AcceptedCurrencies>,
    pub accepted_countries: Option<AcceptedCountries>,
    pub minimum_amount: Option<common_utils::types::MinorUnit>,
    pub maximum_amount: Option<common_utils::types::MinorUnit>,
    pub recurring_enabled: Option<bool>,
    pub installment_payment_enabled: Option<bool>,
}

impl RequestPaymentMethodTypes {
    ///Get payment_method_subtype
    pub fn get_payment_method_type(&self) -> Option<common_enums::PaymentMethodType> {
        Some(self.payment_method_subtype)
    }
}

#[derive(PartialEq, Eq, Hash, Debug, Clone, serde::Serialize, Deserialize, ToSchema)]
#[serde(
    deny_unknown_fields,
    tag = "type",
    content = "list",
    rename_all = "snake_case"
)]
/// Object to filter the countries for which the payment method subtype is enabled
pub enum AcceptedCountries {
    /// Only enable the payment method subtype for specific countries
    #[schema(value_type = Vec<CountryAlpha2>)]
    EnableOnly(Vec<common_enums::CountryAlpha2>),

    /// Only disable the payment method subtype for specific countries
    #[schema(value_type = Vec<CountryAlpha2>)]
    DisableOnly(Vec<common_enums::CountryAlpha2>),

    /// Enable the payment method subtype for all countries, in which the processor has the processing capabilities
    AllAccepted,
}

#[derive(PartialEq, Eq, Hash, Debug, Clone, serde::Serialize, Deserialize, ToSchema)]
#[serde(
    deny_unknown_fields,
    tag = "type",
    content = "list",
    rename_all = "snake_case"
)]
/// Object to filter the countries for which the payment method subtype is enabled
pub enum AcceptedCurrencies {
    /// Only enable the payment method subtype for specific currencies
    #[schema(value_type = Vec<Currency>)]
    EnableOnly(Vec<common_enums::Currency>),

    /// Only disable the payment method subtype for specific currencies
    #[schema(value_type = Vec<Currency>)]
    DisableOnly(Vec<common_enums::Currency>),

    /// Enable the payment method subtype for all currencies, in which the processor has the processing capabilities
    AllAccepted,
}

impl<DB> Queryable<Jsonb, DB> for PaymentMethodsEnabled
where
    DB: Backend,
    Self: FromSql<Jsonb, DB>,
{
    type Row = Self;

    fn build(row: Self::Row) -> deserialize::Result<Self> {
        Ok(row)
    }
}

/// The network tokenization configuration for creating the payment method session
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct NetworkTokenization {
    /// Enable the network tokenization for payment methods that are created using the payment method session
    #[schema(value_type = NetworkTokenizationToggle)]
    pub enable: common_enums::NetworkTokenizationToggle,
}

/// The Payment Service Provider Configuration for payment methods that are created using the payment method session
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct PspTokenization {
    /// The tokenization type to be applied for the payment method
    #[schema(value_type = TokenizationType)]
    pub tokenization_type: common_enums::TokenizationType,

    /// The merchant connector id to be used for tokenization
    #[schema(value_type = String)]
    pub connector_id: common_utils::id_type::MerchantConnectorAccountId,
}


pub struct NordeaAuthType {
    pub(super) client_id: Secret<String>,
    pub(super) client_secret: Secret<String>,
    /// PEM format private key for eIDAS signing
    /// Should be base64 encoded
    pub(super) eidas_private_key: Secret<String>,
}


impl api::PaymentSync for Facilitapay {}

impl api::PaymentSync for for Facilitapay


impl api::PaymentAuthorize for Zen {}


/// Get string representation of the id
    pub fn get_string_repr(&self) -> &str {
        self.0.get_string_repr()
    }


pub struct CardData {
    pub card_number: CardNumber,
    pub exp_month: Secret<String>,
    pub exp_year: Secret<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub card_security_code: Option<Secret<String>>,
}


pub fn server(state: AppState) -> Scope {
        web::scope("/v2/gsm")
            .app_data(web::Data::new(state))
            .service(web::resource("").route(web::post().to(gsm::create_gsm_rule)))
            .service(web::resource("/get").route(web::post().to(gsm::get_gsm_rule)))
            .service(web::resource("/update").route(web::post().to(gsm::update_gsm_rule)))
            .service(web::resource("/delete").route(web::post().to(gsm::delete_gsm_rule)))
    }


File: crates/router/src/core/cards_info.rs
 Public functions: 6
 Public structs: 7

use actix_multipart::form::{bytes::Bytes, MultipartForm};
use api_models::cards_info as cards_info_api_types;
use common_utils::fp_utils::when;
use csv::Reader;
use diesel_models::cards_info as card_info_models;
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::cards_info;
use rdkafka::message::ToBytes;
use router_env::{instrument, tracing};

use crate::{
    core::{
        errors::{self, RouterResponse, RouterResult, StorageErrorExt},
        payments::helpers,
    },
    routes,
    services::ApplicationResponse,
    types::{
        domain,
        transformers::{ForeignFrom, ForeignInto},
    },
};

fn verify_iin_length(card_iin: &str) -> Result<(), errors::ApiErrorResponse> {
    let is_bin_length_in_range = card_iin.len() == 6 || card_iin.len() == 8;
    when(!is_bin_length_in_range, || {
        Err(errors::ApiErrorResponse::InvalidCardIinLength)
    })
}

#[instrument(skip_all)]
pub async fn retrieve_card_info(
    state: routes::SessionState,
    merchant_context: domain::MerchantContext,
    request: cards_info_api_types::CardsInfoRequest,
) -> RouterResponse<cards_info_api_types::CardInfoResponse> {
    let db = state.store.as_ref();

    verify_iin_length(&request.card_iin)?;
    helpers::verify_payment_intent_time_and_client_secret(
        &state,
        &merchant_context,
        request.client_secret,
    )
    .await?;

    let card_info = db
        .get_card_info(&request.card_iin)
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to retrieve card information")?
        .ok_or(report!(errors::ApiErrorResponse::InvalidCardIin))?;

    Ok(ApplicationResponse::Json(
        cards_info_api_types::CardInfoResponse::foreign_from(card_info),
    ))
}

#[instrument(skip_all)]
pub async fn create_card_info(
    state: routes::SessionState,
    card_info_request: cards_info_api_types::CardInfoCreateRequest,
) -> RouterResponse<cards_info_api_types::CardInfoResponse> {
    let db = state.store.as_ref();
    cards_info::CardsInfoInterface::add_card_info(db, card_info_request.foreign_into())
        .await
        .to_duplicate_response(errors::ApiErrorResponse::GenericDuplicateError {
            message: "CardInfo with given key already exists in our records".to_string(),
        })
        .map(|card_info| ApplicationResponse::Json(card_info.foreign_into()))
}

#[instrument(skip_all)]
pub async fn update_card_info(
    state: routes::SessionState,
    card_info_request: cards_info_api_types::CardInfoUpdateRequest,
) -> RouterResponse<cards_info_api_types::CardInfoResponse> {
    let db = state.store.as_ref();
    cards_info::CardsInfoInterface::update_card_info(
        db,
        card_info_request.card_iin,
        card_info_models::UpdateCardInfo {
            card_issuer: card_info_request.card_issuer,
            card_network: card_info_request.card_network,
            card_type: card_info_request.card_type,
            card_subtype: card_info_request.card_subtype,
            card_issuing_country: card_info_request.card_issuing_country,
            bank_code_id: card_info_request.bank_code_id,
            bank_code: card_info_request.bank_code,
            country_code: card_info_request.country_code,
            last_updated: Some(common_utils::date_time::now()),
            last_updated_provider: card_info_request.last_updated_provider,
        },
    )
    .await
    .to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
        message: "Card info with given key does not exist in our records".to_string(),
    })
    .attach_printable("Failed while updating card info")
    .map(|card_info| ApplicationResponse::Json(card_info.foreign_into()))
}

#[derive(Debug, MultipartForm)]
pub struct CardsInfoUpdateForm {
    #[multipart(limit = "1MB")]
    pub file: Bytes,
}

fn parse_cards_bin_csv(
    data: &[u8],
) -> csv::Result<Vec<cards_info_api_types::CardInfoUpdateRequest>> {
    let mut csv_reader = Reader::from_reader(data);
    let mut records = Vec::new();
    let mut id_counter = 0;
    for result in csv_reader.deserialize() {
        let mut record: cards_info_api_types::CardInfoUpdateRequest = result?;
        id_counter += 1;
        record.line_number = Some(id_counter);
        records.push(record);
    }
    Ok(records)
}

pub fn get_cards_bin_records(
    form: CardsInfoUpdateForm,
) -> Result<Vec<cards_info_api_types::CardInfoUpdateRequest>, errors::ApiErrorResponse> {
    match parse_cards_bin_csv(form.file.data.to_bytes()) {
        Ok(records) => Ok(records),
        Err(e) => Err(errors::ApiErrorResponse::PreconditionFailed {
            message: e.to_string(),
        }),
    }
}

#[instrument(skip_all)]
pub async fn migrate_cards_info(
    state: routes::SessionState,
    card_info_records: Vec<cards_info_api_types::CardInfoUpdateRequest>,
) -> RouterResponse<Vec<cards_info_api_types::CardInfoMigrationResponse>> {
    let mut result = Vec::new();
    for record in card_info_records {
        let res = card_info_flow(record.clone(), state.clone()).await;
        result.push(cards_info_api_types::CardInfoMigrationResponse::from((
            match res {
                Ok(ApplicationResponse::Json(response)) => Ok(response),
                Err(e) => Err(e.to_string()),
                _ => Err("Failed to migrate card info".to_string()),
            },
            record,
        )));
    }
    Ok(ApplicationResponse::Json(result))
}

pub trait State {}
pub trait TransitionTo<S: State> {}
// Available states for card info migration
pub struct CardInfoFetch;
pub struct CardInfoAdd;
pub struct CardInfoUpdate;
pub struct CardInfoResponse;

impl State for CardInfoFetch {}
impl State for CardInfoAdd {}
impl State for CardInfoUpdate {}
impl State for CardInfoResponse {}

// State transitions for card info migration
impl TransitionTo<CardInfoAdd> for CardInfoFetch {}
impl TransitionTo<CardInfoUpdate> for CardInfoFetch {}
impl TransitionTo<CardInfoResponse> for CardInfoAdd {}
impl TransitionTo<CardInfoResponse> for CardInfoUpdate {}

// Async executor
pub struct CardInfoMigrateExecutor<'a> {
    state: &'a routes::SessionState,
    record: &'a cards_info_api_types::CardInfoUpdateRequest,
}

impl<'a> CardInfoMigrateExecutor<'a> {
    fn new(
        state: &'a routes::SessionState,
        record: &'a cards_info_api_types::CardInfoUpdateRequest,
    ) -> Self {
        Self { state, record }
    }

    async fn fetch_card_info(&self) -> RouterResult<Option<card_info_models::CardInfo>> {
        let db = self.state.store.as_ref();
        let maybe_card_info = db
            .get_card_info(&self.record.card_iin)
            .await
            .change_context(errors::ApiErrorResponse::InvalidCardIin)?;
        Ok(maybe_card_info)
    }

    async fn add_card_info(&self) -> RouterResult<card_info_models::CardInfo> {
        let db = self.state.store.as_ref();
        let card_info =
            cards_info::CardsInfoInterface::add_card_info(db, self.record.clone().foreign_into())
                .await
                .to_duplicate_response(errors::ApiErrorResponse::GenericDuplicateError {
                    message: "CardInfo with given key already exists in our records".to_string(),
                })?;
        Ok(card_info)
    }

    async fn update_card_info(&self) -> RouterResult<card_info_models::CardInfo> {
        let db = self.state.store.as_ref();
        let card_info = cards_info::CardsInfoInterface::update_card_info(
            db,
            self.record.card_iin.clone(),
            card_info_models::UpdateCardInfo {
                card_issuer: self.record.card_issuer.clone(),
                card_network: self.record.card_network.clone(),
                card_type: self.record.card_type.clone(),
                card_subtype: self.record.card_subtype.clone(),
                card_issuing_country: self.record.card_issuing_country.clone(),
                bank_code_id: self.record.bank_code_id.clone(),
                bank_code: self.record.bank_code.clone(),
                country_code: self.record.country_code.clone(),
                last_updated: Some(common_utils::date_time::now()),
                last_updated_provider: self.record.last_updated_provider.clone(),
            },
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
            message: "Card info with given key does not exist in our records".to_string(),
        })
        .attach_printable("Failed while updating card info")?;
        Ok(card_info)
    }
}

// Builder
pub struct CardInfoBuilder<S: State> {
    state: std::marker::PhantomData<S>,
    pub card_info: Option<card_info_models::CardInfo>,
}

impl CardInfoBuilder<CardInfoFetch> {
    fn new() -> Self {
        Self {
            state: std::marker::PhantomData,
            card_info: None,
        }
    }
}

impl CardInfoBuilder<CardInfoFetch> {
    fn set_card_info(
        self,
        card_info: card_info_models::CardInfo,
    ) -> CardInfoBuilder<CardInfoUpdate> {
        CardInfoBuilder {
            state: std::marker::PhantomData,
            card_info: Some(card_info),
        }
    }

    fn transition(self) -> CardInfoBuilder<CardInfoAdd> {
        CardInfoBuilder {
            state: std::marker::PhantomData,
            card_info: None,
        }
    }
}

impl CardInfoBuilder<CardInfoUpdate> {
    fn set_updated_card_info(
        self,
        card_info: card_info_models::CardInfo,
    ) -> CardInfoBuilder<CardInfoResponse> {
        CardInfoBuilder {
            state: std::marker::PhantomData,
            card_info: Some(card_info),
        }
    }
}

impl CardInfoBuilder<CardInfoAdd> {
    fn set_added_card_info(
        self,
        card_info: card_info_models::CardInfo,
    ) -> CardInfoBuilder<CardInfoResponse> {
        CardInfoBuilder {
            state: std::marker::PhantomData,
            card_info: Some(card_info),
        }
    }
}

impl CardInfoBuilder<CardInfoResponse> {
    pub fn build(self) -> cards_info_api_types::CardInfoMigrateResponseRecord {
        match self.card_info {
            Some(card_info) => cards_info_api_types::CardInfoMigrateResponseRecord {
                card_iin: Some(card_info.card_iin),
                card_issuer: card_info.card_issuer,
                card_network: card_info.card_network.map(|cn| cn.to_string()),
                card_type: card_info.card_type,
                card_sub_type: card_info.card_subtype,
                card_issuing_country: card_info.card_issuing_country,
            },
            None => cards_info_api_types::CardInfoMigrateResponseRecord {
                card_iin: None,
                card_issuer: None,
                card_network: None,
                card_type: None,
                card_sub_type: None,
                card_issuing_country: None,
            },
        }
    }
}

async fn card_info_flow(
    record: cards_info_api_types::CardInfoUpdateRequest,
    state: routes::SessionState,
) -> RouterResponse<cards_info_api_types::CardInfoMigrateResponseRecord> {
    let builder = CardInfoBuilder::new();
    let executor = CardInfoMigrateExecutor::new(&state, &record);
    let fetched_card_info_details = executor.fetch_card_info().await?;

    let builder = match fetched_card_info_details {
        Some(card_info) => {
            let builder = builder.set_card_info(card_info);
            let updated_card_info = executor.update_card_info().await?;
            builder.set_updated_card_info(updated_card_info)
        }
        None => {
            let builder = builder.transition();
            let added_card_info = executor.add_card_info().await?;
            builder.set_added_card_info(added_card_info)
        }
    };

    Ok(ApplicationResponse::Json(builder.build()))
}


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

impl api::ConnectorRedirectResponse for for Authorizedotnet


pub async fn payments_retrieve(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    path: web::Path<common_utils::id_type::PaymentId>,
    json_payload: web::Query<payment_types::PaymentRetrieveBody>,
) -> impl Responder {
    let flow = match json_payload.force_sync {
        Some(true) => Flow::PaymentsRetrieveForceSync,
        _ => Flow::PaymentsRetrieve,
    };
    let payment_id = path.into_inner();
    tracing::Span::current().record("payment_id", payment_id.get_string_repr());

    let payload = payment_types::PaymentsRetrieveRequest {
        resource_id: payment_types::PaymentIdType::PaymentIntentId(payment_id),
        merchant_id: json_payload.merchant_id.clone(),
        force_sync: json_payload.force_sync.unwrap_or(false),
        client_secret: json_payload.client_secret.clone(),
        expand_attempts: json_payload.expand_attempts,
        expand_captures: json_payload.expand_captures,
        all_keys_required: json_payload.all_keys_required,
        ..Default::default()
    };
    let header_payload = match HeaderPayload::foreign_try_from(req.headers()) {
        Ok(headers) => headers,
        Err(err) => {
            return api::log_and_return_error_response(err);
        }
    };

    tracing::Span::current().record("flow", flow.to_string());

    let api_auth = auth::ApiKeyAuth {
        is_connected_allowed: false,
        is_platform_allowed: true,
    };

    let (auth_type, auth_flow) =
        match auth::check_client_secret_and_get_auth(req.headers(), &payload, api_auth) {
            Ok(auth) => auth,
            Err(err) => return api::log_and_return_error_response(report!(err)),
        };

    let locking_action = payload.get_locking_input(flow.clone());

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payments::payments_core::<
                api_types::PSync,
                payment_types::PaymentsResponse,
                _,
                _,
                _,
                payments::PaymentData<api_types::PSync>,
            >(
                state,
                req_state,
                merchant_context,
                auth.profile_id,
                payments::PaymentStatus,
                req,
                auth_flow,
                payments::CallConnectorAction::Trigger,
                None,
                header_payload.clone(),
            )
        },
        auth::auth_type(
            &*auth_type,
            &auth::JWTAuth {
                permission: Permission::ProfilePaymentRead,
            },
            req.headers(),
        ),
        locking_action,
    ))
    .await
}


pub struct ConnectorTokenReferenceRecord {
    pub connector_token: String,
    pub payment_method_subtype: Option<common_enums::PaymentMethodType>,
    pub original_payment_authorized_amount: Option<common_utils::types::MinorUnit>,
    pub original_payment_authorized_currency: Option<common_enums::Currency>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub connector_token_status: common_enums::ConnectorTokenStatus,
    pub connector_token_request_reference_id: Option<String>,
}


pub fn set_surcharge_details(
        &mut self,
        surcharge_details: Option<router_request_types::SurchargeDetails>,
    ) {
        self.surcharge_amount = surcharge_details
            .clone()
            .map(|details| details.surcharge_amount);
        self.tax_on_surcharge = surcharge_details.map(|details| details.tax_on_surcharge_amount);
    }


pub struct NordeaFailures {
    /// Failure code
    pub code: Option<String>,
    /// Failure description
    pub description: Option<String>,
    /// JSON path of the failing element if applicable
    pub path: Option<String>,
    /// Type of the validation error, e.g. NotNull
    #[serde(rename = "type")]
    pub failure_type: Option<String>,
}


pub trait EmailClient: Sync + Send + dyn_clone::DynClone {
    /// The rich text type of the email client
    type RichText;

    /// Sends an email to the specified recipient with the given subject and body.
    async fn send_email(
        &self,
        recipient: pii::Email,
        subject: String,
        body: Self::RichText,
        proxy_url: Option<&String>,
    ) -> EmailResult<()>;

    /// Convert Stringified HTML to client native rich text format
    /// This has to be done because not all clients may format html as the same
    fn convert_to_rich_text(
        &self,
        intermediate_string: IntermediateString,
    ) -> CustomResult<Self::RichText, EmailError>
    where
        Self::RichText: Send;
}


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


pub fn create_merchant_publishable_key() -> String {
    format!(
        "pk_{}_{}",
        router_env::env::prefix_for_env(),
        Uuid::new_v4().simple()
    )
}