// Function: decrypt_and_get_totp_secret
// File: crates/router/src/types/domain/user.rs
// Module: router

pub fn decrypt_and_get_totp_secret(
        &self,
        state: &SessionState,
    ) -> UserResult<Option<Secret<String>>>


// Implementation: impl Capturable for for PaymentsApproveData
// File: crates/router/src/types.rs
// Module: router
// Methods: 0 total (0 public)

impl Capturable for for PaymentsApproveData


// Struct: SuccessRateAccumulator
// File: crates/analytics/src/payments/accumulator.rs
// Module: analytics
// Implementations: 1
// Traits: PaymentMetricAccumulator

pub struct SuccessRateAccumulator


// Function: inner
// File: crates/common_utils/src/types/keymanager.rs
// Module: common_utils

pub fn inner(self) -> StrongSecret<Vec<u8>>


// Implementation: impl ConnectorCommon for for Signifyd
// File: crates/hyperswitch_connectors/src/connectors/signifyd.rs
// Module: hyperswitch_connectors
// Methods: 5 total (0 public)

impl ConnectorCommon for for Signifyd


// Struct: AcquirerDataInput
// File: crates/euclid/src/backend/inputs.rs
// Module: euclid
// Implementations: 0

pub struct AcquirerDataInput


// Function: do_retry
// File: crates/router/src/core/payments/retry.rs
// Module: router

pub fn do_retry<F, ApiRequest, FData, D>(
    state: &routes::SessionState,
    req_state: ReqState,
    connector: &api::ConnectorData,
    operation: &operations::BoxedOperation<'_, F, ApiRequest, D>,
    customer: &Option<domain::Customer>,
    merchant_context: &domain::MerchantContext,
    payment_data: &mut D,
    router_data: types::RouterData<F, FData, types::PaymentsResponseData>,
    validate_result: &operations::ValidateResult,
    schedule_time: Option<time::PrimitiveDateTime>,
    is_step_up: bool,
    frm_suggestion: Option<storage_enums::FrmSuggestion>,
    business_profile: &domain::Profile,
    should_retry_with_pan: bool,
    routing_decision: Option<routing_helpers::RoutingDecisionData>,
) -> RouterResult<types::RouterData<F, FData, types::PaymentsResponseData>>
where
    F: Clone + Send + Sync,
    FData: Send + Sync + types::Capturable,
    payments::PaymentResponse: operations::Operation<F, FData>,
    D: payments::OperationSessionGetters<F>
        + payments::OperationSessionSetters<F>
        + Send
        + Sync
        + Clone,
    D: ConstructFlowSpecificData<F, FData, types::PaymentsResponseData>,
    types::RouterData<F, FData, types::PaymentsResponseData>: Feature<F, FData>,
    dyn api::Connector: services::api::ConnectorIntegration<F, FData, types::PaymentsResponseData>,


// Struct: PaymentsAuthenticateData
// File: crates/hyperswitch_domain_models/src/router_request_types.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct PaymentsAuthenticateData


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

pub fn new() -> &'static Self


// Module Structure
// File: crates/router_env/src/metrics.rs
// Module: router_env

// Public exports:
pub use helpers::f64_histogram_buckets;


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

impl ConnectorRedirectResponse for for Bambora


// Struct: ConfigUpdate
// File: crates/router/src/types/api/configs.rs
// Module: router
// Implementations: 0

pub struct ConfigUpdate


// File: crates/analytics/src/payment_intents/sankey.rs
// Module: analytics
// Public functions: 1
// Public structs: 1

use common_enums::enums;
use common_utils::{
    errors::ParsingError,
    types::{authentication::AuthInfo, TimeRange},
};
use error_stack::ResultExt;
use router_env::logger;

use crate::{
    clickhouse::ClickhouseClient,
    query::{Aggregate, QueryBuilder, QueryFilter},
    types::{AnalyticsCollection, DBEnumWrapper, MetricsError, MetricsResult},
};

#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Eq,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumIter,
    strum::EnumString,
)]
#[serde(rename_all = "snake_case")]
pub enum SessionizerRefundStatus {
    FullRefunded,
    #[default]
    NotRefunded,
    PartialRefunded,
}

#[derive(
    Clone,
    Copy,
    Debug,
    Default,
    Eq,
    Hash,
    PartialEq,
    serde::Deserialize,
    serde::Serialize,
    strum::Display,
    strum::EnumIter,
    strum::EnumString,
)]
#[serde(rename_all = "snake_case")]
pub enum SessionizerDisputeStatus {
    DisputePresent,
    #[default]
    NotDisputed,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct SankeyRow {
    pub count: i64,
    pub status: DBEnumWrapper<enums::IntentStatus>,
    #[serde(default)]
    pub refunds_status: Option<DBEnumWrapper<SessionizerRefundStatus>>,
    #[serde(default)]
    pub dispute_status: Option<DBEnumWrapper<SessionizerDisputeStatus>>,
    pub first_attempt: i64,
}

impl TryInto<SankeyRow> for serde_json::Value {
    type Error = error_stack::Report<ParsingError>;

    fn try_into(self) -> Result<SankeyRow, Self::Error> {
        logger::debug!("Parsing SankeyRow from {:?}", self);
        serde_json::from_value(self).change_context(ParsingError::StructParseFailure(
            "Failed to parse Sankey in clickhouse results",
        ))
    }
}

pub async fn get_sankey_data(
    clickhouse_client: &ClickhouseClient,
    auth: &AuthInfo,
    time_range: &TimeRange,
) -> MetricsResult<Vec<SankeyRow>> {
    let mut query_builder =
        QueryBuilder::<ClickhouseClient>::new(AnalyticsCollection::PaymentIntentSessionized);
    query_builder
        .add_select_column(Aggregate::<String>::Count {
            field: None,
            alias: Some("count"),
        })
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_select_column("status")
        .attach_printable("Error adding select clause")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_select_column("refunds_status")
        .attach_printable("Error adding select clause")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_select_column("dispute_status")
        .attach_printable("Error adding select clause")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_select_column("(attempt_count = 1) as first_attempt")
        .attach_printable("Error adding select clause")
        .change_context(MetricsError::QueryBuildingError)?;

    auth.set_filter_clause(&mut query_builder)
        .change_context(MetricsError::QueryBuildingError)?;

    time_range
        .set_filter_clause(&mut query_builder)
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_group_by_clause("status")
        .attach_printable("Error adding group by clause")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_group_by_clause("refunds_status")
        .attach_printable("Error adding group by clause")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_group_by_clause("dispute_status")
        .attach_printable("Error adding group by clause")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .add_group_by_clause("first_attempt")
        .attach_printable("Error adding group by clause")
        .change_context(MetricsError::QueryBuildingError)?;

    query_builder
        .execute_query::<SankeyRow, _>(clickhouse_client)
        .await
        .change_context(MetricsError::QueryBuildingError)?
        .change_context(MetricsError::QueryExecutionFailure)?
        .into_iter()
        .map(Ok)
        .collect()
}


// Struct: ToggleBlocklistQuery
// File: crates/api_models/src/blocklist.rs
// Module: api_models
// Implementations: 1
// Traits: ApiEventMetric

pub struct ToggleBlocklistQuery


// Struct: AvsSecurityCodeResponse
// File: crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AvsSecurityCodeResponse


// Implementation: impl api::PaymentAuthorizeSessionToken for for Nuvei
// File: crates/hyperswitch_connectors/src/connectors/nuvei.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentAuthorizeSessionToken for for Nuvei


// Function: is_success
// File: crates/common_enums/src/enums.rs
// Module: common_enums

pub fn is_success(&self) -> bool


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

pub mod transformers;
use std::sync::LazyLock;

use api_models::webhooks::{ConnectorWebhookSecrets, IncomingWebhookEvent, ObjectReferenceId};
use base64::Engine;
use common_enums::enums;
use common_utils::{
    crypto,
    errors::CustomResult,
    ext_traits::ByteSliceExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector},
};
use error_stack::{Report, ResultExt};
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        mandate_revoke::MandateRevoke,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, MandateRevokeRequestData, PaymentMethodTokenizationData,
        PaymentsAuthorizeData, PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData,
        PaymentsSyncData, RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, MandateRevokeResponseData, PaymentMethodDetails, PaymentsResponseData,
        RefundsResponseData, SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        MandateRevokeRouterData, PaymentsAuthorizeRouterData, PaymentsCancelRouterData,
        PaymentsCaptureRouterData, PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{
        MandateRevokeType, PaymentsAuthorizeType, PaymentsCaptureType, PaymentsSyncType,
        PaymentsVoidType, RefundExecuteType, RefundSyncType, Response,
    },
    webhooks,
};
use masking::{Mask, PeekInterface};
use router_env::logger;
use transformers as noon;

use crate::{
    constants::headers,
    types::ResponseRouterData,
    utils::{self as connector_utils, PaymentMethodDataType},
};

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

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

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

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

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Noon
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        req: &RouterData<Flow, Request, Response>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let mut header = vec![(
            headers::CONTENT_TYPE.to_string(),
            PaymentsAuthorizeType::get_content_type(self)
                .to_string()
                .into(),
        )];
        let mut api_key = get_auth_header(&req.connector_auth_type)?;
        header.append(&mut api_key);
        Ok(header)
    }
}

fn get_auth_header(
    auth_type: &ConnectorAuthType,
) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
    let auth = noon::NoonAuthType::try_from(auth_type)?;

    let encoded_api_key = auth
        .business_identifier
        .zip(auth.application_identifier)
        .zip(auth.api_key)
        .map(|((business_identifier, application_identifier), api_key)| {
            common_utils::consts::BASE64_ENGINE.encode(format!(
                "{business_identifier}.{application_identifier}:{api_key}",
            ))
        });

    Ok(vec![(
        headers::AUTHORIZATION.to_string(),
        format!("Key {}", encoded_api_key.peek()).into_masked(),
    )])
}

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

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

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

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

        match response {
            Ok(noon_error_response) => {
                event_builder.map(|i| i.set_error_response_body(&noon_error_response));
                router_env::logger::info!(connector_response=?noon_error_response);
                // Adding in case of timeouts, if psync gives 4xx with this code, fail the payment
                let attempt_status = if noon_error_response.result_code == 19001 {
                    Some(enums::AttemptStatus::Failure)
                } else {
                    None
                };
                Ok(ErrorResponse {
                    status_code: res.status_code,
                    code: noon_error_response.result_code.to_string(),
                    message: noon_error_response.class_description,
                    reason: Some(noon_error_response.message),
                    attempt_status,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                })
            }
            Err(error_message) => {
                event_builder.map(|event| event.set_error(serde_json::json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code})));
                logger::error!(deserialization_error =? error_message);
                connector_utils::handle_json_response_deserialization_failure(res, "noon")
            }
        }
    }
}

impl ConnectorValidation for Noon {
    fn validate_connector_against_payment_request(
        &self,
        capture_method: Option<enums::CaptureMethod>,
        _payment_method: enums::PaymentMethod,
        _pmt: Option<enums::PaymentMethodType>,
    ) -> CustomResult<(), errors::ConnectorError> {
        let capture_method = capture_method.unwrap_or_default();
        match capture_method {
            enums::CaptureMethod::Automatic
            | enums::CaptureMethod::Manual
            | enums::CaptureMethod::SequentialAutomatic => Ok(()),
            enums::CaptureMethod::ManualMultiple | enums::CaptureMethod::Scheduled => Err(
                connector_utils::construct_not_implemented_error_report(capture_method, self.id()),
            ),
        }
    }

    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,
        ]);
        connector_utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id())
    }

    fn validate_psync_reference_id(
        &self,
        _data: &PaymentsSyncData,
        _is_three_ds: bool,
        _status: enums::AttemptStatus,
        _connector_meta_data: Option<common_utils::pii::SecretSerdeValue>,
    ) -> CustomResult<(), errors::ConnectorError> {
        // since we can make psync call with our reference_id, having connector_transaction_id is not an mandatory criteria
        Ok(())
    }
}

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

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

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

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

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

    fn get_url(
        &self,
        _req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}payment/v1/order", self.base_url(connectors)))
    }

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

        let mandate_details =
            connector_utils::get_mandate_details(req.request.setup_mandate_details.clone())?;
        let mandate_amount = mandate_details
            .map(|mandate| {
                connector_utils::convert_amount(
                    self.amount_converter,
                    mandate.amount,
                    mandate.currency,
                )
            })
            .transpose()?;

        let connector_router_data = noon::NoonRouterData::from((amount, req, mandate_amount));
        let connector_req = noon::NoonPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        let response: noon::NoonPaymentsResponse = res
            .response
            .parse_struct("Noon PaymentsAuthorizeResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

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

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

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

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

    fn get_url(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}payment/v1/order/getbyreference/{}",
            self.base_url(connectors),
            req.connector_request_reference_id
        ))
    }

    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: noon::NoonPaymentsResponse = res
            .response
            .parse_struct("noon PaymentsSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

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

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

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

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

    fn get_url(
        &self,
        _req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}payment/v1/order", self.base_url(connectors)))
    }

    fn get_request_body(
        &self,
        req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = connector_utils::convert_amount(
            self.amount_converter,
            req.request.minor_amount_to_capture,
            req.request.currency,
        )?;
        let connector_router_data = noon::NoonRouterData::from((amount, req, None));
        let connector_req = noon::NoonPaymentsActionRequest::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<PaymentsCaptureRouterData, errors::ConnectorError> {
        let response: noon::NoonPaymentsResponse = res
            .response
            .parse_struct("Noon PaymentsCaptureResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

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

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

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

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

    fn get_url(
        &self,
        _req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}payment/v1/order", self.base_url(connectors)))
    }
    fn get_request_body(
        &self,
        req: &PaymentsCancelRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = noon::NoonPaymentsCancelRequest::try_from(req)?;
        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(PaymentsVoidType::get_request_body(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsCancelRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCancelRouterData, errors::ConnectorError> {
        let response: noon::NoonPaymentsResponse = res
            .response
            .parse_struct("Noon PaymentsCancelResponse")
            .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<MandateRevoke, MandateRevokeRequestData, MandateRevokeResponseData>
    for Noon
{
    fn get_headers(
        &self,
        req: &MandateRevokeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }
    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }
    fn get_url(
        &self,
        _req: &MandateRevokeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!("{}payment/v1/order", self.base_url(connectors)))
    }
    fn build_request(
        &self,
        req: &MandateRevokeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&MandateRevokeType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(MandateRevokeType::get_headers(self, req, connectors)?)
                .set_body(MandateRevokeType::get_request_body(self, req, connectors)?)
                .build(),
        ))
    }
    fn get_request_body(
        &self,
        req: &MandateRevokeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = noon::NoonRevokeMandateRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn handle_response(
        &self,
        data: &MandateRevokeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<MandateRevokeRouterData, errors::ConnectorError> {
        let response: noon::NoonRevokeMandateResponse = res
            .response
            .parse_struct("Noon NoonRevokeMandateResponse")
            .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<Execute, RefundsData, RefundsResponseData> for Noon {
    fn get_headers(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

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

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

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let refund_amount = connector_utils::convert_amount(
            self.amount_converter,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;
        let connector_router_data = noon::NoonRouterData::from((refund_amount, req, None));
        let connector_req = noon::NoonPaymentsActionRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

    fn handle_response(
        &self,
        data: &RefundsRouterData<Execute>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
        let response: noon::RefundResponse = res
            .response
            .parse_struct("noon RefundResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

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

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

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

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

    fn get_url(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(format!(
            "{}payment/v1/order/getbyreference/{}",
            self.base_url(connectors),
            req.connector_request_reference_id
        ))
    }

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

    fn handle_response(
        &self,
        data: &RefundSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        let response: noon::RefundSyncResponse = res
            .response
            .parse_struct("noon RefundSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

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

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

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

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

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

    fn get_webhook_source_verification_signature(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _connector_webhook_secrets: &ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let webhook_body: noon::NoonWebhookSignature = request
            .body
            .parse_struct("NoonWebhookSignature")
            .change_context(errors::ConnectorError::WebhookSignatureNotFound)?;
        let signature = webhook_body.signature;
        common_utils::consts::BASE64_ENGINE
            .decode(signature)
            .change_context(errors::ConnectorError::WebhookSignatureNotFound)
    }

    fn get_webhook_source_verification_message(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _merchant_id: &common_utils::id_type::MerchantId,
        _connector_webhook_secrets: &ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let webhook_body: noon::NoonWebhookBody = request
            .body
            .parse_struct("NoonWebhookBody")
            .change_context(errors::ConnectorError::WebhookSignatureNotFound)?;
        let message = format!(
            "{},{},{},{},{}",
            webhook_body.order_id,
            webhook_body.order_status,
            webhook_body.event_id,
            webhook_body.event_type,
            webhook_body.time_stamp,
        );
        Ok(message.into_bytes())
    }

    fn get_webhook_object_reference_id(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<ObjectReferenceId, errors::ConnectorError> {
        let details: noon::NoonWebhookOrderId = request
            .body
            .parse_struct("NoonWebhookOrderId")
            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
        Ok(ObjectReferenceId::PaymentId(
            api_models::payments::PaymentIdType::ConnectorTransactionId(
                details.order_id.to_string(),
            ),
        ))
    }

    fn get_webhook_event_type(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
        let details: noon::NoonWebhookEvent = request
            .body
            .parse_struct("NoonWebhookEvent")
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;

        Ok(match &details.event_type {
            noon::NoonWebhookEventTypes::Sale | noon::NoonWebhookEventTypes::Capture => {
                match &details.order_status {
                    noon::NoonPaymentStatus::Captured => IncomingWebhookEvent::PaymentIntentSuccess,
                    _ => Err(errors::ConnectorError::WebhookEventTypeNotFound)?,
                }
            }
            noon::NoonWebhookEventTypes::Fail => IncomingWebhookEvent::PaymentIntentFailure,
            noon::NoonWebhookEventTypes::Authorize
            | noon::NoonWebhookEventTypes::Authenticate
            | noon::NoonWebhookEventTypes::Refund
            | noon::NoonWebhookEventTypes::Unknown => IncomingWebhookEvent::EventNotSupported,
        })
    }

    fn get_webhook_resource_object(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let resource: noon::NoonWebhookObject = request
            .body
            .parse_struct("NoonWebhookObject")
            .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;

        Ok(Box::new(noon::NoonPaymentsResponse::from(resource)))
    }
}

static NOON_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> = LazyLock::new(|| {
    let supported_capture_methods = vec![
        enums::CaptureMethod::Automatic,
        enums::CaptureMethod::Manual,
        enums::CaptureMethod::SequentialAutomatic,
    ];

    let supported_card_network = vec![
        common_enums::CardNetwork::AmericanExpress,
        common_enums::CardNetwork::JCB,
        common_enums::CardNetwork::Mastercard,
        common_enums::CardNetwork::Visa,
    ];

    let mut noon_supported_payment_methods = SupportedPaymentMethods::new();

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

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

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

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

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

    noon_supported_payment_methods
});

static NOON_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Noon",
    description: "Noon is a payment gateway and PSP enabling secure online transactions",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Live,
};

static NOON_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 1] = [enums::EventClass::Payments];

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

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

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


// Struct: Billwerk
// File: crates/hyperswitch_connectors/src/connectors/billwerk.rs
// Module: hyperswitch_connectors
// Implementations: 17
// Traits: api::Payment, api::PaymentSession, api::ConnectorAccessToken, api::MandateSetup, api::PaymentAuthorize, api::PaymentSync, api::PaymentCapture, api::PaymentVoid, api::Refund, api::RefundExecute, api::RefundSync, api::PaymentToken, ConnectorCommon, ConnectorValidation, IncomingWebhook, ConnectorSpecifications

pub struct Billwerk

api::Payment api::PaymentSession api::ConnectorAccessToken api::MandateSetup api::PaymentAuthorize api::PaymentSync api::PaymentCapture api::PaymentVoid api::Refund api::RefundExecute api::RefundSync api::PaymentToken ConnectorCommon ConnectorValidation IncomingWebhook ConnectorSpecifications


// Struct: GetActivePaymentsMetricRequest
// File: crates/api_models/src/analytics.rs
// Module: api_models
// Implementations: 0

pub struct GetActivePaymentsMetricRequest


// Implementation: impl api::RefundSync for for Nordea
// File: crates/hyperswitch_connectors/src/connectors/nordea.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundSync for for Nordea


// Implementation: impl api::Payment for for Worldpayxml
// File: crates/hyperswitch_connectors/src/connectors/worldpayxml.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Payment for for Worldpayxml


// Struct: NextAction
// File: crates/api_models/src/authentication.rs
// Module: api_models
// Implementations: 0

pub struct NextAction


// Struct: GlobalpayWebhookObjectEventType
// File: crates/hyperswitch_connectors/src/connectors/globalpay/response.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct GlobalpayWebhookObjectEventType


// Function: get_most_specific_theme_using_token_and_min_entity
// File: crates/router/src/utils/user/theme.rs
// Module: router

pub fn get_most_specific_theme_using_token_and_min_entity(
    state: &SessionState,
    user_from_token: &UserFromToken,
    min_entity: EntityType,
) -> UserResult<Option<Theme>>


// Struct: ReconTokenResponse
// File: crates/api_models/src/recon.rs
// Module: api_models
// Implementations: 0

pub struct ReconTokenResponse


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

impl api::RefundExecute for for Coinbase


        let payments_request = serde_json::from_str::<PaymentsRequest>(payments_request);
        assert!(payments_request.is_ok());
        assert!(payments_request
            .unwrap()
            .payment_method_data
            .unwrap()
            .billing
            .is_some());
    }
}

#[cfg(test)]
mod payments_response_api_contract {
    #![allow(clippy::unwrap_used)]
    use super::*;

    #[derive(Debug, serde::Serialize)]
    struct TestPaymentsResponse {
        #[serde(serialize_with = "serialize_payment_method_data_response")]
        payment_method_data: Option<PaymentMethodDataResponseWithBilling>,
    }

    #[test]
    fn test_reward_payment_response() {
        let payment_method_response_with_billing = PaymentMethodDataResponseWithBilling {
            payment_method_data: Some(PaymentMethodDataResponse::Reward {}),
            billing: None,
        };

        let payments_response = TestPaymentsResponse {
            payment_method_data: Some(payment_method_response_with_billing),
        };

        let expected_response = r#"{"payment_method_data":"reward"}"#;

        let stringified_payments_response = payments_response.encode_to_string_of_json();
        assert_eq!(stringified_payments_response.unwrap(), expected_response);
    }
}

/// Set of tests to extract billing details from payment method data
/// These are required for backwards compatibility
#[cfg(test)]
mod billing_from_payment_method_data {
    #![allow(clippy::unwrap_used)]
    use common_enums::CountryAlpha2;
    use masking::ExposeOptionInterface;

    use super::*;

    const TEST_COUNTRY: CountryAlpha2 = CountryAlpha2::US;
    const TEST_FIRST_NAME: &str = "John";
    const TEST_LAST_NAME: &str = "Wheat Dough";
    const TEST_FULL_NAME: &str = "John Wheat Dough";
    const TEST_FIRST_NAME_SINGLE: &str = "John";

    #[test]
    fn test_wallet_payment_method_data_paypal() {
        let test_email: Email = Email::try_from("example@example.com".to_string()).unwrap();

        let paypal_wallet_payment_method_data =
            PaymentMethodData::Wallet(WalletData::PaypalRedirect(PaypalRedirection {
                email: Some(test_email.clone()),
            }));

        let billing_address = paypal_wallet_payment_method_data
            .get_billing_address()
            .unwrap();

        assert_eq!(billing_address.email.unwrap(), test_email);

        assert!(billing_address.address.is_none());
        assert!(billing_address.phone.is_none());
    }

    #[test]
    fn test_bank_redirect_payment_method_data_eps() {
        let test_email = Email::try_from("example@example.com".to_string()).unwrap();
        let test_first_name = Secret::new(String::from("Chaser"));

        let bank_redirect_billing = BankRedirectBilling {
            billing_name: Some(test_first_name.clone()),
            email: Some(test_email.clone()),
        };

        let eps_bank_redirect_payment_method_data =
            PaymentMethodData::BankRedirect(BankRedirectData::Eps {
                billing_details: Some(bank_redirect_billing),
                bank_name: None,
                country: Some(TEST_COUNTRY),
            });

        let billing_address = eps_bank_redirect_payment_method_data
            .get_billing_address()
            .unwrap();

        let address_details = billing_address.address.unwrap();

        assert_eq!(billing_address.email.unwrap(), test_email);
        assert_eq!(address_details.country.unwrap(), TEST_COUNTRY);
        assert_eq!(address_details.first_name.unwrap(), test_first_name);
        assert!(billing_address.phone.is_none());
    }

    #[test]
    fn test_paylater_payment_method_data_klarna() {
        let test_email: Email = Email::try_from("example@example.com".to_string()).unwrap();

        let klarna_paylater_payment_method_data =
            PaymentMethodData::PayLater(PayLaterData::KlarnaRedirect {
                billing_email: Some(test_email.clone()),
                billing_country: Some(TEST_COUNTRY),
            });

        let billing_address = klarna_paylater_payment_method_data
            .get_billing_address()
            .unwrap();

        assert_eq!(billing_address.email.unwrap(), test_email);
        assert_eq!(
            billing_address.address.unwrap().country.unwrap(),
            TEST_COUNTRY
        );
        assert!(billing_address.phone.is_none());
    }

    #[test]
    fn test_bank_debit_payment_method_data_ach() {
        let test_email = Email::try_from("example@example.com".to_string()).unwrap();
        let test_first_name = Secret::new(String::from("Chaser"));

        let bank_redirect_billing = BankDebitBilling {
            name: Some(test_first_name.clone()),
            address: None,
            email: Some(test_email.clone()),
        };

        let ach_bank_debit_payment_method_data =
            PaymentMethodData::BankDebit(BankDebitData::AchBankDebit {
                billing_details: Some(bank_redirect_billing),
                account_number: Secret::new("1234".to_string()),
                routing_number: Secret::new("1235".to_string()),
                card_holder_name: None,
                bank_account_holder_name: None,
                bank_name: None,
                bank_type: None,
                bank_holder_type: None,
            });

        let billing_address = ach_bank_debit_payment_method_data
            .get_billing_address()
            .unwrap();

        let address_details = billing_address.address.unwrap();

        assert_eq!(billing_address.email.unwrap(), test_email);
        assert_eq!(address_details.first_name.unwrap(), test_first_name);
        assert!(billing_address.phone.is_none());
    }

    #[test]
    fn test_card_payment_method_data() {
        let card_payment_method_data = PaymentMethodData::Card(Card {
            card_holder_name: Some(Secret::new(TEST_FIRST_NAME_SINGLE.into())),
            ..Default::default()
        });

        let billing_address = card_payment_method_data.get_billing_address();

        let billing_address = billing_address.unwrap();

        assert_eq!(
            billing_address.address.unwrap().first_name.expose_option(),
            Some(TEST_FIRST_NAME_SINGLE.into())
        );
    }

    #[test]
    fn test_card_payment_method_data_empty() {
        let card_payment_method_data = PaymentMethodData::Card(Card::default());

        let billing_address = card_payment_method_data.get_billing_address();

        assert!(billing_address.is_none());
    }

    #[test]
    fn test_card_payment_method_data_full_name() {
        let card_payment_method_data = PaymentMethodData::Card(Card {
            card_holder_name: Some(Secret::new(TEST_FULL_NAME.into())),
            ..Default::default()
        });

        let billing_details = card_payment_method_data.get_billing_address().unwrap();
        let billing_address = billing_details.address.unwrap();

        assert_eq!(
            billing_address.first_name.expose_option(),
            Some(TEST_FIRST_NAME.into())
        );

        assert_eq!(
            billing_address.last_name.expose_option(),
            Some(TEST_LAST_NAME.into())
        );
    }

    #[test]
    fn test_card_payment_method_data_empty_string() {
        let card_payment_method_data = PaymentMethodData::Card(Card {
            card_holder_name: Some(Secret::new("".to_string())),
            ..Default::default()
        });

        let billing_details = card_payment_method_data.get_billing_address();

        assert!(billing_details.is_none());
    }
}

#[cfg(feature = "v2")]
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PaymentRevenueRecoveryMetadata {
    /// Total number of billing connector + recovery retries for a payment intent.
    #[schema(value_type = u16,example = "1")]
    pub total_retry_count: u16,
    /// Flag for the payment connector's call
    pub payment_connector_transmission: Option<PaymentConnectorTransmission>,
    /// Billing Connector Id to update the invoices
    #[schema(value_type = String, example = "mca_1234567890")]
    pub billing_connector_id: id_type::MerchantConnectorAccountId,
    /// Payment Connector Id to retry the payments
    #[schema(value_type = String, example = "mca_1234567890")]
    pub active_attempt_payment_connector_id: id_type::MerchantConnectorAccountId,
    /// Billing Connector Payment Details
    #[schema(value_type = BillingConnectorPaymentDetails)]
    pub billing_connector_payment_details: BillingConnectorPaymentDetails,
    /// Payment Method Type
    #[schema(example = "pay_later", value_type = PaymentMethod)]
    pub payment_method_type: common_enums::PaymentMethod,
    /// PaymentMethod Subtype
    #[schema(example = "klarna", value_type = PaymentMethodType)]
    pub payment_method_subtype: common_enums::PaymentMethodType,
    /// The name of the payment connector through which the payment attempt was made.
    #[schema(value_type = Connector, example = "stripe")]
    pub connector: common_enums::connector_enums::Connector,
    #[schema(value_type = BillingConnectorPaymentMethodDetails)]
    /// Extra Payment Method Details that are needed to be stored
    pub billing_connector_payment_method_details: Option<BillingConnectorPaymentMethodDetails>,
    /// Invoice Next billing time
    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
    pub invoice_next_billing_time: Option<PrimitiveDateTime>,
    /// Invoice Next billing time
    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
    pub invoice_billing_started_at_time: Option<PrimitiveDateTime>,
    /// First Payment Attempt Payment Gateway Error Code
    #[schema(value_type = Option<String>, example = "card_declined")]
    pub first_payment_attempt_pg_error_code: Option<String>,
    /// First Payment Attempt Network Error Code
    #[schema(value_type = Option<String>, example = "05")]
    pub first_payment_attempt_network_decline_code: Option<String>,
    /// First Payment Attempt Network Advice Code
    #[schema(value_type = Option<String>, example = "02")]
    pub first_payment_attempt_network_advice_code: Option<String>,
}

#[cfg(feature = "v2")]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ToSchema)]
#[serde(rename_all = "snake_case", tag = "type", content = "value")]
pub enum BillingConnectorPaymentMethodDetails {
    Card(BillingConnectorAdditionalCardInfo),
}

#[cfg(feature = "v2")]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, ToSchema)]
pub struct BillingConnectorAdditionalCardInfo {
    #[schema(value_type = CardNetwork, example = "Visa")]
    /// Card Network
    pub card_network: Option<common_enums::enums::CardNetwork>,
    #[schema(value_type = Option<String>, example = "JP MORGAN CHASE")]
    /// Card Issuer
    pub card_issuer: Option<String>,
}

#[cfg(feature = "v2")]
impl BillingConnectorPaymentMethodDetails {
    pub fn get_billing_connector_card_info(&self) -> Option<&BillingConnectorAdditionalCardInfo> {
        match self {
            Self::Card(card_details) => Some(card_details),
        }
    }
}

#[cfg(feature = "v2")]
impl PaymentRevenueRecoveryMetadata {
    pub fn set_payment_transmission_field_for_api_request(
        &mut self,
        payment_connector_transmission: PaymentConnectorTransmission,
    ) {
        self.payment_connector_transmission = Some(payment_connector_transmission);
    }
    pub fn get_payment_token_for_api_request(&self) -> mandates::ProcessorPaymentToken {
        mandates::ProcessorPaymentToken {
            processor_payment_token: self
                .billing_connector_payment_details
                .payment_processor_token
                .clone(),
            merchant_connector_id: Some(self.active_attempt_payment_connector_id.clone()),
        }
    }
    pub fn get_merchant_connector_id_for_api_request(&self) -> id_type::MerchantConnectorAccountId {
        self.active_attempt_payment_connector_id.clone()
    }

    pub fn get_connector_customer_id(&self) -> String {
        self.billing_connector_payment_details
            .connector_customer_id
            .to_owned()
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[cfg(feature = "v2")]
pub struct BillingConnectorPaymentDetails {
    /// Payment Processor Token to process the Revenue Recovery Payment
    pub payment_processor_token: String,
    /// Billing Connector's Customer Id
    pub connector_customer_id: String,
}

// Serialize is required because the api event requires Serialize to be implemented
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
#[cfg(feature = "v2")]
pub struct PaymentsAttemptRecordRequest {
    /// The amount details for the payment attempt.
    pub amount_details: PaymentAttemptAmountDetails,

    #[schema(value_type = AttemptStatus, example = "charged")]
    pub status: enums::AttemptStatus,

    /// The billing details of the payment attempt. This address will be used for invoicing.
    pub billing: Option<Address>,

    /// The shipping address for the payment attempt.
    pub shipping: Option<Address>,

    /// Error details provided by the billing processor.
    pub error: Option<RecordAttemptErrorDetails>,

    /// A description for the payment attempt.
    #[schema(example = "It's my first payment request", value_type = Option<String>)]
    pub description: Option<common_utils::types::Description>,

    /// A unique identifier for a payment provided by the connector.
    pub connector_transaction_id: Option<common_utils::types::ConnectorTransactionId>,

    /// The payment method type used for payment attempt.
    #[schema(value_type = PaymentMethod, example = "bank_transfer")]
    pub payment_method_type: api_enums::PaymentMethod,

    /// The name of the payment connector through which the payment attempt was made.
    #[schema(value_type = Option<Connector>, example = "stripe")]
    pub connector: Option<common_enums::connector_enums::Connector>,

    /// Billing connector id to update the invoices.
    #[schema(value_type = String, example = "mca_1234567890")]
    pub billing_connector_id: id_type::MerchantConnectorAccountId,

    /// Billing connector id to update the invoices.
    #[schema(value_type = String, example = "mca_1234567890")]
    pub payment_merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,

    /// The payment method subtype to be used for the payment. This should match with the `payment_method_data` provided
    #[schema(value_type = PaymentMethodType, example = "apple_pay")]
    pub payment_method_subtype: api_enums::PaymentMethodType,

    /// The additional payment data to be used for the payment attempt.
    pub payment_method_data: Option<RecordAttemptPaymentMethodDataRequest>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>, example = r#"{ "udf1": "some-value", "udf2": "some-value" }"#)]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// Additional data that might be required by hyperswitch based on the requested features by the merchants.
    pub feature_metadata: Option<PaymentAttemptFeatureMetadata>,

    /// The time at which payment attempt was created.
    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
    pub transaction_created_at: Option<PrimitiveDateTime>,

    /// payment method token at payment processor end.
    #[schema(value_type = String, example = "1234567890")]
    pub processor_payment_method_token: String,

    /// customer id at payment connector for which mandate is attached.
    #[schema(value_type = String, example = "cust_12345")]
    pub connector_customer_id: String,

    /// Number of attempts made for invoice
    #[schema(value_type = Option<u16>, example = 1)]
    pub retry_count: Option<u16>,

    /// Next Billing time of the Invoice
    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
    pub invoice_next_billing_time: Option<PrimitiveDateTime>,

    /// Next Billing time of the Invoice
    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
    pub invoice_billing_started_at_time: Option<PrimitiveDateTime>,

    /// source where the payment was triggered by
    #[schema(value_type = TriggeredBy, example = "internal" )]
    pub triggered_by: common_enums::TriggeredBy,

    #[schema(value_type = CardNetwork, example = "Visa" )]
    /// card_network
    pub card_network: Option<common_enums::CardNetwork>,

    #[schema(example = "Chase")]
    /// Card Issuer
    pub card_issuer: Option<String>,
}

// Serialize is required because the api event requires Serialize to be implemented
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
#[cfg(feature = "v2")]
pub struct RecoveryPaymentsCreate {
    /// The amount details for the payment
    pub amount_details: AmountDetails,

    /// Unique identifier for the payment. This ensures idempotency for multiple payments
    /// that have been done by a single merchant.
    #[schema(
        value_type = Option<String>,
        min_length = 30,
        max_length = 30,
        example = "pay_mbabizu24mvu3mela5njyhpit4"
    )]
    pub merchant_reference_id: id_type::PaymentReferenceId,

    /// Error details for the payment if any
    pub error: Option<ErrorDetails>,

    /// Billing connector id to update the invoices.
    #[schema(value_type = String, example = "mca_1234567890")]
    pub billing_merchant_connector_id: id_type::MerchantConnectorAccountId,

    /// Payments connector id to update the invoices.
    #[schema(value_type = String, example = "mca_1234567890")]
    pub payment_merchant_connector_id: id_type::MerchantConnectorAccountId,

    #[schema(value_type = AttemptStatus, example = "charged")]
    pub attempt_status: enums::AttemptStatus,

    /// The billing details of the payment attempt.
    pub billing: Option<Address>,

    /// The payment method subtype to be used for the payment. This should match with the `payment_method_data` provided
    #[schema(value_type = PaymentMethodType, example = "apple_pay")]
    pub payment_method_sub_type: api_enums::PaymentMethodType,

    /// The time at which payment attempt was created.
    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
    pub transaction_created_at: Option<PrimitiveDateTime>,

    /// Payment method type for the payment attempt
    #[schema(value_type = Option<PaymentMethod>, example = "wallet")]
    pub payment_method_type: common_enums::PaymentMethod,

    /// customer id at payment connector for which mandate is attached.
    #[schema(value_type = String, example = "cust_12345")]
    pub connector_customer_id: Secret<String>,

    /// Invoice billing started at billing connector end.
    #[schema(example = "2022-09-10T10:11:12Z")]
    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
    pub billing_started_at: Option<PrimitiveDateTime>,

    /// A unique identifier for a payment provided by the payment connector
    #[schema(value_type = Option<String>, example = "993672945374576J")]
    pub connector_transaction_id: Option<Secret<String>>,

    /// payment method token units at payment processor end.
    pub payment_method_data: CustomRecoveryPaymentMethodData,

    /// Type of action that needs to be taken after consuming the recovery payload. For example: scheduling a failed payment or stopping the invoice.
    pub action: common_payments_types::RecoveryAction,

    /// Allow partial authorization for this payment
    #[schema(value_type = Option<bool>, default = false)]
    pub enable_partial_authorization: Option<primitive_wrappers::EnablePartialAuthorizationBool>,

    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
    #[schema(value_type = Option<Object>, example = r#"{ "udf1": "some-value", "udf2": "some-value" }"#)]
    pub metadata: Option<pii::SecretSerdeValue>,
}

/// Error details for the payment
#[cfg(feature = "v2")]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
pub struct RecordAttemptErrorDetails {
    /// error code sent by billing connector.
    pub code: String,
    /// error message sent by billing connector.
    pub message: String,
    /// This field can be returned for both approved and refused Mastercard payments.
    /// This code provides additional information about the type of transaction or the reason why the payment failed.
    /// If the payment failed, the network advice code gives guidance on if and when you can retry the payment.
    pub network_advice_code: Option<String>,
    /// For card errors resulting from a card issuer decline, a brand specific 2, 3, or 4 digit code which indicates the reason the authorization failed.
    pub network_decline_code: Option<String>,
    /// A string indicating how to proceed with an network error if payment gateway provide one. This is used to understand the network error code better.
    pub network_error_message: Option<String>,
}

#[derive(Debug, Clone, Eq, PartialEq, ToSchema)]
pub struct NullObject;

impl Serialize for NullObject {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_none()
    }
}

#[cfg(test)]
mod null_object_test {
    use serde_json;

    use super::*;

    #[allow(clippy::unwrap_used)]
    #[test]
    fn test_null_object_serialization() {
        let null_object = NullObject;
        let serialized = serde_json::to_string(&null_object).unwrap();
        assert_eq!(serialized, "null");
    }
}


// Struct: DummyConnector
// File: crates/router/src/routes/app.rs
// Module: router
// Implementations: 2

pub struct DummyConnector


// File: crates/openapi/src/routes.rs
// Module: openapi

#![allow(unused)]

pub mod api_keys;
pub mod authentication;
pub mod blocklist;
pub mod customers;
pub mod disputes;
pub mod gsm;
pub mod mandates;
pub mod merchant_account;
pub mod merchant_connector_account;
pub mod organization;
pub mod payment_link;
pub mod payment_method;
pub mod payments;
pub mod payouts;
pub mod platform;
pub mod poll;
pub mod profile;
pub mod profile_acquirer;
pub mod proxy;
pub mod refunds;
pub mod relay;
pub mod revenue_recovery;
pub mod routing;
pub mod three_ds_decision_rule;
pub mod tokenization;
pub mod webhook_events;


// Function: get_co_badged_card_data
// File: crates/hyperswitch_domain_models/src/payment_method_data.rs
// Module: hyperswitch_domain_models

pub fn get_co_badged_card_data(&self) -> Option<payment_methods::CoBadgedCardData>


// Struct: ConnectorEventsRequest
// File: crates/api_models/src/analytics/connector_events.rs
// Module: api_models
// Implementations: 0

pub struct ConnectorEventsRequest


// Struct: PaymentsMandateReference
// File: crates/diesel_models/src/payment_method.rs
// Module: diesel_models
// Implementations: 2
// Traits: std::ops::Deref, std::ops::DerefMut

pub struct PaymentsMandateReference


// Function: get_parent_group_info
// File: crates/router/src/routes/user_role.rs
// Module: router

pub fn get_parent_group_info(
    state: web::Data<AppState>,
    http_req: HttpRequest,
    query: web::Query<role_api::GetParentGroupsInfoQueryParams>,
) -> HttpResponse


// Function: retrieve_disputes_list
// File: crates/router/src/core/disputes.rs
// Module: router

pub fn retrieve_disputes_list(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
    constraints: api_models::disputes::DisputeListGetConstraints,
) -> RouterResponse<Vec<api_models::disputes::DisputeResponse>>


// Function: sync_refund_with_gateway
// File: crates/router/src/core/refunds.rs
// Module: router

pub fn sync_refund_with_gateway(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    payment_attempt: &storage::PaymentAttempt,
    payment_intent: &storage::PaymentIntent,
    refund: &diesel_refund::Refund,
    creds_identifier: Option<String>,
    split_refunds: Option<SplitRefundsRequest>,
) -> RouterResult<diesel_refund::Refund>


// Struct: DwollaRequestLink
// File: crates/hyperswitch_connectors/src/connectors/dwolla/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DwollaRequestLink


// Implementation: impl SchedulerInterface for for Store
// File: crates/scheduler/src/scheduler.rs
// Module: scheduler
// Methods: 0 total (0 public)

impl SchedulerInterface for for Store


// Struct: Fiuu
// File: crates/hyperswitch_connectors/src/connectors/fiuu.rs
// Module: hyperswitch_connectors
// Implementations: 17
// Traits: api::Payment, api::PaymentSession, api::ConnectorAccessToken, api::MandateSetup, api::PaymentAuthorize, api::PaymentSync, api::PaymentCapture, api::PaymentVoid, api::Refund, api::RefundExecute, api::RefundSync, api::PaymentToken, ConnectorCommon, ConnectorValidation, webhooks::IncomingWebhook, ConnectorSpecifications

pub struct Fiuu

api::Payment api::PaymentSession api::ConnectorAccessToken api::MandateSetup api::PaymentAuthorize api::PaymentSync api::PaymentCapture api::PaymentVoid api::Refund api::RefundExecute api::RefundSync api::PaymentToken ConnectorCommon ConnectorValidation webhooks::IncomingWebhook ConnectorSpecifications


// Implementation: impl Responder
// File: crates/router/src/routes/payments.rs
// Module: router
// Methods: 0 total (0 public)

impl Responder


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

pub fn new() -> &'static Self


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

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


// Implementation: impl ProfileInterface for for KafkaStore
// File: crates/router/src/db/kafka_store.rs
// Module: router
// Methods: 7 total (0 public)

impl ProfileInterface for for KafkaStore


// Implementation: impl api::PaymentAuthorize for for Finix
// File: crates/hyperswitch_connectors/src/connectors/finix.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentAuthorize for for Finix