Skip to content

Commit 46709ae

Browse files
Anurag-05-progAnurag Singhhyperswitch-bot[bot]AkshayaFoiger
authored
feat(connector): add click to pay feature for trustpay (#8304)
Co-authored-by: Anurag Singh <[email protected]> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: AkshayaFoiger <[email protected]>
1 parent 44d93e5 commit 46709ae

File tree

2 files changed

+101
-3
lines changed

2 files changed

+101
-3
lines changed

crates/hyperswitch_connectors/src/connectors/trustpay/transformers.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use common_utils::{
1010
};
1111
use error_stack::{report, ResultExt};
1212
use hyperswitch_domain_models::{
13+
network_tokenization::NetworkTokenNumber,
1314
payment_method_data::{BankRedirectData, BankTransferData, Card, PaymentMethodData},
1415
router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
1516
router_request_types::{BrowserInformation, PaymentsPreProcessingData, ResponseId},
@@ -29,8 +30,9 @@ use serde::{Deserialize, Serialize};
2930
use crate::{
3031
types::{RefundsResponseRouterData, ResponseRouterData},
3132
utils::{
32-
self, AddressDetailsData, BrowserInformationData, CardData, PaymentsAuthorizeRequestData,
33-
PaymentsPreProcessingRequestData, RouterData as OtherRouterData,
33+
self, AddressDetailsData, BrowserInformationData, CardData, NetworkTokenData,
34+
PaymentsAuthorizeRequestData, PaymentsPreProcessingRequestData,
35+
RouterData as OtherRouterData,
3436
},
3537
};
3638

@@ -226,6 +228,26 @@ pub enum TrustpayPaymentsRequest {
226228
CardsPaymentRequest(Box<PaymentRequestCards>),
227229
BankRedirectPaymentRequest(Box<PaymentRequestBankRedirect>),
228230
BankTransferPaymentRequest(Box<PaymentRequestBankTransfer>),
231+
NetworkTokenPaymentRequest(Box<PaymentRequestNetworkToken>),
232+
}
233+
234+
#[derive(Debug, Serialize, PartialEq)]
235+
pub struct PaymentRequestNetworkToken {
236+
pub amount: StringMajorUnit,
237+
pub currency: enums::Currency,
238+
pub pan: NetworkTokenNumber,
239+
#[serde(rename = "exp")]
240+
pub expiry_date: Secret<String>,
241+
#[serde(rename = "RedirectUrl")]
242+
pub redirect_url: String,
243+
#[serde(rename = "threeDSecureEnrollmentStatus")]
244+
pub enrollment_status: char,
245+
#[serde(rename = "threeDSecureEci")]
246+
pub eci: String,
247+
#[serde(rename = "threeDSecureAuthenticationStatus")]
248+
pub authentication_status: char,
249+
#[serde(rename = "threeDSecureVerificationId")]
250+
pub verification_id: Secret<String>,
229251
}
230252

231253
#[derive(Debug, Serialize, PartialEq)]
@@ -538,6 +560,28 @@ impl TryFrom<&TrustpayRouterData<&PaymentsAuthorizeRouterData>> for TrustpayPaym
538560
auth,
539561
)
540562
}
563+
PaymentMethodData::NetworkToken(ref token_data) => {
564+
Ok(Self::NetworkTokenPaymentRequest(Box::new(
565+
PaymentRequestNetworkToken {
566+
amount: item.amount.to_owned(),
567+
currency: item.router_data.request.currency,
568+
pan: token_data.get_network_token(),
569+
expiry_date: token_data
570+
.get_token_expiry_month_year_2_digit_with_delimiter("/".to_owned())?,
571+
redirect_url: item.router_data.request.get_router_return_url()?,
572+
enrollment_status: 'Y', // Set to 'Y' as network provider not providing this value in response
573+
eci: token_data.eci.clone().ok_or_else(|| {
574+
errors::ConnectorError::MissingRequiredField { field_name: "eci" }
575+
})?,
576+
authentication_status: 'Y', // Set to 'Y' since presence of token_cryptogram is already validated
577+
verification_id: token_data.get_cryptogram().ok_or_else(|| {
578+
errors::ConnectorError::MissingRequiredField {
579+
field_name: "verification_id",
580+
}
581+
})?,
582+
},
583+
)))
584+
}
541585
PaymentMethodData::CardRedirect(_)
542586
| PaymentMethodData::Wallet(_)
543587
| PaymentMethodData::PayLater(_)
@@ -552,7 +596,6 @@ impl TryFrom<&TrustpayRouterData<&PaymentsAuthorizeRouterData>> for TrustpayPaym
552596
| PaymentMethodData::GiftCard(_)
553597
| PaymentMethodData::OpenBanking(_)
554598
| PaymentMethodData::CardToken(_)
555-
| PaymentMethodData::NetworkToken(_)
556599
| PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
557600
Err(errors::ConnectorError::NotImplemented(
558601
utils::get_unimplemented_payment_method_error_message("trustpay"),

crates/hyperswitch_connectors/src/utils.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5970,6 +5970,11 @@ pub trait NetworkTokenData {
59705970
fn get_network_token_expiry_month(&self) -> Secret<String>;
59715971
fn get_network_token_expiry_year(&self) -> Secret<String>;
59725972
fn get_cryptogram(&self) -> Option<Secret<String>>;
5973+
fn get_token_expiry_year_2_digit(&self) -> Result<Secret<String>, errors::ConnectorError>;
5974+
fn get_token_expiry_month_year_2_digit_with_delimiter(
5975+
&self,
5976+
delimiter: String,
5977+
) -> Result<Secret<String>, errors::ConnectorError>;
59735978
}
59745979

59755980
impl NetworkTokenData for payment_method_data::NetworkTokenData {
@@ -6040,6 +6045,56 @@ impl NetworkTokenData for payment_method_data::NetworkTokenData {
60406045
fn get_cryptogram(&self) -> Option<Secret<String>> {
60416046
self.cryptogram.clone()
60426047
}
6048+
6049+
#[cfg(feature = "v1")]
6050+
fn get_token_expiry_year_2_digit(&self) -> Result<Secret<String>, errors::ConnectorError> {
6051+
let binding = self.token_exp_year.clone();
6052+
let year = binding.peek();
6053+
Ok(Secret::new(
6054+
year.get(year.len() - 2..)
6055+
.ok_or(errors::ConnectorError::RequestEncodingFailed)?
6056+
.to_string(),
6057+
))
6058+
}
6059+
6060+
#[cfg(feature = "v2")]
6061+
fn get_token_expiry_year_2_digit(&self) -> Result<Secret<String>, errors::ConnectorError> {
6062+
let binding = self.network_token_exp_year.clone();
6063+
let year = binding.peek();
6064+
Ok(Secret::new(
6065+
year.get(year.len() - 2..)
6066+
.ok_or(errors::ConnectorError::RequestEncodingFailed)?
6067+
.to_string(),
6068+
))
6069+
}
6070+
6071+
#[cfg(feature = "v1")]
6072+
fn get_token_expiry_month_year_2_digit_with_delimiter(
6073+
&self,
6074+
delimiter: String,
6075+
) -> Result<Secret<String>, errors::ConnectorError> {
6076+
let year = self.get_token_expiry_year_2_digit()?;
6077+
Ok(Secret::new(format!(
6078+
"{}{}{}",
6079+
self.token_exp_month.peek(),
6080+
delimiter,
6081+
year.peek()
6082+
)))
6083+
}
6084+
6085+
#[cfg(feature = "v2")]
6086+
fn get_token_expiry_month_year_2_digit_with_delimiter(
6087+
&self,
6088+
delimiter: String,
6089+
) -> Result<Secret<String>, errors::ConnectorError> {
6090+
let year = self.get_token_expiry_year_2_digit()?;
6091+
Ok(Secret::new(format!(
6092+
"{}{}{}",
6093+
self.network_token_exp_month.peek(),
6094+
delimiter,
6095+
year.peek()
6096+
)))
6097+
}
60436098
}
60446099

60456100
pub fn convert_uppercase<'de, D, T>(v: D) -> Result<T, D::Error>

0 commit comments

Comments
 (0)