mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 04:04:55 +08:00
refactor(payment_methods): add support for passing card_cvc in payment_method_data object along with token (#3024)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -204,8 +204,9 @@ pub struct PaymentsRequest {
|
||||
#[schema(example = "187282ab-40ef-47a9-9206-5099ba31e432")]
|
||||
pub payment_token: Option<String>,
|
||||
|
||||
/// This is used when payment is to be confirmed and the card is not saved
|
||||
#[schema(value_type = Option<String>)]
|
||||
/// This is used when payment is to be confirmed and the card is not saved.
|
||||
/// This field will be deprecated soon, use the CardToken object instead
|
||||
#[schema(value_type = Option<String>, deprecated)]
|
||||
pub card_cvc: Option<Secret<String>>,
|
||||
|
||||
/// The shipping address for the payment
|
||||
@ -720,12 +721,16 @@ pub struct Card {
|
||||
pub nick_name: Option<Secret<String>>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
|
||||
#[derive(Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct CardToken {
|
||||
/// The card holder's name
|
||||
#[schema(value_type = String, example = "John Test")]
|
||||
pub card_holder_name: Option<Secret<String>>,
|
||||
|
||||
/// The CVC number for the card
|
||||
#[schema(value_type = Option<String>)]
|
||||
pub card_cvc: Option<Secret<String>>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
|
||||
|
||||
@ -42,7 +42,6 @@ pub trait PaymentMethodRetrieve {
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
token: &storage::PaymentTokenData,
|
||||
payment_intent: &PaymentIntent,
|
||||
card_cvc: Option<masking::Secret<String>>,
|
||||
card_token_data: Option<&CardToken>,
|
||||
) -> RouterResult<Option<(payments::PaymentMethodData, enums::PaymentMethod)>>;
|
||||
}
|
||||
@ -126,7 +125,6 @@ impl PaymentMethodRetrieve for Oss {
|
||||
merchant_key_store: &domain::MerchantKeyStore,
|
||||
token_data: &storage::PaymentTokenData,
|
||||
payment_intent: &PaymentIntent,
|
||||
card_cvc: Option<masking::Secret<String>>,
|
||||
card_token_data: Option<&CardToken>,
|
||||
) -> RouterResult<Option<(payments::PaymentMethodData, enums::PaymentMethod)>> {
|
||||
match token_data {
|
||||
@ -135,7 +133,6 @@ impl PaymentMethodRetrieve for Oss {
|
||||
state,
|
||||
&generic_token.token,
|
||||
payment_intent,
|
||||
card_cvc,
|
||||
merchant_key_store,
|
||||
card_token_data,
|
||||
)
|
||||
@ -147,7 +144,6 @@ impl PaymentMethodRetrieve for Oss {
|
||||
state,
|
||||
&generic_token.token,
|
||||
payment_intent,
|
||||
card_cvc,
|
||||
merchant_key_store,
|
||||
card_token_data,
|
||||
)
|
||||
@ -159,7 +155,6 @@ impl PaymentMethodRetrieve for Oss {
|
||||
state,
|
||||
&card_token.token,
|
||||
payment_intent,
|
||||
card_cvc,
|
||||
card_token_data,
|
||||
)
|
||||
.await
|
||||
@ -171,7 +166,6 @@ impl PaymentMethodRetrieve for Oss {
|
||||
state,
|
||||
&card_token.token,
|
||||
payment_intent,
|
||||
card_cvc,
|
||||
card_token_data,
|
||||
)
|
||||
.await
|
||||
|
||||
@ -1354,7 +1354,6 @@ pub async fn retrieve_payment_method_with_temporary_token(
|
||||
state: &AppState,
|
||||
token: &str,
|
||||
payment_intent: &PaymentIntent,
|
||||
card_cvc: Option<masking::Secret<String>>,
|
||||
merchant_key_store: &domain::MerchantKeyStore,
|
||||
card_token_data: Option<&CardToken>,
|
||||
) -> RouterResult<Option<(api::PaymentMethodData, enums::PaymentMethod)>> {
|
||||
@ -1395,10 +1394,13 @@ pub async fn retrieve_payment_method_with_temporary_token(
|
||||
updated_card.card_holder_name = name_on_card;
|
||||
}
|
||||
|
||||
if let Some(cvc) = card_cvc {
|
||||
is_card_updated = true;
|
||||
updated_card.card_cvc = cvc;
|
||||
if let Some(token_data) = card_token_data {
|
||||
if let Some(cvc) = token_data.card_cvc.clone() {
|
||||
is_card_updated = true;
|
||||
updated_card.card_cvc = cvc;
|
||||
}
|
||||
}
|
||||
|
||||
if is_card_updated {
|
||||
let updated_pm = api::PaymentMethodData::Card(updated_card);
|
||||
vault::Vault::store_payment_method_data_in_locker(
|
||||
@ -1444,7 +1446,6 @@ pub async fn retrieve_card_with_permanent_token(
|
||||
state: &AppState,
|
||||
token: &str,
|
||||
payment_intent: &PaymentIntent,
|
||||
card_cvc: Option<masking::Secret<String>>,
|
||||
card_token_data: Option<&CardToken>,
|
||||
) -> RouterResult<api::PaymentMethodData> {
|
||||
let customer_id = payment_intent
|
||||
@ -1479,7 +1480,11 @@ pub async fn retrieve_card_with_permanent_token(
|
||||
card_holder_name: name_on_card.unwrap_or(masking::Secret::from("".to_string())),
|
||||
card_exp_month: card.card_exp_month,
|
||||
card_exp_year: card.card_exp_year,
|
||||
card_cvc: card_cvc.unwrap_or_default(),
|
||||
card_cvc: card_token_data
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.card_cvc
|
||||
.unwrap_or_default(),
|
||||
card_issuer: card.card_brand,
|
||||
nick_name: card.nick_name.map(masking::Secret::new),
|
||||
card_network: None,
|
||||
@ -1501,6 +1506,22 @@ pub async fn make_pm_data<'a, F: Clone, R, Ctx: PaymentMethodRetrieve>(
|
||||
Option<api::PaymentMethodData>,
|
||||
)> {
|
||||
let request = &payment_data.payment_method_data.clone();
|
||||
|
||||
let mut card_token_data = payment_data
|
||||
.payment_method_data
|
||||
.clone()
|
||||
.and_then(|pmd| match pmd {
|
||||
api_models::payments::PaymentMethodData::CardToken(token_data) => Some(token_data),
|
||||
_ => None,
|
||||
})
|
||||
.or(Some(CardToken::default()));
|
||||
|
||||
if let Some(cvc) = payment_data.card_cvc.clone() {
|
||||
if let Some(token_data) = card_token_data.as_mut() {
|
||||
token_data.card_cvc = Some(cvc);
|
||||
}
|
||||
}
|
||||
|
||||
let token = payment_data.token.clone();
|
||||
|
||||
let hyperswitch_token = match payment_data.mandate_id {
|
||||
@ -1560,13 +1581,6 @@ pub async fn make_pm_data<'a, F: Clone, R, Ctx: PaymentMethodRetrieve>(
|
||||
}
|
||||
};
|
||||
|
||||
let card_cvc = payment_data.card_cvc.clone();
|
||||
|
||||
let card_token_data = request.as_ref().and_then(|pmd| match pmd {
|
||||
api_models::payments::PaymentMethodData::CardToken(token_data) => Some(token_data),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
// TODO: Handle case where payment method and token both are present in request properly.
|
||||
let payment_method = match (request, hyperswitch_token) {
|
||||
(_, Some(hyperswitch_token)) => {
|
||||
@ -1575,8 +1589,7 @@ pub async fn make_pm_data<'a, F: Clone, R, Ctx: PaymentMethodRetrieve>(
|
||||
merchant_key_store,
|
||||
&hyperswitch_token,
|
||||
&payment_data.payment_intent,
|
||||
card_cvc,
|
||||
card_token_data,
|
||||
card_token_data.as_ref(),
|
||||
)
|
||||
.await
|
||||
.attach_printable("in 'make_pm_data'")?;
|
||||
|
||||
@ -4316,6 +4316,11 @@
|
||||
"type": "string",
|
||||
"description": "The card holder's name",
|
||||
"example": "John Test"
|
||||
},
|
||||
"card_cvc": {
|
||||
"type": "string",
|
||||
"description": "The CVC number for the card",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -9545,7 +9550,8 @@
|
||||
},
|
||||
"card_cvc": {
|
||||
"type": "string",
|
||||
"description": "This is used when payment is to be confirmed and the card is not saved",
|
||||
"description": "This is used when payment is to be confirmed and the card is not saved.\nThis field will be deprecated soon, use the CardToken object instead",
|
||||
"deprecated": true,
|
||||
"nullable": true
|
||||
},
|
||||
"shipping": {
|
||||
@ -9914,7 +9920,8 @@
|
||||
},
|
||||
"card_cvc": {
|
||||
"type": "string",
|
||||
"description": "This is used when payment is to be confirmed and the card is not saved",
|
||||
"description": "This is used when payment is to be confirmed and the card is not saved.\nThis field will be deprecated soon, use the CardToken object instead",
|
||||
"deprecated": true,
|
||||
"nullable": true
|
||||
},
|
||||
"shipping": {
|
||||
|
||||
Reference in New Issue
Block a user