pub async fn refund_list(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
    req: api_models::refunds::RefundListRequest,
) -> RouterResponse<api_models::refunds::RefundListResponse> {
    let db = state.store;
    let limit = validator::validate_refund_list(req.limit)?;
    let offset = req.offset.unwrap_or_default();

    let refund_list = db
        .filter_refund_by_constraints(
            merchant_context.get_merchant_account().get_id(),
            &(req.clone(), profile_id_list.clone()).try_into()?,
            merchant_context.get_merchant_account().storage_scheme,
            limit,
            offset,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::RefundNotFound)?;

    let data: Vec<refunds::RefundResponse> = refund_list
        .into_iter()
        .map(ForeignInto::foreign_into)
        .collect();

    let total_count = db
        .get_total_count_of_refunds(
            merchant_context.get_merchant_account().get_id(),
            &(req, profile_id_list).try_into()?,
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::InternalServerError)?;

    Ok(services::ApplicationResponse::Json(
        api_models::refunds::RefundListResponse {
            count: data.len(),
            total_count,
            data,
        },
    ))
}


/// Middleware for Adding Accept-Language header based on query params
pub struct AddAcceptLanguageHeader;


pub struct OrderInformation {
    amount_details: Amount,
}


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


pub struct Theme {
    pub theme_id: String,
    pub tenant_id: id_type::TenantId,
    pub org_id: Option<id_type::OrganizationId>,
    pub merchant_id: Option<id_type::MerchantId>,
    pub profile_id: Option<id_type::ProfileId>,
    pub created_at: PrimitiveDateTime,
    pub last_modified_at: PrimitiveDateTime,
    pub entity_type: EntityType,
    pub theme_name: String,
    pub email_primary_color: String,
    pub email_foreground_color: String,
    pub email_background_color: String,
    pub email_entity_name: String,
    pub email_entity_logo_url: String,
}


impl TypedSql {
    pub fn to_field_value_pairs(
        &self,
        request_id: String,
        global_id: String,
    ) -> crate::StorageResult<Vec<(&str, String)>> {
        let pushed_at = common_utils::date_time::now_unix_timestamp();

        Ok(vec![
            (
                "typed_sql",
                serde_json::to_string(self)
                    .change_context(errors::DatabaseError::QueryGenerationFailed)?,
            ),
            ("global_id", global_id),
            ("request_id", request_id),
            ("pushed_at", pushed_at.to_string()),
        ])
    }
}


pub struct AirwallexCompleteRequest {
    request_id: String,
    three_ds: AirwallexThreeDsData,
    #[serde(rename = "type")]
    three_ds_type: AirwallexThreeDsType,
}


pub struct GocardlessRefundRequest {
    refunds: GocardlessRefund,
}


pub struct Retrieve;


impl ApiKeyId {
    /// Generate Api Key Id from prefix
    pub fn generate_key_id(prefix: &'static str) -> Self {
        Self(crate::generate_ref_id_with_default_length(prefix))
    }
}


pub async fn call_locker_api<T>(
    state: &routes::SessionState,
    request: Request,
    flow_name: &str,
    locker_choice: Option<api_enums::LockerChoice>,
) -> errors::CustomResult<T, errors::VaultError>
where
    T: serde::de::DeserializeOwned,
{
    let locker = &state.conf.locker;
    let jwekey = state.conf.jwekey.get_inner();
    let response_type_name = type_name!(T);

    let response = services::call_connector_api(state, request, flow_name)
        .await
        .change_context(errors::VaultError::ApiError)?;

    let is_locker_call_succeeded = response.is_ok();

    let jwe_body = response
        .unwrap_or_else(|err| err)
        .response
        .parse_struct::<services::JweBody>("JweBody")
        .change_context(errors::VaultError::ResponseDeserializationFailed)
        .attach_printable("Failed while parsing locker response into JweBody")?;

    let decrypted_payload = payment_methods::get_decrypted_response_payload(
        jwekey,
        jwe_body,
        locker_choice,
        locker.decryption_scheme.clone(),
    )
    .await
    .change_context(errors::VaultError::ResponseDeserializationFailed)
    .attach_printable("Failed while decrypting locker payload response")?;

    // Irrespective of locker's response status, payload is JWE + JWS decrypted. But based on locker's status,
    // if Ok, deserialize the decrypted payload into given type T
    // if Err, raise an error including locker error message too
    if is_locker_call_succeeded {
        let stored_card_resp: Result<T, error_stack::Report<errors::VaultError>> =
            decrypted_payload
                .parse_struct(response_type_name)
                .change_context(errors::VaultError::ResponseDeserializationFailed)
                .attach_printable_lazy(|| {
                    format!("Failed while parsing locker response into {response_type_name}")
                });
        stored_card_resp
    } else {
        Err::<T, error_stack::Report<errors::VaultError>>((errors::VaultError::ApiError).into())
            .attach_printable_lazy(|| format!("Locker error response: {decrypted_payload:?}"))
    }
}


pub struct TokenizationNew {
    pub id: id_type::GlobalTokenId,
    pub merchant_id: id_type::MerchantId,
    pub customer_id: id_type::GlobalCustomerId,
    pub locker_id: String,
    pub created_at: PrimitiveDateTime,
    pub updated_at: PrimitiveDateTime,
    pub version: common_enums::enums::ApiVersion,
    pub flag: common_enums::enums::TokenizationFlag,
}


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

use std::collections::HashSet;

use api_models::analytics::{
    auth_events::{
        AuthEventDimensions, AuthEventFilters, AuthEventMetrics, AuthEventMetricsBucketIdentifier,
    },
    Granularity, TimeRange,
};
use diesel_models::enums as storage_enums;
use time::PrimitiveDateTime;

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

mod authentication_attempt_count;
mod authentication_count;
mod authentication_error_message;
mod authentication_exemption_approved_count;
mod authentication_exemption_requested_count;
mod authentication_funnel;
mod authentication_success_count;
mod challenge_attempt_count;
mod challenge_flow_count;
mod challenge_success_count;
mod frictionless_flow_count;
mod frictionless_success_count;

use authentication_attempt_count::AuthenticationAttemptCount;
use authentication_count::AuthenticationCount;
use authentication_error_message::AuthenticationErrorMessage;
use authentication_exemption_approved_count::AuthenticationExemptionApprovedCount;
use authentication_exemption_requested_count::AuthenticationExemptionRequestedCount;
use authentication_funnel::AuthenticationFunnel;
use authentication_success_count::AuthenticationSuccessCount;
use challenge_attempt_count::ChallengeAttemptCount;
use challenge_flow_count::ChallengeFlowCount;
use challenge_success_count::ChallengeSuccessCount;
use frictionless_flow_count::FrictionlessFlowCount;
use frictionless_success_count::FrictionlessSuccessCount;

#[derive(Debug, PartialEq, Eq, serde::Deserialize, Hash)]
pub struct AuthEventMetricRow {
    pub count: Option<i64>,
    pub authentication_status: Option<DBEnumWrapper<storage_enums::AuthenticationStatus>>,
    pub trans_status: Option<DBEnumWrapper<storage_enums::TransactionStatus>>,
    pub authentication_type: Option<DBEnumWrapper<storage_enums::DecoupledAuthenticationType>>,
    pub error_message: Option<String>,
    pub authentication_connector: Option<DBEnumWrapper<storage_enums::AuthenticationConnectors>>,
    pub message_version: Option<String>,
    pub acs_reference_number: Option<String>,
    pub platform: Option<String>,
    pub mcc: Option<String>,
    pub currency: Option<DBEnumWrapper<storage_enums::Currency>>,
    pub merchant_country: Option<String>,
    pub billing_country: Option<String>,
    pub shipping_country: Option<String>,
    pub issuer_country: Option<String>,
    pub earliest_supported_version: Option<String>,
    pub latest_supported_version: Option<String>,
    pub whitelist_decision: Option<bool>,
    pub device_manufacturer: Option<String>,
    pub device_type: Option<String>,
    pub device_brand: Option<String>,
    pub device_os: Option<String>,
    pub device_display: Option<String>,
    pub browser_name: Option<String>,
    pub browser_version: Option<String>,
    pub issuer_id: Option<String>,
    pub scheme_name: Option<String>,
    pub exemption_requested: Option<bool>,
    pub exemption_accepted: Option<bool>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub start_bucket: Option<PrimitiveDateTime>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub end_bucket: Option<PrimitiveDateTime>,
}

pub trait AuthEventMetricAnalytics: LoadRow<AuthEventMetricRow> {}

#[async_trait::async_trait]
pub trait AuthEventMetric<T>
where
    T: AnalyticsDataSource + AuthEventMetricAnalytics,
{
    async fn load_metrics(
        &self,
        auth: &AuthInfo,
        dimensions: &[AuthEventDimensions],
        filters: &AuthEventFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>>;
}

#[async_trait::async_trait]
impl<T> AuthEventMetric<T> for AuthEventMetrics
where
    T: AnalyticsDataSource + AuthEventMetricAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_metrics(
        &self,
        auth: &AuthInfo,
        dimensions: &[AuthEventDimensions],
        filters: &AuthEventFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
        match self {
            Self::AuthenticationCount => {
                AuthenticationCount
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
            Self::AuthenticationAttemptCount => {
                AuthenticationAttemptCount
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
            Self::AuthenticationSuccessCount => {
                AuthenticationSuccessCount
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
            Self::ChallengeFlowCount => {
                ChallengeFlowCount
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
            Self::ChallengeAttemptCount => {
                ChallengeAttemptCount
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
            Self::ChallengeSuccessCount => {
                ChallengeSuccessCount
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
            Self::FrictionlessFlowCount => {
                FrictionlessFlowCount
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
            Self::FrictionlessSuccessCount => {
                FrictionlessSuccessCount
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
            Self::AuthenticationErrorMessage => {
                AuthenticationErrorMessage
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
            Self::AuthenticationFunnel => {
                AuthenticationFunnel
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
            Self::AuthenticationExemptionApprovedCount => {
                AuthenticationExemptionApprovedCount
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
            Self::AuthenticationExemptionRequestedCount => {
                AuthenticationExemptionRequestedCount
                    .load_metrics(auth, dimensions, filters, granularity, time_range, pool)
                    .await
            }
        }
    }
}


impl Responder {
    let flow = Flow::RoutingUnlinkConfig;
    let path = path.into_inner();
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        path.clone(),
        |state, auth: auth::AuthenticationData, path, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            routing::unlink_routing_config_under_profile(
                state,
                merchant_context,
                path,
                transaction_type,
            )
        },
        #[cfg(not(feature = "release"))]
        auth::auth_type(
            &auth::V2ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            },
            &auth::JWTAuthProfileFromRoute {
                profile_id: path,
                required_permission: Permission::MerchantRoutingWrite,
            },
            req.headers(),
        ),
        #[cfg(feature = "release")]
        &auth::JWTAuthProfileFromRoute {
            profile_id: path,
            required_permission: Permission::MerchantRoutingWrite,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl api::RefundExecute for Hipay {}


pub struct ProcessingInformation {
    action_list: Option<Vec<WellsfargoActionsList>>,
    action_token_types: Option<Vec<WellsfargoActionsTokenType>>,
    authorization_options: Option<WellsfargoAuthorizationOptions>,
    commerce_indicator: String,
    capture: Option<bool>,
    capture_options: Option<CaptureOptions>,
    payment_solution: Option<String>,
}


pub struct IncomingWebhookRequestDetails<'a> {
    /// method
    pub method: http::Method,
    /// uri
    pub uri: http::Uri,
    /// headers
    pub headers: &'a actix_web::http::header::HeaderMap,
    /// body
    pub body: &'a [u8],
    /// query_params
    pub query_params: String,
}


pub struct MonerisRouterData<T> {
    pub amount: MinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
    pub router_data: T,
}


impl api::PaymentSync for Datatrans {}


pub struct RouterHealthCheckResponse {
    pub database: bool,
    pub redis: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub vault: Option<bool>,
    #[cfg(feature = "olap")]
    pub analytics: bool,
    #[cfg(feature = "olap")]
    pub opensearch: bool,
    pub outgoing_request: bool,
    #[cfg(feature = "dynamic_routing")]
    pub grpc_health_check: HealthCheckMap,
    #[cfg(feature = "dynamic_routing")]
    pub decision_engine: bool,
    pub unified_connector_service: Option<bool>,
}


pub struct PollId {
    pub poll_id: String,
}


OpenAPI Block Path: components.schemas.PaymentLinkSdkLabelType
{
  "type": "string",
  "enum": [
    "above",
    "floating",
    "never"
  ]
}


OpenAPI Block Path: components.schemas.PhoneDetails
{
  "type": "object",
  "properties": {
    "number": {
      "type": "string",
      "description": "The contact number",
      "example": "9123456789",
      "nullable": true
    },
    "country_code": {
      "type": "string",
      "description": "The country code attached to the number",
      "example": "+1",
      "nullable": true
    }
  }
}


pub struct ReportConfig {
    pub payment_function: String,
    pub refund_function: String,
    pub dispute_function: String,
    pub authentication_function: String,
    pub region: String,
}


impl api::PaymentSync for Payme {}


File: crates/router/src/core/metrics.rs

use router_env::{counter_metric, global_meter};

global_meter!(GLOBAL_METER, "ROUTER_API");

counter_metric!(INCOMING_DISPUTE_WEBHOOK_METRIC, GLOBAL_METER); // No. of incoming dispute webhooks
counter_metric!(
    INCOMING_DISPUTE_WEBHOOK_SIGNATURE_FAILURE_METRIC,
    GLOBAL_METER
); // No. of incoming dispute webhooks for which signature verification failed
counter_metric!(
    INCOMING_DISPUTE_WEBHOOK_VALIDATION_FAILURE_METRIC,
    GLOBAL_METER
); // No. of incoming dispute webhooks for which validation failed
counter_metric!(INCOMING_DISPUTE_WEBHOOK_NEW_RECORD_METRIC, GLOBAL_METER); // No. of incoming dispute webhooks for which new record is created in our db
counter_metric!(INCOMING_DISPUTE_WEBHOOK_UPDATE_RECORD_METRIC, GLOBAL_METER); // No. of incoming dispute webhooks for which we have updated the details to existing record
counter_metric!(
    INCOMING_DISPUTE_WEBHOOK_MERCHANT_NOTIFIED_METRIC,
    GLOBAL_METER
); // No. of incoming dispute webhooks which are notified to merchant
counter_metric!(
    ACCEPT_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC,
    GLOBAL_METER
); //No. of status validation failures while accepting a dispute
counter_metric!(
    EVIDENCE_SUBMISSION_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC,
    GLOBAL_METER
); //No. of status validation failures while submitting evidence for a dispute
   //No. of status validation failures while attaching evidence for a dispute
counter_metric!(
    ATTACH_EVIDENCE_DISPUTE_STATUS_VALIDATION_FAILURE_METRIC,
    GLOBAL_METER
);

counter_metric!(INCOMING_PAYOUT_WEBHOOK_METRIC, GLOBAL_METER); // No. of incoming payout webhooks
counter_metric!(
    INCOMING_PAYOUT_WEBHOOK_SIGNATURE_FAILURE_METRIC,
    GLOBAL_METER
); // No. of incoming payout webhooks for which signature verification failed

counter_metric!(WEBHOOK_INCOMING_COUNT, GLOBAL_METER);
counter_metric!(WEBHOOK_INCOMING_FILTERED_COUNT, GLOBAL_METER);
counter_metric!(WEBHOOK_SOURCE_VERIFIED_COUNT, GLOBAL_METER);
counter_metric!(WEBHOOK_OUTGOING_COUNT, GLOBAL_METER);
counter_metric!(WEBHOOK_OUTGOING_RECEIVED_COUNT, GLOBAL_METER);
counter_metric!(WEBHOOK_OUTGOING_NOT_RECEIVED_COUNT, GLOBAL_METER);
counter_metric!(WEBHOOK_PAYMENT_NOT_FOUND, GLOBAL_METER);
counter_metric!(
    WEBHOOK_EVENT_TYPE_IDENTIFICATION_FAILURE_COUNT,
    GLOBAL_METER
);

counter_metric!(ROUTING_CREATE_REQUEST_RECEIVED, GLOBAL_METER);
counter_metric!(ROUTING_CREATE_SUCCESS_RESPONSE, GLOBAL_METER);
counter_metric!(ROUTING_MERCHANT_DICTIONARY_RETRIEVE, GLOBAL_METER);
counter_metric!(
    ROUTING_MERCHANT_DICTIONARY_RETRIEVE_SUCCESS_RESPONSE,
    GLOBAL_METER
);
counter_metric!(ROUTING_LINK_CONFIG, GLOBAL_METER);
counter_metric!(ROUTING_LINK_CONFIG_SUCCESS_RESPONSE, GLOBAL_METER);
counter_metric!(ROUTING_RETRIEVE_CONFIG, GLOBAL_METER);
counter_metric!(ROUTING_RETRIEVE_CONFIG_SUCCESS_RESPONSE, GLOBAL_METER);
counter_metric!(ROUTING_RETRIEVE_DEFAULT_CONFIG, GLOBAL_METER);
counter_metric!(
    ROUTING_RETRIEVE_DEFAULT_CONFIG_SUCCESS_RESPONSE,
    GLOBAL_METER
);
counter_metric!(ROUTING_RETRIEVE_LINK_CONFIG, GLOBAL_METER);
counter_metric!(ROUTING_RETRIEVE_LINK_CONFIG_SUCCESS_RESPONSE, GLOBAL_METER);
counter_metric!(ROUTING_UNLINK_CONFIG, GLOBAL_METER);
counter_metric!(ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE, GLOBAL_METER);
counter_metric!(ROUTING_UPDATE_CONFIG, GLOBAL_METER);
counter_metric!(ROUTING_UPDATE_CONFIG_SUCCESS_RESPONSE, GLOBAL_METER);
counter_metric!(ROUTING_UPDATE_CONFIG_FOR_PROFILE, GLOBAL_METER);
counter_metric!(
    ROUTING_UPDATE_CONFIG_FOR_PROFILE_SUCCESS_RESPONSE,
    GLOBAL_METER
);
counter_metric!(ROUTING_RETRIEVE_CONFIG_FOR_PROFILE, GLOBAL_METER);
counter_metric!(
    ROUTING_RETRIEVE_CONFIG_FOR_PROFILE_SUCCESS_RESPONSE,
    GLOBAL_METER
);
counter_metric!(DYNAMIC_SUCCESS_BASED_ROUTING, GLOBAL_METER);
counter_metric!(DYNAMIC_CONTRACT_BASED_ROUTING, GLOBAL_METER);

#[cfg(feature = "partial-auth")]
counter_metric!(PARTIAL_AUTH_FAILURE, GLOBAL_METER);

counter_metric!(API_KEY_REQUEST_INITIATED, GLOBAL_METER);
counter_metric!(API_KEY_REQUEST_COMPLETED, GLOBAL_METER);


pub struct RefundResponse {
    id: String,
    status: RefundStatus,
}


impl api::PaymentSync for CtpMastercard {}

impl api::PaymentSync for for CtpMastercard


File: crates/analytics/src/health_check.rs

use common_utils::errors::CustomResult;

use crate::types::QueryExecutionError;

#[async_trait::async_trait]
pub trait HealthCheck {
    async fn deep_health_check(&self) -> CustomResult<(), QueryExecutionError>;
}


impl CreateOrValidateOrganization {
    #[cfg(all(feature = "v1", feature = "olap"))]
    /// Create an action to either create or validate the given organization_id
    /// If organization_id is passed, then validate if this organization exists
    /// If not passed, create a new organization
    fn new(organization_id: Option<id_type::OrganizationId>) -> Self {
        if let Some(organization_id) = organization_id {
            Self::Validate { organization_id }
        } else {
            Self::Create
        }
    }

    #[cfg(all(feature = "v2", feature = "olap"))]
    /// Create an action to validate the provided organization_id
    fn new(organization_id: id_type::OrganizationId) -> Self {
        Self::Validate { organization_id }
    }

    #[cfg(feature = "olap")]
    /// Apply the action, whether to create the organization or validate the given organization_id
    async fn create_or_validate(
        &self,
        db: &dyn AccountsStorageInterface,
    ) -> RouterResult<diesel_models::organization::Organization> {
        match self {
            #[cfg(feature = "v1")]
            Self::Create => {
                let new_organization = api_models::organization::OrganizationNew::new(
                    OrganizationType::Standard,
                    None,
                );
                let db_organization = ForeignFrom::foreign_from(new_organization);
                db.insert_organization(db_organization)
                    .await
                    .to_duplicate_response(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Error when creating organization")
            }
            Self::Validate { organization_id } => db
                .find_organization_by_org_id(organization_id)
                .await
                .to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
                    message: "organization with the given id does not exist".to_string(),
                }),
        }
    }
}


impl DummyConnectors {
    pub fn get_connector_image_link(self, base_url: &str) -> String {
        let image_name = match self {
            Self::PhonyPay => "PHONYPAY.svg",
            Self::FauxPay => "FAUXPAY.svg",
            Self::PretendPay => "PRETENDPAY.svg",
            Self::StripeTest => "STRIPE_TEST.svg",
            Self::PaypalTest => "PAYPAL_TEST.svg",
            _ => "PHONYPAY.svg",
        };
        format!("{base_url}{image_name}")
    }
}


pub struct QrCodeData {
    #[serde(rename = "tranID")]
    pub tran_id: String,
    pub status: String,
}


impl Payme {
    pub const fn new() -> &'static Self {
        &Self {
            amount_converter: &MinorUnitForConnector,
            apple_pay_google_pay_amount_converter: &StringMajorUnitForConnector,
            amount_converter_webhooks: &StringMinorUnitForConnector,
        }
    }
}


        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _merchant_id: &common_utils::id_type::MerchantId,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let trustpay_response: trustpay::TrustpayWebhookResponse = request
            .body
            .parse_struct("TrustpayWebhookResponse")
            .switch()?;
        let response: serde_json::Value = request.body.parse_struct("Webhook Value").switch()?;
        let values = utils::collect_and_sort_values_by_removing_signature(
            &response,
            &trustpay_response.signature,
        );
        let payload = values.join("/");
        Ok(payload.into_bytes())
    }

    fn get_dispute_details(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<DisputePayload, errors::ConnectorError> {
        let trustpay_response: trustpay::TrustpayWebhookResponse = request
            .body
            .parse_struct("TrustpayWebhookResponse")
            .switch()?;
        let payment_info = trustpay_response.payment_information;
        let reason = payment_info.status_reason_information.unwrap_or_default();
        let connector_dispute_id = payment_info
            .references
            .payment_id
            .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?;
        let amount = utils::convert_back_amount_to_minor_units(
            self.amount_converter_to_float_major_unit,
            payment_info.amount.amount,
            payment_info.amount.currency,
        )?;
        Ok(DisputePayload {
            amount: utils::convert_amount(
                self.amount_converter_to_string_minor_unit,
                amount,
                payment_info.amount.currency,
            )?,
            currency: payment_info.amount.currency,
            dispute_stage: api_models::enums::DisputeStage::Dispute,
            connector_dispute_id,
            connector_reason: reason.reason.reject_reason,
            connector_reason_code: reason.reason.code,
            challenge_required_by: None,
            connector_status: payment_info.status.to_string(),
            created_at: None,
            updated_at: None,
        })
    }
}

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

impl utils::ConnectorErrorTypeMapping for Trustpay {
    fn get_connector_error_type(
        &self,
        error_code: String,
        error_message: String,
    ) -> ConnectorErrorType {
        match (error_code.as_str(), error_message.as_str()) {
            // 2xx card api error codes and messages mapping
            ("100.100.600", "Empty CVV for VISA, MASTER not allowed") => ConnectorErrorType::UserError,
            ("100.350.100", "Referenced session is rejected (no action possible)") => ConnectorErrorType::TechnicalError,
            ("100.380.401", "User authentication failed") => ConnectorErrorType::UserError,
            ("100.380.501", "Risk management transaction timeout") => ConnectorErrorType::TechnicalError,
            ("100.390.103", "PARes validation failed - problem with signature") => ConnectorErrorType::TechnicalError,
            ("100.390.111", "Communication error to VISA/Mastercard Directory Server") => ConnectorErrorType::TechnicalError,
            ("100.390.112", "Technical error in 3D system") => ConnectorErrorType::TechnicalError,
            ("100.390.115", "Authentication failed due to invalid message format") => ConnectorErrorType::TechnicalError,
            ("100.390.118", "Authentication failed due to suspected fraud") => ConnectorErrorType::UserError,
            ("100.400.304", "Invalid input data") => ConnectorErrorType::UserError,
            ("200.300.404", "Invalid or missing parameter") => ConnectorErrorType::UserError,
            ("300.100.100", "Transaction declined (additional customer authentication required)") => ConnectorErrorType::UserError,
            ("400.001.301", "Card not enrolled in 3DS") => ConnectorErrorType::UserError,
            ("400.001.600", "Authentication error") => ConnectorErrorType::UserError,
            ("400.001.601", "Transaction declined (auth. declined)") => ConnectorErrorType::UserError,
            ("400.001.602", "Invalid transaction") => ConnectorErrorType::UserError,
            ("400.001.603", "Invalid transaction") => ConnectorErrorType::UserError,
            ("700.400.200", "Cannot refund (refund volume exceeded or tx reversed or invalid workflow)") => ConnectorErrorType::BusinessError,
            ("700.500.001", "Referenced session contains too many transactions") => ConnectorErrorType::TechnicalError,
            ("700.500.003", "Test accounts not allowed in production") => ConnectorErrorType::UserError,
            ("800.100.151", "Transaction declined (invalid card)") => ConnectorErrorType::UserError,
            ("800.100.152", "Transaction declined by authorization system") => ConnectorErrorType::UserError,
            ("800.100.153", "Transaction declined (invalid CVV)") => ConnectorErrorType::UserError,
            ("800.100.155", "Transaction declined (amount exceeds credit)") => ConnectorErrorType::UserError,
            ("800.100.157", "Transaction declined (wrong expiry date)") => ConnectorErrorType::UserError,
            ("800.100.162", "Transaction declined (limit exceeded)") => ConnectorErrorType::BusinessError,
            ("800.100.163", "Transaction declined (maximum transaction frequency exceeded)") => ConnectorErrorType::BusinessError,
            ("800.100.168", "Transaction declined (restricted card)") => ConnectorErrorType::UserError,
            ("800.100.170", "Transaction declined (transaction not permitted)") => ConnectorErrorType::UserError,
            ("800.100.172", "Transaction declined (account blocked)") => ConnectorErrorType::BusinessError,
            ("800.100.190", "Transaction declined (invalid configuration data)") => ConnectorErrorType::BusinessError,
            ("800.120.100", "Rejected by throttling") => ConnectorErrorType::TechnicalError,
            ("800.300.401", "Bin blacklisted") => ConnectorErrorType::BusinessError,
            ("800.700.100", "Transaction for the same session is currently being processed, please try again later") => ConnectorErrorType::TechnicalError,
            ("900.100.300", "Timeout, uncertain result") => ConnectorErrorType::TechnicalError,
            // 4xx error codes for cards api are unique and messages vary, so we are relying only on error code to decide an error type
            ("4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "26" | "34" | "39" | "48" | "52" | "85" | "86", _) => ConnectorErrorType::UserError,
            ("21" | "22" | "23" | "30" | "31" | "32" | "35" | "37" | "40" | "41" | "45" | "46" | "49" | "50" | "56" | "60" | "67" | "81" | "82" | "83" | "84" | "87", _) => ConnectorErrorType::BusinessError,
            ("59", _) => ConnectorErrorType::TechnicalError,
            ("1", _) => ConnectorErrorType::UnknownError,
            // Error codes for bank redirects api are unique and messages vary, so we are relying only on error code to decide an error type
            ("1112008" | "1132000" | "1152000", _) => ConnectorErrorType::UserError,
            ("1112009" | "1122006" | "1132001" | "1132002" | "1132003" | "1132004" | "1132005" | "1132006" | "1132008" | "1132009" | "1132010" | "1132011" | "1132012" | "1132013" | "1133000" | "1133001" | "1133002" | "1133003" | "1133004", _) => ConnectorErrorType::BusinessError,
            ("1132014", _) => ConnectorErrorType::TechnicalError,
            ("1132007", _) => ConnectorErrorType::UnknownError,
            _ => ConnectorErrorType::UnknownError,
        }
    }
}

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

        let supported_card_network = vec![
            common_enums::CardNetwork::Mastercard,
            common_enums::CardNetwork::Visa,
            common_enums::CardNetwork::Interac,
            common_enums::CardNetwork::AmericanExpress,
            common_enums::CardNetwork::JCB,
            common_enums::CardNetwork::DinersClub,
            common_enums::CardNetwork::Discover,
            common_enums::CardNetwork::CartesBancaires,
            common_enums::CardNetwork::UnionPay,
        ];

        let mut trustpay_supported_payment_methods = SupportedPaymentMethods::new();

        trustpay_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Credit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                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::NotSupported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                ),
            },
        );

        trustpay_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Debit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                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::NotSupported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network,
                        }
                    }),
                ),
            },
        );

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

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

        trustpay_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Eps,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        trustpay_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Giropay,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        trustpay_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Ideal,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        trustpay_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Sofort,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        trustpay_supported_payment_methods.add(
            enums::PaymentMethod::BankRedirect,
            enums::PaymentMethodType::Blik,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        trustpay_supported_payment_methods.add(
            enums::PaymentMethod::BankTransfer,
            enums::PaymentMethodType::SepaBankTransfer,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        trustpay_supported_payment_methods.add(
            enums::PaymentMethod::BankTransfer,
            enums::PaymentMethodType::InstantBankTransfer,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        trustpay_supported_payment_methods.add(
            enums::PaymentMethod::BankTransfer,
            enums::PaymentMethodType::InstantBankTransferFinland,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: None,
            },
        );

        trustpay_supported_payment_methods.add(
            enums::PaymentMethod::BankTransfer,
            enums::PaymentMethodType::InstantBankTransferPoland,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::NotSupported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods,
                specific_features: None,
            },
        );

        trustpay_supported_payment_methods
    });

static TRUSTPAY_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Trustpay",
    description: "TrustPay offers cross-border payment solutions for online businesses, including global card processing, local payment methods, business accounts, and reconciliation tools—all under one roof.",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Live,
};

static TRUSTPAY_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 3] = [
    enums::EventClass::Payments,
    enums::EventClass::Refunds,
    enums::EventClass::Disputes,
];

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

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

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


pub async fn list_customer_payment_methods_core(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    customer_id: &id_type::GlobalCustomerId,
) -> RouterResult<Vec<payment_methods::CustomerPaymentMethodResponseItem>> {
    let db = &*state.store;
    let key_manager_state = &(state).into();

    let saved_payment_methods = db
        .find_payment_method_by_global_customer_id_merchant_id_status(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            customer_id,
            merchant_context.get_merchant_account().get_id(),
            common_enums::PaymentMethodStatus::Active,
            None,
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;

    let mut customer_payment_methods = Vec::new();

    let payment_method_results: Result<Vec<_>, error_stack::Report<errors::ApiErrorResponse>> =
        saved_payment_methods
            .into_iter()
            .map(|pm| async move {
                let parent_payment_method_token = generate_id(consts::ID_LENGTH, "token");

                // For payment methods that are active we should always have the payment method type
                let payment_method_type = pm
                    .payment_method_type
                    .get_required_value("payment_method_type")?;

                let intent_fulfillment_time = common_utils::consts::DEFAULT_INTENT_FULFILLMENT_TIME;

                let token_data = get_pm_list_token_data(payment_method_type, &pm)?;

                if let Some(token_data) = token_data {
                    pm_routes::ParentPaymentMethodToken::create_key_for_token((
                        &parent_payment_method_token,
                        payment_method_type,
                    ))
                    .insert(intent_fulfillment_time, token_data, state)
                    .await?;

                    let final_pm = api::CustomerPaymentMethodResponseItem::foreign_try_from((
                        pm,
                        parent_payment_method_token,
                    ))
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to convert payment method to response format")?;

                    Ok(Some(final_pm))
                } else {
                    Ok(None)
                }
            })
            .collect::<futures::stream::FuturesUnordered<_>>()
            .try_collect::<Vec<_>>()
            .await;

    customer_payment_methods.extend(payment_method_results?.into_iter().flatten());

    Ok(customer_payment_methods)
}


impl State for TokenizeWithPmId {}


pub async fn proxy_for_call_connector_service<F, RouterDReq, ApiRequest, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: &domain::MerchantContext,
    connector: api::ConnectorData,
    operation: &BoxedOperation<'_, F, ApiRequest, D>,
    payment_data: &mut D,
    customer: &Option<domain::Customer>,
    call_connector_action: CallConnectorAction,
    validate_result: &operations::ValidateResult,
    schedule_time: Option<time::PrimitiveDateTime>,
    header_payload: HeaderPayload,

    business_profile: &domain::Profile,
    return_raw_connector_response: Option<bool>,
) -> RouterResult<(
    RouterData<F, RouterDReq, router_types::PaymentsResponseData>,
    helpers::MerchantConnectorAccountType,
)>
where
    F: Send + Clone + Sync,
    RouterDReq: Send + Sync,

    // To create connector flow specific interface data
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
    D: ConstructFlowSpecificData<F, RouterDReq, router_types::PaymentsResponseData>,
    RouterData<F, RouterDReq, router_types::PaymentsResponseData>: Feature<F, RouterDReq> + Send,
    // To construct connector flow specific api
    dyn api::Connector:
        services::api::ConnectorIntegration<F, RouterDReq, router_types::PaymentsResponseData>,
{
    let stime_connector = Instant::now();

    let merchant_connector_account = construct_profile_id_and_get_mca(
        state,
        merchant_context,
        payment_data,
        &connector.connector_name.to_string(),
        connector.merchant_connector_id.as_ref(),
        false,
    )
    .await?;

    if payment_data
        .get_payment_attempt()
        .merchant_connector_id
        .is_none()
    {
        payment_data.set_merchant_connector_id_in_attempt(merchant_connector_account.get_mca_id());
    }

    let merchant_recipient_data = None;

    let mut router_data = payment_data
        .construct_router_data(
            state,
            connector.connector.id(),
            merchant_context,
            customer,
            &merchant_connector_account,
            merchant_recipient_data,
            None,
        )
        .await?;

    let add_access_token_result = router_data
        .add_access_token(
            state,
            &connector,
            merchant_context,
            payment_data.get_creds_identifier(),
        )
        .await?;

    router_data = router_data.add_session_token(state, &connector).await?;

    let mut should_continue_further = access_token::update_router_data_with_access_token_result(
        &add_access_token_result,
        &mut router_data,
        &call_connector_action,
    );

    (router_data, should_continue_further) = complete_preprocessing_steps_if_required(
        state,
        &connector,
        payment_data,
        router_data,
        operation,
        should_continue_further,
    )
    .await?;

    if let Ok(router_types::PaymentsResponseData::PreProcessingResponse {
        session_token: Some(session_token),
        ..
    }) = router_data.response.to_owned()
    {
        payment_data.push_sessions_token(session_token);
    };

    let (connector_request, should_continue_further) = if should_continue_further {
        // Check if the actual flow specific request can be built with available data
        router_data
            .build_flow_specific_connector_request(state, &connector, call_connector_action.clone())
            .await?
    } else {
        (None, false)
    };

    if should_add_task_to_process_tracker(payment_data) {
        operation
            .to_domain()?
            .add_task_to_process_tracker(
                state,
                payment_data.get_payment_attempt(),
                validate_result.requeue,
                schedule_time,
            )
            .await
            .map_err(|error| logger::error!(process_tracker_error=?error))
            .ok();
    }

    let updated_customer = None;
    let frm_suggestion = None;

    (_, *payment_data) = operation
        .to_update_tracker()?
        .update_trackers(
            state,
            req_state,
            payment_data.clone(),
            customer.clone(),
            merchant_context.get_merchant_account().storage_scheme,
            updated_customer,
            merchant_context.get_merchant_key_store(),
            frm_suggestion,
            header_payload.clone(),
        )
        .await?;

    let router_data = if should_continue_further {
        // The status of payment_attempt and intent will be updated in the previous step
        // update this in router_data.
        // This is added because few connector integrations do not update the status,
        // and rely on previous status set in router_data
        router_data.status = payment_data.get_payment_attempt().status;
        router_data
            .decide_flows(
                state,
                &connector,
                call_connector_action,
                connector_request,
                business_profile,
                header_payload.clone(),
                return_raw_connector_response,
            )
            .await
    } else {
        Ok(router_data)
    }?;

    let etime_connector = Instant::now();
    let duration_connector = etime_connector.saturating_duration_since(stime_connector);
    tracing::info!(duration = format!("Duration taken: {}", duration_connector.as_millis()));

    Ok((router_data, merchant_connector_account))
}


pub struct Venmo {
    /// mobile number linked to venmo account
    #[schema(value_type = String, example = "16608213349")]
    pub telephone_number: Option<Secret<String>>,
}


impl api::RefundSync for Flexiti {}


impl api::ConnectorAccessToken for Jpmorgan {}

impl api::ConnectorAccessToken for for Jpmorgan


pub async fn routing_retrieve_config() {}


pub struct RefundBodyResponse {
    submit_single_refund_response: SubmitSingleRefundResponse,
}


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


pub struct CardAndNetworkTokenDataForVault {
    pub card_data: payment_method_data::Card,
    pub network_token: NetworkTokenDataForVault,
}


pub async fn signout_hypersense_token(
    state: web::Data<AppState>,
    http_req: HttpRequest,
    json_payload: web::Json<external_service_auth_api::ExternalSignoutTokenRequest>,
) -> HttpResponse {
    let flow = Flow::HypersenseSignoutToken;
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &http_req,
        json_payload.into_inner(),
        |state, _: (), json_payload, _| {
            external_service_auth::signout_external_token(state, json_payload)
        },
        &authentication::NoAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub fn new() -> Self {
        Self {
            data: Vec::new(),
            _marker: PhantomData,
        }
    }


File: crates/storage_impl/src/mock_db/redis_conn.rs

use std::sync::Arc;

use redis_interface::errors::RedisError;

use super::MockDb;
use crate::redis::kv_store::RedisConnInterface;

impl RedisConnInterface for MockDb {
    fn get_redis_conn(
        &self,
    ) -> Result<Arc<redis_interface::RedisConnectionPool>, error_stack::Report<RedisError>> {
        self.redis.get_redis_conn()
    }
}


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


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


File: crates/hyperswitch_domain_models/src/router_response_types/fraud_check.rs

use serde::Serialize;

use crate::router_response_types::ResponseId;

#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum FraudCheckResponseData {
    TransactionResponse {
        resource_id: ResponseId,
        status: diesel_models::enums::FraudCheckStatus,
        connector_metadata: Option<serde_json::Value>,
        reason: Option<serde_json::Value>,
        score: Option<i32>,
    },
    FulfillmentResponse {
        order_id: String,
        shipment_ids: Vec<String>,
    },
    RecordReturnResponse {
        resource_id: ResponseId,
        connector_metadata: Option<serde_json::Value>,
        return_id: Option<String>,
    },
}

impl common_utils::events::ApiEventMetric for FraudCheckResponseData {
    fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
        Some(common_utils::events::ApiEventsType::FraudCheck)
    }
}


pub async fn do_auth_connector_call<F, Req, Res>(
    state: &SessionState,
    authentication_connector_name: String,
    router_data: RouterData<F, Req, Res>,
) -> RouterResult<RouterData<F, Req, Res>>
where
    Req: std::fmt::Debug + Clone + 'static,
    Res: std::fmt::Debug + Clone + 'static,
    F: std::fmt::Debug + Clone + 'static,
    dyn api::Connector + Sync: services::api::ConnectorIntegration<F, Req, Res>,
    dyn api::ConnectorV2 + Sync:
        services::api::ConnectorIntegrationV2<F, ExternalAuthenticationFlowData, Req, Res>,
{
    let connector_data =
        api::AuthenticationConnectorData::get_connector_by_name(&authentication_connector_name)?;
    let connector_integration: services::BoxedExternalAuthenticationConnectorIntegrationInterface<
        F,
        Req,
        Res,
    > = connector_data.connector.get_connector_integration();
    let router_data = execute_connector_processing_step(
        state,
        connector_integration,
        &router_data,
        payments::CallConnectorAction::Trigger,
        None,
        None,
    )
    .await
    .to_payment_failed_response()?;
    Ok(router_data)
}


pub struct PowertranzErrorResponse {
    pub errors: Vec<Error>,
}


impl CoBadgedCardNetworks {
    pub fn get_card_networks(&self) -> Vec<common_enums::CardNetwork> {
        self.0.iter().map(|info| info.network.clone()).collect()
    }

    pub fn get_signature_network(&self) -> Option<common_enums::CardNetwork> {
        self.0
            .iter()
            .find(|info| info.network.is_signature_network())
            .map(|info| info.network.clone())
    }
}


impl ApiEventMetric for FxExchangeRatesCacheEntry {}

impl ApiEventMetric for for FxExchangeRatesCacheEntry


impl IncomingWebhook for Zsl {
    fn get_webhook_object_reference_id(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<ObjectReferenceId, errors::ConnectorError> {
        let notif = get_webhook_object_from_body(request.body)
            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
        Ok(ObjectReferenceId::PaymentId(
            api_models::payments::PaymentIdType::PaymentAttemptId(notif.mer_ref),
        ))
    }

    fn get_webhook_event_type(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
        let notif = get_webhook_object_from_body(request.body)
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;

        Ok(get_status(notif.status))
    }

    fn get_webhook_resource_object(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let response = get_webhook_object_from_body(request.body)
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
        Ok(Box::new(response))
    }

    async fn verify_webhook_source(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        _merchant_id: &common_utils::id_type::MerchantId,
        _connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
        connector_account_details: common_utils::crypto::Encryptable<Secret<serde_json::Value>>,
        _connector_label: &str,
    ) -> CustomResult<bool, errors::ConnectorError> {
        let connector_account_details = connector_account_details
            .parse_value::<ConnectorAuthType>("ConnectorAuthType")
            .change_context_lazy(|| errors::ConnectorError::WebhookSourceVerificationFailed)?;
        let auth_type = zsl::ZslAuthType::try_from(&connector_account_details)?;
        let key = auth_type.api_key.expose();
        let mer_id = auth_type.merchant_id.expose();
        let webhook_response = get_webhook_object_from_body(request.body)?;
        let signature = zsl::calculate_signature(
            webhook_response.enctype,
            zsl::ZslSignatureType::WebhookSignature {
                status: webhook_response.status,
                txn_id: webhook_response.txn_id,
                txn_date: webhook_response.txn_date,
                paid_ccy: webhook_response.paid_ccy.to_string(),
                paid_amt: webhook_response.paid_amt,
                mer_ref: webhook_response.mer_ref,
                mer_id,
                key,
            },
        )?;

        Ok(signature.eq(&webhook_response.signature))
    }

    fn get_webhook_api_response(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
        _error_kind: Option<IncomingWebhookFlowError>,
    ) -> CustomResult<ApplicationResponse<serde_json::Value>, errors::ConnectorError> {
        Ok(ApplicationResponse::TextPlain("CALLBACK-OK".to_string()))
    }
}


Web Documentation: Subscriptions | Hyperswitch
# Type: Web Doc

Hyperswitch enables you to work with your preferred subscription provider while having the flexibility to connect with multiple payment processors and payment methods. The benefits you gain by using Hyperswitch integration as a supplement to your Subscription Solution Provider are as follows:
Flexibility with Payment Processors
Choose any payment processor based on better costs or authorization rates.
Global Market Expansion
Integrate local payment methods to tap into global markets with ease.
Optimized Recurring Payments
Smart routing across multiple payment processors improves recurring payment success rates.
Unified Payment Management
A single solution for managing:
One-time payments
(e-commerce use cases)
Recurring payments
(subscription-based use cases)
What subscription providers do we support?
All major Subscription Solution Providers offer integration points to manage payments with external payment processors. And the integration solution proposed below should work universal across any subscription provider.
We also support
Kill Bill
(an open source subscription solution provider) via a direct
Plugin
.
Use cases supported
User flow 1 -
Plan First, Payment Later
User selects a plan followed by selecting the payment method and adding the payment method details to make the payment and start subscription.
User flow 2 -
Payment First, Plan Later
User selects a payment method and adds the payment method details which are saved. User finally selects the plan to start the subscription
Use cases common to both user flows
Subscription management portal
Subscription payment retries
Subscription reminder emails
User flow-1
User selects a plan followed by selecting the payment method and adding the payment method details to start subscription. This flow can be broken into 5 parts
Integration and set up
- Merchants will setup their account and generate API keys with the subscription provider and Hyperswitch as well as integrate with both of them. Merchants will set up their plans with the subscription provider and set up their payment providers with Hyperswitch.
Retrieve plans and create subscription
- Merchants will retrieve the eligible plans and display them on their website. The customer will select one of the plans shown to them. Merchant will use the selected plan to create a customer and a subscription with the subscription provider.
Collect payment method details
- Once the subscription is created and the key fields are received by the merchant, they'll initiate a Payments create call with Hyperswitch and load the payment SDK on their website (
more on SDK integration
) to collect payment details from the customer
Make payment and return invoice
- Using the payment details entered by the user the merchant will make a payment with Hyperswitch and create a mandate (
more details
). The subscription is marked as active upon successful payment and the invoice with the customer.
In case the subscription start date is in future and the customer need not be charged immediately then the merchant should initiate a $0 mandate with Hyperswitch (
more details
).
Make MIT transactions
User flow-2
User selects a payment method and adds the payment method details which are saved. User finally selects the plan to start the subscription. This flow can be broken into 5 parts
Integration and set up
- Merchants will setup their account and generate API keys with the subscription provider and Hyperswitch as well as integrate with both of them. Merchants will set up their plans with the subscription provider and set up their payment providers with Hyperswitch.
Collect and store payment method details
- Merchant will initiate a Payments create call with Hyperswitch and load the payment SDK on their website (
more on SDK integration
) to collect payment details from the customer.
Merchant will create a customer with the subscription provider
Merchant will initiate a $0 mandate with Hyperswitch (
more details
) to validate and store the payment details and create a mandate with Hyperswitch (using the same customer ID).
Retrieve plans and create subscription
- Merchants will retrieve the eligible plans and display them on their website. The customer will select one of the plans shown to them. Merchant will use the selected plan to create a subscription with the subscription provider.
Make payment and return invoice
- Using the mandate ID created earlier the merchant will make a payment with Hyperswitch. The subscription is marked as active upon successful payment and the invoice with the customer.
In case the subscription start date is in future and the customer need not be charged immediately then no payment is inittaed with Hyperswitch
Make MIT transactions
Subscription management portal
The customer-facing subscription management interface allows the customers to modify their billing address, add new payment method details for subscripotion payments and cancel subscription. If a merchant offers a subscription management portal then here's how Hyperswitch can support:
User updates billing address
- The merchant will update the new billing address with both Hyperswitch and the subscription provider using the customer ID.
User updates payment method details
- The merchant will load Hyperswitch SDK to allow the user to select the payment method and add the relevant payment method details. Merchant will validate and add this payment method with Hyperswitch using $0 mandate and create a new mandate.
User cancels subscriptions
- The merchant will revoke the mandate with Hyperswitch post which they will cancel the subscription with the subscription provider.
Subscription payment retries
The payment made for subscriptions can fail
When customer is present in the flow
- The user will retry the payment using same or different payment method
When customer is not present in the flow
- Once the merchant receives payment failed notification from Hyperswitch, they need to update the same with their subscription provider. All subscription providers have their own retry logics (default or configured by the merchant). Their retry logic will then send retry payment webhooks to the merchant. The merchant needs to consume the webhook and retrigger the payment with Hyperswitch (
more details
)
Subscription reminder emails
The merchant can use the Hyperswitch Payment links when sending email reminders to customers who failed to make their subscription payments. Here's how it'll work:
The customer is redirected to the payment link hosted page (with a validity of 15-mins) which allows them to make the payment using any payment option
Once the payment is successful, the merchant should mark the invoice as paid with their subscription provider and return the invoice to the customer
FAQs
Can I bring in my own subscription provider ?
Yes, we support any subscription provider using the above framework.
Can I process both one-time payments and recurring payments via the same setup?
Yes, once you're integrated with Hyperswitch, you'll be able to process both one-time payments and recurring payments.
10 months ago
Was this helpful?

Subscriptions | Hyperswitch


impl api::MandateSetup for Tsys {}


pub struct AdyenplatformInstantStatus {
    status: Option<InstantPriorityStatus>,
    estimated_arrival_time: Option<String>,
}


pub struct CreateUserAuthenticationMethodRequest {
    pub owner_id: String,
    pub owner_type: common_enums::Owner,
    pub auth_method: AuthConfig,
    pub allow_signup: bool,
    pub email_domain: Option<String>,
}


pub struct UrlDetails {
    pub success_url: String,
    pub failure_url: String,
    pub pending_url: String,
}


impl api::Refund for Custombilling {}


pub struct PaymentIntentMetricRow {
    pub status: Option<DBEnumWrapper<storage_enums::IntentStatus>>,
    pub currency: Option<DBEnumWrapper<storage_enums::Currency>>,
    pub profile_id: Option<String>,
    pub connector: Option<String>,
    pub authentication_type: Option<DBEnumWrapper<storage_enums::AuthenticationType>>,
    pub payment_method: Option<String>,
    pub payment_method_type: Option<String>,
    pub card_network: Option<String>,
    pub merchant_id: Option<String>,
    pub card_last_4: Option<String>,
    pub card_issuer: Option<String>,
    pub error_reason: Option<String>,
    pub first_attempt: Option<i64>,
    pub total: Option<bigdecimal::BigDecimal>,
    pub count: Option<i64>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub start_bucket: Option<PrimitiveDateTime>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub end_bucket: Option<PrimitiveDateTime>,
}


impl<'a> NetworkTokenizationBuilder<'a, CardStored> {
    pub fn set_stored_token_response(
        self,
        store_token_response: &'a StoreLockerResponse,
    ) -> NetworkTokenizationBuilder<'a, CardTokenStored> {
        NetworkTokenizationBuilder {
            state: std::marker::PhantomData,
            card_tokenized: true,
            stored_token: Some(&store_token_response.store_token_resp),
            customer: self.customer,
            card: self.card,
            card_cvc: self.card_cvc,
            network_token: self.network_token,
            stored_card: self.stored_card,
            payment_method_response: self.payment_method_response,
            error_code: self.error_code,
            error_message: self.error_message,
        }
    }
}


impl DummySignal {
    /// Dummy handler for signals in windows (empty)
    pub fn handle(&self) -> Self {
        self.clone()
    }

    /// Hollow implementation, for windows compatibility
    pub fn close(self) {}
}


impl api::RefundExecute for Nuvei {}


pub struct SmartRetriedAmountAccumulator {
    pub amount: Option<i64>,
    pub amount_without_retries: Option<i64>,
}


impl FeatureMatrix {
    pub fn server(state: AppState) -> Scope {
        web::scope("/feature_matrix")
            .app_data(web::Data::new(state))
            .service(web::resource("").route(web::get().to(feature_matrix::fetch_feature_matrix)))
    }
}


pub async fn perform_locking_action<A>(
        self,
        state: &A,
        merchant_id: common_utils::id_type::MerchantId,
    ) -> RouterResult<()>
    where
        A: SessionStateInfo,
    {
        match self {
            Self::HoldMultiple { inputs } => {
                let lock_retries = inputs
                    .iter()
                    .find_map(|input| input.override_lock_retries)
                    .unwrap_or(state.conf().lock_settings.lock_retries);
                let request_id = state.get_request_id();
                let redis_lock_expiry_seconds =
                    state.conf().lock_settings.redis_lock_expiry_seconds;
                let redis_conn = state
                    .store()
                    .get_redis_conn()
                    .change_context(errors::ApiErrorResponse::InternalServerError)?;
                let redis_key_values = inputs
                    .iter()
                    .map(|input| input.get_redis_locking_key(&merchant_id))
                    .map(|key| (RedisKey::from(key.as_str()), request_id.clone()))
                    .collect::<Vec<_>>();
                for _retry in 0..lock_retries {
                    let results: Vec<redis::SetGetReply<_>> = redis_conn
                        .set_multiple_keys_if_not_exists_and_get_values(
                            &redis_key_values,
                            Some(i64::from(redis_lock_expiry_seconds)),
                        )
                        .await
                        .change_context(errors::ApiErrorResponse::InternalServerError)?;
                    let lock_aqcuired = results.iter().all(|res| {
                        // each redis value must match the request_id
                        // if even 1 does match, the lock is not acquired
                        *res.get_value() == request_id
                    });
                    if lock_aqcuired {
                        logger::info!("Lock acquired for locking inputs {:?}", inputs);
                        return Ok(());
                    }
                }
                Err(report!(errors::ApiErrorResponse::ResourceBusy))
            }
            Self::Hold { input } => {
                let redis_conn = state
                    .store()
                    .get_redis_conn()
                    .change_context(errors::ApiErrorResponse::InternalServerError)?;

                let redis_locking_key = input.get_redis_locking_key(&merchant_id);
                let delay_between_retries_in_milliseconds = state
                    .conf()
                    .lock_settings
                    .delay_between_retries_in_milliseconds;
                let redis_lock_expiry_seconds =
                    state.conf().lock_settings.redis_lock_expiry_seconds;
                let lock_retries = input
                    .override_lock_retries
                    .unwrap_or(state.conf().lock_settings.lock_retries);
                for _retry in 0..lock_retries {
                    let redis_lock_result = redis_conn
                        .set_key_if_not_exists_with_expiry(
                            &redis_locking_key.as_str().into(),
                            state.get_request_id(),
                            Some(i64::from(redis_lock_expiry_seconds)),
                        )
                        .await;

                    match redis_lock_result {
                        Ok(redis::SetnxReply::KeySet) => {
                            logger::info!("Lock acquired for locking input {:?}", input);
                            tracing::Span::current()
                                .record("redis_lock_acquired", redis_locking_key);
                            return Ok(());
                        }
                        Ok(redis::SetnxReply::KeyNotSet) => {
                            logger::info!(
                                "Lock busy by other request when tried for locking input {:?}",
                                input
                            );
                            actix_time::sleep(tokio::time::Duration::from_millis(u64::from(
                                delay_between_retries_in_milliseconds,
                            )))
                            .await;
                        }
                        Err(err) => {
                            return Err(err)
                                .change_context(errors::ApiErrorResponse::InternalServerError)
                        }
                    }
                }

                Err(report!(errors::ApiErrorResponse::ResourceBusy))
            }
            Self::QueueWithOk | Self::Drop | Self::NotApplicable => Ok(()),
        }
    }


pub async fn decide_action_type(
    state: &SessionState,
    is_connector_agnostic_mit_enabled: Option<bool>,
    is_network_tokenization_enabled: bool,
    payment_method_info: &domain::PaymentMethod,
    filtered_nt_supported_connectors: Vec<api::ConnectorRoutingData>, //network tokenization supported connectors
) -> Option<ActionType> {
    match (
        is_network_token_with_network_transaction_id_flow(
            is_connector_agnostic_mit_enabled,
            is_network_tokenization_enabled,
            payment_method_info,
        ),
        !filtered_nt_supported_connectors.is_empty(),
    ) {
        (IsNtWithNtiFlow::NtWithNtiSupported(network_transaction_id), true) => {
            if let Ok((token_exp_month, token_exp_year)) =
                network_tokenization::do_status_check_for_network_token(state, payment_method_info)
                    .await
            {
                Some(ActionType::NetworkTokenWithNetworkTransactionId(
                    NTWithNTIRef {
                        token_exp_month,
                        token_exp_year,
                        network_transaction_id,
                    },
                ))
            } else {
                None
            }
        }
        (IsNtWithNtiFlow::NtWithNtiSupported(_), false)
        | (IsNtWithNtiFlow::NTWithNTINotSupported, _) => None,
    }
}


OpenAPI Block Path: paths."/account/{account_id}/business_profile/{profile_id}/dynamic_routing/success_based/toggle"
{
  "post": {
    "tags": [
      "Routing"
    ],
    "summary": "Routing - Toggle success based dynamic routing for profile",
    "description": "Create a success based dynamic routing algorithm",
    "operationId": "Toggle success based dynamic routing algorithm",
    "parameters": [
      {
        "name": "account_id",
        "in": "path",
        "description": "Merchant id",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      {
        "name": "profile_id",
        "in": "path",
        "description": "Profile id under which Dynamic routing needs to be toggled",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      {
        "name": "enable",
        "in": "query",
        "description": "Feature to enable for success based routing",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/DynamicRoutingFeatures"
        }
      }
    ],
    "responses": {
      "200": {
        "description": "Routing Algorithm created",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RoutingDictionaryRecord"
            }
          }
        }
      },
      "400": {
        "description": "Request body is malformed"
      },
      "403": {
        "description": "Forbidden"
      },
      "404": {
        "description": "Resource missing"
      },
      "422": {
        "description": "Unprocessable request"
      },
      "500": {
        "description": "Internal server error"
      }
    },
    "security": [
      {
        "api_key": []
      },
      {
        "jwt_key": []
      }
    ]
  }
}


pub struct AwsSes {
    sender: String,
    ses_config: SESConfig,
    settings: EmailSettings,
}


pub struct MerchantInitiatedTransaction {
    reason: Option<String>,
    previous_transaction_id: Option<Secret<String>>,
    //Required for recurring mandates payment
    original_authorized_amount: Option<String>,
}


pub async fn add_card_to_hs_locker(
    state: &routes::SessionState,
    payload: &payment_methods::StoreLockerReq,
    customer_id: &id_type::CustomerId,
    locker_choice: api_enums::LockerChoice,
) -> errors::CustomResult<payment_methods::StoreCardRespPayload, errors::VaultError> {
    let locker = &state.conf.locker;
    let jwekey = state.conf.jwekey.get_inner();
    let db = &*state.store;
    let stored_card_response = if !locker.mock_locker {
        let request = payment_methods::mk_add_locker_request_hs(
            jwekey,
            locker,
            payload,
            locker_choice,
            state.tenant.tenant_id.clone(),
            state.request_id,
        )
        .await?;
        call_locker_api::<payment_methods::StoreCardResp>(
            state,
            request,
            "add_card_to_hs_locker",
            Some(locker_choice),
        )
        .await
        .change_context(errors::VaultError::SaveCardFailed)?
    } else {
        let card_id = generate_id(consts::ID_LENGTH, "card");
        mock_call_to_locker_hs(db, &card_id, payload, None, None, Some(customer_id)).await?
    };

    let stored_card = stored_card_response
        .payload
        .get_required_value("StoreCardRespPayload")
        .change_context(errors::VaultError::SaveCardFailed)?;
    Ok(stored_card)
}


File: crates/diesel_models/src/api_keys.rs
 Public functions: 1
 Public structs: 4

use diesel::{AsChangeset, AsExpression, Identifiable, Insertable, Queryable, Selectable};
use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;

use crate::schema::api_keys;

#[derive(
    serde::Serialize, serde::Deserialize, Debug, Clone, Identifiable, Queryable, Selectable,
)]
#[diesel(table_name = api_keys, primary_key(key_id), check_for_backend(diesel::pg::Pg))]
pub struct ApiKey {
    pub key_id: common_utils::id_type::ApiKeyId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub name: String,
    pub description: Option<String>,
    pub hashed_api_key: HashedApiKey,
    pub prefix: String,
    pub created_at: PrimitiveDateTime,
    pub expires_at: Option<PrimitiveDateTime>,
    pub last_used: Option<PrimitiveDateTime>,
}

#[derive(Debug, Insertable)]
#[diesel(table_name = api_keys)]
pub struct ApiKeyNew {
    pub key_id: common_utils::id_type::ApiKeyId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub name: String,
    pub description: Option<String>,
    pub hashed_api_key: HashedApiKey,
    pub prefix: String,
    pub created_at: PrimitiveDateTime,
    pub expires_at: Option<PrimitiveDateTime>,
    pub last_used: Option<PrimitiveDateTime>,
}

#[derive(Debug)]
pub enum ApiKeyUpdate {
    Update {
        name: Option<String>,
        description: Option<String>,
        expires_at: Option<Option<PrimitiveDateTime>>,
        last_used: Option<PrimitiveDateTime>,
    },
    LastUsedUpdate {
        last_used: PrimitiveDateTime,
    },
}

#[derive(Debug, AsChangeset)]
#[diesel(table_name = api_keys)]
pub(crate) struct ApiKeyUpdateInternal {
    pub name: Option<String>,
    pub description: Option<String>,
    pub expires_at: Option<Option<PrimitiveDateTime>>,
    pub last_used: Option<PrimitiveDateTime>,
}

impl From<ApiKeyUpdate> for ApiKeyUpdateInternal {
    fn from(api_key_update: ApiKeyUpdate) -> Self {
        match api_key_update {
            ApiKeyUpdate::Update {
                name,
                description,
                expires_at,
                last_used,
            } => Self {
                name,
                description,
                expires_at,
                last_used,
            },
            ApiKeyUpdate::LastUsedUpdate { last_used } => Self {
                last_used: Some(last_used),
                name: None,
                description: None,
                expires_at: None,
            },
        }
    }
}

#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, AsExpression, PartialEq)]
#[diesel(sql_type = diesel::sql_types::Text)]
pub struct HashedApiKey(String);

impl HashedApiKey {
    pub fn into_inner(self) -> String {
        self.0
    }
}

impl From<String> for HashedApiKey {
    fn from(hashed_api_key: String) -> Self {
        Self(hashed_api_key)
    }
}

mod diesel_impl {
    use diesel::{
        backend::Backend,
        deserialize::FromSql,
        serialize::{Output, ToSql},
        sql_types::Text,
        Queryable,
    };

    impl<DB> ToSql<Text, DB> for super::HashedApiKey
    where
        DB: Backend,
        String: ToSql<Text, DB>,
    {
        fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result {
            self.0.to_sql(out)
        }
    }

    impl<DB> FromSql<Text, DB> for super::HashedApiKey
    where
        DB: Backend,
        String: FromSql<Text, DB>,
    {
        fn from_sql(bytes: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
            Ok(Self(String::from_sql(bytes)?))
        }
    }

    impl<DB> Queryable<Text, DB> for super::HashedApiKey
    where
        DB: Backend,
        Self: FromSql<Text, DB>,
    {
        type Row = Self;

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

// Tracking data by process_tracker
#[derive(Default, Debug, Deserialize, Serialize, Clone)]
pub struct ApiKeyExpiryTrackingData {
    pub key_id: common_utils::id_type::ApiKeyId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub api_key_name: String,
    pub prefix: String,
    pub api_key_expiry: Option<PrimitiveDateTime>,
    // Days on which email reminder about api_key expiry has to be sent, prior to it's expiry.
    pub expiry_reminder_days: Vec<u8>,
}


pub struct StoredCredential {
    /// Indicates the transaction processing model being executed when using stored
    /// credentials.
    pub model: Option<Model>,
    /// Indicates the order of this transaction in the sequence of a planned repeating
    /// transaction processing model.
    pub sequence: Option<Sequence>,
}


OpenAPI Block Path: components.schemas.Method
{
  "type": "string",
  "enum": [
    "GET",
    "POST",
    "PUT",
    "DELETE",
    "PATCH"
  ]
}


impl<T: opentelemetry_sdk::trace::ShouldSample + Clone + 'static>
    opentelemetry_sdk::trace::ShouldSample for ConditionalSampler<T>
{
    fn should_sample(
        &self,
        parent_context: Option<&opentelemetry::Context>,
        trace_id: opentelemetry::trace::TraceId,
        name: &str,
        span_kind: &opentelemetry::trace::SpanKind,
        attributes: &[opentelemetry::KeyValue],
        links: &[opentelemetry::trace::Link],
    ) -> opentelemetry::trace::SamplingResult {
        use opentelemetry::trace::TraceContextExt;

        match attributes
            .iter()
            .find(|&kv| kv.key == opentelemetry::Key::new("http.route"))
            .map_or(self.0.default, |inner| {
                self.0.should_trace_url(&inner.value.as_str())
            }) {
            true => {
                self.1
                    .should_sample(parent_context, trace_id, name, span_kind, attributes, links)
            }
            false => opentelemetry::trace::SamplingResult {
                decision: opentelemetry::trace::SamplingDecision::Drop,
                attributes: Vec::new(),
                trace_state: match parent_context {
                    Some(ctx) => ctx.span().span_context().trace_state().clone(),
                    None => opentelemetry::trace::TraceState::default(),
                },
            },
        }
    }
}

impl opentelemetry_sdk::trace::ShouldSample for for ConditionalSampler


pub async fn retry_delete_tokenize(
    db: &dyn db::StorageInterface,
    pm: enums::PaymentMethod,
    pt: storage::ProcessTracker,
) -> Result<(), errors::ProcessTrackerError> {
    let schedule_time = get_delete_tokenize_schedule_time(db, pm, pt.retry_count).await;

    match schedule_time {
        Some(s_time) => {
            let retry_schedule = db
                .as_scheduler()
                .retry_process(pt, s_time)
                .await
                .map_err(Into::into);
            metrics::TASKS_RESET_COUNT.add(
                1,
                router_env::metric_attributes!(("flow", "DeleteTokenizeData")),
            );
            retry_schedule
        }
        None => db
            .as_scheduler()
            .finish_process_with_business_status(
                pt,
                diesel_models::process_tracker::business_status::RETRIES_EXCEEDED,
            )
            .await
            .map_err(Into::into),
    }
}


impl api::PaymentCapture for Coinbase {}

impl api::PaymentCapture for for Coinbase


impl api::MandateSetup for Wellsfargopayout {}

impl api::MandateSetup for for Wellsfargopayout


pub async fn upload_file_to_theme_storage(
    state: SessionState,
    theme_id: String,
    request: theme_api::UploadFileRequest,
) -> UserResponse<()> {
    let db_theme = state
        .store
        .find_theme_by_theme_id(theme_id)
        .await
        .to_not_found_response(UserErrors::ThemeNotFound)?;

    theme_utils::upload_file_to_theme_bucket(
        &state,
        &theme_utils::get_specific_file_key(&db_theme.theme_id, &request.asset_name),
        request.asset_data.expose(),
    )
    .await?;

    Ok(ApplicationResponse::StatusOk)
}


impl MerchantConnectorResponse {
    pub fn to_merchant_connector_info(&self, connector_label: &String) -> MerchantConnectorInfo {
        MerchantConnectorInfo {
            connector_label: connector_label.to_string(),
            merchant_connector_id: self.merchant_connector_id.clone(),
        }
    }
}


pub struct BarclaycardErrorInformation {
    reason: Option<String>,
    message: Option<String>,
    details: Option<Vec<Details>>,
}


pub struct XenditSplitRequestData {
    #[serde(flatten)]
    pub split_data: XenditSplitRequest,
}


pub async fn internal_trigger_refund_to_gateway(
    state: &SessionState,
    refund: &diesel_refund::Refund,
    merchant_context: &domain::MerchantContext,
    payment_attempt: &storage::PaymentAttempt,
    payment_intent: &storage::PaymentIntent,
    merchant_connector_details: common_types::domain::MerchantConnectorAuthDetails,
) -> errors::RouterResult<diesel_refund::Refund> {
    let storage_scheme = merchant_context.get_merchant_account().storage_scheme;

    let routed_through = payment_attempt
        .connector
        .clone()
        .ok_or(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to retrieve connector from payment attempt")?;

    metrics::REFUND_COUNT.add(
        1,
        router_env::metric_attributes!(("connector", routed_through.clone())),
    );

    let connector_enum = merchant_connector_details.connector_name;

    let connector: api::ConnectorData = api::ConnectorData::get_connector_by_name(
        &state.conf.connectors,
        &connector_enum.to_string(),
        api::GetToken::Connector,
        None,
    )?;

    refunds_validator::validate_for_valid_refunds(payment_attempt, connector.connector_name)?;

    let merchant_connector_account =
        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorDetails(
            merchant_connector_details,
        );

    let mut router_data = core_utils::construct_refund_router_data(
        state,
        connector_enum,
        merchant_context,
        payment_intent,
        payment_attempt,
        refund,
        &merchant_connector_account,
    )
    .await?;

    let add_access_token_result = Box::pin(access_token::add_access_token(
        state,
        &connector,
        merchant_context,
        &router_data,
        None,
    ))
    .await?;

    access_token::update_router_data_with_access_token_result(
        &add_access_token_result,
        &mut router_data,
        &payments::CallConnectorAction::Trigger,
    );

    let connector_response = Box::pin(call_connector_service(
        state,
        &connector,
        add_access_token_result,
        router_data,
    ))
    .await;

    let refund_update = get_refund_update_object(
        state,
        &connector,
        &storage_scheme,
        merchant_context,
        &connector_response,
    )
    .await;

    let response = match refund_update {
        Some(refund_update) => state
            .store
            .update_refund(
                refund.to_owned(),
                refund_update,
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::InternalServerError)
            .attach_printable_lazy(|| {
                format!(
                    "Failed while updating refund: refund_id: {}",
                    refund.id.get_string_repr()
                )
            })?,
        None => refund.to_owned(),
    };
    // Implement outgoing webhooks here
    connector_response.to_refund_failed_response()?;
    Ok(response)
}