// File: crates/hyperswitch_domain_models/src/payments.rs
// Module: hyperswitch_domain_models
// Public functions: 32
// Public structs: 18

#[cfg(feature = "v2")]
use std::marker::PhantomData;

#[cfg(feature = "v2")]
use api_models::payments::{SessionToken, VaultSessionDetails};
use common_types::primitive_wrappers;
#[cfg(feature = "v1")]
use common_types::primitive_wrappers::{
    AlwaysRequestExtendedAuthorization, EnableOvercaptureBool, RequestExtendedAuthorizationBool,
};
use common_utils::{
    self,
    crypto::Encryptable,
    encryption::Encryption,
    errors::CustomResult,
    ext_traits::ValueExt,
    id_type, pii,
    types::{keymanager::ToEncryptable, CreatedBy, MinorUnit},
};
use diesel_models::payment_intent::TaxDetails;
#[cfg(feature = "v2")]
use error_stack::ResultExt;
use masking::Secret;
use router_derive::ToEncryption;
use rustc_hash::FxHashMap;
use serde_json::Value;
use time::PrimitiveDateTime;

pub mod payment_attempt;
pub mod payment_intent;

use common_enums as storage_enums;
#[cfg(feature = "v2")]
use diesel_models::types::{FeatureMetadata, OrderDetailsWithAmount};

use self::payment_attempt::PaymentAttempt;
#[cfg(feature = "v2")]
use crate::{
    address::Address, business_profile, customer, errors, merchant_connector_account,
    merchant_connector_account::MerchantConnectorAccountTypeDetails, merchant_context,
    payment_address, payment_method_data, payment_methods, revenue_recovery, routing,
    ApiModelToDieselModelConvertor,
};
#[cfg(feature = "v1")]
use crate::{payment_method_data, RemoteStorageObject};

#[cfg(feature = "v1")]
#[derive(Clone, Debug, PartialEq, serde::Serialize, ToEncryption)]
pub struct PaymentIntent {
    pub payment_id: id_type::PaymentId,
    pub merchant_id: id_type::MerchantId,
    pub status: storage_enums::IntentStatus,
    pub amount: MinorUnit,
    pub shipping_cost: Option<MinorUnit>,
    pub currency: Option<storage_enums::Currency>,
    pub amount_captured: Option<MinorUnit>,
    pub customer_id: Option<id_type::CustomerId>,
    pub description: Option<String>,
    pub return_url: Option<String>,
    pub metadata: Option<Value>,
    pub connector_id: Option<String>,
    pub shipping_address_id: Option<String>,
    pub billing_address_id: Option<String>,
    pub statement_descriptor_name: Option<String>,
    pub statement_descriptor_suffix: Option<String>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub modified_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub last_synced: Option<PrimitiveDateTime>,
    pub setup_future_usage: Option<storage_enums::FutureUsage>,
    pub off_session: Option<bool>,
    pub client_secret: Option<String>,
    pub active_attempt: RemoteStorageObject<PaymentAttempt>,
    pub business_country: Option<storage_enums::CountryAlpha2>,
    pub business_label: Option<String>,
    pub order_details: Option<Vec<pii::SecretSerdeValue>>,
    pub allowed_payment_method_types: Option<Value>,
    pub connector_metadata: Option<Value>,
    pub feature_metadata: Option<Value>,
    pub attempt_count: i16,
    pub profile_id: Option<id_type::ProfileId>,
    pub payment_link_id: Option<String>,
    // Denotes the action(approve or reject) taken by merchant in case of manual review.
    // Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment
    pub merchant_decision: Option<String>,
    pub payment_confirm_source: Option<storage_enums::PaymentSource>,

    pub updated_by: String,
    pub surcharge_applicable: Option<bool>,
    pub request_incremental_authorization: Option<storage_enums::RequestIncrementalAuthorization>,
    pub incremental_authorization_allowed: Option<bool>,
    pub authorization_count: Option<i32>,
    pub fingerprint_id: Option<String>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub session_expiry: Option<PrimitiveDateTime>,
    pub request_external_three_ds_authentication: Option<bool>,
    pub split_payments: Option<common_types::payments::SplitPaymentsRequest>,
    pub frm_metadata: Option<pii::SecretSerdeValue>,
    #[encrypt]
    pub customer_details: Option<Encryptable<Secret<Value>>>,
    #[encrypt]
    pub billing_details: Option<Encryptable<Secret<Value>>>,
    pub merchant_order_reference_id: Option<String>,
    #[encrypt]
    pub shipping_details: Option<Encryptable<Secret<Value>>>,
    pub is_payment_processor_token_flow: Option<bool>,
    pub organization_id: id_type::OrganizationId,
    pub tax_details: Option<TaxDetails>,
    pub skip_external_tax_calculation: Option<bool>,
    pub request_extended_authorization: Option<RequestExtendedAuthorizationBool>,
    pub psd2_sca_exemption_type: Option<storage_enums::ScaExemptionType>,
    pub processor_merchant_id: id_type::MerchantId,
    pub created_by: Option<CreatedBy>,
    pub force_3ds_challenge: Option<bool>,
    pub force_3ds_challenge_trigger: Option<bool>,
    pub is_iframe_redirection_enabled: Option<bool>,
    pub is_payment_id_from_merchant: Option<bool>,
    pub payment_channel: Option<common_enums::PaymentChannel>,
    pub tax_status: Option<storage_enums::TaxStatus>,
    pub discount_amount: Option<MinorUnit>,
    pub order_date: Option<PrimitiveDateTime>,
    pub shipping_amount_tax: Option<MinorUnit>,
    pub duty_amount: Option<MinorUnit>,
    pub enable_partial_authorization: Option<primitive_wrappers::EnablePartialAuthorizationBool>,
    pub enable_overcapture: Option<EnableOvercaptureBool>,
}

impl PaymentIntent {
    #[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.id
    }

    #[cfg(feature = "v2")]
    /// This is the url to which the customer will be redirected to, to complete the redirection flow
    pub fn create_start_redirection_url(
        &self,
        base_url: &str,
        publishable_key: String,
    ) -> CustomResult<url::Url, errors::api_error_response::ApiErrorResponse> {
        let start_redirection_url = &format!(
            "{}/v2/payments/{}/start-redirection?publishable_key={}&profile_id={}",
            base_url,
            self.get_id().get_string_repr(),
            publishable_key,
            self.profile_id.get_string_repr()
        );
        url::Url::parse(start_redirection_url)
            .change_context(errors::api_error_response::ApiErrorResponse::InternalServerError)
            .attach_printable("Error creating start redirection url")
    }
    #[cfg(feature = "v1")]
    pub fn get_request_extended_authorization_bool_if_connector_supports(
        &self,
        connector: common_enums::connector_enums::Connector,
        always_request_extended_authorization_optional: Option<AlwaysRequestExtendedAuthorization>,
        payment_method_optional: Option<common_enums::PaymentMethod>,
        payment_method_type_optional: Option<common_enums::PaymentMethodType>,
    ) -> Option<RequestExtendedAuthorizationBool> {
        use router_env::logger;

        let is_extended_authorization_supported_by_connector = || {
            let supported_pms = connector.get_payment_methods_supporting_extended_authorization();
            let supported_pmts =
                connector.get_payment_method_types_supporting_extended_authorization();
            // check if payment method or payment method type is supported by the connector
            logger::info!(
                "Extended Authentication Connector:{:?}, Supported payment methods: {:?}, Supported payment method types: {:?}, Payment method Selected: {:?}, Payment method type Selected: {:?}",
                connector,
                supported_pms,
                supported_pmts,
                payment_method_optional,
                payment_method_type_optional
            );
            match (payment_method_optional, payment_method_type_optional) {
                (Some(payment_method), Some(payment_method_type)) => {
                    supported_pms.contains(&payment_method)
                        && supported_pmts.contains(&payment_method_type)
                }
                (Some(payment_method), None) => supported_pms.contains(&payment_method),
                (None, Some(payment_method_type)) => supported_pmts.contains(&payment_method_type),
                (None, None) => false,
            }
        };
        let intent_request_extended_authorization_optional = self.request_extended_authorization;

        let is_extended_authorization_requested = intent_request_extended_authorization_optional
            .map(|should_request_extended_authorization| *should_request_extended_authorization)
            .or(always_request_extended_authorization_optional.map(
                |should_always_request_extended_authorization| {
                    *should_always_request_extended_authorization
                },
            ));

        is_extended_authorization_requested
            .map(|requested| {
                if requested {
                    is_extended_authorization_supported_by_connector()
                } else {
                    false
                }
            })
            .map(RequestExtendedAuthorizationBool::from)
    }

    #[cfg(feature = "v1")]
    pub fn get_enable_overcapture_bool_if_connector_supports(
        &self,
        connector: common_enums::connector_enums::Connector,
        always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
        capture_method: &Option<common_enums::CaptureMethod>,
    ) -> Option<EnableOvercaptureBool> {
        let is_overcapture_supported_by_connector =
            connector.is_overcapture_supported_by_connector();
        if matches!(capture_method, Some(common_enums::CaptureMethod::Manual))
            && is_overcapture_supported_by_connector
        {
            self.enable_overcapture
                .or_else(|| always_enable_overcapture.map(EnableOvercaptureBool::from))
        } else {
            None
        }
    }

    #[cfg(feature = "v2")]
    /// This is the url to which the customer will be redirected to, after completing the redirection flow
    pub fn create_finish_redirection_url(
        &self,
        base_url: &str,
        publishable_key: &str,
    ) -> CustomResult<url::Url, errors::api_error_response::ApiErrorResponse> {
        let finish_redirection_url = format!(
            "{base_url}/v2/payments/{}/finish-redirection/{publishable_key}/{}",
            self.id.get_string_repr(),
            self.profile_id.get_string_repr()
        );

        url::Url::parse(&finish_redirection_url)
            .change_context(errors::api_error_response::ApiErrorResponse::InternalServerError)
            .attach_printable("Error creating finish redirection url")
    }

    pub fn parse_and_get_metadata<T>(
        &self,
        type_name: &'static str,
    ) -> CustomResult<Option<T>, common_utils::errors::ParsingError>
    where
        T: for<'de> masking::Deserialize<'de>,
    {
        self.metadata
            .clone()
            .map(|metadata| metadata.parse_value(type_name))
            .transpose()
    }

    #[cfg(feature = "v1")]
    pub fn merge_metadata(
        &self,
        request_metadata: Value,
    ) -> Result<Value, common_utils::errors::ParsingError> {
        if !request_metadata.is_null() {
            match (&self.metadata, &request_metadata) {
                (Some(Value::Object(existing_map)), Value::Object(req_map)) => {
                    let mut merged = existing_map.clone();
                    merged.extend(req_map.clone());
                    Ok(Value::Object(merged))
                }
                (None, Value::Object(_)) => Ok(request_metadata),
                _ => {
                    router_env::logger::error!(
                        "Expected metadata to be an object, got: {:?}",
                        request_metadata
                    );
                    Err(common_utils::errors::ParsingError::UnknownError)
                }
            }
        } else {
            router_env::logger::error!("Metadata does not contain any key");
            Err(common_utils::errors::ParsingError::UnknownError)
        }
    }
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, PartialEq, serde::Serialize)]
pub struct AmountDetails {
    /// The amount of the order in the lowest denomination of currency
    pub order_amount: MinorUnit,
    /// The currency of the order
    pub currency: common_enums::Currency,
    /// The shipping cost of the order. This has to be collected from the merchant
    pub shipping_cost: Option<MinorUnit>,
    /// Tax details related to the order. This will be calculated by the external tax provider
    pub tax_details: Option<TaxDetails>,
    /// The action to whether calculate tax by calling external tax provider or not
    pub skip_external_tax_calculation: common_enums::TaxCalculationOverride,
    /// The action to whether calculate surcharge or not
    pub skip_surcharge_calculation: common_enums::SurchargeCalculationOverride,
    /// The surcharge amount to be added to the order, collected from the merchant
    pub surcharge_amount: Option<MinorUnit>,
    /// tax on surcharge amount
    pub tax_on_surcharge: Option<MinorUnit>,
    /// The total amount captured for the order. This is the sum of all the captured amounts for the order.
    /// For automatic captures, this will be the same as net amount for the order
    pub amount_captured: Option<MinorUnit>,
}

#[cfg(feature = "v2")]
impl AmountDetails {
    /// Get the action to whether calculate surcharge or not as a boolean value
    fn get_surcharge_action_as_bool(&self) -> bool {
        self.skip_surcharge_calculation.as_bool()
    }

    /// Get the action to whether calculate external tax or not as a boolean value
    pub fn get_external_tax_action_as_bool(&self) -> bool {
        self.skip_external_tax_calculation.as_bool()
    }

    /// Calculate the net amount for the order
    pub fn calculate_net_amount(&self) -> MinorUnit {
        self.order_amount
            + self.shipping_cost.unwrap_or(MinorUnit::zero())
            + self.surcharge_amount.unwrap_or(MinorUnit::zero())
            + self.tax_on_surcharge.unwrap_or(MinorUnit::zero())
    }

    pub fn create_attempt_amount_details(
        &self,
        confirm_intent_request: &api_models::payments::PaymentsConfirmIntentRequest,
    ) -> payment_attempt::AttemptAmountDetails {
        let net_amount = self.calculate_net_amount();

        let surcharge_amount = match self.skip_surcharge_calculation {
            common_enums::SurchargeCalculationOverride::Skip => self.surcharge_amount,
            common_enums::SurchargeCalculationOverride::Calculate => None,
        };

        let tax_on_surcharge = match self.skip_surcharge_calculation {
            common_enums::SurchargeCalculationOverride::Skip => self.tax_on_surcharge,
            common_enums::SurchargeCalculationOverride::Calculate => None,
        };

        let order_tax_amount = match self.skip_external_tax_calculation {
            common_enums::TaxCalculationOverride::Skip => {
                self.tax_details.as_ref().and_then(|tax_details| {
                    tax_details.get_tax_amount(Some(confirm_intent_request.payment_method_subtype))
                })
            }
            common_enums::TaxCalculationOverride::Calculate => None,
        };

        payment_attempt::AttemptAmountDetails::from(payment_attempt::AttemptAmountDetailsSetter {
            net_amount,
            amount_to_capture: None,
            surcharge_amount,
            tax_on_surcharge,
            // This will be updated when we receive response from the connector
            amount_capturable: MinorUnit::zero(),
            shipping_cost: self.shipping_cost,
            order_tax_amount,
        })
    }

    pub fn proxy_create_attempt_amount_details(
        &self,
        _confirm_intent_request: &api_models::payments::ProxyPaymentsRequest,
    ) -> payment_attempt::AttemptAmountDetails {
        let net_amount = self.calculate_net_amount();

        let surcharge_amount = match self.skip_surcharge_calculation {
            common_enums::SurchargeCalculationOverride::Skip => self.surcharge_amount,
            common_enums::SurchargeCalculationOverride::Calculate => None,
        };

        let tax_on_surcharge = match self.skip_surcharge_calculation {
            common_enums::SurchargeCalculationOverride::Skip => self.tax_on_surcharge,
            common_enums::SurchargeCalculationOverride::Calculate => None,
        };

        let order_tax_amount = match self.skip_external_tax_calculation {
            common_enums::TaxCalculationOverride::Skip => self
                .tax_details
                .as_ref()
                .and_then(|tax_details| tax_details.get_tax_amount(None)),
            common_enums::TaxCalculationOverride::Calculate => None,
        };

        payment_attempt::AttemptAmountDetails::from(payment_attempt::AttemptAmountDetailsSetter {
            net_amount,
            amount_to_capture: None,
            surcharge_amount,
            tax_on_surcharge,
            // This will be updated when we receive response from the connector
            amount_capturable: MinorUnit::zero(),
            shipping_cost: self.shipping_cost,
            order_tax_amount,
        })
    }

    pub fn update_from_request(self, req: &api_models::payments::AmountDetailsUpdate) -> Self {
        Self {
            order_amount: req
                .order_amount()
                .unwrap_or(self.order_amount.into())
                .into(),
            currency: req.currency().unwrap_or(self.currency),
            shipping_cost: req.shipping_cost().or(self.shipping_cost),
            tax_details: req
                .order_tax_amount()
                .map(|order_tax_amount| TaxDetails {
                    default: Some(diesel_models::DefaultTax { order_tax_amount }),
                    payment_method_type: None,
                })
                .or(self.tax_details),
            skip_external_tax_calculation: req
                .skip_external_tax_calculation()
                .unwrap_or(self.skip_external_tax_calculation),
            skip_surcharge_calculation: req
                .skip_surcharge_calculation()
                .unwrap_or(self.skip_surcharge_calculation),
            surcharge_amount: req.surcharge_amount().or(self.surcharge_amount),
            tax_on_surcharge: req.tax_on_surcharge().or(self.tax_on_surcharge),
            amount_captured: self.amount_captured,
        }
    }
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, PartialEq, serde::Serialize, ToEncryption)]
pub struct PaymentIntent {
    /// The global identifier for the payment intent. This is generated by the system.
    /// The format of the global id is `{cell_id:5}_pay_{time_ordered_uuid:32}`.
    pub id: id_type::GlobalPaymentId,
    /// The identifier for the merchant. This is automatically derived from the api key used to create the payment.
    pub merchant_id: id_type::MerchantId,
    /// The status of payment intent.
    pub status: storage_enums::IntentStatus,
    /// The amount related details of the payment
    pub amount_details: AmountDetails,
    /// The total amount captured for the order. This is the sum of all the captured amounts for the order.
    pub amount_captured: Option<MinorUnit>,
    /// The identifier for the customer. This is the identifier for the customer in the merchant's system.
    pub customer_id: Option<id_type::GlobalCustomerId>,
    /// The description of the order. This will be passed to connectors which support description.
    pub description: Option<common_utils::types::Description>,
    /// The return url for the payment. This is the url to which the user will be redirected after the payment is completed.
    pub return_url: Option<common_utils::types::Url>,
    /// The metadata for the payment intent. This is the metadata that will be passed to the connectors.
    pub metadata: Option<pii::SecretSerdeValue>,
    /// The statement descriptor for the order, this will be displayed in the user's bank statement.
    pub statement_descriptor: Option<common_utils::types::StatementDescriptor>,
    /// The time at which the order was created
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    /// The time at which the order was last modified
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub modified_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub last_synced: Option<PrimitiveDateTime>,
    pub setup_future_usage: storage_enums::FutureUsage,
    /// The active attempt for the payment intent. This is the payment attempt that is currently active for the payment intent.
    pub active_attempt_id: Option<id_type::GlobalAttemptId>,
    /// This field represents whether there are attempt groups for this payment intent. Used in split payments workflow
    pub active_attempt_id_type: common_enums::ActiveAttemptIDType,
    /// The ID of the active attempt group for the payment intent
    pub active_attempts_group_id: Option<String>,
    /// The order details for the payment.
    pub order_details: Option<Vec<Secret<OrderDetailsWithAmount>>>,
    /// This is the list of payment method types that are allowed for the payment intent.
    /// This field allows the merchant to restrict the payment methods that can be used for the payment intent.
    pub allowed_payment_method_types: Option<Vec<common_enums::PaymentMethodType>>,
    /// This metadata contains details about
    pub connector_metadata: Option<pii::SecretSerdeValue>,
    pub feature_metadata: Option<FeatureMetadata>,
    /// Number of attempts that have been made for the order
    pub attempt_count: i16,
    /// The profile id for the payment.
    pub profile_id: id_type::ProfileId,
    /// The payment link id for the payment. This is generated only if `enable_payment_link` is set to true.
    pub payment_link_id: Option<String>,
    /// This Denotes the action(approve or reject) taken by merchant in case of manual review.
    /// Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment
    pub frm_merchant_decision: Option<common_enums::MerchantDecision>,
    /// Denotes the last instance which updated the payment
    pub updated_by: String,
    /// Denotes whether merchant requested for incremental authorization to be enabled for this payment.
    pub request_incremental_authorization: storage_enums::RequestIncrementalAuthorization,
    /// Denotes whether merchant requested for split payments to be enabled for this payment
    pub split_txns_enabled: storage_enums::SplitTxnsEnabled,
    /// Denotes the number of authorizations that have been made for the payment.
    pub authorization_count: Option<i32>,
    /// Denotes the client secret expiry for the payment. This is the time at which the client secret will expire.
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub session_expiry: PrimitiveDateTime,
    /// Denotes whether merchant requested for 3ds authentication to be enabled for this payment.
    pub request_external_three_ds_authentication: common_enums::External3dsAuthenticationRequest,
    /// Metadata related to fraud and risk management
    pub frm_metadata: Option<pii::SecretSerdeValue>,
    /// The details of the customer in a denormalized form. Only a subset of fields are stored.
    #[encrypt]
    pub customer_details: Option<Encryptable<Secret<Value>>>,
    /// The reference id for the order in the merchant's system. This value can be passed by the merchant.
    pub merchant_reference_id: Option<id_type::PaymentReferenceId>,
    /// The billing address for the order in a denormalized form.
    #[encrypt(ty = Value)]
    pub billing_address: Option<Encryptable<Address>>,
    /// The shipping address for the order in a denormalized form.
    #[encrypt(ty = Value)]
    pub shipping_address: Option<Encryptable<Address>>,
    /// Capture method for the payment
    pub capture_method: storage_enums::CaptureMethod,
    /// Authentication type that is requested by the merchant for this payment.
    pub authentication_type: Option<common_enums::AuthenticationType>,
    /// This contains the pre routing results that are done when routing is done during listing the payment methods.
    pub prerouting_algorithm: Option<routing::PaymentRoutingInfo>,
    /// The organization id for the payment. This is derived from the merchant account
    pub organization_id: id_type::OrganizationId,
    /// Denotes the request by the merchant whether to enable a payment link for this payment.
    pub enable_payment_link: common_enums::EnablePaymentLinkRequest,
    /// Denotes the request by the merchant whether to apply MIT exemption for this payment
    pub apply_mit_exemption: common_enums::MitExemptionRequest,
    /// Denotes whether the customer is present during the payment flow. This information may be used for 3ds authentication
    pub customer_present: common_enums::PresenceOfCustomerDuringPayment,
    /// Denotes the override for payment link configuration
    pub payment_link_config: Option<diesel_models::PaymentLinkConfigRequestForPayments>,
    /// The straight through routing algorithm id that is used for this payment. This overrides the default routing algorithm that is configured in business profile.
    pub routing_algorithm_id: Option<id_type::RoutingId>,
    /// Split Payment Data
    pub split_payments: Option<common_types::payments::SplitPaymentsRequest>,

    pub force_3ds_challenge: Option<bool>,
    pub force_3ds_challenge_trigger: Option<bool>,
    /// merchant who owns the credentials of the processor, i.e. processor owner
    pub processor_merchant_id: id_type::MerchantId,
    /// merchantwho invoked the resource based api (identifier) and through what source (Api, Jwt(Dashboard))
    pub created_by: Option<CreatedBy>,

    /// Indicates if the redirection has to open in the iframe
    pub is_iframe_redirection_enabled: Option<bool>,

    /// Indicates whether the payment_id was provided by the merchant (true),
    /// or generated internally by Hyperswitch (false)
    pub is_payment_id_from_merchant: Option<bool>,
    /// Denotes whether merchant requested for partial authorization to be enabled for this payment.
    pub enable_partial_authorization: Option<primitive_wrappers::EnablePartialAuthorizationBool>,
}

#[cfg(feature = "v2")]
impl PaymentIntent {
    /// Extract customer_id from payment intent feature metadata
    pub fn extract_connector_customer_id_from_payment_intent(
        &self,
    ) -> Result<String, common_utils::errors::ValidationError> {
        self.feature_metadata
            .as_ref()
            .and_then(|metadata| metadata.payment_revenue_recovery_metadata.as_ref())
            .map(|recovery| {
                recovery
                    .billing_connector_payment_details
                    .connector_customer_id
                    .clone()
            })
            .ok_or(
                common_utils::errors::ValidationError::MissingRequiredField {
                    field_name: "connector_customer_id".to_string(),
                },
            )
    }

    fn get_payment_method_sub_type(&self) -> Option<common_enums::PaymentMethodType> {
        self.feature_metadata
            .as_ref()
            .and_then(|metadata| metadata.get_payment_method_sub_type())
    }

    fn get_payment_method_type(&self) -> Option<common_enums::PaymentMethod> {
        self.feature_metadata
            .as_ref()
            .and_then(|metadata| metadata.get_payment_method_type())
    }

    pub fn get_connector_customer_id_from_feature_metadata(&self) -> Option<String> {
        self.feature_metadata
            .as_ref()
            .and_then(|metadata| metadata.payment_revenue_recovery_metadata.as_ref())
            .map(|recovery_metadata| {
                recovery_metadata
                    .billing_connector_payment_details
                    .connector_customer_id
                    .clone()
            })
    }

    pub fn get_billing_merchant_connector_account_id(
        &self,
    ) -> Option<id_type::MerchantConnectorAccountId> {
        self.feature_metadata.as_ref().and_then(|feature_metadata| {
            feature_metadata.get_billing_merchant_connector_account_id()
        })
    }

    fn get_request_incremental_authorization_value(
        request: &api_models::payments::PaymentsCreateIntentRequest,
    ) -> CustomResult<
        common_enums::RequestIncrementalAuthorization,
        errors::api_error_response::ApiErrorResponse,
    > {
        request.request_incremental_authorization
            .map(|request_incremental_authorization| {
                if request_incremental_authorization == common_enums::RequestIncrementalAuthorization::True {
                    if request.capture_method == Some(common_enums::CaptureMethod::Automatic) {
                        Err(errors::api_error_response::ApiErrorResponse::InvalidRequestData { message: "incremental authorization is not supported when capture_method is automatic".to_owned() })?
                    }
                    Ok(common_enums::RequestIncrementalAuthorization::True)
                } else {
                    Ok(common_enums::RequestIncrementalAuthorization::False)
                }
            })
            .unwrap_or(Ok(common_enums::RequestIncrementalAuthorization::default()))
    }

    pub async fn create_domain_model_from_request(
        payment_id: &id_type::GlobalPaymentId,
        merchant_context: &merchant_context::MerchantContext,
        profile: &business_profile::Profile,
        request: api_models::payments::PaymentsCreateIntentRequest,
        decrypted_payment_intent: DecryptedPaymentIntent,
    ) -> CustomResult<Self, errors::api_error_response::ApiErrorResponse> {
        let connector_metadata = request
            .get_connector_metadata_as_value()
            .change_context(errors::api_error_response::ApiErrorResponse::InternalServerError)
            .attach_printable("Error getting connector metadata as value")?;
        let request_incremental_authorization =
            Self::get_request_incremental_authorization_value(&request)?;
        let allowed_payment_method_types = request.allowed_payment_method_types;

        let session_expiry =
            common_utils::date_time::now().saturating_add(time::Duration::seconds(
                request.session_expiry.map(i64::from).unwrap_or(
                    profile
                        .session_expiry
                        .unwrap_or(common_utils::consts::DEFAULT_SESSION_EXPIRY),
                ),
            ));
        let order_details = request.order_details.map(|order_details| {
            order_details
                .into_iter()
                .map(|order_detail| Secret::new(OrderDetailsWithAmount::convert_from(order_detail)))
                .collect()
        });

        Ok(Self {
            id: payment_id.clone(),
            merchant_id: merchant_context.get_merchant_account().get_id().clone(),
            // Intent status would be RequiresPaymentMethod because we are creating a new payment intent
            status: common_enums::IntentStatus::RequiresPaymentMethod,
            amount_details: AmountDetails::from(request.amount_details),
            amount_captured: None,
            customer_id: request.customer_id,
            description: request.description,
            return_url: request.return_url,
            metadata: request.metadata,
            statement_descriptor: request.statement_descriptor,
            created_at: common_utils::date_time::now(),
            modified_at: common_utils::date_time::now(),
            last_synced: None,
            setup_future_usage: request.setup_future_usage.unwrap_or_default(),
            active_attempt_id: None,
            active_attempt_id_type: common_enums::ActiveAttemptIDType::AttemptID,
            active_attempts_group_id: None,
            order_details,
            allowed_payment_method_types,
            connector_metadata,
            feature_metadata: request.feature_metadata.map(FeatureMetadata::convert_from),
            // Attempt count is 0 in create intent as no attempt is made yet
            attempt_count: 0,
            profile_id: profile.get_id().clone(),
            payment_link_id: None,
            frm_merchant_decision: None,
            updated_by: merchant_context
                .get_merchant_account()
                .storage_scheme
                .to_string(),
            request_incremental_authorization,
            // Authorization count is 0 in create intent as no authorization is made yet
            authorization_count: Some(0),
            session_expiry,
            request_external_three_ds_authentication: request
                .request_external_three_ds_authentication
                .unwrap_or_default(),
            split_txns_enabled: profile.split_txns_enabled,
            frm_metadata: request.frm_metadata,
            customer_details: None,
            merchant_reference_id: request.merchant_reference_id,
            billing_address: decrypted_payment_intent
                .billing_address
                .as_ref()
                .map(|data| {
                    data.clone()
                        .deserialize_inner_value(|value| value.parse_value("Address"))
                })
                .transpose()
                .change_context(errors::api_error_response::ApiErrorResponse::InternalServerError)
                .attach_printable("Unable to decode billing address")?,
            shipping_address: decrypted_payment_intent
                .shipping_address
                .as_ref()
                .map(|data| {
                    data.clone()
                        .deserialize_inner_value(|value| value.parse_value("Address"))
                })
                .transpose()
                .change_context(errors::api_error_response::ApiErrorResponse::InternalServerError)
                .attach_printable("Unable to decode shipping address")?,
            capture_method: request.capture_method.unwrap_or_default(),
            authentication_type: request.authentication_type,
            prerouting_algorithm: None,
            organization_id: merchant_context
                .get_merchant_account()
                .organization_id
                .clone(),
            enable_payment_link: request.payment_link_enabled.unwrap_or_default(),
            apply_mit_exemption: request.apply_mit_exemption.unwrap_or_default(),
            customer_present: request.customer_present.unwrap_or_default(),
            payment_link_config: request
                .payment_link_config
                .map(ApiModelToDieselModelConvertor::convert_from),
            routing_algorithm_id: request.routing_algorithm_id,
            split_payments: None,
            force_3ds_challenge: None,
            force_3ds_challenge_trigger: None,
            processor_merchant_id: merchant_context.get_merchant_account().get_id().clone(),
            created_by: None,
            is_iframe_redirection_enabled: None,
            is_payment_id_from_merchant: None,
            enable_partial_authorization: request.enable_partial_authorization,
        })
    }

    pub fn get_revenue_recovery_metadata(
        &self,
    ) -> Option<diesel_models::types::PaymentRevenueRecoveryMetadata> {
        self.feature_metadata
            .as_ref()
            .and_then(|feature_metadata| feature_metadata.payment_revenue_recovery_metadata.clone())
    }

    pub fn get_feature_metadata(&self) -> Option<FeatureMetadata> {
        self.feature_metadata.clone()
    }

    pub fn create_revenue_recovery_attempt_data(
        &self,
        revenue_recovery_metadata: api_models::payments::PaymentRevenueRecoveryMetadata,
        billing_connector_account: &merchant_connector_account::MerchantConnectorAccount,
        card_info: api_models::payments::AdditionalCardInfo,
        payment_processor_token: &str,
    ) -> CustomResult<
        revenue_recovery::RevenueRecoveryAttemptData,
        errors::api_error_response::ApiErrorResponse,
    > {
        let merchant_reference_id = self.merchant_reference_id.clone().ok_or_else(|| {
            error_stack::report!(
                errors::api_error_response::ApiErrorResponse::GenericNotFoundError {
                    message: "mandate reference id not found".to_string()
                }
            )
        })?;

        let connector_account_reference_id = billing_connector_account
            .get_account_reference_id_using_payment_merchant_connector_account_id(
                revenue_recovery_metadata.active_attempt_payment_connector_id,
            )
            .ok_or_else(|| {
                error_stack::report!(
                    errors::api_error_response::ApiErrorResponse::GenericNotFoundError {
                        message: "connector account reference id not found".to_string()
                    }
                )
            })?;

        Ok(revenue_recovery::RevenueRecoveryAttemptData {
            amount: self.amount_details.order_amount,
            currency: self.amount_details.currency,
            merchant_reference_id,
            connector_transaction_id: None, // No connector id
            error_code: None,
            error_message: None,
            processor_payment_method_token: payment_processor_token.to_string(),
            connector_customer_id: revenue_recovery_metadata
                .billing_connector_payment_details
                .connector_customer_id,
            connector_account_reference_id,
            transaction_created_at: None, // would unwrap_or as now
            status: common_enums::AttemptStatus::Started,
            payment_method_type: self
                .get_payment_method_type()
                .unwrap_or(revenue_recovery_metadata.payment_method_type),
            payment_method_sub_type: self
                .get_payment_method_sub_type()
                .unwrap_or(revenue_recovery_metadata.payment_method_subtype),
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            retry_count: None,
            invoice_next_billing_time: None,
            invoice_billing_started_at_time: None,
            // No charge id is present here since it is an internal payment and we didn't call connector yet.
            charge_id: None,
            card_info: card_info.clone(),
        })
    }

    pub fn get_optional_customer_id(
        &self,
    ) -> CustomResult<Option<id_type::CustomerId>, common_utils::errors::ValidationError> {
        self.customer_id
            .as_ref()
            .map(|customer_id| id_type::CustomerId::try_from(customer_id.clone()))
            .transpose()
    }

    pub fn get_optional_connector_metadata(
        &self,
    ) -> CustomResult<
        Option<api_models::payments::ConnectorMetadata>,
        common_utils::errors::ParsingError,
    > {
        self.connector_metadata
            .clone()
            .map(|cm| {
                cm.parse_value::<api_models::payments::ConnectorMetadata>("ConnectorMetadata")
            })
            .transpose()
    }

    pub fn get_currency(&self) -> storage_enums::Currency {
        self.amount_details.currency
    }
}

#[cfg(feature = "v1")]
#[derive(Default, Debug, Clone)]
pub struct HeaderPayload {
    pub payment_confirm_source: Option<common_enums::PaymentSource>,
    pub client_source: Option<String>,
    pub client_version: Option<String>,
    pub x_hs_latency: Option<bool>,
    pub browser_name: Option<common_enums::BrowserName>,
    pub x_client_platform: Option<common_enums::ClientPlatform>,
    pub x_merchant_domain: Option<String>,
    pub locale: Option<String>,
    pub x_app_id: Option<String>,
    pub x_redirect_uri: Option<String>,
    pub x_reference_id: Option<String>,
}


// Struct: XenditSplitResponse
// File: crates/hyperswitch_connectors/src/connectors/xendit/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct XenditSplitResponse


// Function: retrieve_conditional_config
// File: crates/router/src/core/conditional_config.rs
// Module: router

pub fn retrieve_conditional_config(
    state: SessionState,
    key_store: domain::MerchantKeyStore,
    profile: domain::Profile,
) -> RouterResponse<common_types::payments::DecisionManagerResponse>


// Function: retrieve_dynamic_routing_volume_split
// File: crates/router/src/core/routing.rs
// Module: router

pub fn retrieve_dynamic_routing_volume_split(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: common_utils::id_type::ProfileId,
) -> RouterResponse<routing_types::RoutingVolumeSplitResponse>


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

pub fn new() -> &'static Self


// File: crates/router/src/db/merchant_account.rs
// Module: router

#[cfg(feature = "olap")]
use std::collections::HashMap;

use common_utils::{ext_traits::AsyncExt, types::keymanager::KeyManagerState};
use diesel_models::MerchantAccountUpdateInternal;
use error_stack::{report, ResultExt};
use router_env::{instrument, tracing};
#[cfg(feature = "accounts_cache")]
use storage_impl::redis::cache::{self, CacheKind, ACCOUNTS_CACHE};

use super::{MasterKeyInterface, MockDb, Store};
use crate::{
    connection,
    core::errors::{self, CustomResult},
    db::merchant_key_store::MerchantKeyStoreInterface,
    types::{
        domain::{
            self,
            behaviour::{Conversion, ReverseConversion},
        },
        storage,
    },
};

#[async_trait::async_trait]
pub trait MerchantAccountInterface
where
    domain::MerchantAccount:
        Conversion<DstType = storage::MerchantAccount, NewDstType = storage::MerchantAccountNew>,
{
    async fn insert_merchant(
        &self,
        state: &KeyManagerState,
        merchant_account: domain::MerchantAccount,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError>;

    async fn find_merchant_account_by_merchant_id(
        &self,
        state: &KeyManagerState,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError>;

    async fn update_all_merchant_account(
        &self,
        merchant_account: storage::MerchantAccountUpdate,
    ) -> CustomResult<usize, errors::StorageError>;

    async fn update_merchant(
        &self,
        state: &KeyManagerState,
        this: domain::MerchantAccount,
        merchant_account: storage::MerchantAccountUpdate,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError>;

    async fn update_specific_fields_in_merchant(
        &self,
        state: &KeyManagerState,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_account: storage::MerchantAccountUpdate,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError>;

    async fn find_merchant_account_by_publishable_key(
        &self,
        state: &KeyManagerState,
        publishable_key: &str,
    ) -> CustomResult<(domain::MerchantAccount, domain::MerchantKeyStore), errors::StorageError>;

    #[cfg(feature = "olap")]
    async fn list_merchant_accounts_by_organization_id(
        &self,
        state: &KeyManagerState,
        organization_id: &common_utils::id_type::OrganizationId,
    ) -> CustomResult<Vec<domain::MerchantAccount>, errors::StorageError>;

    async fn delete_merchant_account_by_merchant_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> CustomResult<bool, errors::StorageError>;

    #[cfg(feature = "olap")]
    async fn list_multiple_merchant_accounts(
        &self,
        state: &KeyManagerState,
        merchant_ids: Vec<common_utils::id_type::MerchantId>,
    ) -> CustomResult<Vec<domain::MerchantAccount>, errors::StorageError>;

    #[cfg(feature = "olap")]
    async fn list_merchant_and_org_ids(
        &self,
        state: &KeyManagerState,
        limit: u32,
        offset: Option<u32>,
    ) -> CustomResult<
        Vec<(
            common_utils::id_type::MerchantId,
            common_utils::id_type::OrganizationId,
        )>,
        errors::StorageError,
    >;
}

#[async_trait::async_trait]
impl MerchantAccountInterface for Store {
    #[instrument(skip_all)]
    async fn insert_merchant(
        &self,
        state: &KeyManagerState,
        merchant_account: domain::MerchantAccount,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
        let conn = connection::pg_accounts_connection_write(self).await?;
        merchant_account
            .construct_new()
            .await
            .change_context(errors::StorageError::EncryptionError)?
            .insert(&conn)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))?
            .convert(
                state,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(errors::StorageError::DecryptionError)
    }

    #[instrument(skip_all)]
    async fn find_merchant_account_by_merchant_id(
        &self,
        state: &KeyManagerState,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
        let fetch_func = || async {
            let conn = connection::pg_accounts_connection_read(self).await?;
            storage::MerchantAccount::find_by_merchant_id(&conn, merchant_id)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        };

        #[cfg(not(feature = "accounts_cache"))]
        {
            fetch_func()
                .await?
                .convert(
                    state,
                    merchant_key_store.key.get_inner(),
                    merchant_id.to_owned().into(),
                )
                .await
                .change_context(errors::StorageError::DecryptionError)
        }

        #[cfg(feature = "accounts_cache")]
        {
            cache::get_or_populate_in_memory(
                self,
                merchant_id.get_string_repr(),
                fetch_func,
                &ACCOUNTS_CACHE,
            )
            .await?
            .convert(
                state,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(errors::StorageError::DecryptionError)
        }
    }

    #[instrument(skip_all)]
    async fn update_merchant(
        &self,
        state: &KeyManagerState,
        this: domain::MerchantAccount,
        merchant_account: storage::MerchantAccountUpdate,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
        let conn = connection::pg_accounts_connection_write(self).await?;

        let updated_merchant_account = Conversion::convert(this)
            .await
            .change_context(errors::StorageError::EncryptionError)?
            .update(&conn, merchant_account.into())
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))?;

        #[cfg(feature = "accounts_cache")]
        {
            publish_and_redact_merchant_account_cache(self, &updated_merchant_account).await?;
        }
        updated_merchant_account
            .convert(
                state,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(errors::StorageError::DecryptionError)
    }

    #[instrument(skip_all)]
    async fn update_specific_fields_in_merchant(
        &self,
        state: &KeyManagerState,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_account: storage::MerchantAccountUpdate,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
        let conn = connection::pg_accounts_connection_write(self).await?;
        let updated_merchant_account = storage::MerchantAccount::update_with_specific_fields(
            &conn,
            merchant_id,
            merchant_account.into(),
        )
        .await
        .map_err(|error| report!(errors::StorageError::from(error)))?;

        #[cfg(feature = "accounts_cache")]
        {
            publish_and_redact_merchant_account_cache(self, &updated_merchant_account).await?;
        }
        updated_merchant_account
            .convert(
                state,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(errors::StorageError::DecryptionError)
    }

    #[instrument(skip_all)]
    async fn find_merchant_account_by_publishable_key(
        &self,
        state: &KeyManagerState,
        publishable_key: &str,
    ) -> CustomResult<(domain::MerchantAccount, domain::MerchantKeyStore), errors::StorageError>
    {
        let fetch_by_pub_key_func = || async {
            let conn = connection::pg_accounts_connection_read(self).await?;

            storage::MerchantAccount::find_by_publishable_key(&conn, publishable_key)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        };

        let merchant_account;
        #[cfg(not(feature = "accounts_cache"))]
        {
            merchant_account = fetch_by_pub_key_func().await?;
        }

        #[cfg(feature = "accounts_cache")]
        {
            merchant_account = cache::get_or_populate_in_memory(
                self,
                publishable_key,
                fetch_by_pub_key_func,
                &ACCOUNTS_CACHE,
            )
            .await?;
        }
        let key_store = self
            .get_merchant_key_store_by_merchant_id(
                state,
                merchant_account.get_id(),
                &self.get_master_key().to_vec().into(),
            )
            .await?;
        let domain_merchant_account = merchant_account
            .convert(
                state,
                key_store.key.get_inner(),
                key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(errors::StorageError::DecryptionError)?;
        Ok((domain_merchant_account, key_store))
    }

    #[cfg(feature = "olap")]
    #[instrument(skip_all)]
    async fn list_merchant_accounts_by_organization_id(
        &self,
        state: &KeyManagerState,
        organization_id: &common_utils::id_type::OrganizationId,
    ) -> CustomResult<Vec<domain::MerchantAccount>, errors::StorageError> {
        use futures::future::try_join_all;
        let conn = connection::pg_accounts_connection_read(self).await?;

        let encrypted_merchant_accounts =
            storage::MerchantAccount::list_by_organization_id(&conn, organization_id)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))?;

        let db_master_key = self.get_master_key().to_vec().into();

        let merchant_key_stores =
            try_join_all(encrypted_merchant_accounts.iter().map(|merchant_account| {
                self.get_merchant_key_store_by_merchant_id(
                    state,
                    merchant_account.get_id(),
                    &db_master_key,
                )
            }))
            .await?;

        let merchant_accounts = try_join_all(
            encrypted_merchant_accounts
                .into_iter()
                .zip(merchant_key_stores.iter())
                .map(|(merchant_account, key_store)| async {
                    merchant_account
                        .convert(
                            state,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(errors::StorageError::DecryptionError)
                }),
        )
        .await?;

        Ok(merchant_accounts)
    }

    #[instrument(skip_all)]
    async fn delete_merchant_account_by_merchant_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> CustomResult<bool, errors::StorageError> {
        let conn = connection::pg_accounts_connection_write(self).await?;

        let is_deleted_func = || async {
            storage::MerchantAccount::delete_by_merchant_id(&conn, merchant_id)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        };

        let is_deleted;

        #[cfg(not(feature = "accounts_cache"))]
        {
            is_deleted = is_deleted_func().await?;
        }

        #[cfg(feature = "accounts_cache")]
        {
            let merchant_account =
                storage::MerchantAccount::find_by_merchant_id(&conn, merchant_id)
                    .await
                    .map_err(|error| report!(errors::StorageError::from(error)))?;

            is_deleted = is_deleted_func().await?;

            publish_and_redact_merchant_account_cache(self, &merchant_account).await?;
        }

        Ok(is_deleted)
    }

    #[cfg(feature = "olap")]
    #[instrument(skip_all)]
    async fn list_multiple_merchant_accounts(
        &self,
        state: &KeyManagerState,
        merchant_ids: Vec<common_utils::id_type::MerchantId>,
    ) -> CustomResult<Vec<domain::MerchantAccount>, errors::StorageError> {
        let conn = connection::pg_accounts_connection_read(self).await?;

        let encrypted_merchant_accounts =
            storage::MerchantAccount::list_multiple_merchant_accounts(&conn, merchant_ids)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))?;

        let db_master_key = self.get_master_key().to_vec().into();

        let merchant_key_stores = self
            .list_multiple_key_stores(
                state,
                encrypted_merchant_accounts
                    .iter()
                    .map(|merchant_account| merchant_account.get_id())
                    .cloned()
                    .collect(),
                &db_master_key,
            )
            .await?;

        let key_stores_by_id: HashMap<_, _> = merchant_key_stores
            .iter()
            .map(|key_store| (key_store.merchant_id.to_owned(), key_store))
            .collect();

        let merchant_accounts =
            futures::future::try_join_all(encrypted_merchant_accounts.into_iter().map(
                |merchant_account| async {
                    let key_store = key_stores_by_id.get(merchant_account.get_id()).ok_or(
                        errors::StorageError::ValueNotFound(format!(
                            "merchant_key_store with merchant_id = {:?}",
                            merchant_account.get_id()
                        )),
                    )?;
                    merchant_account
                        .convert(
                            state,
                            key_store.key.get_inner(),
                            key_store.merchant_id.clone().into(),
                        )
                        .await
                        .change_context(errors::StorageError::DecryptionError)
                },
            ))
            .await?;

        Ok(merchant_accounts)
    }

    #[cfg(feature = "olap")]
    #[instrument(skip_all)]
    async fn list_merchant_and_org_ids(
        &self,
        _state: &KeyManagerState,
        limit: u32,
        offset: Option<u32>,
    ) -> CustomResult<
        Vec<(
            common_utils::id_type::MerchantId,
            common_utils::id_type::OrganizationId,
        )>,
        errors::StorageError,
    > {
        let conn = connection::pg_accounts_connection_read(self).await?;
        let encrypted_merchant_accounts =
            storage::MerchantAccount::list_all_merchant_accounts(&conn, limit, offset)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))?;

        let merchant_and_org_ids = encrypted_merchant_accounts
            .into_iter()
            .map(|merchant_account| {
                let merchant_id = merchant_account.get_id().clone();
                let org_id = merchant_account.organization_id;
                (merchant_id, org_id)
            })
            .collect();
        Ok(merchant_and_org_ids)
    }

    async fn update_all_merchant_account(
        &self,
        merchant_account: storage::MerchantAccountUpdate,
    ) -> CustomResult<usize, errors::StorageError> {
        let conn = connection::pg_accounts_connection_read(self).await?;

        let db_func = || async {
            storage::MerchantAccount::update_all_merchant_accounts(
                &conn,
                MerchantAccountUpdateInternal::from(merchant_account),
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
        };

        let total;
        #[cfg(not(feature = "accounts_cache"))]
        {
            let ma = db_func().await?;
            total = ma.len();
        }

        #[cfg(feature = "accounts_cache")]
        {
            let ma = db_func().await?;
            publish_and_redact_all_merchant_account_cache(self, &ma).await?;
            total = ma.len();
        }

        Ok(total)
    }
}

#[async_trait::async_trait]
impl MerchantAccountInterface for MockDb {
    #[allow(clippy::panic)]
    async fn insert_merchant(
        &self,
        state: &KeyManagerState,
        merchant_account: domain::MerchantAccount,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
        let mut accounts = self.merchant_accounts.lock().await;
        let account = Conversion::convert(merchant_account)
            .await
            .change_context(errors::StorageError::EncryptionError)?;
        accounts.push(account.clone());

        account
            .convert(
                state,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(errors::StorageError::DecryptionError)
    }

    #[allow(clippy::panic)]
    async fn find_merchant_account_by_merchant_id(
        &self,
        state: &KeyManagerState,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
        let accounts = self.merchant_accounts.lock().await;
        accounts
            .iter()
            .find(|account| account.get_id() == merchant_id)
            .cloned()
            .ok_or(errors::StorageError::ValueNotFound(format!(
                "Merchant ID: {merchant_id:?} not found",
            )))?
            .convert(
                state,
                merchant_key_store.key.get_inner(),
                merchant_key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(errors::StorageError::DecryptionError)
    }

    async fn update_merchant(
        &self,
        state: &KeyManagerState,
        merchant_account: domain::MerchantAccount,
        merchant_account_update: storage::MerchantAccountUpdate,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
        let merchant_id = merchant_account.get_id().to_owned();
        let mut accounts = self.merchant_accounts.lock().await;
        accounts
            .iter_mut()
            .find(|account| account.get_id() == merchant_account.get_id())
            .async_map(|account| async {
                let update = MerchantAccountUpdateInternal::from(merchant_account_update)
                    .apply_changeset(
                        Conversion::convert(merchant_account)
                            .await
                            .change_context(errors::StorageError::EncryptionError)?,
                    );
                *account = update.clone();
                update
                    .convert(
                        state,
                        merchant_key_store.key.get_inner(),
                        merchant_key_store.merchant_id.clone().into(),
                    )
                    .await
                    .change_context(errors::StorageError::DecryptionError)
            })
            .await
            .transpose()?
            .ok_or(
                errors::StorageError::ValueNotFound(format!(
                    "Merchant ID: {merchant_id:?} not found",
                ))
                .into(),
            )
    }

    async fn update_specific_fields_in_merchant(
        &self,
        state: &KeyManagerState,
        merchant_id: &common_utils::id_type::MerchantId,
        merchant_account_update: storage::MerchantAccountUpdate,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
        let mut accounts = self.merchant_accounts.lock().await;
        accounts
            .iter_mut()
            .find(|account| account.get_id() == merchant_id)
            .async_map(|account| async {
                let update = MerchantAccountUpdateInternal::from(merchant_account_update)
                    .apply_changeset(account.clone());
                *account = update.clone();
                update
                    .convert(
                        state,
                        merchant_key_store.key.get_inner(),
                        merchant_key_store.merchant_id.clone().into(),
                    )
                    .await
                    .change_context(errors::StorageError::DecryptionError)
            })
            .await
            .transpose()?
            .ok_or(
                errors::StorageError::ValueNotFound(format!(
                    "Merchant ID: {merchant_id:?} not found",
                ))
                .into(),
            )
    }

    async fn find_merchant_account_by_publishable_key(
        &self,
        state: &KeyManagerState,
        publishable_key: &str,
    ) -> CustomResult<(domain::MerchantAccount, domain::MerchantKeyStore), errors::StorageError>
    {
        let accounts = self.merchant_accounts.lock().await;
        let account = accounts
            .iter()
            .find(|account| {
                account
                    .publishable_key
                    .as_ref()
                    .is_some_and(|key| key == publishable_key)
            })
            .ok_or(errors::StorageError::ValueNotFound(format!(
                "Publishable Key: {publishable_key} not found",
            )))?;
        let key_store = self
            .get_merchant_key_store_by_merchant_id(
                state,
                account.get_id(),
                &self.get_master_key().to_vec().into(),
            )
            .await?;
        let merchant_account = account
            .clone()
            .convert(
                state,
                key_store.key.get_inner(),
                key_store.merchant_id.clone().into(),
            )
            .await
            .change_context(errors::StorageError::DecryptionError)?;
        Ok((merchant_account, key_store))
    }

    async fn update_all_merchant_account(
        &self,
        merchant_account_update: storage::MerchantAccountUpdate,
    ) -> CustomResult<usize, errors::StorageError> {
        let mut accounts = self.merchant_accounts.lock().await;
        Ok(accounts.iter_mut().fold(0, |acc, account| {
            let update = MerchantAccountUpdateInternal::from(merchant_account_update.clone())
                .apply_changeset(account.clone());
            *account = update;
            acc + 1
        }))
    }

    async fn delete_merchant_account_by_merchant_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> CustomResult<bool, errors::StorageError> {
        let mut accounts = self.merchant_accounts.lock().await;
        accounts.retain(|x| x.get_id() != merchant_id);
        Ok(true)
    }

    #[cfg(feature = "olap")]
    async fn list_merchant_accounts_by_organization_id(
        &self,
        state: &KeyManagerState,
        organization_id: &common_utils::id_type::OrganizationId,
    ) -> CustomResult<Vec<domain::MerchantAccount>, errors::StorageError> {
        let accounts = self.merchant_accounts.lock().await;
        let futures = accounts
            .iter()
            .filter(|account| account.organization_id == *organization_id)
            .map(|account| async {
                let key_store = self
                    .get_merchant_key_store_by_merchant_id(
                        state,
                        account.get_id(),
                        &self.get_master_key().to_vec().into(),
                    )
                    .await;
                match key_store {
                    Ok(key) => account
                        .clone()
                        .convert(state, key.key.get_inner(), key.merchant_id.clone().into())
                        .await
                        .change_context(errors::StorageError::DecryptionError),
                    Err(err) => Err(err),
                }
            });
        futures::future::join_all(futures)
            .await
            .into_iter()
            .collect()
    }

    #[cfg(feature = "olap")]
    async fn list_multiple_merchant_accounts(
        &self,
        state: &KeyManagerState,
        merchant_ids: Vec<common_utils::id_type::MerchantId>,
    ) -> CustomResult<Vec<domain::MerchantAccount>, errors::StorageError> {
        let accounts = self.merchant_accounts.lock().await;
        let futures = accounts
            .iter()
            .filter(|account| merchant_ids.contains(account.get_id()))
            .map(|account| async {
                let key_store = self
                    .get_merchant_key_store_by_merchant_id(
                        state,
                        account.get_id(),
                        &self.get_master_key().to_vec().into(),
                    )
                    .await;
                match key_store {
                    Ok(key) => account
                        .clone()
                        .convert(state, key.key.get_inner(), key.merchant_id.clone().into())
                        .await
                        .change_context(errors::StorageError::DecryptionError),
                    Err(err) => Err(err),
                }
            });
        futures::future::join_all(futures)
            .await
            .into_iter()
            .collect()
    }

    #[cfg(feature = "olap")]
    async fn list_merchant_and_org_ids(
        &self,
        _state: &KeyManagerState,
        limit: u32,
        offset: Option<u32>,
    ) -> CustomResult<
        Vec<(
            common_utils::id_type::MerchantId,
            common_utils::id_type::OrganizationId,
        )>,
        errors::StorageError,
    > {
        let accounts = self.merchant_accounts.lock().await;
        let limit = limit.try_into().unwrap_or(accounts.len());
        let offset = offset.unwrap_or(0).try_into().unwrap_or(0);

        let merchant_and_org_ids = accounts
            .iter()
            .skip(offset)
            .take(limit)
            .map(|account| (account.get_id().clone(), account.organization_id.clone()))
            .collect::<Vec<_>>();

        Ok(merchant_and_org_ids)
    }
}

#[cfg(feature = "accounts_cache")]
async fn publish_and_redact_merchant_account_cache(
    store: &dyn super::StorageInterface,
    merchant_account: &storage::MerchantAccount,
) -> CustomResult<(), errors::StorageError> {
    let publishable_key = merchant_account
        .publishable_key
        .as_ref()
        .map(|publishable_key| CacheKind::Accounts(publishable_key.into()));

    #[cfg(feature = "v1")]
    let cgraph_key = merchant_account.default_profile.as_ref().map(|profile_id| {
        CacheKind::CGraph(
            format!(
                "cgraph_{}_{}",
                merchant_account.get_id().get_string_repr(),
                profile_id.get_string_repr(),
            )
            .into(),
        )
    });

    // TODO: we will not have default profile in v2
    #[cfg(feature = "v2")]
    let cgraph_key = None;

    let mut cache_keys = vec![CacheKind::Accounts(
        merchant_account.get_id().get_string_repr().into(),
    )];

    cache_keys.extend(publishable_key.into_iter());
    cache_keys.extend(cgraph_key.into_iter());

    cache::redact_from_redis_and_publish(store.get_cache_store().as_ref(), cache_keys).await?;
    Ok(())
}

#[cfg(feature = "accounts_cache")]
async fn publish_and_redact_all_merchant_account_cache(
    store: &dyn super::StorageInterface,
    merchant_accounts: &[storage::MerchantAccount],
) -> CustomResult<(), errors::StorageError> {
    let merchant_ids = merchant_accounts
        .iter()
        .map(|merchant_account| merchant_account.get_id().get_string_repr().to_string());
    let publishable_keys = merchant_accounts
        .iter()
        .filter_map(|m| m.publishable_key.clone());

    let cache_keys: Vec<CacheKind<'_>> = merchant_ids
        .chain(publishable_keys)
        .map(|s| CacheKind::Accounts(s.into()))
        .collect();

    cache::redact_from_redis_and_publish(store.get_cache_store().as_ref(), cache_keys).await?;
    Ok(())
}


// Function: get_disputes_filters
// File: crates/router/src/routes/disputes.rs
// Module: router

pub fn get_disputes_filters(state: web::Data<AppState>, req: HttpRequest) -> HttpResponse


// Function: log_fraud_check
// File: crates/router/src/services/kafka.rs
// Module: router

pub fn log_fraud_check(
        &self,
        attempt: &FraudCheck,
        old_attempt: Option<FraudCheck>,
        tenant_id: TenantID,
    ) -> MQResult<()>


// Function: find_pm_collect_link_by_link_id
// File: crates/diesel_models/src/query/generic_link.rs
// Module: diesel_models

pub fn find_pm_collect_link_by_link_id(
        conn: &PgPooledConn,
        link_id: &str,
    ) -> StorageResult<PaymentMethodCollectLink>


// Implementation: impl Maskable
// File: crates/masking/src/maskable.rs
// Module: masking
// Methods: 5 total (5 public)

impl Maskable


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

impl api::PaymentAuthorize for for Worldpay


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

pub fn create_merchant_account_request_for_org(
    req: user_api::UserOrgMerchantCreateRequest,
    org: organization::Organization,
    product_type: common_enums::MerchantProductType,
) -> UserResult<api_models::admin::MerchantAccountCreate>


// File: crates/router/src/db/capture.rs
// Module: router

use router_env::{instrument, tracing};

use super::MockDb;
use crate::{
    core::errors::{self, CustomResult},
    types::storage::{self as types, enums},
};

#[async_trait::async_trait]
pub trait CaptureInterface {
    async fn insert_capture(
        &self,
        capture: types::CaptureNew,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<types::Capture, errors::StorageError>;

    async fn find_all_captures_by_merchant_id_payment_id_authorized_attempt_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        payment_id: &common_utils::id_type::PaymentId,
        authorized_attempt_id: &str,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<Vec<types::Capture>, errors::StorageError>;

    async fn update_capture_with_capture_id(
        &self,
        this: types::Capture,
        capture: types::CaptureUpdate,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<types::Capture, errors::StorageError>;
}

#[cfg(feature = "kv_store")]
mod storage {
    use error_stack::report;
    use router_env::{instrument, tracing};

    use super::CaptureInterface;
    use crate::{
        connection,
        core::errors::{self, CustomResult},
        services::Store,
        types::storage::{capture::*, enums},
    };

    #[async_trait::async_trait]
    impl CaptureInterface for Store {
        #[instrument(skip_all)]
        async fn insert_capture(
            &self,
            capture: CaptureNew,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Capture, errors::StorageError> {
            let db_call = || async {
                let conn = connection::pg_connection_write(self).await?;
                capture
                    .insert(&conn)
                    .await
                    .map_err(|error| report!(errors::StorageError::from(error)))
            };
            db_call().await
        }

        #[instrument(skip_all)]
        async fn update_capture_with_capture_id(
            &self,
            this: Capture,
            capture: CaptureUpdate,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Capture, errors::StorageError> {
            let db_call = || async {
                let conn = connection::pg_connection_write(self).await?;
                this.update_with_capture_id(&conn, capture)
                    .await
                    .map_err(|error| report!(errors::StorageError::from(error)))
            };
            db_call().await
        }

        #[instrument(skip_all)]
        async fn find_all_captures_by_merchant_id_payment_id_authorized_attempt_id(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            payment_id: &common_utils::id_type::PaymentId,
            authorized_attempt_id: &str,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Vec<Capture>, errors::StorageError> {
            let db_call = || async {
                let conn = connection::pg_connection_read(self).await?;
                Capture::find_all_by_merchant_id_payment_id_authorized_attempt_id(
                    merchant_id,
                    payment_id,
                    authorized_attempt_id,
                    &conn,
                )
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
            };
            db_call().await
        }
    }
}

#[cfg(not(feature = "kv_store"))]
mod storage {
    use error_stack::report;
    use router_env::{instrument, tracing};

    use super::CaptureInterface;
    use crate::{
        connection,
        core::errors::{self, CustomResult},
        services::Store,
        types::storage::{capture::*, enums},
    };

    #[async_trait::async_trait]
    impl CaptureInterface for Store {
        #[instrument(skip_all)]
        async fn insert_capture(
            &self,
            capture: CaptureNew,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Capture, errors::StorageError> {
            let db_call = || async {
                let conn = connection::pg_connection_write(self).await?;
                capture
                    .insert(&conn)
                    .await
                    .map_err(|error| report!(errors::StorageError::from(error)))
            };
            db_call().await
        }

        #[instrument(skip_all)]
        async fn update_capture_with_capture_id(
            &self,
            this: Capture,
            capture: CaptureUpdate,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Capture, errors::StorageError> {
            let db_call = || async {
                let conn = connection::pg_connection_write(self).await?;
                this.update_with_capture_id(&conn, capture)
                    .await
                    .map_err(|error| report!(errors::StorageError::from(error)))
            };
            db_call().await
        }

        #[instrument(skip_all)]
        async fn find_all_captures_by_merchant_id_payment_id_authorized_attempt_id(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            payment_id: &common_utils::id_type::PaymentId,
            authorized_attempt_id: &str,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Vec<Capture>, errors::StorageError> {
            let db_call = || async {
                let conn = connection::pg_connection_read(self).await?;
                Capture::find_all_by_merchant_id_payment_id_authorized_attempt_id(
                    merchant_id,
                    payment_id,
                    authorized_attempt_id,
                    &conn,
                )
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
            };
            db_call().await
        }
    }
}

#[async_trait::async_trait]
impl CaptureInterface for MockDb {
    async fn insert_capture(
        &self,
        capture: types::CaptureNew,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<types::Capture, errors::StorageError> {
        let mut captures = self.captures.lock().await;
        let capture = types::Capture {
            capture_id: capture.capture_id,
            payment_id: capture.payment_id,
            merchant_id: capture.merchant_id,
            status: capture.status,
            amount: capture.amount,
            currency: capture.currency,
            connector: capture.connector,
            error_message: capture.error_message,
            error_code: capture.error_code,
            error_reason: capture.error_reason,
            tax_amount: capture.tax_amount,
            created_at: capture.created_at,
            modified_at: capture.modified_at,
            authorized_attempt_id: capture.authorized_attempt_id,
            capture_sequence: capture.capture_sequence,
            connector_capture_id: capture.connector_capture_id,
            connector_response_reference_id: capture.connector_response_reference_id,
            processor_capture_data: capture.processor_capture_data,
            // Below fields are deprecated. Please add any new fields above this line.
            connector_capture_data: None,
        };
        captures.push(capture.clone());
        Ok(capture)
    }

    #[instrument(skip_all)]
    async fn update_capture_with_capture_id(
        &self,
        _this: types::Capture,
        _capture: types::CaptureUpdate,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<types::Capture, errors::StorageError> {
        //Implement function for `MockDb`
        Err(errors::StorageError::MockDbError)?
    }
    async fn find_all_captures_by_merchant_id_payment_id_authorized_attempt_id(
        &self,
        _merchant_id: &common_utils::id_type::MerchantId,
        _payment_id: &common_utils::id_type::PaymentId,
        _authorized_attempt_id: &str,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<Vec<types::Capture>, errors::StorageError> {
        //Implement function for `MockDb`
        Err(errors::StorageError::MockDbError)?
    }
}


// Function: connector_create
// File: crates/router/src/routes/admin.rs
// Module: router

pub fn connector_create(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<admin::MerchantConnectorCreate>,
) -> HttpResponse


// File: crates/analytics/src/payments/distribution/payment_error_message.rs
// Module: analytics

use api_models::analytics::{
    payments::{PaymentDimensions, PaymentFilters, PaymentMetricsBucketIdentifier},
    Granularity, PaymentDistributionBody, TimeRange,
};
use common_utils::errors::ReportSwitchExt;
use diesel_models::enums as storage_enums;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

use super::{PaymentDistribution, PaymentDistributionRow};
use crate::{
    enums::AuthInfo,
    query::{
        Aggregate, GroupByClause, Order, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window,
    },
    types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
};

#[derive(Default)]
pub(super) struct PaymentErrorMessage;

#[async_trait::async_trait]
impl<T> PaymentDistribution<T> for PaymentErrorMessage
where
    T: AnalyticsDataSource + super::PaymentDistributionAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_distribution(
        &self,
        distribution: &PaymentDistributionBody,
        dimensions: &[PaymentDimensions],
        auth: &AuthInfo,
        filters: &PaymentFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentDistributionRow)>> {
        let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::Payment);

        for dim in dimensions.iter() {
            query_builder.add_select_column(dim).switch()?;
        }

        query_builder
            .add_select_column(&distribution.distribution_for)
            .switch()?;

        query_builder
            .add_select_column(Aggregate::Count {
                field: None,
                alias: Some("count"),
            })
            .switch()?;
        query_builder
            .add_select_column(Aggregate::Min {
                field: "created_at",
                alias: Some("start_bucket"),
            })
            .switch()?;
        query_builder
            .add_select_column(Aggregate::Max {
                field: "created_at",
                alias: Some("end_bucket"),
            })
            .switch()?;

        filters.set_filter_clause(&mut query_builder).switch()?;

        auth.set_filter_clause(&mut query_builder).switch()?;

        time_range
            .set_filter_clause(&mut query_builder)
            .attach_printable("Error filtering time range")
            .switch()?;

        for dim in dimensions.iter() {
            query_builder
                .add_group_by_clause(dim)
                .attach_printable("Error grouping by dimensions")
                .switch()?;
        }

        query_builder
            .add_group_by_clause(&distribution.distribution_for)
            .attach_printable("Error grouping by distribution_for")
            .switch()?;

        if let Some(granularity) = granularity {
            granularity
                .set_group_by_clause(&mut query_builder)
                .attach_printable("Error adding granularity")
                .switch()?;
        }

        query_builder
            .add_filter_clause(
                PaymentDimensions::PaymentStatus,
                storage_enums::AttemptStatus::Failure,
            )
            .switch()?;

        for dim in dimensions.iter() {
            query_builder.add_outer_select_column(dim).switch()?;
        }

        query_builder
            .add_outer_select_column(&distribution.distribution_for)
            .switch()?;
        query_builder.add_outer_select_column("count").switch()?;
        query_builder
            .add_outer_select_column("start_bucket")
            .switch()?;
        query_builder
            .add_outer_select_column("end_bucket")
            .switch()?;
        let sql_dimensions = query_builder.transform_to_sql_values(dimensions).switch()?;

        query_builder
            .add_outer_select_column(Window::Sum {
                field: "count",
                partition_by: Some(sql_dimensions),
                order_by: None,
                alias: Some("total"),
            })
            .switch()?;

        query_builder
            .add_top_n_clause(
                dimensions,
                distribution.distribution_cardinality.into(),
                "count",
                Order::Descending,
            )
            .switch()?;

        query_builder
            .execute_query::<PaymentDistributionRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| {
                Ok((
                    PaymentMetricsBucketIdentifier::new(
                        i.currency.as_ref().map(|i| i.0),
                        i.status.as_ref().map(|i| i.0),
                        i.connector.clone(),
                        i.authentication_type.as_ref().map(|i| i.0),
                        i.payment_method.clone(),
                        i.payment_method_type.clone(),
                        i.client_source.clone(),
                        i.client_version.clone(),
                        i.profile_id.clone(),
                        i.card_network.clone(),
                        i.merchant_id.clone(),
                        i.card_last_4.clone(),
                        i.card_issuer.clone(),
                        i.error_reason.clone(),
                        i.routing_approach.as_ref().map(|i| i.0.clone()),
                        i.signature_network.clone(),
                        i.is_issuer_regulated,
                        i.is_debit_routed,
                        TimeRange {
                            start_time: match (granularity, i.start_bucket) {
                                (Some(g), Some(st)) => g.clip_to_start(st)?,
                                _ => time_range.start_time,
                            },
                            end_time: granularity.as_ref().map_or_else(
                                || Ok(time_range.end_time),
                                |g| i.end_bucket.map(|et| g.clip_to_end(et)).transpose(),
                            )?,
                        },
                    ),
                    i,
                ))
            })
            .collect::<error_stack::Result<
                Vec<(PaymentMetricsBucketIdentifier, PaymentDistributionRow)>,
                crate::query::PostProcessingError,
            >>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


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

impl Responder


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

impl ConnectorValidation for for Amazonpay


// Function: new
// File: crates/api_models/src/routing.rs
// Module: api_models

pub fn new(
        algorithm_id_with_timestamp: DynamicAlgorithmWithTimestamp<
            common_utils::id_type::RoutingId,
        >,
    ) -> Self


// Struct: FluidData
// File: crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FluidData


// Struct: NovalnetRefundsTransactionData
// File: crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NovalnetRefundsTransactionData