mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 04:04:55 +08:00
feat(router): add NTID flow for cybersource (#4193)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -297,6 +297,7 @@ pub struct CybersourceAuthorizationOptions {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MerchantInitiatedTransaction {
|
||||
reason: Option<String>,
|
||||
previous_transaction_id: Option<Secret<String>>,
|
||||
//Required for recurring mandates payment
|
||||
original_authorized_amount: Option<String>,
|
||||
}
|
||||
@ -314,6 +315,7 @@ pub struct CybersourcePaymentInitiator {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum CybersourcePaymentInitiatorTypes {
|
||||
Customer,
|
||||
Merchant,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
@ -503,6 +505,24 @@ impl
|
||||
Option<String>,
|
||||
),
|
||||
) -> Result<Self, Self::Error> {
|
||||
let mut commerce_indicator = solution
|
||||
.as_ref()
|
||||
.map(|pm_solution| match pm_solution {
|
||||
PaymentSolution::ApplePay => network
|
||||
.as_ref()
|
||||
.map(|card_network| match card_network.to_lowercase().as_str() {
|
||||
"amex" => "aesk",
|
||||
"discover" => "dipb",
|
||||
"mastercard" => "spa",
|
||||
"visa" => "internet",
|
||||
_ => "internet",
|
||||
})
|
||||
.unwrap_or("internet"),
|
||||
PaymentSolution::GooglePay => "internet",
|
||||
})
|
||||
.unwrap_or("internet")
|
||||
.to_string();
|
||||
|
||||
let (action_list, action_token_types, authorization_options) = if item
|
||||
.router_data
|
||||
.request
|
||||
@ -531,44 +551,113 @@ impl
|
||||
merchant_intitiated_transaction: None,
|
||||
}),
|
||||
)
|
||||
} else if item.router_data.request.connector_mandate_id().is_some() {
|
||||
let original_amount = item
|
||||
} else if item.router_data.request.mandate_id.is_some() {
|
||||
match item
|
||||
.router_data
|
||||
.get_recurring_mandate_payment_data()?
|
||||
.get_original_payment_amount()?;
|
||||
let original_currency = item
|
||||
.router_data
|
||||
.get_recurring_mandate_payment_data()?
|
||||
.get_original_payment_currency()?;
|
||||
(
|
||||
None,
|
||||
None,
|
||||
Some(CybersourceAuthorizationOptions {
|
||||
initiator: None,
|
||||
merchant_intitiated_transaction: Some(MerchantInitiatedTransaction {
|
||||
reason: None,
|
||||
original_authorized_amount: Some(utils::get_amount_as_string(
|
||||
&types::api::CurrencyUnit::Base,
|
||||
original_amount,
|
||||
original_currency,
|
||||
)?),
|
||||
}),
|
||||
}),
|
||||
)
|
||||
.request
|
||||
.mandate_id
|
||||
.clone()
|
||||
.and_then(|mandate_id| mandate_id.mandate_reference_id)
|
||||
{
|
||||
Some(api_models::payments::MandateReferenceId::ConnectorMandateId(_)) => {
|
||||
let original_amount = item
|
||||
.router_data
|
||||
.get_recurring_mandate_payment_data()?
|
||||
.get_original_payment_amount()?;
|
||||
let original_currency = item
|
||||
.router_data
|
||||
.get_recurring_mandate_payment_data()?
|
||||
.get_original_payment_currency()?;
|
||||
(
|
||||
None,
|
||||
None,
|
||||
Some(CybersourceAuthorizationOptions {
|
||||
initiator: None,
|
||||
merchant_intitiated_transaction: Some(MerchantInitiatedTransaction {
|
||||
reason: None,
|
||||
original_authorized_amount: Some(utils::get_amount_as_string(
|
||||
&types::api::CurrencyUnit::Base,
|
||||
original_amount,
|
||||
original_currency,
|
||||
)?),
|
||||
previous_transaction_id: None,
|
||||
}),
|
||||
}),
|
||||
)
|
||||
}
|
||||
Some(api_models::payments::MandateReferenceId::NetworkMandateId(
|
||||
network_transaction_id,
|
||||
)) => {
|
||||
let (original_amount, original_currency) = match network
|
||||
.clone()
|
||||
.map(|network| network.to_lowercase())
|
||||
.as_deref()
|
||||
{
|
||||
Some("discover") => {
|
||||
let original_amount = Some(
|
||||
item.router_data
|
||||
.get_recurring_mandate_payment_data()?
|
||||
.get_original_payment_amount()?,
|
||||
);
|
||||
let original_currency = Some(
|
||||
item.router_data
|
||||
.get_recurring_mandate_payment_data()?
|
||||
.get_original_payment_currency()?,
|
||||
);
|
||||
(original_amount, original_currency)
|
||||
}
|
||||
_ => {
|
||||
let original_amount = item
|
||||
.router_data
|
||||
.recurring_mandate_payment_data
|
||||
.as_ref()
|
||||
.and_then(|recurring_mandate_payment_data| {
|
||||
recurring_mandate_payment_data
|
||||
.original_payment_authorized_amount
|
||||
});
|
||||
|
||||
let original_currency = item
|
||||
.router_data
|
||||
.recurring_mandate_payment_data
|
||||
.as_ref()
|
||||
.and_then(|recurring_mandate_payment_data| {
|
||||
recurring_mandate_payment_data
|
||||
.original_payment_authorized_currency
|
||||
});
|
||||
|
||||
(original_amount, original_currency)
|
||||
}
|
||||
};
|
||||
|
||||
let original_authorized_amount = match (original_amount, original_currency) {
|
||||
(Some(original_amount), Some(original_currency)) => Some(
|
||||
utils::to_currency_base_unit(original_amount, original_currency)?,
|
||||
),
|
||||
_ => None,
|
||||
};
|
||||
commerce_indicator = "recurring".to_string();
|
||||
(
|
||||
None,
|
||||
None,
|
||||
Some(CybersourceAuthorizationOptions {
|
||||
initiator: Some(CybersourcePaymentInitiator {
|
||||
initiator_type: Some(CybersourcePaymentInitiatorTypes::Merchant),
|
||||
credential_stored_on_file: None,
|
||||
stored_credential_used: Some(true),
|
||||
}),
|
||||
merchant_intitiated_transaction: Some(MerchantInitiatedTransaction {
|
||||
reason: Some("7".to_string()),
|
||||
original_authorized_amount,
|
||||
previous_transaction_id: Some(Secret::new(network_transaction_id)),
|
||||
}),
|
||||
}),
|
||||
)
|
||||
}
|
||||
None => (None, None, None),
|
||||
}
|
||||
} else {
|
||||
(None, None, None)
|
||||
};
|
||||
let commerce_indicator = match network {
|
||||
Some(card_network) => match card_network.to_lowercase().as_str() {
|
||||
"amex" => "aesk",
|
||||
"discover" => "dipb",
|
||||
"mastercard" => "spa",
|
||||
"visa" => "internet",
|
||||
_ => "internet",
|
||||
},
|
||||
None => "internet",
|
||||
}
|
||||
.to_string();
|
||||
Ok(Self {
|
||||
capture: Some(matches!(
|
||||
item.router_data.request.capture_method,
|
||||
@ -754,11 +843,11 @@ impl
|
||||
expiration_month: ccard.card_exp_month,
|
||||
expiration_year: ccard.card_exp_year,
|
||||
security_code: ccard.card_cvc,
|
||||
card_type,
|
||||
card_type: card_type.clone(),
|
||||
},
|
||||
});
|
||||
|
||||
let processing_information = ProcessingInformation::try_from((item, None, None))?;
|
||||
let processing_information = ProcessingInformation::try_from((item, None, card_type))?;
|
||||
let client_reference_information = ClientReferenceInformation::from(item);
|
||||
let merchant_defined_information =
|
||||
item.router_data.request.metadata.clone().map(|metadata| {
|
||||
@ -1287,6 +1376,7 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsIncrementalAuthorizationRout
|
||||
}),
|
||||
merchant_intitiated_transaction: Some(MerchantInitiatedTransaction {
|
||||
reason: Some("5".to_owned()),
|
||||
previous_transaction_id: None,
|
||||
original_authorized_amount: None,
|
||||
}),
|
||||
}),
|
||||
@ -1537,6 +1627,7 @@ pub struct ClientReferenceInformation {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClientProcessorInformation {
|
||||
network_transaction_id: Option<String>,
|
||||
avs: Option<Avs>,
|
||||
}
|
||||
|
||||
@ -1667,7 +1758,7 @@ fn get_payment_response(
|
||||
.processor_information
|
||||
.as_ref()
|
||||
.map(|processor_information| serde_json::json!({"avs_response": processor_information.avs})),
|
||||
network_txn_id: None,
|
||||
network_txn_id: info_response.processor_information.as_ref().and_then(|processor_information| processor_information.network_transaction_id.clone()),
|
||||
connector_response_reference_id: Some(
|
||||
info_response
|
||||
.client_reference_information
|
||||
@ -2281,6 +2372,7 @@ impl<F>
|
||||
}
|
||||
}
|
||||
|
||||
// zero dollar response
|
||||
impl<F, T>
|
||||
TryFrom<
|
||||
types::ResponseRouterData<
|
||||
@ -2328,7 +2420,11 @@ impl<F, T>
|
||||
redirection_data: None,
|
||||
mandate_reference,
|
||||
connector_metadata: None,
|
||||
network_txn_id: None,
|
||||
network_txn_id: info_response.processor_information.as_ref().and_then(
|
||||
|processor_information| {
|
||||
processor_information.network_transaction_id.clone()
|
||||
},
|
||||
),
|
||||
connector_response_reference_id: Some(
|
||||
info_response
|
||||
.client_reference_information
|
||||
|
||||
Reference in New Issue
Block a user