mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 11:24:45 +08:00
feat(core): [Retry] MIT Retries (#8628)
This commit is contained in:
@ -14,6 +14,8 @@ use common_utils::{
|
||||
use error_stack::ResultExt;
|
||||
use time::PrimitiveDateTime;
|
||||
|
||||
use crate::router_data::RecurringMandatePaymentData;
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct MandateDetails {
|
||||
@ -174,6 +176,20 @@ pub struct PaymentsMandateReferenceRecord {
|
||||
pub connector_mandate_request_reference_id: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
impl From<&PaymentsMandateReferenceRecord> for RecurringMandatePaymentData {
|
||||
fn from(mandate_reference_record: &PaymentsMandateReferenceRecord) -> Self {
|
||||
Self {
|
||||
payment_method_type: mandate_reference_record.payment_method_type,
|
||||
original_payment_authorized_amount: mandate_reference_record
|
||||
.original_payment_authorized_amount,
|
||||
original_payment_authorized_currency: mandate_reference_record
|
||||
.original_payment_authorized_currency,
|
||||
mandate_metadata: mandate_reference_record.mandate_metadata.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ConnectorTokenReferenceRecord {
|
||||
|
||||
@ -693,7 +693,7 @@ fn process_connector_for_networks(
|
||||
let matching_networks = find_matching_networks(
|
||||
&merchant_debit_networks,
|
||||
fee_sorted_debit_networks,
|
||||
&connector_data.connector_data,
|
||||
connector_data,
|
||||
debit_routing_config,
|
||||
has_us_local_network,
|
||||
);
|
||||
@ -715,13 +715,13 @@ fn find_merchant_connector_account(
|
||||
fn find_matching_networks(
|
||||
merchant_debit_networks: &HashSet<common_enums::CardNetwork>,
|
||||
fee_sorted_debit_networks: &[common_enums::CardNetwork],
|
||||
connector_data: &api::ConnectorData,
|
||||
connector_routing_data: &api::ConnectorRoutingData,
|
||||
debit_routing_config: &settings::DebitRoutingConfig,
|
||||
has_us_local_network: &mut bool,
|
||||
) -> Vec<api::ConnectorRoutingData> {
|
||||
let is_routing_enabled = debit_routing_config
|
||||
.supported_connectors
|
||||
.contains(&connector_data.connector_name);
|
||||
.contains(&connector_routing_data.connector_data.connector_name.clone());
|
||||
|
||||
fee_sorted_debit_networks
|
||||
.iter()
|
||||
@ -733,8 +733,9 @@ fn find_matching_networks(
|
||||
}
|
||||
|
||||
api::ConnectorRoutingData {
|
||||
connector_data: connector_data.clone(),
|
||||
connector_data: connector_routing_data.connector_data.clone(),
|
||||
network: Some(network.clone()),
|
||||
action_type: connector_routing_data.action_type.clone(),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
||||
@ -8981,88 +8981,64 @@ where
|
||||
.get_required_value("payment_method_info")?
|
||||
.clone();
|
||||
|
||||
//fetch connectors that support ntid flow
|
||||
let ntid_supported_connectors = &state
|
||||
.conf
|
||||
.network_transaction_id_supported_connectors
|
||||
.connector_list;
|
||||
//filered connectors list with ntid_supported_connectors
|
||||
let filtered_ntid_supported_connectors =
|
||||
filter_ntid_supported_connectors(connectors.clone(), ntid_supported_connectors);
|
||||
let retryable_connectors =
|
||||
join_all(connectors.into_iter().map(|connector_routing_data| {
|
||||
let payment_method = payment_method_info.clone();
|
||||
async move {
|
||||
let action_types = get_all_action_types(
|
||||
state,
|
||||
is_connector_agnostic_mit_enabled,
|
||||
is_network_tokenization_enabled,
|
||||
&payment_method.clone(),
|
||||
connector_routing_data.connector_data.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
//fetch connectors that support network tokenization flow
|
||||
let network_tokenization_supported_connectors = &state
|
||||
.conf
|
||||
.network_tokenization_supported_connectors
|
||||
.connector_list;
|
||||
//filered connectors list with ntid_supported_connectors and network_tokenization_supported_connectors
|
||||
let filtered_nt_supported_connectors = filter_network_tokenization_supported_connectors(
|
||||
filtered_ntid_supported_connectors,
|
||||
network_tokenization_supported_connectors,
|
||||
action_types
|
||||
.into_iter()
|
||||
.map(|action_type| api::ConnectorRoutingData {
|
||||
connector_data: connector_routing_data.connector_data.clone(),
|
||||
action_type: Some(action_type),
|
||||
network: connector_routing_data.network.clone(),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}))
|
||||
.await
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let chosen_connector_routing_data = retryable_connectors
|
||||
.first()
|
||||
.ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)
|
||||
.attach_printable("no eligible connector found for token-based MIT payment")?;
|
||||
|
||||
let mandate_reference_id = get_mandate_reference_id(
|
||||
chosen_connector_routing_data.action_type.clone(),
|
||||
chosen_connector_routing_data.clone(),
|
||||
payment_data,
|
||||
&payment_method_info,
|
||||
)?;
|
||||
|
||||
routing_data.routed_through = Some(
|
||||
chosen_connector_routing_data
|
||||
.connector_data
|
||||
.connector_name
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
let action_type = decide_action_type(
|
||||
state,
|
||||
is_connector_agnostic_mit_enabled,
|
||||
is_network_tokenization_enabled,
|
||||
&payment_method_info,
|
||||
filtered_nt_supported_connectors.clone(),
|
||||
)
|
||||
.await;
|
||||
routing_data.merchant_connector_id.clone_from(
|
||||
&chosen_connector_routing_data
|
||||
.connector_data
|
||||
.merchant_connector_id,
|
||||
);
|
||||
|
||||
match action_type {
|
||||
Some(ActionType::NetworkTokenWithNetworkTransactionId(nt_data)) => {
|
||||
logger::info!(
|
||||
"using network_tokenization with network_transaction_id for MIT flow"
|
||||
);
|
||||
|
||||
let mandate_reference_id =
|
||||
Some(payments_api::MandateReferenceId::NetworkTokenWithNTI(
|
||||
payments_api::NetworkTokenWithNTIRef {
|
||||
network_transaction_id: nt_data.network_transaction_id.to_string(),
|
||||
token_exp_month: nt_data.token_exp_month,
|
||||
token_exp_year: nt_data.token_exp_year,
|
||||
},
|
||||
));
|
||||
let chosen_connector_data = filtered_nt_supported_connectors
|
||||
.first()
|
||||
.ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)
|
||||
.attach_printable(
|
||||
"no eligible connector found for token-based MIT payment",
|
||||
)?;
|
||||
|
||||
routing_data.routed_through = Some(
|
||||
chosen_connector_data
|
||||
.connector_data
|
||||
.connector_name
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
routing_data
|
||||
.merchant_connector_id
|
||||
.clone_from(&chosen_connector_data.connector_data.merchant_connector_id);
|
||||
|
||||
payment_data.set_mandate_id(payments_api::MandateIds {
|
||||
mandate_id: None,
|
||||
mandate_reference_id,
|
||||
});
|
||||
|
||||
Ok(ConnectorCallType::PreDetermined(
|
||||
chosen_connector_data.clone(),
|
||||
))
|
||||
}
|
||||
None => {
|
||||
decide_connector_for_normal_or_recurring_payment(
|
||||
state,
|
||||
payment_data,
|
||||
routing_data,
|
||||
connectors,
|
||||
is_connector_agnostic_mit_enabled,
|
||||
&payment_method_info,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
payment_data.set_mandate_id(payments_api::MandateIds {
|
||||
mandate_id: None,
|
||||
mandate_reference_id,
|
||||
});
|
||||
Ok(ConnectorCallType::Retryable(retryable_connectors))
|
||||
}
|
||||
(
|
||||
None,
|
||||
@ -9112,6 +9088,78 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
pub fn get_mandate_reference_id<F: Clone, D>(
|
||||
action_type: Option<ActionType>,
|
||||
connector_routing_data: api::ConnectorRoutingData,
|
||||
payment_data: &mut D,
|
||||
payment_method_info: &domain::PaymentMethod,
|
||||
) -> RouterResult<Option<api_models::payments::MandateReferenceId>>
|
||||
where
|
||||
D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
|
||||
{
|
||||
let mandate_reference_id = match action_type {
|
||||
Some(ActionType::NetworkTokenWithNetworkTransactionId(network_token_data)) => {
|
||||
logger::info!("using network token with network_transaction_id for MIT flow");
|
||||
|
||||
Some(payments_api::MandateReferenceId::NetworkTokenWithNTI(
|
||||
network_token_data.into(),
|
||||
))
|
||||
}
|
||||
Some(ActionType::CardWithNetworkTransactionId(network_transaction_id)) => {
|
||||
logger::info!("using card with network_transaction_id for MIT flow");
|
||||
|
||||
Some(payments_api::MandateReferenceId::NetworkMandateId(
|
||||
network_transaction_id,
|
||||
))
|
||||
}
|
||||
Some(ActionType::ConnectorMandate(connector_mandate_details)) => {
|
||||
logger::info!("using connector_mandate_id for MIT flow");
|
||||
let merchant_connector_id = connector_routing_data
|
||||
.connector_data
|
||||
.merchant_connector_id
|
||||
.as_ref()
|
||||
.ok_or_else(|| {
|
||||
report!(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)
|
||||
.attach_printable("No eligible connector found for token-based MIT flow: no connector mandate details")
|
||||
})?;
|
||||
|
||||
let mandate_reference_record = connector_mandate_details
|
||||
.get(merchant_connector_id)
|
||||
.ok_or_else(|| {
|
||||
report!(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)
|
||||
.attach_printable("No mandate record found for merchant connector ID")
|
||||
})?;
|
||||
|
||||
if let Some(mandate_currency) =
|
||||
mandate_reference_record.original_payment_authorized_currency
|
||||
{
|
||||
if mandate_currency != payment_data.get_currency() {
|
||||
return Err(report!(errors::ApiErrorResponse::MandateValidationFailed {
|
||||
reason: "Cross currency mandates not supported".into(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
payment_data.set_recurring_mandate_payment_data(mandate_reference_record.into());
|
||||
|
||||
Some(payments_api::MandateReferenceId::ConnectorMandateId(
|
||||
api_models::payments::ConnectorMandateReferenceId::new(
|
||||
Some(mandate_reference_record.connector_mandate_id.clone()),
|
||||
Some(payment_method_info.get_id().clone()),
|
||||
None,
|
||||
mandate_reference_record.mandate_metadata.clone(),
|
||||
mandate_reference_record
|
||||
.connector_mandate_request_reference_id
|
||||
.clone(),
|
||||
),
|
||||
))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
Ok(mandate_reference_id)
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn decide_connector_for_normal_or_recurring_payment<F: Clone, D>(
|
||||
@ -9178,16 +9226,8 @@ where
|
||||
)
|
||||
));
|
||||
payment_data.set_recurring_mandate_payment_data(
|
||||
hyperswitch_domain_models::router_data::RecurringMandatePaymentData {
|
||||
payment_method_type: mandate_reference_record
|
||||
.payment_method_type,
|
||||
original_payment_authorized_amount: mandate_reference_record
|
||||
.original_payment_authorized_amount,
|
||||
original_payment_authorized_currency: mandate_reference_record
|
||||
.original_payment_authorized_currency,
|
||||
mandate_metadata: mandate_reference_record
|
||||
.mandate_metadata.clone()
|
||||
});
|
||||
mandate_reference_record.into(),
|
||||
);
|
||||
connector_choice = Some((connector_data, mandate_reference_id.clone()));
|
||||
break;
|
||||
}
|
||||
@ -9260,9 +9300,23 @@ pub struct NTWithNTIRef {
|
||||
pub token_exp_year: Option<Secret<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, Eq, PartialEq)]
|
||||
impl From<NTWithNTIRef> for payments_api::NetworkTokenWithNTIRef {
|
||||
fn from(network_token_data: NTWithNTIRef) -> Self {
|
||||
Self {
|
||||
network_transaction_id: network_token_data.network_transaction_id,
|
||||
token_exp_month: network_token_data.token_exp_month,
|
||||
token_exp_year: network_token_data.token_exp_year,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This represents the recurring details of a connector which will be used for retries
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub enum ActionType {
|
||||
NetworkTokenWithNetworkTransactionId(NTWithNTIRef),
|
||||
CardWithNetworkTransactionId(String), // Network Transaction Id
|
||||
#[cfg(feature = "v1")]
|
||||
ConnectorMandate(hyperswitch_domain_models::mandates::PaymentsMandateReference),
|
||||
}
|
||||
|
||||
pub fn filter_network_tokenization_supported_connectors(
|
||||
@ -9278,40 +9332,154 @@ pub fn filter_network_tokenization_supported_connectors(
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
pub async fn decide_action_type(
|
||||
#[derive(Default)]
|
||||
pub struct ActionTypesBuilder {
|
||||
action_types: Vec<ActionType>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
impl ActionTypesBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
action_types: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_mandate_flow(
|
||||
mut self,
|
||||
is_mandate_flow: bool,
|
||||
connector_mandate_details: Option<
|
||||
hyperswitch_domain_models::mandates::PaymentsMandateReference,
|
||||
>,
|
||||
) -> Self {
|
||||
if is_mandate_flow {
|
||||
self.action_types.extend(
|
||||
connector_mandate_details
|
||||
.map(|details| ActionType::ConnectorMandate(details.to_owned())),
|
||||
);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn with_network_tokenization(
|
||||
mut self,
|
||||
state: &SessionState,
|
||||
is_network_token_with_ntid_flow: IsNtWithNtiFlow,
|
||||
is_nt_with_ntid_supported_connector: bool,
|
||||
payment_method_info: &domain::PaymentMethod,
|
||||
) -> Self {
|
||||
match is_network_token_with_ntid_flow {
|
||||
IsNtWithNtiFlow::NtWithNtiSupported(network_transaction_id)
|
||||
if is_nt_with_ntid_supported_connector =>
|
||||
{
|
||||
self.action_types.extend(
|
||||
network_tokenization::do_status_check_for_network_token(
|
||||
state,
|
||||
payment_method_info,
|
||||
)
|
||||
.await
|
||||
.inspect_err(|e| {
|
||||
logger::error!("Status check for network token failed: {:?}", e)
|
||||
})
|
||||
.ok()
|
||||
.map(|(token_exp_month, token_exp_year)| {
|
||||
ActionType::NetworkTokenWithNetworkTransactionId(NTWithNTIRef {
|
||||
token_exp_month,
|
||||
token_exp_year,
|
||||
network_transaction_id,
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_card_network_transaction_id(
|
||||
mut self,
|
||||
is_card_with_ntid_flow: bool,
|
||||
payment_method_info: &domain::PaymentMethod,
|
||||
) -> Self {
|
||||
if is_card_with_ntid_flow {
|
||||
self.action_types.extend(
|
||||
payment_method_info
|
||||
.network_transaction_id
|
||||
.as_ref()
|
||||
.map(|ntid| ActionType::CardWithNetworkTransactionId(ntid.clone())),
|
||||
);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Vec<ActionType> {
|
||||
self.action_types
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
pub async fn get_all_action_types(
|
||||
state: &SessionState,
|
||||
is_connector_agnostic_mit_enabled: Option<bool>,
|
||||
is_network_tokenization_enabled: bool,
|
||||
payment_method_info: &domain::PaymentMethod,
|
||||
filtered_nt_supported_connectors: Vec<api::ConnectorRoutingData>, //network tokenization supported connectors
|
||||
) -> Option<ActionType> {
|
||||
match (
|
||||
is_network_token_with_network_transaction_id_flow(
|
||||
is_connector_agnostic_mit_enabled,
|
||||
is_network_tokenization_enabled,
|
||||
connector: api::ConnectorData,
|
||||
) -> Vec<ActionType> {
|
||||
let merchant_connector_id = connector.merchant_connector_id.as_ref();
|
||||
|
||||
//fetch connectors that support ntid flow
|
||||
let ntid_supported_connectors = &state
|
||||
.conf
|
||||
.network_transaction_id_supported_connectors
|
||||
.connector_list;
|
||||
|
||||
//fetch connectors that support network tokenization flow
|
||||
let network_tokenization_supported_connectors = &state
|
||||
.conf
|
||||
.network_tokenization_supported_connectors
|
||||
.connector_list;
|
||||
|
||||
let is_network_token_with_ntid_flow = is_network_token_with_network_transaction_id_flow(
|
||||
is_connector_agnostic_mit_enabled,
|
||||
is_network_tokenization_enabled,
|
||||
payment_method_info,
|
||||
);
|
||||
let is_card_with_ntid_flow = is_network_transaction_id_flow(
|
||||
state,
|
||||
is_connector_agnostic_mit_enabled,
|
||||
connector.connector_name,
|
||||
payment_method_info,
|
||||
);
|
||||
let payments_mandate_reference = payment_method_info
|
||||
.get_common_mandate_reference()
|
||||
.map_err(|err| {
|
||||
logger::warn!("Error getting connector mandate details: {:?}", err);
|
||||
err
|
||||
})
|
||||
.ok()
|
||||
.and_then(|details| details.payments);
|
||||
|
||||
let is_mandate_flow = payments_mandate_reference
|
||||
.clone()
|
||||
.zip(merchant_connector_id)
|
||||
.map(|(details, merchant_connector_id)| details.contains_key(merchant_connector_id))
|
||||
.unwrap_or(false);
|
||||
|
||||
let is_nt_with_ntid_supported_connector = ntid_supported_connectors
|
||||
.contains(&connector.connector_name)
|
||||
&& network_tokenization_supported_connectors.contains(&connector.connector_name);
|
||||
|
||||
ActionTypesBuilder::new()
|
||||
.with_mandate_flow(is_mandate_flow, payments_mandate_reference)
|
||||
.with_network_tokenization(
|
||||
state,
|
||||
is_network_token_with_ntid_flow,
|
||||
is_nt_with_ntid_supported_connector,
|
||||
payment_method_info,
|
||||
),
|
||||
!filtered_nt_supported_connectors.is_empty(),
|
||||
) {
|
||||
(IsNtWithNtiFlow::NtWithNtiSupported(network_transaction_id), true) => {
|
||||
if let Ok((token_exp_month, token_exp_year)) =
|
||||
network_tokenization::do_status_check_for_network_token(state, payment_method_info)
|
||||
.await
|
||||
{
|
||||
Some(ActionType::NetworkTokenWithNetworkTransactionId(
|
||||
NTWithNTIRef {
|
||||
token_exp_month,
|
||||
token_exp_year,
|
||||
network_transaction_id,
|
||||
},
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
(IsNtWithNtiFlow::NtWithNtiSupported(_), false)
|
||||
| (IsNtWithNtiFlow::NTWithNTINotSupported, _) => None,
|
||||
}
|
||||
)
|
||||
.await
|
||||
.with_card_network_transaction_id(is_card_with_ntid_flow, payment_method_info)
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn is_network_transaction_id_flow(
|
||||
|
||||
@ -3,6 +3,7 @@ use std::vec::IntoIter;
|
||||
use common_utils::{ext_traits::Encode, types::MinorUnit};
|
||||
use diesel_models::enums as storage_enums;
|
||||
use error_stack::ResultExt;
|
||||
use hyperswitch_domain_models::ext_traits::OptionExt;
|
||||
use router_env::{
|
||||
logger,
|
||||
tracing::{self, instrument},
|
||||
@ -159,7 +160,31 @@ where
|
||||
&& clear_pan_possible
|
||||
&& business_profile.is_clear_pan_retries_enabled;
|
||||
|
||||
let (connector, routing_decision) = if should_retry_with_pan {
|
||||
// Currently we are taking off_session as a source of truth to identify MIT payments.
|
||||
let is_mit_payment = payment_data
|
||||
.get_payment_intent()
|
||||
.off_session
|
||||
.unwrap_or(false);
|
||||
|
||||
let (connector, routing_decision) = if is_mit_payment {
|
||||
let connector_routing_data =
|
||||
super::get_connector_data(&mut connector_routing_data)?;
|
||||
let payment_method_info = payment_data
|
||||
.get_payment_method_info()
|
||||
.get_required_value("payment_method_info")?
|
||||
.clone();
|
||||
let mandate_reference_id = payments::get_mandate_reference_id(
|
||||
connector_routing_data.action_type.clone(),
|
||||
connector_routing_data.clone(),
|
||||
payment_data,
|
||||
&payment_method_info,
|
||||
)?;
|
||||
payment_data.set_mandate_id(api_models::payments::MandateIds {
|
||||
mandate_id: None,
|
||||
mandate_reference_id, //mandate_ref_id
|
||||
});
|
||||
(connector_routing_data.connector_data, None)
|
||||
} else if should_retry_with_pan {
|
||||
// If should_retry_with_pan is true, it indicates that we are retrying with PAN using the same connector.
|
||||
(original_connector_data.clone(), None)
|
||||
} else {
|
||||
|
||||
@ -107,6 +107,7 @@ impl From<ConnectorData> for ConnectorRoutingData {
|
||||
Self {
|
||||
connector_data,
|
||||
network: None,
|
||||
action_type: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,11 @@ pub use super::fraud_check_v2::{
|
||||
FraudCheckTransactionV2, FraudCheckV2,
|
||||
};
|
||||
use super::{ConnectorData, SessionConnectorDatas};
|
||||
use crate::{connector, core::errors, services::connector_integration_interface::ConnectorEnum};
|
||||
use crate::{
|
||||
connector,
|
||||
core::{errors, payments::ActionType},
|
||||
services::connector_integration_interface::ConnectorEnum,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FraudCheckConnectorData {
|
||||
@ -33,6 +37,8 @@ pub enum ConnectorCallType {
|
||||
pub struct ConnectorRoutingData {
|
||||
pub connector_data: ConnectorData,
|
||||
pub network: Option<common_enums::CardNetwork>,
|
||||
// action_type is used for mandates currently
|
||||
pub action_type: Option<ActionType>,
|
||||
}
|
||||
|
||||
impl FraudCheckConnectorData {
|
||||
|
||||
Reference in New Issue
Block a user