// File: crates/router/src/core/webhooks/incoming.rs
// Module: router
// Public functions: 5
// Public structs: 1

use std::{str::FromStr, time::Instant};

use actix_web::FromRequest;
#[cfg(feature = "payouts")]
use api_models::payouts as payout_models;
use api_models::webhooks::{self, WebhookResponseTracker};
use common_utils::{
    errors::ReportSwitchExt,
    events::ApiEventsType,
    ext_traits::{AsyncExt, ByteSliceExt},
    types::{AmountConvertor, StringMinorUnitForConnector},
};
use diesel_models::{refund as diesel_refund, ConnectorMandateReferenceId};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    mandates::CommonMandateReference,
    payments::{payment_attempt::PaymentAttempt, HeaderPayload},
    router_request_types::VerifyWebhookSourceRequestData,
    router_response_types::{VerifyWebhookSourceResponseData, VerifyWebhookStatus},
};
use hyperswitch_interfaces::webhooks::{IncomingWebhookFlowError, IncomingWebhookRequestDetails};
use masking::{ExposeInterface, PeekInterface};
use router_env::{instrument, tracing, tracing_actix_web::RequestId};

use super::{types, utils, MERCHANT_ID};
use crate::{
    consts,
    core::{
        api_locking,
        errors::{self, ConnectorErrorExt, CustomResult, RouterResponse, StorageErrorExt},
        metrics, payment_methods,
        payments::{self, tokenization},
        refunds, relay, unified_connector_service, utils as core_utils,
        webhooks::{network_tokenization_incoming, utils::construct_webhook_router_data},
    },
    db::StorageInterface,
    events::api_logs::ApiEvent,
    logger,
    routes::{
        app::{ReqState, SessionStateInfo},
        lock_utils, SessionState,
    },
    services::{
        self, authentication as auth, connector_integration_interface::ConnectorEnum,
        ConnectorValidation,
    },
    types::{
        api::{
            self, mandates::MandateResponseExt, ConnectorCommon, ConnectorData, GetToken,
            IncomingWebhook,
        },
        domain,
        storage::{self, enums},
        transformers::{ForeignFrom, ForeignInto, ForeignTryFrom},
    },
    utils::{self as helper_utils, ext_traits::OptionExt, generate_id},
};
#[cfg(feature = "payouts")]
use crate::{core::payouts, types::storage::PayoutAttemptUpdate};

#[allow(clippy::too_many_arguments)]
pub async fn incoming_webhooks_wrapper<W: types::OutgoingWebhookType>(
    flow: &impl router_env::types::FlowMetric,
    state: SessionState,
    req_state: ReqState,
    req: &actix_web::HttpRequest,
    merchant_context: domain::MerchantContext,
    connector_name_or_mca_id: &str,
    body: actix_web::web::Bytes,
    is_relay_webhook: bool,
) -> RouterResponse<serde_json::Value> {
    let start_instant = Instant::now();
    let (application_response, webhooks_response_tracker, serialized_req) =
        Box::pin(incoming_webhooks_core::<W>(
            state.clone(),
            req_state,
            req,
            merchant_context.clone(),
            connector_name_or_mca_id,
            body.clone(),
            is_relay_webhook,
        ))
        .await?;

    logger::info!(incoming_webhook_payload = ?serialized_req);

    let request_duration = Instant::now()
        .saturating_duration_since(start_instant)
        .as_millis();

    let request_id = RequestId::extract(req)
        .await
        .attach_printable("Unable to extract request id from request")
        .change_context(errors::ApiErrorResponse::InternalServerError)?;
    let auth_type = auth::AuthenticationType::WebhookAuth {
        merchant_id: merchant_context.get_merchant_account().get_id().clone(),
    };
    let status_code = 200;
    let api_event = ApiEventsType::Webhooks {
        connector: connector_name_or_mca_id.to_string(),
        payment_id: webhooks_response_tracker.get_payment_id(),
    };
    let response_value = serde_json::to_value(&webhooks_response_tracker)
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Could not convert webhook effect to string")?;
    let infra = state.infra_components.clone();
    let api_event = ApiEvent::new(
        state.tenant.tenant_id.clone(),
        Some(merchant_context.get_merchant_account().get_id().clone()),
        flow,
        &request_id,
        request_duration,
        status_code,
        serialized_req,
        Some(response_value),
        None,
        auth_type,
        None,
        api_event,
        req,
        req.method(),
        infra,
    );
    state.event_handler().log_event(&api_event);
    Ok(application_response)
}

#[cfg(feature = "v1")]
pub async fn network_token_incoming_webhooks_wrapper<W: types::OutgoingWebhookType>(
    flow: &impl router_env::types::FlowMetric,
    state: SessionState,
    req: &actix_web::HttpRequest,
    body: actix_web::web::Bytes,
) -> RouterResponse<serde_json::Value> {
    let start_instant = Instant::now();

    let request_details: IncomingWebhookRequestDetails<'_> = IncomingWebhookRequestDetails {
        method: req.method().clone(),
        uri: req.uri().clone(),
        headers: req.headers(),
        query_params: req.query_string().to_string(),
        body: &body,
    };

    let (application_response, webhooks_response_tracker, serialized_req, merchant_id) = Box::pin(
        network_token_incoming_webhooks_core::<W>(&state, request_details),
    )
    .await?;

    logger::info!(incoming_webhook_payload = ?serialized_req);

    let request_duration = Instant::now()
        .saturating_duration_since(start_instant)
        .as_millis();

    let request_id = RequestId::extract(req)
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to extract request id from request")?;
    let auth_type = auth::AuthenticationType::NoAuth;
    let status_code = 200;
    let api_event = ApiEventsType::NetworkTokenWebhook {
        payment_method_id: webhooks_response_tracker.get_payment_method_id(),
    };
    let response_value = serde_json::to_value(&webhooks_response_tracker)
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Could not convert webhook effect to string")?;
    let infra = state.infra_components.clone();
    let api_event = ApiEvent::new(
        state.tenant.tenant_id.clone(),
        Some(merchant_id),
        flow,
        &request_id,
        request_duration,
        status_code,
        serialized_req,
        Some(response_value),
        None,
        auth_type,
        None,
        api_event,
        req,
        req.method(),
        infra,
    );
    state.event_handler().log_event(&api_event);
    Ok(application_response)
}

#[allow(clippy::too_many_arguments)]
#[instrument(skip_all)]
async fn incoming_webhooks_core<W: types::OutgoingWebhookType>(
    state: SessionState,
    req_state: ReqState,
    req: &actix_web::HttpRequest,
    merchant_context: domain::MerchantContext,
    connector_name_or_mca_id: &str,
    body: actix_web::web::Bytes,
    is_relay_webhook: bool,
) -> errors::RouterResult<(
    services::ApplicationResponse<serde_json::Value>,
    WebhookResponseTracker,
    serde_json::Value,
)> {
    // Initial setup and metrics
    metrics::WEBHOOK_INCOMING_COUNT.add(
        1,
        router_env::metric_attributes!((
            MERCHANT_ID,
            merchant_context.get_merchant_account().get_id().clone()
        )),
    );

    let request_details = IncomingWebhookRequestDetails {
        method: req.method().clone(),
        uri: req.uri().clone(),
        headers: req.headers(),
        query_params: req.query_string().to_string(),
        body: &body,
    };

    // Fetch the merchant connector account to get the webhooks source secret
    let (merchant_connector_account, connector, connector_name) =
        fetch_optional_mca_and_connector(&state, &merchant_context, connector_name_or_mca_id)
            .await?;

    // Determine webhook processing path (UCS vs non-UCS) and handle event type extraction
    let webhook_processing_result =
        match if unified_connector_service::should_call_unified_connector_service_for_webhooks(
            &state,
            &merchant_context,
            &connector_name,
        )
        .await?
        {
            logger::info!(
                connector = connector_name,
                "Using Unified Connector Service for webhook processing",
            );
            process_ucs_webhook_transform(
                &state,
                &merchant_context,
                &connector_name,
                &body,
                &request_details,
                merchant_connector_account.as_ref(),
            )
            .await
        } else {
            // NON-UCS PATH: Need to decode body first
            let decoded_body = connector
                .decode_webhook_body(
                    &request_details,
                    merchant_context.get_merchant_account().get_id(),
                    merchant_connector_account
                        .and_then(|mca| mca.connector_webhook_details.clone()),
                    &connector_name,
                )
                .await
                .switch()
                .attach_printable("There was an error in incoming webhook body decoding")?;

            process_non_ucs_webhook(
                &state,
                &merchant_context,
                &connector,
                &connector_name,
                decoded_body.into(),
                &request_details,
            )
            .await
        } {
            Ok(result) => result,
            Err(error) => {
                let error_result = handle_incoming_webhook_error(
                    error,
                    &connector,
                    connector_name.as_str(),
                    &request_details,
                );
                match error_result {
                    Ok((response, webhook_tracker, serialized_request)) => {
                        return Ok((response, webhook_tracker, serialized_request));
                    }
                    Err(e) => return Err(e),
                }
            }
        };

    // if it is a setup webhook event, return ok status
    if webhook_processing_result.event_type == webhooks::IncomingWebhookEvent::SetupWebhook {
        return Ok((
            services::ApplicationResponse::StatusOk,
            WebhookResponseTracker::NoEffect,
            serde_json::Value::default(),
        ));
    }

    // Update request_details with the appropriate body (decoded for non-UCS, raw for UCS)
    let final_request_details = match &webhook_processing_result.decoded_body {
        Some(decoded_body) => IncomingWebhookRequestDetails {
            method: request_details.method.clone(),
            uri: request_details.uri.clone(),
            headers: request_details.headers,
            query_params: request_details.query_params.clone(),
            body: decoded_body,
        },
        None => request_details, // Use original request details for UCS
    };

    logger::info!(event_type=?webhook_processing_result.event_type);

    // Check if webhook should be processed further
    let is_webhook_event_supported = !matches!(
        webhook_processing_result.event_type,
        webhooks::IncomingWebhookEvent::EventNotSupported
    );
    let is_webhook_event_enabled = !utils::is_webhook_event_disabled(
        &*state.clone().store,
        connector_name.as_str(),
        merchant_context.get_merchant_account().get_id(),
        &webhook_processing_result.event_type,
    )
    .await;
    let flow_type: api::WebhookFlow = webhook_processing_result.event_type.into();
    let process_webhook_further = is_webhook_event_enabled
        && is_webhook_event_supported
        && !matches!(flow_type, api::WebhookFlow::ReturnResponse);
    logger::info!(process_webhook=?process_webhook_further);
    let mut event_object: Box<dyn masking::ErasedMaskSerialize> = Box::new(serde_json::Value::Null);

    let webhook_effect = match process_webhook_further {
        true => {
            let business_logic_result = process_webhook_business_logic(
                &state,
                req_state,
                &merchant_context,
                &connector,
                &connector_name,
                webhook_processing_result.event_type,
                webhook_processing_result.source_verified,
                &webhook_processing_result.transform_data,
                &final_request_details,
                is_relay_webhook,
            )
            .await;

            match business_logic_result {
                Ok(response) => {
                    // Extract event object for serialization
                    event_object = extract_webhook_event_object(
                        &webhook_processing_result.transform_data,
                        &connector,
                        &final_request_details,
                    )?;
                    response
                }
                Err(error) => {
                    let error_result = handle_incoming_webhook_error(
                        error,
                        &connector,
                        connector_name.as_str(),
                        &final_request_details,
                    );
                    match error_result {
                        Ok((_, webhook_tracker, _)) => webhook_tracker,
                        Err(e) => return Err(e),
                    }
                }
            }
        }
        false => {
            metrics::WEBHOOK_INCOMING_FILTERED_COUNT.add(
                1,
                router_env::metric_attributes!((
                    MERCHANT_ID,
                    merchant_context.get_merchant_account().get_id().clone()
                )),
            );
            WebhookResponseTracker::NoEffect
        }
    };

    // Generate response
    let response = connector
        .get_webhook_api_response(&final_request_details, None)
        .switch()
        .attach_printable("Could not get incoming webhook api response from connector")?;

    let serialized_request = event_object
        .masked_serialize()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Could not convert webhook effect to string")?;

    Ok((response, webhook_effect, serialized_request))
}

/// Process UCS webhook transformation using the high-level UCS abstraction
async fn process_ucs_webhook_transform(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    connector_name: &str,
    body: &actix_web::web::Bytes,
    request_details: &IncomingWebhookRequestDetails<'_>,
    merchant_connector_account: Option<&domain::MerchantConnectorAccount>,
) -> errors::RouterResult<WebhookProcessingResult> {
    // Use the new UCS abstraction which provides clean separation
    let (event_type, source_verified, transform_data) =
        unified_connector_service::call_unified_connector_service_for_webhook(
            state,
            merchant_context,
            connector_name,
            body,
            request_details,
            merchant_connector_account,
        )
        .await?;
    Ok(WebhookProcessingResult {
        event_type,
        source_verified,
        transform_data: Some(Box::new(transform_data)),
        decoded_body: None, // UCS path uses raw body
    })
}
/// Result type for webhook processing path determination
pub struct WebhookProcessingResult {
    event_type: webhooks::IncomingWebhookEvent,
    source_verified: bool,
    transform_data: Option<Box<unified_connector_service::WebhookTransformData>>,
    decoded_body: Option<actix_web::web::Bytes>,
}

/// Process non-UCS webhook using traditional connector processing
async fn process_non_ucs_webhook(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    connector: &ConnectorEnum,
    connector_name: &str,
    decoded_body: actix_web::web::Bytes,
    request_details: &IncomingWebhookRequestDetails<'_>,
) -> errors::RouterResult<WebhookProcessingResult> {
    // Create request_details with decoded body for connector processing
    let updated_request_details = IncomingWebhookRequestDetails {
        method: request_details.method.clone(),
        uri: request_details.uri.clone(),
        headers: request_details.headers,
        query_params: request_details.query_params.clone(),
        body: &decoded_body,
    };

    match connector
        .get_webhook_event_type(&updated_request_details)
        .allow_webhook_event_type_not_found(
            state
                .clone()
                .conf
                .webhooks
                .ignore_error
                .event_type
                .unwrap_or(true),
        )
        .switch()
        .attach_printable("Could not find event type in incoming webhook body")?
    {
        Some(event_type) => Ok(WebhookProcessingResult {
            event_type,
            source_verified: false,
            transform_data: None,
            decoded_body: Some(decoded_body),
        }),
        None => {
            metrics::WEBHOOK_EVENT_TYPE_IDENTIFICATION_FAILURE_COUNT.add(
                1,
                router_env::metric_attributes!(
                    (
                        MERCHANT_ID,
                        merchant_context.get_merchant_account().get_id().clone()
                    ),
                    ("connector", connector_name.to_string())
                ),
            );
            Err(errors::ApiErrorResponse::WebhookProcessingFailure)
                .attach_printable("Failed to identify event type in incoming webhook body")
        }
    }
}

/// Extract webhook event object based on transform data availability
fn extract_webhook_event_object(
    transform_data: &Option<Box<unified_connector_service::WebhookTransformData>>,
    connector: &ConnectorEnum,
    request_details: &IncomingWebhookRequestDetails<'_>,
) -> errors::RouterResult<Box<dyn masking::ErasedMaskSerialize>> {
    match transform_data {
        Some(transform_data) => match &transform_data.webhook_content {
            Some(webhook_content) => {
                let serialized_value = serde_json::to_value(webhook_content)
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to serialize UCS webhook content")?;
                Ok(Box::new(serialized_value))
            }
            None => connector
                .get_webhook_resource_object(request_details)
                .switch()
                .attach_printable("Could not find resource object in incoming webhook body"),
        },
        None => connector
            .get_webhook_resource_object(request_details)
            .switch()
            .attach_printable("Could not find resource object in incoming webhook body"),
    }
}

/// Process the main webhook business logic after event type determination
#[allow(clippy::too_many_arguments)]
async fn process_webhook_business_logic(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: &domain::MerchantContext,
    connector: &ConnectorEnum,
    connector_name: &str,
    event_type: webhooks::IncomingWebhookEvent,
    source_verified_via_ucs: bool,
    webhook_transform_data: &Option<Box<unified_connector_service::WebhookTransformData>>,
    request_details: &IncomingWebhookRequestDetails<'_>,
    is_relay_webhook: bool,
) -> errors::RouterResult<WebhookResponseTracker> {
    let object_ref_id = connector
        .get_webhook_object_reference_id(request_details)
        .switch()
        .attach_printable("Could not find object reference id in incoming webhook body")?;
    let connector_enum = api_models::enums::Connector::from_str(connector_name)
        .change_context(errors::ApiErrorResponse::InvalidDataValue {
            field_name: "connector",
        })
        .attach_printable_lazy(|| format!("unable to parse connector name {connector_name:?}"))?;
    let connectors_with_source_verification_call = &state.conf.webhook_source_verification_call;

    let merchant_connector_account = match Box::pin(helper_utils::get_mca_from_object_reference_id(
        state,
        object_ref_id.clone(),
        merchant_context,
        connector_name,
    ))
    .await
    {
        Ok(mca) => mca,
        Err(error) => {
            let result =
                handle_incoming_webhook_error(error, connector, connector_name, request_details);
            match result {
                Ok((_, webhook_tracker, _)) => return Ok(webhook_tracker),
                Err(e) => return Err(e),
            }
        }
    };

    let source_verified = if source_verified_via_ucs {
        // If UCS handled verification, use that result
        source_verified_via_ucs
    } else {
        // Fall back to traditional source verification
        if connectors_with_source_verification_call
            .connectors_with_webhook_source_verification_call
            .contains(&connector_enum)
        {
            verify_webhook_source_verification_call(
                connector.clone(),
                state,
                merchant_context,
                merchant_connector_account.clone(),
                connector_name,
                request_details,
            )
            .await
            .or_else(|error| match error.current_context() {
                errors::ConnectorError::WebhookSourceVerificationFailed => {
                    logger::error!(?error, "Source Verification Failed");
                    Ok(false)
                }
                _ => Err(error),
            })
            .switch()
            .attach_printable("There was an issue in incoming webhook source verification")?
        } else {
            connector
                .clone()
                .verify_webhook_source(
                    request_details,
                    merchant_context.get_merchant_account().get_id(),
                    merchant_connector_account.connector_webhook_details.clone(),
                    merchant_connector_account.connector_account_details.clone(),
                    connector_name,
                )
                .await
                .or_else(|error| match error.current_context() {
                    errors::ConnectorError::WebhookSourceVerificationFailed => {
                        logger::error!(?error, "Source Verification Failed");
                        Ok(false)
                    }
                    _ => Err(error),
                })
                .switch()
                .attach_printable("There was an issue in incoming webhook source verification")?
        }
    };

    if source_verified {
        metrics::WEBHOOK_SOURCE_VERIFIED_COUNT.add(
            1,
            router_env::metric_attributes!((
                MERCHANT_ID,
                merchant_context.get_merchant_account().get_id().clone()
            )),
        );
    } else if connector.is_webhook_source_verification_mandatory() {
        // if webhook consumption is mandatory for connector, fail webhook
        // so that merchant can retrigger it after updating merchant_secret
        return Err(errors::ApiErrorResponse::WebhookAuthenticationFailed.into());
    }

    logger::info!(source_verified=?source_verified);

    let event_object: Box<dyn masking::ErasedMaskSerialize> =
        if let Some(transform_data) = webhook_transform_data {
            // Use UCS transform data if available
            if let Some(webhook_content) = &transform_data.webhook_content {
                // Convert UCS webhook content to appropriate format
                Box::new(
                    serde_json::to_value(webhook_content)
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Failed to serialize UCS webhook content")?,
                )
            } else {
                // Fall back to connector extraction
                connector
                    .get_webhook_resource_object(request_details)
                    .switch()
                    .attach_printable("Could not find resource object in incoming webhook body")?
            }
        } else {
            // Use traditional connector extraction
            connector
                .get_webhook_resource_object(request_details)
                .switch()
                .attach_printable("Could not find resource object in incoming webhook body")?
        };

    let webhook_details = api::IncomingWebhookDetails {
        object_reference_id: object_ref_id.clone(),
        resource_object: serde_json::to_vec(&event_object)
            .change_context(errors::ParsingError::EncodeError("byte-vec"))
            .attach_printable("Unable to convert webhook payload to a value")
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable(
                "There was an issue when encoding the incoming webhook body to bytes",
            )?,
    };

    let profile_id = &merchant_connector_account.profile_id;
    let key_manager_state = &(state).into();

    let business_profile = state
        .store
        .find_business_profile_by_profile_id(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            profile_id,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::ProfileNotFound {
            id: profile_id.get_string_repr().to_owned(),
        })?;

    // If the incoming webhook is a relay webhook, then we need to trigger the relay webhook flow
    let result_response = if is_relay_webhook {
        let relay_webhook_response = Box::pin(relay_incoming_webhook_flow(
            state.clone(),
            merchant_context.clone(),
            business_profile,
            webhook_details,
            event_type,
            source_verified,
        ))
        .await
        .attach_printable("Incoming webhook flow for relay failed");

        // Using early return ensures unsupported webhooks are acknowledged to the connector
        if let Some(errors::ApiErrorResponse::NotSupported { .. }) = relay_webhook_response
            .as_ref()
            .err()
            .map(|a| a.current_context())
        {
            logger::error!(
                webhook_payload =? request_details.body,
                "Failed while identifying the event type",
            );

            let _response = connector
                    .get_webhook_api_response(request_details, None)
                    .switch()
                    .attach_printable(
                        "Failed while early return in case of not supported event type in relay webhooks",
                    )?;

            return Ok(WebhookResponseTracker::NoEffect);
        };

        relay_webhook_response
    } else {
        let flow_type: api::WebhookFlow = event_type.into();
        match flow_type {
            api::WebhookFlow::Payment => Box::pin(payments_incoming_webhook_flow(
                state.clone(),
                req_state,
                merchant_context.clone(),
                business_profile,
                webhook_details,
                source_verified,
                connector,
                request_details,
                event_type,
                webhook_transform_data,
            ))
            .await
            .attach_printable("Incoming webhook flow for payments failed"),

            api::WebhookFlow::Refund => Box::pin(refunds_incoming_webhook_flow(
                state.clone(),
                merchant_context.clone(),
                business_profile,
                webhook_details,
                connector_name,
                source_verified,
                event_type,
            ))
            .await
            .attach_printable("Incoming webhook flow for refunds failed"),

            api::WebhookFlow::Dispute => Box::pin(disputes_incoming_webhook_flow(
                state.clone(),
                merchant_context.clone(),
                business_profile,
                webhook_details,
                source_verified,
                connector,
                request_details,
                event_type,
            ))
            .await
            .attach_printable("Incoming webhook flow for disputes failed"),

            api::WebhookFlow::BankTransfer => Box::pin(bank_transfer_webhook_flow(
                state.clone(),
                req_state,
                merchant_context.clone(),
                business_profile,
                webhook_details,
                source_verified,
            ))
            .await
            .attach_printable("Incoming bank-transfer webhook flow failed"),

            api::WebhookFlow::ReturnResponse => Ok(WebhookResponseTracker::NoEffect),

            api::WebhookFlow::Mandate => Box::pin(mandates_incoming_webhook_flow(
                state.clone(),
                merchant_context.clone(),
                business_profile,
                webhook_details,
                source_verified,
                event_type,
            ))
            .await
            .attach_printable("Incoming webhook flow for mandates failed"),

            api::WebhookFlow::ExternalAuthentication => {
                Box::pin(external_authentication_incoming_webhook_flow(
                    state.clone(),
                    req_state,
                    merchant_context.clone(),
                    source_verified,
                    event_type,
                    request_details,
                    connector,
                    object_ref_id,
                    business_profile,
                    merchant_connector_account,
                ))
                .await
                .attach_printable("Incoming webhook flow for external authentication failed")
            }
            api::WebhookFlow::FraudCheck => Box::pin(frm_incoming_webhook_flow(
                state.clone(),
                req_state,
                merchant_context.clone(),
                source_verified,
                event_type,
                object_ref_id,
                business_profile,
            ))
            .await
            .attach_printable("Incoming webhook flow for fraud check failed"),

            #[cfg(feature = "payouts")]
            api::WebhookFlow::Payout => Box::pin(payouts_incoming_webhook_flow(
                state.clone(),
                merchant_context.clone(),
                business_profile,
                webhook_details,
                event_type,
                source_verified,
            ))
            .await
            .attach_printable("Incoming webhook flow for payouts failed"),

            _ => Err(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Unsupported Flow Type received in incoming webhooks"),
        }
    };

    match result_response {
        Ok(response) => Ok(response),
        Err(error) => {
            let result =
                handle_incoming_webhook_error(error, connector, connector_name, request_details);
            match result {
                Ok((_, webhook_tracker, _)) => Ok(webhook_tracker),
                Err(e) => Err(e),
            }
        }
    }
}

fn handle_incoming_webhook_error(
    error: error_stack::Report<errors::ApiErrorResponse>,
    connector: &ConnectorEnum,
    connector_name: &str,
    request_details: &IncomingWebhookRequestDetails<'_>,
) -> errors::RouterResult<(
    services::ApplicationResponse<serde_json::Value>,
    WebhookResponseTracker,
    serde_json::Value,
)> {
    logger::error!(?error, "Incoming webhook flow failed");

    // fetch the connector enum from the connector name
    let connector_enum = api_models::connector_enums::Connector::from_str(connector_name)
        .change_context(errors::ApiErrorResponse::InvalidDataValue {
            field_name: "connector",
        })
        .attach_printable_lazy(|| format!("unable to parse connector name {connector_name:?}"))?;

    // get the error response from the connector
    if connector_enum.should_acknowledge_webhook_for_resource_not_found_errors() {
        let response = connector
            .get_webhook_api_response(
                request_details,
                Some(IncomingWebhookFlowError::from(error.current_context())),
            )
            .switch()
            .attach_printable("Failed to get incoming webhook api response from connector")?;
        Ok((
            response,
            WebhookResponseTracker::NoEffect,
            serde_json::Value::Null,
        ))
    } else {
        Err(error)
    }
}

#[instrument(skip_all)]
#[cfg(feature = "v1")]
async fn network_token_incoming_webhooks_core<W: types::OutgoingWebhookType>(
    state: &SessionState,
    request_details: IncomingWebhookRequestDetails<'_>,
) -> errors::RouterResult<(
    services::ApplicationResponse<serde_json::Value>,
    WebhookResponseTracker,
    serde_json::Value,
    common_utils::id_type::MerchantId,
)> {
    let serialized_request =
        network_tokenization_incoming::get_network_token_resource_object(&request_details)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Network Token Requestor Webhook deserialization failed")?
            .masked_serialize()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Could not convert webhook effect to string")?;

    let network_tokenization_service = &state
        .conf
        .network_tokenization_service
        .as_ref()
        .ok_or(errors::NetworkTokenizationError::NetworkTokenizationServiceNotConfigured)
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Network Tokenization Service not configured")?;

    //source verification
    network_tokenization_incoming::Authorization::new(request_details.headers.get("Authorization"))
        .verify_webhook_source(network_tokenization_service.get_inner())
        .await?;

    let response: network_tokenization_incoming::NetworkTokenWebhookResponse = request_details
        .body
        .parse_struct("NetworkTokenWebhookResponse")
        .change_context(errors::ApiErrorResponse::WebhookUnprocessableEntity)?;

    let (merchant_id, payment_method_id, _customer_id) = response
        .fetch_merchant_id_payment_method_id_customer_id_from_callback_mapper(state)
        .await?;

    metrics::WEBHOOK_SOURCE_VERIFIED_COUNT.add(
        1,
        router_env::metric_attributes!((MERCHANT_ID, merchant_id.clone())),
    );

    let merchant_context =
        network_tokenization_incoming::fetch_merchant_account_for_network_token_webhooks(
            state,
            &merchant_id,
        )
        .await?;
    let payment_method =
        network_tokenization_incoming::fetch_payment_method_for_network_token_webhooks(
            state,
            merchant_context.get_merchant_account(),
            merchant_context.get_merchant_key_store(),
            &payment_method_id,
        )
        .await?;

    let response_data = response.get_response_data();

    let webhook_resp_tracker = response_data
        .update_payment_method(state, &payment_method, &merchant_context)
        .await?;

    Ok((
        services::ApplicationResponse::StatusOk,
        webhook_resp_tracker,
        serialized_request,
        merchant_id.clone(),
    ))
}

#[allow(clippy::too_many_arguments)]
#[instrument(skip_all)]
async fn payments_incoming_webhook_flow(
    state: SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    business_profile: domain::Profile,
    webhook_details: api::IncomingWebhookDetails,
    source_verified: bool,
    connector: &ConnectorEnum,
    request_details: &IncomingWebhookRequestDetails<'_>,
    event_type: webhooks::IncomingWebhookEvent,
    webhook_transform_data: &Option<Box<unified_connector_service::WebhookTransformData>>,
) -> CustomResult<WebhookResponseTracker, errors::ApiErrorResponse> {
    let consume_or_trigger_flow = if source_verified {
        // Determine the appropriate action based on UCS availability
        let resource_object = webhook_details.resource_object;

        match webhook_transform_data.as_ref() {
            Some(transform_data) => {
                // Serialize the transform data to pass to UCS handler
                let transform_data_bytes = serde_json::to_vec(transform_data.as_ref())
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to serialize UCS webhook transform data")?;
                payments::CallConnectorAction::UCSHandleResponse(transform_data_bytes)
            }
            None => payments::CallConnectorAction::HandleResponse(resource_object),
        }
    } else {
        payments::CallConnectorAction::Trigger
    };
    let payments_response = match webhook_details.object_reference_id {
        webhooks::ObjectReferenceId::PaymentId(ref id) => {
            let payment_id = get_payment_id(
                state.store.as_ref(),
                id,
                merchant_context.get_merchant_account().get_id(),
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await?;

            let lock_action = api_locking::LockAction::Hold {
                input: api_locking::LockingInput {
                    unique_locking_key: payment_id.get_string_repr().to_owned(),
                    api_identifier: lock_utils::ApiIdentifier::Payments,
                    override_lock_retries: None,
                },
            };

            lock_action
                .clone()
                .perform_locking_action(
                    &state,
                    merchant_context.get_merchant_account().get_id().to_owned(),
                )
                .await?;

            let response = Box::pin(payments::payments_core::<
                api::PSync,
                api::PaymentsResponse,
                _,
                _,
                _,
                payments::PaymentData<api::PSync>,
            >(
                state.clone(),
                req_state,
                merchant_context.clone(),
                None,
                payments::operations::PaymentStatus,
                api::PaymentsRetrieveRequest {
                    resource_id: id.clone(),
                    merchant_id: Some(merchant_context.get_merchant_account().get_id().clone()),
                    force_sync: true,
                    connector: None,
                    param: None,
                    merchant_connector_details: None,
                    client_secret: None,
                    expand_attempts: None,
                    expand_captures: None,
                    all_keys_required: None,
                },
                services::AuthFlow::Merchant,
                consume_or_trigger_flow.clone(),
                None,
                HeaderPayload::default(),
            ))
            .await;
            // When mandate details are present in successful webhooks, and consuming webhooks are skipped during payment sync if the payment status is already updated to charged, this function is used to update the connector mandate details.
            if should_update_connector_mandate_details(source_verified, event_type) {
                update_connector_mandate_details(
                    &state,
                    &merchant_context,
                    webhook_details.object_reference_id.clone(),
                    connector,
                    request_details,
                )
                .await?
            };
            lock_action
                .free_lock_action(
                    &state,
                    merchant_context.get_merchant_account().get_id().to_owned(),
                )
                .await?;

            match response {
                Ok(value) => value,
                Err(err)
                    if matches!(
                        err.current_context(),
                        &errors::ApiErrorResponse::PaymentNotFound
                    ) && state
                        .conf
                        .webhooks
                        .ignore_error
                        .payment_not_found
                        .unwrap_or(true) =>
                {
                    metrics::WEBHOOK_PAYMENT_NOT_FOUND.add(
                        1,
                        router_env::metric_attributes!((
                            "merchant_id",
                            merchant_context.get_merchant_account().get_id().clone()
                        )),
                    );
                    return Ok(WebhookResponseTracker::NoEffect);
                }
                error @ Err(_) => error?,
            }
        }
        _ => Err(errors::ApiErrorResponse::WebhookProcessingFailure).attach_printable(
            "Did not get payment id as object reference id in webhook payments flow",
        )?,
    };

    match payments_response {
        services::ApplicationResponse::JsonWithHeaders((payments_response, _)) => {
            let payment_id = payments_response.payment_id.clone();

            let status = payments_response.status;

            let event_type: Option<enums::EventType> = payments_response.status.into();

            // If event is NOT an UnsupportedEvent, trigger Outgoing Webhook
            if let Some(outgoing_event_type) = event_type {
                let primary_object_created_at = payments_response.created;
                Box::pin(super::create_event_and_trigger_outgoing_webhook(
                    state,
                    merchant_context,
                    business_profile,
                    outgoing_event_type,
                    enums::EventClass::Payments,
                    payment_id.get_string_repr().to_owned(),
                    enums::EventObjectType::PaymentDetails,
                    api::OutgoingWebhookContent::PaymentDetails(Box::new(payments_response)),
                    primary_object_created_at,
                ))
                .await?;
            };

            let response = WebhookResponseTracker::Payment { payment_id, status };

            Ok(response)
        }

        _ => Err(errors::ApiErrorResponse::WebhookProcessingFailure)
            .attach_printable("received non-json response from payments core")?,
    }
}

#[cfg(feature = "payouts")]
#[instrument(skip_all)]
async fn payouts_incoming_webhook_flow(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    business_profile: domain::Profile,
    webhook_details: api::IncomingWebhookDetails,
    event_type: webhooks::IncomingWebhookEvent,
    source_verified: bool,


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

pub fn server(state: AppState) -> Scope


// Function: create_recipient
// File: crates/router/src/core/payouts.rs
// Module: router

pub fn create_recipient(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    connector_data: &api::ConnectorData,
    payout_data: &mut PayoutData,
) -> RouterResult<()>


// Trait: ConnectorEventLogAnalytics
// File: crates/analytics/src/connector_events/events.rs
// Module: analytics

pub trait ConnectorEventLogAnalytics: LoadRow<ConnectorEventsResult>


// Function: save_in_locker_internal
// File: crates/router/src/core/payments/tokenization.rs
// Module: router

pub fn save_in_locker_internal(
    _state: &SessionState,
    _merchant_context: &domain::MerchantContext,
    _payment_method_request: api::PaymentMethodCreate,
) -> RouterResult<(
    api_models::payment_methods::PaymentMethodResponse,
    Option<payment_methods::transformers::DataDuplicationCheck>,
)>


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

pub struct ThreeDsData


// Implementation: impl ConnectorValidation for for Worldpay
// File: crates/hyperswitch_connectors/src/connectors/worldpay.rs
// Module: hyperswitch_connectors
// Methods: 2 total (0 public)

impl ConnectorValidation for for Worldpay


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

// Public submodules:
pub mod transformers;


// File: crates/router/src/configs/defaults/payout_required_fields.rs
// Module: router

use std::collections::HashMap;

use api_models::{
    enums::{
        CountryAlpha2, FieldType,
        PaymentMethod::{BankTransfer, Card, Wallet},
        PaymentMethodType, PayoutConnectors,
    },
    payment_methods::RequiredFieldInfo,
};

use crate::settings::{
    ConnectorFields, PaymentMethodType as PaymentMethodTypeInfo, PayoutRequiredFields,
    RequiredFieldFinal,
};

#[cfg(feature = "v1")]
impl Default for PayoutRequiredFields {
    fn default() -> Self {
        Self(HashMap::from([
            (
                Card,
                PaymentMethodTypeInfo(HashMap::from([
                    // Adyen
                    get_connector_payment_method_type_fields(
                        PayoutConnectors::Adyenplatform,
                        PaymentMethodType::Debit,
                    ),
                    get_connector_payment_method_type_fields(
                        PayoutConnectors::Adyenplatform,
                        PaymentMethodType::Credit,
                    ),
                ])),
            ),
            (
                BankTransfer,
                PaymentMethodTypeInfo(HashMap::from([
                    // Adyen
                    get_connector_payment_method_type_fields(
                        PayoutConnectors::Adyenplatform,
                        PaymentMethodType::SepaBankTransfer,
                    ),
                    // Ebanx
                    get_connector_payment_method_type_fields(
                        PayoutConnectors::Ebanx,
                        PaymentMethodType::Pix,
                    ),
                    // Wise
                    get_connector_payment_method_type_fields(
                        PayoutConnectors::Wise,
                        PaymentMethodType::Bacs,
                    ),
                ])),
            ),
            (
                Wallet,
                PaymentMethodTypeInfo(HashMap::from([
                    // Adyen
                    get_connector_payment_method_type_fields(
                        PayoutConnectors::Adyenplatform,
                        PaymentMethodType::Paypal,
                    ),
                ])),
            ),
        ]))
    }
}

fn get_billing_details_for_payment_method(
    connector: PayoutConnectors,
    payment_method_type: PaymentMethodType,
) -> HashMap<String, RequiredFieldInfo> {
    match connector {
        PayoutConnectors::Adyenplatform => {
            let mut fields = HashMap::from([
                (
                    "billing.address.line1".to_string(),
                    RequiredFieldInfo {
                        required_field: "billing.address.line1".to_string(),
                        display_name: "billing_address_line1".to_string(),
                        field_type: FieldType::Text,
                        value: None,
                    },
                ),
                (
                    "billing.address.line2".to_string(),
                    RequiredFieldInfo {
                        required_field: "billing.address.line2".to_string(),
                        display_name: "billing_address_line2".to_string(),
                        field_type: FieldType::Text,
                        value: None,
                    },
                ),
                (
                    "billing.address.city".to_string(),
                    RequiredFieldInfo {
                        required_field: "billing.address.city".to_string(),
                        display_name: "billing_address_city".to_string(),
                        field_type: FieldType::Text,
                        value: None,
                    },
                ),
                (
                    "billing.address.country".to_string(),
                    RequiredFieldInfo {
                        required_field: "billing.address.country".to_string(),
                        display_name: "billing_address_country".to_string(),
                        field_type: FieldType::UserAddressCountry {
                            options: get_countries_for_connector(connector)
                                .iter()
                                .map(|country| country.to_string())
                                .collect::<Vec<String>>(),
                        },
                        value: None,
                    },
                ),
            ]);

            // Add first_name for bank payouts only
            if payment_method_type == PaymentMethodType::SepaBankTransfer {
                fields.insert(
                    "billing.address.first_name".to_string(),
                    RequiredFieldInfo {
                        required_field: "billing.address.first_name".to_string(),
                        display_name: "billing_address_first_name".to_string(),
                        field_type: FieldType::Text,
                        value: None,
                    },
                );
            }

            fields
        }
        _ => get_billing_details(connector),
    }
}

#[cfg(feature = "v1")]
fn get_connector_payment_method_type_fields(
    connector: PayoutConnectors,
    payment_method_type: PaymentMethodType,
) -> (PaymentMethodType, ConnectorFields) {
    let mut common_fields = get_billing_details_for_payment_method(connector, payment_method_type);
    match payment_method_type {
        // Card
        PaymentMethodType::Debit => {
            common_fields.extend(get_card_fields());
            (
                payment_method_type,
                ConnectorFields {
                    fields: HashMap::from([(
                        connector.into(),
                        RequiredFieldFinal {
                            mandate: HashMap::new(),
                            non_mandate: HashMap::new(),
                            common: common_fields,
                        },
                    )]),
                },
            )
        }
        PaymentMethodType::Credit => {
            common_fields.extend(get_card_fields());
            (
                payment_method_type,
                ConnectorFields {
                    fields: HashMap::from([(
                        connector.into(),
                        RequiredFieldFinal {
                            mandate: HashMap::new(),
                            non_mandate: HashMap::new(),
                            common: common_fields,
                        },
                    )]),
                },
            )
        }

        // Banks
        PaymentMethodType::Bacs => {
            common_fields.extend(get_bacs_fields());
            (
                payment_method_type,
                ConnectorFields {
                    fields: HashMap::from([(
                        connector.into(),
                        RequiredFieldFinal {
                            mandate: HashMap::new(),
                            non_mandate: HashMap::new(),
                            common: common_fields,
                        },
                    )]),
                },
            )
        }
        PaymentMethodType::Pix => {
            common_fields.extend(get_pix_bank_transfer_fields());
            (
                payment_method_type,
                ConnectorFields {
                    fields: HashMap::from([(
                        connector.into(),
                        RequiredFieldFinal {
                            mandate: HashMap::new(),
                            non_mandate: HashMap::new(),
                            common: common_fields,
                        },
                    )]),
                },
            )
        }
        PaymentMethodType::SepaBankTransfer => {
            common_fields.extend(get_sepa_fields());
            (
                payment_method_type,
                ConnectorFields {
                    fields: HashMap::from([(
                        connector.into(),
                        RequiredFieldFinal {
                            mandate: HashMap::new(),
                            non_mandate: HashMap::new(),
                            common: common_fields,
                        },
                    )]),
                },
            )
        }

        // Wallets
        PaymentMethodType::Paypal => {
            common_fields.extend(get_paypal_fields());
            (
                payment_method_type,
                ConnectorFields {
                    fields: HashMap::from([(
                        connector.into(),
                        RequiredFieldFinal {
                            mandate: HashMap::new(),
                            non_mandate: HashMap::new(),
                            common: common_fields,
                        },
                    )]),
                },
            )
        }

        _ => (
            payment_method_type,
            ConnectorFields {
                fields: HashMap::new(),
            },
        ),
    }
}

fn get_card_fields() -> HashMap<String, RequiredFieldInfo> {
    HashMap::from([
        (
            "payout_method_data.card.card_number".to_string(),
            RequiredFieldInfo {
                required_field: "payout_method_data.card.card_number".to_string(),
                display_name: "card_number".to_string(),
                field_type: FieldType::UserCardNumber,
                value: None,
            },
        ),
        (
            "payout_method_data.card.expiry_month".to_string(),
            RequiredFieldInfo {
                required_field: "payout_method_data.card.expiry_month".to_string(),
                display_name: "exp_month".to_string(),
                field_type: FieldType::UserCardExpiryMonth,
                value: None,
            },
        ),
        (
            "payout_method_data.card.expiry_year".to_string(),
            RequiredFieldInfo {
                required_field: "payout_method_data.card.expiry_year".to_string(),
                display_name: "exp_year".to_string(),
                field_type: FieldType::UserCardExpiryYear,
                value: None,
            },
        ),
        (
            "payout_method_data.card.card_holder_name".to_string(),
            RequiredFieldInfo {
                required_field: "payout_method_data.card.card_holder_name".to_string(),
                display_name: "card_holder_name".to_string(),
                field_type: FieldType::UserFullName,
                value: None,
            },
        ),
    ])
}

fn get_bacs_fields() -> HashMap<String, RequiredFieldInfo> {
    HashMap::from([
        (
            "payout_method_data.bank.bank_sort_code".to_string(),
            RequiredFieldInfo {
                required_field: "payout_method_data.bank.bank_sort_code".to_string(),
                display_name: "bank_sort_code".to_string(),
                field_type: FieldType::Text,
                value: None,
            },
        ),
        (
            "payout_method_data.bank.bank_account_number".to_string(),
            RequiredFieldInfo {
                required_field: "payout_method_data.bank.bank_account_number".to_string(),
                display_name: "bank_account_number".to_string(),
                field_type: FieldType::Text,
                value: None,
            },
        ),
    ])
}

fn get_pix_bank_transfer_fields() -> HashMap<String, RequiredFieldInfo> {
    HashMap::from([
        (
            "payout_method_data.bank.bank_account_number".to_string(),
            RequiredFieldInfo {
                required_field: "payout_method_data.bank.bank_account_number".to_string(),
                display_name: "bank_account_number".to_string(),
                field_type: FieldType::Text,
                value: None,
            },
        ),
        (
            "payout_method_data.bank.pix_key".to_string(),
            RequiredFieldInfo {
                required_field: "payout_method_data.bank.pix_key".to_string(),
                display_name: "pix_key".to_string(),
                field_type: FieldType::Text,
                value: None,
            },
        ),
    ])
}

fn get_sepa_fields() -> HashMap<String, RequiredFieldInfo> {
    HashMap::from([
        (
            "payout_method_data.bank.iban".to_string(),
            RequiredFieldInfo {
                required_field: "payout_method_data.bank.iban".to_string(),
                display_name: "iban".to_string(),
                field_type: FieldType::Text,
                value: None,
            },
        ),
        (
            "payout_method_data.bank.bic".to_string(),
            RequiredFieldInfo {
                required_field: "payout_method_data.bank.bic".to_string(),
                display_name: "bic".to_string(),
                field_type: FieldType::Text,
                value: None,
            },
        ),
    ])
}

fn get_paypal_fields() -> HashMap<String, RequiredFieldInfo> {
    HashMap::from([(
        "payout_method_data.wallet.telephone_number".to_string(),
        RequiredFieldInfo {
            required_field: "payout_method_data.wallet.telephone_number".to_string(),
            display_name: "telephone_number".to_string(),
            field_type: FieldType::Text,
            value: None,
        },
    )])
}

fn get_countries_for_connector(connector: PayoutConnectors) -> Vec<CountryAlpha2> {
    match connector {
        PayoutConnectors::Adyenplatform => vec![
            CountryAlpha2::ES,
            CountryAlpha2::SK,
            CountryAlpha2::AT,
            CountryAlpha2::NL,
            CountryAlpha2::DE,
            CountryAlpha2::BE,
            CountryAlpha2::FR,
            CountryAlpha2::FI,
            CountryAlpha2::PT,
            CountryAlpha2::IE,
            CountryAlpha2::EE,
            CountryAlpha2::LT,
            CountryAlpha2::LV,
            CountryAlpha2::IT,
            CountryAlpha2::CZ,
            CountryAlpha2::DE,
            CountryAlpha2::HU,
            CountryAlpha2::NO,
            CountryAlpha2::PL,
            CountryAlpha2::SE,
            CountryAlpha2::GB,
            CountryAlpha2::CH,
        ],
        PayoutConnectors::Stripe => vec![CountryAlpha2::US],
        _ => vec![],
    }
}

fn get_billing_details(connector: PayoutConnectors) -> HashMap<String, RequiredFieldInfo> {
    match connector {
        PayoutConnectors::Adyen => HashMap::from([
            (
                "billing.address.line1".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.line1".to_string(),
                    display_name: "billing_address_line1".to_string(),
                    field_type: FieldType::Text,
                    value: None,
                },
            ),
            (
                "billing.address.line2".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.line2".to_string(),
                    display_name: "billing_address_line2".to_string(),
                    field_type: FieldType::Text,
                    value: None,
                },
            ),
            (
                "billing.address.city".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.city".to_string(),
                    display_name: "billing_address_city".to_string(),
                    field_type: FieldType::Text,
                    value: None,
                },
            ),
            (
                "billing.address.zip".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.zip".to_string(),
                    display_name: "billing_address_zip".to_string(),
                    field_type: FieldType::Text,
                    value: None,
                },
            ),
            (
                "billing.address.country".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.country".to_string(),
                    display_name: "billing_address_country".to_string(),
                    field_type: FieldType::UserAddressCountry {
                        options: get_countries_for_connector(connector)
                            .iter()
                            .map(|country| country.to_string())
                            .collect::<Vec<String>>(),
                    },
                    value: None,
                },
            ),
            (
                "billing.address.first_name".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.first_name".to_string(),
                    display_name: "billing_address_first_name".to_string(),
                    field_type: FieldType::Text,
                    value: None,
                },
            ),
            (
                "billing.address.last_name".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.last_name".to_string(),
                    display_name: "billing_address_last_name".to_string(),
                    field_type: FieldType::Text,
                    value: None,
                },
            ),
        ]),
        PayoutConnectors::Wise => HashMap::from([
            (
                "billing.address.line1".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.line1".to_string(),
                    display_name: "billing_address_line1".to_string(),
                    field_type: FieldType::Text,
                    value: None,
                },
            ),
            (
                "billing.address.city".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.city".to_string(),
                    display_name: "billing_address_city".to_string(),
                    field_type: FieldType::Text,
                    value: None,
                },
            ),
            (
                "billing.address.state".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.state".to_string(),
                    display_name: "billing_address_state".to_string(),
                    field_type: FieldType::Text,
                    value: None,
                },
            ),
            (
                "billing.address.zip".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.zip".to_string(),
                    display_name: "billing_address_zip".to_string(),
                    field_type: FieldType::Text,
                    value: None,
                },
            ),
            (
                "billing.address.country".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.country".to_string(),
                    display_name: "billing_address_country".to_string(),
                    field_type: FieldType::UserAddressCountry {
                        options: get_countries_for_connector(connector)
                            .iter()
                            .map(|country| country.to_string())
                            .collect::<Vec<String>>(),
                    },
                    value: None,
                },
            ),
            (
                "billing.address.first_name".to_string(),
                RequiredFieldInfo {
                    required_field: "billing.address.first_name".to_string(),
                    display_name: "billing_address_first_name".to_string(),
                    field_type: FieldType::Text,
                    value: None,
                },
            ),
        ]),
        _ => HashMap::from([]),
    }
}


// Function: totp_verify
// File: crates/router/src/routes/user.rs
// Module: router

pub fn totp_verify(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<user_api::VerifyTotpRequest>,
) -> HttpResponse


// Struct: PaypalSourceVerificationRequest
// File: crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaypalSourceVerificationRequest


// Function: set_distinct
// File: crates/analytics/src/query.rs
// Module: analytics

pub fn set_distinct(&mut self)


// Function: retrieve_forex
// File: crates/router/src/core/currency.rs
// Module: router

pub fn retrieve_forex(
    state: SessionState,
) -> CustomResult<ApplicationResponse<currency::FxExchangeRatesCacheEntry>, ApiErrorResponse>


// File: crates/diesel_models/src/merchant_account.rs
// Module: diesel_models
// Public functions: 4
// Public structs: 8

use common_utils::{encryption::Encryption, pii};
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};

use crate::enums as storage_enums;
#[cfg(feature = "v1")]
use crate::schema::merchant_account;
#[cfg(feature = "v2")]
use crate::schema_v2::merchant_account;

/// Note: The order of fields in the struct is important.
/// This should be in the same order as the fields in the schema.rs file, otherwise the code will not compile
/// If two adjacent columns have the same type, then the compiler will not throw any error, but the fields read / written will be interchanged
#[cfg(feature = "v1")]
#[derive(
    Clone,
    Debug,
    serde::Deserialize,
    Identifiable,
    serde::Serialize,
    Queryable,
    Selectable,
    router_derive::DebugAsDisplay,
)]
#[diesel(table_name = merchant_account, primary_key(merchant_id), check_for_backend(diesel::pg::Pg))]
pub struct MerchantAccount {
    merchant_id: common_utils::id_type::MerchantId,
    pub return_url: Option<String>,
    pub enable_payment_response_hash: bool,
    pub payment_response_hash_key: Option<String>,
    pub redirect_to_merchant_with_http_post: bool,
    pub merchant_name: Option<Encryption>,
    pub merchant_details: Option<Encryption>,
    pub webhook_details: Option<crate::business_profile::WebhookDetails>,
    pub sub_merchants_enabled: Option<bool>,
    pub parent_merchant_id: Option<common_utils::id_type::MerchantId>,
    pub publishable_key: Option<String>,
    pub storage_scheme: storage_enums::MerchantStorageScheme,
    pub locker_id: Option<String>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub routing_algorithm: Option<serde_json::Value>,
    pub primary_business_details: serde_json::Value,
    pub intent_fulfillment_time: Option<i64>,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    pub frm_routing_algorithm: Option<serde_json::Value>,
    pub payout_routing_algorithm: Option<serde_json::Value>,
    pub organization_id: common_utils::id_type::OrganizationId,
    pub is_recon_enabled: bool,
    pub default_profile: Option<common_utils::id_type::ProfileId>,
    pub recon_status: storage_enums::ReconStatus,
    pub payment_link_config: Option<serde_json::Value>,
    pub pm_collect_link_config: Option<serde_json::Value>,
    pub version: common_enums::ApiVersion,
    pub is_platform_account: bool,
    pub id: Option<common_utils::id_type::MerchantId>,
    pub product_type: Option<common_enums::MerchantProductType>,
    pub merchant_account_type: Option<common_enums::MerchantAccountType>,
}

#[cfg(feature = "v1")]
pub struct MerchantAccountSetter {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub return_url: Option<String>,
    pub enable_payment_response_hash: bool,
    pub payment_response_hash_key: Option<String>,
    pub redirect_to_merchant_with_http_post: bool,
    pub merchant_name: Option<Encryption>,
    pub merchant_details: Option<Encryption>,
    pub webhook_details: Option<crate::business_profile::WebhookDetails>,
    pub sub_merchants_enabled: Option<bool>,
    pub parent_merchant_id: Option<common_utils::id_type::MerchantId>,
    pub publishable_key: Option<String>,
    pub storage_scheme: storage_enums::MerchantStorageScheme,
    pub locker_id: Option<String>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub routing_algorithm: Option<serde_json::Value>,
    pub primary_business_details: serde_json::Value,
    pub intent_fulfillment_time: Option<i64>,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    pub frm_routing_algorithm: Option<serde_json::Value>,
    pub payout_routing_algorithm: Option<serde_json::Value>,
    pub organization_id: common_utils::id_type::OrganizationId,
    pub is_recon_enabled: bool,
    pub default_profile: Option<common_utils::id_type::ProfileId>,
    pub recon_status: storage_enums::ReconStatus,
    pub payment_link_config: Option<serde_json::Value>,
    pub pm_collect_link_config: Option<serde_json::Value>,
    pub version: common_enums::ApiVersion,
    pub is_platform_account: bool,
    pub product_type: Option<common_enums::MerchantProductType>,
    pub merchant_account_type: common_enums::MerchantAccountType,
}

#[cfg(feature = "v1")]
impl From<MerchantAccountSetter> for MerchantAccount {
    fn from(item: MerchantAccountSetter) -> Self {
        Self {
            id: Some(item.merchant_id.clone()),
            merchant_id: item.merchant_id,
            return_url: item.return_url,
            enable_payment_response_hash: item.enable_payment_response_hash,
            payment_response_hash_key: item.payment_response_hash_key,
            redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
            merchant_name: item.merchant_name,
            merchant_details: item.merchant_details,
            webhook_details: item.webhook_details,
            sub_merchants_enabled: item.sub_merchants_enabled,
            parent_merchant_id: item.parent_merchant_id,
            publishable_key: item.publishable_key,
            storage_scheme: item.storage_scheme,
            locker_id: item.locker_id,
            metadata: item.metadata,
            routing_algorithm: item.routing_algorithm,
            primary_business_details: item.primary_business_details,
            intent_fulfillment_time: item.intent_fulfillment_time,
            created_at: item.created_at,
            modified_at: item.modified_at,
            frm_routing_algorithm: item.frm_routing_algorithm,
            payout_routing_algorithm: item.payout_routing_algorithm,
            organization_id: item.organization_id,
            is_recon_enabled: item.is_recon_enabled,
            default_profile: item.default_profile,
            recon_status: item.recon_status,
            payment_link_config: item.payment_link_config,
            pm_collect_link_config: item.pm_collect_link_config,
            version: item.version,
            is_platform_account: item.is_platform_account,
            product_type: item.product_type,
            merchant_account_type: Some(item.merchant_account_type),
        }
    }
}

/// Note: The order of fields in the struct is important.
/// This should be in the same order as the fields in the schema.rs file, otherwise the code will not compile
/// If two adjacent columns have the same type, then the compiler will not throw any error, but the fields read / written will be interchanged
#[cfg(feature = "v2")]
#[derive(
    Clone,
    Debug,
    serde::Deserialize,
    Identifiable,
    serde::Serialize,
    Queryable,
    router_derive::DebugAsDisplay,
    Selectable,
)]
#[diesel(table_name = merchant_account, primary_key(id), check_for_backend(diesel::pg::Pg))]
pub struct MerchantAccount {
    pub merchant_name: Option<Encryption>,
    pub merchant_details: Option<Encryption>,
    pub publishable_key: Option<String>,
    pub storage_scheme: storage_enums::MerchantStorageScheme,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    pub organization_id: common_utils::id_type::OrganizationId,
    pub recon_status: storage_enums::ReconStatus,
    pub version: common_enums::ApiVersion,
    pub is_platform_account: bool,
    pub id: common_utils::id_type::MerchantId,
    pub product_type: Option<common_enums::MerchantProductType>,
    pub merchant_account_type: Option<common_enums::MerchantAccountType>,
}

#[cfg(feature = "v2")]
impl From<MerchantAccountSetter> for MerchantAccount {
    fn from(item: MerchantAccountSetter) -> Self {
        Self {
            id: item.id,
            merchant_name: item.merchant_name,
            merchant_details: item.merchant_details,
            publishable_key: item.publishable_key,
            storage_scheme: item.storage_scheme,
            metadata: item.metadata,
            created_at: item.created_at,
            modified_at: item.modified_at,
            organization_id: item.organization_id,
            recon_status: item.recon_status,
            version: item.version,
            is_platform_account: item.is_platform_account,
            product_type: item.product_type,
            merchant_account_type: Some(item.merchant_account_type),
        }
    }
}

#[cfg(feature = "v2")]
pub struct MerchantAccountSetter {
    pub id: common_utils::id_type::MerchantId,
    pub merchant_name: Option<Encryption>,
    pub merchant_details: Option<Encryption>,
    pub publishable_key: Option<String>,
    pub storage_scheme: storage_enums::MerchantStorageScheme,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    pub organization_id: common_utils::id_type::OrganizationId,
    pub recon_status: storage_enums::ReconStatus,
    pub version: common_enums::ApiVersion,
    pub is_platform_account: bool,
    pub product_type: Option<common_enums::MerchantProductType>,
    pub merchant_account_type: common_enums::MerchantAccountType,
}

impl MerchantAccount {
    #[cfg(feature = "v1")]
    /// Get the unique identifier of MerchantAccount
    pub fn get_id(&self) -> &common_utils::id_type::MerchantId {
        &self.merchant_id
    }

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

#[cfg(feature = "v1")]
#[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay)]
#[diesel(table_name = merchant_account)]
pub struct MerchantAccountNew {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub merchant_name: Option<Encryption>,
    pub merchant_details: Option<Encryption>,
    pub return_url: Option<String>,
    pub webhook_details: Option<crate::business_profile::WebhookDetails>,
    pub sub_merchants_enabled: Option<bool>,
    pub parent_merchant_id: Option<common_utils::id_type::MerchantId>,
    pub enable_payment_response_hash: Option<bool>,
    pub payment_response_hash_key: Option<String>,
    pub redirect_to_merchant_with_http_post: Option<bool>,
    pub publishable_key: Option<String>,
    pub locker_id: Option<String>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub routing_algorithm: Option<serde_json::Value>,
    pub primary_business_details: serde_json::Value,
    pub intent_fulfillment_time: Option<i64>,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    pub frm_routing_algorithm: Option<serde_json::Value>,
    pub payout_routing_algorithm: Option<serde_json::Value>,
    pub organization_id: common_utils::id_type::OrganizationId,
    pub is_recon_enabled: bool,
    pub default_profile: Option<common_utils::id_type::ProfileId>,
    pub recon_status: storage_enums::ReconStatus,
    pub payment_link_config: Option<serde_json::Value>,
    pub pm_collect_link_config: Option<serde_json::Value>,
    pub version: common_enums::ApiVersion,
    pub is_platform_account: bool,
    pub id: Option<common_utils::id_type::MerchantId>,
    pub product_type: Option<common_enums::MerchantProductType>,
    pub merchant_account_type: common_enums::MerchantAccountType,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay)]
#[diesel(table_name = merchant_account)]
pub struct MerchantAccountNew {
    pub merchant_name: Option<Encryption>,
    pub merchant_details: Option<Encryption>,
    pub publishable_key: Option<String>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    pub organization_id: common_utils::id_type::OrganizationId,
    pub recon_status: storage_enums::ReconStatus,
    pub id: common_utils::id_type::MerchantId,
    pub version: common_enums::ApiVersion,
    pub is_platform_account: bool,
    pub product_type: Option<common_enums::MerchantProductType>,
    pub merchant_account_type: common_enums::MerchantAccountType,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)]
#[diesel(table_name = merchant_account)]
pub struct MerchantAccountUpdateInternal {
    pub merchant_name: Option<Encryption>,
    pub merchant_details: Option<Encryption>,
    pub publishable_key: Option<String>,
    pub storage_scheme: Option<storage_enums::MerchantStorageScheme>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub modified_at: time::PrimitiveDateTime,
    pub organization_id: Option<common_utils::id_type::OrganizationId>,
    pub recon_status: Option<storage_enums::ReconStatus>,
    pub is_platform_account: Option<bool>,
    pub product_type: Option<common_enums::MerchantProductType>,
}

#[cfg(feature = "v2")]
impl MerchantAccountUpdateInternal {
    pub fn apply_changeset(self, source: MerchantAccount) -> MerchantAccount {
        let Self {
            merchant_name,
            merchant_details,
            publishable_key,
            storage_scheme,
            metadata,
            modified_at,
            organization_id,
            recon_status,
            is_platform_account,
            product_type,
        } = self;

        MerchantAccount {
            merchant_name: merchant_name.or(source.merchant_name),
            merchant_details: merchant_details.or(source.merchant_details),
            publishable_key: publishable_key.or(source.publishable_key),
            storage_scheme: storage_scheme.unwrap_or(source.storage_scheme),
            metadata: metadata.or(source.metadata),
            created_at: source.created_at,
            modified_at,
            organization_id: organization_id.unwrap_or(source.organization_id),
            recon_status: recon_status.unwrap_or(source.recon_status),
            version: source.version,
            id: source.id,
            is_platform_account: is_platform_account.unwrap_or(source.is_platform_account),
            product_type: product_type.or(source.product_type),
            merchant_account_type: source.merchant_account_type,
        }
    }
}

#[cfg(feature = "v1")]
#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)]
#[diesel(table_name = merchant_account)]
pub struct MerchantAccountUpdateInternal {
    pub merchant_name: Option<Encryption>,
    pub merchant_details: Option<Encryption>,
    pub return_url: Option<String>,
    pub webhook_details: Option<crate::business_profile::WebhookDetails>,
    pub sub_merchants_enabled: Option<bool>,
    pub parent_merchant_id: Option<common_utils::id_type::MerchantId>,
    pub enable_payment_response_hash: Option<bool>,
    pub payment_response_hash_key: Option<String>,
    pub redirect_to_merchant_with_http_post: Option<bool>,
    pub publishable_key: Option<String>,
    pub storage_scheme: Option<storage_enums::MerchantStorageScheme>,
    pub locker_id: Option<String>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub routing_algorithm: Option<serde_json::Value>,
    pub primary_business_details: Option<serde_json::Value>,
    pub modified_at: time::PrimitiveDateTime,
    pub intent_fulfillment_time: Option<i64>,
    pub frm_routing_algorithm: Option<serde_json::Value>,
    pub payout_routing_algorithm: Option<serde_json::Value>,
    pub organization_id: Option<common_utils::id_type::OrganizationId>,
    pub is_recon_enabled: Option<bool>,
    pub default_profile: Option<Option<common_utils::id_type::ProfileId>>,
    pub recon_status: Option<storage_enums::ReconStatus>,
    pub payment_link_config: Option<serde_json::Value>,
    pub pm_collect_link_config: Option<serde_json::Value>,
    pub is_platform_account: Option<bool>,
    pub product_type: Option<common_enums::MerchantProductType>,
}

#[cfg(feature = "v1")]
impl MerchantAccountUpdateInternal {
    pub fn apply_changeset(self, source: MerchantAccount) -> MerchantAccount {
        let Self {
            merchant_name,
            merchant_details,
            return_url,
            webhook_details,
            sub_merchants_enabled,
            parent_merchant_id,
            enable_payment_response_hash,
            payment_response_hash_key,
            redirect_to_merchant_with_http_post,
            publishable_key,
            storage_scheme,
            locker_id,
            metadata,
            routing_algorithm,
            primary_business_details,
            modified_at,
            intent_fulfillment_time,
            frm_routing_algorithm,
            payout_routing_algorithm,
            organization_id,
            is_recon_enabled,
            default_profile,
            recon_status,
            payment_link_config,
            pm_collect_link_config,
            is_platform_account,
            product_type,
        } = self;

        MerchantAccount {
            merchant_id: source.merchant_id,
            return_url: return_url.or(source.return_url),
            enable_payment_response_hash: enable_payment_response_hash
                .unwrap_or(source.enable_payment_response_hash),
            payment_response_hash_key: payment_response_hash_key
                .or(source.payment_response_hash_key),
            redirect_to_merchant_with_http_post: redirect_to_merchant_with_http_post
                .unwrap_or(source.redirect_to_merchant_with_http_post),
            merchant_name: merchant_name.or(source.merchant_name),
            merchant_details: merchant_details.or(source.merchant_details),
            webhook_details: webhook_details.or(source.webhook_details),
            sub_merchants_enabled: sub_merchants_enabled.or(source.sub_merchants_enabled),
            parent_merchant_id: parent_merchant_id.or(source.parent_merchant_id),
            publishable_key: publishable_key.or(source.publishable_key),
            storage_scheme: storage_scheme.unwrap_or(source.storage_scheme),
            locker_id: locker_id.or(source.locker_id),
            metadata: metadata.or(source.metadata),
            routing_algorithm: routing_algorithm.or(source.routing_algorithm),
            primary_business_details: primary_business_details
                .unwrap_or(source.primary_business_details),
            intent_fulfillment_time: intent_fulfillment_time.or(source.intent_fulfillment_time),
            created_at: source.created_at,
            modified_at,
            frm_routing_algorithm: frm_routing_algorithm.or(source.frm_routing_algorithm),
            payout_routing_algorithm: payout_routing_algorithm.or(source.payout_routing_algorithm),
            organization_id: organization_id.unwrap_or(source.organization_id),
            is_recon_enabled: is_recon_enabled.unwrap_or(source.is_recon_enabled),
            default_profile: default_profile.unwrap_or(source.default_profile),
            recon_status: recon_status.unwrap_or(source.recon_status),
            payment_link_config: payment_link_config.or(source.payment_link_config),
            pm_collect_link_config: pm_collect_link_config.or(source.pm_collect_link_config),
            version: source.version,
            is_platform_account: is_platform_account.unwrap_or(source.is_platform_account),
            id: source.id,
            product_type: product_type.or(source.product_type),
            merchant_account_type: source.merchant_account_type,
        }
    }
}


// Implementation: impl Organization
// File: crates/diesel_models/src/query/organization.rs
// Module: diesel_models
// Methods: 2 total (0 public)

impl Organization


// Implementation: impl api::MandateSetup for for Trustpay
// File: crates/hyperswitch_connectors/src/connectors/trustpay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::MandateSetup for for Trustpay


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

impl api::Payment for for Payu


// Struct: NoonGooglePay
// File: crates/hyperswitch_connectors/src/connectors/noon/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NoonGooglePay


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

impl api::Payment for for Wise


// Implementation: impl ConnectorCommon for for Coingate
// File: crates/hyperswitch_connectors/src/connectors/coingate.rs
// Module: hyperswitch_connectors
// Methods: 6 total (0 public)

impl ConnectorCommon for for Coingate


// Struct: CancelResponseData
// File: crates/hyperswitch_connectors/src/connectors/getnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CancelResponseData


// Struct: RSyncTransactionResponse
// File: crates/hyperswitch_connectors/src/connectors/authorizedotnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RSyncTransactionResponse


// Function: vault_payment_method_external_v1
// File: crates/router/src/core/payment_methods.rs
// Module: router

pub fn vault_payment_method_external_v1(
    state: &SessionState,
    pmd: &hyperswitch_domain_models::vault::PaymentMethodVaultingData,
    merchant_account: &domain::MerchantAccount,
    merchant_connector_account: hyperswitch_domain_models::merchant_connector_account::MerchantConnectorAccount,
) -> RouterResult<pm_types::AddVaultResponse>


// Implementation: impl ConnectorValidation for for Opennode
// File: crates/hyperswitch_connectors/src/connectors/opennode.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl ConnectorValidation for for Opennode


// Struct: CustomerUpdateInternal
// File: crates/diesel_models/src/customers.rs
// Module: diesel_models
// Implementations: 2

pub struct CustomerUpdateInternal


// Struct: MerchantConnectorId
// File: crates/api_models/src/admin.rs
// Module: api_models
// Implementations: 0

pub struct MerchantConnectorId


// Struct: MandatePaymentInformation
// File: crates/hyperswitch_connectors/src/connectors/wellsfargo/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct MandatePaymentInformation


// Module Structure
// File: crates/pm_auth/src/connector/plaid.rs
// Module: pm_auth

// Public submodules:
pub mod transformers;


// Struct: CheckoutGooglePayData
// File: crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CheckoutGooglePayData


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

impl FraudCheckSale for for Signifyd


// Struct: ProcessingInfoResponse
// File: crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ProcessingInfoResponse


// Struct: RoutingEventsResult
// File: crates/analytics/src/routing_events/events.rs
// Module: analytics
// Implementations: 0

pub struct RoutingEventsResult


// Struct: WellsfargoTokenInformation
// File: crates/hyperswitch_connectors/src/connectors/wellsfargo/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct WellsfargoTokenInformation


// Struct: AccountIDSupportedMethods
// File: crates/connector_configs/src/connector.rs
// Module: connector_configs
// Implementations: 0

pub struct AccountIDSupportedMethods


// Trait: FileStorageInterface
// File: crates/external_services/src/file_storage.rs
// Module: external_services

pub trait FileStorageInterface: dyn_clone::DynClone + Sync + Send


// Struct: BeginTotpResponse
// File: crates/api_models/src/user.rs
// Module: api_models
// Implementations: 0

pub struct BeginTotpResponse


// Implementation: impl api::ConnectorCustomer for for Facilitapay
// File: crates/hyperswitch_connectors/src/connectors/facilitapay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorCustomer for for Facilitapay


// Struct: NoonApplePayPaymentMethod
// File: crates/hyperswitch_connectors/src/connectors/noon/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NoonApplePayPaymentMethod


// Module Structure
// File: crates/hyperswitch_domain_models/src/payouts.rs
// Module: hyperswitch_domain_models

// Public submodules:
pub mod payout_attempt;
pub mod payouts;


// Implementation: impl GsmFeatureData
// File: crates/common_types/src/domain.rs
// Module: common_types
// Methods: 2 total (2 public)

impl GsmFeatureData


// Function: delete_by_merchant_id
// File: crates/diesel_models/src/query/merchant_account.rs
// Module: diesel_models

pub fn delete_by_merchant_id(
        conn: &PgPooledConn,
        identifier: &common_utils::id_type::MerchantId,
    ) -> StorageResult<bool>


// Struct: TimelinePayment
// File: crates/hyperswitch_connectors/src/connectors/coinbase/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TimelinePayment


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

pub struct RefundsMetricsResponse<T>


// Struct: DeviceDetails
// File: crates/hyperswitch_connectors/src/connectors/unified_authentication_service/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DeviceDetails


// Struct: PaymentMethodsPTMapping
// File: crates/scheduler/src/consumer/types/process_data.rs
// Module: scheduler
// Implementations: 1
// Traits: Default

pub struct PaymentMethodsPTMapping


// Implementation: impl ConnectorSpecifications for for Peachpayments
// File: crates/hyperswitch_connectors/src/connectors/peachpayments.rs
// Module: hyperswitch_connectors
// Methods: 3 total (0 public)

impl ConnectorSpecifications for for Peachpayments


// File: crates/analytics/src/refunds/metrics.rs
// Module: analytics
// Public structs: 1

use api_models::analytics::{
    refunds::{
        RefundDimensions, RefundFilters, RefundMetrics, RefundMetricsBucketIdentifier, RefundType,
    },
    Granularity, TimeRange,
};
use diesel_models::enums as storage_enums;
use time::PrimitiveDateTime;
mod refund_count;
mod refund_processed_amount;
mod refund_success_count;
mod refund_success_rate;
mod sessionized_metrics;
use std::collections::HashSet;

use refund_count::RefundCount;
use refund_processed_amount::RefundProcessedAmount;
use refund_success_count::RefundSuccessCount;
use refund_success_rate::RefundSuccessRate;

use crate::{
    enums::AuthInfo,
    query::{Aggregate, GroupByClause, ToSql, Window},
    types::{AnalyticsCollection, AnalyticsDataSource, DBEnumWrapper, LoadRow, MetricsResult},
};

#[derive(Debug, Eq, PartialEq, serde::Deserialize, Hash)]
pub struct RefundMetricRow {
    pub currency: Option<DBEnumWrapper<storage_enums::Currency>>,
    pub refund_status: Option<DBEnumWrapper<storage_enums::RefundStatus>>,
    pub connector: Option<String>,
    pub refund_type: Option<DBEnumWrapper<RefundType>>,
    pub profile_id: Option<String>,
    pub refund_reason: Option<String>,
    pub refund_error_message: Option<String>,
    pub total: Option<bigdecimal::BigDecimal>,
    pub count: Option<i64>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub start_bucket: Option<PrimitiveDateTime>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub end_bucket: Option<PrimitiveDateTime>,
}

pub trait RefundMetricAnalytics: LoadRow<RefundMetricRow> {}

#[async_trait::async_trait]
pub trait RefundMetric<T>
where
    T: AnalyticsDataSource + RefundMetricAnalytics,
    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: &[RefundDimensions],
        auth: &AuthInfo,
        filters: &RefundFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>>;
}

#[async_trait::async_trait]
impl<T> RefundMetric<T> for RefundMetrics
where
    T: AnalyticsDataSource + RefundMetricAnalytics,
    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: &[RefundDimensions],
        auth: &AuthInfo,
        filters: &RefundFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>> {
        match self {
            Self::RefundSuccessRate => {
                RefundSuccessRate::default()
                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                    .await
            }
            Self::RefundCount => {
                RefundCount::default()
                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                    .await
            }
            Self::RefundSuccessCount => {
                RefundSuccessCount::default()
                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                    .await
            }
            Self::RefundProcessedAmount => {
                RefundProcessedAmount::default()
                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                    .await
            }
            Self::SessionizedRefundSuccessRate => {
                sessionized_metrics::RefundSuccessRate::default()
                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                    .await
            }
            Self::SessionizedRefundCount => {
                sessionized_metrics::RefundCount::default()
                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                    .await
            }
            Self::SessionizedRefundSuccessCount => {
                sessionized_metrics::RefundSuccessCount::default()
                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                    .await
            }
            Self::SessionizedRefundProcessedAmount => {
                sessionized_metrics::RefundProcessedAmount::default()
                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                    .await
            }
            Self::SessionizedRefundReason => {
                sessionized_metrics::RefundReason
                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                    .await
            }
            Self::SessionizedRefundErrorMessage => {
                sessionized_metrics::RefundErrorMessage
                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                    .await
            }
        }
    }
}


// Struct: CybersourceConsumerAuthInformationEnrollmentResponse
// File: crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CybersourceConsumerAuthInformationEnrollmentResponse


// Implementation: impl api::UasAuthenticationConfirmation for for Juspaythreedsserver
// File: crates/hyperswitch_connectors/src/connectors/juspaythreedsserver.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::UasAuthenticationConfirmation for for Juspaythreedsserver