impl PaymentAttemptUpdate {
    pub fn to_storage_model(self) -> diesel_models::PaymentAttemptUpdate {
        match self {
            Self::Update {
                net_amount,
                currency,
                status,
                authentication_type,
                payment_method,
                payment_token,
                payment_method_data,
                payment_method_type,
                payment_experience,
                business_sub_label,
                amount_to_capture,
                capture_method,
                fingerprint_id,
                network_transaction_id,
                payment_method_billing_address_id,
                updated_by,
            } => DieselPaymentAttemptUpdate::Update {
                amount: net_amount.get_order_amount(),
                currency,
                status,
                authentication_type,
                payment_method,
                payment_token,
                payment_method_data,
                payment_method_type,
                payment_experience,
                business_sub_label,
                amount_to_capture,
                capture_method,
                surcharge_amount: net_amount.get_surcharge_amount(),
                tax_amount: net_amount.get_tax_on_surcharge(),
                fingerprint_id,
                payment_method_billing_address_id,
                network_transaction_id,
                updated_by,
            },
            Self::UpdateTrackers {
                payment_token,
                connector,
                straight_through_algorithm,
                amount_capturable,
                updated_by,
                surcharge_amount,
                tax_amount,
                merchant_connector_id,
                routing_approach,
            } => DieselPaymentAttemptUpdate::UpdateTrackers {
                payment_token,
                connector,
                straight_through_algorithm,
                amount_capturable,
                surcharge_amount,
                tax_amount,
                updated_by,
                merchant_connector_id,
                routing_approach: routing_approach.map(|approach| match approach {
                    storage_enums::RoutingApproach::Other(_) => {
                        // we need to make sure Other variant is not stored in DB, in the rare case
                        // where we attempt to store an unknown value, we default to the default value
                        storage_enums::RoutingApproach::default()
                    }
                    _ => approach,
                }),
            },
            Self::AuthenticationTypeUpdate {
                authentication_type,
                updated_by,
            } => DieselPaymentAttemptUpdate::AuthenticationTypeUpdate {
                authentication_type,
                updated_by,
            },
            Self::BlocklistUpdate {
                status,
                error_code,
                error_message,
                updated_by,
            } => DieselPaymentAttemptUpdate::BlocklistUpdate {
                status,
                error_code,
                error_message,
                updated_by,
            },
            Self::ConnectorMandateDetailUpdate {
                connector_mandate_detail,
                updated_by,
            } => DieselPaymentAttemptUpdate::ConnectorMandateDetailUpdate {
                connector_mandate_detail,
                updated_by,
            },
            Self::PaymentMethodDetailsUpdate {
                payment_method_id,
                updated_by,
            } => DieselPaymentAttemptUpdate::PaymentMethodDetailsUpdate {
                payment_method_id,
                updated_by,
            },
            Self::ConfirmUpdate {
                net_amount,
                currency,
                status,
                authentication_type,
                capture_method,
                payment_method,
                browser_info,
                connector,
                payment_token,
                payment_method_data,
                payment_method_type,
                payment_experience,
                business_sub_label,
                straight_through_algorithm,
                error_code,
                error_message,
                fingerprint_id,
                updated_by,
                merchant_connector_id: connector_id,
                payment_method_id,
                external_three_ds_authentication_attempted,
                authentication_connector,
                authentication_id,
                payment_method_billing_address_id,
                client_source,
                client_version,
                customer_acceptance,
                connector_mandate_detail,
                card_discovery,
                routing_approach,
                connector_request_reference_id,
                network_transaction_id,
            } => DieselPaymentAttemptUpdate::ConfirmUpdate {
                amount: net_amount.get_order_amount(),
                currency,
                status,
                authentication_type,
                capture_method,
                payment_method,
                browser_info,
                connector,
                payment_token,
                payment_method_data,
                payment_method_type,
                payment_experience,
                business_sub_label,
                straight_through_algorithm,
                error_code,
                error_message,
                surcharge_amount: net_amount.get_surcharge_amount(),
                tax_amount: net_amount.get_tax_on_surcharge(),
                fingerprint_id,
                updated_by,
                merchant_connector_id: connector_id,
                payment_method_id,
                external_three_ds_authentication_attempted,
                authentication_connector,
                authentication_id,
                payment_method_billing_address_id,
                client_source,
                client_version,
                customer_acceptance,
                shipping_cost: net_amount.get_shipping_cost(),
                order_tax_amount: net_amount.get_order_tax_amount(),
                connector_mandate_detail,
                card_discovery,
                routing_approach: routing_approach.map(|approach| match approach {
                    // we need to make sure Other variant is not stored in DB, in the rare case
                    // where we attempt to store an unknown value, we default to the default value
                    storage_enums::RoutingApproach::Other(_) => {
                        storage_enums::RoutingApproach::default()
                    }
                    _ => approach,
                }),
                connector_request_reference_id,
                network_transaction_id,
            },
            Self::VoidUpdate {
                status,
                cancellation_reason,
                updated_by,
            } => DieselPaymentAttemptUpdate::VoidUpdate {
                status,
                cancellation_reason,
                updated_by,
            },
            Self::ResponseUpdate {
                status,
                connector,
                connector_transaction_id,
                authentication_type,
                payment_method_id,
                mandate_id,
                connector_metadata,
                payment_token,
                error_code,
                error_message,
                error_reason,
                connector_response_reference_id,
                amount_capturable,
                updated_by,
                authentication_data,
                encoded_data,
                unified_code,
                unified_message,
                capture_before,
                extended_authorization_applied,
                payment_method_data,
                connector_mandate_detail,
                charges,
                setup_future_usage_applied,
                network_transaction_id,
                debit_routing_savings: _,
            } => DieselPaymentAttemptUpdate::ResponseUpdate {
                status,
                connector,
                connector_transaction_id,
                authentication_type,
                payment_method_id,
                mandate_id,
                connector_metadata,
                payment_token,
                error_code,
                error_message,
                error_reason,
                connector_response_reference_id,
                amount_capturable,
                updated_by,
                authentication_data,
                encoded_data,
                unified_code,
                unified_message,
                capture_before,
                extended_authorization_applied,
                payment_method_data,
                connector_mandate_detail,
                charges,
                setup_future_usage_applied,
                network_transaction_id,
            },
            Self::UnresolvedResponseUpdate {
                status,
                connector,
                connector_transaction_id,
                payment_method_id,
                error_code,
                error_message,
                error_reason,
                connector_response_reference_id,
                updated_by,
            } => DieselPaymentAttemptUpdate::UnresolvedResponseUpdate {
                status,
                connector,
                connector_transaction_id,
                payment_method_id,
                error_code,
                error_message,
                error_reason,
                connector_response_reference_id,
                updated_by,
            },
            Self::StatusUpdate { status, updated_by } => {
                DieselPaymentAttemptUpdate::StatusUpdate { status, updated_by }
            }
            Self::ErrorUpdate {
                connector,
                status,
                error_code,
                error_message,
                error_reason,
                amount_capturable,
                updated_by,
                unified_code,
                unified_message,
                connector_transaction_id,
                payment_method_data,
                authentication_type,
                issuer_error_code,
                issuer_error_message,
            } => DieselPaymentAttemptUpdate::ErrorUpdate {
                connector,
                status,
                error_code,
                error_message,
                error_reason,
                amount_capturable,
                updated_by,
                unified_code,
                unified_message,
                connector_transaction_id,
                payment_method_data,
                authentication_type,
                issuer_error_code,
                issuer_error_message,
            },
            Self::CaptureUpdate {
                multiple_capture_count,
                updated_by,
                amount_to_capture,
            } => DieselPaymentAttemptUpdate::CaptureUpdate {
                multiple_capture_count,
                updated_by,
                amount_to_capture,
            },
            Self::PreprocessingUpdate {
                status,
                payment_method_id,
                connector_metadata,
                preprocessing_step_id,
                connector_transaction_id,
                connector_response_reference_id,
                updated_by,
            } => DieselPaymentAttemptUpdate::PreprocessingUpdate {
                status,
                payment_method_id,
                connector_metadata,
                preprocessing_step_id,
                connector_transaction_id,
                connector_response_reference_id,
                updated_by,
            },
            Self::RejectUpdate {
                status,
                error_code,
                error_message,
                updated_by,
            } => DieselPaymentAttemptUpdate::RejectUpdate {
                status,
                error_code,
                error_message,
                updated_by,
            },
            Self::AmountToCaptureUpdate {
                status,
                amount_capturable,
                updated_by,
            } => DieselPaymentAttemptUpdate::AmountToCaptureUpdate {
                status,
                amount_capturable,
                updated_by,
            },
            Self::ConnectorResponse {
                authentication_data,
                encoded_data,
                connector_transaction_id,
                connector,
                charges,
                updated_by,
            } => DieselPaymentAttemptUpdate::ConnectorResponse {
                authentication_data,
                encoded_data,
                connector_transaction_id,
                charges,
                connector,
                updated_by,
            },
            Self::IncrementalAuthorizationAmountUpdate {
                net_amount,
                amount_capturable,
            } => DieselPaymentAttemptUpdate::IncrementalAuthorizationAmountUpdate {
                amount: net_amount.get_order_amount(),
                amount_capturable,
            },
            Self::AuthenticationUpdate {
                status,
                external_three_ds_authentication_attempted,
                authentication_connector,
                authentication_id,
                updated_by,
            } => DieselPaymentAttemptUpdate::AuthenticationUpdate {
                status,
                external_three_ds_authentication_attempted,
                authentication_connector,
                authentication_id,
                updated_by,
            },
            Self::ManualUpdate {
                status,
                error_code,
                error_message,
                error_reason,
                updated_by,
                unified_code,
                unified_message,
                connector_transaction_id,
            } => DieselPaymentAttemptUpdate::ManualUpdate {
                status,
                error_code,
                error_message,
                error_reason,
                updated_by,
                unified_code,
                unified_message,
                connector_transaction_id,
            },
            Self::PostSessionTokensUpdate {
                updated_by,
                connector_metadata,
            } => DieselPaymentAttemptUpdate::PostSessionTokensUpdate {
                updated_by,
                connector_metadata,
            },
        }
    }

    pub fn get_debit_routing_savings(&self) -> Option<&MinorUnit> {
        match self {
            Self::ResponseUpdate {
                debit_routing_savings,
                ..
            } => debit_routing_savings.as_ref(),
            Self::Update { .. }
            | Self::UpdateTrackers { .. }
            | Self::AuthenticationTypeUpdate { .. }
            | Self::ConfirmUpdate { .. }
            | Self::RejectUpdate { .. }
            | Self::BlocklistUpdate { .. }
            | Self::PaymentMethodDetailsUpdate { .. }
            | Self::ConnectorMandateDetailUpdate { .. }
            | Self::VoidUpdate { .. }
            | Self::UnresolvedResponseUpdate { .. }
            | Self::StatusUpdate { .. }
            | Self::ErrorUpdate { .. }
            | Self::CaptureUpdate { .. }
            | Self::AmountToCaptureUpdate { .. }
            | Self::PreprocessingUpdate { .. }
            | Self::ConnectorResponse { .. }
            | Self::IncrementalAuthorizationAmountUpdate { .. }
            | Self::AuthenticationUpdate { .. }
            | Self::ManualUpdate { .. }
            | Self::PostSessionTokensUpdate { .. } => None,
        }
    }
}


pub fn server(state: AppState) -> Scope {
        web::scope("/cards")
            .app_data(web::Data::new(state))
            .service(web::resource("/create").route(web::post().to(create_cards_info)))
            .service(web::resource("/update").route(web::post().to(update_cards_info)))
            .service(web::resource("/update-batch").route(web::post().to(migrate_cards_info)))
            .service(web::resource("/{bin}").route(web::get().to(card_iin_info)))
    }


pub async fn find_last_successful_or_partially_captured_attempt_by_payment_id_merchant_id(
        conn: &PgPooledConn,
        payment_id: &common_utils::id_type::PaymentId,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> StorageResult<Self> {
        // perform ordering on the application level instead of database level
        generics::generic_filter::<<Self as HasTable>::Table, _, _, Self>(
            conn,
            dsl::payment_id
                .eq(payment_id.to_owned())
                .and(dsl::merchant_id.eq(merchant_id.to_owned()))
                .and(
                    dsl::status
                        .eq(enums::AttemptStatus::Charged)
                        .or(dsl::status.eq(enums::AttemptStatus::PartialCharged)),
                ),
            Some(1),
            None,
            Some(dsl::modified_at.desc()),
        )
        .await?
        .into_iter()
        .nth(0)
        .ok_or(report!(DatabaseError::NotFound))
    }


/// Emit the event and log any errors.
    pub fn emit(self) {
        self.try_emit()
            .map_err(|e| {
                logger::error!("Error emitting event: {:?}", e);
            })
            .ok();
    }


impl ClientSecretFetch for PaymentMethodListRequest {
    fn get_client_secret(&self) -> Option<&String> {
        self.client_secret.as_ref()
    }
}

impl ClientSecretFetch for for PaymentMethodListRequest


pub struct ClientSecretType {
    pub id: common_utils::id_type::ClientSecretId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub resource_id: common_utils::types::authentication::ResourceId,
    pub created_at: time::PrimitiveDateTime,
    pub expires: time::PrimitiveDateTime,
    pub secret: Secret<String>,
}


pub async fn create_role_v2(
    state: SessionState,
    user_from_token: UserFromToken,
    req: role_api::CreateRoleV2Request,
    _req_state: ReqState,
) -> UserResponse<role_api::RoleInfoResponseWithParentsGroup> {
    let now = common_utils::date_time::now();

    let user_entity_type = user_from_token
        .get_role_info_from_db(&state)
        .await
        .attach_printable("Invalid role_id in JWT")?
        .get_entity_type();

    let role_entity_type = req.entity_type.unwrap_or(EntityType::Merchant);

    if matches!(role_entity_type, EntityType::Organization) {
        return Err(report!(UserErrors::InvalidRoleOperation))
            .attach_printable("User trying to create org level custom role");
    }

    let requestor_entity_from_role_scope = EntityType::from(req.role_scope);

    if requestor_entity_from_role_scope < role_entity_type {
        return Err(report!(UserErrors::InvalidRoleOperation)).attach_printable(format!(
            "User is trying to create role of type {role_entity_type} and scope {requestor_entity_from_role_scope}",
        ));
    }

    let max_from_scope_and_entity = cmp::max(requestor_entity_from_role_scope, role_entity_type);

    if user_entity_type < max_from_scope_and_entity {
        return Err(report!(UserErrors::InvalidRoleOperation)).attach_printable(format!(
            "{user_entity_type} is trying to create of scope {requestor_entity_from_role_scope} and of type {role_entity_type}",
        ));
    }

    let role_name = RoleName::new(req.role_name.clone())?;

    let permission_groups =
        utils::user_role::parent_group_info_request_to_permission_groups(&req.parent_groups)?;

    utils::user_role::validate_role_groups(&permission_groups)?;
    utils::user_role::validate_role_name(
        &state,
        &role_name,
        &user_from_token.merchant_id,
        &user_from_token.org_id,
        user_from_token
            .tenant_id
            .as_ref()
            .unwrap_or(&state.tenant.tenant_id),
        &user_from_token.profile_id,
        &role_entity_type,
    )
    .await?;

    let (org_id, merchant_id, profile_id) = match role_entity_type {
        EntityType::Organization | EntityType::Tenant => (user_from_token.org_id, None, None),
        EntityType::Merchant => (
            user_from_token.org_id,
            Some(user_from_token.merchant_id),
            None,
        ),
        EntityType::Profile => (
            user_from_token.org_id,
            Some(user_from_token.merchant_id),
            Some(user_from_token.profile_id),
        ),
    };

    let role = state
        .global_store
        .insert_role(RoleNew {
            role_id: generate_id_with_default_len("role"),
            role_name: role_name.get_role_name(),
            merchant_id,
            org_id,
            groups: permission_groups,
            scope: req.role_scope,
            entity_type: role_entity_type,
            created_by: user_from_token.user_id.clone(),
            last_modified_by: user_from_token.user_id,
            created_at: now,
            last_modified_at: now,
            profile_id,
            tenant_id: user_from_token.tenant_id.unwrap_or(state.tenant.tenant_id),
        })
        .await
        .to_duplicate_response(UserErrors::RoleNameAlreadyExists)?;

    let response_parent_groups =
        utils::user_role::permission_groups_to_parent_group_info(&role.groups, role.entity_type);

    Ok(ApplicationResponse::Json(
        role_api::RoleInfoResponseWithParentsGroup {
            role_id: role.role_id,
            role_name: role.role_name,
            role_scope: role.scope,
            entity_type: role.entity_type,
            parent_groups: response_parent_groups,
        },
    ))
}


pub async fn dummy_connector_authorize_payment(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    path: web::Path<String>,
) -> impl actix_web::Responder {
    let flow = types::Flow::DummyPaymentAuthorize;
    let attempt_id = path.into_inner();
    let payload = types::DummyConnectorPaymentConfirmRequest { attempt_id };
    api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _: (), req, _| core::payment_authorize(state, req),
        &auth::NoAuth,
        api_locking::LockAction::NotApplicable,
    )
    .await
}


Documentation: api-reference/v1/mandates/mandates--revoke-mandate.mdx
# Type: Doc File

---
openapi: post /mandates/revoke/{mandate_id}
---


File: crates/analytics/src/payment_intents/metrics/sessionized_metrics/successful_smart_retries.rs

use std::collections::HashSet;

use api_models::{
    analytics::{
        payment_intents::{
            PaymentIntentDimensions, PaymentIntentFilters, PaymentIntentMetricsBucketIdentifier,
        },
        Granularity, TimeRange,
    },
    enums::IntentStatus,
};
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

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

#[derive(Default)]
pub(crate) struct SuccessfulSmartRetries;

#[async_trait::async_trait]
impl<T> super::PaymentIntentMetric<T> for SuccessfulSmartRetries
where
    T: AnalyticsDataSource + super::PaymentIntentMetricAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_metrics(
        &self,
        dimensions: &[PaymentIntentDimensions],
        auth: &AuthInfo,
        filters: &PaymentIntentFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>
    {
        let mut query_builder: QueryBuilder<T> =
            QueryBuilder::new(AnalyticsCollection::PaymentIntentSessionized);

        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()?;

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

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

        query_builder
            .add_custom_filter_clause("attempt_count", "1", FilterTypes::Gt)
            .switch()?;
        query_builder
            .add_custom_filter_clause("status", IntentStatus::Succeeded, FilterTypes::Equal)
            .switch()?;
        time_range
            .set_filter_clause(&mut query_builder)
            .attach_printable("Error filtering time range")
            .switch()?;

        for dim in dimensions.iter() {
            query_builder
                .add_group_by_clause(dim)
                .attach_printable("Error grouping by dimensions")
                .switch()?;
        }
        if let Some(granularity) = granularity {
            granularity
                .set_group_by_clause(&mut query_builder)
                .attach_printable("Error adding granularity")
                .switch()?;
        }

        query_builder
            .execute_query::<PaymentIntentMetricRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| {
                Ok((
                    PaymentIntentMetricsBucketIdentifier::new(
                        i.status.as_ref().map(|i| i.0),
                        i.currency.as_ref().map(|i| i.0),
                        i.profile_id.clone(),
                        i.connector.clone(),
                        i.authentication_type.as_ref().map(|i| i.0),
                        i.payment_method.clone(),
                        i.payment_method_type.clone(),
                        i.card_network.clone(),
                        i.merchant_id.clone(),
                        i.card_last_4.clone(),
                        i.card_issuer.clone(),
                        i.error_reason.clone(),
                        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<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
                crate::query::PostProcessingError,
            >>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


pub struct DecryptDataRequest {
    #[serde(flatten)]
    pub identifier: Identifier,
    pub data: StrongSecret<String>,
}


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


pub struct OnlineMandate {
    /// Ip address of the customer machine from which the mandate was created
    #[schema(value_type = String, example = "123.32.25.123")]
    pub ip_address: Option<Secret<String, pii::IpAddress>>,
    /// The user-agent of the customer's browser
    pub user_agent: String,
}


pub fn apply_changeset(self, source: Profile) -> Profile {
        let Self {
            profile_name,
            modified_at,
            return_url,
            enable_payment_response_hash,
            payment_response_hash_key,
            redirect_to_merchant_with_http_post,
            webhook_details,
            metadata,
            is_recon_enabled,
            applepay_verified_domains,
            payment_link_config,
            session_expiry,
            authentication_connector_details,
            payout_link_config,
            is_extended_card_info_enabled,
            extended_card_info_config,
            is_connector_agnostic_mit_enabled,
            use_billing_as_payment_method_billing,
            collect_shipping_details_from_wallet_connector,
            collect_billing_details_from_wallet_connector,
            outgoing_webhook_custom_http_headers,
            always_collect_billing_details_from_wallet_connector,
            always_collect_shipping_details_from_wallet_connector,
            tax_connector_id,
            is_tax_connector_enabled,
            routing_algorithm_id,
            order_fulfillment_time,
            order_fulfillment_time_origin,
            frm_routing_algorithm_id,
            payout_routing_algorithm_id,
            default_fallback_routing,
            should_collect_cvv_during_payment,
            is_network_tokenization_enabled,
            is_auto_retries_enabled,
            max_auto_retries_enabled,
            is_click_to_pay_enabled,
            authentication_product_ids,
            three_ds_decision_manager_config,
            card_testing_guard_config,
            card_testing_secret_key,
            is_clear_pan_retries_enabled,
            is_debit_routing_enabled,
            merchant_business_country,
            revenue_recovery_retry_algorithm_type,
            revenue_recovery_retry_algorithm_data,
            is_iframe_redirection_enabled,
            is_external_vault_enabled,
            external_vault_connector_details,
            merchant_category_code,
            merchant_country_code,
            split_txns_enabled,
        } = self;
        Profile {
            id: source.id,
            merchant_id: source.merchant_id,
            profile_name: profile_name.unwrap_or(source.profile_name),
            created_at: source.created_at,
            modified_at,
            return_url: return_url.or(source.return_url),
            enable_payment_response_hash: enable_payment_response_hash
                .unwrap_or(source.enable_payment_response_hash),
            payment_response_hash_key: payment_response_hash_key
                .or(source.payment_response_hash_key),
            redirect_to_merchant_with_http_post: redirect_to_merchant_with_http_post
                .unwrap_or(source.redirect_to_merchant_with_http_post),
            webhook_details: webhook_details.or(source.webhook_details),
            metadata: metadata.or(source.metadata),
            is_recon_enabled: is_recon_enabled.unwrap_or(source.is_recon_enabled),
            applepay_verified_domains: applepay_verified_domains
                .or(source.applepay_verified_domains),
            payment_link_config: payment_link_config.or(source.payment_link_config),
            session_expiry: session_expiry.or(source.session_expiry),
            authentication_connector_details: authentication_connector_details
                .or(source.authentication_connector_details),
            payout_link_config: payout_link_config.or(source.payout_link_config),
            is_extended_card_info_enabled: is_extended_card_info_enabled
                .or(source.is_extended_card_info_enabled),
            is_connector_agnostic_mit_enabled: is_connector_agnostic_mit_enabled
                .or(source.is_connector_agnostic_mit_enabled),
            extended_card_info_config: extended_card_info_config
                .or(source.extended_card_info_config),
            use_billing_as_payment_method_billing: use_billing_as_payment_method_billing
                .or(source.use_billing_as_payment_method_billing),
            collect_shipping_details_from_wallet_connector:
                collect_shipping_details_from_wallet_connector
                    .or(source.collect_shipping_details_from_wallet_connector),
            collect_billing_details_from_wallet_connector:
                collect_billing_details_from_wallet_connector
                    .or(source.collect_billing_details_from_wallet_connector),
            outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers
                .or(source.outgoing_webhook_custom_http_headers),
            always_collect_billing_details_from_wallet_connector:
                always_collect_billing_details_from_wallet_connector
                    .or(always_collect_billing_details_from_wallet_connector),
            always_collect_shipping_details_from_wallet_connector:
                always_collect_shipping_details_from_wallet_connector
                    .or(always_collect_shipping_details_from_wallet_connector),
            tax_connector_id: tax_connector_id.or(source.tax_connector_id),
            is_tax_connector_enabled: is_tax_connector_enabled.or(source.is_tax_connector_enabled),
            routing_algorithm_id: routing_algorithm_id.or(source.routing_algorithm_id),
            order_fulfillment_time: order_fulfillment_time.or(source.order_fulfillment_time),
            order_fulfillment_time_origin: order_fulfillment_time_origin
                .or(source.order_fulfillment_time_origin),
            frm_routing_algorithm_id: frm_routing_algorithm_id.or(source.frm_routing_algorithm_id),
            payout_routing_algorithm_id: payout_routing_algorithm_id
                .or(source.payout_routing_algorithm_id),
            default_fallback_routing: default_fallback_routing.or(source.default_fallback_routing),
            should_collect_cvv_during_payment: should_collect_cvv_during_payment
                .or(source.should_collect_cvv_during_payment),
            version: source.version,
            dynamic_routing_algorithm: None,
            is_network_tokenization_enabled: is_network_tokenization_enabled
                .unwrap_or(source.is_network_tokenization_enabled),
            is_auto_retries_enabled: is_auto_retries_enabled.or(source.is_auto_retries_enabled),
            max_auto_retries_enabled: max_auto_retries_enabled.or(source.max_auto_retries_enabled),
            always_request_extended_authorization: None,
            is_click_to_pay_enabled: is_click_to_pay_enabled
                .unwrap_or(source.is_click_to_pay_enabled),
            authentication_product_ids: authentication_product_ids
                .or(source.authentication_product_ids),
            three_ds_decision_manager_config: three_ds_decision_manager_config
                .or(source.three_ds_decision_manager_config),
            card_testing_guard_config: card_testing_guard_config
                .or(source.card_testing_guard_config),
            card_testing_secret_key: card_testing_secret_key.or(source.card_testing_secret_key),
            is_clear_pan_retries_enabled: is_clear_pan_retries_enabled
                .unwrap_or(source.is_clear_pan_retries_enabled),
            force_3ds_challenge: None,
            is_debit_routing_enabled: is_debit_routing_enabled
                .unwrap_or(source.is_debit_routing_enabled),
            merchant_business_country: merchant_business_country
                .or(source.merchant_business_country),
            revenue_recovery_retry_algorithm_type: revenue_recovery_retry_algorithm_type
                .or(source.revenue_recovery_retry_algorithm_type),
            revenue_recovery_retry_algorithm_data: revenue_recovery_retry_algorithm_data
                .or(source.revenue_recovery_retry_algorithm_data),
            is_iframe_redirection_enabled: is_iframe_redirection_enabled
                .or(source.is_iframe_redirection_enabled),
            is_external_vault_enabled: is_external_vault_enabled
                .or(source.is_external_vault_enabled),
            external_vault_connector_details: external_vault_connector_details
                .or(source.external_vault_connector_details),
            three_ds_decision_rule_algorithm: None,
            acquirer_config_map: None,
            merchant_category_code: merchant_category_code.or(source.merchant_category_code),
            merchant_country_code: merchant_country_code.or(source.merchant_country_code),
            dispute_polling_interval: None,
            split_txns_enabled: split_txns_enabled.or(source.split_txns_enabled),
            is_manual_retry_enabled: None,
        }
    }


pub struct NomupayPaymentResponse {
    pub id: String,
    pub status: NomupayPaymentStatus,
    pub created_on: String,
    pub last_updated: String,
    pub source_id: Secret<String>,
    pub destination_id: Secret<String>,
    pub payment_reference: String,
    pub amount: FloatMajorUnit,
    pub currency_code: String,
    pub purpose: String,
    pub description: String,
    pub internal_memo: String,
    pub release_on: String,
    pub expire_on: String,
}


File: crates/hyperswitch_connectors/src/connectors/threedsecureio/transformers.rs
 Public structs: 12

use std::str::FromStr;

use api_models::payments::{DeviceChannel, ThreeDsCompletionIndicator};
use base64::Engine;
use common_enums::enums;
use common_utils::{consts::BASE64_ENGINE, date_time, ext_traits::OptionExt as _};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    router_data::{ConnectorAuthType, ErrorResponse},
    router_flow_types::authentication::{Authentication, PreAuthentication},
    router_request_types::{
        authentication::{
            AuthNFlowType, ChallengeParams, ConnectorAuthenticationRequestData, MessageCategory,
            PreAuthNRequestData,
        },
        BrowserInformation,
    },
    router_response_types::AuthenticationResponseData,
};
use hyperswitch_interfaces::{api::CurrencyUnit, consts::NO_ERROR_MESSAGE, errors};
use iso_currency::Currency;
use masking::{ExposeInterface, Secret};
use serde::{Deserialize, Serialize};
use serde_json::{json, to_string};

use crate::{
    types::{ConnectorAuthenticationRouterData, PreAuthNRouterData, ResponseRouterData},
    utils::{get_card_details, to_connector_meta, AddressDetailsData, CardData as _},
};

pub struct ThreedsecureioRouterData<T> {
    pub amount: String,
    pub router_data: T,
}

impl<T> TryFrom<(&CurrencyUnit, enums::Currency, i64, T)> for ThreedsecureioRouterData<T> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        (_currency_unit, _currency, amount, item): (&CurrencyUnit, enums::Currency, i64, T),
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: amount.to_string(),
            router_data: item,
        })
    }
}

impl<T> TryFrom<(i64, T)> for ThreedsecureioRouterData<T> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from((amount, router_data): (i64, T)) -> Result<Self, Self::Error> {
        Ok(Self {
            amount: amount.to_string(),
            router_data,
        })
    }
}

impl
    TryFrom<
        ResponseRouterData<
            PreAuthentication,
            ThreedsecureioPreAuthenticationResponse,
            PreAuthNRequestData,
            AuthenticationResponseData,
        >,
    > for PreAuthNRouterData
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            PreAuthentication,
            ThreedsecureioPreAuthenticationResponse,
            PreAuthNRequestData,
            AuthenticationResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        let response = match item.response {
            ThreedsecureioPreAuthenticationResponse::Success(pre_authn_response) => {
                let three_ds_method_data = json!({
                    "threeDSServerTransID": pre_authn_response.threeds_server_trans_id,
                });
                let three_ds_method_data_str = to_string(&three_ds_method_data)
                    .change_context(errors::ConnectorError::ResponseDeserializationFailed)
                    .attach_printable("error while constructing three_ds_method_data_str")?;
                let three_ds_method_data_base64 = BASE64_ENGINE.encode(three_ds_method_data_str);
                let connector_metadata = serde_json::json!(ThreeDSecureIoConnectorMetaData {
                    ds_start_protocol_version: pre_authn_response.ds_start_protocol_version,
                    ds_end_protocol_version: pre_authn_response.ds_end_protocol_version,
                    acs_start_protocol_version: pre_authn_response.acs_start_protocol_version,
                    acs_end_protocol_version: pre_authn_response.acs_end_protocol_version.clone(),
                });
                Ok(AuthenticationResponseData::PreAuthNResponse {
                    threeds_server_transaction_id: pre_authn_response
                        .threeds_server_trans_id
                        .clone(),
                    maximum_supported_3ds_version: common_utils::types::SemanticVersion::from_str(
                        &pre_authn_response.acs_end_protocol_version,
                    )
                    .change_context(errors::ConnectorError::ParsingFailed)?,
                    connector_authentication_id: pre_authn_response.threeds_server_trans_id,
                    three_ds_method_data: Some(three_ds_method_data_base64),
                    three_ds_method_url: pre_authn_response.threeds_method_url,
                    message_version: common_utils::types::SemanticVersion::from_str(
                        &pre_authn_response.acs_end_protocol_version,
                    )
                    .change_context(errors::ConnectorError::ParsingFailed)?,
                    connector_metadata: Some(connector_metadata),
                    directory_server_id: None,
                })
            }
            ThreedsecureioPreAuthenticationResponse::Failure(error_response) => {
                Err(ErrorResponse {
                    code: error_response.error_code,
                    message: error_response
                        .error_description
                        .clone()
                        .unwrap_or(NO_ERROR_MESSAGE.to_owned()),
                    reason: error_response.error_description,
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                })
            }
        };
        Ok(Self {
            response,
            ..item.data.clone()
        })
    }
}

impl
    TryFrom<
        ResponseRouterData<
            Authentication,
            ThreedsecureioAuthenticationResponse,
            ConnectorAuthenticationRequestData,
            AuthenticationResponseData,
        >,
    > for ConnectorAuthenticationRouterData
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            Authentication,
            ThreedsecureioAuthenticationResponse,
            ConnectorAuthenticationRequestData,
            AuthenticationResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        let response = match item.response {
            ThreedsecureioAuthenticationResponse::Success(response) => {
                let creq = serde_json::json!({
                    "threeDSServerTransID": response.three_dsserver_trans_id,
                    "acsTransID": response.acs_trans_id,
                    "messageVersion": response.message_version,
                    "messageType": "CReq",
                    "challengeWindowSize": "01",
                });
                let creq_str = to_string(&creq)
                    .change_context(errors::ConnectorError::ResponseDeserializationFailed)
                    .attach_printable("error while constructing creq_str")?;
                let creq_base64 = Engine::encode(&BASE64_ENGINE, creq_str)
                    .trim_end_matches('=')
                    .to_owned();
                Ok(AuthenticationResponseData::AuthNResponse {
                    trans_status: response.trans_status.clone().into(),
                    authn_flow_type: if response.trans_status == ThreedsecureioTransStatus::C {
                        AuthNFlowType::Challenge(Box::new(ChallengeParams {
                            acs_url: response.acs_url,
                            challenge_request: Some(creq_base64),
                            acs_reference_number: Some(response.acs_reference_number.clone()),
                            acs_trans_id: Some(response.acs_trans_id.clone()),
                            three_dsserver_trans_id: Some(response.three_dsserver_trans_id),
                            acs_signed_content: response.acs_signed_content,
                        }))
                    } else {
                        AuthNFlowType::Frictionless
                    },
                    authentication_value: response.authentication_value,
                    connector_metadata: None,
                    ds_trans_id: Some(response.ds_trans_id),
                    eci: None,
                    challenge_code: None,
                    challenge_cancel: None,
                    challenge_code_reason: None,
                    message_extension: None,
                })
            }
            ThreedsecureioAuthenticationResponse::Error(err_response) => match *err_response {
                ThreedsecureioErrorResponseWrapper::ErrorResponse(resp) => Err(ErrorResponse {
                    code: resp.error_code,
                    message: resp
                        .error_description
                        .clone()
                        .unwrap_or(NO_ERROR_MESSAGE.to_owned()),
                    reason: resp.error_description,
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
                ThreedsecureioErrorResponseWrapper::ErrorString(error) => Err(ErrorResponse {
                    code: error.clone(),
                    message: error.clone(),
                    reason: Some(error),
                    status_code: item.http_code,
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
            },
        };
        Ok(Self {
            response,
            ..item.data.clone()
        })
    }
}

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

impl TryFrom<&ConnectorAuthType> for ThreedsecureioAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
                api_key: api_key.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

impl TryFrom<&ThreedsecureioRouterData<&ConnectorAuthenticationRouterData>>
    for ThreedsecureioAuthenticationRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: &ThreedsecureioRouterData<&ConnectorAuthenticationRouterData>,
    ) -> Result<Self, Self::Error> {
        let request = &item.router_data.request;
        //browser_details are mandatory for Browser flows
        let browser_details = match request.browser_details.clone() {
            Some(details) => Ok::<Option<BrowserInformation>, Self::Error>(Some(details)),
            None => {
                if request.device_channel == DeviceChannel::Browser {
                    Err(errors::ConnectorError::MissingRequiredField {
                        field_name: "browser_info",
                    })?
                } else {
                    Ok(None)
                }
            }
        }?;
        let card_details = get_card_details(request.payment_method_data.clone(), "threedsecureio")?;
        let currency = request
            .currency
            .map(|currency| currency.to_string())
            .ok_or(errors::ConnectorError::RequestEncodingFailed)
            .attach_printable("missing field currency")?;
        let purchase_currency: Currency = Currency::from_code(&currency)
            .ok_or(errors::ConnectorError::RequestEncodingFailed)
            .attach_printable("error while parsing Currency")?;
        let billing_address = request.billing_address.address.clone().ok_or(
            errors::ConnectorError::MissingRequiredField {
                field_name: "billing_address.address",
            },
        )?;
        let billing_state = billing_address.clone().to_state_code()?;
        let billing_country = isocountry::CountryCode::for_alpha2(
            &billing_address
                .country
                .ok_or(errors::ConnectorError::MissingRequiredField {
                    field_name: "billing_address.address.country",
                })?
                .to_string(),
        )
        .change_context(errors::ConnectorError::RequestEncodingFailed)
        .attach_printable("Error parsing billing_address.address.country")?;
        let connector_meta_data: ThreeDSecureIoMetaData = item
            .router_data
            .connector_meta_data
            .clone()
            .parse_value("ThreeDSecureIoMetaData")
            .change_context(errors::ConnectorError::RequestEncodingFailed)?;

        let pre_authentication_data = &request.pre_authentication_data;
        let sdk_information = match request.device_channel {
            DeviceChannel::App => Some(item.router_data.request.sdk_information.clone().ok_or(
                errors::ConnectorError::MissingRequiredField {
                    field_name: "sdk_information",
                },
            )?),
            DeviceChannel::Browser => None,
        };
        let (acquirer_bin, acquirer_merchant_id) = pre_authentication_data
            .acquirer_bin
            .clone()
            .zip(pre_authentication_data.acquirer_merchant_id.clone())
            .get_required_value("acquirer_details")
            .change_context(errors::ConnectorError::MissingRequiredField {
                field_name: "acquirer_details",
            })?;
        let meta: ThreeDSecureIoConnectorMetaData =
            to_connector_meta(request.pre_authentication_data.connector_metadata.clone())?;

        let card_holder_name = billing_address.get_optional_full_name();

        Ok(Self {
            ds_start_protocol_version: meta.ds_start_protocol_version.clone(),
            ds_end_protocol_version: meta.ds_end_protocol_version.clone(),
            acs_start_protocol_version: meta.acs_start_protocol_version.clone(),
            acs_end_protocol_version: meta.acs_end_protocol_version.clone(),
            three_dsserver_trans_id: pre_authentication_data
                .threeds_server_transaction_id
                .clone(),
            acct_number: card_details.card_number.clone(),
            notification_url: request
                .return_url
                .clone()
                .ok_or(errors::ConnectorError::RequestEncodingFailed)
                .attach_printable("missing return_url")?,
            three_dscomp_ind: ThreeDSecureIoThreeDsCompletionIndicator::from(
                request.threeds_method_comp_ind.clone(),
            ),
            three_dsrequestor_url: request.three_ds_requestor_url.clone(),
            acquirer_bin,
            acquirer_merchant_id,
            card_expiry_date: card_details.get_expiry_date_as_yymm()?.expose(),
            bill_addr_city: billing_address
                .city
                .clone()
                .ok_or(errors::ConnectorError::MissingRequiredField {
                    field_name: "billing_address.address.city",
                })?
                .to_string(),
            bill_addr_country: billing_country.numeric_id().to_string().into(),
            bill_addr_line1: billing_address.line1.clone().ok_or(
                errors::ConnectorError::MissingRequiredField {
                    field_name: "billing_address.address.line1",
                },
            )?,
            bill_addr_post_code: billing_address.zip.clone().ok_or(
                errors::ConnectorError::MissingRequiredField {
                    field_name: "billing_address.address.zip",
                },
            )?,
            bill_addr_state: billing_state,
            // Indicates the type of Authentication request, "01" for Payment transaction
            three_dsrequestor_authentication_ind: "01".to_string(),
            device_channel: match item.router_data.request.device_channel.clone() {
                DeviceChannel::App => "01",
                DeviceChannel::Browser => "02",
            }
            .to_string(),
            message_category: match item.router_data.request.message_category.clone() {
                MessageCategory::Payment => "01",
                MessageCategory::NonPayment => "02",
            }
            .to_string(),
            browser_javascript_enabled: browser_details
                .as_ref()
                .and_then(|details| details.java_script_enabled),
            browser_accept_header: browser_details
                .as_ref()
                .and_then(|details| details.accept_header.clone()),
            browser_ip: browser_details
                .clone()
                .and_then(|details| details.ip_address.map(|ip| Secret::new(ip.to_string()))),
            browser_java_enabled: browser_details
                .as_ref()
                .and_then(|details| details.java_enabled),
            browser_language: browser_details
                .as_ref()
                .and_then(|details| details.language.clone()),
            browser_color_depth: browser_details
                .as_ref()
                .and_then(|details| details.color_depth.map(|a| a.to_string())),
            browser_screen_height: browser_details
                .as_ref()
                .and_then(|details| details.screen_height.map(|a| a.to_string())),
            browser_screen_width: browser_details
                .as_ref()
                .and_then(|details| details.screen_width.map(|a| a.to_string())),
            browser_tz: browser_details
                .as_ref()
                .and_then(|details| details.time_zone.map(|a| a.to_string())),
            browser_user_agent: browser_details
                .as_ref()
                .and_then(|details| details.user_agent.clone().map(|a| a.to_string())),
            mcc: connector_meta_data.mcc,
            merchant_country_code: connector_meta_data.merchant_country_code,
            merchant_name: connector_meta_data.merchant_name,
            message_type: "AReq".to_string(),
            message_version: pre_authentication_data.message_version.to_string(),
            purchase_amount: item.amount.clone(),
            purchase_currency: purchase_currency.numeric().to_string(),
            trans_type: "01".to_string(),
            purchase_exponent: purchase_currency
                .exponent()
                .ok_or(errors::ConnectorError::RequestEncodingFailed)
                .attach_printable("missing purchase_exponent")?
                .to_string(),
            purchase_date: date_time::DateTime::<date_time::YYYYMMDDHHmmss>::from(date_time::now())
                .to_string(),
            sdk_app_id: sdk_information
                .as_ref()
                .map(|sdk_info| sdk_info.sdk_app_id.clone()),
            sdk_enc_data: sdk_information
                .as_ref()
                .map(|sdk_info| sdk_info.sdk_enc_data.clone()),
            sdk_ephem_pub_key: sdk_information
                .as_ref()
                .map(|sdk_info| sdk_info.sdk_ephem_pub_key.clone()),
            sdk_reference_number: sdk_information
                .as_ref()
                .map(|sdk_info| sdk_info.sdk_reference_number.clone()),
            sdk_trans_id: sdk_information
                .as_ref()
                .map(|sdk_info| sdk_info.sdk_trans_id.clone()),
            sdk_max_timeout: sdk_information
                .as_ref()
                .map(|sdk_info| sdk_info.sdk_max_timeout.to_string()),
            device_render_options: match request.device_channel {
                DeviceChannel::App => Some(DeviceRenderOptions {
                    // SDK Interface types that the device supports for displaying specific challenge user interfaces within the SDK, 01 for Native
                    sdk_interface: "01".to_string(),
                    // UI types that the device supports for displaying specific challenge user interfaces within the SDK, 01 for Text
                    sdk_ui_type: vec!["01".to_string()],
                }),
                DeviceChannel::Browser => None,
            },
            cardholder_name: card_holder_name,
            email: request.email.clone(),
        })
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ThreedsecureioErrorResponse {
    pub error_code: String,
    pub error_component: Option<String>,
    pub error_description: Option<String>,
    pub error_detail: Option<String>,
    pub error_message_type: Option<String>,
    pub message_type: Option<String>,
    pub message_version: Option<String>,
    pub three_dsserver_trans_id: Option<String>,
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum ThreedsecureioErrorResponseWrapper {
    ErrorResponse(ThreedsecureioErrorResponse),
    ErrorString(String),
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ThreedsecureioAuthenticationResponse {
    Success(Box<ThreedsecureioAuthenticationSuccessResponse>),
    Error(Box<ThreedsecureioErrorResponseWrapper>),
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ThreedsecureioAuthenticationSuccessResponse {
    #[serde(rename = "acsChallengeMandated")]
    pub acs_challenge_mandated: Option<String>,
    #[serde(rename = "acsOperatorID")]
    pub acs_operator_id: Option<String>,
    #[serde(rename = "acsReferenceNumber")]
    pub acs_reference_number: String,
    #[serde(rename = "acsTransID")]
    pub acs_trans_id: String,
    #[serde(rename = "acsURL")]
    pub acs_url: Option<url::Url>,
    #[serde(rename = "authenticationType")]
    pub authentication_type: Option<String>,
    #[serde(rename = "dsReferenceNumber")]
    pub ds_reference_number: String,
    #[serde(rename = "dsTransID")]
    pub ds_trans_id: String,
    #[serde(rename = "messageType")]
    pub message_type: Option<String>,
    #[serde(rename = "messageVersion")]
    pub message_version: String,
    #[serde(rename = "threeDSServerTransID")]
    pub three_dsserver_trans_id: String,
    #[serde(rename = "transStatus")]
    pub trans_status: ThreedsecureioTransStatus,
    #[serde(rename = "acsSignedContent")]
    pub acs_signed_content: Option<String>,
    #[serde(rename = "authenticationValue")]
    pub authentication_value: Option<Secret<String>>,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum ThreeDSecureIoThreeDsCompletionIndicator {
    Y,
    N,
    U,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ThreedsecureioAuthenticationRequest {
    pub ds_start_protocol_version: String,
    pub ds_end_protocol_version: String,
    pub acs_start_protocol_version: String,
    pub acs_end_protocol_version: String,
    pub three_dsserver_trans_id: String,
    pub acct_number: cards::CardNumber,
    pub notification_url: String,
    pub three_dscomp_ind: ThreeDSecureIoThreeDsCompletionIndicator,
    pub three_dsrequestor_url: String,
    pub acquirer_bin: String,
    pub acquirer_merchant_id: String,
    pub card_expiry_date: String,
    pub bill_addr_city: String,
    pub bill_addr_country: Secret<String>,
    pub bill_addr_line1: Secret<String>,
    pub bill_addr_post_code: Secret<String>,
    pub bill_addr_state: Secret<String>,
    pub email: Option<common_utils::pii::Email>,
    pub three_dsrequestor_authentication_ind: String,
    pub cardholder_name: Option<Secret<String>>,
    pub device_channel: String,
    pub browser_javascript_enabled: Option<bool>,
    pub browser_accept_header: Option<String>,
    pub browser_ip: Option<Secret<String, common_utils::pii::IpAddress>>,
    pub browser_java_enabled: Option<bool>,
    pub browser_language: Option<String>,
    pub browser_color_depth: Option<String>,
    pub browser_screen_height: Option<String>,
    pub browser_screen_width: Option<String>,
    pub browser_tz: Option<String>,
    pub browser_user_agent: Option<String>,
    pub sdk_app_id: Option<String>,
    pub sdk_enc_data: Option<String>,
    pub sdk_ephem_pub_key: Option<std::collections::HashMap<String, String>>,
    pub sdk_reference_number: Option<String>,
    pub sdk_trans_id: Option<String>,
    pub mcc: String,
    pub merchant_country_code: String,
    pub merchant_name: String,
    pub message_category: String,
    pub message_type: String,
    pub message_version: String,
    pub purchase_amount: String,
    pub purchase_currency: String,
    pub purchase_exponent: String,
    pub purchase_date: String,
    pub trans_type: String,
    pub sdk_max_timeout: Option<String>,
    pub device_render_options: Option<DeviceRenderOptions>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ThreeDSecureIoMetaData {
    pub mcc: String,
    pub merchant_country_code: String,
    pub merchant_name: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ThreeDSecureIoConnectorMetaData {
    pub ds_start_protocol_version: String,
    pub ds_end_protocol_version: String,
    pub acs_start_protocol_version: String,
    pub acs_end_protocol_version: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DeviceRenderOptions {
    pub sdk_interface: String,
    pub sdk_ui_type: Vec<String>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ThreedsecureioPreAuthenticationRequest {
    acct_number: cards::CardNumber,
    ds: Option<DirectoryServer>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ThreedsecureioPostAuthenticationRequest {
    pub three_ds_server_trans_id: String,
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ThreedsecureioPostAuthenticationResponse {
    pub authentication_value: Option<Secret<String>>,
    pub trans_status: ThreedsecureioTransStatus,
    pub eci: Option<String>,
}

#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
pub enum ThreedsecureioTransStatus {
    /// Authentication/ Account Verification Successful
    Y,
    /// Not Authenticated /Account Not Verified; Transaction denied
    N,
    /// Authentication/ Account Verification Could Not Be Performed; Technical or other problem, as indicated in ARes or RReq
    U,
    /// Attempts Processing Performed; Not Authenticated/Verified , but a proof of attempted authentication/verification is provided
    A,
    /// Authentication/ Account Verification Rejected; Issuer is rejecting authentication/verification and request that authorisation not be attempted.
    R,
    C,
}

impl From<ThreeDsCompletionIndicator> for ThreeDSecureIoThreeDsCompletionIndicator {
    fn from(value: ThreeDsCompletionIndicator) -> Self {
        match value {
            ThreeDsCompletionIndicator::Success => Self::Y,
            ThreeDsCompletionIndicator::Failure => Self::N,
            ThreeDsCompletionIndicator::NotAvailable => Self::U,
        }
    }
}

impl From<ThreedsecureioTransStatus> for common_enums::TransactionStatus {
    fn from(value: ThreedsecureioTransStatus) -> Self {
        match value {
            ThreedsecureioTransStatus::Y => Self::Success,
            ThreedsecureioTransStatus::N => Self::Failure,
            ThreedsecureioTransStatus::U => Self::VerificationNotPerformed,
            ThreedsecureioTransStatus::A => Self::NotVerified,
            ThreedsecureioTransStatus::R => Self::Rejected,
            ThreedsecureioTransStatus::C => Self::ChallengeRequired,
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum DirectoryServer {
    Standin,
    Visa,
    Mastercard,
    Jcb,
    Upi,
    Amex,
    Protectbuy,
    Sbn,
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum ThreedsecureioPreAuthenticationResponse {
    Success(Box<ThreedsecureioPreAuthenticationResponseData>),
    Failure(Box<ThreedsecureioErrorResponse>),
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ThreedsecureioPreAuthenticationResponseData {
    pub ds_start_protocol_version: String,
    pub ds_end_protocol_version: String,
    pub acs_start_protocol_version: String,
    pub acs_end_protocol_version: String,
    #[serde(rename = "threeDSMethodURL")]
    pub threeds_method_url: Option<String>,
    #[serde(rename = "threeDSServerTransID")]
    pub threeds_server_trans_id: String,
    pub scheme: Option<String>,
    pub message_type: Option<String>,
}

impl TryFrom<&ThreedsecureioRouterData<&PreAuthNRouterData>>
    for ThreedsecureioPreAuthenticationRequest
{
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        value: &ThreedsecureioRouterData<&PreAuthNRouterData>,
    ) -> Result<Self, Self::Error> {
        let router_data = value.router_data;
        Ok(Self {
            acct_number: router_data.request.card.card_number.clone(),
            ds: None,
        })
    }
}


pub fn get_group_authorization_info() -> Option<Vec<GroupInfo>> {
    let groups = PermissionGroup::iter()
        .filter_map(get_group_info_from_permission_group)
        .collect::<Vec<_>>();

    groups.is_empty().not().then_some(groups)
}


impl Parse for ResourceInput {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let resource_name: Ident = input.parse()?;
        input.parse::<Token![:]>()?; // Expect ':'

        let content;
        braced!(content in input);

        let (_scopes_label, scopes) = parse_label_with_punctuated_data(&content)?;
        content.parse::<Comma>()?;

        let (_entities_label, entities) = parse_label_with_punctuated_data(&content)?;

        Ok(Self {
            resource_name,
            scopes,
            entities,
        })
    }
}


impl webhooks::IncomingWebhook for Jpmorgan {
    fn get_webhook_object_reference_id(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_event_type(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_resource_object(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }
}

impl webhooks::IncomingWebhook for for Jpmorgan


pub fn payments_get_intent() {}


pub struct ThreedsInfo {
    cardholder: CardHolder,
}


pub struct RecurringMandatePaymentData {
    pub payment_method_type: Option<common_enums::enums::PaymentMethodType>, //required for making recurring payment using saved payment method through stripe
    pub original_payment_authorized_amount: Option<i64>,
    pub original_payment_authorized_currency: Option<common_enums::enums::Currency>,
    pub mandate_metadata: Option<common_utils::pii::SecretSerdeValue>,
}


impl Relay {
    pub fn server(state: AppState) -> Scope {
        web::scope("/relay")
            .app_data(web::Data::new(state))
            .service(web::resource("").route(web::post().to(relay::relay)))
            .service(web::resource("/{relay_id}").route(web::get().to(relay::relay_retrieve)))
    }
}


pub struct GooglePayPaymentMethodDetails {
    pub auth_method: common_enums::enums::GooglePayAuthMethod,
    pub expiration_month: cards::CardExpirationMonth,
    pub expiration_year: cards::CardExpirationYear,
    pub pan: cards::CardNumber,
    pub cryptogram: Option<Secret<String>>,
    pub eci_indicator: Option<String>,
    pub card_network: Option<String>,
}


pub struct Edge {
    pub strength: Strength,
    pub relation: Relation,
    pub pred: NodeId,
    pub succ: NodeId,
    pub domain: Option<DomainId>,
}