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

pub mod transformers;

use std::sync::LazyLock;

use base64::Engine;
use common_enums::enums;
use common_utils::{
    consts,
    errors::CustomResult,
    ext_traits::BytesExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, MinorUnit, StringMajorUnit, StringMajorUnitForConnector},
};
use error_stack::{report, Report, ResultExt};
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{AccessToken, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        mandate_revoke::MandateRevoke,
        payments::{
            Authorize, Capture, IncrementalAuthorization, PSync, PaymentMethodToken, Session,
            SetupMandate, Void,
        },
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, MandateRevokeRequestData, PaymentMethodTokenizationData,
        PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData,
        PaymentsIncrementalAuthorizationData, PaymentsSessionData, PaymentsSyncData, RefundsData,
        SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, MandateRevokeResponseData, PaymentMethodDetails, PaymentsResponseData,
        RefundsResponseData, SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        MandateRevokeRouterData, PaymentsAuthorizeRouterData, PaymentsCancelRouterData,
        PaymentsCaptureRouterData, PaymentsIncrementalAuthorizationRouterData,
        PaymentsSyncRouterData, RefundExecuteRouterData, RefundSyncRouterData,
        SetupMandateRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self,
        refunds::{Refund, RefundExecute, RefundSync},
        ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{
        IncrementalAuthorizationType, MandateRevokeType, PaymentsAuthorizeType,
        PaymentsCaptureType, PaymentsSyncType, PaymentsVoidType, RefundExecuteType, RefundSyncType,
        Response, SetupMandateType,
    },
    webhooks,
};
use masking::{ExposeInterface, Mask, Maskable, PeekInterface};
use ring::{digest, hmac};
use time::OffsetDateTime;
use transformers as wellsfargo;
use url::Url;

use crate::{
    constants::{self, headers},
    types::ResponseRouterData,
    utils::{self, convert_amount, PaymentMethodDataType, RefundsRequestData},
};
#[derive(Clone)]
pub struct Wellsfargo {
    amount_converter: &'static (dyn AmountConvertor<Output = StringMajorUnit> + Sync),
}

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

    pub fn generate_digest(&self, payload: &[u8]) -> String {
        let payload_digest = digest::digest(&digest::SHA256, payload);
        consts::BASE64_ENGINE.encode(payload_digest)
    }

    pub fn generate_signature(
        &self,
        auth: wellsfargo::WellsfargoAuthType,
        host: String,
        resource: &str,
        payload: &String,
        date: OffsetDateTime,
        http_method: Method,
    ) -> CustomResult<String, errors::ConnectorError> {
        let wellsfargo::WellsfargoAuthType {
            api_key,
            merchant_account,
            api_secret,
        } = auth;
        let is_post_method = matches!(http_method, Method::Post);
        let is_patch_method = matches!(http_method, Method::Patch);
        let is_delete_method = matches!(http_method, Method::Delete);
        let digest_str = if is_post_method || is_patch_method {
            "digest "
        } else {
            ""
        };
        let headers = format!("host date (request-target) {digest_str}v-c-merchant-id");
        let request_target = if is_post_method {
            format!("(request-target): post {resource}\ndigest: SHA-256={payload}\n")
        } else if is_patch_method {
            format!("(request-target): patch {resource}\ndigest: SHA-256={payload}\n")
        } else if is_delete_method {
            format!("(request-target): delete {resource}\n")
        } else {
            format!("(request-target): get {resource}\n")
        };
        let signature_string = format!(
            "host: {host}\ndate: {date}\n{request_target}v-c-merchant-id: {}",
            merchant_account.peek()
        );
        let key_value = consts::BASE64_ENGINE
            .decode(api_secret.expose())
            .change_context(errors::ConnectorError::InvalidConnectorConfig {
                config: "connector_account_details.api_secret",
            })?;
        let key = hmac::Key::new(hmac::HMAC_SHA256, &key_value);
        let signature_value =
            consts::BASE64_ENGINE.encode(hmac::sign(&key, signature_string.as_bytes()).as_ref());
        let signature_header = format!(
            r#"keyid="{}", algorithm="HmacSHA256", headers="{headers}", signature="{signature_value}""#,
            api_key.peek()
        );

        Ok(signature_header)
    }
}

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

    fn common_get_content_type(&self) -> &'static str {
        "application/json;charset=utf-8"
    }

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

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

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

        let error_message = if res.status_code == 401 {
            constants::CONNECTOR_UNAUTHORIZED_ERROR
        } else {
            hyperswitch_interfaces::consts::NO_ERROR_MESSAGE
        };
        match response {
            Ok(transformers::WellsfargoErrorResponse::StandardError(response)) => {
                event_builder.map(|i| i.set_error_response_body(&response));
                router_env::logger::info!(connector_response=?response);

                let (code, message, reason) = match response.error_information {
                    Some(ref error_info) => {
                        let detailed_error_info = error_info.details.as_ref().map(|details| {
                            details
                                .iter()
                                .map(|det| format!("{} : {}", det.field, det.reason))
                                .collect::<Vec<_>>()
                                .join(", ")
                        });
                        (
                            error_info.reason.clone(),
                            error_info.reason.clone(),
                            transformers::get_error_reason(
                                Some(error_info.message.clone()),
                                detailed_error_info,
                                None,
                            ),
                        )
                    }
                    None => {
                        let detailed_error_info = response.details.map(|details| {
                            details
                                .iter()
                                .map(|det| format!("{} : {}", det.field, det.reason))
                                .collect::<Vec<_>>()
                                .join(", ")
                        });
                        (
                            response.reason.clone().map_or(
                                hyperswitch_interfaces::consts::NO_ERROR_CODE.to_string(),
                                |reason| reason.to_string(),
                            ),
                            response
                                .reason
                                .map_or(error_message.to_string(), |reason| reason.to_string()),
                            transformers::get_error_reason(
                                response.message,
                                detailed_error_info,
                                None,
                            ),
                        )
                    }
                };

                Ok(ErrorResponse {
                    status_code: res.status_code,
                    code,
                    message,
                    reason,
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                })
            }
            Ok(transformers::WellsfargoErrorResponse::AuthenticationError(response)) => {
                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: hyperswitch_interfaces::consts::NO_ERROR_CODE.to_string(),
                    message: response.response.rmsg.clone(),
                    reason: Some(response.response.rmsg),
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                })
            }
            Ok(transformers::WellsfargoErrorResponse::NotAvailableError(response)) => {
                event_builder.map(|i| i.set_error_response_body(&response));
                router_env::logger::info!(connector_response=?response);
                let error_response = response
                    .errors
                    .iter()
                    .map(|error_info| {
                        format!(
                            "{}: {}",
                            error_info.error_type.clone().unwrap_or("".to_string()),
                            error_info.message.clone().unwrap_or("".to_string())
                        )
                    })
                    .collect::<Vec<String>>()
                    .join(" & ");
                Ok(ErrorResponse {
                    status_code: res.status_code,
                    code: hyperswitch_interfaces::consts::NO_ERROR_CODE.to_string(),
                    message: error_response.clone(),
                    reason: Some(error_response),
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                })
            }
            Err(error_msg) => {
                event_builder.map(|event| event.set_error(serde_json::json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code})));
                router_env::logger::error!(deserialization_error =? error_msg);
                utils::handle_json_response_deserialization_failure(res, "wellsfargo")
            }
        }
    }
}

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

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Wellsfargo
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        let date = OffsetDateTime::now_utc();
        let wellsfargo_req = self.get_request_body(req, connectors)?;
        let auth = wellsfargo::WellsfargoAuthType::try_from(&req.connector_auth_type)?;
        let merchant_account = auth.merchant_account.clone();
        let base_url = connectors.wellsfargo.base_url.as_str();
        let wellsfargo_host =
            Url::parse(base_url).change_context(errors::ConnectorError::RequestEncodingFailed)?;
        let host = wellsfargo_host
            .host_str()
            .ok_or(errors::ConnectorError::RequestEncodingFailed)?;
        let path: String = self
            .get_url(req, connectors)?
            .chars()
            .skip(base_url.len() - 1)
            .collect();
        let sha256 = self.generate_digest(wellsfargo_req.get_inner_value().expose().as_bytes());
        let http_method = self.get_http_method();
        let signature = self.generate_signature(
            auth,
            host.to_string(),
            path.as_str(),
            &sha256,
            date,
            http_method,
        )?;

        let mut headers = vec![
            (
                headers::CONTENT_TYPE.to_string(),
                self.get_content_type().to_string().into(),
            ),
            (
                headers::ACCEPT.to_string(),
                "application/hal+json;charset=utf-8".to_string().into(),
            ),
            (
                "v-c-merchant-id".to_string(),
                merchant_account.into_masked(),
            ),
            ("Date".to_string(), date.to_string().into()),
            ("Host".to_string(), host.to_string().into()),
            ("Signature".to_string(), signature.into_masked()),
        ];
        if matches!(http_method, Method::Post | Method::Put | Method::Patch) {
            headers.push((
                "Digest".to_string(),
                format!("SHA-256={sha256}").into_masked(),
            ));
        }
        Ok(headers)
    }
}

impl api::Payment for Wellsfargo {}
impl api::PaymentAuthorize for Wellsfargo {}
impl api::PaymentSync for Wellsfargo {}
impl api::PaymentVoid for Wellsfargo {}
impl api::PaymentCapture for Wellsfargo {}
impl api::PaymentIncrementalAuthorization for Wellsfargo {}
impl api::MandateSetup for Wellsfargo {}
impl api::ConnectorAccessToken for Wellsfargo {}
impl api::PaymentToken for Wellsfargo {}
impl api::ConnectorMandateRevoke for Wellsfargo {}

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

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

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

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

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

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

        let attempt_status = match response.reason {
            Some(reason) => match reason {
                transformers::Reason::SystemError => Some(enums::AttemptStatus::Failure),
                transformers::Reason::ServerTimeout | transformers::Reason::ServiceTimeout => None,
            },
            None => None,
        };
        Ok(ErrorResponse {
            status_code: res.status_code,
            reason: response.status.clone(),
            code: response
                .status
                .unwrap_or(hyperswitch_interfaces::consts::NO_ERROR_CODE.to_string()),
            message: response
                .message
                .unwrap_or(hyperswitch_interfaces::consts::NO_ERROR_MESSAGE.to_string()),
            attempt_status,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorIntegration<MandateRevoke, MandateRevokeRequestData, MandateRevokeResponseData>
    for Wellsfargo
{
    fn get_headers(
        &self,
        req: &MandateRevokeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }
    fn get_http_method(&self) -> Method {
        Method::Delete
    }
    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }
    fn get_url(
        &self,
        req: &MandateRevokeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}tms/v1/paymentinstruments/{}",
            self.base_url(connectors),
            utils::RevokeMandateRequestData::get_connector_mandate_id(&req.request)?
        ))
    }
    fn build_request(
        &self,
        req: &MandateRevokeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Delete)
                .url(&MandateRevokeType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(MandateRevokeType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }
    fn handle_response(
        &self,
        data: &MandateRevokeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<MandateRevokeRouterData, errors::ConnectorError> {
        if matches!(res.status_code, 204) {
            event_builder.map(|i| i.set_response_body(&serde_json::json!({"mandate_status": common_enums::MandateStatus::Revoked.to_string()})));
            Ok(MandateRevokeRouterData {
                response: Ok(MandateRevokeResponseData {
                    mandate_status: common_enums::MandateStatus::Revoked,
                }),
                ..data.clone()
            })
        } else {
            // If http_code != 204 || http_code != 4xx, we dont know any other response scenario yet.
            let response_value: serde_json::Value = serde_json::from_slice(&res.response)
                .change_context(errors::ConnectorError::ResponseHandlingFailed)?;
            let response_string = response_value.to_string();

            event_builder.map(|i| {
                i.set_response_body(
                    &serde_json::json!({"response_string": response_string.clone()}),
                )
            });
            router_env::logger::info!(connector_response=?response_string);

            Ok(MandateRevokeRouterData {
                response: Err(ErrorResponse {
                    code: hyperswitch_interfaces::consts::NO_ERROR_CODE.to_string(),
                    message: response_string.clone(),
                    reason: Some(response_string),
                    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,
                }),
                ..data.clone()
            })
        }
    }
    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}
impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Wellsfargo {
    // Not Implemented (R)
}

impl api::PaymentSession for Wellsfargo {}

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

impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Wellsfargo {
    fn get_headers(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

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

        let connector_router_data = wellsfargo::WellsfargoRouterData::from((amount, req));

        let connector_req =
            wellsfargo::WellsfargoPaymentsCaptureRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }
    fn build_request(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsCaptureType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsCaptureType::get_headers(self, req, connectors)?)
                .set_body(PaymentsCaptureType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }
    fn handle_response(
        &self,
        data: &PaymentsCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<
        RouterData<Capture, PaymentsCaptureData, PaymentsResponseData>,
        errors::ConnectorError,
    > {
        let response: wellsfargo::WellsfargoPaymentsResponse = res
            .response
            .parse_struct("Wellsfargo PaymentResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }
    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            reason: response.status.clone(),
            code: response
                .status
                .unwrap_or(hyperswitch_interfaces::consts::NO_ERROR_CODE.to_string()),
            message: response
                .message
                .unwrap_or(hyperswitch_interfaces::consts::NO_ERROR_MESSAGE.to_string()),
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Wellsfargo {
    fn get_headers(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

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

    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&PaymentsSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }
    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        let response: wellsfargo::WellsfargoTransactionResponse = res
            .response
            .parse_struct("Wellsfargo PaymentSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }
    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Wellsfargo {
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

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

        let connector_router_data = wellsfargo::WellsfargoRouterData::from((amount, req));
        let connector_req =
            wellsfargo::WellsfargoPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

        Ok(Some(request))
    }

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

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

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

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

        let attempt_status = match response.reason {
            Some(reason) => match reason {
                transformers::Reason::SystemError => Some(enums::AttemptStatus::Failure),
                transformers::Reason::ServerTimeout | transformers::Reason::ServiceTimeout => None,
            },
            None => None,
        };
        Ok(ErrorResponse {
            status_code: res.status_code,
            reason: response.status.clone(),
            code: response
                .status
                .unwrap_or(hyperswitch_interfaces::consts::NO_ERROR_CODE.to_string()),
            message: response
                .message
                .unwrap_or(hyperswitch_interfaces::consts::NO_ERROR_MESSAGE.to_string()),
            attempt_status,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Wellsfargo {
    fn get_headers(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

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

        let connector_router_data = wellsfargo::WellsfargoRouterData::from((amount, req));
        let connector_req = wellsfargo::WellsfargoVoidRequest::try_from(&connector_router_data)?;

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

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

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

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

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            reason: response.status.clone(),
            code: response
                .status
                .unwrap_or(hyperswitch_interfaces::consts::NO_ERROR_CODE.to_string()),
            message: response
                .message
                .unwrap_or(hyperswitch_interfaces::consts::NO_ERROR_MESSAGE.to_string()),
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl Refund for Wellsfargo {}
impl RefundExecute for Wellsfargo {}
impl RefundSync for Wellsfargo {}

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Wellsfargo {
    fn get_headers(
        &self,
        req: &RefundExecuteRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

    fn get_url(
        &self,
        req: &RefundExecuteRouterData,
        connectors: &Connectors,


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


OpenAPI Block Path: components.schemas.ApplepayConnectorMetadataRequest
{
  "type": "object",
  "properties": {
    "session_token_data": {
      "allOf": [
        {
          "$ref": "#/components/schemas/SessionTokenInfo"
        }
      ],
      "nullable": true
    }
  }
}


File: crates/router/src/compatibility/stripe/customers/types.rs
 Public structs: 9

use std::{convert::From, default::Default};

#[cfg(feature = "v1")]
use api_models::payment_methods as api_types;
use api_models::payments;
#[cfg(feature = "v1")]
use common_utils::{crypto::Encryptable, date_time};
use common_utils::{
    id_type,
    pii::{self, Email},
    types::Description,
};
use serde::{Deserialize, Serialize};

#[cfg(feature = "v1")]
use crate::logger;
use crate::types::{api, api::enums as api_enums};

#[derive(Default, Serialize, PartialEq, Eq, Deserialize, Clone)]
pub struct Shipping {
    pub address: StripeAddressDetails,
    pub name: Option<masking::Secret<String>>,
    pub carrier: Option<String>,
    pub phone: Option<masking::Secret<String>>,
    pub tracking_number: Option<masking::Secret<String>>,
}

#[derive(Default, Serialize, PartialEq, Eq, Deserialize, Clone)]
pub struct StripeAddressDetails {
    pub city: Option<String>,
    pub country: Option<api_enums::CountryAlpha2>,
    pub line1: Option<masking::Secret<String>>,
    pub line2: Option<masking::Secret<String>>,
    pub postal_code: Option<masking::Secret<String>>,
    pub state: Option<masking::Secret<String>>,
}

#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct CreateCustomerRequest {
    pub email: Option<Email>,
    pub invoice_prefix: Option<String>,
    pub name: Option<masking::Secret<String>>,
    pub phone: Option<masking::Secret<String>>,
    pub address: Option<StripeAddressDetails>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub description: Option<Description>,
    pub shipping: Option<Shipping>,
    pub payment_method: Option<String>,              // not used
    pub balance: Option<i64>,                        // not used
    pub cash_balance: Option<pii::SecretSerdeValue>, // not used
    pub coupon: Option<String>,                      // not used
    pub invoice_settings: Option<pii::SecretSerdeValue>, // not used
    pub next_invoice_sequence: Option<String>,       // not used
    pub preferred_locales: Option<String>,           // not used
    pub promotion_code: Option<String>,              // not used
    pub source: Option<String>,                      // not used
    pub tax: Option<pii::SecretSerdeValue>,          // not used
    pub tax_exempt: Option<String>,                  // not used
    pub tax_id_data: Option<String>,                 // not used
    pub test_clock: Option<String>,                  // not used
}

#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct CustomerUpdateRequest {
    pub description: Option<Description>,
    pub email: Option<Email>,
    pub phone: Option<masking::Secret<String, masking::WithType>>,
    pub name: Option<masking::Secret<String>>,
    pub address: Option<StripeAddressDetails>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub shipping: Option<Shipping>,
    pub payment_method: Option<String>,              // not used
    pub balance: Option<i64>,                        // not used
    pub cash_balance: Option<pii::SecretSerdeValue>, // not used
    pub coupon: Option<String>,                      // not used
    pub default_source: Option<String>,              // not used
    pub invoice_settings: Option<pii::SecretSerdeValue>, // not used
    pub next_invoice_sequence: Option<String>,       // not used
    pub preferred_locales: Option<String>,           // not used
    pub promotion_code: Option<String>,              // not used
    pub source: Option<String>,                      // not used
    pub tax: Option<pii::SecretSerdeValue>,          // not used
    pub tax_exempt: Option<String>,                  // not used
}

#[derive(Serialize, PartialEq, Eq)]
pub struct CreateCustomerResponse {
    pub id: id_type::CustomerId,
    pub object: String,
    pub created: u64,
    pub description: Option<Description>,
    pub email: Option<Email>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub name: Option<masking::Secret<String>>,
    pub phone: Option<masking::Secret<String, masking::WithType>>,
}

pub type CustomerRetrieveResponse = CreateCustomerResponse;
pub type CustomerUpdateResponse = CreateCustomerResponse;

#[derive(Serialize, PartialEq, Eq)]
pub struct CustomerDeleteResponse {
    pub id: id_type::CustomerId,
    pub deleted: bool,
}

impl From<StripeAddressDetails> for payments::AddressDetails {
    fn from(address: StripeAddressDetails) -> Self {
        Self {
            city: address.city,
            country: address.country,
            line1: address.line1,
            line2: address.line2,
            zip: address.postal_code,
            state: address.state,
            first_name: None,
            line3: None,
            last_name: None,
            origin_zip: None,
        }
    }
}

#[cfg(feature = "v1")]
impl From<CreateCustomerRequest> for api::CustomerRequest {
    fn from(req: CreateCustomerRequest) -> Self {
        Self {
            customer_id: Some(common_utils::generate_customer_id_of_default_length()),
            name: req.name,
            phone: req.phone,
            email: req.email,
            description: req.description,
            metadata: req.metadata,
            address: req.address.map(|s| s.into()),
            ..Default::default()
        }
    }
}

#[cfg(feature = "v1")]
impl From<CustomerUpdateRequest> for api::CustomerUpdateRequest {
    fn from(req: CustomerUpdateRequest) -> Self {
        Self {
            name: req.name,
            phone: req.phone,
            email: req.email,
            description: req.description,
            metadata: req.metadata,
            address: req.address.map(|s| s.into()),
            ..Default::default()
        }
    }
}

#[cfg(feature = "v1")]
impl From<api::CustomerResponse> for CreateCustomerResponse {
    fn from(cust: api::CustomerResponse) -> Self {
        let cust = cust.into_inner();
        Self {
            id: cust.customer_id,
            object: "customer".to_owned(),
            created: u64::try_from(cust.created_at.assume_utc().unix_timestamp()).unwrap_or_else(
                |error| {
                    logger::error!(
                        %error,
                        "incorrect value for `customer.created_at` provided {}", cust.created_at
                    );
                    // Current timestamp converted to Unix timestamp should have a positive value
                    // for many years to come
                    u64::try_from(date_time::now().assume_utc().unix_timestamp())
                        .unwrap_or_default()
                },
            ),
            description: cust.description,
            email: cust.email.map(|inner| inner.into()),
            metadata: cust.metadata,
            name: cust.name.map(Encryptable::into_inner),
            phone: cust.phone.map(Encryptable::into_inner),
        }
    }
}

#[cfg(feature = "v1")]
impl From<api::CustomerDeleteResponse> for CustomerDeleteResponse {
    fn from(cust: api::CustomerDeleteResponse) -> Self {
        Self {
            id: cust.customer_id,
            deleted: cust.customer_deleted,
        }
    }
}

#[derive(Default, Serialize, PartialEq, Eq)]
pub struct CustomerPaymentMethodListResponse {
    pub object: &'static str,
    pub data: Vec<PaymentMethodData>,
}

#[derive(Default, Serialize, PartialEq, Eq)]
pub struct PaymentMethodData {
    pub id: Option<String>,
    pub object: &'static str,
    pub card: Option<CardDetails>,
    pub created: Option<time::PrimitiveDateTime>,
}

#[derive(Default, Serialize, PartialEq, Eq)]
pub struct CardDetails {
    pub country: Option<String>,
    pub last4: Option<String>,
    pub exp_month: Option<masking::Secret<String>>,
    pub exp_year: Option<masking::Secret<String>>,
    pub fingerprint: Option<masking::Secret<String>>,
}

#[cfg(feature = "v1")]
impl From<api::CustomerPaymentMethodsListResponse> for CustomerPaymentMethodListResponse {
    fn from(item: api::CustomerPaymentMethodsListResponse) -> Self {
        let customer_payment_methods = item.customer_payment_methods;
        let data = customer_payment_methods
            .into_iter()
            .map(From::from)
            .collect();
        Self {
            object: "list",
            data,
        }
    }
}

#[cfg(feature = "v1")]
impl From<api_types::CustomerPaymentMethod> for PaymentMethodData {
    fn from(item: api_types::CustomerPaymentMethod) -> Self {
        let card = item.card.map(From::from);
        Self {
            id: Some(item.payment_token),
            object: "payment_method",
            card,
            created: item.created,
        }
    }
}

#[cfg(feature = "v1")]
impl From<api_types::CardDetailFromLocker> for CardDetails {
    fn from(item: api_types::CardDetailFromLocker) -> Self {
        Self {
            country: item.issuer_country,
            last4: item.last4_digits,
            exp_month: item.expiry_month,
            exp_year: item.expiry_year,
            fingerprint: item.card_fingerprint,
        }
    }
}


pub struct StripebillingWebhookBody {
    #[serde(rename = "type")]
    pub event_type: StripebillingEventType,
    pub data: StripebillingWebhookData,
}


impl api::PayoutEligibility for Ebanx {}

impl api::PayoutEligibility for for Ebanx


impl api::PaymentCapture for Itaubank {}

impl api::PaymentCapture for for Itaubank


/// Validation for the SES client specific configs
    pub fn validate(&self) -> Result<(), &'static str> {
        use common_utils::{ext_traits::ConfigExt, fp_utils::when};

        when(self.email_role_arn.is_default_or_empty(), || {
            Err("email.aws_ses.email_role_arn must not be empty")
        })?;

        when(self.sts_role_session_name.is_default_or_empty(), || {
            Err("email.aws_ses.sts_role_session_name must not be empty")
        })
    }


pub struct PaymentCardDetails {
    expiry_date: ExpiryDate,
    bin: String,
    last4: String,
    brand: String,
}


pub async fn retrieve_file_from_theme_bucket(
    state: &SessionState,
    path: &PathBuf,
) -> UserResult<Vec<u8>> {
    state
        .theme_storage_client
        .retrieve_file(path_buf_to_str(path)?)
        .await
        .change_context(UserErrors::ErrorRetrievingFile)
}


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

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

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

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

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

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

static CONNECTOR: PaysafeTest = PaysafeTest {};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// Connector dependent test cases goes here

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


pub struct BraintreeMeta {
    merchant_account_id: Secret<String>,
    merchant_config_currency: enums::Currency,
}


impl api::PaymentIncrementalAuthorization for Cybersource {}

impl api::PaymentIncrementalAuthorization for for Cybersource


impl api::Payment for Taxjar {}


pub fn is_transaction_event(event_code: &AirwallexWebhookEventType) -> bool {
    matches!(
        event_code,
        AirwallexWebhookEventType::PaymentAttemptFailedToProcess
            | AirwallexWebhookEventType::PaymentAttemptAuthorized
    )
}


OpenAPI Block Path: components.schemas.AuthenticationSyncRequest
{
  "type": "object",
  "required": [
    "client_secret"
  ],
  "properties": {
    "client_secret": {
      "type": "string",
      "description": "The client secret for this authentication."
    }
  }
}


impl AmountDetails {
    /// Get the action to whether calculate surcharge or not as a boolean value
    fn get_surcharge_action_as_bool(&self) -> bool {
        self.skip_surcharge_calculation.as_bool()
    }

    /// Get the action to whether calculate external tax or not as a boolean value
    pub fn get_external_tax_action_as_bool(&self) -> bool {
        self.skip_external_tax_calculation.as_bool()
    }

    /// Calculate the net amount for the order
    pub fn calculate_net_amount(&self) -> MinorUnit {
        self.order_amount
            + self.shipping_cost.unwrap_or(MinorUnit::zero())
            + self.surcharge_amount.unwrap_or(MinorUnit::zero())
            + self.tax_on_surcharge.unwrap_or(MinorUnit::zero())
    }

    pub fn create_attempt_amount_details(
        &self,
        confirm_intent_request: &api_models::payments::PaymentsConfirmIntentRequest,
    ) -> payment_attempt::AttemptAmountDetails {
        let net_amount = self.calculate_net_amount();

        let surcharge_amount = match self.skip_surcharge_calculation {
            common_enums::SurchargeCalculationOverride::Skip => self.surcharge_amount,
            common_enums::SurchargeCalculationOverride::Calculate => None,
        };

        let tax_on_surcharge = match self.skip_surcharge_calculation {
            common_enums::SurchargeCalculationOverride::Skip => self.tax_on_surcharge,
            common_enums::SurchargeCalculationOverride::Calculate => None,
        };

        let order_tax_amount = match self.skip_external_tax_calculation {
            common_enums::TaxCalculationOverride::Skip => {
                self.tax_details.as_ref().and_then(|tax_details| {
                    tax_details.get_tax_amount(Some(confirm_intent_request.payment_method_subtype))
                })
            }
            common_enums::TaxCalculationOverride::Calculate => None,
        };

        payment_attempt::AttemptAmountDetails::from(payment_attempt::AttemptAmountDetailsSetter {
            net_amount,
            amount_to_capture: None,
            surcharge_amount,
            tax_on_surcharge,
            // This will be updated when we receive response from the connector
            amount_capturable: MinorUnit::zero(),
            shipping_cost: self.shipping_cost,
            order_tax_amount,
        })
    }

    pub fn proxy_create_attempt_amount_details(
        &self,
        _confirm_intent_request: &api_models::payments::ProxyPaymentsRequest,
    ) -> payment_attempt::AttemptAmountDetails {
        let net_amount = self.calculate_net_amount();

        let surcharge_amount = match self.skip_surcharge_calculation {
            common_enums::SurchargeCalculationOverride::Skip => self.surcharge_amount,
            common_enums::SurchargeCalculationOverride::Calculate => None,
        };

        let tax_on_surcharge = match self.skip_surcharge_calculation {
            common_enums::SurchargeCalculationOverride::Skip => self.tax_on_surcharge,
            common_enums::SurchargeCalculationOverride::Calculate => None,
        };

        let order_tax_amount = match self.skip_external_tax_calculation {
            common_enums::TaxCalculationOverride::Skip => self
                .tax_details
                .as_ref()
                .and_then(|tax_details| tax_details.get_tax_amount(None)),
            common_enums::TaxCalculationOverride::Calculate => None,
        };

        payment_attempt::AttemptAmountDetails::from(payment_attempt::AttemptAmountDetailsSetter {
            net_amount,
            amount_to_capture: None,
            surcharge_amount,
            tax_on_surcharge,
            // This will be updated when we receive response from the connector
            amount_capturable: MinorUnit::zero(),
            shipping_cost: self.shipping_cost,
            order_tax_amount,
        })
    }

    pub fn update_from_request(self, req: &api_models::payments::AmountDetailsUpdate) -> Self {
        Self {
            order_amount: req
                .order_amount()
                .unwrap_or(self.order_amount.into())
                .into(),
            currency: req.currency().unwrap_or(self.currency),
            shipping_cost: req.shipping_cost().or(self.shipping_cost),
            tax_details: req
                .order_tax_amount()
                .map(|order_tax_amount| TaxDetails {
                    default: Some(diesel_models::DefaultTax { order_tax_amount }),
                    payment_method_type: None,
                })
                .or(self.tax_details),
            skip_external_tax_calculation: req
                .skip_external_tax_calculation()
                .unwrap_or(self.skip_external_tax_calculation),
            skip_surcharge_calculation: req
                .skip_surcharge_calculation()
                .unwrap_or(self.skip_surcharge_calculation),
            surcharge_amount: req.surcharge_amount().or(self.surcharge_amount),
            tax_on_surcharge: req.tax_on_surcharge().or(self.tax_on_surcharge),
            amount_captured: self.amount_captured,
        }
    }
}


pub struct CallBackResponse {
    pub transaction_id: String,
    pub order_ref: String,
}


/// An event that can be published.
pub trait Event: EventInfo {
    /// The type of the event.
    type EventType;
    /// The timestamp of the event.
    fn timestamp(&self) -> PrimitiveDateTime;

    /// The (unique) identifier of the event.
    fn identifier(&self) -> String;

    /// The class/type of the event. This is used to group/categorize events together.
    fn class(&self) -> Self::EventType;

    /// Metadata associated with the event
    fn metadata(&self) -> HashMap<String, String> {
        HashMap::new()
    }
}


/// Similar to [`DieselEnum`] but uses text when storing in the database, this is to avoid
/// making changes to the database when the enum variants are added or modified
///
/// # Example
/// [DieselEnum]: macro@crate::diesel_enum
///
/// ```
/// use router_derive::{diesel_enum};
///
/// // Deriving `FromStr` and `ToString` using the `strum` crate, you can also implement it
/// // yourself if required.
/// #[derive(strum::Display, strum::EnumString)]
/// #[derive(Debug)]
/// #[diesel_enum(storage_type = "text")]
/// enum Color {
///     Red,
///     Green,
///     Blue,
/// }
/// ```
#[proc_macro_derive(DieselEnumText)]
pub fn diesel_enum_derive_string(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let ast = syn::parse_macro_input!(input as syn::DeriveInput);
    let tokens = macros::diesel_enum_text_derive_inner(&ast)
        .unwrap_or_else(|error| error.to_compile_error());
    tokens.into()
}


/// NoCrm struct
pub struct NoCrm;


pub async fn add_entry_to_blocklist() {}


pub trait ProcessPaymentAttempt {
    fn build_payment_data_from_payment_attempt(
        self,
        payment_attempt: types::DummyConnectorPaymentAttempt,
        redirect_url: String,
    ) -> types::DummyConnectorResult<types::DummyConnectorPaymentData>;
}


pub async fn verify_external_token(
    state: SessionState,
    json_payload: external_service_auth_api::ExternalVerifyTokenRequest,
    external_service_type: ExternalServiceType,
) -> RouterResponse<external_service_auth_api::ExternalVerifyTokenResponse> {
    let token_from_payload = json_payload.token.expose();

    let token = authentication::decode_jwt::<ExternalToken>(&token_from_payload, &state)
        .await
        .change_context(errors::ApiErrorResponse::Unauthorized)?;

    fp_utils::when(
        authentication::blacklist::check_user_in_blacklist(&state, &token.user_id, token.exp)
            .await?,
        || Err(errors::ApiErrorResponse::InvalidJwtToken),
    )?;

    token.check_service_type(&external_service_type)?;

    let user_in_db = state
        .global_store
        .find_user_by_id(&token.user_id)
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("User not found in database")?;

    let email = user_in_db.email.clone();
    let name = user_in_db.name;

    Ok(service_api::ApplicationResponse::Json(
        external_service_auth_api::ExternalVerifyTokenResponse::Hypersense {
            user_id: user_in_db.user_id,
            merchant_id: token.merchant_id,
            name,
            email,
        },
    ))
}


pub async fn refund_data(
    state: SessionState,
    req: types::DummyConnectorRefundRetrieveRequest,
) -> types::DummyConnectorResponse<types::DummyConnectorRefundResponse> {
    let refund_id = req.refund_id;
    utils::tokio_mock_sleep(
        state.conf.dummy_connector.refund_retrieve_duration,
        state.conf.dummy_connector.refund_retrieve_tolerance,
    )
    .await;

    let redis_conn = state
        .store
        .get_redis_conn()
        .change_context(errors::DummyConnectorErrors::InternalServerError)
        .attach_printable("Failed to get redis connection")?;
    let refund_data = redis_conn
        .get_and_deserialize_key::<types::DummyConnectorRefundResponse>(
            &refund_id.as_str().into(),
            "DummyConnectorRefundResponse",
        )
        .await
        .change_context(errors::DummyConnectorErrors::RefundNotFound)?;
    Ok(api::ApplicationResponse::Json(refund_data))
}


pub fn is_db_unique_violation(&self) -> bool {
        match self {
            Self::DatabaseError(err) => {
                matches!(err.current_context(), DatabaseError::UniqueViolation,)
            }
            Self::DuplicateValue { .. } => true,
            _ => false,
        }
    }


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


pub async fn revenue_recovery_pt_retrieve_api() {}


File: crates/hyperswitch_connectors/src/connectors/mpgs/transformers.rs
 Public structs: 8

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

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

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

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

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

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

impl TryFrom<&MpgsRouterData<&PaymentsAuthorizeRouterData>> for MpgsPaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &MpgsRouterData<&PaymentsAuthorizeRouterData>) -> Result<Self, Self::Error> {
        match item.router_data.request.payment_method_data.clone() {
            PaymentMethodData::Card(_) => Err(errors::ConnectorError::NotImplemented(
                "Card payment method not implemented".to_string(),
            )
            .into()),
            _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
        }
    }
}

//TODO: Fill the struct with respective fields
// Auth Struct
pub struct MpgsAuthType {
    pub(super) api_key: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for MpgsAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
                api_key: api_key.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}
// PaymentsResponse
//TODO: Append the remaining status flags
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum MpgsPaymentStatus {
    Succeeded,
    Failed,
    #[default]
    Processing,
}

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

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

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

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

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

// Type definition for Refund Response

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

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

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

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

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

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


pub struct CustomerListConstraints {
    pub limit: u16,
    pub offset: Option<u32>,
}


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


pub fn is_permanent_card(&self) -> bool {
        matches!(self, Self::PermanentCard(_))
    }


impl CurrencyFactors {
    pub fn new(to_factor: Decimal, from_factor: Decimal) -> Self {
        Self {
            to_factor,
            from_factor,
        }
    }
}


impl PaymentSession for Netcetera {}


pub trait NonSerializableSecret: Serialize {}


File: crates/analytics/src/sdk_events/metrics/payment_methods_call_count.rs

use std::collections::HashSet;

use api_models::analytics::{
    sdk_events::{
        SdkEventDimensions, SdkEventFilters, SdkEventMetricsBucketIdentifier, SdkEventNames,
    },
    Granularity, TimeRange,
};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

use super::SdkEventMetricRow;
use crate::{
    query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, ToSql, Window},
    types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
};

#[derive(Default)]
pub(super) struct PaymentMethodsCallCount;

#[async_trait::async_trait]
impl<T> super::SdkEventMetric<T> for PaymentMethodsCallCount
where
    T: AnalyticsDataSource + super::SdkEventMetricAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_metrics(
        &self,
        dimensions: &[SdkEventDimensions],
        publishable_key: &str,
        filters: &SdkEventFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
        let mut query_builder: QueryBuilder<T> =
            QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
        let dimensions = dimensions.to_vec();

        for dim in dimensions.iter() {
            query_builder.add_select_column(dim).switch()?;
        }

        query_builder
            .add_select_column(Aggregate::Count {
                field: None,
                alias: Some("count"),
            })
            .switch()?;

        if let Some(granularity) = granularity {
            query_builder
                .add_granularity_in_mins(granularity)
                .switch()?;
        }

        filters.set_filter_clause(&mut query_builder).switch()?;

        query_builder
            .add_filter_clause("merchant_id", publishable_key)
            .switch()?;

        query_builder
            .add_bool_filter_clause("first_event", 1)
            .switch()?;

        query_builder
            .add_filter_clause("event_name", SdkEventNames::PaymentMethodsCall)
            .switch()?;

        query_builder
            .add_filter_clause("log_type", "INFO")
            .switch()?;

        query_builder
            .add_filter_clause("category", "API")
            .switch()?;

        time_range
            .set_filter_clause(&mut query_builder)
            .attach_printable("Error filtering time range")
            .switch()?;

        for dim in dimensions.iter() {
            query_builder
                .add_group_by_clause(dim)
                .attach_printable("Error grouping by dimensions")
                .switch()?;
        }

        if let Some(_granularity) = granularity.as_ref() {
            query_builder
                .add_group_by_clause("time_bucket")
                .attach_printable("Error adding granularity")
                .switch()?;
        }

        query_builder
            .execute_query::<SdkEventMetricRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| {
                Ok((
                    SdkEventMetricsBucketIdentifier::new(
                        i.payment_method.clone(),
                        i.platform.clone(),
                        i.browser_name.clone(),
                        i.source.clone(),
                        i.component.clone(),
                        i.payment_experience.clone(),
                        i.time_bucket.clone(),
                    ),
                    i,
                ))
            })
            .collect::<error_stack::Result<
                HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
                crate::query::PostProcessingError,
            >>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


impl Profile {
    #[cfg(feature = "v1")]
    pub fn get_id(&self) -> &common_utils::id_type::ProfileId {
        &self.profile_id
    }

    #[cfg(feature = "v2")]
    pub fn get_id(&self) -> &common_utils::id_type::ProfileId {
        &self.id
    }
}


File: crates/router/src/db/routing_algorithm.rs

use diesel_models::routing_algorithm as routing_storage;
use error_stack::report;
use router_env::{instrument, tracing};
use storage_impl::mock_db::MockDb;

use crate::{
    connection,
    core::errors::{self, CustomResult},
    services::Store,
};

type StorageResult<T> = CustomResult<T, errors::StorageError>;

#[async_trait::async_trait]
pub trait RoutingAlgorithmInterface {
    async fn insert_routing_algorithm(
        &self,
        routing_algorithm: routing_storage::RoutingAlgorithm,
    ) -> StorageResult<routing_storage::RoutingAlgorithm>;

    async fn find_routing_algorithm_by_profile_id_algorithm_id(
        &self,
        profile_id: &common_utils::id_type::ProfileId,
        algorithm_id: &common_utils::id_type::RoutingId,
    ) -> StorageResult<routing_storage::RoutingAlgorithm>;

    async fn find_routing_algorithm_by_algorithm_id_merchant_id(
        &self,
        algorithm_id: &common_utils::id_type::RoutingId,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> StorageResult<routing_storage::RoutingAlgorithm>;

    async fn find_routing_algorithm_metadata_by_algorithm_id_profile_id(
        &self,
        algorithm_id: &common_utils::id_type::RoutingId,
        profile_id: &common_utils::id_type::ProfileId,
    ) -> StorageResult<routing_storage::RoutingProfileMetadata>;

    async fn list_routing_algorithm_metadata_by_profile_id(
        &self,
        profile_id: &common_utils::id_type::ProfileId,
        limit: i64,
        offset: i64,
    ) -> StorageResult<Vec<routing_storage::RoutingProfileMetadata>>;

    async fn list_routing_algorithm_metadata_by_merchant_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        limit: i64,
        offset: i64,
    ) -> StorageResult<Vec<routing_storage::RoutingProfileMetadata>>;

    async fn list_routing_algorithm_metadata_by_merchant_id_transaction_type(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        transaction_type: &common_enums::TransactionType,
        limit: i64,
        offset: i64,
    ) -> StorageResult<Vec<routing_storage::RoutingProfileMetadata>>;
}

#[async_trait::async_trait]
impl RoutingAlgorithmInterface for Store {
    #[instrument(skip_all)]
    async fn insert_routing_algorithm(
        &self,
        routing_algorithm: routing_storage::RoutingAlgorithm,
    ) -> StorageResult<routing_storage::RoutingAlgorithm> {
        let conn = connection::pg_connection_write(self).await?;
        routing_algorithm
            .insert(&conn)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
    }

    #[instrument(skip_all)]
    async fn find_routing_algorithm_by_profile_id_algorithm_id(
        &self,
        profile_id: &common_utils::id_type::ProfileId,
        algorithm_id: &common_utils::id_type::RoutingId,
    ) -> StorageResult<routing_storage::RoutingAlgorithm> {
        let conn = connection::pg_connection_write(self).await?;
        routing_storage::RoutingAlgorithm::find_by_algorithm_id_profile_id(
            &conn,
            algorithm_id,
            profile_id,
        )
        .await
        .map_err(|error| report!(errors::StorageError::from(error)))
    }

    #[instrument(skip_all)]
    async fn find_routing_algorithm_by_algorithm_id_merchant_id(
        &self,
        algorithm_id: &common_utils::id_type::RoutingId,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> StorageResult<routing_storage::RoutingAlgorithm> {
        let conn = connection::pg_connection_write(self).await?;
        routing_storage::RoutingAlgorithm::find_by_algorithm_id_merchant_id(
            &conn,
            algorithm_id,
            merchant_id,
        )
        .await
        .map_err(|error| report!(errors::StorageError::from(error)))
    }

    #[instrument(skip_all)]
    async fn find_routing_algorithm_metadata_by_algorithm_id_profile_id(
        &self,
        algorithm_id: &common_utils::id_type::RoutingId,
        profile_id: &common_utils::id_type::ProfileId,
    ) -> StorageResult<routing_storage::RoutingProfileMetadata> {
        let conn = connection::pg_connection_write(self).await?;
        routing_storage::RoutingAlgorithm::find_metadata_by_algorithm_id_profile_id(
            &conn,
            algorithm_id,
            profile_id,
        )
        .await
        .map_err(|error| report!(errors::StorageError::from(error)))
    }

    #[instrument(skip_all)]
    async fn list_routing_algorithm_metadata_by_profile_id(
        &self,
        profile_id: &common_utils::id_type::ProfileId,
        limit: i64,
        offset: i64,
    ) -> StorageResult<Vec<routing_storage::RoutingProfileMetadata>> {
        let conn = connection::pg_connection_write(self).await?;
        routing_storage::RoutingAlgorithm::list_metadata_by_profile_id(
            &conn, profile_id, limit, offset,
        )
        .await
        .map_err(|error| report!(errors::StorageError::from(error)))
    }

    #[instrument(skip_all)]
    async fn list_routing_algorithm_metadata_by_merchant_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        limit: i64,
        offset: i64,
    ) -> StorageResult<Vec<routing_storage::RoutingProfileMetadata>> {
        let conn = connection::pg_connection_write(self).await?;
        routing_storage::RoutingAlgorithm::list_metadata_by_merchant_id(
            &conn,
            merchant_id,
            limit,
            offset,
        )
        .await
        .map_err(|error| report!(errors::StorageError::from(error)))
    }

    async fn list_routing_algorithm_metadata_by_merchant_id_transaction_type(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        transaction_type: &common_enums::TransactionType,
        limit: i64,
        offset: i64,
    ) -> StorageResult<Vec<routing_storage::RoutingProfileMetadata>> {
        let conn = connection::pg_connection_write(self).await?;
        routing_storage::RoutingAlgorithm::list_metadata_by_merchant_id_transaction_type(
            &conn,
            merchant_id,
            transaction_type,
            limit,
            offset,
        )
        .await
        .map_err(|error| report!(errors::StorageError::from(error)))
    }
}

#[async_trait::async_trait]
impl RoutingAlgorithmInterface for MockDb {
    async fn insert_routing_algorithm(
        &self,
        _routing_algorithm: routing_storage::RoutingAlgorithm,
    ) -> StorageResult<routing_storage::RoutingAlgorithm> {
        Err(errors::StorageError::MockDbError)?
    }

    async fn find_routing_algorithm_by_profile_id_algorithm_id(
        &self,
        _profile_id: &common_utils::id_type::ProfileId,
        _algorithm_id: &common_utils::id_type::RoutingId,
    ) -> StorageResult<routing_storage::RoutingAlgorithm> {
        Err(errors::StorageError::MockDbError)?
    }

    async fn find_routing_algorithm_by_algorithm_id_merchant_id(
        &self,
        _algorithm_id: &common_utils::id_type::RoutingId,
        _merchant_id: &common_utils::id_type::MerchantId,
    ) -> StorageResult<routing_storage::RoutingAlgorithm> {
        Err(errors::StorageError::MockDbError)?
    }

    async fn find_routing_algorithm_metadata_by_algorithm_id_profile_id(
        &self,
        _algorithm_id: &common_utils::id_type::RoutingId,
        _profile_id: &common_utils::id_type::ProfileId,
    ) -> StorageResult<routing_storage::RoutingProfileMetadata> {
        Err(errors::StorageError::MockDbError)?
    }

    async fn list_routing_algorithm_metadata_by_profile_id(
        &self,
        _profile_id: &common_utils::id_type::ProfileId,
        _limit: i64,
        _offset: i64,
    ) -> StorageResult<Vec<routing_storage::RoutingProfileMetadata>> {
        Err(errors::StorageError::MockDbError)?
    }

    async fn list_routing_algorithm_metadata_by_merchant_id(
        &self,
        _merchant_id: &common_utils::id_type::MerchantId,
        _limit: i64,
        _offset: i64,
    ) -> StorageResult<Vec<routing_storage::RoutingProfileMetadata>> {
        Err(errors::StorageError::MockDbError)?
    }

    async fn list_routing_algorithm_metadata_by_merchant_id_transaction_type(
        &self,
        _merchant_id: &common_utils::id_type::MerchantId,
        _transaction_type: &common_enums::TransactionType,
        _limit: i64,
        _offset: i64,
    ) -> StorageResult<Vec<routing_storage::RoutingProfileMetadata>> {
        Err(errors::StorageError::MockDbError)?
    }
}


pub struct ReconActivation {
    pub recipient_email: domain::UserEmail,
    pub user_name: domain::UserName,
    pub subject: &'static str,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
}


pub struct OrderInformationWithBill {
    amount_details: Amount,
    bill_to: Option<BillTo>,
}


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


impl api::ConnectorAccessToken for Juspaythreedsserver {}

impl api::ConnectorAccessToken for for Juspaythreedsserver


pub fn is_payout_err_state(status: api_enums::PayoutStatus) -> bool {
    matches!(
        status,
        api_enums::PayoutStatus::Cancelled
            | api_enums::PayoutStatus::Failed
            | api_enums::PayoutStatus::Ineligible
    )
}


impl FileMetadataInterface for KafkaStore {
    async fn insert_file_metadata(
        &self,
        file: storage::FileMetadataNew,
    ) -> CustomResult<storage::FileMetadata, errors::StorageError> {
        self.diesel_store.insert_file_metadata(file).await
    }

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

    async fn delete_file_metadata_by_merchant_id_file_id(
        &self,
        merchant_id: &id_type::MerchantId,
        file_id: &str,
    ) -> CustomResult<bool, errors::StorageError> {
        self.diesel_store
            .delete_file_metadata_by_merchant_id_file_id(merchant_id, file_id)
            .await
    }

    async fn update_file_metadata(
        &self,
        this: storage::FileMetadata,
        file_metadata: storage::FileMetadataUpdate,
    ) -> CustomResult<storage::FileMetadata, errors::StorageError> {
        self.diesel_store
            .update_file_metadata(this, file_metadata)
            .await
    }
}

impl FileMetadataInterface for for KafkaStore


pub struct RoutingAlgorithm {
    pub algorithm_id: id_type::RoutingId,
    pub profile_id: id_type::ProfileId,
    pub merchant_id: id_type::MerchantId,
    pub name: String,
    pub description: Option<String>,
    pub kind: enums::RoutingAlgorithmKind,
    pub algorithm_data: serde_json::Value,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    pub algorithm_for: enums::TransactionType,
    pub decision_engine_routing_id: Option<String>,
}


OpenAPI Block Path: components.schemas.AuthenticationStatus
{
  "type": "string",
  "enum": [
    "started",
    "pending",
    "success",
    "failed"
  ]
}


pub struct Notifications {
    pub return_url: Option<String>,
    pub status_url: Option<String>,
    pub cancel_url: Option<String>,
}


pub async fn user_merchant_account_create(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<user_api::UserMerchantCreate>,
) -> HttpResponse {
    let flow = Flow::UserMerchantAccountCreate;
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        json_payload.into_inner(),
        |state, auth: auth::UserFromToken, json_payload, _| {
            user_core::create_merchant_account(state, auth, json_payload)
        },
        &auth::JWTAuth {
            permission: Permission::OrganizationAccountWrite,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl PaymentIntentMetricAccumulator for CountAccumulator {
    type MetricOutput = Option<u64>;
    #[inline]
    fn add_metrics_bucket(&mut self, metrics: &PaymentIntentMetricRow) {
        self.count = match (self.count, metrics.count) {
            (None, None) => None,
            (None, i @ Some(_)) | (i @ Some(_), None) => i,
            (Some(a), Some(b)) => Some(a + b),
        }
    }
    #[inline]
    fn collect(self) -> Self::MetricOutput {
        self.count.and_then(|i| u64::try_from(i).ok())
    }
}

impl PaymentIntentMetricAccumulator for for CountAccumulator


pub struct KafkaStore {
    pub kafka_producer: KafkaProducer,
    pub diesel_store: Store,
    pub tenant_id: TenantID,
}