pub struct AuthenticatePaymentFlowResponse {
    pub payments_response: api_models::payments::PaymentsResponse,
    pub poll_config: PollConfig,
    pub business_profile: domain::Profile,
}


impl api::PaymentSync for Razorpay {}


pub fn get_mut(&mut self, idx: K) -> Option<&mut V> {
        self.data.get_mut(idx.get_id())
    }


pub struct RapydPaymentsRequest {
    pub amount: FloatMajorUnit,
    pub currency: enums::Currency,
    pub payment_method: PaymentMethod,
    pub payment_method_options: Option<PaymentMethodOptions>,
    pub merchant_reference_id: Option<String>,
    pub capture: Option<bool>,
    pub description: Option<String>,
    pub complete_payment_url: Option<String>,
    pub error_payment_url: Option<String>,
}


pub struct StripeBillingDetails {
    pub address: Option<AddressDetails>,
    pub email: Option<Email>,
    pub name: Option<String>,
    pub phone: Option<masking::Secret<String>>,
}


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

    fn get_webhook_source_verification_signature(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let notif_item = getnet::get_webhook_response(request.body)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
        let response_base64 = &notif_item.response_base64.peek().clone();
        BASE64_ENGINE
            .decode(response_base64)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
    }

    fn get_webhook_source_verification_message(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _merchant_id: &common_utils::id_type::MerchantId,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let notif = getnet::get_webhook_response(request.body)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;

        Ok(notif.response_base64.peek().clone().into_bytes())
    }

    fn get_webhook_object_reference_id(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        let notif = getnet::get_webhook_object_from_body(request.body)
            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
        let transaction_type = &notif.payment.transaction_type;
        if getnet::is_refund_event(transaction_type) {
            Ok(api_models::webhooks::ObjectReferenceId::RefundId(
                api_models::webhooks::RefundIdType::ConnectorRefundId(
                    notif.payment.transaction_id.to_string(),
                ),
            ))
        } else {
            Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
                api_models::payments::PaymentIdType::ConnectorTransactionId(
                    notif.payment.transaction_id.to_string(),
                ),
            ))
        }
    }

    fn get_webhook_event_type(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
        let notif = getnet::get_webhook_object_from_body(request.body)
            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
        let incoming_webhook_event = getnet::get_incoming_webhook_event(
            notif.payment.transaction_type,
            notif.payment.transaction_state,
        );
        Ok(incoming_webhook_event)
    }

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

    async fn verify_webhook_source(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
        _connector_account_details: crypto::Encryptable<Secret<serde_json::Value>>,
        connector_name: &str,
    ) -> CustomResult<bool, errors::ConnectorError> {
        let notif_item = getnet::get_webhook_response(request.body)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;

        let connector_webhook_secrets = self
            .get_webhook_source_verification_merchant_secret(
                merchant_id,
                connector_name,
                connector_webhook_details,
            )
            .await?;

        let signature = notif_item.response_signature_base64.peek().clone();

        let message = self.get_webhook_source_verification_message(
            request,
            merchant_id,
            &connector_webhook_secrets,
        )?;

        let secret = connector_webhook_secrets.secret;

        let key = hmac::Key::new(hmac::HMAC_SHA256, &secret);
        let result = hmac::sign(&key, &message);

        let computed_signature = BASE64_ENGINE.encode(result.as_ref());

        let normalized_computed_signature = computed_signature.replace("+", " ");
        Ok(signature == normalized_computed_signature)
    }
}

impl webhooks::IncomingWebhook for for Getnet


pub async fn execute_query<R, P>(
        &mut self,
        store: &P,
    ) -> CustomResult<CustomResult<Vec<R>, QueryExecutionError>, QueryBuildingError>
    where
        P: LoadRow<R> + AnalyticsDataSource,
        Aggregate<&'static str>: ToSql<T>,
        Window<&'static str>: ToSql<T>,
    {
        let query = self
            .build_query()
            .change_context(QueryBuildingError::SqlSerializeError)
            .attach_printable("Failed to execute query")?;

        Ok(store.load_results(query.as_str()).await)
    }


pub struct ZenWebhookBody {
    #[serde(rename = "transactionId")]
    pub id: String,
    pub merchant_transaction_id: String,
    pub amount: String,
    pub currency: String,
    pub status: ZenPaymentStatus,
}


File: crates/router/src/services/kafka/payment_intent_event.rs
 Public functions: 4
 Public structs: 2

#[cfg(feature = "v2")]
use ::common_types::{payments, primitive_wrappers::RequestExtendedAuthorizationBool};
#[cfg(feature = "v2")]
use common_enums::{self, RequestIncrementalAuthorization};
use common_utils::{
    crypto::Encryptable, hashing::HashedString, id_type, pii, types as common_types,
};
use diesel_models::enums as storage_enums;
#[cfg(feature = "v2")]
use diesel_models::{types as diesel_types, PaymentLinkConfigRequestForPayments};
#[cfg(feature = "v2")]
use diesel_models::{types::OrderDetailsWithAmount, TaxDetails};
use hyperswitch_domain_models::payments::PaymentIntent;
#[cfg(feature = "v2")]
use hyperswitch_domain_models::{address, routing};
use masking::{PeekInterface, Secret};
use serde_json::Value;
use time::OffsetDateTime;

#[cfg(feature = "v1")]
#[serde_with::skip_serializing_none]
#[derive(serde::Serialize, Debug)]
pub struct KafkaPaymentIntentEvent<'a> {
    pub payment_id: &'a id_type::PaymentId,
    pub merchant_id: &'a id_type::MerchantId,
    pub status: storage_enums::IntentStatus,
    pub amount: common_types::MinorUnit,
    pub currency: Option<storage_enums::Currency>,
    pub amount_captured: Option<common_types::MinorUnit>,
    pub customer_id: Option<&'a id_type::CustomerId>,
    pub description: Option<&'a String>,
    pub return_url: Option<&'a String>,
    pub metadata: Option<String>,
    pub connector_id: Option<&'a String>,
    pub statement_descriptor_name: Option<&'a String>,
    pub statement_descriptor_suffix: Option<&'a String>,
    #[serde(with = "time::serde::timestamp::nanoseconds")]
    pub created_at: OffsetDateTime,
    #[serde(with = "time::serde::timestamp::nanoseconds")]
    pub modified_at: OffsetDateTime,
    #[serde(default, with = "time::serde::timestamp::nanoseconds::option")]
    pub last_synced: Option<OffsetDateTime>,
    pub setup_future_usage: Option<storage_enums::FutureUsage>,
    pub off_session: Option<bool>,
    pub client_secret: Option<&'a String>,
    pub active_attempt_id: String,
    pub business_country: Option<storage_enums::CountryAlpha2>,
    pub business_label: Option<&'a String>,
    pub attempt_count: i16,
    pub profile_id: Option<&'a id_type::ProfileId>,
    pub payment_confirm_source: Option<storage_enums::PaymentSource>,
    pub billing_details: Option<Encryptable<Secret<Value>>>,
    pub shipping_details: Option<Encryptable<Secret<Value>>>,
    pub customer_email: Option<HashedString<pii::EmailStrategy>>,
    pub feature_metadata: Option<&'a Value>,
    pub merchant_order_reference_id: Option<&'a String>,
    pub organization_id: &'a id_type::OrganizationId,
    #[serde(flatten)]
    pub infra_values: Option<Value>,
}

#[cfg(feature = "v2")]
#[serde_with::skip_serializing_none]
#[derive(serde::Serialize, Debug)]
pub struct KafkaPaymentIntentEvent<'a> {
    pub payment_id: &'a id_type::GlobalPaymentId,
    pub merchant_id: &'a id_type::MerchantId,
    pub status: storage_enums::IntentStatus,
    pub amount: common_types::MinorUnit,
    pub currency: storage_enums::Currency,
    pub amount_captured: Option<common_types::MinorUnit>,
    pub customer_id: Option<&'a id_type::GlobalCustomerId>,
    pub description: Option<&'a common_types::Description>,
    pub return_url: Option<&'a common_types::Url>,
    pub metadata: Option<&'a Secret<Value>>,
    pub statement_descriptor: Option<&'a common_types::StatementDescriptor>,
    #[serde(with = "time::serde::timestamp::nanoseconds")]
    pub created_at: OffsetDateTime,
    #[serde(with = "time::serde::timestamp::nanoseconds")]
    pub modified_at: OffsetDateTime,
    #[serde(default, with = "time::serde::timestamp::nanoseconds::option")]
    pub last_synced: Option<OffsetDateTime>,
    pub setup_future_usage: storage_enums::FutureUsage,
    pub off_session: bool,
    pub active_attempt_id: Option<&'a id_type::GlobalAttemptId>,
    pub attempt_count: i16,
    pub profile_id: &'a id_type::ProfileId,
    pub customer_email: Option<HashedString<pii::EmailStrategy>>,
    pub feature_metadata: Option<&'a diesel_types::FeatureMetadata>,
    pub organization_id: &'a id_type::OrganizationId,
    pub order_details: Option<&'a Vec<Secret<OrderDetailsWithAmount>>>,

    pub allowed_payment_method_types: Option<&'a Vec<common_enums::PaymentMethodType>>,
    pub connector_metadata: Option<&'a Secret<Value>>,
    pub payment_link_id: Option<&'a String>,
    pub updated_by: &'a String,
    pub surcharge_applicable: Option<bool>,
    pub request_incremental_authorization: RequestIncrementalAuthorization,
    pub split_txns_enabled: common_enums::SplitTxnsEnabled,
    pub authorization_count: Option<i32>,
    #[serde(with = "time::serde::timestamp::nanoseconds")]
    pub session_expiry: OffsetDateTime,
    pub request_external_three_ds_authentication: common_enums::External3dsAuthenticationRequest,
    pub frm_metadata: Option<Secret<&'a Value>>,
    pub customer_details: Option<Secret<&'a Value>>,
    pub shipping_cost: Option<common_types::MinorUnit>,
    pub tax_details: Option<TaxDetails>,
    pub skip_external_tax_calculation: bool,
    pub request_extended_authorization: Option<RequestExtendedAuthorizationBool>,
    pub psd2_sca_exemption_type: Option<storage_enums::ScaExemptionType>,
    pub split_payments: Option<&'a payments::SplitPaymentsRequest>,
    pub platform_merchant_id: Option<&'a id_type::MerchantId>,
    pub force_3ds_challenge: Option<bool>,
    pub force_3ds_challenge_trigger: Option<bool>,
    pub processor_merchant_id: &'a id_type::MerchantId,
    pub created_by: Option<&'a common_types::CreatedBy>,
    pub is_iframe_redirection_enabled: Option<bool>,
    pub merchant_reference_id: Option<&'a id_type::PaymentReferenceId>,
    pub capture_method: storage_enums::CaptureMethod,
    pub authentication_type: Option<common_enums::AuthenticationType>,
    pub prerouting_algorithm: Option<&'a routing::PaymentRoutingInfo>,
    pub surcharge_amount: Option<common_types::MinorUnit>,
    pub billing_address: Option<Secret<&'a address::Address>>,
    pub shipping_address: Option<Secret<&'a address::Address>>,
    pub tax_on_surcharge: Option<common_types::MinorUnit>,
    pub frm_merchant_decision: Option<common_enums::MerchantDecision>,
    pub enable_payment_link: common_enums::EnablePaymentLinkRequest,
    pub apply_mit_exemption: common_enums::MitExemptionRequest,
    pub customer_present: common_enums::PresenceOfCustomerDuringPayment,
    pub routing_algorithm_id: Option<&'a id_type::RoutingId>,
    pub payment_link_config: Option<&'a PaymentLinkConfigRequestForPayments>,

    #[serde(flatten)]
    infra_values: Option<Value>,
}

impl KafkaPaymentIntentEvent<'_> {
    #[cfg(feature = "v1")]
    pub fn get_id(&self) -> &id_type::PaymentId {
        self.payment_id
    }

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

#[cfg(feature = "v1")]
impl<'a> KafkaPaymentIntentEvent<'a> {
    pub fn from_storage(intent: &'a PaymentIntent, infra_values: Option<Value>) -> Self {
        Self {
            payment_id: &intent.payment_id,
            merchant_id: &intent.merchant_id,
            status: intent.status,
            amount: intent.amount,
            currency: intent.currency,
            amount_captured: intent.amount_captured,
            customer_id: intent.customer_id.as_ref(),
            description: intent.description.as_ref(),
            return_url: intent.return_url.as_ref(),
            metadata: intent.metadata.as_ref().map(|x| x.to_string()),
            connector_id: intent.connector_id.as_ref(),
            statement_descriptor_name: intent.statement_descriptor_name.as_ref(),
            statement_descriptor_suffix: intent.statement_descriptor_suffix.as_ref(),
            created_at: intent.created_at.assume_utc(),
            modified_at: intent.modified_at.assume_utc(),
            last_synced: intent.last_synced.map(|i| i.assume_utc()),
            setup_future_usage: intent.setup_future_usage,
            off_session: intent.off_session,
            client_secret: intent.client_secret.as_ref(),
            active_attempt_id: intent.active_attempt.get_id(),
            business_country: intent.business_country,
            business_label: intent.business_label.as_ref(),
            attempt_count: intent.attempt_count,
            profile_id: intent.profile_id.as_ref(),
            payment_confirm_source: intent.payment_confirm_source,
            // TODO: use typed information here to avoid PII logging
            billing_details: None,
            shipping_details: None,
            customer_email: intent
                .customer_details
                .as_ref()
                .and_then(|value| value.get_inner().peek().as_object())
                .and_then(|obj| obj.get("email"))
                .and_then(|email| email.as_str())
                .map(|email| HashedString::from(Secret::new(email.to_string()))),
            feature_metadata: intent.feature_metadata.as_ref(),
            merchant_order_reference_id: intent.merchant_order_reference_id.as_ref(),
            organization_id: &intent.organization_id,
            infra_values: infra_values.clone(),
        }
    }
}

#[cfg(feature = "v2")]
impl<'a> KafkaPaymentIntentEvent<'a> {
    pub fn from_storage(intent: &'a PaymentIntent, infra_values: Option<Value>) -> Self {
        let PaymentIntent {
            id,
            merchant_id,
            status,
            amount_details,
            amount_captured,
            customer_id,
            description,
            return_url,
            metadata,
            statement_descriptor,
            created_at,
            modified_at,
            last_synced,
            setup_future_usage,
            active_attempt_id,
            order_details,
            allowed_payment_method_types,
            connector_metadata,
            feature_metadata,
            attempt_count,
            profile_id,
            payment_link_id,
            frm_merchant_decision,
            updated_by,
            request_incremental_authorization,
            split_txns_enabled,
            authorization_count,
            session_expiry,
            request_external_three_ds_authentication,
            frm_metadata,
            customer_details,
            merchant_reference_id,
            billing_address,
            shipping_address,
            capture_method,
            authentication_type,
            prerouting_algorithm,
            organization_id,
            enable_payment_link,
            apply_mit_exemption,
            customer_present,
            payment_link_config,
            routing_algorithm_id,
            split_payments,
            force_3ds_challenge,
            force_3ds_challenge_trigger,
            processor_merchant_id,
            created_by,
            is_iframe_redirection_enabled,
            is_payment_id_from_merchant,
        } = intent;

        Self {
            payment_id: id,
            merchant_id,
            status: *status,
            amount: amount_details.order_amount,
            currency: amount_details.currency,
            amount_captured: *amount_captured,
            customer_id: customer_id.as_ref(),
            description: description.as_ref(),
            return_url: return_url.as_ref(),
            metadata: metadata.as_ref(),
            statement_descriptor: statement_descriptor.as_ref(),
            created_at: created_at.assume_utc(),
            modified_at: modified_at.assume_utc(),
            last_synced: last_synced.map(|t| t.assume_utc()),
            setup_future_usage: *setup_future_usage,
            off_session: setup_future_usage.is_off_session(),
            active_attempt_id: active_attempt_id.as_ref(),
            attempt_count: *attempt_count,
            profile_id,
            customer_email: None,
            feature_metadata: feature_metadata.as_ref(),
            organization_id,
            order_details: order_details.as_ref(),
            allowed_payment_method_types: allowed_payment_method_types.as_ref(),
            connector_metadata: connector_metadata.as_ref(),
            payment_link_id: payment_link_id.as_ref(),
            updated_by,
            surcharge_applicable: None,
            request_incremental_authorization: *request_incremental_authorization,
            split_txns_enabled: *split_txns_enabled,
            authorization_count: *authorization_count,
            session_expiry: session_expiry.assume_utc(),
            request_external_three_ds_authentication: *request_external_three_ds_authentication,
            frm_metadata: frm_metadata
                .as_ref()
                .map(|frm_metadata| frm_metadata.as_ref()),
            customer_details: customer_details
                .as_ref()
                .map(|customer_details| customer_details.get_inner().as_ref()),
            shipping_cost: amount_details.shipping_cost,
            tax_details: amount_details.tax_details.clone(),
            skip_external_tax_calculation: amount_details.get_external_tax_action_as_bool(),
            request_extended_authorization: None,
            psd2_sca_exemption_type: None,
            split_payments: split_payments.as_ref(),
            platform_merchant_id: None,
            force_3ds_challenge: *force_3ds_challenge,
            force_3ds_challenge_trigger: *force_3ds_challenge_trigger,
            processor_merchant_id,
            created_by: created_by.as_ref(),
            is_iframe_redirection_enabled: *is_iframe_redirection_enabled,
            merchant_reference_id: merchant_reference_id.as_ref(),
            billing_address: billing_address
                .as_ref()
                .map(|billing_address| Secret::new(billing_address.get_inner())),
            shipping_address: shipping_address
                .as_ref()
                .map(|shipping_address| Secret::new(shipping_address.get_inner())),
            capture_method: *capture_method,
            authentication_type: *authentication_type,
            prerouting_algorithm: prerouting_algorithm.as_ref(),
            surcharge_amount: amount_details.surcharge_amount,
            tax_on_surcharge: amount_details.tax_on_surcharge,
            frm_merchant_decision: *frm_merchant_decision,
            enable_payment_link: *enable_payment_link,
            apply_mit_exemption: *apply_mit_exemption,
            customer_present: *customer_present,
            routing_algorithm_id: routing_algorithm_id.as_ref(),
            payment_link_config: payment_link_config.as_ref(),
            infra_values,
        }
    }
}

impl super::KafkaMessage for KafkaPaymentIntentEvent<'_> {
    fn key(&self) -> String {
        format!(
            "{}_{}",
            self.merchant_id.get_string_repr(),
            self.get_id().get_string_repr(),
        )
    }

    fn event_type(&self) -> crate::events::EventType {
        crate::events::EventType::PaymentIntent
    }
}


macro_rules! impl_entity {
    ($name:ident) => {
        impl $crate::dense_map::EntityId for $name {
            #[inline]
            fn get_id(&self) -> usize {
                self.0
            }

            #[inline]
            fn with_id(id: usize) -> Self {
                Self(id)
            }
        }
    };
}


pub fn comparison_type(input: &str) -> ParseResult<&str, ast::ComparisonType> {
    error::context(
        "comparison_operator",
        combinator::map_res(
            branch::alt((
                complete::tag("/="),
                complete::tag(">="),
                complete::tag("<="),
                complete::tag("="),
                complete::tag(">"),
                complete::tag("<"),
            )),
            |s: &str| match s {
                "/=" => Ok(ast::ComparisonType::NotEqual),
                ">=" => Ok(ast::ComparisonType::GreaterThanEqual),
                "<=" => Ok(ast::ComparisonType::LessThanEqual),
                "=" => Ok(ast::ComparisonType::Equal),
                ">" => Ok(ast::ComparisonType::GreaterThan),
                "<" => Ok(ast::ComparisonType::LessThan),
                _ => Err(EuclidError::InvalidOperator(s.to_string())),
            },
        ),
    )(input)
}


pub struct DecisionEngineSRSubLevelInputConfig {
    pub payment_method_type: Option<String>,
    pub payment_method: Option<String>,
    pub latency_threshold: Option<f64>,
    pub bucket_size: Option<i32>,
    pub hedging_percent: Option<f64>,
    pub lower_reset_factor: Option<f64>,
    pub upper_reset_factor: Option<f64>,
    pub gateway_extra_score: Option<Vec<DecisionEngineGatewayWiseExtraScore>>,
}


impl api::PaymentAuthorize for Opennode {}

impl api::PaymentAuthorize for for Opennode


pub struct Wise {
    #[cfg(feature = "payouts")]
    amount_converter: &'static (dyn AmountConvertor<Output = FloatMajorUnit> + Sync),
}


OpenAPI Block Path: components.schemas.CustomerPaymentMethod
{
  "type": "object",
  "required": [
    "payment_token",
    "payment_method_id",
    "customer_id",
    "payment_method",
    "requires_cvv",
    "default_payment_method_set"
  ],
  "properties": {
    "payment_token": {
      "type": "string",
      "description": "Token for payment method in temporary card locker which gets refreshed often",
      "example": "7ebf443f-a050-4067-84e5-e6f6d4800aef"
    },
    "payment_method_id": {
      "type": "string",
      "description": "The unique identifier of the customer.",
      "example": "pm_iouuy468iyuowqs"
    },
    "customer_id": {
      "type": "string",
      "description": "The unique identifier of the customer.",
      "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44",
      "maxLength": 64,
      "minLength": 1
    },
    "payment_method": {
      "$ref": "#/components/schemas/PaymentMethod"
    },
    "payment_method_type": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentMethodType"
        }
      ],
      "nullable": true
    },
    "payment_method_issuer": {
      "type": "string",
      "description": "The name of the bank/ provider issuing the payment method to the end user",
      "example": "Citibank",
      "nullable": true
    },
    "payment_method_issuer_code": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentMethodIssuerCode"
        }
      ],
      "nullable": true
    },
    "recurring_enabled": {
      "type": "boolean",
      "description": "Indicates whether the payment method supports recurring payments. Optional.",
      "example": true,
      "nullable": true
    },
    "installment_payment_enabled": {
      "type": "boolean",
      "description": "Indicates whether the payment method is eligible for installment payments (e.g., EMI, BNPL). Optional.",
      "example": true,
      "nullable": true
    },
    "payment_experience": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/PaymentExperience"
      },
      "description": "Type of payment experience enabled with the connector",
      "example": [
        "redirect_to_url"
      ],
      "nullable": true
    },
    "card": {
      "allOf": [
        {
          "$ref": "#/components/schemas/CardDetailFromLocker"
        }
      ],
      "nullable": true
    },
    "metadata": {
      "type": "object",
      "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.",
      "nullable": true
    },
    "created": {
      "type": "string",
      "format": "date-time",
      "description": "A timestamp (ISO 8601 code) that determines when the payment method was created",
      "example": "2023-01-18T11:04:09.922Z",
      "nullable": true
    },
    "bank_transfer": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Bank"
        }
      ],
      "nullable": true
    },
    "bank": {
      "allOf": [
        {
          "$ref": "#/components/schemas/MaskedBankDetails"
        }
      ],
      "nullable": true
    },
    "surcharge_details": {
      "allOf": [
        {
          "$ref": "#/components/schemas/SurchargeDetailsResponse"
        }
      ],
      "nullable": true
    },
    "requires_cvv": {
      "type": "boolean",
      "description": "Whether this payment method requires CVV to be collected",
      "example": true
    },
    "last_used_at": {
      "type": "string",
      "format": "date-time",
      "description": "A timestamp (ISO 8601 code) that determines when the payment method was last used",
      "example": "2024-02-24T11:04:09.922Z",
      "nullable": true
    },
    "default_payment_method_set": {
      "type": "boolean",
      "description": "Indicates if the payment method has been set to default or not",
      "example": true
    },
    "billing": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Address"
        }
      ],
      "nullable": true
    }
  }
}


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

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

impl ConnectorSpecifications for for Chargebee


            common_enums::CardNetwork::JCB,
            common_enums::CardNetwork::DinersClub,
            common_enums::CardNetwork::UnionPay,
            common_enums::CardNetwork::Discover,
            common_enums::CardNetwork::CartesBancaires,
            common_enums::CardNetwork::Interac,
        ];

        let mut novalnet_supported_payment_methods = SupportedPaymentMethods::new();

        novalnet_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(),
                        }
                    }),
                ),
            },
        );

        novalnet_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(),
                        }
                    }),
                ),
            },
        );

        novalnet_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, // three-ds needed for googlepay
            },
        );

        novalnet_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,
            },
        );

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

        novalnet_supported_payment_methods
    });

static NOVALNET_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Novalnet",
    description: "Novalnet provides tailored, data-driven payment solutions that maximize acceptance, boost conversions, and deliver seamless customer experiences worldwide.",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Live,
};

static NOVALNET_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 4] = [
    enums::EventClass::Payments,
    enums::EventClass::Refunds,
    enums::EventClass::Disputes,
    enums::EventClass::Mandates,
];

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

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

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


pub async fn find_by_profile_id_connector_transaction_id(
        conn: &PgPooledConn,
        profile_id: &common_utils::id_type::ProfileId,
        connector_txn_id: &str,
    ) -> StorageResult<Self> {
        let (txn_id, txn_data) = common_utils::types::ConnectorTransactionId::form_id_and_data(
            connector_txn_id.to_string(),
        );
        let connector_transaction_id = txn_id
            .get_txn_id(txn_data.as_ref())
            .change_context(DatabaseError::Others)
            .attach_printable_lazy(|| {
                format!("Failed to retrieve txn_id for ({txn_id:?}, {txn_data:?})")
            })?;
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::profile_id
                .eq(profile_id.to_owned())
                .and(dsl::connector_payment_id.eq(connector_transaction_id.to_owned())),
        )
        .await
    }


pub fn get_error_reason(
    error_info: Option<String>,
    detailed_error_info: Option<String>,
    avs_error_info: Option<String>,
) -> Option<String> {
    match (error_info, detailed_error_info, avs_error_info) {
        (Some(message), Some(details), Some(avs_message)) => Some(format!(
            "{message}, detailed_error_information: {details}, avs_message: {avs_message}",
        )),
        (Some(message), Some(details), None) => {
            Some(format!("{message}, detailed_error_information: {details}"))
        }
        (Some(message), None, Some(avs_message)) => {
            Some(format!("{message}, avs_message: {avs_message}"))
        }
        (None, Some(details), Some(avs_message)) => {
            Some(format!("{details}, avs_message: {avs_message}"))
        }
        (Some(message), None, None) => Some(message),
        (None, Some(details), None) => Some(details),
        (None, None, Some(avs_message)) => Some(avs_message),
        (None, None, None) => None,
    }
}


pub async fn trigger_payouts_webhook(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    payout_response: &api_models::payouts::PayoutCreateResponse,
) -> RouterResult<()> {
    todo!()
}


impl quote::ToTokens for FieldMeta {
    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
        self.value.to_tokens(tokens);
    }
}


impl api::PaymentSession for Noon {}


impl PaymentAuthorize for Signifyd {}


pub struct CardVerification {
    result_code: Option<String>,
    result_code_raw: Option<String>,
}


pub struct PaymentsRejectData {
    pub amount: Option<i64>,
    pub currency: Option<storage_enums::Currency>,
}


pub struct BreadpayErrorResponse {
    /// Human-readable error description
    pub description: String,

    /// Error type classification
    #[serde(rename = "type")]
    pub error_type: String,
}


pub struct CustomerNew {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub name: Option<Encryption>,
    pub email: Option<Encryption>,
    pub phone: Option<Encryption>,
    pub phone_country_code: Option<String>,
    pub description: Option<Description>,
    pub created_at: PrimitiveDateTime,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub connector_customer: Option<common_types::customers::ConnectorCustomerMap>,
    pub modified_at: PrimitiveDateTime,
    pub default_payment_method_id: Option<common_utils::id_type::GlobalPaymentMethodId>,
    pub updated_by: Option<String>,
    pub version: ApiVersion,
    pub tax_registration_id: Option<Encryption>,
    pub merchant_reference_id: Option<common_utils::id_type::CustomerId>,
    pub default_billing_address: Option<Encryption>,
    pub default_shipping_address: Option<Encryption>,
    pub status: DeleteStatus,
    pub id: common_utils::id_type::GlobalCustomerId,
}


pub struct PaypalDetails {
    shopper_name: Secret<String>,
    country_code: enums::CountryAlpha2,
}


pub struct PaytmAuthType {
    pub merchant_id: Secret<String>,
    pub merchant_key: Secret<String>,
    pub website: Secret<String>,
}


pub struct RefundIntegrityObject {
    /// refund currency
    pub currency: storage_enums::Currency,
    /// refund amount
    pub refund_amount: MinorUnit,
}


impl ApiEventMetric for AuthenticationEligibilityResponse {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        Some(ApiEventsType::Authentication {
            authentication_id: self.authentication_id.clone(),
        })
    }
}

impl ApiEventMetric for for AuthenticationEligibilityResponse


impl api::PayoutQuote for Ebanx {}


pub struct Checkout;


pub async fn profiles_list(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<common_utils::id_type::MerchantId>,
) -> HttpResponse {
    let flow = Flow::ProfileList;
    let merchant_id = path.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        merchant_id.clone(),
        |state, _auth, merchant_id, _| list_profile(state, merchant_id, None),
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuthWithMerchantIdFromRoute(merchant_id.clone())),
            &auth::JWTAuthMerchantFromRoute {
                merchant_id,
                required_permission: permissions::Permission::MerchantAccountRead,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub fn get_allowed_signals() -> Result<DummySignal, std::io::Error> {
    Ok(DummySignal)
}


impl api::PaymentVoid for Fiuu {}


Documentation: api-reference/v2/payment-methods/payment-methods--payment-methods-list.mdx
# Type: Doc File

---
openapi: get /v2/payment-methods/{id}/list-enabled-payment-methods
---


/// returns `false` otherwise.
    pub fn is_masked(&self) -> bool {
        matches!(self, Self::Masked(_))
    }


File: crates/hyperswitch_domain_models/src/router_flow_types/dispute.rs
 Public structs: 5

#[derive(Debug, Clone)]
pub struct Accept;
#[derive(Debug, Clone)]
pub struct Evidence;

#[derive(Debug, Clone)]
pub struct Defend;

#[derive(Debug, Clone)]
pub struct Fetch;

#[derive(Debug, Clone)]
pub struct Dsync;


                    .update_dynamic_routing_stats(
                        payment_attempt.attempt_id.clone(),
                        &payment_attempt.merchant_id.to_owned(),
                        dynamic_routing_update,
                    )
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Unable to update dynamic routing stats to db")?;
            } else {
                let dynamic_routing_stats = DynamicRoutingStatsNew {
                    payment_id: payment_attempt.payment_id.to_owned(),
                    attempt_id: payment_attempt.attempt_id.clone(),
                    merchant_id: payment_attempt.merchant_id.to_owned(),
                    profile_id: payment_attempt.profile_id.to_owned(),
                    amount: payment_attempt.get_total_amount(),
                    success_based_routing_connector: first_merchant_success_based_connector_label
                        .to_string(),
                    payment_connector: payment_connector.to_string(),
                    payment_method_type: payment_attempt.payment_method_type,
                    currency: payment_attempt.currency,
                    payment_method: payment_attempt.payment_method,
                    capture_method: payment_attempt.capture_method,
                    authentication_type: payment_attempt.authentication_type,
                    payment_status: payment_attempt.status,
                    conclusive_classification: outcome,
                    created_at: common_utils::date_time::now(),
                    global_success_based_connector: Some(
                        first_global_success_based_connector.label.to_string(),
                    ),
                };

                state
                    .store
                    .insert_dynamic_routing_stat_entry(dynamic_routing_stats)
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Unable to push dynamic routing stats to db")?;
            };

            let label_with_status = routing_utils::UpdateLabelWithStatusEventRequest {
                label: routable_connector.clone().to_string(),
                status: payment_status_attribute == common_enums::AttemptStatus::Charged,
            };
            let event_request = routing_utils::UpdateSuccessRateWindowEventRequest {
                id: payment_attempt.profile_id.get_string_repr().to_string(),
                params: success_based_routing_config_params.clone(),
                labels_with_status: vec![label_with_status.clone()],
                global_labels_with_status: vec![label_with_status],
                config: success_based_routing_configs
                    .config
                    .as_ref()
                    .map(routing_utils::UpdateSuccessRateWindowConfig::from),
            };

            let routing_events_wrapper = routing_utils::RoutingEventsWrapper::new(
                state.tenant.tenant_id.clone(),
                state.request_id,
                payment_attempt.payment_id.get_string_repr().to_string(),
                profile_id.to_owned(),
                payment_attempt.merchant_id.to_owned(),
                "IntelligentRouter: UpdateSuccessRateWindow".to_string(),
                Some(event_request.clone()),
                true,
                false,
            );

            let closure = || async {
                let update_response_result = client
                    .update_success_rate(
                        profile_id.get_string_repr().into(),
                        success_based_routing_configs,
                        success_based_routing_config_params,
                        vec![routing_types::RoutableConnectorChoiceWithStatus::new(
                            routable_connector.clone(),
                            payment_status_attribute == common_enums::AttemptStatus::Charged,
                        )],
                        state.get_grpc_headers(),
                    )
                    .await
                    .change_context(errors::RoutingError::SuccessRateCalculationError)
                    .attach_printable(
                        "unable to update success based routing window in dynamic routing service",
                    );

                match update_response_result {
                    Ok(update_response) => {
                        let updated_resp =
                            routing_utils::UpdateSuccessRateWindowEventResponse::try_from(
                                &update_response,
                            )
                            .change_context(errors::RoutingError::RoutingEventsError { message: "Unable to convert to UpdateSuccessRateWindowEventResponse from UpdateSuccessRateWindowResponse".to_string(), status_code: 500 })?;
                        Ok(Some(updated_resp))
                    }
                    Err(err) => {
                        logger::error!(
                            "unable to update connector score in dynamic routing service: {:?}",
                            err.current_context()
                        );

                        Err(err)
                    }
                }
            };

            let events_response = routing_events_wrapper
                .construct_event_builder(
                    "SuccessRateCalculator.UpdateSuccessRateWindow".to_string(),
                    routing_events::RoutingEngine::IntelligentRouter,
                    routing_events::ApiMethod::Grpc,
                )
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(
                    "SR-Intelligent-Router: Failed to update success rate in Intelligent-Router",
                )?
                .trigger_event(state, closure)
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(
                    "SR-Intelligent-Router: Failed to update success rate in Intelligent-Router",
                )?;

            let _response: routing_utils::UpdateSuccessRateWindowEventResponse = events_response
                .response
                .ok_or(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(
                    "UpdateSuccessRateWindowEventResponse not found in RoutingEventResponse",
                )?;

            let mut routing_event = events_response
                .event
                .ok_or(errors::RoutingError::RoutingEventsError {
                    message:
                        "SR-Intelligent-Router: RoutingEvent not found in RoutingEventsResponse"
                            .to_string(),
                    status_code: 500,
                })
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(
                    "SR-Intelligent-Router: RoutingEvent not found in RoutingEventsResponse",
                )?;

            routing_event.set_status_code(200);
            routing_event.set_payment_connector(routable_connector); // we can do this inside the event wrap by implementing an interface on the req type
            state.event_handler().log_event(&routing_event);

            Ok(())
        } else {
            Ok(())
        }
    } else {
        Ok(())
    }
}

/// update window for elimination based dynamic routing
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn update_window_for_elimination_routing(
    state: &SessionState,
    payment_attempt: &storage::PaymentAttempt,
    profile_id: &id_type::ProfileId,
    dynamic_algo_ref: routing_types::DynamicRoutingAlgorithmRef,
    elimination_routing_configs_params_interpolator: DynamicRoutingConfigParamsInterpolator,
    gsm_error_category: common_enums::ErrorCategory,
) -> RouterResult<()> {
    if let Some(elimination_algo_ref) = dynamic_algo_ref.elimination_routing_algorithm {
        if elimination_algo_ref.enabled_feature != routing_types::DynamicRoutingFeatures::None {
            let client = &state
                .grpc_client
                .dynamic_routing
                .as_ref()
                .ok_or(errors::ApiErrorResponse::GenericNotFoundError {
                    message: "dynamic routing gRPC client not found".to_string(),
                })?
                .elimination_based_client;

            let elimination_routing_config = fetch_dynamic_routing_configs::<
                routing_types::EliminationRoutingConfig,
            >(
                state,
                profile_id,
                elimination_algo_ref
                    .algorithm_id_with_timestamp
                    .algorithm_id
                    .ok_or(errors::ApiErrorResponse::GenericNotFoundError {
                        message: "elimination routing algorithm_id not found".to_string(),
                    })
                    .attach_printable(
                        "elimination_routing_algorithm_id not found in business_profile",
                    )?,
            )
            .await
            .change_context(errors::ApiErrorResponse::GenericNotFoundError {
                message: "elimination based dynamic routing configs not found".to_string(),
            })
            .attach_printable("unable to retrieve success_rate based dynamic routing configs")?;

            let payment_connector = &payment_attempt.connector.clone().ok_or(
                errors::ApiErrorResponse::GenericNotFoundError {
                    message: "unable to derive payment connector from payment attempt".to_string(),
                },
            )?;

            let elimination_routing_config_params = elimination_routing_configs_params_interpolator
                .get_string_val(
                    elimination_routing_config
                        .params
                        .as_ref()
                        .ok_or(errors::RoutingError::EliminationBasedRoutingParamsNotFoundError)
                        .change_context(errors::ApiErrorResponse::InternalServerError)?,
                );

            let labels_with_bucket_name =
                vec![routing_types::RoutableConnectorChoiceWithBucketName::new(
                    routing_types::RoutableConnectorChoice {
                        choice_kind: api_models::routing::RoutableChoiceKind::FullStruct,
                        connector: common_enums::RoutableConnectors::from_str(
                            payment_connector.as_str(),
                        )
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("unable to infer routable_connector from connector")?,
                        merchant_connector_id: payment_attempt.merchant_connector_id.clone(),
                    },
                    gsm_error_category.to_string(),
                )];

            let event_request = routing_utils::UpdateEliminationBucketEventRequest {
                id: profile_id.get_string_repr().to_string(),
                params: elimination_routing_config_params.clone(),
                labels_with_bucket_name: labels_with_bucket_name
                    .iter()
                    .map(|conn_choice| {
                        routing_utils::LabelWithBucketNameEventRequest::from(conn_choice)
                    })
                    .collect(),
                config: elimination_routing_config
                    .elimination_analyser_config
                    .as_ref()
                    .map(routing_utils::EliminationRoutingEventBucketConfig::from),
            };

            let routing_events_wrapper = routing_utils::RoutingEventsWrapper::new(
                state.tenant.tenant_id.clone(),
                state.request_id,
                payment_attempt.payment_id.get_string_repr().to_string(),
                profile_id.to_owned(),
                payment_attempt.merchant_id.to_owned(),
                "IntelligentRouter: UpdateEliminationBucket".to_string(),
                Some(event_request.clone()),
                true,
                false,
            );

            let closure = || async {
                let update_response_result = client
                .update_elimination_bucket_config(
                    profile_id.get_string_repr().to_string(),
                    elimination_routing_config_params,
                    labels_with_bucket_name,
                    elimination_routing_config.elimination_analyser_config,
                    state.get_grpc_headers(),
                )
                .await
                .change_context(errors::RoutingError::EliminationRoutingCalculationError)
                .attach_printable(
                    "unable to update elimination based routing buckets in dynamic routing service",
                );

                match update_response_result {
                    Ok(resp) => {
                        let updated_resp =
                            routing_utils::UpdateEliminationBucketEventResponse::try_from(&resp)
                            .change_context(errors::RoutingError::RoutingEventsError { message: "Unable to convert to UpdateEliminationBucketEventResponse from UpdateEliminationBucketResponse".to_string(), status_code: 500 })?;

                        Ok(Some(updated_resp))
                    }
                    Err(err) => {
                        logger::error!(
                            "unable to update elimination  score in dynamic routing service: {:?}",
                            err.current_context()
                        );

                        Err(err)
                    }
                }
            };

            let events_response = routing_events_wrapper.construct_event_builder( "EliminationAnalyser.UpdateEliminationBucket".to_string(),
            routing_events::RoutingEngine::IntelligentRouter,
            routing_events::ApiMethod::Grpc)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Elimination-Intelligent-Router: Failed to update elimination bucket in Intelligent-Router")?
            .trigger_event(state, closure)
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Elimination-Intelligent-Router: Failed to update elimination bucket in Intelligent-Router")?;

            let _response: routing_utils::UpdateEliminationBucketEventResponse = events_response
                .response
                .ok_or(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(
                    "UpdateEliminationBucketEventResponse not found in RoutingEventResponse",
                )?;

            let mut routing_event = events_response
                .event
                .ok_or(errors::RoutingError::RoutingEventsError {
                    message:
                        "Elimination-Intelligent-Router: RoutingEvent not found in RoutingEventsResponse"
                            .to_string(),
                    status_code: 500,
                })
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Elimination-Intelligent-Router: RoutingEvent not found in RoutingEventsResponse")?;

            routing_event.set_status_code(200);
            routing_event.set_payment_connector(routing_types::RoutableConnectorChoice {
                choice_kind: api_models::routing::RoutableChoiceKind::FullStruct,
                connector: common_enums::RoutableConnectors::from_str(payment_connector.as_str())
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("unable to infer routable_connector from connector")?,
                merchant_connector_id: payment_attempt.merchant_connector_id.clone(),
            });
            state.event_handler().log_event(&routing_event);
            Ok(())
        } else {
            Ok(())
        }
    } else {
        Ok(())
    }
}

/// metrics for contract based dynamic routing
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn push_metrics_with_update_window_for_contract_based_routing(
    state: &SessionState,
    payment_attempt: &storage::PaymentAttempt,
    routable_connectors: Vec<routing_types::RoutableConnectorChoice>,
    profile_id: &id_type::ProfileId,
    dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef,
    _dynamic_routing_config_params_interpolator: DynamicRoutingConfigParamsInterpolator,
) -> RouterResult<()> {
    if let Some(contract_routing_algo_ref) = dynamic_routing_algo_ref.contract_based_routing {
        if contract_routing_algo_ref.enabled_feature != routing_types::DynamicRoutingFeatures::None
        {
            let client = &state
                .grpc_client
                .dynamic_routing
                .as_ref()
                .ok_or(errors::ApiErrorResponse::GenericNotFoundError {
                    message: "dynamic routing gRPC client not found".to_string(),
                })?
                .contract_based_client;

            let payment_connector = &payment_attempt.connector.clone().ok_or(
                errors::ApiErrorResponse::GenericNotFoundError {
                    message: "unable to derive payment connector from payment attempt".to_string(),
                },
            )?;

            let contract_based_routing_config =
                fetch_dynamic_routing_configs::<routing_types::ContractBasedRoutingConfig>(
                    state,
                    profile_id,
                    contract_routing_algo_ref
                        .algorithm_id_with_timestamp
                        .algorithm_id
                        .ok_or(errors::ApiErrorResponse::GenericNotFoundError {
                            message: "contract_routing algorithm_id not found".to_string(),
                        })
                        .attach_printable(
                            "contract_based_routing_algorithm_id not found in business_profile",
                        )?,
                )
                .await
                .change_context(errors::ApiErrorResponse::GenericNotFoundError {
                    message: "contract based dynamic routing configs not found".to_string(),
                })
                .attach_printable("unable to retrieve contract based dynamic routing configs")?;

            let mut existing_label_info = None;

            contract_based_routing_config
                .label_info
                .as_ref()
                .map(|label_info_vec| {
                    for label_info in label_info_vec {
                        if Some(&label_info.mca_id)
                            == payment_attempt.merchant_connector_id.as_ref()
                        {
                            existing_label_info = Some(label_info.clone());
                        }
                    }
                });

            let final_label_info = existing_label_info
                .ok_or(errors::ApiErrorResponse::GenericNotFoundError {
                    message: "LabelInformation from ContractBasedRoutingConfig not found"
                        .to_string(),
                })
                .attach_printable(
                    "unable to get LabelInformation from ContractBasedRoutingConfig",
                )?;

            logger::debug!(
                "contract based routing: matched LabelInformation - {:?}",
                final_label_info
            );

            let request_label_info = routing_types::LabelInformation {
                label: final_label_info.label.clone(),
                target_count: final_label_info.target_count,
                target_time: final_label_info.target_time,
                mca_id: final_label_info.mca_id.to_owned(),
            };

            let payment_status_attribute =
                get_desired_payment_status_for_dynamic_routing_metrics(payment_attempt.status);

            if payment_status_attribute == common_enums::AttemptStatus::Charged {
                let event_request = routing_utils::UpdateContractRequestEventRequest {
                    id: profile_id.get_string_repr().to_string(),
                    params: "".to_string(),
                    labels_information: vec![
                        routing_utils::ContractLabelInformationEventRequest::from(
                            &request_label_info,
                        ),
                    ],
                };

                let routing_events_wrapper = routing_utils::RoutingEventsWrapper::new(
                    state.tenant.tenant_id.clone(),
                    state.request_id,
                    payment_attempt.payment_id.get_string_repr().to_string(),
                    profile_id.to_owned(),
                    payment_attempt.merchant_id.to_owned(),
                    "IntelligentRouter: UpdateContractScore".to_string(),
                    Some(event_request.clone()),
                    true,
                    false,
                );

                let closure = || async {
                    let update_response_result = client
                    .update_contracts(
                        profile_id.get_string_repr().into(),
                        vec![request_label_info],
                        "".to_string(),
                        vec![],
                        1,
                        state.get_grpc_headers(),
                    )
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable(
                        "unable to update contract based routing window in dynamic routing service",
                    );

                    match update_response_result {
                        Ok(resp) => {
                            let updated_resp =
                                routing_utils::UpdateContractEventResponse::try_from(&resp)
                                .change_context(errors::RoutingError::RoutingEventsError { message: "Unable to convert to UpdateContractEventResponse from UpdateContractResponse".to_string(), status_code: 500 })?;
                            Ok(Some(updated_resp))
                        }
                        Err(err) => {
                            logger::error!(
                                "unable to update elimination  score in dynamic routing service: {:?}",
                                err.current_context()
                            );

                            // have to refactor errors
                            Err(error_stack::report!(
                                errors::RoutingError::ContractScoreUpdationError
                            ))
                        }
                    }
                };

                let events_response = routing_events_wrapper.construct_event_builder( "ContractScoreCalculator.UpdateContract".to_string(),
                routing_events::RoutingEngine::IntelligentRouter,
                routing_events::ApiMethod::Grpc)
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("ContractRouting-Intelligent-Router: Failed to construct RoutingEventsBuilder")?
                .trigger_event(state, closure)
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("ContractRouting-Intelligent-Router: Failed to update contract scores in Intelligent-Router")?;

                let _response: routing_utils::UpdateContractEventResponse = events_response
                    .response
                    .ok_or(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable(
                        "UpdateContractEventResponse not found in RoutingEventResponse",
                    )?;

                let mut routing_event = events_response
                    .event
                    .ok_or(errors::RoutingError::RoutingEventsError {
                        message:
                            "ContractRouting-Intelligent-Router: RoutingEvent not found in RoutingEventsResponse"
                                .to_string(),
                        status_code: 500,
                    })
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("ContractRouting-Intelligent-Router: RoutingEvent not found in RoutingEventsResponse")?;

                routing_event.set_payment_connector(routing_types::RoutableConnectorChoice {
                    choice_kind: api_models::routing::RoutableChoiceKind::FullStruct,
                    connector: common_enums::RoutableConnectors::from_str(
                        final_label_info.label.as_str(),
                    )
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("unable to infer routable_connector from connector")?,
                    merchant_connector_id: Some(final_label_info.mca_id.clone()),
                });
                routing_event.set_status_code(200);
                state.event_handler().log_event(&routing_event);
            }

            let contract_based_connectors = routable_connectors
                .into_iter()
                .filter(|conn| {
                    conn.merchant_connector_id.clone() == Some(final_label_info.mca_id.clone())
                })
                .collect::<Vec<_>>();

            let contract_scores = client
                .calculate_contract_score(
                    profile_id.get_string_repr().into(),
                    contract_based_routing_config.clone(),
                    "".to_string(),
                    contract_based_connectors,
                    state.get_grpc_headers(),
                )
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(
                    "unable to calculate/fetch contract scores from dynamic routing service",
                )?;

            let first_contract_based_connector = &contract_scores
                .labels_with_score
                .first()
                .ok_or(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(
                    "unable to fetch the first connector from list of connectors obtained from dynamic routing service",
                )?;

            let (first_contract_based_connector, connector_score, current_payment_cnt) = (first_contract_based_connector.label
                .split_once(':')
                .ok_or(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(format!(
                    "unable to split connector_name and mca_id from the first connector {first_contract_based_connector:?} obtained from dynamic routing service",

                ))?
                .0, first_contract_based_connector.score, first_contract_based_connector.current_count );

            core_metrics::DYNAMIC_CONTRACT_BASED_ROUTING.add(
                1,
                router_env::metric_attributes!(
                    (
                        "tenant",
                        state.tenant.tenant_id.get_string_repr().to_owned(),
                    ),
                    (
                        "merchant_profile_id",
                        format!(
                            "{}:{}",
                            payment_attempt.merchant_id.get_string_repr(),
                            payment_attempt.profile_id.get_string_repr()
                        ),
                    ),
                    (
                        "contract_based_routing_connector",
                        first_contract_based_connector.to_string(),
                    ),
                    (
                        "contract_based_routing_connector_score",
                        connector_score.to_string(),
                    ),
                    (
                        "current_payment_count_contract_based_routing_connector",
                        current_payment_cnt.to_string(),
                    ),
                    ("payment_connector", payment_connector.to_string()),
                    (
                        "currency",
                        payment_attempt
                            .currency
                            .map_or_else(|| "None".to_string(), |currency| currency.to_string()),
                    ),
                    (
                        "payment_method",
                        payment_attempt.payment_method.map_or_else(
                            || "None".to_string(),
                            |payment_method| payment_method.to_string(),
                        ),
                    ),
                    (
                        "payment_method_type",
                        payment_attempt.payment_method_type.map_or_else(
                            || "None".to_string(),
                            |payment_method_type| payment_method_type.to_string(),
                        ),
                    ),
                    (
                        "capture_method",
                        payment_attempt.capture_method.map_or_else(
                            || "None".to_string(),
                            |capture_method| capture_method.to_string(),
                        ),
                    ),
                    (
                        "authentication_type",
                        payment_attempt.authentication_type.map_or_else(
                            || "None".to_string(),
                            |authentication_type| authentication_type.to_string(),
                        ),
                    ),
                    ("payment_status", payment_attempt.status.to_string()),
                ),
            );
            logger::debug!("successfully pushed contract_based_routing metrics");

            Ok(())
        } else {
            Ok(())
        }
    } else {
        Ok(())
    }
}

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
fn get_desired_payment_status_for_dynamic_routing_metrics(
    attempt_status: common_enums::AttemptStatus,
) -> common_enums::AttemptStatus {
    match attempt_status {
        common_enums::AttemptStatus::Charged
        | common_enums::AttemptStatus::Authorized
        | common_enums::AttemptStatus::PartialCharged
        | common_enums::AttemptStatus::PartialChargedAndChargeable
        | common_enums::AttemptStatus::PartiallyAuthorized => common_enums::AttemptStatus::Charged,
        common_enums::AttemptStatus::Failure
        | common_enums::AttemptStatus::AuthorizationFailed
        | common_enums::AttemptStatus::AuthenticationFailed
        | common_enums::AttemptStatus::CaptureFailed
        | common_enums::AttemptStatus::RouterDeclined => common_enums::AttemptStatus::Failure,
        common_enums::AttemptStatus::Started
        | common_enums::AttemptStatus::AuthenticationPending
        | common_enums::AttemptStatus::AuthenticationSuccessful
        | common_enums::AttemptStatus::Authorizing
        | common_enums::AttemptStatus::CodInitiated
        | common_enums::AttemptStatus::Voided
        | common_enums::AttemptStatus::VoidedPostCharge
        | common_enums::AttemptStatus::VoidInitiated
        | common_enums::AttemptStatus::CaptureInitiated
        | common_enums::AttemptStatus::VoidFailed
        | common_enums::AttemptStatus::AutoRefunded
        | common_enums::AttemptStatus::Unresolved
        | common_enums::AttemptStatus::Pending
        | common_enums::AttemptStatus::IntegrityFailure
        | common_enums::AttemptStatus::PaymentMethodAwaited
        | common_enums::AttemptStatus::ConfirmationAwaited
        | common_enums::AttemptStatus::DeviceDataCollectionPending
        | common_enums::AttemptStatus::Expired => common_enums::AttemptStatus::Pending,
    }
}

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
impl ForeignFrom<common_enums::AttemptStatus> for open_router::TxnStatus {
    fn foreign_from(attempt_status: common_enums::AttemptStatus) -> Self {
        match attempt_status {
            common_enums::AttemptStatus::Started => Self::Started,
            common_enums::AttemptStatus::AuthenticationFailed => Self::AuthenticationFailed,
            common_enums::AttemptStatus::RouterDeclined => Self::JuspayDeclined,
            common_enums::AttemptStatus::AuthenticationPending => Self::PendingVbv,
            common_enums::AttemptStatus::AuthenticationSuccessful => Self::VBVSuccessful,
            common_enums::AttemptStatus::Authorized
            | common_enums::AttemptStatus::PartiallyAuthorized => Self::Authorized,
            common_enums::AttemptStatus::AuthorizationFailed => Self::AuthorizationFailed,
            common_enums::AttemptStatus::Charged => Self::Charged,
            common_enums::AttemptStatus::Authorizing => Self::Authorizing,
            common_enums::AttemptStatus::CodInitiated => Self::CODInitiated,
            common_enums::AttemptStatus::Voided | common_enums::AttemptStatus::Expired => {
                Self::Voided
            }
            common_enums::AttemptStatus::VoidedPostCharge => Self::VoidedPostCharge,
            common_enums::AttemptStatus::VoidInitiated => Self::VoidInitiated,
            common_enums::AttemptStatus::CaptureInitiated => Self::CaptureInitiated,
            common_enums::AttemptStatus::CaptureFailed => Self::CaptureFailed,
            common_enums::AttemptStatus::VoidFailed => Self::VoidFailed,
            common_enums::AttemptStatus::AutoRefunded => Self::AutoRefunded,
            common_enums::AttemptStatus::PartialCharged => Self::PartialCharged,
            common_enums::AttemptStatus::PartialChargedAndChargeable => Self::ToBeCharged,
            common_enums::AttemptStatus::Unresolved => Self::Pending,
            common_enums::AttemptStatus::Pending
            | common_enums::AttemptStatus::IntegrityFailure => Self::Pending,
            common_enums::AttemptStatus::Failure => Self::Failure,
            common_enums::AttemptStatus::PaymentMethodAwaited => Self::Pending,
            common_enums::AttemptStatus::ConfirmationAwaited => Self::Pending,
            common_enums::AttemptStatus::DeviceDataCollectionPending => Self::Pending,
        }
    }
}

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
fn get_dynamic_routing_based_metrics_outcome_for_payment(
    payment_status_attribute: common_enums::AttemptStatus,
    payment_connector: String,
    first_success_based_connector: String,
) -> common_enums::SuccessBasedRoutingConclusiveState {
    match payment_status_attribute {
        common_enums::AttemptStatus::Charged
            if *first_success_based_connector == *payment_connector =>
        {
            common_enums::SuccessBasedRoutingConclusiveState::TruePositive
        }
        common_enums::AttemptStatus::Failure
            if *first_success_based_connector == *payment_connector =>
        {
            common_enums::SuccessBasedRoutingConclusiveState::FalsePositive
        }
        common_enums::AttemptStatus::Failure
            if *first_success_based_connector != *payment_connector =>
        {
            common_enums::SuccessBasedRoutingConclusiveState::TrueNegative
        }
        common_enums::AttemptStatus::Charged
            if *first_success_based_connector != *payment_connector =>
        {
            common_enums::SuccessBasedRoutingConclusiveState::FalseNegative
        }
        _ => common_enums::SuccessBasedRoutingConclusiveState::NonDeterministic,
    }
}

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
pub async fn disable_dynamic_routing_algorithm(
    state: &SessionState,
    key_store: domain::MerchantKeyStore,
    business_profile: domain::Profile,
    dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef,
    dynamic_routing_type: routing_types::DynamicRoutingType,
) -> RouterResult<ApplicationResponse<routing_types::RoutingDictionaryRecord>> {
    let db = state.store.as_ref();
    let key_manager_state = &state.into();
    let profile_id = business_profile.get_id().clone();
    let (algorithm_id, mut dynamic_routing_algorithm, cache_entries_to_redact) =
        match dynamic_routing_type {
            routing_types::DynamicRoutingType::SuccessRateBasedRouting => {
                let Some(algorithm_ref) = dynamic_routing_algo_ref.success_based_algorithm else {
                    Err(errors::ApiErrorResponse::PreconditionFailed {
                        message: "Success rate based routing is already disabled".to_string(),
                    })?
                };
                let Some(algorithm_id) = algorithm_ref.algorithm_id_with_timestamp.algorithm_id
                else {
                    Err(errors::ApiErrorResponse::PreconditionFailed {
                        message: "Algorithm is already inactive".to_string(),
                    })?
                };

                let cache_key = format!(
                    "{}_{}",
                    business_profile.get_id().get_string_repr(),
                    algorithm_id.get_string_repr()
                );
                let cache_entries_to_redact =
                    vec![cache::CacheKind::SuccessBasedDynamicRoutingCache(
                        cache_key.into(),
                    )];
                (
                    algorithm_id,
                    routing_types::DynamicRoutingAlgorithmRef {
                        success_based_algorithm: Some(routing_types::SuccessBasedAlgorithm {
                            algorithm_id_with_timestamp:
                                routing_types::DynamicAlgorithmWithTimestamp::new(None),
                            enabled_feature: routing_types::DynamicRoutingFeatures::None,
                        }),
                        elimination_routing_algorithm: dynamic_routing_algo_ref
                            .elimination_routing_algorithm,
                        contract_based_routing: dynamic_routing_algo_ref.contract_based_routing,
                        dynamic_routing_volume_split: dynamic_routing_algo_ref
                            .dynamic_routing_volume_split,
                        is_merchant_created_in_decision_engine: dynamic_routing_algo_ref
                            .is_merchant_created_in_decision_engine,
                    },
                    cache_entries_to_redact,
                )
            }
            routing_types::DynamicRoutingType::EliminationRouting => {
                let Some(algorithm_ref) = dynamic_routing_algo_ref.elimination_routing_algorithm
                else {
                    Err(errors::ApiErrorResponse::PreconditionFailed {
                        message: "Elimination routing is already disabled".to_string(),
                    })?
                };
                let Some(algorithm_id) = algorithm_ref.algorithm_id_with_timestamp.algorithm_id
                else {
                    Err(errors::ApiErrorResponse::PreconditionFailed {
                        message: "Algorithm is already inactive".to_string(),
                    })?
                };
                let cache_key = format!(
                    "{}_{}",
                    business_profile.get_id().get_string_repr(),
                    algorithm_id.get_string_repr()
                );
                let cache_entries_to_redact =
                    vec![cache::CacheKind::EliminationBasedDynamicRoutingCache(
                        cache_key.into(),
                    )];
                (
                    algorithm_id,
                    routing_types::DynamicRoutingAlgorithmRef {
                        success_based_algorithm: dynamic_routing_algo_ref.success_based_algorithm,
                        dynamic_routing_volume_split: dynamic_routing_algo_ref
                            .dynamic_routing_volume_split,
                        elimination_routing_algorithm: Some(
                            routing_types::EliminationRoutingAlgorithm {
                                algorithm_id_with_timestamp:
                                    routing_types::DynamicAlgorithmWithTimestamp::new(None),
                                enabled_feature: routing_types::DynamicRoutingFeatures::None,
                            },
                        ),
                        contract_based_routing: dynamic_routing_algo_ref.contract_based_routing,
                        is_merchant_created_in_decision_engine: dynamic_routing_algo_ref
                            .is_merchant_created_in_decision_engine,
                    },
                    cache_entries_to_redact,
                )
            }
            routing_types::DynamicRoutingType::ContractBasedRouting => {
                let Some(algorithm_ref) = dynamic_routing_algo_ref.contract_based_routing else {
                    Err(errors::ApiErrorResponse::PreconditionFailed {
                        message: "Contract routing is already disabled".to_string(),
                    })?
                };
                let Some(algorithm_id) = algorithm_ref.algorithm_id_with_timestamp.algorithm_id
                else {
                    Err(errors::ApiErrorResponse::PreconditionFailed {
                        message: "Algorithm is already inactive".to_string(),
                    })?
                };
                let cache_key = format!(
                    "{}_{}",
                    business_profile.get_id().get_string_repr(),
                    algorithm_id.get_string_repr()
                );
                let cache_entries_to_redact =
                    vec![cache::CacheKind::ContractBasedDynamicRoutingCache(
                        cache_key.into(),
                    )];
                (
                    algorithm_id,
                    routing_types::DynamicRoutingAlgorithmRef {
                        success_based_algorithm: dynamic_routing_algo_ref.success_based_algorithm,
                        elimination_routing_algorithm: dynamic_routing_algo_ref
                            .elimination_routing_algorithm,
                        dynamic_routing_volume_split: dynamic_routing_algo_ref
                            .dynamic_routing_volume_split,
                        contract_based_routing: Some(routing_types::ContractRoutingAlgorithm {
                            algorithm_id_with_timestamp:
                                routing_types::DynamicAlgorithmWithTimestamp::new(None),
                            enabled_feature: routing_types::DynamicRoutingFeatures::None,
                        }),
                        is_merchant_created_in_decision_engine: dynamic_routing_algo_ref
                            .is_merchant_created_in_decision_engine,
                    },
                    cache_entries_to_redact,
                )
            }
        };

    // Call to DE here
    if state.conf.open_router.dynamic_routing_enabled {
        disable_decision_engine_dynamic_routing_setup(
            state,
            business_profile.get_id(),
            dynamic_routing_type,
            &mut dynamic_routing_algorithm,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("unable to disable dynamic routing setup in decision engine")?;
    }

    // redact cache for dynamic routing config
    let _ = cache::redact_from_redis_and_publish(
        state.store.get_cache_store().as_ref(),
        cache_entries_to_redact,
    )
    .await
    .change_context(errors::ApiErrorResponse::InternalServerError)
    .attach_printable(
        "unable to publish into the redact channel for evicting the dynamic routing config cache",
    )?;

    let record = db
        .find_routing_algorithm_by_profile_id_algorithm_id(business_profile.get_id(), &algorithm_id)
        .await
        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
    let response = record.foreign_into();
    update_business_profile_active_dynamic_algorithm_ref(
        db,
        key_manager_state,
        &key_store,
        business_profile,
        dynamic_routing_algorithm,
    )
    .await?;

    core_metrics::ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE.add(
        1,
        router_env::metric_attributes!(("profile_id", profile_id)),
    );

    Ok(ApplicationResponse::Json(response))
}

#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
pub async fn enable_dynamic_routing_algorithm(
    state: &SessionState,
    key_store: domain::MerchantKeyStore,
    business_profile: domain::Profile,
    feature_to_enable: routing_types::DynamicRoutingFeatures,
    dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef,
    dynamic_routing_type: routing_types::DynamicRoutingType,
    payload: Option<routing_types::DynamicRoutingPayload>,
) -> RouterResult<ApplicationResponse<routing_types::RoutingDictionaryRecord>> {
    let mut dynamic_routing = dynamic_routing_algo_ref.clone();
    match dynamic_routing_type {
        routing_types::DynamicRoutingType::SuccessRateBasedRouting => {
            dynamic_routing
                .disable_algorithm_id(routing_types::DynamicRoutingType::ContractBasedRouting);

            enable_specific_routing_algorithm(
                state,
                key_store,
                business_profile,
                feature_to_enable,
                dynamic_routing.clone(),
                dynamic_routing_type,
                dynamic_routing.success_based_algorithm,
                payload,
            )
            .await
        }
        routing_types::DynamicRoutingType::EliminationRouting => {
            enable_specific_routing_algorithm(
                state,
                key_store,
                business_profile,
                feature_to_enable,
                dynamic_routing.clone(),
                dynamic_routing_type,
                dynamic_routing.elimination_routing_algorithm,
                payload,
            )
            .await
        }
        routing_types::DynamicRoutingType::ContractBasedRouting => {
            Err((errors::ApiErrorResponse::InvalidRequestData {
                message: "Contract routing cannot be set as default".to_string(),
            })
            .into())
        }
    }
}

#[allow(clippy::too_many_arguments)]
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
pub async fn enable_specific_routing_algorithm<A>(
    state: &SessionState,
    key_store: domain::MerchantKeyStore,
    business_profile: domain::Profile,
    feature_to_enable: routing_types::DynamicRoutingFeatures,
    mut dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef,
    dynamic_routing_type: routing_types::DynamicRoutingType,
    algo_type: Option<A>,
    payload: Option<routing_types::DynamicRoutingPayload>,
) -> RouterResult<ApplicationResponse<routing_types::RoutingDictionaryRecord>>
where
    A: routing_types::DynamicRoutingAlgoAccessor + Clone + Debug,
{
    //Check for payload
    if let Some(payload) = payload {
        return create_specific_dynamic_routing_setup(
            state,
            key_store,
            business_profile,
            feature_to_enable,
            dynamic_routing_algo_ref,
            dynamic_routing_type,
            payload,
        )
        .await;
    }
    // Algorithm wasn't created yet
    let Some(mut algo_type) = algo_type else {
        return default_specific_dynamic_routing_setup(
            state,
            key_store,
            business_profile,
            feature_to_enable,
            dynamic_routing_algo_ref,
            dynamic_routing_type,
        )
        .await;
    };

    // Algorithm was in disabled state
    let Some(algo_type_algorithm_id) = algo_type
        .clone()
        .get_algorithm_id_with_timestamp()
        .algorithm_id
    else {
        return default_specific_dynamic_routing_setup(
            state,
            key_store,
            business_profile,
            feature_to_enable,
            dynamic_routing_algo_ref,
            dynamic_routing_type,
        )
        .await;
    };
    let db = state.store.as_ref();
    let profile_id = business_profile.get_id().clone();
    let algo_type_enabled_features = algo_type.get_enabled_features();


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


pub fn get_order_tax_amount(&self) -> Option<MinorUnit> {
        self.order_tax_amount
    }


File: crates/storage_impl/src/database/store.rs
 Public functions: 1
 Public structs: 2

use async_bb8_diesel::{AsyncConnection, ConnectionError};
use bb8::CustomizeConnection;
use common_utils::DbConnectionParams;
use diesel::PgConnection;
use error_stack::ResultExt;

use crate::{
    config::{Database, TenantConfig},
    errors::{StorageError, StorageResult},
};

pub type PgPool = bb8::Pool<async_bb8_diesel::ConnectionManager<PgConnection>>;
pub type PgPooledConn = async_bb8_diesel::Connection<PgConnection>;

#[async_trait::async_trait]
pub trait DatabaseStore: Clone + Send + Sync {
    type Config: Send;
    async fn new(
        config: Self::Config,
        tenant_config: &dyn TenantConfig,
        test_transaction: bool,
    ) -> StorageResult<Self>;
    fn get_master_pool(&self) -> &PgPool;
    fn get_replica_pool(&self) -> &PgPool;
    fn get_accounts_master_pool(&self) -> &PgPool;
    fn get_accounts_replica_pool(&self) -> &PgPool;
}

#[derive(Debug, Clone)]
pub struct Store {
    pub master_pool: PgPool,
    pub accounts_pool: PgPool,
}

#[async_trait::async_trait]
impl DatabaseStore for Store {
    type Config = Database;
    async fn new(
        config: Database,
        tenant_config: &dyn TenantConfig,
        test_transaction: bool,
    ) -> StorageResult<Self> {
        Ok(Self {
            master_pool: diesel_make_pg_pool(&config, tenant_config.get_schema(), test_transaction)
                .await?,
            accounts_pool: diesel_make_pg_pool(
                &config,
                tenant_config.get_accounts_schema(),
                test_transaction,
            )
            .await?,
        })
    }

    fn get_master_pool(&self) -> &PgPool {
        &self.master_pool
    }

    fn get_replica_pool(&self) -> &PgPool {
        &self.master_pool
    }

    fn get_accounts_master_pool(&self) -> &PgPool {
        &self.accounts_pool
    }

    fn get_accounts_replica_pool(&self) -> &PgPool {
        &self.accounts_pool
    }
}

#[derive(Debug, Clone)]
pub struct ReplicaStore {
    pub master_pool: PgPool,
    pub replica_pool: PgPool,
    pub accounts_master_pool: PgPool,
    pub accounts_replica_pool: PgPool,
}

#[async_trait::async_trait]
impl DatabaseStore for ReplicaStore {
    type Config = (Database, Database);
    async fn new(
        config: (Database, Database),
        tenant_config: &dyn TenantConfig,
        test_transaction: bool,
    ) -> StorageResult<Self> {
        let (master_config, replica_config) = config;
        let master_pool =
            diesel_make_pg_pool(&master_config, tenant_config.get_schema(), test_transaction)
                .await
                .attach_printable("failed to create master pool")?;
        let accounts_master_pool = diesel_make_pg_pool(
            &master_config,
            tenant_config.get_accounts_schema(),
            test_transaction,
        )
        .await
        .attach_printable("failed to create accounts master pool")?;
        let replica_pool = diesel_make_pg_pool(
            &replica_config,
            tenant_config.get_schema(),
            test_transaction,
        )
        .await
        .attach_printable("failed to create replica pool")?;

        let accounts_replica_pool = diesel_make_pg_pool(
            &replica_config,
            tenant_config.get_accounts_schema(),
            test_transaction,
        )
        .await
        .attach_printable("failed to create accounts pool")?;
        Ok(Self {
            master_pool,
            replica_pool,
            accounts_master_pool,
            accounts_replica_pool,
        })
    }

    fn get_master_pool(&self) -> &PgPool {
        &self.master_pool
    }

    fn get_replica_pool(&self) -> &PgPool {
        &self.replica_pool
    }

    fn get_accounts_master_pool(&self) -> &PgPool {
        &self.accounts_master_pool
    }

    fn get_accounts_replica_pool(&self) -> &PgPool {
        &self.accounts_replica_pool
    }
}

pub async fn diesel_make_pg_pool(
    database: &Database,
    schema: &str,
    test_transaction: bool,
) -> StorageResult<PgPool> {
    let database_url = database.get_database_url(schema);
    let manager = async_bb8_diesel::ConnectionManager::<PgConnection>::new(database_url);
    let mut pool = bb8::Pool::builder()
        .max_size(database.pool_size)
        .min_idle(database.min_idle)
        .queue_strategy(database.queue_strategy.into())
        .connection_timeout(std::time::Duration::from_secs(database.connection_timeout))
        .max_lifetime(database.max_lifetime.map(std::time::Duration::from_secs));

    if test_transaction {
        pool = pool.connection_customizer(Box::new(TestTransaction));
    }

    pool.build(manager)
        .await
        .change_context(StorageError::InitializationError)
        .attach_printable("Failed to create PostgreSQL connection pool")
}

#[derive(Debug)]
struct TestTransaction;

#[async_trait::async_trait]
impl CustomizeConnection<PgPooledConn, ConnectionError> for TestTransaction {
    #[allow(clippy::unwrap_used)]
    async fn on_acquire(&self, conn: &mut PgPooledConn) -> Result<(), ConnectionError> {
        use diesel::Connection;

        conn.run(|conn| {
            conn.begin_test_transaction().unwrap();
            Ok(())
        })
        .await
    }
}


pub struct RefundSuccessCount;