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:
Chethan Rao
2023-12-04 12:40:43 +05:30
committed by GitHub
parent 83fcd1a9de
commit 3ce04abae4
4 changed files with 45 additions and 26 deletions

View File

@ -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)]

View File

@ -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

View File

@ -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'")?;

View File

@ -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": {