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

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

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

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

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

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

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

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Wellsfargo {
    fn get_headers(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }
    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }
    fn get_http_method(&self) -> Method {
        Method::Get
    }
    fn get_url(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        let refund_id = req.request.get_connector_refund_id()?;
        Ok(format!(
            "{}tss/v2/transactions/{}",
            self.base_url(connectors),
            refund_id
        ))
    }
    fn build_request(
        &self,
        req: &RefundSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Get)
                .url(&RefundSyncType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(RefundSyncType::get_headers(self, req, connectors)?)
                .build(),
        ))
    }
    fn handle_response(
        &self,
        data: &RefundSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
        let response: wellsfargo::WellsfargoRsyncResponse = res
            .response
            .parse_struct("Wellsfargo RefundSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }
    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

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

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

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

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

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

        let connector_router_data = wellsfargo::WellsfargoRouterData::from((amount, req));
        let connector_request =
            wellsfargo::WellsfargoPaymentsIncrementalAuthorizationRequest::try_from(
                &connector_router_data,
            )?;
        Ok(RequestContent::Json(Box::new(connector_request)))
    }
    fn build_request(
        &self,
        req: &PaymentsIncrementalAuthorizationRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Patch)
                .url(&IncrementalAuthorizationType::get_url(
                    self, req, connectors,
                )?)
                .attach_default_headers()
                .headers(IncrementalAuthorizationType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(IncrementalAuthorizationType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }
    fn handle_response(
        &self,
        data: &PaymentsIncrementalAuthorizationRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<
        RouterData<
            IncrementalAuthorization,
            PaymentsIncrementalAuthorizationData,
            PaymentsResponseData,
        >,
        errors::ConnectorError,
    > {
        let response: wellsfargo::WellsfargoPaymentsIncrementalAuthorizationResponse = res
            .response
            .parse_struct("Wellsfargo PaymentResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }
    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

#[async_trait::async_trait]
impl webhooks::IncomingWebhook for Wellsfargo {
    fn get_webhook_object_reference_id(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_event_type(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        Ok(api_models::webhooks::IncomingWebhookEvent::EventNotSupported)
    }

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

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

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

        let mut wellsfargo_supported_payment_methods = SupportedPaymentMethods::new();

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

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

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

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

        wellsfargo_supported_payment_methods.add(
            enums::PaymentMethod::BankDebit,
            enums::PaymentMethodType::Ach,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        wellsfargo_supported_payment_methods
    });

static WELLSFARGO_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Wells Fargo",
    description:
        "Wells Fargo is a major bank offering retail, commercial, and wealth management services",
    connector_type: enums::HyperswitchConnectorCategory::BankAcquirer,
    integration_status: enums::ConnectorIntegrationStatus::Beta,
};

static WELLSFARGO_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 0] = [];

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

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

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


// Function: add_certificate_key
// File: crates/common_utils/src/request.rs
// Module: common_utils

pub fn add_certificate_key(mut self, certificate_key: Option<Secret<String>>) -> Self


// Function: get_payment_intent_metrics
// File: crates/analytics/src/lib.rs
// Module: analytics

pub fn get_payment_intent_metrics(
        &self,
        metric: &PaymentIntentMetrics,
        dimensions: &[PaymentIntentDimensions],
        auth: &AuthInfo,
        filters: &PaymentIntentFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
    ) -> types::MetricsResult<HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>


// Struct: VolumeSplit
// File: crates/router/src/core/payments/routing/utils.rs
// Module: router
// Implementations: 0

pub struct VolumeSplit<T>


// Implementation: impl crate::events::ApiEventMetric for for ClientSecretId
// File: crates/common_utils/src/id_type/client_secret.rs
// Module: common_utils
// Methods: 1 total (0 public)

impl crate::events::ApiEventMetric for for ClientSecretId


// Struct: RecurlyInvoiceBillingAddress
// File: crates/hyperswitch_connectors/src/connectors/recurly/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RecurlyInvoiceBillingAddress


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

impl DisputeInterface for for KafkaStore


// Function: call_decide_gateway_open_router
// File: crates/router/src/routes/routing.rs
// Module: router

pub fn call_decide_gateway_open_router(
    state: web::Data<AppState>,
    req: HttpRequest,
    payload: web::Json<api_models::open_router::OpenRouterDecideGatewayRequest>,
) -> impl Responder


// Function: find_invoice_by_id_invoice_id
// File: crates/diesel_models/src/query/invoice.rs
// Module: diesel_models

pub fn find_invoice_by_id_invoice_id(
        conn: &PgPooledConn,
        id: String,
    ) -> StorageResult<Self>


// Struct: NomupayAuthType
// File: crates/hyperswitch_connectors/src/connectors/nomupay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NomupayAuthType


// File: crates/router/src/types/storage/gsm.rs
// Module: router

pub use diesel_models::gsm::{
    GatewayStatusMap, GatewayStatusMapperUpdateInternal, GatewayStatusMappingNew,
    GatewayStatusMappingUpdate,
};


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

impl api::PaymentAuthorize for for Celero


// File: crates/scheduler/src/configs.rs
// Module: scheduler

pub mod defaults;
pub mod settings;
pub mod validations;


// Struct: FileMetadataResponse
// File: crates/api_models/src/files.rs
// Module: api_models
// Implementations: 0

pub struct FileMetadataResponse


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

pub mod transformers;

use std::sync::LazyLock;

use common_enums::enums;
use common_utils::{
    errors::CustomResult,
    ext_traits::BytesExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, StringMinorUnit, StringMinorUnitForConnector},
};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
    },
    router_request_types::{
        AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
        PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
        RefundsData, SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentsResponseData, RefundsResponseData, SupportedPaymentMethods,
    },
    types::{
        PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData,
        RefundSyncRouterData, RefundsRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation,
    },
    configs::Connectors,
    errors,
    events::connector_api_logs::ConnectorEvent,
    types::{self, Response},
    webhooks,
};
use masking::{ExposeInterface, Mask};
use transformers as katapult;

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

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

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

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

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

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

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

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Base
        //    TODO! Check connector documentation, on which unit they are processing the currency.
        //    If the connector accepts amount in lower unit ( i.e cents for USD) then return api::CurrencyUnit::Minor,
        //    if connector accepts amount in base unit (i.e dollars for USD) then return api::CurrencyUnit::Base
    }

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

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

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

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

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

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

impl ConnectorValidation for Katapult {
    fn validate_mandate_payment(
        &self,
        _pm_type: Option<enums::PaymentMethodType>,
        pm_data: PaymentMethodData,
    ) -> CustomResult<(), errors::ConnectorError> {
        match pm_data {
            PaymentMethodData::Card(_) => Err(errors::ConnectorError::NotImplemented(
                "validate_mandate_payment does not support cards".to_string(),
            )
            .into()),
            _ => Ok(()),
        }
    }

    fn validate_psync_reference_id(
        &self,
        _data: &PaymentsSyncData,
        _is_three_ds: bool,
        _status: enums::AttemptStatus,
        _connector_meta_data: Option<common_utils::pii::SecretSerdeValue>,
    ) -> CustomResult<(), errors::ConnectorError> {
        Ok(())
    }
}

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

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

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

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

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

    fn get_url(
        &self,
        _req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

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

        let connector_router_data = katapult::KatapultRouterData::from((amount, req));
        let connector_req = katapult::KatapultPaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

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

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

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

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

    fn get_url(
        &self,
        _req: &PaymentsSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

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

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

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

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

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

    fn get_url(
        &self,
        _req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

    fn get_request_body(
        &self,
        _req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into())
    }

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

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

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

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

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

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

    fn get_url(
        &self,
        _req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

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

        let connector_router_data = katapult::KatapultRouterData::from((refund_amount, req));
        let connector_req = katapult::KatapultRefundRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

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

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

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

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

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

    fn get_url(
        &self,
        _req: &RefundSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
    }

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

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

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

#[async_trait::async_trait]
impl webhooks::IncomingWebhook for Katapult {
    fn get_webhook_object_reference_id(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

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

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

static KATAPULT_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> =
    LazyLock::new(SupportedPaymentMethods::new);

static KATAPULT_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Katapult",
    description: "Katapult connector",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Alpha,
};

static KATAPULT_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 0] = [];

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

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

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


// Function: get_decision
// File: crates/common_types/src/three_ds_decision_rule_engine.rs
// Module: common_types

// Documentation: Returns the decision

pub fn get_decision(&self) -> ThreeDSDecision


// Implementation: impl NetworkTokenizationBuilder
// File: crates/router/src/core/payment_methods/tokenize/card_executor.rs
// Module: router
// Methods: 1 total (1 public)

impl NetworkTokenizationBuilder


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

impl api::MandateSetup for for Tsys


// Implementation: impl api::ConnectorAccessToken for for Taxjar
// File: crates/hyperswitch_connectors/src/connectors/taxjar.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorAccessToken for for Taxjar


// Struct: LineItem
// File: crates/hyperswitch_connectors/src/connectors/riskified/transformers/api.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct LineItem


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

impl ConnectorValidation for for Bankofamerica


// Struct: NodeId
// File: crates/hyperswitch_constraint_graph/src/types.rs
// Module: hyperswitch_constraint_graph
// Implementations: 0

pub struct NodeId


// Struct: ResponseInsights
// File: crates/hyperswitch_connectors/src/connectors/barclaycard/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ResponseInsights


// Implementation: impl AddressStructForDbEntry
// File: crates/router/src/core/customers.rs
// Module: router
// Methods: 1 total (0 public)

impl AddressStructForDbEntry


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

pub struct StatusReasonInformation


// Struct: AuthenticationErrorInformation
// File: crates/hyperswitch_connectors/src/connectors/barclaycard/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AuthenticationErrorInformation


        customer_acceptance: &Option<common_payments_types::CustomerAcceptance>,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> RouterResult<(
        storage::PaymentAttemptNew,
        Option<api_models::payments::AdditionalPaymentData>,
    )> {
        let payment_method_data =
            request
                .payment_method_data
                .as_ref()
                .and_then(|payment_method_data_request| {
                    payment_method_data_request.payment_method_data.as_ref()
                });

        let created_at @ modified_at @ last_synced = Some(common_utils::date_time::now());
        let status = helpers::payment_attempt_status_fsm(payment_method_data, request.confirm);
        let (amount, currency) = (money.0, Some(money.1));

        let mut additional_pm_data = request
            .payment_method_data
            .as_ref()
            .and_then(|payment_method_data_request| {
                payment_method_data_request.payment_method_data.clone()
            })
            .async_map(|payment_method_data| async {
                helpers::get_additional_payment_data(
                    &payment_method_data.into(),
                    &*state.store,
                    &profile_id,
                )
                .await
            })
            .await
            .transpose()?
            .flatten();

        if additional_pm_data.is_none() {
            // If recurring payment is made using payment_method_id, then fetch payment_method_data from retrieved payment_method object
            additional_pm_data = payment_method_info.as_ref().and_then(|pm_info| {
                pm_info
                    .payment_method_data
                    .clone()
                    .map(|x| x.into_inner().expose())
                    .and_then(|v| {
                        serde_json::from_value::<PaymentMethodsData>(v)
                            .map_err(|err| {
                                logger::error!(
                                    "Unable to deserialize payment methods data: {:?}",
                                    err
                                )
                            })
                            .ok()
                    })
                    .and_then(|pmd| match pmd {
                        PaymentMethodsData::Card(card) => {
                            Some(api_models::payments::AdditionalPaymentData::Card(Box::new(
                                api::CardDetailFromLocker::from(card).into(),
                            )))
                        }
                        PaymentMethodsData::WalletDetails(wallet) => match payment_method_type {
                            Some(enums::PaymentMethodType::ApplePay) => {
                                Some(api_models::payments::AdditionalPaymentData::Wallet {
                                    apple_pay: api::payments::ApplepayPaymentMethod::try_from(
                                        wallet,
                                    )
                                    .inspect_err(|err| {
                                        logger::error!(
                                            "Unable to transform PaymentMethodDataWalletInfo to ApplepayPaymentMethod: {:?}",
                                            err
                                        )
                                    })
                                    .ok(),
                                    google_pay: None,
                                    samsung_pay: None,
                                })
                            }
                            Some(enums::PaymentMethodType::GooglePay) => {
                                Some(api_models::payments::AdditionalPaymentData::Wallet {
                                    apple_pay: None,
                                    google_pay: Some(wallet.into()),
                                    samsung_pay: None,
                                })
                            }
                            Some(enums::PaymentMethodType::SamsungPay) => {
                                Some(api_models::payments::AdditionalPaymentData::Wallet {
                                    apple_pay: None,
                                    google_pay: None,
                                    samsung_pay: Some(wallet.into()),
                                })
                            }
                            _ => None,
                        },
                        _ => None,
                    })
                    .or_else(|| match payment_method_type {
                        Some(enums::PaymentMethodType::Paypal) => {
                            Some(api_models::payments::AdditionalPaymentData::Wallet {
                                apple_pay: None,
                                google_pay: None,
                                samsung_pay: None,
                            })
                        }
                        _ => None,
                    })
            });
        };

        let additional_pm_data_value = additional_pm_data
            .as_ref()
            .map(Encode::encode_to_value)
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to encode additional pm data")?;
        let attempt_id = if core_utils::is_merchant_enabled_for_payment_id_as_connector_request_id(
            &state.conf,
            merchant_id,
        ) {
            payment_id.get_string_repr().to_owned()
        } else {
            payment_id.get_attempt_id(1)
        };

        if request.mandate_data.as_ref().is_some_and(|mandate_data| {
            mandate_data.update_mandate_id.is_some() && mandate_data.mandate_type.is_some()
        }) {
            Err(errors::ApiErrorResponse::InvalidRequestData {message:"Only one field out of 'mandate_type' and 'update_mandate_id' was expected, found both".to_string()})?
        }

        let mandate_data = if let Some(update_id) = request
            .mandate_data
            .as_ref()
            .and_then(|inner| inner.update_mandate_id.clone())
        {
            let mandate_details = MandateDetails {
                update_mandate_id: Some(update_id),
            };
            Some(mandate_details)
        } else {
            None
        };

        let payment_method_type = Option::<enums::PaymentMethodType>::foreign_from((
            payment_method_type,
            additional_pm_data.as_ref(),
            payment_method,
        ));

        // TODO: remove once https://github.com/juspay/hyperswitch/issues/7421 is fixed
        let payment_method_billing_address_id = match optional_payment_method_billing_address_id {
            None => payment_method_info
                .as_ref()
                .and_then(|pm_info| pm_info.payment_method_billing_address.as_ref())
                .map(|address| {
                    address.clone().deserialize_inner_value(|value| {
                        value.parse_value::<api_models::payments::Address>("Address")
                    })
                })
                .transpose()
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .ok()
                .flatten()
                .async_map(|addr| async move {
                    helpers::create_or_find_address_for_payment_by_request(
                        state,
                        Some(addr.get_inner()),
                        None,
                        merchant_id,
                        payment_method_info
                            .as_ref()
                            .map(|pmd_info| pmd_info.customer_id.clone())
                            .as_ref(),
                        key_store,
                        payment_id,
                        storage_scheme,
                    )
                    .await
                })
                .await
                .transpose()
                .change_context(errors::ApiErrorResponse::InternalServerError)?
                .flatten()
                .map(|address| address.address_id),
            address_id => address_id,
        };

        let is_stored_credential = helpers::is_stored_credential(
            &request.recurring_details,
            &request.payment_token,
            request.mandate_id.is_some(),
            request.is_stored_credential,
        );
        Ok((
            storage::PaymentAttemptNew {
                payment_id: payment_id.to_owned(),
                merchant_id: merchant_id.to_owned(),
                attempt_id,
                status,
                currency,
                payment_method,
                capture_method: request.capture_method,
                capture_on: request.capture_on,
                confirm: request.confirm.unwrap_or(false),
                created_at,
                modified_at,
                last_synced,
                authentication_type: request.authentication_type,
                browser_info,
                payment_experience: request.payment_experience,
                payment_method_type,
                payment_method_data: additional_pm_data_value,
                amount_to_capture: request.amount_to_capture,
                payment_token: request.payment_token.clone(),
                mandate_id: request.mandate_id.clone(),
                business_sub_label: request.business_sub_label.clone(),
                mandate_details: request
                    .mandate_data
                    .as_ref()
                    .and_then(|inner| inner.mandate_type.clone().map(Into::into)),
                external_three_ds_authentication_attempted: None,
                mandate_data,
                payment_method_billing_address_id,
                net_amount: hyperswitch_domain_models::payments::payment_attempt::NetAmount::from_payments_request(
                    request,
                    MinorUnit::from(amount),
                ),
                save_to_locker: None,
                connector: None,
                error_message: None,
                offer_amount: None,
                payment_method_id: payment_method_info
                    .as_ref()
                    .map(|pm_info| pm_info.get_id().clone()),
                cancellation_reason: None,
                error_code: None,
                connector_metadata: None,
                straight_through_algorithm: None,
                preprocessing_step_id: None,
                error_reason: None,
                connector_response_reference_id: None,
                multiple_capture_count: None,
                amount_capturable: MinorUnit::new(i64::default()),
                updated_by: String::default(),
                authentication_data: None,
                encoded_data: None,
                merchant_connector_id: None,
                unified_code: None,
                unified_message: None,
                fingerprint_id: None,
                authentication_connector: None,
                authentication_id: None,
                client_source: None,
                client_version: None,
                customer_acceptance: customer_acceptance
                    .clone()
                    .map(|customer_acceptance| customer_acceptance.encode_to_value())
                    .transpose()
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to serialize customer_acceptance")?
                    .map(Secret::new),
                organization_id: organization_id.clone(),
                profile_id,
                connector_mandate_detail: None,
                request_extended_authorization: None,
                extended_authorization_applied: None,
                capture_before: None,
                card_discovery: None,
                processor_merchant_id: merchant_id.to_owned(),
                created_by: None,
                setup_future_usage_applied: request.setup_future_usage,
                routing_approach: Some(common_enums::RoutingApproach::default()),
                connector_request_reference_id: None,
                network_transaction_id:None,
                network_details:None,
                is_stored_credential
            },
            additional_pm_data,

        ))
    }

    #[instrument(skip_all)]
    #[allow(clippy::too_many_arguments)]
    async fn make_payment_intent(
        state: &SessionState,
        payment_id: &common_utils::id_type::PaymentId,
        merchant_context: &domain::MerchantContext,
        money: (api::Amount, enums::Currency),
        request: &api::PaymentsRequest,
        shipping_address_id: Option<String>,
        payment_link_data: Option<api_models::payments::PaymentLinkResponse>,
        billing_address_id: Option<String>,
        active_attempt_id: String,
        profile_id: common_utils::id_type::ProfileId,
        session_expiry: PrimitiveDateTime,
        business_profile: &domain::Profile,
        is_payment_id_from_merchant: bool,
    ) -> RouterResult<storage::PaymentIntent> {
        let created_at @ modified_at @ last_synced = common_utils::date_time::now();

        let status = helpers::payment_intent_status_fsm(
            request
                .payment_method_data
                .as_ref()
                .and_then(|request_payment_method_data| {
                    request_payment_method_data.payment_method_data.as_ref()
                }),
            request.confirm,
        );
        let client_secret = payment_id.generate_client_secret();
        let (amount, currency) = (money.0, Some(money.1));

        let order_details = request
            .get_order_details_as_value()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to convert order details to value")?;

        let allowed_payment_method_types = request
            .get_allowed_payment_method_types_as_value()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Error converting allowed_payment_types to Value")?;

        let connector_metadata = request
            .get_connector_metadata_as_value()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Error converting connector_metadata to Value")?;

        let feature_metadata = request
            .get_feature_metadata_as_value()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Error converting feature_metadata to Value")?;

        let payment_link_id = payment_link_data.map(|pl_data| pl_data.payment_link_id);

        let request_incremental_authorization =
            core_utils::get_request_incremental_authorization_value(
                request.request_incremental_authorization,
                request.capture_method,
            )?;

        let split_payments = request.split_payments.clone();

        // Derivation of directly supplied Customer data in our Payment Create Request
        let raw_customer_details = if request.customer_id.is_none()
            && (request.name.is_some()
                || request.email.is_some()
                || request.phone.is_some()
                || request.phone_country_code.is_some())
        {
            Some(CustomerData {
                name: request.name.clone(),
                phone: request.phone.clone(),
                email: request.email.clone(),
                phone_country_code: request.phone_country_code.clone(),
                tax_registration_id: None,
            })
        } else {
            None
        };
        let is_payment_processor_token_flow = request.recurring_details.as_ref().and_then(
            |recurring_details| match recurring_details {
                RecurringDetails::ProcessorPaymentToken(_) => Some(true),
                _ => None,
            },
        );

        let key = merchant_context
            .get_merchant_key_store()
            .key
            .get_inner()
            .peek();
        let identifier = Identifier::Merchant(
            merchant_context
                .get_merchant_key_store()
                .merchant_id
                .clone(),
        );
        let key_manager_state: KeyManagerState = state.into();

        let shipping_details_encoded = request
            .shipping
            .clone()
            .map(|shipping| Encode::encode_to_value(&shipping).map(Secret::new))
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Unable to encode billing details to serde_json::Value")?;

        let billing_details_encoded = request
            .billing
            .clone()
            .map(|billing| Encode::encode_to_value(&billing).map(Secret::new))
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Unable to encode billing details to serde_json::Value")?;

        let customer_details_encoded = raw_customer_details
            .map(|customer| Encode::encode_to_value(&customer).map(Secret::new))
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Unable to encode shipping details to serde_json::Value")?;

        let encrypted_data = domain::types::crypto_operation(
            &key_manager_state,
            type_name!(storage::PaymentIntent),
            domain::types::CryptoOperation::BatchEncrypt(
                FromRequestEncryptablePaymentIntent::to_encryptable(
                    FromRequestEncryptablePaymentIntent {
                        shipping_details: shipping_details_encoded,
                        billing_details: billing_details_encoded,
                        customer_details: customer_details_encoded,
                    },
                ),
            ),
            identifier.clone(),
            key,
        )
        .await
        .and_then(|val| val.try_into_batchoperation())
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to encrypt data")?;

        let encrypted_data = FromRequestEncryptablePaymentIntent::from_encryptable(encrypted_data)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Unable to encrypt the payment intent data")?;

        let skip_external_tax_calculation = request.skip_external_tax_calculation;

        let tax_details = request
            .order_tax_amount
            .map(|tax_amount| diesel_models::TaxDetails {
                default: Some(diesel_models::DefaultTax {
                    order_tax_amount: tax_amount,
                }),
                payment_method_type: None,
            });
        let force_3ds_challenge_trigger = request
            .force_3ds_challenge
            .unwrap_or(business_profile.force_3ds_challenge);

        Ok(storage::PaymentIntent {
            payment_id: payment_id.to_owned(),
            merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
            status,
            amount: MinorUnit::from(amount),
            currency,
            description: request.description.clone(),
            created_at,
            modified_at,
            last_synced: Some(last_synced),
            client_secret: Some(client_secret),
            setup_future_usage: request.setup_future_usage,
            off_session: request.off_session,
            return_url: request.return_url.as_ref().map(|a| a.to_string()),
            shipping_address_id,
            billing_address_id,
            statement_descriptor_name: request.statement_descriptor_name.clone(),
            statement_descriptor_suffix: request.statement_descriptor_suffix.clone(),
            metadata: request.metadata.clone(),
            business_country: request.business_country,
            business_label: request.business_label.clone(),
            active_attempt: hyperswitch_domain_models::RemoteStorageObject::ForeignID(
                active_attempt_id,
            ),
            order_details,
            amount_captured: None,
            customer_id: request.get_customer_id().cloned(),
            connector_id: None,
            allowed_payment_method_types,
            connector_metadata,
            feature_metadata,
            attempt_count: 1,
            profile_id: Some(profile_id),
            merchant_decision: None,
            payment_link_id,
            payment_confirm_source: None,
            surcharge_applicable: None,
            updated_by: merchant_context
                .get_merchant_account()
                .storage_scheme
                .to_string(),
            request_incremental_authorization,
            incremental_authorization_allowed: None,
            authorization_count: None,
            fingerprint_id: None,
            session_expiry: Some(session_expiry),
            request_external_three_ds_authentication: request
                .request_external_three_ds_authentication,
            split_payments,
            frm_metadata: request.frm_metadata.clone(),
            billing_details: encrypted_data.billing_details,
            customer_details: encrypted_data.customer_details,
            merchant_order_reference_id: request.merchant_order_reference_id.clone(),
            shipping_details: encrypted_data.shipping_details,
            is_payment_processor_token_flow,
            organization_id: merchant_context
                .get_merchant_account()
                .organization_id
                .clone(),
            shipping_cost: request.shipping_cost,
            tax_details,
            skip_external_tax_calculation,
            request_extended_authorization: request.request_extended_authorization,
            psd2_sca_exemption_type: request.psd2_sca_exemption_type,
            processor_merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
            created_by: None,
            force_3ds_challenge: request.force_3ds_challenge,
            force_3ds_challenge_trigger: Some(force_3ds_challenge_trigger),
            is_iframe_redirection_enabled: request
                .is_iframe_redirection_enabled
                .or(business_profile.is_iframe_redirection_enabled),
            is_payment_id_from_merchant: Some(is_payment_id_from_merchant),
            payment_channel: request.payment_channel.clone(),
            order_date: request.order_date,
            discount_amount: request.discount_amount,
            duty_amount: request.duty_amount,
            tax_status: request.tax_status,
            shipping_amount_tax: request.shipping_amount_tax,
            enable_partial_authorization: request.enable_partial_authorization,
            enable_overcapture: request.enable_overcapture,
        })
    }

    #[instrument(skip_all)]
    pub async fn get_ephemeral_key(
        request: &api::PaymentsRequest,
        state: &SessionState,
        merchant_context: &domain::MerchantContext,
    ) -> Option<ephemeral_key::EphemeralKey> {
        match request.get_customer_id() {
            Some(customer_id) => helpers::make_ephemeral_key(
                state.clone(),
                customer_id.clone(),
                merchant_context
                    .get_merchant_account()
                    .get_id()
                    .to_owned()
                    .clone(),
            )
            .await
            .ok()
            .and_then(|ek| {
                if let services::ApplicationResponse::Json(ek) = ek {
                    Some(ek)
                } else {
                    None
                }
            }),
            None => None,
        }
    }
}

#[instrument(skip_all)]
pub fn payments_create_request_validation(
    req: &api::PaymentsRequest,
) -> RouterResult<(api::Amount, enums::Currency)> {
    let currency = req.currency.get_required_value("currency")?;
    let amount = req.amount.get_required_value("amount")?;
    Ok((amount, currency))
}

#[allow(clippy::too_many_arguments)]
async fn create_payment_link(
    request: &api::PaymentsRequest,
    payment_link_config: api_models::admin::PaymentLinkConfig,
    merchant_id: &common_utils::id_type::MerchantId,
    payment_id: common_utils::id_type::PaymentId,
    db: &dyn StorageInterface,
    amount: api::Amount,
    description: Option<String>,
    profile_id: common_utils::id_type::ProfileId,
    domain_name: String,
    session_expiry: PrimitiveDateTime,
    locale: Option<String>,
) -> RouterResult<Option<api_models::payments::PaymentLinkResponse>> {
    let created_at @ last_modified_at = Some(common_utils::date_time::now());
    let payment_link_id = utils::generate_id(consts::ID_LENGTH, "plink");
    let locale_str = locale.unwrap_or("en".to_owned());
    let open_payment_link = format!(
        "{}/payment_link/{}/{}?locale={}",
        domain_name,
        merchant_id.get_string_repr(),
        payment_id.get_string_repr(),
        locale_str.clone(),
    );

    let secure_link = payment_link_config.allowed_domains.as_ref().map(|_| {
        format!(
            "{}/payment_link/s/{}/{}?locale={}",
            domain_name,
            merchant_id.get_string_repr(),
            payment_id.get_string_repr(),
            locale_str,
        )
    });

    let payment_link_config_encoded_value = payment_link_config.encode_to_value().change_context(
        errors::ApiErrorResponse::InvalidDataValue {
            field_name: "payment_link_config",
        },
    )?;

    let payment_link_req = storage::PaymentLinkNew {
        payment_link_id: payment_link_id.clone(),
        payment_id: payment_id.clone(),
        merchant_id: merchant_id.clone(),
        link_to_pay: open_payment_link.clone(),
        amount: MinorUnit::from(amount),
        currency: request.currency,
        created_at,
        last_modified_at,
        fulfilment_time: Some(session_expiry),
        custom_merchant_name: Some(payment_link_config.seller_name),
        description,
        payment_link_config: Some(payment_link_config_encoded_value),
        profile_id: Some(profile_id),
        secure_link,
    };
    let payment_link_db = db
        .insert_payment_link(payment_link_req)
        .await
        .to_duplicate_response(errors::ApiErrorResponse::GenericDuplicateError {
            message: "payment link already exists!".to_string(),
        })?;

    Ok(Some(api_models::payments::PaymentLinkResponse {
        link: payment_link_db.link_to_pay.clone(),
        secure_link: payment_link_db.secure_link,
        payment_link_id: payment_link_db.payment_link_id,
    }))
}


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

impl ConnectorCommon for for Juspaythreedsserver


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

pub struct GatewayResponse


// Struct: EnablePartialAuthorizationBool
// File: crates/common_types/src/primitive_wrappers.rs
// Module: common_types
// Implementations: 2
// Traits: Deref

pub struct EnablePartialAuthorizationBool


// Implementation: impl api::PaymentVoid for for Gpayments
// File: crates/hyperswitch_connectors/src/connectors/gpayments.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentVoid for for Gpayments


// Function: new
// File: crates/external_services/src/hashicorp_vault/core.rs
// Module: external_services

// Documentation: - `config`: A reference to a `HashiCorpVaultConfig` containing the configuration details.

pub fn new(config: &HashiCorpVaultConfig) -> error_stack::Result<Self, HashiCorpError>


// Struct: CaptureResponseTransactionBody
// File: crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CaptureResponseTransactionBody


// File: crates/currency_conversion/src/lib.rs
// Module: currency_conversion

pub mod conversion;
pub mod error;
pub mod types;


// Trait: NonSerializableSecret
// File: crates/masking/src/serde.rs
// Module: masking

pub trait NonSerializableSecret: Serialize


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

pub struct OpensearchError


// Implementation: impl api::ConnectorAccessToken for for Paysafe
// File: crates/hyperswitch_connectors/src/connectors/paysafe.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorAccessToken for for Paysafe


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

pub struct CybersourcePaymentInitiator


// Struct: GooglePayPredecryptDataInternal
// File: crates/hyperswitch_domain_models/src/router_data.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct GooglePayPredecryptDataInternal


// Implementation: impl common_utils::events::ApiEventMetric for for TotalEventsResponse
// File: crates/api_models/src/webhook_events.rs
// Module: api_models
// Methods: 1 total (0 public)

impl common_utils::events::ApiEventMetric for for TotalEventsResponse


// Function: payouts_accounts
// File: crates/router/src/routes/payouts.rs
// Module: router

pub fn payouts_accounts() -> impl Responder


// Module Structure
// File: crates/api_models/src/user.rs
// Module: api_models

// Public submodules:
pub mod dashboard_metadata;
pub mod sample_data;
pub mod theme;


// Function: get_authorization_url
// File: crates/router/src/services/openidconnect.rs
// Module: router

pub fn get_authorization_url(
    state: SessionState,
    redirect_url: String,
    redirect_state: Secret<String>,
    base_url: Secret<String>,
    client_id: Secret<String>,
) -> UserResult<url::Url>


// File: crates/diesel_models/src/query/payouts.rs
// Module: diesel_models
// Public functions: 6

use async_bb8_diesel::AsyncRunQueryDsl;
use diesel::{
    associations::HasTable, debug_query, pg::Pg, BoolExpressionMethods, ExpressionMethods,
    JoinOnDsl, QueryDsl,
};
use error_stack::{report, ResultExt};

use super::generics;
use crate::{
    enums, errors,
    payouts::{Payouts, PayoutsNew, PayoutsUpdate, PayoutsUpdateInternal},
    query::generics::db_metrics,
    schema::{payout_attempt, payouts::dsl},
    PgPooledConn, StorageResult,
};

impl PayoutsNew {
    pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<Payouts> {
        generics::generic_insert(conn, self).await
    }
}
impl Payouts {
    pub async fn update(
        self,
        conn: &PgPooledConn,
        payout_update: PayoutsUpdate,
    ) -> StorageResult<Self> {
        match generics::generic_update_with_results::<<Self as HasTable>::Table, _, _, _>(
            conn,
            dsl::payout_id
                .eq(self.payout_id.to_owned())
                .and(dsl::merchant_id.eq(self.merchant_id.to_owned())),
            PayoutsUpdateInternal::from(payout_update),
        )
        .await
        {
            Err(error) => match error.current_context() {
                errors::DatabaseError::NoFieldsToUpdate => Ok(self),
                _ => Err(error),
            },
            Ok(mut payouts) => payouts
                .pop()
                .ok_or(error_stack::report!(errors::DatabaseError::NotFound)),
        }
    }

    pub async fn find_by_merchant_id_payout_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        payout_id: &common_utils::id_type::PayoutId,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::payout_id.eq(payout_id.to_owned())),
        )
        .await
    }

    pub async fn update_by_merchant_id_payout_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        payout_id: &common_utils::id_type::PayoutId,
        payout: PayoutsUpdate,
    ) -> StorageResult<Self> {
        generics::generic_update_with_results::<<Self as HasTable>::Table, _, _, _>(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::payout_id.eq(payout_id.to_owned())),
            PayoutsUpdateInternal::from(payout),
        )
        .await?
        .first()
        .cloned()
        .ok_or_else(|| {
            report!(errors::DatabaseError::NotFound).attach_printable("Error while updating payout")
        })
    }

    pub async fn find_optional_by_merchant_id_payout_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        payout_id: &common_utils::id_type::PayoutId,
    ) -> StorageResult<Option<Self>> {
        generics::generic_find_one_optional::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::payout_id.eq(payout_id.to_owned())),
        )
        .await
    }

    pub async fn get_total_count_of_payouts(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        active_payout_ids: &[common_utils::id_type::PayoutId],
        connector: Option<Vec<String>>,
        currency: Option<Vec<enums::Currency>>,
        status: Option<Vec<enums::PayoutStatus>>,
        payout_type: Option<Vec<enums::PayoutType>>,
    ) -> StorageResult<i64> {
        let mut filter = <Self as HasTable>::table()
            .inner_join(payout_attempt::table.on(payout_attempt::dsl::payout_id.eq(dsl::payout_id)))
            .count()
            .filter(dsl::merchant_id.eq(merchant_id.to_owned()))
            .filter(dsl::payout_id.eq_any(active_payout_ids.to_vec()))
            .into_boxed();

        if let Some(connector) = connector {
            filter = filter.filter(payout_attempt::dsl::connector.eq_any(connector));
        }
        if let Some(currency) = currency {
            filter = filter.filter(dsl::destination_currency.eq_any(currency));
        }
        if let Some(status) = status {
            filter = filter.filter(dsl::status.eq_any(status));
        }
        if let Some(payout_type) = payout_type {
            filter = filter.filter(dsl::payout_type.eq_any(payout_type));
        }
        router_env::logger::debug!(query = %debug_query::<Pg, _>(&filter).to_string());

        db_metrics::track_database_call::<<Self as HasTable>::Table, _, _>(
            filter.get_result_async::<i64>(conn),
            db_metrics::DatabaseOperation::Filter,
        )
        .await
        .change_context(errors::DatabaseError::Others)
        .attach_printable("Error filtering count of payouts")
    }
}


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

pub struct UasTokenDetails


// Struct: BillingInformation
// File: crates/hyperswitch_connectors/src/connectors/flexiti/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BillingInformation


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

impl api::Payment for for Gpayments


// Function: try_from_string
// File: crates/common_utils/src/id_type/organization.rs
// Module: common_utils

// Documentation: Get an organization id from String

pub fn try_from_string(org_id: String) -> CustomResult<Self, ValidationError>


// File: crates/router/src/utils/user.rs
// Module: router
// Public functions: 20

use std::sync::Arc;

#[cfg(feature = "v1")]
use api_models::admin as admin_api;
use api_models::user as user_api;
#[cfg(feature = "v1")]
use common_enums::connector_enums;
use common_enums::UserAuthType;
#[cfg(feature = "v1")]
use common_utils::ext_traits::ValueExt;
use common_utils::{
    encryption::Encryption,
    errors::CustomResult,
    id_type, type_name,
    types::{keymanager::Identifier, user::LineageContext},
};
use diesel_models::organization::{self, OrganizationBridge};
use error_stack::ResultExt;
#[cfg(feature = "v1")]
use hyperswitch_domain_models::merchant_connector_account::MerchantConnectorAccount as DomainMerchantConnectorAccount;
#[cfg(feature = "v1")]
use masking::PeekInterface;
use masking::{ExposeInterface, Secret};
use redis_interface::RedisConnectionPool;
use router_env::{env, logger};

#[cfg(feature = "v1")]
use crate::types::AdditionalMerchantData;
use crate::{
    consts::user::{REDIS_SSO_PREFIX, REDIS_SSO_TTL},
    core::errors::{StorageError, UserErrors, UserResult},
    routes::SessionState,
    services::{
        authentication::{AuthToken, UserFromToken},
        authorization::roles::RoleInfo,
    },
    types::{
        domain::{self, MerchantAccount, UserFromStorage},
        transformers::ForeignFrom,
    },
};

pub mod dashboard_metadata;
pub mod password;
#[cfg(feature = "dummy_connector")]
pub mod sample_data;
pub mod theme;
pub mod two_factor_auth;

impl UserFromToken {
    pub async fn get_merchant_account_from_db(
        &self,
        state: SessionState,
    ) -> UserResult<MerchantAccount> {
        let key_manager_state = &(&state).into();
        let key_store = state
            .store
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                &self.merchant_id,
                &state.store.get_master_key().to_vec().into(),
            )
            .await
            .map_err(|e| {
                if e.current_context().is_db_not_found() {
                    e.change_context(UserErrors::MerchantIdNotFound)
                } else {
                    e.change_context(UserErrors::InternalServerError)
                }
            })?;
        let merchant_account = state
            .store
            .find_merchant_account_by_merchant_id(key_manager_state, &self.merchant_id, &key_store)
            .await
            .map_err(|e| {
                if e.current_context().is_db_not_found() {
                    e.change_context(UserErrors::MerchantIdNotFound)
                } else {
                    e.change_context(UserErrors::InternalServerError)
                }
            })?;
        Ok(merchant_account)
    }

    pub async fn get_user_from_db(&self, state: &SessionState) -> UserResult<UserFromStorage> {
        let user = state
            .global_store
            .find_user_by_id(&self.user_id)
            .await
            .change_context(UserErrors::InternalServerError)?;
        Ok(user.into())
    }

    pub async fn get_role_info_from_db(&self, state: &SessionState) -> UserResult<RoleInfo> {
        RoleInfo::from_role_id_org_id_tenant_id(
            state,
            &self.role_id,
            &self.org_id,
            self.tenant_id.as_ref().unwrap_or(&state.tenant.tenant_id),
        )
        .await
        .change_context(UserErrors::InternalServerError)
    }
}

pub async fn generate_jwt_auth_token_with_attributes(
    state: &SessionState,
    user_id: String,
    merchant_id: id_type::MerchantId,
    org_id: id_type::OrganizationId,
    role_id: String,
    profile_id: id_type::ProfileId,
    tenant_id: Option<id_type::TenantId>,
) -> UserResult<Secret<String>> {
    let token = AuthToken::new_token(
        user_id,
        merchant_id,
        role_id,
        &state.conf,
        org_id,
        profile_id,
        tenant_id,
    )
    .await?;
    Ok(Secret::new(token))
}

#[allow(unused_variables)]
pub fn get_verification_days_left(
    state: &SessionState,
    user: &UserFromStorage,
) -> UserResult<Option<i64>> {
    #[cfg(feature = "email")]
    return user.get_verification_days_left(state);
    #[cfg(not(feature = "email"))]
    return Ok(None);
}

pub async fn get_user_from_db_by_email(
    state: &SessionState,
    email: domain::UserEmail,
) -> CustomResult<UserFromStorage, StorageError> {
    state
        .global_store
        .find_user_by_email(&email)
        .await
        .map(UserFromStorage::from)
}

pub fn get_redis_connection_for_global_tenant(
    state: &SessionState,
) -> UserResult<Arc<RedisConnectionPool>> {
    state
        .global_store
        .get_redis_conn()
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Failed to get redis connection")
}

impl ForeignFrom<&user_api::AuthConfig> for UserAuthType {
    fn foreign_from(from: &user_api::AuthConfig) -> Self {
        match *from {
            user_api::AuthConfig::OpenIdConnect { .. } => Self::OpenIdConnect,
            user_api::AuthConfig::Password => Self::Password,
            user_api::AuthConfig::MagicLink => Self::MagicLink,
        }
    }
}

pub async fn construct_public_and_private_db_configs(
    state: &SessionState,
    auth_config: &user_api::AuthConfig,
    encryption_key: &[u8],
    id: String,
) -> UserResult<(Option<Encryption>, Option<serde_json::Value>)> {
    match auth_config {
        user_api::AuthConfig::OpenIdConnect {
            private_config,
            public_config,
        } => {
            let private_config_value = serde_json::to_value(private_config.clone())
                .change_context(UserErrors::InternalServerError)
                .attach_printable("Failed to convert auth config to json")?;

            let encrypted_config =
                domain::types::crypto_operation::<serde_json::Value, masking::WithType>(
                    &state.into(),
                    type_name!(diesel_models::user::User),
                    domain::types::CryptoOperation::Encrypt(private_config_value.into()),
                    Identifier::UserAuth(id),
                    encryption_key,
                )
                .await
                .and_then(|val| val.try_into_operation())
                .change_context(UserErrors::InternalServerError)
                .attach_printable("Failed to encrypt auth config")?;

            Ok((
                Some(encrypted_config.into()),
                Some(
                    serde_json::to_value(public_config.clone())
                        .change_context(UserErrors::InternalServerError)
                        .attach_printable("Failed to convert auth config to json")?,
                ),
            ))
        }
        user_api::AuthConfig::Password | user_api::AuthConfig::MagicLink => Ok((None, None)),
    }
}

pub fn parse_value<T>(value: serde_json::Value, type_name: &str) -> UserResult<T>
where
    T: serde::de::DeserializeOwned,
{
    serde_json::from_value::<T>(value)
        .change_context(UserErrors::InternalServerError)
        .attach_printable(format!("Unable to parse {type_name}"))
}

pub async fn decrypt_oidc_private_config(
    state: &SessionState,
    encrypted_config: Option<Encryption>,
    id: String,
) -> UserResult<user_api::OpenIdConnectPrivateConfig> {
    let user_auth_key = hex::decode(
        state
            .conf
            .user_auth_methods
            .get_inner()
            .encryption_key
            .clone()
            .expose(),
    )
    .change_context(UserErrors::InternalServerError)
    .attach_printable("Failed to decode DEK")?;

    let private_config = domain::types::crypto_operation::<serde_json::Value, masking::WithType>(
        &state.into(),
        type_name!(diesel_models::user::User),
        domain::types::CryptoOperation::DecryptOptional(encrypted_config),
        Identifier::UserAuth(id),
        &user_auth_key,
    )
    .await
    .and_then(|val| val.try_into_optionaloperation())
    .change_context(UserErrors::InternalServerError)
    .attach_printable("Failed to decrypt private config")?
    .ok_or(UserErrors::InternalServerError)
    .attach_printable("Private config not found")?
    .into_inner()
    .expose();

    serde_json::from_value::<user_api::OpenIdConnectPrivateConfig>(private_config)
        .change_context(UserErrors::InternalServerError)
        .attach_printable("unable to parse OpenIdConnectPrivateConfig")
}

pub async fn set_sso_id_in_redis(
    state: &SessionState,
    oidc_state: Secret<String>,
    sso_id: String,
) -> UserResult<()> {
    let connection = get_redis_connection_for_global_tenant(state)?;
    let key = get_oidc_key(&oidc_state.expose());
    connection
        .set_key_with_expiry(&key.into(), sso_id, REDIS_SSO_TTL)
        .await
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Failed to set sso id in redis")
}

pub async fn get_sso_id_from_redis(
    state: &SessionState,
    oidc_state: Secret<String>,
) -> UserResult<String> {
    let connection = get_redis_connection_for_global_tenant(state)?;
    let key = get_oidc_key(&oidc_state.expose());
    connection
        .get_key::<Option<String>>(&key.into())
        .await
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Failed to get sso id from redis")?
        .ok_or(UserErrors::SSOFailed)
        .attach_printable("Cannot find oidc state in redis. Oidc state invalid or expired")
}

fn get_oidc_key(oidc_state: &str) -> String {
    format!("{REDIS_SSO_PREFIX}{oidc_state}")
}

pub fn get_oidc_sso_redirect_url(state: &SessionState, provider: &str) -> String {
    format!("{}/redirect/oidc/{}", state.conf.user.base_url, provider)
}

pub fn is_sso_auth_type(auth_type: UserAuthType) -> bool {
    match auth_type {
        UserAuthType::OpenIdConnect => true,
        UserAuthType::Password | UserAuthType::MagicLink => false,
    }
}

#[cfg(feature = "v1")]
pub fn create_merchant_account_request_for_org(
    req: user_api::UserOrgMerchantCreateRequest,
    org: organization::Organization,
    product_type: common_enums::MerchantProductType,
) -> UserResult<api_models::admin::MerchantAccountCreate> {
    let merchant_id = generate_env_specific_merchant_id(req.merchant_name.clone().expose())?;

    let company_name = domain::UserCompanyName::new(req.merchant_name.expose())?;
    Ok(api_models::admin::MerchantAccountCreate {
        merchant_id,
        metadata: None,
        locker_id: None,
        return_url: None,
        merchant_name: Some(Secret::new(company_name.get_secret())),
        webhook_details: None,
        publishable_key: None,
        organization_id: Some(org.get_organization_id()),
        merchant_details: None,
        routing_algorithm: None,
        parent_merchant_id: None,
        sub_merchants_enabled: None,
        frm_routing_algorithm: None,
        #[cfg(feature = "payouts")]
        payout_routing_algorithm: None,
        primary_business_details: None,
        payment_response_hash_key: None,
        enable_payment_response_hash: None,
        redirect_to_merchant_with_http_post: None,
        pm_collect_link_config: None,
        product_type: Some(product_type),
        merchant_account_type: None,
    })
}

pub async fn validate_email_domain_auth_type_using_db(
    state: &SessionState,
    email: &domain::UserEmail,
    required_auth_type: UserAuthType,
) -> UserResult<()> {
    let domain = email.extract_domain()?;
    let user_auth_methods = state
        .store
        .list_user_authentication_methods_for_email_domain(domain)
        .await
        .change_context(UserErrors::InternalServerError)?;

    (user_auth_methods.is_empty()
        || user_auth_methods
            .iter()
            .any(|auth_method| auth_method.auth_type == required_auth_type))
    .then_some(())
    .ok_or(UserErrors::InvalidUserAuthMethodOperation.into())
}

pub fn spawn_async_lineage_context_update_to_db(
    state: &SessionState,
    user_id: &str,
    lineage_context: LineageContext,
) {
    let state = state.clone();
    let lineage_context = lineage_context.clone();
    let user_id = user_id.to_owned();
    tokio::spawn(async move {
        match state
            .global_store
            .update_user_by_user_id(
                &user_id,
                diesel_models::user::UserUpdate::LineageContextUpdate { lineage_context },
            )
            .await
        {
            Ok(_) => {
                logger::debug!("Successfully updated lineage context for user {}", user_id);
            }
            Err(e) => {
                logger::error!(
                    "Failed to update lineage context for user {}: {:?}",
                    user_id,
                    e
                );
            }
        }
    });
}

pub fn generate_env_specific_merchant_id(value: String) -> UserResult<id_type::MerchantId> {
    if matches!(env::which(), env::Env::Production) {
        let raw_id = domain::MerchantId::new(value)?;
        Ok(id_type::MerchantId::try_from(raw_id)?)
    } else {
        Ok(id_type::MerchantId::new_from_unix_timestamp())
    }
}

pub fn get_base_url(state: &SessionState) -> &str {
    if !state.conf.multitenancy.enabled {
        &state.conf.user.base_url
    } else {
        &state.tenant.user.control_center_url
    }
}

#[cfg(feature = "v1")]
pub async fn build_cloned_connector_create_request(
    source_mca: DomainMerchantConnectorAccount,
    destination_profile_id: Option<id_type::ProfileId>,
    destination_connector_label: Option<String>,
) -> UserResult<admin_api::MerchantConnectorCreate> {
    let source_mca_name = source_mca
        .connector_name
        .parse::<connector_enums::Connector>()
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Invalid connector name received")?;

    let payment_methods_enabled = source_mca
        .payment_methods_enabled
        .clone()
        .map(|data| {
            let val = data.into_iter().map(|secret| secret.expose()).collect();
            serde_json::Value::Array(val)
                .parse_value("PaymentMethods")
                .change_context(UserErrors::InternalServerError)
                .attach_printable("Unable to deserialize PaymentMethods")
        })
        .transpose()?;

    let frm_configs = source_mca
        .frm_configs
        .as_ref()
        .map(|configs_vec| {
            configs_vec
                .iter()
                .map(|config_secret| {
                    config_secret
                        .peek()
                        .clone()
                        .parse_value("FrmConfigs")
                        .change_context(UserErrors::InternalServerError)
                        .attach_printable("Unable to deserialize FrmConfigs")
                })
                .collect::<Result<Vec<_>, _>>()
        })
        .transpose()?;

    let connector_webhook_details = source_mca
        .connector_webhook_details
        .map(|webhook_details| {
            serde_json::Value::parse_value(
                webhook_details.expose(),
                "MerchantConnectorWebhookDetails",
            )
            .change_context(UserErrors::InternalServerError)
            .attach_printable("Unable to deserialize connector_webhook_details")
        })
        .transpose()?;

    let connector_wallets_details = source_mca
        .connector_wallets_details
        .map(|secret_value| {
            secret_value
                .into_inner()
                .expose()
                .parse_value::<admin_api::ConnectorWalletDetails>("ConnectorWalletDetails")
                .change_context(UserErrors::InternalServerError)
                .attach_printable("Unable to parse ConnectorWalletDetails from Value")
        })
        .transpose()?;

    let additional_merchant_data = source_mca
        .additional_merchant_data
        .map(|secret_value| {
            secret_value
                .into_inner()
                .expose()
                .parse_value::<AdditionalMerchantData>("AdditionalMerchantData")
                .change_context(UserErrors::InternalServerError)
                .attach_printable("Unable to parse AdditionalMerchantData from Value")
        })
        .transpose()?
        .map(admin_api::AdditionalMerchantData::foreign_from);

    Ok(admin_api::MerchantConnectorCreate {
        connector_type: source_mca.connector_type,
        connector_name: source_mca_name,
        connector_label: destination_connector_label.or(source_mca.connector_label.clone()),
        merchant_connector_id: None,
        connector_account_details: Some(source_mca.connector_account_details.clone().into_inner()),
        test_mode: source_mca.test_mode,
        disabled: source_mca.disabled,
        payment_methods_enabled,
        metadata: source_mca.metadata,
        business_country: source_mca.business_country,
        business_label: source_mca.business_label.clone(),
        business_sub_label: source_mca.business_sub_label.clone(),
        frm_configs,
        connector_webhook_details,
        profile_id: destination_profile_id,
        pm_auth_config: source_mca.pm_auth_config.clone(),
        connector_wallets_details,
        status: Some(source_mca.status),
        additional_merchant_data,
    })
}


// Struct: PhonepePaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/phonepe/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PhonepePaymentsRequest


// Struct: DummyConnectorPaymentAttempt
// File: crates/router/src/routes/dummy_connector/types.rs
// Module: router
// Implementations: 1

pub struct DummyConnectorPaymentAttempt


// Implementation: impl api::ConnectorAccessToken for for Boku
// File: crates/hyperswitch_connectors/src/connectors/boku.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorAccessToken for for Boku


// Struct: Recurly
// File: crates/hyperswitch_connectors/src/connectors/recurly.rs
// Module: hyperswitch_connectors
// Implementations: 21
// Traits: api::PayoutsV2, api::UnifiedAuthenticationServiceV2, api::UasPreAuthenticationV2, api::UasPostAuthenticationV2, api::UasAuthenticationV2, api::UasAuthenticationConfirmationV2, api::revenue_recovery_v2::RevenueRecoveryV2, api::subscriptions_v2::SubscriptionsV2, api::subscriptions_v2::GetSubscriptionPlansV2, api::subscriptions_v2::SubscriptionConnectorCustomerV2, api::subscriptions_v2::GetSubscriptionPlanPricesV2, api::subscriptions_v2::SubscriptionsCreateV2, api::subscriptions_v2::GetSubscriptionEstimateV2, api::revenue_recovery_v2::RevenueRecoveryRecordBackV2, api::revenue_recovery_v2::BillingConnectorPaymentsSyncIntegrationV2, api::revenue_recovery_v2::BillingConnectorInvoiceSyncIntegrationV2, ConnectorCommon, ConnectorValidation, webhooks::IncomingWebhook, ConnectorSpecifications

pub struct Recurly


// Struct: ErrorResponse
// File: crates/hyperswitch_connectors/src/connectors/worldline/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ErrorResponse


// Function: connector_list
// File: crates/openapi/src/routes/merchant_connector_account.rs
// Module: openapi

pub fn connector_list()


// Implementation: impl api::PaymentCapture for for Cashtocode
// File: crates/hyperswitch_connectors/src/connectors/cashtocode.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentCapture for for Cashtocode


// Module Structure
// File: crates/router/src/core/errors.rs
// Module: router

// Public submodules:
pub mod chat;
pub mod customers_error_response;
pub mod error_handlers;
pub mod transformers;
pub mod user;
pub mod utils;

// Public exports:
pub use ::payment_methods::core::errors::VaultError;
pub use common_utils::errors::{CustomResult, ParsingError, ValidationError};
pub use hyperswitch_domain_models::errors::api_error_response::{
    ApiErrorResponse, ErrorType, NotImplementedMessage,
};
pub use hyperswitch_interfaces::errors::ConnectorError;
pub use redis_interface::errors::RedisError;
pub use user::*;
pub use self::{
    customers_error_response::CustomersErrorResponse,
    sch_errors::*,
    storage_errors::*,
    storage_impl_errors::*,
    utils::{ConnectorErrorExt, StorageErrorExt},
};
pub use error_stack_parsing::*;


// Function: update_with_attempt_id
// File: crates/diesel_models/src/query/payment_attempt.rs
// Module: diesel_models

pub fn update_with_attempt_id(
        self,
        conn: &PgPooledConn,
        payment_attempt: PaymentAttemptUpdateInternal,
    ) -> StorageResult<Self>


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

impl api::PaymentAuthorize for for Zsl