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

use std::collections::HashSet;

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

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

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

#[async_trait::async_trait]
impl<T> super::PaymentIntentMetric<T> for PaymentProcessedAmount
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);

        let mut dimensions = dimensions.to_vec();

        dimensions.push(PaymentIntentDimensions::PaymentIntentStatus);

        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("(attempt_count = 1) as first_attempt")
            .switch()?;
        query_builder.add_select_column("currency").switch()?;
        query_builder
            .add_select_column(Aggregate::Sum {
                field: "amount",
                alias: Some("total"),
            })
            .switch()?;
        query_builder
            .add_select_column(Aggregate::Min {
                field: "created_at",
                alias: Some("start_bucket"),
            })
            .switch()?;
        query_builder
            .add_select_column(Aggregate::Max {
                field: "created_at",
                alias: Some("end_bucket"),
            })
            .switch()?;

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

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

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

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

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

        query_builder
            .add_filter_clause(
                PaymentIntentDimensions::PaymentIntentStatus,
                storage_enums::IntentStatus::Succeeded,
            )
            .switch()?;

        query_builder
            .execute_query::<PaymentIntentMetricRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| {
                Ok((
                    PaymentIntentMetricsBucketIdentifier::new(
                        None,
                        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)
    }
}


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

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

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

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

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

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response_error_message = if res.response.is_empty() && res.status_code == 401 {
            ErrorResponse {
                status_code: res.status_code,
                code: NO_ERROR_CODE.to_string(),
                message: NO_ERROR_MESSAGE.to_string(),
                reason: Some(CONNECTOR_UNAUTHORIZED_ERROR.to_string()),
                attempt_status: None,
                connector_transaction_id: None,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            }
        } else {
            let response: iatapay::IatapayErrorResponse = res
                .response
                .parse_struct("IatapayErrorResponse")
                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

            event_builder.map(|i| i.set_error_response_body(&response));
            router_env::logger::info!(connector_response=?response);
            ErrorResponse {
                status_code: res.status_code,
                code: response.error,
                message: response.message.unwrap_or(NO_ERROR_MESSAGE.to_string()),
                reason: response.reason,
                attempt_status: None,
                connector_transaction_id: None,
                network_advice_code: None,
                network_decline_code: None,
                network_error_message: None,
                connector_metadata: None,
            }
        };
        Ok(response_error_message)
    }
}


pub fn export_collection(connector_name: &str, collection_dir_path: String) {
    let collection_path = get_collection_path(connector_name);

    let mut newman_command = Command::new("newman");
    newman_command.args([
        "dir-import".to_owned(),
        collection_dir_path,
        "-o".to_owned(),
        collection_path.clone(),
    ]);

    match newman_command.spawn().and_then(|mut child| child.wait()) {
        Ok(exit_status) => {
            if exit_status.success() {
                println!("Conversion of collection from directory structure to json successful!");
            } else {
                eprintln!("Conversion of collection from directory structure to json failed!");
                exit(exit_status.code().unwrap_or(1));
            }
        }
        Err(err) => {
            eprintln!("Failed to execute dir-import: {err:?}");
            exit(1);
        }
    }
}


impl FraudCheck for Riskified {}


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


pub async fn insert_cvc_using_payment_token(
    state: &routes::SessionState,
    payment_token: &String,
    payment_method_data: api_models::payment_methods::PaymentMethodCreateData,
    payment_method: common_enums::PaymentMethod,
    fulfillment_time: i64,
    encryption_key: &masking::Secret<Vec<u8>>,
) -> RouterResult<()> {
    let card_cvc = domain::PaymentMethodVaultingData::try_from(payment_method_data)?
        .get_card()
        .and_then(|card| card.card_cvc.clone());

    if let Some(card_cvc) = card_cvc {
        let redis_conn = state
            .store
            .get_redis_conn()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to get redis connection")?;

        let key = format!("pm_token_{payment_token}_{payment_method}_hyperswitch_cvc");

        let payload_to_be_encrypted = TemporaryVaultCvc { card_cvc };

        let payload = payload_to_be_encrypted
            .encode_to_string_of_json()
            .change_context(errors::ApiErrorResponse::InternalServerError)?;

        // Encrypt the CVC and store it in Redis
        let encrypted_payload = GcmAes256
            .encode_message(encryption_key.peek().as_ref(), payload.as_bytes())
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to encode TemporaryVaultCvc for vault")?;

        redis_conn
            .set_key_if_not_exists_with_expiry(
                &key.as_str().into(),
                bytes::Bytes::from(encrypted_payload),
                Some(fulfillment_time),
            )
            .await
            .change_context(errors::StorageError::KVError)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to add token in redis")?;
    };

    Ok(())
}


pub async fn retrieve_conditional_config(
    state: SessionState,
    key_store: domain::MerchantKeyStore,
    profile: domain::Profile,
) -> RouterResponse<common_types::payments::DecisionManagerResponse> {
    let db = state.store.as_ref();
    let key_manager_state: &KeyManagerState = &(&state).into();
    let profile_id = profile.get_id();

    let record = profile
        .three_ds_decision_manager_config
        .clone()
        .ok_or(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("The Conditional Config Record was not found")?;

    let response = common_types::payments::DecisionManagerRecord {
        name: record.name,
        program: record.program,
        created_at: record.created_at,
    };
    Ok(service_api::ApplicationResponse::Json(response))
}


File: crates/router/src/routes/payout_link.rs
 Public functions: 1

use actix_web::{web, Responder};
use api_models::payouts::PayoutLinkInitiateRequest;
use router_env::Flow;

use crate::{
    core::{api_locking, payout_link::*},
    services::{
        api,
        authentication::{self as auth},
    },
    types::domain,
    AppState,
};
#[cfg(feature = "v1")]
pub async fn render_payout_link(
    state: web::Data<AppState>,
    req: actix_web::HttpRequest,
    path: web::Path<(
        common_utils::id_type::MerchantId,
        common_utils::id_type::PayoutId,
    )>,
) -> impl Responder {
    let flow = Flow::PayoutLinkInitiate;
    let (merchant_id, payout_id) = path.into_inner();
    let payload = PayoutLinkInitiateRequest {
        merchant_id: merchant_id.clone(),
        payout_id,
    };
    let headers = req.headers();
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload.clone(),
        |state, auth, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            initiate_payout_link(state, merchant_context, req, headers)
        },
        &auth::MerchantIdAuth(merchant_id),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


File: crates/analytics/src/frm/metrics.rs
 Public structs: 1

use api_models::analytics::{
    frm::{FrmDimensions, FrmFilters, FrmMetrics, FrmMetricsBucketIdentifier, FrmTransactionType},
    Granularity, TimeRange,
};
use diesel_models::enums as storage_enums;
use time::PrimitiveDateTime;
mod frm_blocked_rate;
mod frm_triggered_attempts;

use frm_blocked_rate::FrmBlockedRate;
use frm_triggered_attempts::FrmTriggeredAttempts;

use crate::{
    query::{Aggregate, GroupByClause, ToSql, Window},
    types::{AnalyticsCollection, AnalyticsDataSource, DBEnumWrapper, LoadRow, MetricsResult},
};
#[derive(Debug, Eq, PartialEq, serde::Deserialize)]
pub struct FrmMetricRow {
    pub frm_name: Option<String>,
    pub frm_status: Option<DBEnumWrapper<storage_enums::FraudCheckStatus>>,
    pub frm_transaction_type: Option<DBEnumWrapper<FrmTransactionType>>,
    pub total: Option<bigdecimal::BigDecimal>,
    pub count: Option<i64>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub start_bucket: Option<PrimitiveDateTime>,
    #[serde(with = "common_utils::custom_serde::iso8601::option")]
    pub end_bucket: Option<PrimitiveDateTime>,
}

pub trait FrmMetricAnalytics: LoadRow<FrmMetricRow> {}

#[async_trait::async_trait]
pub trait FrmMetric<T>
where
    T: AnalyticsDataSource + FrmMetricAnalytics,
    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: &[FrmDimensions],
        merchant_id: &common_utils::id_type::MerchantId,
        filters: &FrmFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<Vec<(FrmMetricsBucketIdentifier, FrmMetricRow)>>;
}

#[async_trait::async_trait]
impl<T> FrmMetric<T> for FrmMetrics
where
    T: AnalyticsDataSource + FrmMetricAnalytics,
    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: &[FrmDimensions],
        merchant_id: &common_utils::id_type::MerchantId,
        filters: &FrmFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<Vec<(FrmMetricsBucketIdentifier, FrmMetricRow)>> {
        match self {
            Self::FrmTriggeredAttempts => {
                FrmTriggeredAttempts::default()
                    .load_metrics(
                        dimensions,
                        merchant_id,
                        filters,
                        granularity,
                        time_range,
                        pool,
                    )
                    .await
            }
            Self::FrmBlockedRate => {
                FrmBlockedRate::default()
                    .load_metrics(
                        dimensions,
                        merchant_id,
                        filters,
                        granularity,
                        time_range,
                        pool,
                    )
                    .await
            }
        }
    }
}


pub fn get_nmi_webhook_event(status: NmiWebhookEventType) -> IncomingWebhookEvent {
    match status {
        NmiWebhookEventType::SaleSuccess => IncomingWebhookEvent::PaymentIntentSuccess,
        NmiWebhookEventType::SaleFailure => IncomingWebhookEvent::PaymentIntentFailure,
        NmiWebhookEventType::RefundSuccess => IncomingWebhookEvent::RefundSuccess,
        NmiWebhookEventType::RefundFailure => IncomingWebhookEvent::RefundFailure,
        NmiWebhookEventType::VoidSuccess => IncomingWebhookEvent::PaymentIntentCancelled,
        NmiWebhookEventType::AuthSuccess => IncomingWebhookEvent::PaymentIntentAuthorizationSuccess,
        NmiWebhookEventType::CaptureSuccess => IncomingWebhookEvent::PaymentIntentCaptureSuccess,
        NmiWebhookEventType::AuthFailure => IncomingWebhookEvent::PaymentIntentAuthorizationFailure,
        NmiWebhookEventType::CaptureFailure => IncomingWebhookEvent::PaymentIntentCaptureFailure,
        NmiWebhookEventType::VoidFailure => IncomingWebhookEvent::PaymentIntentCancelFailure,
        NmiWebhookEventType::SaleUnknown
        | NmiWebhookEventType::RefundUnknown
        | NmiWebhookEventType::AuthUnknown
        | NmiWebhookEventType::VoidUnknown
        | NmiWebhookEventType::CaptureUnknown => IncomingWebhookEvent::EventNotSupported,
    }
}


pub struct Mobile {
    device_model: Option<String>,
    os_type: Option<String>,
    os_version: Option<String>,
}


impl ProfileInterface for KafkaStore {
    async fn insert_business_profile(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        business_profile: domain::Profile,
    ) -> CustomResult<domain::Profile, errors::StorageError> {
        self.diesel_store
            .insert_business_profile(key_manager_state, merchant_key_store, business_profile)
            .await
    }

    async fn find_business_profile_by_profile_id(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        profile_id: &id_type::ProfileId,
    ) -> CustomResult<domain::Profile, errors::StorageError> {
        self.diesel_store
            .find_business_profile_by_profile_id(key_manager_state, merchant_key_store, profile_id)
            .await
    }

    async fn find_business_profile_by_merchant_id_profile_id(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        merchant_id: &id_type::MerchantId,
        profile_id: &id_type::ProfileId,
    ) -> CustomResult<domain::Profile, errors::StorageError> {
        self.diesel_store
            .find_business_profile_by_merchant_id_profile_id(
                key_manager_state,
                merchant_key_store,
                merchant_id,
                profile_id,
            )
            .await
    }

    async fn update_profile_by_profile_id(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        current_state: domain::Profile,
        business_profile_update: domain::ProfileUpdate,
    ) -> CustomResult<domain::Profile, errors::StorageError> {
        self.diesel_store
            .update_profile_by_profile_id(
                key_manager_state,
                merchant_key_store,
                current_state,
                business_profile_update,
            )
            .await
    }

    async fn delete_profile_by_profile_id_merchant_id(
        &self,
        profile_id: &id_type::ProfileId,
        merchant_id: &id_type::MerchantId,
    ) -> CustomResult<bool, errors::StorageError> {
        self.diesel_store
            .delete_profile_by_profile_id_merchant_id(profile_id, merchant_id)
            .await
    }

    async fn list_profile_by_merchant_id(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        merchant_id: &id_type::MerchantId,
    ) -> CustomResult<Vec<domain::Profile>, errors::StorageError> {
        self.diesel_store
            .list_profile_by_merchant_id(key_manager_state, merchant_key_store, merchant_id)
            .await
    }

    async fn find_business_profile_by_profile_name_merchant_id(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        profile_name: &str,
        merchant_id: &id_type::MerchantId,
    ) -> CustomResult<domain::Profile, errors::StorageError> {
        self.diesel_store
            .find_business_profile_by_profile_name_merchant_id(
                key_manager_state,
                merchant_key_store,
                profile_name,
                merchant_id,
            )
            .await
    }
}

impl ProfileInterface for for KafkaStore


impl api::PaymentSync for Airwallex {}


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


OpenAPI Block Path: components.schemas.MandateData
{
  "type": "object",
  "description": "Passing this object during payments creates a mandate. The mandate_type sub object is passed by the server.",
  "properties": {
    "update_mandate_id": {
      "type": "string",
      "description": "A way to update the mandate's payment method details",
      "nullable": true
    },
    "customer_acceptance": {
      "allOf": [
        {
          "$ref": "#/components/schemas/CustomerAcceptance"
        }
      ],
      "nullable": true
    },
    "mandate_type": {
      "allOf": [
        {
          "$ref": "#/components/schemas/MandateType"
        }
      ],
      "nullable": true
    }
  },
  "additionalProperties": false
}


pub struct RSyncTransactionResponse {
    #[serde(rename = "transId")]
    transaction_id: String,
    transaction_status: RSyncStatus,
}


pub async fn construct_payment_router_data_for_update_metadata<'a>(
    state: &'a SessionState,
    payment_data: PaymentData<api::UpdateMetadata>,
    connector_id: &str,
    merchant_context: &domain::MerchantContext,
    customer: &'a Option<domain::Customer>,
    merchant_connector_account: &helpers::MerchantConnectorAccountType,
    merchant_recipient_data: Option<types::MerchantRecipientData>,
    header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
) -> RouterResult<
    types::RouterData<
        api::UpdateMetadata,
        types::PaymentsUpdateMetadataData,
        types::PaymentsResponseData,
    >,
> {
    let (payment_method, router_data);

    fp_utils::when(merchant_connector_account.is_disabled(), || {
        Err(errors::ApiErrorResponse::MerchantConnectorAccountDisabled)
    })?;

    let test_mode = merchant_connector_account.is_test_mode_on();

    let auth_type: types::ConnectorAuthType = merchant_connector_account
        .get_connector_account_details()
        .parse_value("ConnectorAuthType")
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed while parsing value for ConnectorAuthType")?;

    payment_method = payment_data
        .payment_attempt
        .payment_method
        .or(payment_data.payment_attempt.payment_method)
        .get_required_value("payment_method_type")?;

    // [#44]: why should response be filled during request
    let response = Err(hyperswitch_domain_models::router_data::ErrorResponse {
        code: "IR_20".to_string(),
        message: "Update metadata is not implemented for this connector".to_string(),
        reason: None,
        status_code: http::StatusCode::BAD_REQUEST.as_u16(),
        attempt_status: None,
        connector_transaction_id: None,
        network_decline_code: None,
        network_advice_code: None,
        network_error_message: None,
        connector_metadata: None,
    });

    let additional_data = PaymentAdditionalData {
        router_base_url: state.base_url.clone(),
        connector_name: connector_id.to_string(),
        payment_data: payment_data.clone(),
        state,
        customer_data: customer,
    };

    let customer_id = customer.to_owned().map(|customer| customer.customer_id);

    let supported_connector = &state
        .conf
        .multiple_api_version_supported_connectors
        .supported_connectors;
    let connector_enum = api_models::enums::Connector::from_str(connector_id)
        .change_context(errors::ConnectorError::InvalidConnectorName)
        .change_context(errors::ApiErrorResponse::InvalidDataValue {
            field_name: "connector",
        })
        .attach_printable_lazy(|| format!("unable to parse connector name {connector_id:?}"))?;

    let connector_api_version = if supported_connector.contains(&connector_enum) {
        state
            .store
            .find_config_by_key(&format!("connector_api_version_{connector_id}"))
            .await
            .map(|value| value.config)
            .ok()
    } else {
        None
    };

    let apple_pay_flow = payments::decide_apple_pay_flow(
        state,
        payment_data.payment_attempt.payment_method_type,
        Some(merchant_connector_account),
    );

    let unified_address = if let Some(payment_method_info) =
        payment_data.payment_method_info.clone()
    {
        let payment_method_billing = payment_method_info
            .payment_method_billing_address
            .map(|decrypted_data| decrypted_data.into_inner().expose())
            .map(|decrypted_value| decrypted_value.parse_value("payment_method_billing_address"))
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("unable to parse payment_method_billing_address")?;
        payment_data
            .address
            .clone()
            .unify_with_payment_data_billing(payment_method_billing)
    } else {
        payment_data.address
    };
    let connector_mandate_request_reference_id = payment_data
        .payment_attempt
        .connector_mandate_detail
        .as_ref()
        .and_then(|detail| detail.get_connector_mandate_request_reference_id());

    crate::logger::debug!("unified address details {:?}", unified_address);

    router_data = types::RouterData {
        flow: PhantomData,
        merchant_id: merchant_context.get_merchant_account().get_id().clone(),
        customer_id,
        tenant_id: state.tenant.tenant_id.clone(),
        connector: connector_id.to_owned(),
        payment_id: payment_data
            .payment_attempt
            .payment_id
            .get_string_repr()
            .to_owned(),
        attempt_id: payment_data.payment_attempt.attempt_id.clone(),
        status: payment_data.payment_attempt.status,
        payment_method,
        connector_auth_type: auth_type,
        description: payment_data.payment_intent.description.clone(),
        address: unified_address,
        auth_type: payment_data
            .payment_attempt
            .authentication_type
            .unwrap_or_default(),
        connector_meta_data: merchant_connector_account.get_metadata(),
        connector_wallets_details: merchant_connector_account.get_connector_wallets_details(),
        request: types::PaymentsUpdateMetadataData::try_from(additional_data)?,
        response,
        amount_captured: payment_data
            .payment_intent
            .amount_captured
            .map(|amt| amt.get_amount_as_i64()),
        minor_amount_captured: payment_data.payment_intent.amount_captured,
        access_token: None,
        session_token: None,
        reference_id: None,
        payment_method_status: payment_data.payment_method_info.map(|info| info.status),
        payment_method_token: payment_data
            .pm_token
            .map(|token| types::PaymentMethodToken::Token(Secret::new(token))),
        connector_customer: payment_data.connector_customer_id,
        recurring_mandate_payment_data: payment_data.recurring_mandate_payment_data,
        connector_request_reference_id: core_utils::get_connector_request_reference_id(
            &state.conf,
            merchant_context.get_merchant_account().get_id(),
            &payment_data.payment_intent,
            &payment_data.payment_attempt,
            connector_id,
        )?,
        preprocessing_id: payment_data.payment_attempt.preprocessing_step_id,
        #[cfg(feature = "payouts")]
        payout_method_data: None,
        #[cfg(feature = "payouts")]
        quote_id: None,
        test_mode,
        payment_method_balance: None,
        connector_api_version,
        connector_http_status_code: None,
        external_latency: None,
        apple_pay_flow,
        frm_metadata: None,
        refund_id: None,
        dispute_id: None,
        connector_response: None,
        integrity_check: Ok(()),
        additional_merchant_data: merchant_recipient_data.map(|data| {
            api_models::admin::AdditionalMerchantData::foreign_from(
                types::AdditionalMerchantData::OpenBankingRecipientData(data),
            )
        }),
        header_payload,
        connector_mandate_request_reference_id,
        authentication_id: None,
        psd2_sca_exemption_type: payment_data.payment_intent.psd2_sca_exemption_type,
        raw_connector_response: None,
        is_payment_id_from_merchant: payment_data.payment_intent.is_payment_id_from_merchant,
        l2_l3_data: None,
        minor_amount_capturable: None,
    };

    Ok(router_data)
}


impl Responder {
    let flow = Flow::PaymentsList;
    let payload = payload.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payments::get_filters_for_payments(state, merchant_context, req)
        },
        &auth::JWTAuth {
            permission: Permission::MerchantPaymentRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl api::Payment for CtpMastercard {}


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

---
openapi: post /organization
---


pub struct VoltPaymentsRequest {
    amount: MinorUnit,
    currency_code: enums::Currency,
    #[serde(rename = "type")]
    transaction_type: TransactionType,
    merchant_internal_reference: String,
    shopper: ShopperDetails,
    payment_success_url: Option<String>,
    payment_failure_url: Option<String>,
    payment_pending_url: Option<String>,
    payment_cancel_url: Option<String>,
}


impl PaymentToken for Signifyd {}


pub async fn payments_operation_core<F, Req, Op, FData, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: &domain::MerchantContext,
    profile_id_from_auth_layer: Option<id_type::ProfileId>,
    operation: Op,
    req: Req,
    call_connector_action: CallConnectorAction,
    auth_flow: services::AuthFlow,
    eligible_connectors: Option<Vec<common_enums::RoutableConnectors>>,
    header_payload: HeaderPayload,
) -> RouterResult<(D, Req, Option<domain::Customer>, Option<u16>, Option<u128>)>
where
    F: Send + Clone + Sync,
    Req: Authenticate + Clone,
    Op: Operation<F, Req, Data = D> + Send + Sync,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,

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

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

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

    tracing::Span::current().record(
        "merchant_id",
        merchant_context
            .get_merchant_account()
            .get_id()
            .get_string_repr(),
    );
    let (operation, validate_result) = operation
        .to_validate_request()?
        .validate_request(&req, merchant_context)?;

    tracing::Span::current().record("payment_id", format!("{}", validate_result.payment_id));
    // get profile from headers
    let operations::GetTrackerResponse {
        operation,
        customer_details,
        mut payment_data,
        business_profile,
        mandate_type,
    } = operation
        .to_get_tracker()?
        .get_trackers(
            state,
            &validate_result.payment_id,
            &req,
            merchant_context,
            auth_flow,
            &header_payload,
        )
        .await?;

    operation
        .to_get_tracker()?
        .validate_request_with_state(state, &req, &mut payment_data, &business_profile)
        .await?;

    core_utils::validate_profile_id_from_auth_layer(
        profile_id_from_auth_layer,
        &payment_data.get_payment_intent().clone(),
    )?;

    let (operation, customer) = operation
        .to_domain()?
        // get_customer_details
        .get_or_create_customer_details(
            state,
            &mut payment_data,
            customer_details,
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)
        .attach_printable("Failed while fetching/creating customer")?;

    let authentication_type =
        call_decision_manager(state, merchant_context, &business_profile, &payment_data).await?;

    payment_data.set_authentication_type_in_attempt(authentication_type);

    let connector = get_connector_choice(
        &operation,
        state,
        &req,
        merchant_context,
        &business_profile,
        &mut payment_data,
        eligible_connectors,
        mandate_type,
    )
    .await?;

    let payment_method_token = get_decrypted_wallet_payment_method_token(
        &operation,
        state,
        merchant_context,
        &mut payment_data,
        connector.as_ref(),
    )
    .await?;

    payment_method_token.map(|token| payment_data.set_payment_method_token(Some(token)));

    let (connector, debit_routing_output) = debit_routing::perform_debit_routing(
        &operation,
        state,
        &business_profile,
        &mut payment_data,
        connector,
    )
    .await;

    operation
        .to_domain()?
        .apply_three_ds_authentication_strategy(state, &mut payment_data, &business_profile)
        .await?;

    let should_add_task_to_process_tracker = should_add_task_to_process_tracker(&payment_data);

    let locale = header_payload.locale.clone();

    payment_data = tokenize_in_router_when_confirm_false_or_external_authentication(
        state,
        &operation,
        &mut payment_data,
        &validate_result,
        merchant_context.get_merchant_key_store(),
        &customer,
        &business_profile,
    )
    .await?;

    let mut connector_http_status_code = None;
    let mut external_latency = None;
    if let Some(connector_details) = connector {
        // Fetch and check FRM configs
        #[cfg(feature = "frm")]
        let mut frm_info = None;
        #[allow(unused_variables, unused_mut)]
        let mut should_continue_transaction: bool = true;
        #[cfg(feature = "frm")]
        let mut should_continue_capture: bool = true;
        #[cfg(feature = "frm")]
        let frm_configs = if state.conf.frm.enabled {
            Box::pin(frm_core::call_frm_before_connector_call(
                &operation,
                merchant_context,
                &mut payment_data,
                state,
                &mut frm_info,
                &customer,
                &mut should_continue_transaction,
                &mut should_continue_capture,
            ))
            .await?
        } else {
            None
        };
        #[cfg(feature = "frm")]
        logger::debug!(
            "frm_configs: {:?}\nshould_continue_transaction: {:?}\nshould_continue_capture: {:?}",
            frm_configs,
            should_continue_transaction,
            should_continue_capture,
        );

        let is_eligible_for_uas = helpers::is_merchant_eligible_authentication_service(
            merchant_context.get_merchant_account().get_id(),
            state,
        )
        .await?;

        if is_eligible_for_uas {
            operation
                .to_domain()?
                .call_unified_authentication_service_if_eligible(
                    state,
                    &mut payment_data,
                    &mut should_continue_transaction,
                    &connector_details,
                    &business_profile,
                    merchant_context.get_merchant_key_store(),
                    mandate_type,
                )
                .await?;
        } else {
            logger::info!(
                "skipping authentication service call since the merchant is not eligible."
            );

            operation
                .to_domain()?
                .call_external_three_ds_authentication_if_eligible(
                    state,
                    &mut payment_data,
                    &mut should_continue_transaction,
                    &connector_details,
                    &business_profile,
                    merchant_context.get_merchant_key_store(),
                    mandate_type,
                )
                .await?;
        };

        operation
            .to_domain()?
            .payments_dynamic_tax_calculation(
                state,
                &mut payment_data,
                &connector_details,
                &business_profile,
                merchant_context,
            )
            .await?;

        if should_continue_transaction {
            #[cfg(feature = "frm")]
            match (
                should_continue_capture,
                payment_data.get_payment_attempt().capture_method,
            ) {
                (
                    false,
                    Some(storage_enums::CaptureMethod::Automatic)
                    | Some(storage_enums::CaptureMethod::SequentialAutomatic),
                )
                | (false, Some(storage_enums::CaptureMethod::Scheduled)) => {
                    if let Some(info) = &mut frm_info {
                        if let Some(frm_data) = &mut info.frm_data {
                            frm_data.fraud_check.payment_capture_method =
                                payment_data.get_payment_attempt().capture_method;
                        }
                    }
                    payment_data
                        .set_capture_method_in_attempt(storage_enums::CaptureMethod::Manual);
                    logger::debug!("payment_id : {:?} capture method has been changed to manual, since it has configured Post FRM flow",payment_data.get_payment_attempt().payment_id);
                }
                _ => (),
            };

            payment_data = match connector_details {
                ConnectorCallType::PreDetermined(ref connector) => {
                    #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
                    let routable_connectors = convert_connector_data_to_routable_connectors(
                        std::slice::from_ref(connector),
                    )
                    .map_err(|e| logger::error!(routable_connector_error=?e))
                    .unwrap_or_default();
                    let schedule_time = if should_add_task_to_process_tracker {
                        payment_sync::get_sync_process_schedule_time(
                            &*state.store,
                            connector.connector_data.connector.id(),
                            merchant_context.get_merchant_account().get_id(),
                            0,
                        )
                        .await
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Failed while getting process schedule time")?
                    } else {
                        None
                    };

                    let (merchant_connector_account, router_data, tokenization_action) =
                        call_connector_service_prerequisites(
                            state,
                            merchant_context,
                            connector.connector_data.clone(),
                            &operation,
                            &mut payment_data,
                            &customer,
                            &validate_result,
                            &business_profile,
                            false,
                            None,
                        )
                        .await?;

                    let (router_data, mca) = decide_unified_connector_service_call(
                        state,
                        req_state.clone(),
                        merchant_context,
                        connector.connector_data.clone(),
                        &operation,
                        &mut payment_data,
                        &customer,
                        call_connector_action.clone(),
                        &validate_result,
                        schedule_time,
                        header_payload.clone(),
                        #[cfg(feature = "frm")]
                        frm_info.as_ref().and_then(|fi| fi.suggested_action),
                        #[cfg(not(feature = "frm"))]
                        None,
                        &business_profile,
                        false,
                        <Req as Authenticate>::should_return_raw_response(&req),
                        merchant_connector_account,
                        router_data,
                        tokenization_action,
                    )
                    .await?;

                    let op_ref = &operation;
                    let should_trigger_post_processing_flows = is_operation_confirm(&operation);

                    let operation = Box::new(PaymentResponse);

                    connector_http_status_code = router_data.connector_http_status_code;
                    external_latency = router_data.external_latency;
                    //add connector http status code metrics
                    add_connector_http_status_code_metrics(connector_http_status_code);

                    operation
                        .to_post_update_tracker()?
                        .save_pm_and_mandate(
                            state,
                            &router_data,
                            merchant_context,
                            &mut payment_data,
                            &business_profile,
                        )
                        .await?;

                    let mut payment_data = operation
                        .to_post_update_tracker()?
                        .update_tracker(
                            state,
                            payment_data,
                            router_data,
                            merchant_context.get_merchant_key_store(),
                            merchant_context.get_merchant_account().storage_scheme,
                            &locale,
                            #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
                            routable_connectors,
                            #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
                            &business_profile,
                        )
                        .await?;

                    if should_trigger_post_processing_flows {
                        complete_postprocessing_steps_if_required(
                            state,
                            merchant_context,
                            &customer,
                            &mca,
                            &connector.connector_data,
                            &mut payment_data,
                            op_ref,
                            Some(header_payload.clone()),
                        )
                        .await?;
                    }

                    if is_eligible_for_uas {
                        complete_confirmation_for_click_to_pay_if_required(
                            state,
                            merchant_context,
                            &payment_data,
                        )
                        .await?;
                    }

                    payment_data
                }

                ConnectorCallType::Retryable(ref connectors) => {
                    #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
                    let routable_connectors =
                        convert_connector_data_to_routable_connectors(connectors)
                            .map_err(|e| logger::error!(routable_connector_error=?e))
                            .unwrap_or_default();

                    let mut connectors = connectors.clone().into_iter();

                    let (connector_data, routing_decision) =
                        get_connector_data_with_routing_decision(
                            &mut connectors,
                            &business_profile,
                            debit_routing_output,
                        )?;

                    let schedule_time = if should_add_task_to_process_tracker {
                        payment_sync::get_sync_process_schedule_time(
                            &*state.store,
                            connector_data.connector.id(),
                            merchant_context.get_merchant_account().get_id(),
                            0,
                        )
                        .await
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Failed while getting process schedule time")?
                    } else {
                        None
                    };

                    let (merchant_connector_account, router_data, tokenization_action) =
                        call_connector_service_prerequisites(
                            state,
                            merchant_context,
                            connector_data.clone(),
                            &operation,
                            &mut payment_data,
                            &customer,
                            &validate_result,
                            &business_profile,
                            false,
                            routing_decision,
                        )
                        .await?;

                    let (router_data, mca) = decide_unified_connector_service_call(
                        state,
                        req_state.clone(),
                        merchant_context,
                        connector_data.clone(),
                        &operation,
                        &mut payment_data,
                        &customer,
                        call_connector_action.clone(),
                        &validate_result,
                        schedule_time,
                        header_payload.clone(),
                        #[cfg(feature = "frm")]
                        frm_info.as_ref().and_then(|fi| fi.suggested_action),
                        #[cfg(not(feature = "frm"))]
                        None,
                        &business_profile,
                        false,
                        <Req as Authenticate>::should_return_raw_response(&req),
                        merchant_connector_account,
                        router_data,
                        tokenization_action,
                    )
                    .await?;

                    #[cfg(all(feature = "retry", feature = "v1"))]
                    let mut router_data = router_data;
                    #[cfg(all(feature = "retry", feature = "v1"))]
                    {
                        use crate::core::payments::retry::{self, GsmValidation};
                        let config_bool = retry::config_should_call_gsm(
                            &*state.store,
                            merchant_context.get_merchant_account().get_id(),
                            &business_profile,
                        )
                        .await;

                        if config_bool && router_data.should_call_gsm() {
                            router_data = retry::do_gsm_actions(
                                state,
                                req_state.clone(),
                                &mut payment_data,
                                connectors,
                                &connector_data,
                                router_data,
                                merchant_context,
                                &operation,
                                &customer,
                                &validate_result,
                                schedule_time,
                                #[cfg(feature = "frm")]
                                frm_info.as_ref().and_then(|fi| fi.suggested_action),
                                #[cfg(not(feature = "frm"))]
                                None,
                                &business_profile,
                            )
                            .await?;
                        };
                    }

                    let op_ref = &operation;
                    let should_trigger_post_processing_flows = is_operation_confirm(&operation);

                    let operation = Box::new(PaymentResponse);
                    connector_http_status_code = router_data.connector_http_status_code;
                    external_latency = router_data.external_latency;
                    //add connector http status code metrics
                    add_connector_http_status_code_metrics(connector_http_status_code);

                    operation
                        .to_post_update_tracker()?
                        .save_pm_and_mandate(
                            state,
                            &router_data,
                            merchant_context,
                            &mut payment_data,
                            &business_profile,
                        )
                        .await?;

                    let mut payment_data = operation
                        .to_post_update_tracker()?
                        .update_tracker(
                            state,
                            payment_data,
                            router_data,
                            merchant_context.get_merchant_key_store(),
                            merchant_context.get_merchant_account().storage_scheme,
                            &locale,
                            #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
                            routable_connectors,
                            #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
                            &business_profile,
                        )
                        .await?;

                    if should_trigger_post_processing_flows {
                        complete_postprocessing_steps_if_required(
                            state,
                            merchant_context,
                            &customer,
                            &mca,
                            &connector_data,
                            &mut payment_data,
                            op_ref,
                            Some(header_payload.clone()),
                        )
                        .await?;
                    }

                    if is_eligible_for_uas {
                        complete_confirmation_for_click_to_pay_if_required(
                            state,
                            merchant_context,
                            &payment_data,
                        )
                        .await?;
                    }

                    payment_data
                }

                ConnectorCallType::SessionMultiple(connectors) => {
                    let session_surcharge_details =
                        call_surcharge_decision_management_for_session_flow(
                            state,
                            merchant_context,
                            &business_profile,
                            payment_data.get_payment_attempt(),
                            payment_data.get_payment_intent(),
                            payment_data.get_billing_address(),
                            &connectors,
                        )
                        .await?;
                    Box::pin(call_multiple_connectors_service(
                        state,
                        merchant_context,
                        connectors,
                        &operation,
                        payment_data,
                        &customer,
                        session_surcharge_details,
                        &business_profile,
                        header_payload.clone(),
                        <Req as Authenticate>::should_return_raw_response(&req),
                    ))
                    .await?
                }
            };

            #[cfg(feature = "frm")]
            if let Some(fraud_info) = &mut frm_info {
                #[cfg(feature = "v1")]
                Box::pin(frm_core::post_payment_frm_core(
                    state,
                    req_state,
                    merchant_context,
                    &mut payment_data,
                    fraud_info,
                    frm_configs
                        .clone()
                        .ok_or(errors::ApiErrorResponse::MissingRequiredField {
                            field_name: "frm_configs",
                        })
                        .attach_printable("Frm configs label not found")?,
                    &customer,
                    &mut should_continue_capture,
                ))
                .await?;
            }
        } else {
            (_, payment_data) = operation
                .to_update_tracker()?
                .update_trackers(
                    state,
                    req_state,
                    payment_data.clone(),
                    customer.clone(),
                    validate_result.storage_scheme,
                    None,
                    merchant_context.get_merchant_key_store(),
                    #[cfg(feature = "frm")]
                    frm_info.and_then(|info| info.suggested_action),
                    #[cfg(not(feature = "frm"))]
                    None,
                    header_payload.clone(),
                )
                .await?;
        }

        let payment_intent_status = payment_data.get_payment_intent().status;

        payment_data
            .get_payment_attempt()
            .payment_token
            .as_ref()
            .zip(payment_data.get_payment_attempt().payment_method)
            .map(ParentPaymentMethodToken::create_key_for_token)
            .async_map(|key_for_hyperswitch_token| async move {
                if key_for_hyperswitch_token
                    .should_delete_payment_method_token(payment_intent_status)
                {
                    let _ = key_for_hyperswitch_token.delete(state).await;
                }
            })
            .await;
    } else {
        (_, payment_data) = operation
            .to_update_tracker()?
            .update_trackers(
                state,
                req_state,
                payment_data.clone(),
                customer.clone(),
                validate_result.storage_scheme,
                None,
                merchant_context.get_merchant_key_store(),
                None,
                header_payload.clone(),
            )
            .await?;
    }

    let cloned_payment_data = payment_data.clone();
    let cloned_customer = customer.clone();

    #[cfg(feature = "v1")]
    operation
        .to_domain()?
        .store_extended_card_info_temporarily(
            state,
            payment_data.get_payment_intent().get_id(),
            &business_profile,
            payment_data.get_payment_method_data(),
        )
        .await?;

    utils::trigger_payments_webhook(
        merchant_context.clone(),
        business_profile,
        cloned_payment_data,
        cloned_customer,
        state,
        operation,
    )
    .await
    .map_err(|error| logger::warn!(payments_outgoing_webhook_error=?error))
    .ok();

    Ok((
        payment_data,
        req,
        customer,
        connector_http_status_code,
        external_latency,
    ))
}


pub fn add_tenant(&mut self, tenant_config: &dyn TenantConfig) {
        if let Self::Kafka(kafka_producer) = self {
            kafka_producer.set_tenancy(tenant_config);
        }
    }


pub struct PayoutAttemptUpdateMems {
    pub orig: PayoutAttempt,
    pub update_data: PayoutAttemptUpdate,
}


Documentation: api-reference/v2/payments/payments--get.mdx
# Type: Doc File

---
openapi: get /v2/payments/{id}
---


OpenAPI Block Path: paths."/payment_methods/{method_id}"
{
  "get": {
    "tags": [
      "Payment Methods"
    ],
    "summary": "Payment Method - Retrieve",
    "description": "Retrieves a payment method of a customer.",
    "operationId": "Retrieve a Payment method",
    "parameters": [
      {
        "name": "method_id",
        "in": "path",
        "description": "The unique identifier for the Payment Method",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    ],
    "responses": {
      "200": {
        "description": "Payment Method retrieved",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PaymentMethodResponse"
            }
          }
        }
      },
      "404": {
        "description": "Payment Method does not exist in records"
      }
    },
    "security": [
      {
        "api_key": []
      }
    ]
  },
  "delete": {
    "tags": [
      "Payment Methods"
    ],
    "summary": "Payment Method - Delete",
    "description": "Deletes a payment method of a customer.",
    "operationId": "Delete a Payment method",
    "parameters": [
      {
        "name": "method_id",
        "in": "path",
        "description": "The unique identifier for the Payment Method",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    ],
    "responses": {
      "200": {
        "description": "Payment Method deleted",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PaymentMethodDeleteResponse"
            }
          }
        }
      },
      "404": {
        "description": "Payment Method does not exist in records"
      }
    },
    "security": [
      {
        "api_key": []
      }
    ]
  }
}


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


File: crates/router/src/types/transformers.rs

use actix_web::http::header::HeaderMap;
use api_models::{
    cards_info as card_info_types, enums as api_enums, gsm as gsm_api_types, payment_methods,
    payments, routing::ConnectorSelection,
};
use common_utils::{
    consts::X_HS_LATENCY,
    crypto::Encryptable,
    ext_traits::{Encode, StringExt, ValueExt},
    fp_utils::when,
    pii,
    types::ConnectorTransactionIdTrait,
};
use diesel_models::enums as storage_enums;
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::payments::payment_intent::CustomerData;
use masking::{ExposeInterface, PeekInterface, Secret};

use super::domain;
#[cfg(feature = "v2")]
use crate::db::storage::revenue_recovery_redis_operation;
use crate::{
    core::errors,
    headers::{
        ACCEPT_LANGUAGE, BROWSER_NAME, X_APP_ID, X_CLIENT_PLATFORM, X_CLIENT_SOURCE,
        X_CLIENT_VERSION, X_MERCHANT_DOMAIN, X_PAYMENT_CONFIRM_SOURCE, X_REDIRECT_URI,
    },
    services::authentication::get_header_value_by_key,
    types::{
        self as router_types,
        api::{self as api_types, routing as routing_types},
        storage,
    },
};

pub trait ForeignInto<T> {
    fn foreign_into(self) -> T;
}

pub trait ForeignTryInto<T> {
    type Error;

    fn foreign_try_into(self) -> Result<T, Self::Error>;
}

pub trait ForeignFrom<F> {
    fn foreign_from(from: F) -> Self;
}

pub trait ForeignTryFrom<F>: Sized {
    type Error;

    fn foreign_try_from(from: F) -> Result<Self, Self::Error>;
}

impl<F, T> ForeignInto<T> for F
where
    T: ForeignFrom<F>,
{
    fn foreign_into(self) -> T {
        T::foreign_from(self)
    }
}

impl<F, T> ForeignTryInto<T> for F
where
    T: ForeignTryFrom<F>,
{
    type Error = <T as ForeignTryFrom<F>>::Error;

    fn foreign_try_into(self) -> Result<T, Self::Error> {
        T::foreign_try_from(self)
    }
}

impl ForeignFrom<api_models::refunds::RefundType> for storage_enums::RefundType {
    fn foreign_from(item: api_models::refunds::RefundType) -> Self {
        match item {
            api_models::refunds::RefundType::Instant => Self::InstantRefund,
            api_models::refunds::RefundType::Scheduled => Self::RegularRefund,
        }
    }
}

#[cfg(feature = "v1")]
impl
    ForeignFrom<(
        Option<payment_methods::CardDetailFromLocker>,
        domain::PaymentMethod,
    )> for payment_methods::PaymentMethodResponse
{
    fn foreign_from(
        (card_details, item): (
            Option<payment_methods::CardDetailFromLocker>,
            domain::PaymentMethod,
        ),
    ) -> Self {
        Self {
            merchant_id: item.merchant_id.to_owned(),
            customer_id: Some(item.customer_id.to_owned()),
            payment_method_id: item.get_id().clone(),
            payment_method: item.get_payment_method_type(),
            payment_method_type: item.get_payment_method_subtype(),
            card: card_details,
            recurring_enabled: Some(false),
            installment_payment_enabled: Some(false),
            payment_experience: None,
            metadata: item.metadata,
            created: Some(item.created_at),
            #[cfg(feature = "payouts")]
            bank_transfer: None,
            last_used_at: None,
            client_secret: item.client_secret,
        }
    }
}

#[cfg(feature = "v2")]
impl
    ForeignFrom<(
        Option<payment_methods::CardDetailFromLocker>,
        domain::PaymentMethod,
    )> for payment_methods::PaymentMethodResponse
{
    fn foreign_from(
        (card_details, item): (
            Option<payment_methods::CardDetailFromLocker>,
            domain::PaymentMethod,
        ),
    ) -> Self {
        todo!()
    }
}

// TODO: remove this usage in v1 code
impl ForeignFrom<storage_enums::AttemptStatus> for storage_enums::IntentStatus {
    fn foreign_from(s: storage_enums::AttemptStatus) -> Self {
        Self::from(s)
    }
}

impl ForeignTryFrom<storage_enums::AttemptStatus> for storage_enums::CaptureStatus {
    type Error = error_stack::Report<errors::ApiErrorResponse>;

    fn foreign_try_from(
        attempt_status: storage_enums::AttemptStatus,
    ) -> errors::RouterResult<Self> {
        match attempt_status {
            storage_enums::AttemptStatus::Charged
            | storage_enums::AttemptStatus::PartialCharged | storage_enums::AttemptStatus::IntegrityFailure => Ok(Self::Charged),
            storage_enums::AttemptStatus::Pending
            | storage_enums::AttemptStatus::CaptureInitiated => Ok(Self::Pending),
            storage_enums::AttemptStatus::Failure
            | storage_enums::AttemptStatus::CaptureFailed => Ok(Self::Failed),

            storage_enums::AttemptStatus::Started
            | storage_enums::AttemptStatus::AuthenticationFailed
            | storage_enums::AttemptStatus::RouterDeclined
            | storage_enums::AttemptStatus::AuthenticationPending
            | storage_enums::AttemptStatus::AuthenticationSuccessful
            | storage_enums::AttemptStatus::Authorized
            | storage_enums::AttemptStatus::AuthorizationFailed
            | storage_enums::AttemptStatus::Authorizing
            | storage_enums::AttemptStatus::CodInitiated
            | storage_enums::AttemptStatus::Voided
            | storage_enums::AttemptStatus::VoidedPostCharge
            | storage_enums::AttemptStatus::VoidInitiated
            | storage_enums::AttemptStatus::VoidFailed
            | storage_enums::AttemptStatus::AutoRefunded
            | storage_enums::AttemptStatus::Unresolved
            | storage_enums::AttemptStatus::PaymentMethodAwaited
            | storage_enums::AttemptStatus::ConfirmationAwaited
            | storage_enums::AttemptStatus::DeviceDataCollectionPending
            | storage_enums::AttemptStatus::PartiallyAuthorized
            | storage_enums::AttemptStatus::PartialChargedAndChargeable | storage_enums::AttemptStatus::Expired => {
                Err(errors::ApiErrorResponse::PreconditionFailed {
                    message: "AttemptStatus must be one of these for multiple partial captures [Charged, PartialCharged, Pending, CaptureInitiated, Failure, CaptureFailed]".into(),
                }.into())
            }
        }
    }
}

impl ForeignFrom<payments::MandateType> for storage_enums::MandateDataType {
    fn foreign_from(from: payments::MandateType) -> Self {
        match from {
            payments::MandateType::SingleUse(inner) => Self::SingleUse(inner.foreign_into()),
            payments::MandateType::MultiUse(inner) => {
                Self::MultiUse(inner.map(ForeignInto::foreign_into))
            }
        }
    }
}

impl ForeignFrom<storage_enums::MandateDataType> for payments::MandateType {
    fn foreign_from(from: storage_enums::MandateDataType) -> Self {
        match from {
            storage_enums::MandateDataType::SingleUse(inner) => {
                Self::SingleUse(inner.foreign_into())
            }
            storage_enums::MandateDataType::MultiUse(inner) => {
                Self::MultiUse(inner.map(ForeignInto::foreign_into))
            }
        }
    }
}

impl ForeignFrom<storage_enums::MandateAmountData> for payments::MandateAmountData {
    fn foreign_from(from: storage_enums::MandateAmountData) -> Self {
        Self {
            amount: from.amount,
            currency: from.currency,
            start_date: from.start_date,
            end_date: from.end_date,
            metadata: from.metadata,
        }
    }
}

// TODO: remove foreign from since this conversion won't be needed in the router crate once data models is treated as a single & primary source of truth for structure information
impl ForeignFrom<payments::MandateData> for hyperswitch_domain_models::mandates::MandateData {
    fn foreign_from(d: payments::MandateData) -> Self {
        Self {
            customer_acceptance: d.customer_acceptance,
            mandate_type: d.mandate_type.map(|d| match d {
                payments::MandateType::MultiUse(Some(i)) => {
                    hyperswitch_domain_models::mandates::MandateDataType::MultiUse(Some(
                        hyperswitch_domain_models::mandates::MandateAmountData {
                            amount: i.amount,
                            currency: i.currency,
                            start_date: i.start_date,
                            end_date: i.end_date,
                            metadata: i.metadata,
                        },
                    ))
                }
                payments::MandateType::SingleUse(i) => {
                    hyperswitch_domain_models::mandates::MandateDataType::SingleUse(
                        hyperswitch_domain_models::mandates::MandateAmountData {
                            amount: i.amount,
                            currency: i.currency,
                            start_date: i.start_date,
                            end_date: i.end_date,
                            metadata: i.metadata,
                        },
                    )
                }
                payments::MandateType::MultiUse(None) => {
                    hyperswitch_domain_models::mandates::MandateDataType::MultiUse(None)
                }
            }),
            update_mandate_id: d.update_mandate_id,
        }
    }
}

impl ForeignFrom<payments::MandateAmountData> for storage_enums::MandateAmountData {
    fn foreign_from(from: payments::MandateAmountData) -> Self {
        Self {
            amount: from.amount,
            currency: from.currency,
            start_date: from.start_date,
            end_date: from.end_date,
            metadata: from.metadata,
        }
    }
}

impl ForeignFrom<api_enums::PaymentMethodType> for api_enums::PaymentMethod {
    fn foreign_from(payment_method_type: api_enums::PaymentMethodType) -> Self {
        match payment_method_type {
            api_enums::PaymentMethodType::AmazonPay
            | api_enums::PaymentMethodType::Paysera
            | api_enums::PaymentMethodType::Skrill
            | api_enums::PaymentMethodType::ApplePay
            | api_enums::PaymentMethodType::GooglePay
            | api_enums::PaymentMethodType::Paypal
            | api_enums::PaymentMethodType::AliPay
            | api_enums::PaymentMethodType::AliPayHk
            | api_enums::PaymentMethodType::Dana
            | api_enums::PaymentMethodType::MbWay
            | api_enums::PaymentMethodType::MobilePay
            | api_enums::PaymentMethodType::Paze
            | api_enums::PaymentMethodType::SamsungPay
            | api_enums::PaymentMethodType::Twint
            | api_enums::PaymentMethodType::Vipps
            | api_enums::PaymentMethodType::TouchNGo
            | api_enums::PaymentMethodType::Swish
            | api_enums::PaymentMethodType::WeChatPay
            | api_enums::PaymentMethodType::GoPay
            | api_enums::PaymentMethodType::Gcash
            | api_enums::PaymentMethodType::Momo
            | api_enums::PaymentMethodType::Cashapp
            | api_enums::PaymentMethodType::KakaoPay
            | api_enums::PaymentMethodType::Venmo
            | api_enums::PaymentMethodType::Mifinity
            | api_enums::PaymentMethodType::RevolutPay
            | api_enums::PaymentMethodType::Bluecode => Self::Wallet,
            api_enums::PaymentMethodType::Affirm
            | api_enums::PaymentMethodType::Alma
            | api_enums::PaymentMethodType::AfterpayClearpay
            | api_enums::PaymentMethodType::Klarna
            | api_enums::PaymentMethodType::Flexiti
            | api_enums::PaymentMethodType::PayBright
            | api_enums::PaymentMethodType::Atome
            | api_enums::PaymentMethodType::Walley
            | api_enums::PaymentMethodType::Breadpay => Self::PayLater,
            api_enums::PaymentMethodType::Giropay
            | api_enums::PaymentMethodType::Ideal
            | api_enums::PaymentMethodType::Sofort
            | api_enums::PaymentMethodType::Eft
            | api_enums::PaymentMethodType::Eps
            | api_enums::PaymentMethodType::BancontactCard
            | api_enums::PaymentMethodType::Blik
            | api_enums::PaymentMethodType::LocalBankRedirect
            | api_enums::PaymentMethodType::OnlineBankingThailand
            | api_enums::PaymentMethodType::OnlineBankingCzechRepublic
            | api_enums::PaymentMethodType::OnlineBankingFinland
            | api_enums::PaymentMethodType::OnlineBankingFpx
            | api_enums::PaymentMethodType::OnlineBankingPoland
            | api_enums::PaymentMethodType::OnlineBankingSlovakia
            | api_enums::PaymentMethodType::OpenBankingUk
            | api_enums::PaymentMethodType::OpenBankingPIS
            | api_enums::PaymentMethodType::Przelewy24
            | api_enums::PaymentMethodType::Trustly
            | api_enums::PaymentMethodType::Bizum
            | api_enums::PaymentMethodType::Interac => Self::BankRedirect,
            api_enums::PaymentMethodType::UpiCollect | api_enums::PaymentMethodType::UpiIntent => {
                Self::Upi
            }
            api_enums::PaymentMethodType::CryptoCurrency => Self::Crypto,
            api_enums::PaymentMethodType::Ach
            | api_enums::PaymentMethodType::Sepa
            | api_enums::PaymentMethodType::Bacs
            | api_enums::PaymentMethodType::Becs => Self::BankDebit,
            api_enums::PaymentMethodType::Credit | api_enums::PaymentMethodType::Debit => {
                Self::Card
            }
            #[cfg(feature = "v2")]
            api_enums::PaymentMethodType::Card => Self::Card,
            api_enums::PaymentMethodType::Evoucher
            | api_enums::PaymentMethodType::ClassicReward => Self::Reward,
            api_enums::PaymentMethodType::Boleto
            | api_enums::PaymentMethodType::Efecty
            | api_enums::PaymentMethodType::PagoEfectivo
            | api_enums::PaymentMethodType::RedCompra
            | api_enums::PaymentMethodType::Alfamart
            | api_enums::PaymentMethodType::Indomaret
            | api_enums::PaymentMethodType::Oxxo
            | api_enums::PaymentMethodType::SevenEleven
            | api_enums::PaymentMethodType::Lawson
            | api_enums::PaymentMethodType::MiniStop
            | api_enums::PaymentMethodType::FamilyMart
            | api_enums::PaymentMethodType::Seicomart
            | api_enums::PaymentMethodType::PayEasy
            | api_enums::PaymentMethodType::RedPagos => Self::Voucher,
            api_enums::PaymentMethodType::Pse
            | api_enums::PaymentMethodType::Multibanco
            | api_enums::PaymentMethodType::PermataBankTransfer
            | api_enums::PaymentMethodType::BcaBankTransfer
            | api_enums::PaymentMethodType::BniVa
            | api_enums::PaymentMethodType::BriVa
            | api_enums::PaymentMethodType::CimbVa
            | api_enums::PaymentMethodType::DanamonVa
            | api_enums::PaymentMethodType::MandiriVa
            | api_enums::PaymentMethodType::LocalBankTransfer
            | api_enums::PaymentMethodType::InstantBankTransfer
            | api_enums::PaymentMethodType::InstantBankTransferFinland
            | api_enums::PaymentMethodType::InstantBankTransferPoland
            | api_enums::PaymentMethodType::SepaBankTransfer
            | api_enums::PaymentMethodType::IndonesianBankTransfer
            | api_enums::PaymentMethodType::Pix => Self::BankTransfer,
            api_enums::PaymentMethodType::Givex
            | api_enums::PaymentMethodType::PaySafeCard
            | api_enums::PaymentMethodType::BhnCardNetwork => Self::GiftCard,
            api_enums::PaymentMethodType::Benefit
            | api_enums::PaymentMethodType::Knet
            | api_enums::PaymentMethodType::MomoAtm
            | api_enums::PaymentMethodType::CardRedirect => Self::CardRedirect,
            api_enums::PaymentMethodType::Fps
            | api_enums::PaymentMethodType::DuitNow
            | api_enums::PaymentMethodType::PromptPay
            | api_enums::PaymentMethodType::VietQr => Self::RealTimePayment,
            api_enums::PaymentMethodType::DirectCarrierBilling => Self::MobilePayment,
        }
    }
}

impl ForeignTryFrom<payments::PaymentMethodData> for api_enums::PaymentMethod {
    type Error = errors::ApiErrorResponse;
    fn foreign_try_from(
        payment_method_data: payments::PaymentMethodData,
    ) -> Result<Self, Self::Error> {
        match payment_method_data {
            payments::PaymentMethodData::Card(..) | payments::PaymentMethodData::CardToken(..) => {
                Ok(Self::Card)
            }
            payments::PaymentMethodData::Wallet(..) => Ok(Self::Wallet),
            payments::PaymentMethodData::PayLater(..) => Ok(Self::PayLater),
            payments::PaymentMethodData::BankRedirect(..) => Ok(Self::BankRedirect),
            payments::PaymentMethodData::BankDebit(..) => Ok(Self::BankDebit),
            payments::PaymentMethodData::BankTransfer(..) => Ok(Self::BankTransfer),
            payments::PaymentMethodData::Crypto(..) => Ok(Self::Crypto),
            payments::PaymentMethodData::Reward => Ok(Self::Reward),
            payments::PaymentMethodData::RealTimePayment(..) => Ok(Self::RealTimePayment),
            payments::PaymentMethodData::Upi(..) => Ok(Self::Upi),
            payments::PaymentMethodData::Voucher(..) => Ok(Self::Voucher),
            payments::PaymentMethodData::GiftCard(..) => Ok(Self::GiftCard),
            payments::PaymentMethodData::CardRedirect(..) => Ok(Self::CardRedirect),
            payments::PaymentMethodData::OpenBanking(..) => Ok(Self::OpenBanking),
            payments::PaymentMethodData::MobilePayment(..) => Ok(Self::MobilePayment),
            payments::PaymentMethodData::MandatePayment => {
                Err(errors::ApiErrorResponse::InvalidRequestData {
                    message: ("Mandate payments cannot have payment_method_data field".to_string()),
                })
            }
        }
    }
}

impl ForeignTryFrom<api_models::webhooks::IncomingWebhookEvent> for storage_enums::RefundStatus {
    type Error = errors::ValidationError;

    fn foreign_try_from(
        value: api_models::webhooks::IncomingWebhookEvent,
    ) -> Result<Self, Self::Error> {
        match value {
            api_models::webhooks::IncomingWebhookEvent::RefundSuccess => Ok(Self::Success),
            api_models::webhooks::IncomingWebhookEvent::RefundFailure => Ok(Self::Failure),
            _ => Err(errors::ValidationError::IncorrectValueProvided {
                field_name: "incoming_webhook_event_type",
            }),
        }
    }
}

impl ForeignTryFrom<api_models::webhooks::IncomingWebhookEvent> for api_enums::RelayStatus {
    type Error = errors::ValidationError;

    fn foreign_try_from(
        value: api_models::webhooks::IncomingWebhookEvent,
    ) -> Result<Self, Self::Error> {
        match value {
            api_models::webhooks::IncomingWebhookEvent::RefundSuccess => Ok(Self::Success),
            api_models::webhooks::IncomingWebhookEvent::RefundFailure => Ok(Self::Failure),
            _ => Err(errors::ValidationError::IncorrectValueProvided {
                field_name: "incoming_webhook_event_type",
            }),
        }
    }
}

#[cfg(feature = "payouts")]
impl ForeignTryFrom<api_models::webhooks::IncomingWebhookEvent> for storage_enums::PayoutStatus {
    type Error = errors::ValidationError;

    fn foreign_try_from(
        value: api_models::webhooks::IncomingWebhookEvent,
    ) -> Result<Self, Self::Error> {
        match value {
            api_models::webhooks::IncomingWebhookEvent::PayoutSuccess => Ok(Self::Success),
            api_models::webhooks::IncomingWebhookEvent::PayoutFailure => Ok(Self::Failed),
            api_models::webhooks::IncomingWebhookEvent::PayoutCancelled => Ok(Self::Cancelled),
            api_models::webhooks::IncomingWebhookEvent::PayoutProcessing => Ok(Self::Pending),
            api_models::webhooks::IncomingWebhookEvent::PayoutCreated => Ok(Self::Initiated),
            api_models::webhooks::IncomingWebhookEvent::PayoutExpired => Ok(Self::Expired),
            api_models::webhooks::IncomingWebhookEvent::PayoutReversed => Ok(Self::Reversed),
            _ => Err(errors::ValidationError::IncorrectValueProvided {
                field_name: "incoming_webhook_event_type",
            }),
        }
    }
}

impl ForeignTryFrom<api_models::webhooks::IncomingWebhookEvent> for storage_enums::MandateStatus {
    type Error = errors::ValidationError;

    fn foreign_try_from(
        value: api_models::webhooks::IncomingWebhookEvent,
    ) -> Result<Self, Self::Error> {
        match value {
            api_models::webhooks::IncomingWebhookEvent::MandateActive => Ok(Self::Active),
            api_models::webhooks::IncomingWebhookEvent::MandateRevoked => Ok(Self::Revoked),
            _ => Err(errors::ValidationError::IncorrectValueProvided {
                field_name: "incoming_webhook_event_type",
            }),
        }
    }
}

impl ForeignFrom<storage::Config> for api_types::Config {
    fn foreign_from(config: storage::Config) -> Self {
        Self {
            key: config.key,
            value: config.config,
        }
    }
}

impl ForeignFrom<&api_types::ConfigUpdate> for storage::ConfigUpdate {
    fn foreign_from(config: &api_types::ConfigUpdate) -> Self {
        Self::Update {
            config: Some(config.value.clone()),
        }
    }
}

impl From<&domain::Address> for hyperswitch_domain_models::address::Address {
    fn from(address: &domain::Address) -> Self {
        // If all the fields of address are none, then pass the address as None
        let address_details = if address.city.is_none()
            && address.line1.is_none()
            && address.line2.is_none()
            && address.line3.is_none()
            && address.state.is_none()
            && address.country.is_none()
            && address.zip.is_none()
            && address.first_name.is_none()
            && address.last_name.is_none()
        {
            None
        } else {
            Some(hyperswitch_domain_models::address::AddressDetails {
                city: address.city.clone(),
                country: address.country,
                line1: address.line1.clone().map(Encryptable::into_inner),
                line2: address.line2.clone().map(Encryptable::into_inner),
                line3: address.line3.clone().map(Encryptable::into_inner),
                state: address.state.clone().map(Encryptable::into_inner),
                zip: address.zip.clone().map(Encryptable::into_inner),
                first_name: address.first_name.clone().map(Encryptable::into_inner),
                last_name: address.last_name.clone().map(Encryptable::into_inner),
                origin_zip: address.origin_zip.clone().map(Encryptable::into_inner),
            })
        };

        // If all the fields of phone are none, then pass the phone as None
        let phone_details = if address.phone_number.is_none() && address.country_code.is_none() {
            None
        } else {
            Some(hyperswitch_domain_models::address::PhoneDetails {
                number: address.phone_number.clone().map(Encryptable::into_inner),
                country_code: address.country_code.clone(),
            })
        };

        Self {
            address: address_details,
            phone: phone_details,
            email: address.email.clone().map(pii::Email::from),
        }
    }
}

impl ForeignFrom<domain::Address> for api_types::Address {
    fn foreign_from(address: domain::Address) -> Self {
        // If all the fields of address are none, then pass the address as None
        let address_details = if address.city.is_none()
            && address.line1.is_none()
            && address.line2.is_none()
            && address.line3.is_none()
            && address.state.is_none()
            && address.country.is_none()
            && address.zip.is_none()
            && address.first_name.is_none()
            && address.last_name.is_none()
        {
            None
        } else {
            Some(api_types::AddressDetails {
                city: address.city.clone(),
                country: address.country,
                line1: address.line1.clone().map(Encryptable::into_inner),
                line2: address.line2.clone().map(Encryptable::into_inner),
                line3: address.line3.clone().map(Encryptable::into_inner),
                state: address.state.clone().map(Encryptable::into_inner),
                zip: address.zip.clone().map(Encryptable::into_inner),
                first_name: address.first_name.clone().map(Encryptable::into_inner),
                last_name: address.last_name.clone().map(Encryptable::into_inner),
                origin_zip: address.origin_zip.clone().map(Encryptable::into_inner),
            })
        };

        // If all the fields of phone are none, then pass the phone as None
        let phone_details = if address.phone_number.is_none() && address.country_code.is_none() {
            None
        } else {
            Some(api_types::PhoneDetails {
                number: address.phone_number.clone().map(Encryptable::into_inner),
                country_code: address.country_code.clone(),
            })
        };

        Self {
            address: address_details,
            phone: phone_details,
            email: address.email.clone().map(pii::Email::from),
        }
    }
}

impl
    ForeignFrom<(
        diesel_models::api_keys::ApiKey,
        crate::core::api_keys::PlaintextApiKey,
    )> for api_models::api_keys::CreateApiKeyResponse
{
    fn foreign_from(
        item: (
            diesel_models::api_keys::ApiKey,
            crate::core::api_keys::PlaintextApiKey,
        ),
    ) -> Self {
        use masking::StrongSecret;

        let (api_key, plaintext_api_key) = item;
        Self {
            key_id: api_key.key_id,
            merchant_id: api_key.merchant_id,
            name: api_key.name,
            description: api_key.description,
            api_key: StrongSecret::from(plaintext_api_key.peek().to_owned()),
            created: api_key.created_at,
            expiration: api_key.expires_at.into(),
        }
    }
}

impl ForeignFrom<diesel_models::api_keys::ApiKey> for api_models::api_keys::RetrieveApiKeyResponse {
    fn foreign_from(api_key: diesel_models::api_keys::ApiKey) -> Self {
        Self {
            key_id: api_key.key_id,
            merchant_id: api_key.merchant_id,
            name: api_key.name,
            description: api_key.description,
            prefix: api_key.prefix.into(),
            created: api_key.created_at,
            expiration: api_key.expires_at.into(),
        }
    }
}

impl ForeignFrom<api_models::api_keys::UpdateApiKeyRequest>
    for diesel_models::api_keys::ApiKeyUpdate
{
    fn foreign_from(api_key: api_models::api_keys::UpdateApiKeyRequest) -> Self {
        Self::Update {
            name: api_key.name,
            description: api_key.description,
            expires_at: api_key.expiration.map(Into::into),
            last_used: None,
        }
    }
}

impl ForeignTryFrom<api_models::webhooks::IncomingWebhookEvent> for storage_enums::DisputeStatus {
    type Error = errors::ValidationError;

    fn foreign_try_from(
        value: api_models::webhooks::IncomingWebhookEvent,
    ) -> Result<Self, Self::Error> {
        match value {
            api_models::webhooks::IncomingWebhookEvent::DisputeOpened => Ok(Self::DisputeOpened),
            api_models::webhooks::IncomingWebhookEvent::DisputeExpired => Ok(Self::DisputeExpired),
            api_models::webhooks::IncomingWebhookEvent::DisputeAccepted => {
                Ok(Self::DisputeAccepted)
            }
            api_models::webhooks::IncomingWebhookEvent::DisputeCancelled => {
                Ok(Self::DisputeCancelled)
            }
            api_models::webhooks::IncomingWebhookEvent::DisputeChallenged => {
                Ok(Self::DisputeChallenged)
            }
            api_models::webhooks::IncomingWebhookEvent::DisputeWon => Ok(Self::DisputeWon),
            api_models::webhooks::IncomingWebhookEvent::DisputeLost => Ok(Self::DisputeLost),
            _ => Err(errors::ValidationError::IncorrectValueProvided {
                field_name: "incoming_webhook_event",
            }),
        }
    }
}

impl ForeignFrom<storage::Dispute> for api_models::disputes::DisputeResponse {
    fn foreign_from(dispute: storage::Dispute) -> Self {
        Self {
            dispute_id: dispute.dispute_id,
            payment_id: dispute.payment_id,
            attempt_id: dispute.attempt_id,
            amount: dispute.amount,
            currency: dispute.dispute_currency.unwrap_or(
                dispute
                    .currency
                    .to_uppercase()
                    .parse_enum("Currency")
                    .unwrap_or_default(),
            ),
            dispute_stage: dispute.dispute_stage,
            dispute_status: dispute.dispute_status,
            connector: dispute.connector,
            connector_status: dispute.connector_status,
            connector_dispute_id: dispute.connector_dispute_id,
            connector_reason: dispute.connector_reason,
            connector_reason_code: dispute.connector_reason_code,
            challenge_required_by: dispute.challenge_required_by,
            connector_created_at: dispute.connector_created_at,
            connector_updated_at: dispute.connector_updated_at,
            created_at: dispute.created_at,
            profile_id: dispute.profile_id,
            merchant_connector_id: dispute.merchant_connector_id,
        }
    }
}

impl ForeignFrom<storage::Authorization> for payments::IncrementalAuthorizationResponse {
    fn foreign_from(authorization: storage::Authorization) -> Self {
        Self {
            authorization_id: authorization.authorization_id,
            amount: authorization.amount,
            status: authorization.status,
            error_code: authorization.error_code,
            error_message: authorization.error_message,
            previously_authorized_amount: authorization.previously_authorized_amount,
        }
    }
}

impl
    ForeignFrom<
        &hyperswitch_domain_models::router_request_types::authentication::AuthenticationStore,
    > for payments::ExternalAuthenticationDetailsResponse
{
    fn foreign_from(
        authn_store: &hyperswitch_domain_models::router_request_types::authentication::AuthenticationStore,
    ) -> Self {
        let authn_data = &authn_store.authentication;
        let version = authn_data
            .maximum_supported_version
            .as_ref()
            .map(|version| version.to_string());
        Self {
            authentication_flow: authn_data.authentication_type,
            electronic_commerce_indicator: authn_data.eci.clone(),
            status: authn_data.authentication_status,
            ds_transaction_id: authn_data.threeds_server_transaction_id.clone(),
            version,
            error_code: authn_data.error_code.clone(),
            error_message: authn_data.error_message.clone(),
        }
    }
}

impl ForeignFrom<storage::Dispute> for api_models::disputes::DisputeResponsePaymentsRetrieve {
    fn foreign_from(dispute: storage::Dispute) -> Self {
        Self {
            dispute_id: dispute.dispute_id,
            dispute_stage: dispute.dispute_stage,
            dispute_status: dispute.dispute_status,
            connector_status: dispute.connector_status,
            connector_dispute_id: dispute.connector_dispute_id,
            connector_reason: dispute.connector_reason,
            connector_reason_code: dispute.connector_reason_code,
            challenge_required_by: dispute.challenge_required_by,
            connector_created_at: dispute.connector_created_at,
            connector_updated_at: dispute.connector_updated_at,
            created_at: dispute.created_at,
        }
    }
}

impl ForeignFrom<storage::FileMetadata> for api_models::files::FileMetadataResponse {
    fn foreign_from(file_metadata: storage::FileMetadata) -> Self {
        Self {
            file_id: file_metadata.file_id,
            file_name: file_metadata.file_name,
            file_size: file_metadata.file_size,
            file_type: file_metadata.file_type,
            available: file_metadata.available,
        }
    }
}

impl ForeignFrom<diesel_models::cards_info::CardInfo> for api_models::cards_info::CardInfoResponse {
    fn foreign_from(item: diesel_models::cards_info::CardInfo) -> Self {
        Self {
            card_iin: item.card_iin,
            card_type: item.card_type,
            card_sub_type: item.card_subtype,
            card_network: item.card_network.map(|x| x.to_string()),
            card_issuer: item.card_issuer,
            card_issuing_country: item.card_issuing_country,
        }
    }
}

impl ForeignTryFrom<domain::MerchantConnectorAccount>
    for api_models::admin::MerchantConnectorListResponse
{
    type Error = error_stack::Report<errors::ApiErrorResponse>;
    fn foreign_try_from(item: domain::MerchantConnectorAccount) -> Result<Self, Self::Error> {
        #[cfg(feature = "v1")]
        let payment_methods_enabled = match item.payment_methods_enabled {
            Some(secret_val) => {
                let val = secret_val
                    .into_iter()
                    .map(|secret| secret.expose())
                    .collect();
                serde_json::Value::Array(val)
                    .parse_value("PaymentMethods")
                    .change_context(errors::ApiErrorResponse::InternalServerError)?
            }
            None => None,
        };

        let frm_configs = match item.frm_configs {
            Some(frm_value) => {
                let configs_for_frm : Vec<api_models::admin::FrmConfigs> = frm_value
                    .iter()
                    .map(|config| { config
                        .peek()
                        .clone()
                        .parse_value("FrmConfigs")
                        .change_context(errors::ApiErrorResponse::InvalidDataFormat {
                            field_name: "frm_configs".to_string(),
                            expected_format: r#"[{ "gateway": "stripe", "payment_methods": [{ "payment_method": "card","payment_method_types": [{"payment_method_type": "credit","card_networks": ["Visa"],"flow": "pre","action": "cancel_txn"}]}]}]"#.to_string(),
                        })
                    })
                    .collect::<Result<Vec<_>, _>>()?;
                Some(configs_for_frm)
            }
            None => None,
        };
        #[cfg(feature = "v1")]
        let response = Self {
            connector_type: item.connector_type,
            connector_name: item.connector_name,
            connector_label: item.connector_label,
            merchant_connector_id: item.merchant_connector_id,
            test_mode: item.test_mode,
            disabled: item.disabled,
            payment_methods_enabled,
            business_country: item.business_country,
            business_label: item.business_label,
            business_sub_label: item.business_sub_label,
            frm_configs,
            profile_id: item.profile_id,
            applepay_verified_domains: item.applepay_verified_domains,
            pm_auth_config: item.pm_auth_config,
            status: item.status,
        };
        #[cfg(feature = "v2")]
        let response = Self {
            id: item.id,
            connector_type: item.connector_type,
            connector_name: item.connector_name,
            connector_label: item.connector_label,
            disabled: item.disabled,
            payment_methods_enabled: item.payment_methods_enabled,
            frm_configs,
            profile_id: item.profile_id,
            applepay_verified_domains: item.applepay_verified_domains,
            pm_auth_config: item.pm_auth_config,
            status: item.status,
        };
        Ok(response)
    }
}

#[cfg(feature = "v1")]
impl ForeignTryFrom<domain::MerchantConnectorAccount>
    for api_models::admin::MerchantConnectorResponse
{
    type Error = error_stack::Report<errors::ApiErrorResponse>;
    fn foreign_try_from(item: domain::MerchantConnectorAccount) -> Result<Self, Self::Error> {
        let payment_methods_enabled = match item.payment_methods_enabled.clone() {
            Some(secret_val) => {
                let val = secret_val
                    .into_iter()
                    .map(|secret| secret.expose())
                    .collect();
                serde_json::Value::Array(val)
                    .parse_value("PaymentMethods")
                    .change_context(errors::ApiErrorResponse::InternalServerError)?
            }
            None => None,
        };
        let frm_configs = match item.frm_configs {
            Some(ref frm_value) => {
                let configs_for_frm : Vec<api_models::admin::FrmConfigs> = frm_value
                    .iter()
                    .map(|config| { config
                        .peek()
                        .clone()
                        .parse_value("FrmConfigs")
                        .change_context(errors::ApiErrorResponse::InvalidDataFormat {
                            field_name: "frm_configs".to_string(),


pub struct StaxRouterData<T> {
    pub amount: f64,
    pub router_data: T,
}


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


pub fn set_cookie_response<R>(response: R, token: Secret<String>) -> UserResponse<R> {
    let jwt_expiry_in_seconds = JWT_TOKEN_TIME_IN_SECS
        .try_into()
        .map_err(|_| UserErrors::InternalServerError)?;
    let (expiry, max_age) = get_expiry_and_max_age_from_seconds(jwt_expiry_in_seconds);

    let header_value = create_cookie(token, expiry, max_age)
        .to_string()
        .into_masked();
    let header_key = get_set_cookie_header();
    let header = vec![(header_key, header_value)];

    Ok(ApplicationResponse::JsonWithHeaders((response, header)))
}


pub struct AccessTokenErrorResponse {
    pub cause: String,
    pub description: String,
}


pub struct CardParams {
    pub card: AuthResult,
}