File: crates/api_models/src/organization.rs
 Public functions: 1
 Public structs: 6

use common_enums::OrganizationType;
use common_utils::{id_type, pii};
use utoipa::ToSchema;
pub struct OrganizationNew {
    pub org_id: id_type::OrganizationId,
    pub org_type: OrganizationType,
    pub org_name: Option<String>,
}

impl OrganizationNew {
    pub fn new(org_type: OrganizationType, org_name: Option<String>) -> Self {
        Self {
            org_id: id_type::OrganizationId::default(),
            org_type,
            org_name,
        }
    }
}

#[derive(Clone, Debug, serde::Serialize)]
pub struct OrganizationId {
    pub organization_id: id_type::OrganizationId,
}

#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct OrganizationCreateRequest {
    /// Name of the organization
    pub organization_name: String,

    /// Details about the organization
    #[schema(value_type = Option<Object>)]
    pub organization_details: Option<pii::SecretSerdeValue>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>)]
    pub metadata: Option<pii::SecretSerdeValue>,
}

#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct OrganizationUpdateRequest {
    /// Name of the organization
    pub organization_name: Option<String>,

    /// Details about the organization
    #[schema(value_type = Option<Object>)]
    pub organization_details: Option<pii::SecretSerdeValue>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>)]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// Platform merchant id is unique distiguisher for special merchant in the platform org
    #[schema(value_type = String)]
    pub platform_merchant_id: Option<id_type::MerchantId>,
}
#[cfg(feature = "v1")]
#[derive(Debug, serde::Serialize, Clone, ToSchema)]
pub struct OrganizationResponse {
    /// The unique identifier for the Organization
    #[schema(value_type = String, max_length = 64, min_length = 1, example = "org_q98uSGAYbjEwqs0mJwnz")]
    pub organization_id: id_type::OrganizationId,

    /// Name of the Organization
    pub organization_name: Option<String>,

    /// Details about the organization
    #[schema(value_type = Option<Object>)]
    pub organization_details: Option<pii::SecretSerdeValue>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>)]
    pub metadata: Option<pii::SecretSerdeValue>,
    pub modified_at: time::PrimitiveDateTime,
    pub created_at: time::PrimitiveDateTime,

    /// Organization Type of the organization
    #[schema(value_type = Option<OrganizationType>, example = "standard")]
    pub organization_type: Option<OrganizationType>,
}

#[cfg(feature = "v2")]
#[derive(Debug, serde::Serialize, Clone, ToSchema)]
pub struct OrganizationResponse {
    /// The unique identifier for the Organization
    #[schema(value_type = String, max_length = 64, min_length = 1, example = "org_q98uSGAYbjEwqs0mJwnz")]
    pub id: id_type::OrganizationId,

    /// Name of the Organization
    pub organization_name: Option<String>,

    /// Details about the organization
    #[schema(value_type = Option<Object>)]
    pub organization_details: Option<pii::SecretSerdeValue>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>)]
    pub metadata: Option<pii::SecretSerdeValue>,
    pub modified_at: time::PrimitiveDateTime,
    pub created_at: time::PrimitiveDateTime,

    /// Organization Type of the organization
    #[schema(value_type = Option<OrganizationType>, example = "standard")]
    pub organization_type: Option<OrganizationType>,
}


pub struct ArchipelAuthType {
    pub(super) ca_certificate: Option<Secret<String>>,
}


pub struct Links {
    rel: String,
    href: String,
    method: String,
}


pub struct NewUserRole<E: Clone> {
    pub user_id: String,
    pub role_id: String,
    pub status: UserStatus,
    pub created_by: String,
    pub last_modified_by: String,
    pub created_at: PrimitiveDateTime,
    pub last_modified: PrimitiveDateTime,
    pub entity: E,
}


pub struct ArchipelBillingAddress {
    address: Option<Secret<String>>,
    postal_code: Option<Secret<String>>,
}


OpenAPI Block Path: paths."/events/{merchant_id}"
{
  "post": {
    "tags": [
      "Event"
    ],
    "summary": "Events - List",
    "description": "List all Events associated with a Merchant Account or Profile.",
    "operationId": "List all Events associated with a Merchant Account or Profile",
    "parameters": [
      {
        "name": "merchant_id",
        "in": "path",
        "description": "The unique identifier for the Merchant Account.",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    ],
    "requestBody": {
      "description": "The constraints that can be applied when listing Events.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/EventListConstraints"
          },
          "examples": {
            "example": {
              "value": {
                "created_after": "2023-01-01T00:00:00",
                "created_before": "2023-01-31T23:59:59",
                "event_classes": [
                  "payments",
                  "refunds"
                ],
                "event_types": [
                  "payment_succeeded"
                ],
                "is_delivered": true,
                "limit": 5,
                "object_id": "{{object_id}}",
                "offset": 0,
                "profile_id": "{{profile_id}}"
              }
            }
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "description": "List of Events retrieved successfully",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/TotalEventsResponse"
            }
          }
        }
      }
    },
    "security": [
      {
        "admin_api_key": []
      }
    ]
  }
}


pub trait FileStorageInterface: dyn_clone::DynClone + Sync + Send {
    /// Uploads a file to the selected storage scheme.
    async fn upload_file(
        &self,
        file_key: &str,
        file: Vec<u8>,
    ) -> CustomResult<(), FileStorageError>;

    /// Deletes a file from the selected storage scheme.
    async fn delete_file(&self, file_key: &str) -> CustomResult<(), FileStorageError>;

    /// Retrieves a file from the selected storage scheme.
    async fn retrieve_file(&self, file_key: &str) -> CustomResult<Vec<u8>, FileStorageError>;
}


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


pub struct ProfileAcquirerUpdate {
    #[schema(value_type = Option<String>, example = "M987654321")]
    pub acquirer_assigned_merchant_id: Option<String>,
    #[schema(value_type = Option<String>, example = "Updated Retailer Name")]
    pub merchant_name: Option<String>,
    #[schema(value_type = Option<String>, example = "MASTERCARD")]
    pub network: Option<common_enums::enums::CardNetwork>,
    #[schema(value_type = Option<String>, example = "987654")]
    pub acquirer_bin: Option<String>,
    #[schema(value_type = Option<String>, example = "501299")]
    pub acquirer_ica: Option<String>,
    #[schema(value_type = Option<f64>, example = "0.02")]
    pub acquirer_fraud_rate: Option<f64>,
}


pub async fn update_theme(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
    payload: web::Json<theme_api::UpdateThemeRequest>,
) -> HttpResponse {
    let flow = Flow::UpdateTheme;
    let theme_id = path.into_inner();
    let payload = payload.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _, payload, _| theme_core::update_theme(state, theme_id.clone(), payload),
        &auth::AdminApiAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub fn as_bool(self) -> bool {
        match self {
            Self::Skip => false,
            Self::Calculate => true,
        }
    }


impl api::Payouts for Cybersource {}


impl api::PaymentsPreProcessing for Nuvei {}

impl api::PaymentsPreProcessing for for Nuvei


pub async fn increment_stream_index(
    (index, jobs_picked)


impl OutgoingWebhookEvent {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        tenant_id: common_utils::id_type::TenantId,
        merchant_id: common_utils::id_type::MerchantId,
        event_id: String,
        event_type: OutgoingWebhookEventType,
        content: Option<OutgoingWebhookEventContent>,
        error: Option<Value>,
        initial_attempt_id: Option<String>,
        status_code: Option<u16>,
        delivery_attempt: Option<WebhookDeliveryAttempt>,
    ) -> Self {
        Self {
            tenant_id,
            merchant_id,
            event_id,
            event_type,
            content,
            is_error: error.is_some(),
            error,
            created_at_timestamp: OffsetDateTime::now_utc().unix_timestamp_nanos() / 1_000_000,
            initial_attempt_id,
            status_code,
            delivery_attempt,
        }
    }
}


pub struct EliminationRoutingPayloadWrapper {
    pub updated_config: EliminationRoutingConfig,
    pub algorithm_id: common_utils::id_type::RoutingId,
    pub profile_id: common_utils::id_type::ProfileId,
}


pub struct NetworkTokenResponse {
    pub payment_method_data: NetworkTokenDetailsPaymentMethod,
}


pub fn map_cybersource_attempt_status(
    status: CybersourcePaymentStatus,
    capture: bool,
) -> enums::AttemptStatus {
    match status {
        CybersourcePaymentStatus::Authorized => {
            if capture {
                // Because Cybersource will return Payment Status as Authorized even in AutoCapture Payment
                enums::AttemptStatus::Charged
            } else {
                enums::AttemptStatus::Authorized
            }
        }
        CybersourcePaymentStatus::Succeeded | CybersourcePaymentStatus::Transmitted => {
            enums::AttemptStatus::Charged
        }
        CybersourcePaymentStatus::Voided
        | CybersourcePaymentStatus::Reversed
        | CybersourcePaymentStatus::Cancelled => enums::AttemptStatus::Voided,
        CybersourcePaymentStatus::Failed
        | CybersourcePaymentStatus::Declined
        | CybersourcePaymentStatus::AuthorizedRiskDeclined
        | CybersourcePaymentStatus::Rejected
        | CybersourcePaymentStatus::InvalidRequest
        | CybersourcePaymentStatus::ServerError => enums::AttemptStatus::Failure,
        CybersourcePaymentStatus::PendingAuthentication => {
            enums::AttemptStatus::AuthenticationPending
        }
        CybersourcePaymentStatus::PendingReview
        | CybersourcePaymentStatus::StatusNotReceived
        | CybersourcePaymentStatus::Challenge
        | CybersourcePaymentStatus::Accepted
        | CybersourcePaymentStatus::Pending
        | CybersourcePaymentStatus::AuthorizedPendingReview => enums::AttemptStatus::Pending,
    }
}


/// Construct a redis key from the id to be stored in redis
    pub fn get_redis_key(&self) -> String {
        format!("payment_method_session:{}", self.get_string_repr())
    }


pub struct IatapayPaymentsRequest {
    merchant_id: Secret<String>,
    merchant_payment_id: Option<String>,
    amount: FloatMajorUnit,
    currency: common_enums::Currency,
    country: common_enums::CountryAlpha2,
    locale: String,
    redirect_urls: RedirectUrls,
    notification_url: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    payer_info: Option<PayerInfo>,
    #[serde(skip_serializing_if = "Option::is_none")]
    preferred_checkout_method: Option<PreferredCheckoutMethod>,
}


pub struct RapydRefundRequest {
    pub payment: String,
    pub amount: Option<FloatMajorUnit>,
    pub currency: Option<enums::Currency>,
}


pub struct Amount {
    pub net: CoinbaseProcessingFee,
    pub gross: CoinbaseProcessingFee,
    pub coinbase_fee: CoinbaseProcessingFee,
}


impl api::MandateSetup for Globalpay {}

impl api::MandateSetup for for Globalpay


pub struct AverageAccumulator {
    pub total: u32,
    pub count: u32,
}


impl VerifyIdForUpdateCustomer<'_> {
    async fn verify_id_and_get_customer_object(
        &self,
        db: &dyn StorageInterface,
    ) -> Result<domain::Customer, error_stack::Report<errors::CustomersErrorResponse>> {
        let customer = db
            .find_customer_by_customer_id_merchant_id(
                self.key_manager_state,
                self.merchant_reference_id,
                self.merchant_account.get_id(),
                self.key_store,
                self.merchant_account.storage_scheme,
            )
            .await
            .switch()?;

        Ok(customer)
    }
}


pub fn into_inner(self) -> Vec<Secret<String>> {
        self.0
    }


pub struct NameDescription {
    pub name: String,
    pub desc: String,
}


pub struct Browser {
    /// Exact content of the HTTP accept headers as sent to the 3DS Requestor from the Cardholder's browser.
    /// This field is limited to maximum 2048 characters  and if the total length exceeds the limit, the 3DS Server
    /// truncates the excess portion.
    ///
    /// This field is required for requests where deviceChannel=02 (BRW).
    browser_accept_header: Option<String>,

    /// IP address of the browser as returned by the HTTP headers to the 3DS Requestor. The field is limited to maximum 45
    /// characters and the accepted values are as following:
    ///      - IPv4 address is represented in the dotted decimal format of 4 sets of decimal numbers separated by dots. The
    ///        decimal number in each and every set is in the range 0 - 255. Example: 1.12.123.255
    ///      - IPv6 address is represented as eight groups of four hexadecimal digits, each group representing 16 bits (two
    ///        octets). The groups are separated by colons (:). Example: 2011:0db8:85a3:0101:0101:8a2e:0370:7334
    ///
    /// This field is required for requests when deviceChannel = 02 (BRW) where regionally acceptable.
    #[serde(rename = "browserIP")]
    browser_ip: Option<masking::Secret<String, common_utils::pii::IpAddress>>,

    /// Boolean that represents the ability of the cardholder browser to execute Java. Value is returned from the
    /// navigator.javaEnabled property.
    ///
    /// Depending on the message version, the field is required for requests:
    /// - with message version = 2.1.0 and deviceChannel = 02 (BRW).
    /// - with message version = 2.2.0 and deviceChannel = 02 (BRW) and browserJavascriptEnabled = true.
    browser_java_enabled: Option<bool>,

    /// Value representing the browser language as defined in IETF BCP47.
    ///
    /// Until EMV 3DS 2.2.0:
    /// The value is limited to 1-8 characters. If the value exceeds 8 characters, it will be truncated to a
    /// semantically valid value, if possible. The value is returned from navigator.language property.
    ///
    /// This field is required for requests where deviceChannel = 02 (BRW)
    /// In other cases this field is optional.
    ///
    /// Starting from EMV 3DS 2.3.1:
    /// The value is limited to 35 characters. If the value exceeds 35 characters, it will be truncated to a
    /// semantically valid value, if possible. The value is returned from navigator.language property.
    ///
    /// This field is required for requests where deviceChannel = 02 (BRW) and browserJavascriptEnabled = true.
    /// In other cases this field is optional.
    browser_language: Option<String>,

    /// Value representing the bit depth of the colour palette for displaying images, in bits per pixel. Obtained from
    /// Cardholder browser using the screen.colorDepth property. The field is limited to 1-2 characters.
    ///
    /// Accepted values are:
    ///  - 1 -> 1 bit
    ///  - 4 -> 4 bits
    ///  - 8 -> 8 bits
    ///  - 15 -> 15 bits
    ///  - 16 -> 16 bits
    ///  - 24 -> 24 bits
    ///  - 32 -> 32 bits
    ///  - 48 -> 48 bits
    ///
    ///  If the value is not in the accepted values, it will be resolved to the first accepted value lower from the one
    ///  provided.
    ///
    /// Depending on the message version, the field is required for requests:
    /// - with message version = 2.1.0 and deviceChannel = 02 (BRW).
    /// - with message version = 2.2.0 and deviceChannel = 02 (BRW) and browserJavascriptEnabled = true.
    browser_color_depth: Option<String>,

    /// Total height of the Cardholder's screen in pixels. Value is returned from the screen.height property. The value is
    /// limited to 1-6 characters.
    ///
    /// Depending on the message version, the field is required for requests:
    /// - with message version = 2.1.0 and deviceChannel = 02 (BRW).
    /// - with message version = 2.2.0 and deviceChannel = 02 (BRW) and browserJavascriptEnabled = true.
    browser_screen_height: Option<u32>,

    /// Total width of the Cardholder's screen in pixels. Value is returned from the screen.width property. The value is
    /// limited to 1-6 characters.
    ///
    /// Depending on the message version, the field is required for requests:
    /// - with message version = 2.1.0 and deviceChannel = 02 (BRW).
    /// - with message version = 2.2.0 and deviceChannel = 02 (BRW) and browserJavascriptEnabled = true.
    browser_screen_width: Option<u32>,

    /// Time difference between UTC time and the Cardholder browser local time, in minutes. The field is limited to 1-5
    /// characters where the vauyes is returned from the getTimezoneOffset() method.
    ///
    /// Depending on the message version, the field is required for requests:
    /// - with message version = 2.1.0 and deviceChannel = 02 (BRW).
    /// - with message version = 2.2.0 and deviceChannel = 02 (BRW) and browserJavascriptEnabled = true.
    #[serde(rename = "browserTZ")]
    browser_tz: Option<i32>,

    /// Exact content of the HTTP user-agent header. The field is limited to maximum 2048 characters. If the total length of
    /// the User-Agent sent by the browser exceeds 2048 characters, the 3DS Server truncates the excess portion.
    ///
    /// This field is required for requests where deviceChannel = 02 (BRW).
    browser_user_agent: Option<String>,

    /// Dimensions of the challenge window that has been displayed to the Cardholder. The ACS shall reply with content
    /// that is formatted to appropriately render in this window to provide the best possible user experience.
    ///
    /// Preconfigured sizes are width X height in pixels of the window displayed in the Cardholder browser window. This is
    /// used only to prepare the CReq request and it is not part of the AReq flow. If not present it will be omitted.
    ///
    /// However, when sending the Challenge Request, this field is required when deviceChannel = 02 (BRW).
    ///
    /// Accepted values are:
    ///  - 01 -> 250 x 400
    ///  - 02 -> 390 x 400
    ///  - 03 -> 500 x 600
    ///  - 04 -> 600 x 400
    ///  - 05 -> Full screen
    challenge_window_size: Option<ChallengeWindowSizeEnum>,

    /// Boolean that represents the ability of the cardholder browser to execute JavaScript.
    ///
    /// This field is required for requests where deviceChannel = 02 (BRW).
    /// Available for supporting EMV 3DS 2.2.0 and later versions.
    browser_javascript_enabled: Option<bool>,

    /// Value representing the browser language preference present in the http header, as defined in IETF BCP 47.
    ///
    /// The value is limited to 1-99 elements. Each element should contain a maximum of 100 characters.
    ///
    /// This field is required for requests where deviceChannel = 02 (BRW).
    /// Available for supporting EMV 3DS 2.3.1 and later versions.
    accept_language: Option<Vec<String>>,
}


File: crates/analytics/src/frm.rs

pub mod accumulator;
mod core;

pub mod filters;
pub mod metrics;
pub mod types;
pub use accumulator::{FrmMetricAccumulator, FrmMetricsAccumulator};

pub use self::core::{get_filters, get_metrics};


pub async fn payment_method_intent_create(
    state: &SessionState,
    req: api::PaymentMethodIntentCreate,
    merchant_context: &domain::MerchantContext,
) -> RouterResponse<api::PaymentMethodResponse> {
    let db = &*state.store;
    let merchant_id = merchant_context.get_merchant_account().get_id();
    let customer_id = req.customer_id.to_owned();
    let key_manager_state = &(state).into();

    db.find_customer_by_global_id(
        key_manager_state,
        &customer_id,
        merchant_context.get_merchant_key_store(),
        merchant_context.get_merchant_account().storage_scheme,
    )
    .await
    .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)
    .attach_printable("Customer not found for the payment method")?;

    let payment_method_billing_address = req
        .billing
        .clone()
        .async_map(|billing| {
            cards::create_encrypted_data(
                key_manager_state,
                merchant_context.get_merchant_key_store(),
                billing,
            )
        })
        .await
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to encrypt Payment method billing address")?
        .map(|encoded_address| {
            encoded_address.deserialize_inner_value(|value| value.parse_value("Address"))
        })
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to parse Payment method billing address")?;

    // create pm entry

    let payment_method_id =
        id_type::GlobalPaymentMethodId::generate(&state.conf.cell_information.id)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Unable to generate GlobalPaymentMethodId")?;

    let payment_method = create_payment_method_for_intent(
        state,
        req.metadata.clone(),
        &customer_id,
        payment_method_id,
        merchant_id,
        merchant_context.get_merchant_key_store(),
        merchant_context.get_merchant_account().storage_scheme,
        payment_method_billing_address,
    )
    .await
    .attach_printable("Failed to add Payment method to DB")?;

    let resp = pm_transforms::generate_payment_method_response(&payment_method, &None)?;

    Ok(services::ApplicationResponse::Json(resp))
}


impl api::Refund for Ebanx {}


impl api::Refund for Dwolla {}


impl api::ConnectorValidation for Wise {}

impl api::ConnectorValidation for for Wise


OpenAPI Block Path: components.schemas.BankCodeResponse
{
  "type": "object",
  "required": [
    "bank_name",
    "eligible_connectors"
  ],
  "properties": {
    "bank_name": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/BankNames"
      }
    },
    "eligible_connectors": {
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  }
}


impl api::MandateSetup for Wellsfargo {}

impl api::MandateSetup for for Wellsfargo


File: crates/drainer/src/types.rs
 Public functions: 1
 Public structs: 1

use std::collections::HashMap;

use common_utils::errors;
use error_stack::ResultExt;
use serde::{de::value::MapDeserializer, Deserialize, Serialize};

use crate::{
    kv,
    utils::{deserialize_db_op, deserialize_i64},
};

#[derive(Deserialize, Serialize)]
pub struct StreamData {
    pub request_id: String,
    pub global_id: String,
    #[serde(deserialize_with = "deserialize_db_op")]
    pub typed_sql: kv::DBOperation,
    #[serde(deserialize_with = "deserialize_i64")]
    pub pushed_at: i64,
}

impl StreamData {
    pub fn from_hashmap(
        hashmap: HashMap<String, String>,
    ) -> errors::CustomResult<Self, errors::ParsingError> {
        let iter = MapDeserializer::<
            '_,
            std::collections::hash_map::IntoIter<String, String>,
            serde_json::error::Error,
        >::new(hashmap.into_iter());

        Self::deserialize(iter)
            .change_context(errors::ParsingError::StructParseFailure("StreamData"))
    }
}


File: crates/analytics/src/auth_events/metrics/authentication_exemption_requested_count.rs

use std::collections::HashSet;

use api_models::analytics::{
    auth_events::{AuthEventDimensions, AuthEventFilters, AuthEventMetricsBucketIdentifier},
    Granularity, TimeRange,
};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

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

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

#[async_trait::async_trait]
impl<T> super::AuthEventMetric<T> for AuthenticationExemptionRequestedCount
where
    T: AnalyticsDataSource + super::AuthEventMetricAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_metrics(
        &self,
        auth: &AuthInfo,
        dimensions: &[AuthEventDimensions],
        filters: &AuthEventFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
        let mut query_builder: QueryBuilder<T> =
            QueryBuilder::new(AnalyticsCollection::Authentications);
        for dim in dimensions.iter() {
            query_builder.add_select_column(dim).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()?;

        query_builder
            .add_filter_clause(AuthEventDimensions::ExemptionRequested, true)
            .switch()?;

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

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

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

        query_builder
            .execute_query::<AuthEventMetricRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| {
                Ok((
                    AuthEventMetricsBucketIdentifier::new(
                        i.authentication_status.as_ref().map(|i| i.0),
                        i.trans_status.as_ref().map(|i| i.0.clone()),
                        i.authentication_type.as_ref().map(|i| i.0),
                        i.error_message.clone(),
                        i.authentication_connector.as_ref().map(|i| i.0),
                        i.message_version.clone(),
                        i.acs_reference_number.clone(),
                        i.mcc.clone(),
                        i.currency.as_ref().map(|i| i.0),
                        i.merchant_country.clone(),
                        i.billing_country.clone(),
                        i.shipping_country.clone(),
                        i.issuer_country.clone(),
                        i.earliest_supported_version.clone(),
                        i.latest_supported_version.clone(),
                        i.whitelist_decision,
                        i.device_manufacturer.clone(),
                        i.device_type.clone(),
                        i.device_brand.clone(),
                        i.device_os.clone(),
                        i.device_display.clone(),
                        i.browser_name.clone(),
                        i.browser_version.clone(),
                        i.issuer_id.clone(),
                        i.scheme_name.clone(),
                        i.exemption_requested,
                        i.exemption_accepted,
                        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<
                HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
                crate::query::PostProcessingError,
            >>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


/// Panics if `json_payload` array does not contain one `GetDisputeMetricRequest` element.
    pub async fn get_org_dispute_metrics(
        state: web::Data<AppState>,
        req: actix_web::HttpRequest,
        json_payload: web::Json<[GetDisputeMetricRequest; 1]>,
    ) -> impl Responder {
        // safety: This shouldn't panic owing to the data type
        #[allow(clippy::expect_used)]
        let payload = json_payload
            .into_inner()
            .to_vec()
            .pop()
            .expect("Couldn't get GetDisputeMetricRequest");
        let flow = AnalyticsFlow::GetDisputeMetrics;
        Box::pin(api::server_wrap(
            flow,
            state,
            &req,
            payload,
            |state, auth: AuthenticationData, req, _| async move {
                let org_id = auth.merchant_account.get_org_id();
                let auth: AuthInfo = AuthInfo::OrgLevel {
                    org_id: org_id.clone(),
                };
                analytics::disputes::get_metrics(&state.pool, &auth, req)
                    .await
                    .map(ApplicationResponse::Json)
            },
            auth::auth_type(
                &auth::PlatformOrgAdminAuth {
                    is_admin_auth_allowed: false,
                    organization_id: None,
                },
                &auth::JWTAuth {
                    permission: Permission::OrganizationAnalyticsRead,
                },
                req.headers(),
            ),
            api_locking::LockAction::NotApplicable,
        ))
        .await
    }


pub fn get_password(&self) -> Option<UserPassword> {
        self.password
            .as_ref()
            .map(|password| password.deref().clone())
    }


OpenAPI Block Path: paths."/poll/status/{poll_id}"
{
  "get": {
    "tags": [
      "Poll"
    ],
    "summary": "Poll - Retrieve Poll Status",
    "operationId": "Retrieve Poll Status",
    "parameters": [
      {
        "name": "poll_id",
        "in": "path",
        "description": "The identifier for poll",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    ],
    "responses": {
      "200": {
        "description": "The poll status was retrieved successfully",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PollResponse"
            }
          }
        }
      },
      "404": {
        "description": "Poll not found"
      }
    },
    "security": [
      {
        "publishable_key": []
      }
    ]
  }
}


pub async fn get_disputes_aggregate_profile(
    state: web::Data<AppState>,
    req: HttpRequest,
    query_param: web::Query<common_utils::types::TimeRange>,
) -> HttpResponse {
    let flow = Flow::DisputesAggregate;
    let query_param = query_param.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        query_param,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            disputes::get_aggregates_for_disputes(
                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
}


impl RoutingApproach {
    pub fn from_decision_engine_approach(approach: &str) -> Self {
        match approach {
            "SR_SELECTION_V3_ROUTING" => Self::Exploitation,
            "SR_V3_HEDGING" => Self::Exploration,
            _ => Self::Default,
        }
    }
}


pub struct PaymentLink;


File: crates/router/src/utils.rs
 Public functions: 24

#[cfg(feature = "olap")]
pub mod connector_onboarding;
pub mod currency;
pub mod db_utils;
pub mod ext_traits;
#[cfg(feature = "kv_store")]
pub mod storage_partitioning;
#[cfg(feature = "olap")]
pub mod user;
#[cfg(feature = "olap")]
pub mod user_role;
#[cfg(feature = "olap")]
pub mod verify_connector;
use std::fmt::Debug;

use api_models::{
    enums,
    payments::{self},
    webhooks,
};
use common_utils::types::keymanager::KeyManagerState;
pub use common_utils::{
    crypto::{self, Encryptable},
    ext_traits::{ByteSliceExt, BytesExt, Encode, StringExt, ValueExt},
    fp_utils::when,
    id_type, pii,
    validation::validate_email,
};
#[cfg(feature = "v1")]
use common_utils::{
    type_name,
    types::keymanager::{Identifier, ToEncryptable},
};
use error_stack::ResultExt;
pub use hyperswitch_connectors::utils::QrImage;
use hyperswitch_domain_models::payments::PaymentIntent;
#[cfg(feature = "v1")]
use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation};
use masking::{ExposeInterface, SwitchStrategy};
use nanoid::nanoid;
use serde::de::DeserializeOwned;
use serde_json::Value;
use tracing_futures::Instrument;

pub use self::ext_traits::{OptionExt, ValidateCall};
use crate::{
    consts,
    core::{
        authentication::types::ExternalThreeDSConnectorMetadata,
        errors::{self, CustomResult, RouterResult, StorageErrorExt},
        payments as payments_core,
    },
    headers::ACCEPT_LANGUAGE,
    logger,
    routes::{metrics, SessionState},
    services::{self, authentication::get_header_value_by_key},
    types::{self, domain, transformers::ForeignInto},
};
#[cfg(feature = "v1")]
use crate::{core::webhooks as webhooks_core, types::storage};

pub mod error_parser {
    use std::fmt::Display;

    use actix_web::{
        error::{Error, JsonPayloadError},
        http::StatusCode,
        HttpRequest, ResponseError,
    };

    #[derive(Debug)]
    struct CustomJsonError {
        err: JsonPayloadError,
    }

    // Display is a requirement defined by the actix crate for implementing ResponseError trait
    impl Display for CustomJsonError {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            f.write_str(
                serde_json::to_string(&serde_json::json!({
                    "error": {
                        "error_type": "invalid_request",
                        "message": self.err.to_string(),
                        "code": "IR_06",
                    }
                }))
                .as_deref()
                .unwrap_or("Invalid Json Error"),
            )
        }
    }

    impl ResponseError for CustomJsonError {
        fn status_code(&self) -> StatusCode {
            StatusCode::BAD_REQUEST
        }

        fn error_response(&self) -> actix_web::HttpResponse<actix_web::body::BoxBody> {
            use actix_web::http::header;

            actix_web::HttpResponseBuilder::new(self.status_code())
                .insert_header((header::CONTENT_TYPE, mime::APPLICATION_JSON))
                .body(self.to_string())
        }
    }

    pub fn custom_json_error_handler(err: JsonPayloadError, _req: &HttpRequest) -> Error {
        Error::from(CustomJsonError { err })
    }
}

#[inline]
pub fn generate_id(length: usize, prefix: &str) -> String {
    format!("{}_{}", prefix, nanoid!(length, &consts::ALPHABETS))
}

pub trait ConnectorResponseExt: Sized {
    fn get_response(self) -> RouterResult<types::Response>;
    fn get_error_response(self) -> RouterResult<types::Response>;
    fn get_response_inner<T: DeserializeOwned>(self, type_name: &'static str) -> RouterResult<T> {
        self.get_response()?
            .response
            .parse_struct(type_name)
            .change_context(errors::ApiErrorResponse::InternalServerError)
    }
}

impl<E> ConnectorResponseExt
    for Result<Result<types::Response, types::Response>, error_stack::Report<E>>
{
    fn get_error_response(self) -> RouterResult<types::Response> {
        self.map_err(|error| error.change_context(errors::ApiErrorResponse::InternalServerError))
            .attach_printable("Error while receiving response")
            .and_then(|inner| match inner {
                Ok(res) => {
                    logger::error!(response=?res);
                    Err(errors::ApiErrorResponse::InternalServerError).attach_printable(format!(
                        "Expecting error response, received response: {res:?}"
                    ))
                }
                Err(err_res) => Ok(err_res),
            })
    }

    fn get_response(self) -> RouterResult<types::Response> {
        self.map_err(|error| error.change_context(errors::ApiErrorResponse::InternalServerError))
            .attach_printable("Error while receiving response")
            .and_then(|inner| match inner {
                Err(err_res) => {
                    logger::error!(error_response=?err_res);
                    Err(errors::ApiErrorResponse::InternalServerError).attach_printable(format!(
                        "Expecting response, received error response: {err_res:?}"
                    ))
                }
                Ok(res) => Ok(res),
            })
    }
}

#[inline]
pub fn get_payout_attempt_id(payout_id: &str, attempt_count: i16) -> String {
    format!("{payout_id}_{attempt_count}")
}

#[cfg(feature = "v1")]
pub async fn find_payment_intent_from_payment_id_type(
    state: &SessionState,
    payment_id_type: payments::PaymentIdType,
    merchant_context: &domain::MerchantContext,
) -> CustomResult<PaymentIntent, errors::ApiErrorResponse> {
    let key_manager_state: KeyManagerState = state.into();
    let db = &*state.store;
    match payment_id_type {
        payments::PaymentIdType::PaymentIntentId(payment_id) => db
            .find_payment_intent_by_payment_id_merchant_id(
                &key_manager_state,
                &payment_id,
                merchant_context.get_merchant_account().get_id(),
                merchant_context.get_merchant_key_store(),
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound),
        payments::PaymentIdType::ConnectorTransactionId(connector_transaction_id) => {
            let attempt = db
                .find_payment_attempt_by_merchant_id_connector_txn_id(
                    merchant_context.get_merchant_account().get_id(),
                    &connector_transaction_id,
                    merchant_context.get_merchant_account().storage_scheme,
                )
                .await
                .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
            db.find_payment_intent_by_payment_id_merchant_id(
                &key_manager_state,
                &attempt.payment_id,
                merchant_context.get_merchant_account().get_id(),
                merchant_context.get_merchant_key_store(),
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
        }
        payments::PaymentIdType::PaymentAttemptId(attempt_id) => {
            let attempt = db
                .find_payment_attempt_by_attempt_id_merchant_id(
                    &attempt_id,
                    merchant_context.get_merchant_account().get_id(),
                    merchant_context.get_merchant_account().storage_scheme,
                )
                .await
                .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
            db.find_payment_intent_by_payment_id_merchant_id(
                &key_manager_state,
                &attempt.payment_id,
                merchant_context.get_merchant_account().get_id(),
                merchant_context.get_merchant_key_store(),
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
        }
        payments::PaymentIdType::PreprocessingId(_) => {
            Err(errors::ApiErrorResponse::PaymentNotFound)?
        }
    }
}

#[cfg(feature = "v1")]
pub async fn find_payment_intent_from_refund_id_type(
    state: &SessionState,
    refund_id_type: webhooks::RefundIdType,
    merchant_context: &domain::MerchantContext,
    connector_name: &str,
) -> CustomResult<PaymentIntent, errors::ApiErrorResponse> {
    let db = &*state.store;
    let refund = match refund_id_type {
        webhooks::RefundIdType::RefundId(id) => db
            .find_refund_by_merchant_id_refund_id(
                merchant_context.get_merchant_account().get_id(),
                &id,
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::RefundNotFound)?,
        webhooks::RefundIdType::ConnectorRefundId(id) => db
            .find_refund_by_merchant_id_connector_refund_id_connector(
                merchant_context.get_merchant_account().get_id(),
                &id,
                connector_name,
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::RefundNotFound)?,
    };
    let attempt = db
        .find_payment_attempt_by_attempt_id_merchant_id(
            &refund.attempt_id,
            merchant_context.get_merchant_account().get_id(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
    db.find_payment_intent_by_payment_id_merchant_id(
        &state.into(),
        &attempt.payment_id,
        merchant_context.get_merchant_account().get_id(),
        merchant_context.get_merchant_key_store(),
        merchant_context.get_merchant_account().storage_scheme,
    )
    .await
    .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
}

#[cfg(feature = "v1")]
pub async fn find_payment_intent_from_mandate_id_type(
    state: &SessionState,
    mandate_id_type: webhooks::MandateIdType,
    merchant_context: &domain::MerchantContext,
) -> CustomResult<PaymentIntent, errors::ApiErrorResponse> {
    let db = &*state.store;
    let mandate = match mandate_id_type {
        webhooks::MandateIdType::MandateId(mandate_id) => db
            .find_mandate_by_merchant_id_mandate_id(
                merchant_context.get_merchant_account().get_id(),
                mandate_id.as_str(),
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::MandateNotFound)?,
        webhooks::MandateIdType::ConnectorMandateId(connector_mandate_id) => db
            .find_mandate_by_merchant_id_connector_mandate_id(
                merchant_context.get_merchant_account().get_id(),
                connector_mandate_id.as_str(),
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::MandateNotFound)?,
    };
    db.find_payment_intent_by_payment_id_merchant_id(
        &state.into(),
        &mandate
            .original_payment_id
            .ok_or(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("original_payment_id not present in mandate record")?,
        merchant_context.get_merchant_account().get_id(),
        merchant_context.get_merchant_key_store(),
        merchant_context.get_merchant_account().storage_scheme,
    )
    .await
    .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
}

#[cfg(feature = "v1")]
pub async fn find_mca_from_authentication_id_type(
    state: &SessionState,
    authentication_id_type: webhooks::AuthenticationIdType,
    merchant_context: &domain::MerchantContext,
) -> CustomResult<domain::MerchantConnectorAccount, errors::ApiErrorResponse> {
    let db = &*state.store;
    let authentication = match authentication_id_type {
        webhooks::AuthenticationIdType::AuthenticationId(authentication_id) => db
            .find_authentication_by_merchant_id_authentication_id(
                merchant_context.get_merchant_account().get_id(),
                &authentication_id,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::InternalServerError)?,
        webhooks::AuthenticationIdType::ConnectorAuthenticationId(connector_authentication_id) => {
            db.find_authentication_by_merchant_id_connector_authentication_id(
                merchant_context.get_merchant_account().get_id().clone(),
                connector_authentication_id,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::InternalServerError)?
        }
    };
    #[cfg(feature = "v1")]
    {
        // raise error if merchant_connector_id is not present since it should we be present in the current flow
        let mca_id = authentication
            .merchant_connector_id
            .ok_or(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("merchant_connector_id not present in authentication record")?;
        db.find_by_merchant_connector_account_merchant_id_merchant_connector_id(
            &state.into(),
            merchant_context.get_merchant_account().get_id(),
            &mca_id,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .to_not_found_response(
            errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
                id: mca_id.get_string_repr().to_string(),
            },
        )
    }
    #[cfg(feature = "v2")]
    //get mca using id
    {
        let _ = key_store;
        let _ = authentication;
        todo!()
    }
}

#[cfg(feature = "v1")]
pub async fn get_mca_from_payment_intent(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    payment_intent: PaymentIntent,
    connector_name: &str,
) -> CustomResult<domain::MerchantConnectorAccount, errors::ApiErrorResponse> {
    let db = &*state.store;
    let key_manager_state: &KeyManagerState = &state.into();

    #[cfg(feature = "v1")]
    let payment_attempt = db
        .find_payment_attempt_by_attempt_id_merchant_id(
            &payment_intent.active_attempt.get_id(),
            merchant_context.get_merchant_account().get_id(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

    #[cfg(feature = "v2")]
    let payment_attempt = db
        .find_payment_attempt_by_attempt_id_merchant_id(
            key_manager_state,
            key_store,
            &payment_intent.active_attempt.get_id(),
            merchant_account.get_id(),
            merchant_account.storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

    match payment_attempt.merchant_connector_id {
        Some(merchant_connector_id) => {
            #[cfg(feature = "v1")]
            {
                db.find_by_merchant_connector_account_merchant_id_merchant_connector_id(
                    key_manager_state,
                    merchant_context.get_merchant_account().get_id(),
                    &merchant_connector_id,
                    merchant_context.get_merchant_key_store(),
                )
                .await
                .to_not_found_response(
                    errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
                        id: merchant_connector_id.get_string_repr().to_string(),
                    },
                )
            }
            #[cfg(feature = "v2")]
            {
                //get mca using id
                let _id = merchant_connector_id;
                let _ = key_store;
                let _ = key_manager_state;
                let _ = connector_name;
                todo!()
            }
        }
        None => {
            let profile_id = payment_intent
                .profile_id
                .as_ref()
                .get_required_value("profile_id")
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("profile_id is not set in payment_intent")?
                .clone();

            #[cfg(feature = "v1")]
            {
                db.find_merchant_connector_account_by_profile_id_connector_name(
                    key_manager_state,
                    &profile_id,
                    connector_name,
                    merchant_context.get_merchant_key_store(),
                )
                .await
                .to_not_found_response(
                    errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
                        id: format!(
                            "profile_id {} and connector_name {connector_name}",
                            profile_id.get_string_repr()
                        ),
                    },
                )
            }
            #[cfg(feature = "v2")]
            {
                //get mca using id
                let _ = profile_id;
                todo!()
            }
        }
    }
}

#[cfg(feature = "payouts")]
pub async fn get_mca_from_payout_attempt(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    payout_id_type: webhooks::PayoutIdType,
    connector_name: &str,
) -> CustomResult<domain::MerchantConnectorAccount, errors::ApiErrorResponse> {
    let db = &*state.store;
    let payout = match payout_id_type {
        webhooks::PayoutIdType::PayoutAttemptId(payout_attempt_id) => db
            .find_payout_attempt_by_merchant_id_payout_attempt_id(
                merchant_context.get_merchant_account().get_id(),
                &payout_attempt_id,
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PayoutNotFound)?,
        webhooks::PayoutIdType::ConnectorPayoutId(connector_payout_id) => db
            .find_payout_attempt_by_merchant_id_connector_payout_id(
                merchant_context.get_merchant_account().get_id(),
                &connector_payout_id,
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PayoutNotFound)?,
    };
    let key_manager_state: &KeyManagerState = &state.into();
    match payout.merchant_connector_id {
        Some(merchant_connector_id) => {
            #[cfg(feature = "v1")]
            {
                db.find_by_merchant_connector_account_merchant_id_merchant_connector_id(
                    key_manager_state,
                    merchant_context.get_merchant_account().get_id(),
                    &merchant_connector_id,
                    merchant_context.get_merchant_key_store(),
                )
                .await
                .to_not_found_response(
                    errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
                        id: merchant_connector_id.get_string_repr().to_string(),
                    },
                )
            }
            #[cfg(feature = "v2")]
            {
                //get mca using id
                let _id = merchant_connector_id;
                let _ = merchant_context.get_merchant_key_store();
                let _ = connector_name;
                let _ = key_manager_state;
                todo!()
            }
        }
        None => {
            #[cfg(feature = "v1")]
            {
                db.find_merchant_connector_account_by_profile_id_connector_name(
                    key_manager_state,
                    &payout.profile_id,
                    connector_name,
                    merchant_context.get_merchant_key_store(),
                )
                .await
                .to_not_found_response(
                    errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
                        id: format!(
                            "profile_id {} and connector_name {}",
                            payout.profile_id.get_string_repr(),
                            connector_name
                        ),
                    },
                )
            }
            #[cfg(feature = "v2")]
            {
                todo!()
            }
        }
    }
}

#[cfg(feature = "v1")]
pub async fn get_mca_from_object_reference_id(
    state: &SessionState,
    object_reference_id: webhooks::ObjectReferenceId,
    merchant_context: &domain::MerchantContext,
    connector_name: &str,
) -> CustomResult<domain::MerchantConnectorAccount, errors::ApiErrorResponse> {
    let db = &*state.store;

    #[cfg(feature = "v1")]
    let default_profile_id = merchant_context
        .get_merchant_account()
        .default_profile
        .as_ref();

    #[cfg(feature = "v2")]
    let default_profile_id = Option::<&String>::None;

    match default_profile_id {
        Some(profile_id) => {
            #[cfg(feature = "v1")]
            {
                db.find_merchant_connector_account_by_profile_id_connector_name(
                    &state.into(),
                    profile_id,
                    connector_name,
                    merchant_context.get_merchant_key_store(),
                )
                .await
                .to_not_found_response(
                    errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
                        id: format!(
                            "profile_id {} and connector_name {connector_name}",
                            profile_id.get_string_repr()
                        ),
                    },
                )
            }
            #[cfg(feature = "v2")]
            {
                let _db = db;
                let _profile_id = profile_id;
                todo!()
            }
        }
        _ => match object_reference_id {
            webhooks::ObjectReferenceId::PaymentId(payment_id_type) => {
                get_mca_from_payment_intent(
                    state,
                    merchant_context,
                    find_payment_intent_from_payment_id_type(
                        state,
                        payment_id_type,
                        merchant_context,
                    )
                    .await?,
                    connector_name,
                )
                .await
            }
            webhooks::ObjectReferenceId::RefundId(refund_id_type) => {
                get_mca_from_payment_intent(
                    state,
                    merchant_context,
                    find_payment_intent_from_refund_id_type(
                        state,
                        refund_id_type,
                        merchant_context,
                        connector_name,
                    )
                    .await?,
                    connector_name,
                )
                .await
            }
            webhooks::ObjectReferenceId::MandateId(mandate_id_type) => {
                get_mca_from_payment_intent(
                    state,
                    merchant_context,
                    find_payment_intent_from_mandate_id_type(
                        state,
                        mandate_id_type,
                        merchant_context,
                    )
                    .await?,
                    connector_name,
                )
                .await
            }
            webhooks::ObjectReferenceId::ExternalAuthenticationID(authentication_id_type) => {
                find_mca_from_authentication_id_type(
                    state,
                    authentication_id_type,
                    merchant_context,
                )
                .await
            }
            #[cfg(feature = "payouts")]
            webhooks::ObjectReferenceId::PayoutId(payout_id_type) => {
                get_mca_from_payout_attempt(state, merchant_context, payout_id_type, connector_name)
                    .await
            }
        },
    }
}

// validate json format for the error
pub fn handle_json_response_deserialization_failure(
    res: types::Response,
    connector: &'static str,
) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
    metrics::RESPONSE_DESERIALIZATION_FAILURE
        .add(1, router_env::metric_attributes!(("connector", connector)));

    let response_data = String::from_utf8(res.response.to_vec())
        .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

    // check for whether the response is in json format
    match serde_json::from_str::<Value>(&response_data) {
        // in case of unexpected response but in json format
        Ok(_) => Err(errors::ConnectorError::ResponseDeserializationFailed)?,
        // in case of unexpected response but in html or string format
        Err(error_msg) => {
            logger::error!(deserialization_error=?error_msg);
            logger::error!("UNEXPECTED RESPONSE FROM CONNECTOR: {}", response_data);
            Ok(types::ErrorResponse {
                status_code: res.status_code,
                code: consts::NO_ERROR_CODE.to_string(),
                message: consts::UNSUPPORTED_ERROR_MESSAGE.to_string(),
                reason: Some(response_data),
                attempt_status: None,
                connector_transaction_id: None,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            })
        }
    }
}

pub fn get_http_status_code_type(
    status_code: u16,
) -> CustomResult<String, errors::ApiErrorResponse> {
    let status_code_type = match status_code {
        100..=199 => "1xx",
        200..=299 => "2xx",
        300..=399 => "3xx",
        400..=499 => "4xx",
        500..=599 => "5xx",
        _ => Err(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Invalid http status code")?,
    };
    Ok(status_code_type.to_string())
}

pub fn add_connector_http_status_code_metrics(option_status_code: Option<u16>) {
    if let Some(status_code) = option_status_code {
        let status_code_type = get_http_status_code_type(status_code).ok();
        match status_code_type.as_deref() {
            Some("1xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_1XX_COUNT.add(1, &[]),
            Some("2xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_2XX_COUNT.add(1, &[]),
            Some("3xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_3XX_COUNT.add(1, &[]),
            Some("4xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_4XX_COUNT.add(1, &[]),
            Some("5xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_5XX_COUNT.add(1, &[]),
            _ => logger::info!("Skip metrics as invalid http status code received from connector"),
        };
    } else {
        logger::info!("Skip metrics as no http status code received from connector")
    }
}

#[cfg(feature = "v1")]
#[async_trait::async_trait]
pub trait CustomerAddress {
    async fn get_address_update(
        &self,
        state: &SessionState,
        address_details: payments::AddressDetails,
        key: &[u8],
        storage_scheme: storage::enums::MerchantStorageScheme,
        merchant_id: id_type::MerchantId,
    ) -> CustomResult<storage::AddressUpdate, common_utils::errors::CryptoError>;

    async fn get_domain_address(
        &self,
        state: &SessionState,
        address_details: payments::AddressDetails,
        merchant_id: &id_type::MerchantId,
        customer_id: &id_type::CustomerId,
        key: &[u8],
        storage_scheme: storage::enums::MerchantStorageScheme,
    ) -> CustomResult<domain::CustomerAddress, common_utils::errors::CryptoError>;
}

#[cfg(feature = "v1")]
#[async_trait::async_trait]
impl CustomerAddress for api_models::customers::CustomerRequest {
    async fn get_address_update(
        &self,
        state: &SessionState,
        address_details: payments::AddressDetails,
        key: &[u8],
        storage_scheme: storage::enums::MerchantStorageScheme,
        merchant_id: id_type::MerchantId,
    ) -> CustomResult<storage::AddressUpdate, common_utils::errors::CryptoError> {
        let encrypted_data = crypto_operation(
            &state.into(),
            type_name!(storage::Address),
            CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable(
                domain::FromRequestEncryptableAddress {
                    line1: address_details.line1.clone(),
                    line2: address_details.line2.clone(),
                    line3: address_details.line3.clone(),
                    state: address_details.state.clone(),
                    first_name: address_details.first_name.clone(),
                    last_name: address_details.last_name.clone(),
                    zip: address_details.zip.clone(),
                    phone_number: self.phone.clone(),
                    email: self
                        .email
                        .as_ref()
                        .map(|a| a.clone().expose().switch_strategy()),
                    origin_zip: address_details.origin_zip.clone(),
                },
            )),
            Identifier::Merchant(merchant_id.to_owned()),
            key,
        )
        .await
        .and_then(|val| val.try_into_batchoperation())?;

        let encryptable_address =
            domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
                .change_context(common_utils::errors::CryptoError::EncodingFailed)?;

        Ok(storage::AddressUpdate::Update {
            city: address_details.city,
            country: address_details.country,
            line1: encryptable_address.line1,
            line2: encryptable_address.line2,
            line3: encryptable_address.line3,
            zip: encryptable_address.zip,
            state: encryptable_address.state,
            first_name: encryptable_address.first_name,
            last_name: encryptable_address.last_name,
            phone_number: encryptable_address.phone_number,
            country_code: self.phone_country_code.clone(),
            updated_by: storage_scheme.to_string(),
            email: encryptable_address.email.map(|email| {
                let encryptable: Encryptable<masking::Secret<String, pii::EmailStrategy>> =
                    Encryptable::new(
                        email.clone().into_inner().switch_strategy(),
                        email.into_encrypted(),
                    );
                encryptable
            }),
            origin_zip: encryptable_address.origin_zip,
        })
    }

    async fn get_domain_address(
        &self,
        state: &SessionState,
        address_details: payments::AddressDetails,
        merchant_id: &id_type::MerchantId,
        customer_id: &id_type::CustomerId,
        key: &[u8],
        storage_scheme: storage::enums::MerchantStorageScheme,
    ) -> CustomResult<domain::CustomerAddress, common_utils::errors::CryptoError> {
        let encrypted_data = crypto_operation(
            &state.into(),
            type_name!(storage::Address),
            CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable(
                domain::FromRequestEncryptableAddress {
                    line1: address_details.line1.clone(),
                    line2: address_details.line2.clone(),
                    line3: address_details.line3.clone(),
                    state: address_details.state.clone(),
                    first_name: address_details.first_name.clone(),
                    last_name: address_details.last_name.clone(),
                    zip: address_details.zip.clone(),
                    phone_number: self.phone.clone(),
                    email: self
                        .email
                        .as_ref()
                        .map(|a| a.clone().expose().switch_strategy()),
                    origin_zip: address_details.origin_zip.clone(),
                },
            )),
            Identifier::Merchant(merchant_id.to_owned()),
            key,
        )
        .await
        .and_then(|val| val.try_into_batchoperation())?;

        let encryptable_address =
            domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
                .change_context(common_utils::errors::CryptoError::EncodingFailed)?;

        let address = domain::Address {
            city: address_details.city,
            country: address_details.country,
            line1: encryptable_address.line1,
            line2: encryptable_address.line2,
            line3: encryptable_address.line3,
            zip: encryptable_address.zip,
            state: encryptable_address.state,
            first_name: encryptable_address.first_name,
            last_name: encryptable_address.last_name,
            phone_number: encryptable_address.phone_number,
            country_code: self.phone_country_code.clone(),
            merchant_id: merchant_id.to_owned(),
            address_id: generate_id(consts::ID_LENGTH, "add"),
            created_at: common_utils::date_time::now(),
            modified_at: common_utils::date_time::now(),
            updated_by: storage_scheme.to_string(),
            email: encryptable_address.email.map(|email| {
                let encryptable: Encryptable<masking::Secret<String, pii::EmailStrategy>> =
                    Encryptable::new(
                        email.clone().into_inner().switch_strategy(),
                        email.into_encrypted(),
                    );
                encryptable
            }),
            origin_zip: encryptable_address.origin_zip,
        };

        Ok(domain::CustomerAddress {
            address,
            customer_id: customer_id.to_owned(),
        })
    }
}

#[cfg(feature = "v1")]
#[async_trait::async_trait]
impl CustomerAddress for api_models::customers::CustomerUpdateRequest {
    async fn get_address_update(
        &self,
        state: &SessionState,
        address_details: payments::AddressDetails,
        key: &[u8],
        storage_scheme: storage::enums::MerchantStorageScheme,
        merchant_id: id_type::MerchantId,
    ) -> CustomResult<storage::AddressUpdate, common_utils::errors::CryptoError> {
        let encrypted_data = crypto_operation(
            &state.into(),
            type_name!(storage::Address),
            CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable(
                domain::FromRequestEncryptableAddress {
                    line1: address_details.line1.clone(),
                    line2: address_details.line2.clone(),
                    line3: address_details.line3.clone(),
                    state: address_details.state.clone(),
                    first_name: address_details.first_name.clone(),
                    last_name: address_details.last_name.clone(),
                    zip: address_details.zip.clone(),
                    phone_number: self.phone.clone(),
                    email: self
                        .email
                        .as_ref()
                        .map(|a| a.clone().expose().switch_strategy()),
                    origin_zip: address_details.origin_zip.clone(),
                },
            )),
            Identifier::Merchant(merchant_id.to_owned()),
            key,
        )
        .await
        .and_then(|val| val.try_into_batchoperation())?;

        let encryptable_address =
            domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
                .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
        Ok(storage::AddressUpdate::Update {
            city: address_details.city,
            country: address_details.country,
            line1: encryptable_address.line1,
            line2: encryptable_address.line2,
            line3: encryptable_address.line3,
            zip: encryptable_address.zip,
            state: encryptable_address.state,
            first_name: encryptable_address.first_name,
            last_name: encryptable_address.last_name,
            phone_number: encryptable_address.phone_number,
            country_code: self.phone_country_code.clone(),
            updated_by: storage_scheme.to_string(),
            email: encryptable_address.email.map(|email| {
                let encryptable: Encryptable<masking::Secret<String, pii::EmailStrategy>> =
                    Encryptable::new(
                        email.clone().into_inner().switch_strategy(),
                        email.into_encrypted(),
                    );
                encryptable
            }),
            origin_zip: encryptable_address.origin_zip,
        })
    }

    async fn get_domain_address(
        &self,
        state: &SessionState,
        address_details: payments::AddressDetails,
        merchant_id: &id_type::MerchantId,
        customer_id: &id_type::CustomerId,
        key: &[u8],
        storage_scheme: storage::enums::MerchantStorageScheme,
    ) -> CustomResult<domain::CustomerAddress, common_utils::errors::CryptoError> {
        let encrypted_data = crypto_operation(
            &state.into(),
            type_name!(storage::Address),
            CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable(
                domain::FromRequestEncryptableAddress {
                    line1: address_details.line1.clone(),
                    line2: address_details.line2.clone(),
                    line3: address_details.line3.clone(),
                    state: address_details.state.clone(),
                    first_name: address_details.first_name.clone(),
                    last_name: address_details.last_name.clone(),
                    zip: address_details.zip.clone(),
                    phone_number: self.phone.clone(),
                    email: self
                        .email
                        .as_ref()
                        .map(|a| a.clone().expose().switch_strategy()),
                    origin_zip: address_details.origin_zip.clone(),
                },
            )),
            Identifier::Merchant(merchant_id.to_owned()),
            key,
        )
        .await
        .and_then(|val| val.try_into_batchoperation())?;

        let encryptable_address =
            domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
                .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
        let address = domain::Address {
            city: address_details.city,
            country: address_details.country,
            line1: encryptable_address.line1,
            line2: encryptable_address.line2,
            line3: encryptable_address.line3,
            zip: encryptable_address.zip,
            state: encryptable_address.state,
            first_name: encryptable_address.first_name,
            last_name: encryptable_address.last_name,
            phone_number: encryptable_address.phone_number,
            country_code: self.phone_country_code.clone(),
            merchant_id: merchant_id.to_owned(),
            address_id: generate_id(consts::ID_LENGTH, "add"),
            created_at: common_utils::date_time::now(),
            modified_at: common_utils::date_time::now(),
            updated_by: storage_scheme.to_string(),
            email: encryptable_address.email.map(|email| {
                let encryptable: Encryptable<masking::Secret<String, pii::EmailStrategy>> =
                    Encryptable::new(
                        email.clone().into_inner().switch_strategy(),
                        email.into_encrypted(),
                    );
                encryptable
            }),
            origin_zip: encryptable_address.origin_zip,
        };

        Ok(domain::CustomerAddress {
            address,
            customer_id: customer_id.to_owned(),
        })
    }
}

pub fn add_apple_pay_flow_metrics(
    apple_pay_flow: &Option<domain::ApplePayFlow>,
    connector: Option<String>,
    merchant_id: id_type::MerchantId,
) {
    if let Some(flow) = apple_pay_flow {
        match flow {
            domain::ApplePayFlow::Simplified(_) => metrics::APPLE_PAY_SIMPLIFIED_FLOW.add(
                1,
                router_env::metric_attributes!(
                    (
                        "connector",
                        connector.to_owned().unwrap_or("null".to_string()),
                    ),
                    ("merchant_id", merchant_id.clone()),
                ),
            ),
            domain::ApplePayFlow::Manual => metrics::APPLE_PAY_MANUAL_FLOW.add(
                1,
                router_env::metric_attributes!(
                    (
                        "connector",
                        connector.to_owned().unwrap_or("null".to_string()),
                    ),
                    ("merchant_id", merchant_id.clone()),
                ),
            ),
        }
    }
}

pub fn add_apple_pay_payment_status_metrics(
    payment_attempt_status: enums::AttemptStatus,
    apple_pay_flow: Option<domain::ApplePayFlow>,
    connector: Option<String>,
    merchant_id: id_type::MerchantId,
) {
    if payment_attempt_status == enums::AttemptStatus::Charged {
        if let Some(flow) = apple_pay_flow {
            match flow {
                domain::ApplePayFlow::Simplified(_) => {
                    metrics::APPLE_PAY_SIMPLIFIED_FLOW_SUCCESSFUL_PAYMENT.add(
                        1,


impl Responder {
    let flow = Flow::PaymentsCreate;
    let mut payload = json_payload.into_inner();
    if let Err(err) = payload
        .validate()
        .map_err(|message| errors::ApiErrorResponse::InvalidRequestData { message })
    {
        return api::log_and_return_error_response(err.into());
    };

    if let Some(api_enums::CaptureMethod::Scheduled) = payload.capture_method {
        return http_not_implemented();
    };

    if let Err(err) = get_or_generate_payment_id(&mut payload) {
        return api::log_and_return_error_response(err);
    }

    let header_payload = match HeaderPayload::foreign_try_from(req.headers()) {
        Ok(headers) => headers,
        Err(err) => {
            return api::log_and_return_error_response(err);
        }
    };

    tracing::Span::current().record(
        "payment_id",
        payload
            .payment_id
            .as_ref()
            .map(|payment_id_type| payment_id_type.get_payment_intent_id())
            .transpose()
            .unwrap_or_default()
            .as_ref()
            .map(|id| id.get_string_repr())
            .unwrap_or_default(),
    );

    let locking_action = payload.get_locking_input(flow.clone());

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            authorize_verify_select::<_>(
                payments::PaymentCreate,
                state,
                req_state,
                merchant_context,
                auth.profile_id,
                header_payload.clone(),
                req,
                api::AuthFlow::Client,
            )
        },
        match env::which() {
            env::Env::Production => &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: true,
            }),
            _ => auth::auth_type(
                &auth::HeaderAuth(auth::ApiKeyAuth {
                    is_connected_allowed: false,
                    is_platform_allowed: true,
                }),
                &auth::JWTAuth {
                    permission: Permission::ProfilePaymentWrite,
                },
                req.headers(),
            ),
        },
        locking_action,
    ))
    .await
}


pub struct ToggleDynamicRoutingWrapper {
    pub profile_id: common_utils::id_type::ProfileId,
    pub feature_to_enable: DynamicRoutingFeatures,
}


pub struct InviteUser {
    pub recipient_email: domain::UserEmail,
    pub user_name: domain::UserName,
    pub settings: std::sync::Arc<configs::Settings>,
    pub entity: Entity,
    pub auth_id: Option<String>,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
}


impl api::RefundSync for Multisafepay {}

impl api::RefundSync for for Multisafepay


pub async fn get_token_vault_core(
    state: SessionState,
    merchant_account: &domain::MerchantAccount,
    merchant_key_store: &domain::MerchantKeyStore,
    query: id_type::GlobalTokenId,
) -> CustomResult<serde_json::Value, errors::ApiErrorResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let tokenization_record = db
        .get_entity_id_vault_id_by_token_id(
            &query,
            &(merchant_key_store.clone()),
            key_manager_state,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to get tokenization record")?;

    if tokenization_record.flag == enums::TokenizationFlag::Disabled {
        return Err(errors::ApiErrorResponse::GenericNotFoundError {
            message: "Tokenization is disabled for the id".to_string(),
        }
        .into());
    }

    let vault_request = pm_types::VaultRetrieveRequest {
        entity_id: tokenization_record.customer_id.clone(),
        vault_id: hyperswitch_domain_models::payment_methods::VaultId::generate(
            tokenization_record.locker_id.clone(),
        ),
    };

    let vault_data = pm_vault::retrieve_value_from_vault(&state, vault_request)
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to retrieve vault data")?;

    let data_json = vault_data
        .get("data")
        .cloned()
        .unwrap_or(serde_json::Value::Null);

    // Create the response
    Ok(data_json)
}


File: crates/router/src/db/callback_mapper.rs

use error_stack::report;
use hyperswitch_domain_models::callback_mapper as domain;
use router_env::{instrument, tracing};
use storage_impl::{DataModelExt, MockDb};

use super::Store;
use crate::{
    connection,
    core::errors::{self, CustomResult},
    types::storage,
};

#[async_trait::async_trait]
pub trait CallbackMapperInterface {
    async fn insert_call_back_mapper(
        &self,
        call_back_mapper: domain::CallbackMapper,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError>;

    async fn find_call_back_mapper_by_id(
        &self,
        id: &str,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError>;
}

#[async_trait::async_trait]
impl CallbackMapperInterface for Store {
    #[instrument(skip_all)]
    async fn insert_call_back_mapper(
        &self,
        call_back_mapper: domain::CallbackMapper,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError> {
        let conn = connection::pg_connection_write(self).await?;
        call_back_mapper
            .to_storage_model()
            .insert(&conn)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
            .map(domain::CallbackMapper::from_storage_model)
    }

    #[instrument(skip_all)]
    async fn find_call_back_mapper_by_id(
        &self,
        id: &str,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError> {
        let conn = connection::pg_connection_read(self).await?;
        storage::CallbackMapper::find_by_id(&conn, id)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
            .map(domain::CallbackMapper::from_storage_model)
    }
}

#[async_trait::async_trait]
impl CallbackMapperInterface for MockDb {
    #[instrument(skip_all)]
    async fn insert_call_back_mapper(
        &self,
        _call_back_mapper: domain::CallbackMapper,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError> {
        Err(errors::StorageError::MockDbError)?
    }

    #[instrument(skip_all)]
    async fn find_call_back_mapper_by_id(
        &self,
        _id: &str,
    ) -> CustomResult<domain::CallbackMapper, errors::StorageError> {
        Err(errors::StorageError::MockDbError)?
    }
}


pub struct PayuPaymentsCaptureResponse {
    status: PayuPaymentStatusData,
}


pub fn enum_variant_array_value(input: &str) -> ParseResult<&str, ast::ValueType> {
    let many_with_comma = multi::many0(sequence::preceded(
        skip_ws(complete::tag(",")),
        skip_ws(enum_value_string),
    ));

    let full_sequence = sequence::pair(skip_ws(enum_value_string), many_with_comma);

    error::context(
        "enum_variant_array_value",
        combinator::map(
            sequence::delimited(
                skip_ws(complete::tag("(")),
                full_sequence,
                skip_ws(complete::tag(")")),
            ),
            |tup: (String, Vec<String>)| {
                let mut rest = tup.1;
                rest.insert(0, tup.0);
                ast::ValueType::EnumVariantArray(rest)
            },
        ),
    )(input)
}


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


File: crates/diesel_models/src/tokenization.rs
 Public structs: 3

#[cfg(feature = "v2")]
use common_enums;
#[cfg(feature = "v2")]
use common_utils::id_type;
#[cfg(feature = "v2")]
use diesel::{AsChangeset, Identifiable, Insertable, Queryable};
#[cfg(feature = "v2")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "v2")]
use time::PrimitiveDateTime;

#[cfg(feature = "v2")]
use crate::schema_v2::tokenization;

#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
#[derive(Clone, Debug, Identifiable, Insertable, Queryable)]
#[diesel(table_name = tokenization)]
pub struct Tokenization {
    pub id: id_type::GlobalTokenId,
    pub merchant_id: id_type::MerchantId,
    pub customer_id: id_type::GlobalCustomerId,
    pub created_at: PrimitiveDateTime,
    pub updated_at: PrimitiveDateTime,
    pub locker_id: String,
    pub flag: common_enums::enums::TokenizationFlag,
    pub version: common_enums::enums::ApiVersion,
}

#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
#[derive(Clone, Debug, Insertable)]
#[diesel(table_name = tokenization)]
pub struct TokenizationNew {
    pub id: id_type::GlobalTokenId,
    pub merchant_id: id_type::MerchantId,
    pub customer_id: id_type::GlobalCustomerId,
    pub locker_id: String,
    pub created_at: PrimitiveDateTime,
    pub updated_at: PrimitiveDateTime,
    pub version: common_enums::enums::ApiVersion,
    pub flag: common_enums::enums::TokenizationFlag,
}

#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
#[derive(Clone, Debug, AsChangeset)]
#[diesel(table_name = tokenization)]
pub struct TokenizationUpdateInternal {
    pub updated_at: PrimitiveDateTime,
    pub flag: Option<common_enums::enums::TokenizationFlag>,
}


pub struct ApiKeyExpiryReminder {
    pub recipient_email: domain::UserEmail,
    pub subject: &'static str,
    pub expires_in: u8,
    pub api_key_name: String,
    pub prefix: String,
    pub theme_id: Option<String>,
    pub theme_config: EmailThemeConfig,
}


pub async fn api_key_update(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<(
        common_utils::id_type::MerchantId,
        common_utils::id_type::ApiKeyId,
    )


impl api::Refund for Noon {}


pub struct GocardlessCustomerResponse {
    customers: Customers,
}


pub struct DwollaMetaData {
    pub merchant_funding_source: Secret<String>,
}


pub(crate) fn into_stripe_next_action(
    next_action: Option<payments::NextActionData>,
    return_url: Option<String>,
) -> Option<StripeNextAction> {
    next_action.map(|next_action_data| match next_action_data {
        payments::NextActionData::RedirectToUrl { redirect_to_url } => {
            StripeNextAction::RedirectToUrl {
                redirect_to_url: RedirectUrl {
                    return_url,
                    url: Some(redirect_to_url),
                },
            }
        }
        payments::NextActionData::RedirectInsidePopup { popup_url, .. } => {
            StripeNextAction::RedirectToUrl {
                redirect_to_url: RedirectUrl {
                    return_url,
                    url: Some(popup_url),
                },
            }
        }
        payments::NextActionData::DisplayBankTransferInformation {
            bank_transfer_steps_and_charges_details,
        } => StripeNextAction::DisplayBankTransferInformation {
            bank_transfer_steps_and_charges_details,
        },
        payments::NextActionData::ThirdPartySdkSessionToken { session_token } => {
            StripeNextAction::ThirdPartySdkSessionToken { session_token }
        }

        payments::NextActionData::QrCodeInformation {
            image_data_url,
            display_to_timestamp,
            qr_code_url,
            border_color,
            display_text,
        } => StripeNextAction::QrCodeInformation {
            image_data_url,
            display_to_timestamp,
            qr_code_url,
            border_color,
            display_text,
        },
        payments::NextActionData::FetchQrCodeInformation { qr_code_fetch_url } => {
            StripeNextAction::FetchQrCodeInformation { qr_code_fetch_url }
        }
        payments::NextActionData::DisplayVoucherInformation { voucher_details } => {
            StripeNextAction::DisplayVoucherInformation { voucher_details }
        }
        payments::NextActionData::WaitScreenInformation {
            display_from_timestamp,
            display_to_timestamp,
            poll_config: _,
        } => StripeNextAction::WaitScreenInformation {
            display_from_timestamp,
            display_to_timestamp,
            poll_config: None,
        },
        payments::NextActionData::ThreeDsInvoke { .. } => StripeNextAction::RedirectToUrl {
            redirect_to_url: RedirectUrl {
                return_url: None,
                url: None,
            },
        },
        payments::NextActionData::InvokeSdkClient { next_action_data } => {
            StripeNextAction::InvokeSdkClient { next_action_data }
        }
        payments::NextActionData::CollectOtp {
            consent_data_required,
        } => StripeNextAction::CollectOtp {
            consent_data_required,
        },
        payments::NextActionData::InvokeHiddenIframe { iframe_data } => {
            StripeNextAction::InvokeHiddenIframe { iframe_data }
        }
    })
}


pub async fn get_payment_processor_token_with_schedule_time(
        state: &SessionState,
        connector_customer_id: &str,
    ) -> CustomResult<Option<PaymentProcessorTokenStatus>, errors::StorageError> {
        let tokens =
            Self::get_connector_customer_payment_processor_tokens(state, connector_customer_id)
                .await?;

        let scheduled_token = tokens
            .values()
            .find(|status| status.scheduled_at.is_some())
            .cloned();

        tracing::debug!(
            connector_customer_id = connector_customer_id,
            "Fetched payment processor token with schedule time",
        );

        Ok(scheduled_token)
    }


pub struct DeutschebankAmount {
    amount: MinorUnit,
    currency: api_models::enums::Currency,
}


pub struct DwollaFundingSourceResponse {}