From 83fcd1a9deb106a44c8262923c7f1660b0c46bf2 Mon Sep 17 00:00:00 2001 From: Shankar Singh C <83439957+ShankarSinghC@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:20:41 +0530 Subject: [PATCH 1/3] feat(router): add key_value to locker metrics (#2995) --- .../router/src/core/payment_methods/cards.rs | 84 ++++++++++++++++--- crates/router/src/routes/metrics.rs | 1 + 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 044e270a7ea9..545733e298ab 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -225,12 +225,21 @@ pub async fn add_card_to_locker( ) .await .map_err(|error| { - metrics::CARD_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::CARD_LOCKER_FAILURES.add( + &metrics::CONTEXT, + 1, + &[ + router_env::opentelemetry::KeyValue::new("locker", "basilisk"), + router_env::opentelemetry::KeyValue::new("operation", "add"), + ], + ); error }) }, &metrics::CARD_ADD_TIME, - &[], + &[router_env::opentelemetry::KeyValue::new( + "locker", "basilisk", + )], ) .await?; logger::debug!("card added to basilisk locker"); @@ -248,22 +257,45 @@ pub async fn add_card_to_locker( ) .await .map_err(|error| { - metrics::CARD_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::CARD_LOCKER_FAILURES.add( + &metrics::CONTEXT, + 1, + &[ + router_env::opentelemetry::KeyValue::new("locker", "rust"), + router_env::opentelemetry::KeyValue::new("operation", "add"), + ], + ); error }) }, &metrics::CARD_ADD_TIME, - &[], + &[router_env::opentelemetry::KeyValue::new("locker", "rust")], ) .await; match add_card_to_rs_resp { value @ Ok(_) => { - logger::debug!("Card added successfully"); + logger::debug!("card added to rust locker"); + let _ = &metrics::CARD_LOCKER_SUCCESSFUL_RESPONSE.add( + &metrics::CONTEXT, + 1, + &[ + router_env::opentelemetry::KeyValue::new("locker", "rust"), + router_env::opentelemetry::KeyValue::new("operation", "add"), + ], + ); value } Err(err) => { - logger::debug!(error =? err,"failed to add card"); + logger::debug!(error =? err,"failed to add card to rust locker"); + let _ = &metrics::CARD_LOCKER_SUCCESSFUL_RESPONSE.add( + &metrics::CONTEXT, + 1, + &[ + router_env::opentelemetry::KeyValue::new("locker", "basilisk"), + router_env::opentelemetry::KeyValue::new("operation", "add"), + ], + ); Ok(add_card_to_hs_resp) } } @@ -290,12 +322,19 @@ pub async fn get_card_from_locker( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while getting card from basilisk_hs") .map_err(|error| { - metrics::CARD_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::CARD_LOCKER_FAILURES.add( + &metrics::CONTEXT, + 1, + &[ + router_env::opentelemetry::KeyValue::new("locker", "rust"), + router_env::opentelemetry::KeyValue::new("operation", "get"), + ], + ); error }) }, &metrics::CARD_GET_TIME, - &[], + &[router_env::opentelemetry::KeyValue::new("locker", "rust")], ) .await; @@ -313,20 +352,45 @@ pub async fn get_card_from_locker( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while getting card from basilisk_hs") .map_err(|error| { - metrics::CARD_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); + metrics::CARD_LOCKER_FAILURES.add( + &metrics::CONTEXT, + 1, + &[ + router_env::opentelemetry::KeyValue::new("locker", "basilisk"), + router_env::opentelemetry::KeyValue::new("operation", "get"), + ], + ); error }) }, &metrics::CARD_GET_TIME, - &[], + &[router_env::opentelemetry::KeyValue::new( + "locker", "basilisk", + )], ) .await .map(|inner_card| { logger::debug!("card retrieved from basilisk locker"); + let _ = &metrics::CARD_LOCKER_SUCCESSFUL_RESPONSE.add( + &metrics::CONTEXT, + 1, + &[ + router_env::opentelemetry::KeyValue::new("locker", "basilisk"), + router_env::opentelemetry::KeyValue::new("operation", "get"), + ], + ); inner_card }), Ok(_) => { logger::debug!("card retrieved from rust locker"); + let _ = &metrics::CARD_LOCKER_SUCCESSFUL_RESPONSE.add( + &metrics::CONTEXT, + 1, + &[ + router_env::opentelemetry::KeyValue::new("locker", "rust"), + router_env::opentelemetry::KeyValue::new("operation", "get"), + ], + ); get_card_from_rs_locker_resp } } diff --git a/crates/router/src/routes/metrics.rs b/crates/router/src/routes/metrics.rs index a8e6f9d2a892..192df1a09298 100644 --- a/crates/router/src/routes/metrics.rs +++ b/crates/router/src/routes/metrics.rs @@ -85,6 +85,7 @@ counter_metric!(CONNECTOR_HTTP_STATUS_CODE_5XX_COUNT, GLOBAL_METER); // Service Level counter_metric!(CARD_LOCKER_FAILURES, GLOBAL_METER); +counter_metric!(CARD_LOCKER_SUCCESSFUL_RESPONSE, GLOBAL_METER); counter_metric!(TEMP_LOCKER_FAILURES, GLOBAL_METER); histogram_metric!(CARD_ADD_TIME, GLOBAL_METER); histogram_metric!(CARD_GET_TIME, GLOBAL_METER); From 3ce04abae4eddfa27025368f5ef28987cccea43d Mon Sep 17 00:00:00 2001 From: Chethan Rao <70657455+Chethan-rao@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:40:43 +0530 Subject: [PATCH 2/3] 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> --- crates/api_models/src/payments.rs | 11 ++++-- crates/router/src/core/payment_methods.rs | 6 --- crates/router/src/core/payments/helpers.rs | 43 ++++++++++++++-------- openapi/openapi_spec.json | 11 +++++- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index fe5ed417f350..49f2781a18a0 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -204,8 +204,9 @@ pub struct PaymentsRequest { #[schema(example = "187282ab-40ef-47a9-9206-5099ba31e432")] pub payment_token: Option, - /// This is used when payment is to be confirmed and the card is not saved - #[schema(value_type = Option)] + /// 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, deprecated)] pub card_cvc: Option>, /// The shipping address for the payment @@ -720,12 +721,16 @@ pub struct Card { pub nick_name: Option>, } -#[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>, + + /// The CVC number for the card + #[schema(value_type = Option)] + pub card_cvc: Option>, } #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 1049137a9470..a2dbfb1480c4 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -42,7 +42,6 @@ pub trait PaymentMethodRetrieve { key_store: &domain::MerchantKeyStore, token: &storage::PaymentTokenData, payment_intent: &PaymentIntent, - card_cvc: Option>, card_token_data: Option<&CardToken>, ) -> RouterResult>; } @@ -126,7 +125,6 @@ impl PaymentMethodRetrieve for Oss { merchant_key_store: &domain::MerchantKeyStore, token_data: &storage::PaymentTokenData, payment_intent: &PaymentIntent, - card_cvc: Option>, card_token_data: Option<&CardToken>, ) -> RouterResult> { 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 diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 4d11f6400f44..0cce91bebeeb 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1354,7 +1354,6 @@ pub async fn retrieve_payment_method_with_temporary_token( state: &AppState, token: &str, payment_intent: &PaymentIntent, - card_cvc: Option>, merchant_key_store: &domain::MerchantKeyStore, card_token_data: Option<&CardToken>, ) -> RouterResult> { @@ -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>, card_token_data: Option<&CardToken>, ) -> RouterResult { 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, )> { 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'")?; diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index f5ad99f05752..b1e313f15baa 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -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": { From 9d935332193dcc9f191a0a5a9e7405316794a418 Mon Sep 17 00:00:00 2001 From: Swangi Kumari <85639103+swangi-kumari@users.noreply.github.com> Date: Mon, 4 Dec 2023 14:39:33 +0530 Subject: [PATCH 3/3] feat(pm_list): Add required field for open_banking_uk for Adyen and Volt Connector (#3032) Co-authored-by: Prasunna Soppa <70575890+prasunna09@users.noreply.github.com> --- crates/router/src/configs/defaults.rs | 52 +++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/crates/router/src/configs/defaults.rs b/crates/router/src/configs/defaults.rs index f9bfcae1ca10..db29e8180089 100644 --- a/crates/router/src/configs/defaults.rs +++ b/crates/router/src/configs/defaults.rs @@ -4106,6 +4106,58 @@ impl Default for super::settings::RequiredFields { ( enums::PaymentMethod::BankRedirect, PaymentMethodType(HashMap::from([ + ( + enums::PaymentMethodType::OpenBankingUk, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Volt, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ]), + common: HashMap::new(), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap:: from([ + ( + "payment_method_data.bank_redirect.open_banking_uk.issuer".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_redirect.open_banking_uk.issuer".to_string(), + display_name: "issuer".to_string(), + field_type: enums::FieldType::UserBank, + value: None, + } + ) + ]), + common: HashMap::new(), + } + ) + ]), + }, + ), ( enums::PaymentMethodType::Przelewy24, ConnectorFields {