File: crates/analytics/src/payments/core.rs
 Public functions: 2

#![allow(dead_code)]
use std::collections::{HashMap, HashSet};

use api_models::analytics::{
    payments::{
        MetricsBucketResponse, PaymentDimensions, PaymentDistributions, PaymentMetrics,
        PaymentMetricsBucketIdentifier,
    },
    FilterValue, GetPaymentFiltersRequest, GetPaymentMetricRequest, PaymentFiltersResponse,
    PaymentsAnalyticsMetadata, PaymentsMetricsResponse,
};
use bigdecimal::ToPrimitive;
use common_enums::Currency;
use common_utils::errors::CustomResult;
use currency_conversion::{conversion::convert, types::ExchangeRates};
use error_stack::ResultExt;
use router_env::{
    instrument, logger,
    tracing::{self, Instrument},
};

use super::{
    distribution::PaymentDistributionRow,
    filters::{get_payment_filter_for_dimension, PaymentFilterRow},
    metrics::PaymentMetricRow,
    PaymentMetricsAccumulator,
};
use crate::{
    enums::AuthInfo,
    errors::{AnalyticsError, AnalyticsResult},
    metrics,
    payments::{PaymentDistributionAccumulator, PaymentMetricAccumulator},
    AnalyticsProvider,
};

#[derive(Debug)]
pub enum TaskType {
    MetricTask(
        PaymentMetrics,
        CustomResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>, AnalyticsError>,
    ),
    DistributionTask(
        PaymentDistributions,
        CustomResult<Vec<(PaymentMetricsBucketIdentifier, PaymentDistributionRow)>, AnalyticsError>,
    ),
}

#[instrument(skip_all)]
pub async fn get_metrics(
    pool: &AnalyticsProvider,
    ex_rates: &Option<ExchangeRates>,
    auth: &AuthInfo,
    req: GetPaymentMetricRequest,
) -> AnalyticsResult<PaymentsMetricsResponse<MetricsBucketResponse>> {
    let mut metrics_accumulator: HashMap<
        PaymentMetricsBucketIdentifier,
        PaymentMetricsAccumulator,
    > = HashMap::new();

    let mut set = tokio::task::JoinSet::new();
    for metric_type in req.metrics.iter().cloned() {
        let req = req.clone();
        let pool = pool.clone();
        let task_span = tracing::debug_span!(
            "analytics_payments_metrics_query",
            payment_metric = metric_type.as_ref()
        );

        // TODO: lifetime issues with joinset,
        // can be optimized away if joinset lifetime requirements are relaxed
        let auth_scoped = auth.to_owned();
        set.spawn(
            async move {
                let data = pool
                    .get_payment_metrics(
                        &metric_type,
                        &req.group_by_names.clone(),
                        &auth_scoped,
                        &req.filters,
                        req.time_series.map(|t| t.granularity),
                        &req.time_range,
                    )
                    .await
                    .change_context(AnalyticsError::UnknownError);
                TaskType::MetricTask(metric_type, data)
            }
            .instrument(task_span),
        );
    }

    if let Some(distribution) = req.clone().distribution {
        let req = req.clone();
        let pool = pool.clone();
        let task_span = tracing::debug_span!(
            "analytics_payments_distribution_query",
            payment_distribution = distribution.distribution_for.as_ref()
        );

        let auth_scoped = auth.to_owned();
        set.spawn(
            async move {
                let data = pool
                    .get_payment_distribution(
                        &distribution,
                        &req.group_by_names.clone(),
                        &auth_scoped,
                        &req.filters,
                        req.time_series.map(|t| t.granularity),
                        &req.time_range,
                    )
                    .await
                    .change_context(AnalyticsError::UnknownError);
                TaskType::DistributionTask(distribution.distribution_for, data)
            }
            .instrument(task_span),
        );
    }

    while let Some(task_type) = set
        .join_next()
        .await
        .transpose()
        .change_context(AnalyticsError::UnknownError)?
    {
        match task_type {
            TaskType::MetricTask(metric, data) => {
                let data = data?;
                let attributes = router_env::metric_attributes!(
                    ("metric_type", metric.to_string()),
                    ("source", pool.to_string()),
                );

                let value = u64::try_from(data.len());
                if let Ok(val) = value {
                    metrics::BUCKETS_FETCHED.record(val, attributes);
                    logger::debug!("Attributes: {:?}, Buckets fetched: {}", attributes, val);
                }

                for (id, value) in data {
                    logger::debug!(bucket_id=?id, bucket_value=?value, "Bucket row for metric {metric}");
                    let metrics_builder = metrics_accumulator.entry(id).or_default();
                    match metric {
                        PaymentMetrics::PaymentSuccessRate
                        | PaymentMetrics::SessionizedPaymentSuccessRate => metrics_builder
                            .payment_success_rate
                            .add_metrics_bucket(&value),
                        PaymentMetrics::PaymentCount | PaymentMetrics::SessionizedPaymentCount => {
                            metrics_builder.payment_count.add_metrics_bucket(&value)
                        }
                        PaymentMetrics::PaymentSuccessCount
                        | PaymentMetrics::SessionizedPaymentSuccessCount => {
                            metrics_builder.payment_success.add_metrics_bucket(&value)
                        }
                        PaymentMetrics::PaymentProcessedAmount
                        | PaymentMetrics::SessionizedPaymentProcessedAmount => {
                            metrics_builder.processed_amount.add_metrics_bucket(&value)
                        }
                        PaymentMetrics::AvgTicketSize
                        | PaymentMetrics::SessionizedAvgTicketSize => {
                            metrics_builder.avg_ticket_size.add_metrics_bucket(&value)
                        }
                        PaymentMetrics::RetriesCount | PaymentMetrics::SessionizedRetriesCount => {
                            metrics_builder.retries_count.add_metrics_bucket(&value);
                            metrics_builder
                                .retries_amount_processed
                                .add_metrics_bucket(&value)
                        }
                        PaymentMetrics::ConnectorSuccessRate
                        | PaymentMetrics::SessionizedConnectorSuccessRate => {
                            metrics_builder
                                .connector_success_rate
                                .add_metrics_bucket(&value);
                        }
                        PaymentMetrics::DebitRouting | PaymentMetrics::SessionizedDebitRouting => {
                            metrics_builder.debit_routing.add_metrics_bucket(&value);
                        }
                        PaymentMetrics::PaymentsDistribution => {
                            metrics_builder
                                .payments_distribution
                                .add_metrics_bucket(&value);
                        }
                        PaymentMetrics::FailureReasons => {
                            metrics_builder
                                .failure_reasons_distribution
                                .add_metrics_bucket(&value);
                        }
                    }
                }

                logger::debug!(
                    "Analytics Accumulated Results: metric: {}, results: {:#?}",
                    metric,
                    metrics_accumulator
                );
            }
            TaskType::DistributionTask(distribution, data) => {
                let data = data?;
                let attributes = router_env::metric_attributes!(
                    ("distribution_type", distribution.to_string()),
                    ("source", pool.to_string()),
                );

                let value = u64::try_from(data.len());
                if let Ok(val) = value {
                    metrics::BUCKETS_FETCHED.record(val, attributes);
                    logger::debug!("Attributes: {:?}, Buckets fetched: {}", attributes, val);
                }

                for (id, value) in data {
                    logger::debug!(bucket_id=?id, bucket_value=?value, "Bucket row for distribution {distribution}");
                    let metrics_accumulator = metrics_accumulator.entry(id).or_default();
                    match distribution {
                        PaymentDistributions::PaymentErrorMessage => metrics_accumulator
                            .payment_error_message
                            .add_distribution_bucket(&value),
                    }
                }

                logger::debug!(
                    "Analytics Accumulated Results: distribution: {}, results: {:#?}",
                    distribution,
                    metrics_accumulator
                );
            }
        }
    }
    let mut total_payment_processed_amount = 0;
    let mut total_payment_processed_count = 0;
    let mut total_payment_processed_amount_without_smart_retries = 0;
    let mut total_payment_processed_count_without_smart_retries = 0;
    let mut total_failure_reasons_count = 0;
    let mut total_failure_reasons_count_without_smart_retries = 0;
    let mut total_payment_processed_amount_in_usd = 0;
    let mut total_payment_processed_amount_without_smart_retries_usd = 0;
    let query_data: Vec<MetricsBucketResponse> = metrics_accumulator
        .into_iter()
        .map(|(id, val)| {
            let mut collected_values = val.collect();
            if let Some(amount) = collected_values.payment_processed_amount {
                let amount_in_usd = if let Some(ex_rates) = ex_rates {
                    id.currency
                        .and_then(|currency| {
                            i64::try_from(amount)
                                .inspect_err(|e| logger::error!("Amount conversion error: {:?}", e))
                                .ok()
                                .and_then(|amount_i64| {
                                    convert(ex_rates, currency, Currency::USD, amount_i64)
                                        .inspect_err(|e| {
                                            logger::error!("Currency conversion error: {:?}", e)
                                        })
                                        .ok()
                                })
                        })
                        .map(|amount| (amount * rust_decimal::Decimal::new(100, 0)).to_u64())
                        .unwrap_or_default()
                } else {
                    None
                };
                collected_values.payment_processed_amount_in_usd = amount_in_usd;
                total_payment_processed_amount += amount;
                total_payment_processed_amount_in_usd += amount_in_usd.unwrap_or(0);
            }
            if let Some(count) = collected_values.payment_processed_count {
                total_payment_processed_count += count;
            }
            if let Some(amount) = collected_values.payment_processed_amount_without_smart_retries {
                let amount_in_usd = if let Some(ex_rates) = ex_rates {
                    id.currency
                        .and_then(|currency| {
                            i64::try_from(amount)
                                .inspect_err(|e| logger::error!("Amount conversion error: {:?}", e))
                                .ok()
                                .and_then(|amount_i64| {
                                    convert(ex_rates, currency, Currency::USD, amount_i64)
                                        .inspect_err(|e| {
                                            logger::error!("Currency conversion error: {:?}", e)
                                        })
                                        .ok()
                                })
                        })
                        .map(|amount| (amount * rust_decimal::Decimal::new(100, 0)).to_u64())
                        .unwrap_or_default()
                } else {
                    None
                };
                collected_values.payment_processed_amount_without_smart_retries_usd = amount_in_usd;
                total_payment_processed_amount_without_smart_retries += amount;
                total_payment_processed_amount_without_smart_retries_usd +=
                    amount_in_usd.unwrap_or(0);
            }
            if let Some(count) = collected_values.payment_processed_count_without_smart_retries {
                total_payment_processed_count_without_smart_retries += count;
            }
            if let Some(count) = collected_values.failure_reason_count {
                total_failure_reasons_count += count;
            }
            if let Some(count) = collected_values.failure_reason_count_without_smart_retries {
                total_failure_reasons_count_without_smart_retries += count;
            }
            if let Some(savings) = collected_values.debit_routing_savings {
                let savings_in_usd = if let Some(ex_rates) = ex_rates {
                    id.currency
                        .and_then(|currency| {
                            i64::try_from(savings)
                                .inspect_err(|e| {
                                    logger::error!(
                                        "Debit Routing savings conversion error: {:?}",
                                        e
                                    )
                                })
                                .ok()
                                .and_then(|savings_i64| {
                                    convert(ex_rates, currency, Currency::USD, savings_i64)
                                        .inspect_err(|e| {
                                            logger::error!("Currency conversion error: {:?}", e)
                                        })
                                        .ok()
                                })
                        })
                        .map(|savings| (savings * rust_decimal::Decimal::new(100, 0)).to_u64())
                        .unwrap_or_default()
                } else {
                    None
                };
                collected_values.debit_routing_savings_in_usd = savings_in_usd;
            }
            MetricsBucketResponse {
                values: collected_values,
                dimensions: id,
            }
        })
        .collect();
    Ok(PaymentsMetricsResponse {
        query_data,
        meta_data: [PaymentsAnalyticsMetadata {
            total_payment_processed_amount: Some(total_payment_processed_amount),
            total_payment_processed_amount_in_usd: if ex_rates.is_some() {
                Some(total_payment_processed_amount_in_usd)
            } else {
                None
            },
            total_payment_processed_amount_without_smart_retries: Some(
                total_payment_processed_amount_without_smart_retries,
            ),
            total_payment_processed_amount_without_smart_retries_usd: if ex_rates.is_some() {
                Some(total_payment_processed_amount_without_smart_retries_usd)
            } else {
                None
            },
            total_payment_processed_count: Some(total_payment_processed_count),
            total_payment_processed_count_without_smart_retries: Some(
                total_payment_processed_count_without_smart_retries,
            ),
            total_failure_reasons_count: Some(total_failure_reasons_count),
            total_failure_reasons_count_without_smart_retries: Some(
                total_failure_reasons_count_without_smart_retries,
            ),
        }],
    })
}

pub async fn get_filters(
    pool: &AnalyticsProvider,
    req: GetPaymentFiltersRequest,
    auth: &AuthInfo,
) -> AnalyticsResult<PaymentFiltersResponse> {
    let mut res = PaymentFiltersResponse::default();

    for dim in req.group_by_names {
        let values = match pool {
                        AnalyticsProvider::Sqlx(pool) => {
                get_payment_filter_for_dimension(dim, auth, &req.time_range, pool)
                    .await
            }
                        AnalyticsProvider::Clickhouse(pool) => {
                get_payment_filter_for_dimension(dim, auth, &req.time_range, pool)
                    .await
            }
                    AnalyticsProvider::CombinedCkh(sqlx_poll, ckh_pool) => {
                let ckh_result = get_payment_filter_for_dimension(
                    dim,
                    auth,
                    &req.time_range,
                    ckh_pool,
                )
                .await;
                let sqlx_result = get_payment_filter_for_dimension(
                    dim,
                    auth,
                    &req.time_range,
                    sqlx_poll,
                )
                .await;
                match (&sqlx_result, &ckh_result) {
                    (Ok(ref sqlx_res), Ok(ref ckh_res)) if sqlx_res != ckh_res => {
                        router_env::logger::error!(clickhouse_result=?ckh_res, postgres_result=?sqlx_res, "Mismatch between clickhouse & postgres payments analytics filters")
                    },
                    _ => {}
                };
                ckh_result
            }
                    AnalyticsProvider::CombinedSqlx(sqlx_poll, ckh_pool) => {
                let ckh_result = get_payment_filter_for_dimension(
                    dim,
                    auth,
                    &req.time_range,
                    ckh_pool,
                )
                .await;
                let sqlx_result = get_payment_filter_for_dimension(
                    dim,
                    auth,
                    &req.time_range,
                    sqlx_poll,
                )
                .await;
                match (&sqlx_result, &ckh_result) {
                    (Ok(ref sqlx_res), Ok(ref ckh_res)) if sqlx_res != ckh_res => {
                        router_env::logger::error!(clickhouse_result=?ckh_res, postgres_result=?sqlx_res, "Mismatch between clickhouse & postgres payments analytics filters")
                    },
                    _ => {}
                };
                sqlx_result
            }
        }
        .change_context(AnalyticsError::UnknownError)?
        .into_iter()
        .filter_map(|fil: PaymentFilterRow| match dim {
            PaymentDimensions::Currency => fil.currency.map(|i| i.as_ref().to_string()),
            PaymentDimensions::PaymentStatus => fil.status.map(|i| i.as_ref().to_string()),
            PaymentDimensions::Connector => fil.connector,
            PaymentDimensions::AuthType => fil.authentication_type.map(|i| i.as_ref().to_string()),
            PaymentDimensions::PaymentMethod => fil.payment_method,
            PaymentDimensions::PaymentMethodType => fil.payment_method_type,
            PaymentDimensions::ClientSource => fil.client_source,
            PaymentDimensions::ClientVersion => fil.client_version,
            PaymentDimensions::ProfileId => fil.profile_id,
            PaymentDimensions::CardNetwork => fil.card_network,
            PaymentDimensions::MerchantId => fil.merchant_id,
            PaymentDimensions::CardLast4 => fil.card_last_4,
            PaymentDimensions::CardIssuer => fil.card_issuer,
            PaymentDimensions::ErrorReason => fil.error_reason,
            PaymentDimensions::RoutingApproach => fil.routing_approach.map(|i| i.as_ref().to_string()),
            PaymentDimensions::SignatureNetwork => fil.signature_network,
            PaymentDimensions::IsIssuerRegulated => fil.is_issuer_regulated.map(|b| b.to_string()),
            PaymentDimensions::IsDebitRouted => fil.is_debit_routed.map(|b| b.to_string())
        })
        .collect::<Vec<String>>();
        res.query_data.push(FilterValue {
            dimension: dim,
            values,
        })
    }
    Ok(res)
}


pub struct SantanderMetadataObject {
    pub pix_key: Secret<String>,
    pub expiration_time: i32,
    pub cpf: Secret<String>,
    pub merchant_city: String,
    pub merchant_name: String,
    pub workspace_id: String,
    pub covenant_code: String, // max_size : 9
}


impl Datatrans {
    pub const fn new() -> &'static Self {
        &Self {
            amount_converter: &MinorUnitForConnector,
        }
    }
}


pub fn get_specific_file_key(theme_id: &str, file_name: &str) -> PathBuf {
    let mut path = get_theme_dir_key(theme_id);
    path.push(file_name);
    path
}


impl api::ConnectorAccessToken for Billwerk {}

impl api::ConnectorAccessToken for for Billwerk


impl api::ConnectorAccessToken for Nordea {}

impl api::ConnectorAccessToken for for Nordea


pub struct PaymentStatusData<F>
where
    F: Clone,
{
    pub flow: PhantomData<F>,
    pub payment_intent: PaymentIntent,
    pub payment_attempt: PaymentAttempt,
    pub payment_address: payment_address::PaymentAddress,
    pub attempts: Option<Vec<PaymentAttempt>>,
    /// Should the payment status be synced with connector
    /// This will depend on the payment status and the force sync flag in the request
    pub should_sync_with_connector: bool,
    pub merchant_connector_details: Option<common_types::domain::MerchantConnectorAuthDetails>,
}


pub async fn mk_delete_card_request_hs_by_id(
    jwekey: &settings::Jwekey,
    locker: &settings::Locker,
    id: &String,
    merchant_id: &id_type::MerchantId,
    card_reference: &str,
    tenant_id: id_type::TenantId,
    request_id: Option<RequestId>,
) -> CustomResult<services::Request, errors::VaultError> {
    let merchant_customer_id = id.to_owned();
    let card_req_body = CardReqBodyV2 {
        merchant_id: merchant_id.to_owned(),
        merchant_customer_id,
        card_reference: card_reference.to_owned(),
    };
    let payload = card_req_body
        .encode_to_vec()
        .change_context(errors::VaultError::RequestEncodingFailed)?;

    let private_key = jwekey.vault_private_key.peek().as_bytes();

    let jws = encryption::jws_sign_payload(&payload, &locker.locker_signing_key_id, private_key)
        .await
        .change_context(errors::VaultError::RequestEncodingFailed)?;

    let jwe_payload =
        mk_basilisk_req(jwekey, &jws, api_enums::LockerChoice::HyperswitchCardVault).await?;

    let mut url = locker.host.to_owned();
    url.push_str("/cards/delete");
    let mut request = services::Request::new(services::Method::Post, &url);
    request.add_header(headers::CONTENT_TYPE, "application/json".into());
    request.add_header(
        headers::X_TENANT_ID,
        tenant_id.get_string_repr().to_owned().into(),
    );
    if let Some(req_id) = request_id {
        request.add_header(
            headers::X_REQUEST_ID,
            req_id.as_hyphenated().to_string().into(),
        );
    }

    request.set_body(RequestContent::Json(Box::new(jwe_payload)));
    Ok(request)
}


pub struct ProfileAcquirerConfigs {
    pub acquirer_config_map: Option<common_types::domain::AcquirerConfigMap>,
    pub profile_id: common_utils::id_type::ProfileId,
}


pub async fn set_metadata(
    state: SessionState,
    user: UserFromToken,
    request: api::SetMetaDataRequest,
    _req_state: ReqState,
) -> UserResponse<()> {
    let metadata_value = parse_set_request(request)?;
    let metadata_key = DBEnum::from(&metadata_value);

    insert_metadata(&state, user, metadata_key, metadata_value).await?;

    Ok(ApplicationResponse::StatusOk)
}


pub async fn success_based_routing_update_configs(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<routing_types::DynamicRoutingUpdateConfigQuery>,
    json_payload: web::Json<routing_types::SuccessBasedRoutingConfig>,
) -> impl Responder {
    let flow = Flow::UpdateDynamicRoutingConfigs;
    let routing_payload_wrapper = routing_types::SuccessBasedRoutingPayloadWrapper {
        updated_config: json_payload.into_inner(),
        algorithm_id: path.clone().algorithm_id,
        profile_id: path.clone().profile_id,
    };
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        routing_payload_wrapper.clone(),
        |state, _, wrapper: routing_types::SuccessBasedRoutingPayloadWrapper, _| async {
            Box::pin(routing::success_based_routing_update_configs(
                state,
                wrapper.updated_config,
                wrapper.algorithm_id,
                wrapper.profile_id,
            ))
            .await
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuthProfileFromRoute {
                profile_id: routing_payload_wrapper.profile_id,
                required_permission: Permission::ProfileRoutingWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub struct StoreCardResp {
    pub status: String,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub payload: Option<StoreCardRespPayload>,
}


pub struct OrderInformationWithBill {
    amount_details: Amount,
    bill_to: Option<BillTo>,
}


pub struct Mistercash {
    pub mobile_pay_button_position: Option<String>,
    pub disable_mobile_pay_button: Option<String>,
    pub qr_only: Option<String>,
    pub qr_size: Option<String>,
}


pub struct GetnetRefundRequest {
    pub payment: RefundPaymentData,
}


OpenAPI Block Path: components.schemas.DecisionEngineSuccessRateData
{
  "type": "object",
  "properties": {
    "defaultLatencyThreshold": {
      "type": "number",
      "format": "double",
      "nullable": true
    },
    "defaultBucketSize": {
      "type": "integer",
      "format": "int32",
      "nullable": true
    },
    "defaultHedgingPercent": {
      "type": "number",
      "format": "double",
      "nullable": true
    },
    "defaultLowerResetFactor": {
      "type": "number",
      "format": "double",
      "nullable": true
    },
    "defaultUpperResetFactor": {
      "type": "number",
      "format": "double",
      "nullable": true
    },
    "defaultGatewayExtraScore": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/DecisionEngineGatewayWiseExtraScore"
      },
      "nullable": true
    },
    "subLevelInputConfig": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/DecisionEngineSRSubLevelInputConfig"
      },
      "nullable": true
    }
  }
}


pub struct LockerMockUp {
    pub card_id: String,
    pub external_id: String,
    pub card_fingerprint: String,
    pub card_global_fingerprint: String,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub card_number: String,
    pub card_exp_year: String,
    pub card_exp_month: String,
    pub name_on_card: Option<String>,
    pub nickname: Option<String>,
    pub customer_id: Option<common_utils::id_type::CustomerId>,
    pub duplicate: Option<bool>,
    pub card_cvc: Option<String>,
    pub payment_method_id: Option<String>,
    pub enc_card_data: Option<String>,
}


impl api::PaymentAuthorize for Worldpay {}

impl api::PaymentAuthorize for for Worldpay


pub struct BamboraapacMeta {
    pub authorize_id: String,
}


pub struct PayuPaymentStatusData {
    status_code: PayuPaymentStatus,
    severity: Option<String>,
    status_desc: Option<String>,
}


pub fn log_and_return_error_response<T>(error: Report<T>) -> HttpResponse
where
    T: error_stack::Context + ResponseError + Clone,
{
    logger::error!(?error);
    let body = serde_json::json!({
        "message": error.to_string()
    })
    .to_string();
    HttpResponse::InternalServerError()
        .content_type(mime::APPLICATION_JSON)
        .body(body)
}


pub struct CaptureOptions {
    capture_sequence_number: u32,
    total_capture_count: u32,
}


pub fn get_entity_id_and_type(&self) -> Option<(String, EntityType)> {
        match (self.version, self.entity_type, self.role_id.as_str()) {
            (enums::UserRoleVersion::V1, None, consts::ROLE_ID_ORGANIZATION_ADMIN) => {
                let org_id = self.org_id.clone()?.get_string_repr().to_string();
                Some((org_id, EntityType::Organization))
            }
            (enums::UserRoleVersion::V1, None, _) => {
                let merchant_id = self.merchant_id.clone()?.get_string_repr().to_string();
                Some((merchant_id, EntityType::Merchant))
            }
            (enums::UserRoleVersion::V1, Some(_), _) => {
                self.entity_id.clone().zip(self.entity_type)
            }
            (enums::UserRoleVersion::V2, _, _) => self.entity_id.clone().zip(self.entity_type),
        }
    }


pub struct SquareAuthType {
    pub(super) api_key: Secret<String>,
    pub(super) key1: Secret<String>,
}


pub struct PaymentOptions {
    pub notification_url: Option<String>,
    pub notification_method: Option<String>,
    pub redirect_url: String,
    pub cancel_url: String,
    pub close_window: Option<bool>,
    pub settings: Option<Settings>,
    pub template_id: Option<String>,
    pub allowed_countries: Option<Vec<String>>,
}


pub struct Capture;


pub struct ApiErrorResponse {
    pub message: String,
    pub errors: ErrorsObject,
}


pub fn new(
        algorithm_id_with_timestamp: DynamicAlgorithmWithTimestamp<
            common_utils::id_type::RoutingId,
        >,
    ) -> Self {
        Self {
            algorithm_id_with_timestamp,
            enabled_feature: DynamicRoutingFeatures::None,
        }
    }


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

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Base
    }

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

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

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

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

        event_builder.map(|i| i.set_error_response_body(&response));

        let mut error_response = ErrorResponse::from(&response);

        // Set status code from the response, or 400 if error code is a "404"
        if let Some(error_code) = &response.error.code {
            if error_code == "404" {
                error_response.status_code = 404;
            } else {
                error_response.status_code = res.status_code;
            }
        } else {
            error_response.status_code = res.status_code;
        }

        Ok(error_response)
    }
}


impl api::PaymentSession for CtpMastercard {}

impl api::PaymentSession for for CtpMastercard


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

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        // Silverflow processes amounts in minor units (cents)
        api::CurrencyUnit::Minor
    }

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

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

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = silverflow::SilverflowAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        let auth_string = format!("{}:{}", auth.api_key.expose(), auth.api_secret.expose());
        let encoded = common_utils::consts::BASE64_ENGINE.encode(auth_string.as_bytes());
        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            format!("Basic {encoded}").into_masked(),
        )])
    }

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

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

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.error.code,
            message: response.error.message,
            reason: response
                .error
                .details
                .map(|d| format!("Field: {}, Issue: {}", d.field, d.issue)),
            attempt_status: None,
            connector_transaction_id: None,
            network_decline_code: None,
            network_advice_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}


impl api::Refund for Bluesnap {}


pub struct CustomerDetails {
    pub customer_id: Option<id_type::CustomerId>,
    pub name: Option<Secret<String, masking::WithType>>,
    pub email: Option<pii::Email>,
    pub phone: Option<Secret<String, masking::WithType>>,
    pub phone_country_code: Option<String>,
    pub tax_registration_id: Option<Secret<String, masking::WithType>>,
}


pub async fn payouts_list_filters() {}


pub async fn config_should_call_gsm(
    db: &dyn StorageInterface,
    merchant_id: &common_utils::id_type::MerchantId,
    profile: &domain::Profile,
) -> bool {
    let merchant_config_gsm = get_merchant_config_for_gsm(db, merchant_id).await;
    let profile_config_gsm = profile.is_auto_retries_enabled;
    merchant_config_gsm || profile_config_gsm
}


Documentation: api-reference/v1/payment-methods/payment-method--update.mdx
# Type: Doc File

---
openapi: post /payment_methods/{method_id}/update
---


pub async fn internal_payments_operation_core<F, Req, Op, FData, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: domain::MerchantContext,
    profile: &domain::Profile,
    operation: Op,
    req: Req,
    get_tracker_response: operations::GetTrackerResponse<D>,
    call_connector_action: CallConnectorAction,
    header_payload: HeaderPayload,
) -> RouterResult<(
    D,
    Req,
    Option<u16>,
    Option<u128>,
    common_types::domain::ConnectorResponseData,
)>
where
    F: Send + Clone + Sync,
    Req: Send + Sync + Authenticate,
    Op: Operation<F, Req, Data = D> + Send + Sync,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,

    // To create connector flow specific interface data
    D: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
    RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,

    // To construct connector flow specific api
    dyn api::Connector:
        services::api::ConnectorIntegration<F, FData, router_types::PaymentsResponseData>,

    RouterData<F, FData, router_types::PaymentsResponseData>:
        hyperswitch_domain_models::router_data::TrackerPostUpdateObjects<F, FData, D>,

    // To perform router related operation for PaymentResponse
    PaymentResponse: Operation<F, FData, Data = D>,
    FData: Send + Sync + Clone,
{
    let operation: BoxedOperation<'_, F, Req, D> = Box::new(operation);

    // Get the trackers related to track the state of the payment
    let operations::GetTrackerResponse { mut payment_data } = get_tracker_response;

    let connector_data = operation
        .to_domain()?
        .get_connector_from_request(state, &req, &mut payment_data)
        .await?;

    let merchant_connector_account = payment_data
        .get_merchant_connector_details()
        .map(domain::MerchantConnectorAccountTypeDetails::MerchantConnectorDetails)
        .ok_or_else(|| {
            error_stack::report!(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Merchant connector details not found in payment data")
        })?;

    operation
        .to_domain()?
        .populate_payment_data(
            state,
            &mut payment_data,
            &merchant_context,
            profile,
            &connector_data,
        )
        .await?;

    let router_data = connector_service_decider(
        state,
        req_state.clone(),
        &merchant_context,
        connector_data.clone(),
        &operation,
        &mut payment_data,
        call_connector_action.clone(),
        header_payload.clone(),
        profile,
        req.should_return_raw_response(),
        merchant_connector_account,
    )
    .await?;

    let connector_response_data = common_types::domain::ConnectorResponseData {
        raw_connector_response: router_data.raw_connector_response.clone(),
    };

    let payments_response_operation = Box::new(PaymentResponse);

    let connector_http_status_code = router_data.connector_http_status_code;
    add_connector_http_status_code_metrics(connector_http_status_code);

    let payment_data = payments_response_operation
        .to_post_update_tracker()?
        .update_tracker(
            state,
            payment_data,
            router_data,
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await?;

    Ok((
        payment_data,
        req,
        connector_http_status_code,
        None,
        connector_response_data,
    ))
}


pub async fn retrieve_disputes_list_profile(
    state: web::Data<AppState>,
    req: HttpRequest,
    payload: web::Query<dispute_models::DisputeListGetConstraints>,
) -> HttpResponse {
    let flow = Flow::DisputesList;
    let payload = payload.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            disputes::retrieve_disputes_list(
                state,
                merchant_context,
                auth.profile_id.map(|profile_id| vec![profile_id]),
                req,
            )
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuth {
                permission: Permission::ProfileDisputeRead,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


File: crates/masking/src/string.rs

//! Secret strings
//!
//! There is not alias type by design.

use alloc::{
    str::FromStr,
    string::{String, ToString},
};

#[cfg(feature = "serde")]
use super::SerializableSecret;
use super::{Secret, Strategy};
use crate::StrongSecret;

#[cfg(feature = "serde")]
impl SerializableSecret for String {}

impl<I> FromStr for Secret<String, I>
where
    I: Strategy<String>,
{
    type Err = core::convert::Infallible;

    fn from_str(src: &str) -> Result<Self, Self::Err> {
        Ok(Self::new(src.to_string()))
    }
}

impl<I> FromStr for StrongSecret<String, I>
where
    I: Strategy<String>,
{
    type Err = core::convert::Infallible;

    fn from_str(src: &str) -> Result<Self, Self::Err> {
        Ok(Self::new(src.to_string()))
    }
}


pub trait PaymentMetric<T>
where
    T: AnalyticsDataSource + PaymentMetricAnalytics,
{
    async fn load_metrics(
        &self,
        dimensions: &[PaymentDimensions],
        auth: &AuthInfo,
        filters: &PaymentFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>>;
}


pub struct ClientReferenceInformation {
    code: Option<String>,
}


File: crates/hyperswitch_constraint_graph/src/builder.rs
 Public functions: 8
 Public structs: 1

use std::sync::Arc;

use rustc_hash::{FxHashMap, FxHashSet};

use crate::{
    dense_map::DenseMap,
    error::GraphError,
    graph::ConstraintGraph,
    types::{
        DomainId, DomainIdentifier, DomainInfo, Edge, EdgeId, Metadata, Node, NodeId, NodeType,
        NodeValue, Relation, Strength, ValueNode,
    },
};

pub enum DomainIdOrIdentifier {
    DomainId(DomainId),
    DomainIdentifier(DomainIdentifier),
}

impl From<String> for DomainIdOrIdentifier {
    fn from(value: String) -> Self {
        Self::DomainIdentifier(DomainIdentifier::new(value))
    }
}

impl From<DomainIdentifier> for DomainIdOrIdentifier {
    fn from(value: DomainIdentifier) -> Self {
        Self::DomainIdentifier(value)
    }
}

impl From<DomainId> for DomainIdOrIdentifier {
    fn from(value: DomainId) -> Self {
        Self::DomainId(value)
    }
}
#[derive(Debug)]
pub struct ConstraintGraphBuilder<V: ValueNode> {
    domain: DenseMap<DomainId, DomainInfo>,
    nodes: DenseMap<NodeId, Node<V>>,
    edges: DenseMap<EdgeId, Edge>,
    domain_identifier_map: FxHashMap<DomainIdentifier, DomainId>,
    value_map: FxHashMap<NodeValue<V>, NodeId>,
    edges_map: FxHashMap<(NodeId, NodeId, Option<DomainId>), EdgeId>,
    node_info: DenseMap<NodeId, Option<&'static str>>,
    node_metadata: DenseMap<NodeId, Option<Arc<dyn Metadata>>>,
}

#[allow(clippy::new_without_default)]
impl<V> ConstraintGraphBuilder<V>
where
    V: ValueNode,
{
    pub fn new() -> Self {
        Self {
            domain: DenseMap::new(),
            nodes: DenseMap::new(),
            edges: DenseMap::new(),
            domain_identifier_map: FxHashMap::default(),
            value_map: FxHashMap::default(),
            edges_map: FxHashMap::default(),
            node_info: DenseMap::new(),
            node_metadata: DenseMap::new(),
        }
    }

    pub fn build(self) -> ConstraintGraph<V> {
        ConstraintGraph {
            domain: self.domain,
            domain_identifier_map: self.domain_identifier_map,
            nodes: self.nodes,
            edges: self.edges,
            value_map: self.value_map,
            node_info: self.node_info,
            node_metadata: self.node_metadata,
        }
    }

    fn retrieve_domain_from_identifier(
        &self,
        domain_ident: DomainIdentifier,
    ) -> Result<DomainId, GraphError<V>> {
        self.domain_identifier_map
            .get(&domain_ident)
            .copied()
            .ok_or(GraphError::DomainNotFound)
    }

    pub fn make_domain(
        &mut self,
        domain_identifier: String,
        domain_description: &str,
    ) -> Result<DomainId, GraphError<V>> {
        let domain_identifier = DomainIdentifier::new(domain_identifier);
        Ok(self
            .domain_identifier_map
            .clone()
            .get(&domain_identifier)
            .map_or_else(
                || {
                    let domain_id = self.domain.push(DomainInfo {
                        domain_identifier: domain_identifier.clone(),
                        domain_description: domain_description.to_string(),
                    });
                    self.domain_identifier_map
                        .insert(domain_identifier, domain_id);
                    domain_id
                },
                |domain_id| *domain_id,
            ))
    }

    pub fn make_value_node<M: Metadata>(
        &mut self,
        value: NodeValue<V>,
        info: Option<&'static str>,
        metadata: Option<M>,
    ) -> NodeId {
        self.value_map.get(&value).copied().unwrap_or_else(|| {
            let node_id = self.nodes.push(Node::new(NodeType::Value(value.clone())));
            let _node_info_id = self.node_info.push(info);

            let _node_metadata_id = self
                .node_metadata
                .push(metadata.map(|meta| -> Arc<dyn Metadata> { Arc::new(meta) }));

            self.value_map.insert(value, node_id);
            node_id
        })
    }

    pub fn make_edge<T: Into<DomainIdOrIdentifier>>(
        &mut self,
        pred_id: NodeId,
        succ_id: NodeId,
        strength: Strength,
        relation: Relation,
        domain: Option<T>,
    ) -> Result<EdgeId, GraphError<V>> {
        self.ensure_node_exists(pred_id)?;
        self.ensure_node_exists(succ_id)?;
        let domain_id = domain
            .map(|d| match d.into() {
                DomainIdOrIdentifier::DomainIdentifier(ident) => {
                    self.retrieve_domain_from_identifier(ident)
                }
                DomainIdOrIdentifier::DomainId(domain_id) => {
                    self.ensure_domain_exists(domain_id).map(|_| domain_id)
                }
            })
            .transpose()?;
        self.edges_map
            .get(&(pred_id, succ_id, domain_id))
            .copied()
            .and_then(|edge_id| self.edges.get(edge_id).cloned().map(|edge| (edge_id, edge)))
            .map_or_else(
                || {
                    let edge_id = self.edges.push(Edge {
                        strength,
                        relation,
                        pred: pred_id,
                        succ: succ_id,
                        domain: domain_id,
                    });
                    self.edges_map
                        .insert((pred_id, succ_id, domain_id), edge_id);

                    let pred = self
                        .nodes
                        .get_mut(pred_id)
                        .ok_or(GraphError::NodeNotFound)?;
                    pred.succs.push(edge_id);

                    let succ = self
                        .nodes
                        .get_mut(succ_id)
                        .ok_or(GraphError::NodeNotFound)?;
                    succ.preds.push(edge_id);

                    Ok(edge_id)
                },
                |(edge_id, edge)| {
                    if edge.strength == strength && edge.relation == relation {
                        Ok(edge_id)
                    } else {
                        Err(GraphError::ConflictingEdgeCreated)
                    }
                },
            )
    }

    pub fn make_all_aggregator<M: Metadata>(
        &mut self,
        nodes: &[(NodeId, Relation, Strength)],
        info: Option<&'static str>,
        metadata: Option<M>,
        domain_id: Option<DomainId>,
    ) -> Result<NodeId, GraphError<V>> {
        nodes
            .iter()
            .try_for_each(|(node_id, _, _)| self.ensure_node_exists(*node_id))?;

        let aggregator_id = self.nodes.push(Node::new(NodeType::AllAggregator));
        let _aggregator_info_id = self.node_info.push(info);

        let _node_metadata_id = self
            .node_metadata
            .push(metadata.map(|meta| -> Arc<dyn Metadata> { Arc::new(meta) }));

        for (node_id, relation, strength) in nodes {
            self.make_edge(*node_id, aggregator_id, *strength, *relation, domain_id)?;
        }

        Ok(aggregator_id)
    }

    pub fn make_any_aggregator<M: Metadata>(
        &mut self,
        nodes: &[(NodeId, Relation, Strength)],
        info: Option<&'static str>,
        metadata: Option<M>,
        domain_id: Option<DomainId>,
    ) -> Result<NodeId, GraphError<V>> {
        nodes
            .iter()
            .try_for_each(|(node_id, _, _)| self.ensure_node_exists(*node_id))?;

        let aggregator_id = self.nodes.push(Node::new(NodeType::AnyAggregator));
        let _aggregator_info_id = self.node_info.push(info);

        let _node_metadata_id = self
            .node_metadata
            .push(metadata.map(|meta| -> Arc<dyn Metadata> { Arc::new(meta) }));

        for (node_id, relation, strength) in nodes {
            self.make_edge(*node_id, aggregator_id, *strength, *relation, domain_id)?;
        }

        Ok(aggregator_id)
    }

    pub fn make_in_aggregator<M: Metadata>(
        &mut self,
        values: Vec<V>,
        info: Option<&'static str>,
        metadata: Option<M>,
    ) -> Result<NodeId, GraphError<V>> {
        let key = values
            .first()
            .ok_or(GraphError::NoInAggregatorValues)?
            .get_key();

        for val in &values {
            if val.get_key() != key {
                Err(GraphError::MalformedGraph {
                    reason: "Values for 'In' aggregator not of same key".to_string(),
                })?;
            }
        }
        let node_id = self
            .nodes
            .push(Node::new(NodeType::InAggregator(FxHashSet::from_iter(
                values,
            ))));
        let _aggregator_info_id = self.node_info.push(info);

        let _node_metadata_id = self
            .node_metadata
            .push(metadata.map(|meta| -> Arc<dyn Metadata> { Arc::new(meta) }));

        Ok(node_id)
    }

    fn ensure_node_exists(&self, id: NodeId) -> Result<(), GraphError<V>> {
        if self.nodes.contains_key(id) {
            Ok(())
        } else {
            Err(GraphError::NodeNotFound)
        }
    }

    fn ensure_domain_exists(&self, id: DomainId) -> Result<(), GraphError<V>> {
        if self.domain.contains_key(id) {
            Ok(())
        } else {
            Err(GraphError::DomainNotFound)
        }
    }
}


pub struct PaymentData {
    /// The amount of the payment in minor units (e.g., cents for USD).
    #[schema(value_type = i64)]
    pub amount: common_utils::types::MinorUnit,
    /// The currency of the payment.
    #[schema(value_type = Currency)]
    pub currency: common_enums::Currency,
}


OpenAPI Block Path: components.schemas.PaypalRedirection
{
  "type": "object",
  "properties": {
    "email": {
      "type": "string",
      "description": "paypal's email address",
      "example": "johntest@test.com",
      "nullable": true,
      "maxLength": 255
    }
  }
}


pub struct ReferencesResponse {
    pub payment_request_id: String,
}


pub fn server(config: AppState) -> Scope {
        web::scope("/v2/client-secret")
            .app_data(web::Data::new(config))
            .service(web::resource("").route(web::post().to(client_secret_create)))
            .service(web::resource("/{id}").route(web::delete().to(client_secret_delete)))
    }


pub struct ExchangeRate {
    pub base_currency: Option<api_models::enums::Currency>,
    pub exchange_currency: Option<api_models::enums::Currency>,
}


pub async fn check_token_status_with_tokenization_service(
    state: &routes::SessionState,
    customer_id: &id_type::CustomerId,
    network_token_requestor_reference_id: String,
    tokenization_service: &settings::NetworkTokenizationService,
) -> CustomResult<(Option<Secret<String>>, Option<Secret<String>>), errors::NetworkTokenizationError>
{
    let mut request = services::Request::new(
        services::Method::Post,
        tokenization_service.check_token_status_url.as_str(),
    );
    let payload = pm_types::CheckTokenStatus {
        card_reference: network_token_requestor_reference_id,
        customer_id: customer_id.clone(),
    };

    request.add_header(headers::CONTENT_TYPE, "application/json".into());
    request.add_header(
        headers::AUTHORIZATION,
        tokenization_service
            .token_service_api_key
            .clone()
            .peek()
            .clone()
            .into_masked(),
    );
    request.add_default_headers();
    request.set_body(RequestContent::Json(Box::new(payload)));

    // Send the request using `call_connector_api`
    let response = services::call_connector_api(state, request, "Check Network token Status")
        .await
        .change_context(errors::NetworkTokenizationError::ApiError);
    let res = response
        .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)
        .attach_printable("Error while receiving response")
        .and_then(|inner| match inner {
            Err(err_res) => {
                let parsed_error: pm_types::NetworkTokenErrorResponse = err_res
                    .response
                    .parse_struct("Delete Network Tokenization Response")
                    .change_context(
                        errors::NetworkTokenizationError::ResponseDeserializationFailed,
                    )?;
                logger::error!(
                    error_code = %parsed_error.error_info.code,
                    developer_message = %parsed_error.error_info.developer_message,
                    "Network tokenization error: {}",
                    parsed_error.error_message
                );
                Err(errors::NetworkTokenizationError::ResponseDeserializationFailed)
                    .attach_printable(format!("Response Deserialization Failed: {err_res:?}"))
            }
            Ok(res) => Ok(res),
        })
        .inspect_err(|err| {
            logger::error!("Error while deserializing response: {:?}", err);
        })?;

    let check_token_status_response: pm_types::CheckTokenStatusResponse = res
        .response
        .parse_struct("Delete Network Tokenization Response")
        .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)?;

    match check_token_status_response.payload.token_status {
        pm_types::TokenStatus::Active => Ok((
            Some(check_token_status_response.payload.token_expiry_month),
            Some(check_token_status_response.payload.token_expiry_year),
        )),
        pm_types::TokenStatus::Inactive => Ok((None, None)),
    }
}


pub async fn add_refund_execute_task(
    db: &dyn db::StorageInterface,
    refund: &diesel_refund::Refund,
    runner: storage::ProcessTrackerRunner,
) -> errors::RouterResult<storage::ProcessTracker> {
    let task = "EXECUTE_REFUND";
    let process_tracker_id = format!("{runner}_{task}_{}", refund.id.get_string_repr());
    let tag = ["REFUND"];
    let schedule_time = common_utils::date_time::now();
    let refund_workflow_tracking_data = refund_to_refund_core_workflow_model(refund);
    let process_tracker_entry = storage::ProcessTrackerNew::new(
        process_tracker_id,
        task,
        runner,
        tag,
        refund_workflow_tracking_data,
        None,
        schedule_time,
        common_types::consts::API_VERSION,
    )
    .change_context(errors::ApiErrorResponse::InternalServerError)
    .attach_printable("Failed to construct refund execute process tracker task")?;

    let response = db
        .insert_process(process_tracker_entry)
        .await
        .to_duplicate_response(errors::ApiErrorResponse::DuplicateRefundRequest)
        .attach_printable_lazy(|| {
            format!(
                "Failed while inserting task in process_tracker: refund_id: {}",
                refund.id.get_string_repr()
            )
        })?;
    Ok(response)
}


pub struct GetApiEventFiltersRequest {
    pub time_range: TimeRange,
    #[serde(default)]
    pub group_by_names: Vec<ApiEventDimensions>,
}


Documentation: api-reference/v1/payouts/payouts--create.mdx
# Type: Doc File

---
openapi: post /payouts/create
---


impl api::MandateSetup for Iatapay {}


pub async fn get_profile_refund_filters(
        state: web::Data<AppState>,
        req: actix_web::HttpRequest,
        json_payload: web::Json<GetRefundFilterRequest>,
    ) -> impl Responder {
        let flow = AnalyticsFlow::GetRefundFilters;
        Box::pin(api::server_wrap(
            flow,
            state,
            &req,
            json_payload.into_inner(),
            |state, auth: AuthenticationData, req: GetRefundFilterRequest, _| async move {
                let org_id = auth.merchant_account.get_org_id();
                let merchant_id = auth.merchant_account.get_id();
                let profile_id = auth
                    .profile_id
                    .ok_or(report!(UserErrors::JwtProfileIdMissing))
                    .change_context(AnalyticsError::AccessForbiddenError)?;
                let auth: AuthInfo = AuthInfo::ProfileLevel {
                    org_id: org_id.clone(),
                    merchant_id: merchant_id.clone(),
                    profile_ids: vec![profile_id.clone()],
                };
                analytics::refunds::get_filters(&state.pool, req, &auth)
                    .await
                    .map(ApplicationResponse::Json)
            },
            &auth::JWTAuth {
                permission: Permission::ProfileAnalyticsRead,
            },
            api_locking::LockAction::NotApplicable,
        ))
        .await
    }


pub struct RequestIdMiddleware<S> {
    service: S,
}


File: crates/external_services/src/aws_kms.rs

//! Interactions with the AWS KMS SDK

pub mod core;

pub mod implementers;


pub trait SeriesBucket {
    type SeriesType;
    type GranularityLevel;

    fn get_lowest_common_granularity_level(&self) -> Self::GranularityLevel;

    fn get_bucket_size(&self) -> u8;

    fn clip_to_start(
        &self,
        value: Self::SeriesType,
    ) -> error_stack::Result<Self::SeriesType, PostProcessingError>;

    fn clip_to_end(
        &self,
        value: Self::SeriesType,
    ) -> error_stack::Result<Self::SeriesType, PostProcessingError>;
}


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


pub async fn initiate_secure_payment_link_flow(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    merchant_id: common_utils::id_type::MerchantId,
    payment_id: common_utils::id_type::PaymentId,
    request_headers: &header::HeaderMap,
) -> RouterResponse<services::PaymentLinkFormData> {
    let (payment_link, payment_link_details, payment_link_config) =
        form_payment_link_data(&state, merchant_context, merchant_id, payment_id).await?;

    validator::validate_secure_payment_link_render_request(
        request_headers,
        &payment_link,
        &payment_link_config,
    )?;

    let css_script = get_payment_link_css_script(&payment_link_config)?;

    match payment_link_details {
        PaymentLinkData::PaymentLinkStatusDetails(ref status_details) => {
            let js_script = get_js_script(&payment_link_details)?;
            let payment_link_error_data = services::PaymentLinkStatusData {
                js_script,
                css_script,
            };
            logger::info!(
                "payment link data, for building payment link status page {:?}",
                status_details
            );
            Ok(services::ApplicationResponse::PaymentLinkForm(Box::new(
                services::api::PaymentLinkAction::PaymentLinkStatus(payment_link_error_data),
            )))
        }
        PaymentLinkData::PaymentLinkDetails(link_details) => {
            let secure_payment_link_details = api_models::payments::SecurePaymentLinkDetails {
                enabled_saved_payment_method: payment_link_config.enabled_saved_payment_method,
                hide_card_nickname_field: payment_link_config.hide_card_nickname_field,
                show_card_form_by_default: payment_link_config.show_card_form_by_default,
                payment_link_details: *link_details.to_owned(),
                payment_button_text: payment_link_config.payment_button_text,
                custom_message_for_card_terms: payment_link_config.custom_message_for_card_terms,
                payment_button_colour: payment_link_config.payment_button_colour,
                skip_status_screen: payment_link_config.skip_status_screen,
                background_colour: payment_link_config.background_colour,
                payment_button_text_colour: payment_link_config.payment_button_text_colour,
                sdk_ui_rules: payment_link_config.sdk_ui_rules,
                enable_button_only_on_form_ready: payment_link_config
                    .enable_button_only_on_form_ready,
                payment_form_header_text: payment_link_config.payment_form_header_text,
                payment_form_label_type: payment_link_config.payment_form_label_type,
                show_card_terms: payment_link_config.show_card_terms,
                color_icon_card_cvc_error: payment_link_config.color_icon_card_cvc_error,
            };
            let payment_details_str = serde_json::to_string(&secure_payment_link_details)
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed to serialize PaymentLinkData")?;
            let url_encoded_str = urlencoding::encode(&payment_details_str);
            let js_script = format!("window.__PAYMENT_DETAILS = '{url_encoded_str}';");
            let html_meta_tags = get_meta_tags_html(&link_details);
            let payment_link_data = services::PaymentLinkFormData {
                js_script,
                sdk_url: state.conf.payment_link.sdk_url.clone(),
                css_script,
                html_meta_tags,
            };
            let allowed_domains = payment_link_config
                .allowed_domains
                .clone()
                .ok_or(report!(errors::ApiErrorResponse::InternalServerError))
                .attach_printable_lazy(|| {
                    format!(
                        "Invalid list of allowed_domains found - {:?}",
                        payment_link_config.allowed_domains.clone()
                    )
                })?;

            if allowed_domains.is_empty() {
                return Err(report!(errors::ApiErrorResponse::InternalServerError))
                    .attach_printable_lazy(|| {
                        format!(
                            "Invalid list of allowed_domains found - {:?}",
                            payment_link_config.allowed_domains.clone()
                        )
                    });
            }

            let link_data = GenericLinks {
                allowed_domains,
                data: GenericLinksData::SecurePaymentLink(payment_link_data),
                locale: DEFAULT_LOCALE.to_string(),
            };
            logger::info!(
                "payment link data, for building secure payment link {:?}",
                link_data
            );

            Ok(services::ApplicationResponse::GenericLinkForm(Box::new(
                link_data,
            )))
        }
    }
}