Skip to content

Commit

Permalink
feat(router): add NTID flow for cybersource (#4193)
Browse files Browse the repository at this point in the history
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
  • Loading branch information
ShankarSinghC and hyperswitch-bot[bot] authored Apr 4, 2024
1 parent 02ffe7e commit 071462f
Showing 1 changed file with 134 additions and 38 deletions.
172 changes: 134 additions & 38 deletions crates/router/src/connector/cybersource/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
}
Expand All @@ -314,6 +315,7 @@ pub struct CybersourcePaymentInitiator {
#[serde(rename_all = "camelCase")]
pub enum CybersourcePaymentInitiatorTypes {
Customer,
Merchant,
}

#[derive(Debug, Serialize)]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -531,44 +551,113 @@ impl
merchant_intitiated_transaction: None,
}),
)
} else if item.router_data.request.connector_mandate_id().is_some() {
let original_amount = item
.router_data
.get_recurring_mandate_payment_data()?
.get_original_payment_amount()?;
let original_currency = item
} else if item.router_data.request.mandate_id.is_some() {
match 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,
Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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,
}),
}),
Expand Down Expand Up @@ -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>,
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2281,6 +2372,7 @@ impl<F>
}
}

// zero dollar response
impl<F, T>
TryFrom<
types::ResponseRouterData<
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 071462f

Please sign in to comment.