Skip to content

Commit

Permalink
refactor: resolve comments and add more validations
Browse files Browse the repository at this point in the history
  • Loading branch information
kashif-m committed Feb 3, 2025
1 parent dac3060 commit 364ec3e
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 120 deletions.
9 changes: 3 additions & 6 deletions crates/api_models/src/payment_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2405,9 +2405,6 @@ pub struct CardNetworkTokenizeRequest {
#[serde(flatten)]
pub data: TokenizeDataRequest,

/// Card type
pub card_type: Option<CardType>,

/// Customer details
pub customer: payments::CustomerDetails,

Expand Down Expand Up @@ -2446,8 +2443,8 @@ pub struct TokenizeCardRequest {
pub card_expiry_year: masking::Secret<String>,

/// The CVC number for the card
#[schema(value_type = String, example = "242")]
pub card_cvc: masking::Secret<String>,
#[schema(value_type = Option<String>, example = "242")]
pub card_cvc: Option<masking::Secret<String>>,

/// Card Holder Name
#[schema(value_type = Option<String>, example = "John Doe")]
Expand Down Expand Up @@ -2477,7 +2474,7 @@ pub struct TokenizePaymentMethodRequest {
pub payment_method_id: String,

/// The CVC number for the card
pub card_cvc: masking::Secret<String>,
pub card_cvc: Option<masking::Secret<String>>,
}

#[derive(Debug, Default, serde::Deserialize, serde::Serialize, ToSchema)]
Expand Down
63 changes: 27 additions & 36 deletions crates/hyperswitch_domain_models/src/bulk_tokenization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use crate::{
#[derive(Debug)]
pub struct CardNetworkTokenizeRequest {
pub data: TokenizeDataRequest,
pub card_type: Option<payment_methods_api::CardType>,
pub customer: CustomerDetails,
pub billing: Option<Address>,
pub metadata: Option<pii::SecretSerdeValue>,
Expand All @@ -35,7 +34,7 @@ pub struct TokenizeCardRequest {
pub raw_card_number: CardNumber,
pub card_expiry_month: masking::Secret<String>,
pub card_expiry_year: masking::Secret<String>,
pub card_cvc: masking::Secret<String>,
pub card_cvc: Option<masking::Secret<String>>,
pub card_holder_name: Option<masking::Secret<String>>,
pub nick_name: Option<masking::Secret<String>>,
pub card_issuing_country: Option<String>,
Expand All @@ -47,7 +46,7 @@ pub struct TokenizeCardRequest {
#[derive(Clone, Debug)]
pub struct TokenizePaymentMethodRequest {
pub payment_method_id: String,
pub card_cvc: masking::Secret<String>,
pub card_cvc: Option<masking::Secret<String>>,
}

#[derive(Default, Debug, serde::Deserialize, serde::Serialize)]
Expand Down Expand Up @@ -145,48 +144,41 @@ impl ForeignTryFrom<CardNetworkTokenizeRecord> for payment_methods_api::CardNetw
record.raw_card_number,
record.card_expiry_month,
record.card_expiry_year,
record.card_cvc,
record.payment_method_id,
) {
(
Some(raw_card_number),
Some(card_expiry_month),
Some(card_expiry_year),
Some(card_cvc),
_,
) => Ok(Self {
merchant_id,
data: payment_methods_api::TokenizeDataRequest::Card(
payment_methods_api::TokenizeCardRequest {
raw_card_number,
card_expiry_month,
card_expiry_year,
card_cvc,
card_holder_name: record.card_holder_name,
nick_name: record.nick_name,
card_issuing_country: record.card_issuing_country,
card_network: record.card_network,
card_issuer: record.card_issuer,
card_type: record.card_type.clone(),
},
),
billing,
customer,
card_type: record.card_type,
metadata: None,
payment_method_issuer: record.payment_method_issuer,
}),
(_, _, _, Some(card_cvc), Some(payment_method_id)) => Ok(Self {
(Some(raw_card_number), Some(card_expiry_month), Some(card_expiry_year), _) => {
Ok(Self {
merchant_id,
data: payment_methods_api::TokenizeDataRequest::Card(
payment_methods_api::TokenizeCardRequest {
raw_card_number,
card_expiry_month,
card_expiry_year,
card_cvc: record.card_cvc,
card_holder_name: record.card_holder_name,
nick_name: record.nick_name,
card_issuing_country: record.card_issuing_country,
card_network: record.card_network,
card_issuer: record.card_issuer,
card_type: record.card_type.clone(),
},
),
billing,
customer,
metadata: None,
payment_method_issuer: record.payment_method_issuer,
})
}
(_, _, _, Some(payment_method_id)) => Ok(Self {
merchant_id,
data: payment_methods_api::TokenizeDataRequest::PaymentMethod(
payment_methods_api::TokenizePaymentMethodRequest {
payment_method_id,
card_cvc,
card_cvc: record.card_cvc,
},
),
billing,
customer,
card_type: record.card_type,
metadata: None,
payment_method_issuer: record.payment_method_issuer,
}),
Expand Down Expand Up @@ -233,7 +225,6 @@ impl ForeignFrom<payment_methods_api::CardNetworkTokenizeRequest> for CardNetwor
fn foreign_from(req: payment_methods_api::CardNetworkTokenizeRequest) -> Self {
Self {
data: TokenizeDataRequest::foreign_from(req.data),
card_type: req.card_type,
customer: CustomerDetails::foreign_from(req.customer),
billing: req.billing.map(ForeignFrom::foreign_from),
metadata: req.metadata,
Expand Down
17 changes: 17 additions & 0 deletions crates/hyperswitch_domain_models/src/payment_method_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,23 @@ impl CardDetailsForNetworkTransactionId {
}
}

impl From<&Card> for CardDetailsForNetworkTransactionId {
fn from(item: &Card) -> Self {
Self {
card_number: item.card_number.to_owned(),
card_exp_month: item.card_exp_month.to_owned(),
card_exp_year: item.card_exp_year.to_owned(),
card_issuer: item.card_issuer.to_owned(),
card_network: item.card_network.to_owned(),
card_type: item.card_type.to_owned(),
card_issuing_country: item.card_issuing_country.to_owned(),
bank_code: item.bank_code.to_owned(),
nick_name: item.nick_name.to_owned(),
card_holder_name: item.card_holder_name.to_owned(),
}
}
}

impl From<mandates::NetworkTransactionIdAndCardDetails> for CardDetailsForNetworkTransactionId {
fn from(card_details_for_nti: mandates::NetworkTransactionIdAndCardDetails) -> Self {
Self {
Expand Down
45 changes: 31 additions & 14 deletions crates/router/src/core/payment_methods/cards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6075,25 +6075,33 @@ pub async fn execute_card_tokenization(
.await?;
let builder = builder.set_validate_result();

// Perform BIN lookup and validate card network
let optional_card_info = executor
.fetch_bin_details_and_validate_card_network(
req.raw_card_number.clone(),
req.card_issuer.as_ref(),
req.card_network.as_ref(),
req.card_type.as_ref(),
req.card_issuing_country.as_ref(),
)
.await?;
let builder = builder.set_card_details(req, optional_card_info);

// Create customer if not present
let customer = match optional_customer {
Some(customer) => customer,
None => executor.create_customer().await?,
};
let builder = builder.set_customer(&customer);

// Perform BIN lookup
let optional_card_info = executor
.fetch_bin_details(req.raw_card_number.clone())
.await?;
let builder = builder.set_card_details(req, optional_card_info);

// Tokenize card
let domain_card = builder
.get_optional_card()
.get_required_value("value")
let (optional_card, optional_cvc) = builder.get_optional_card_and_cvc();
let domain_card = optional_card
.get_required_value("card")
.change_context(errors::ApiErrorResponse::InternalServerError)?;
let network_token_details = executor.tokenize_card(&customer.id, &domain_card).await?;
let network_token_details = executor
.tokenize_card(&customer.id, &domain_card, optional_cvc)
.await?;
let builder = builder.set_token_details(&network_token_details);

// Store card and token in locker
Expand Down Expand Up @@ -6147,15 +6155,24 @@ pub async fn execute_payment_method_tokenization(
)
.await?;

// Perform BIN lookup
// Perform BIN lookup and validate card network
let optional_card_info = executor
.fetch_bin_details(card_details.card_number.clone())
.fetch_bin_details_and_validate_card_network(
card_details.card_number.clone(),
None,
None,
None,
None,
)
.await?;
let builder = builder.set_card_details(&card_details, optional_card_info, req.card_cvc.clone());

// Tokenize card
let domain_card = builder.get_optional_card().get_required_value("card")?;
let network_token_details = executor.tokenize_card(&customer.id, &domain_card).await?;
let (optional_card, optional_cvc) = builder.get_optional_card_and_cvc();
let domain_card = optional_card.get_required_value("card")?;
let network_token_details = executor
.tokenize_card(&customer.id, &domain_card, optional_cvc)
.await?;
let builder = builder.set_token_details(&network_token_details);

// Store token in locker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub struct CardData {
card_number: CardNumber,
exp_month: Secret<String>,
exp_year: Secret<String>,
card_security_code: Secret<String>,
card_security_code: Option<Secret<String>>,
}

#[derive(Debug, Serialize)]
Expand Down Expand Up @@ -264,15 +264,16 @@ pub async fn mk_tokenization_req(

pub async fn make_card_network_tokenization_request(
state: &routes::SessionState,
card: &domain::Card,
card: &domain::CardDetailsForNetworkTransactionId,
optional_cvc: Option<Secret<String>>,
customer_id: &id_type::CustomerId,
) -> CustomResult<(CardNetworkTokenResponsePayload, Option<String>), errors::NetworkTokenizationError>
{
let card_data = CardData {
card_number: card.card_number.clone(),
exp_month: card.card_exp_month.clone(),
exp_year: card.card_exp_year.clone(),
card_security_code: card.card_cvc.clone(),
card_security_code: optional_cvc,
};

let payload = card_data
Expand Down
Loading

0 comments on commit 364ec3e

Please sign in to comment.