diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 6a7f7148bd3a..cab8071de087 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -2092,14 +2092,29 @@ mod payment_method_data_serde { if inner_map.is_empty() { None } else { - Some( - serde_json::from_value::( - payment_method_data_value, - ) - .map_err(|serde_json_error| { - de::Error::custom(serde_json_error.to_string()) - })?, + let payment_method_data = serde_json::from_value::( + payment_method_data_value, ) + .map_err(|serde_json_error| { + de::Error::custom(serde_json_error.to_string()) + })?; + let address_details = parsed_value + .billing + .as_ref() + .and_then(|billing| billing.address.clone()); + match (payment_method_data.clone(), address_details.as_ref()) { + ( + PaymentMethodData::Card(ref mut card), + Some(billing_address_details), + ) => { + if card.card_holder_name.is_none() { + card.card_holder_name = + billing_address_details.get_optional_full_name(); + } + Some(PaymentMethodData::Card(card.clone())) + } + _ => Some(payment_method_data), + } } } else { Err(de::Error::custom("Expected a map for payment_method_data"))? diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 820959a59637..db35766f33ae 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -82,6 +82,7 @@ pub struct Card { pub card_issuing_country: Option, pub bank_code: Option, pub nick_name: Option>, + pub card_holder_name: Option>, } #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)] @@ -95,6 +96,7 @@ pub struct CardDetailsForNetworkTransactionId { pub card_issuing_country: Option, pub bank_code: Option, pub nick_name: Option>, + pub card_holder_name: Option>, } impl CardDetailsForNetworkTransactionId { @@ -136,6 +138,7 @@ impl From for CardDetailsForNetwor card_issuing_country: card_details_for_nti.card_issuing_country, bank_code: card_details_for_nti.bank_code, nick_name: card_details_for_nti.nick_name, + card_holder_name: card_details_for_nti.card_holder_name, } } } @@ -666,7 +669,7 @@ impl From for Card { card_number, card_exp_month, card_exp_year, - card_holder_name: _, + card_holder_name, card_cvc, card_issuer, card_network, @@ -687,6 +690,7 @@ impl From for Card { card_issuing_country, bank_code, nick_name, + card_holder_name, } } } @@ -1438,6 +1442,7 @@ pub struct TokenizedCardValue1 { pub nickname: Option, pub card_last_four: Option, pub card_token: Option, + pub card_holder_name: Option>, } #[derive(Debug, serde::Serialize, serde::Deserialize)] diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs index 32a42d301659..fcff711f6c9a 100644 --- a/crates/router/src/core/payment_methods/vault.rs +++ b/crates/router/src/core/payment_methods/vault.rs @@ -66,6 +66,7 @@ impl Vaultable for domain::Card { nickname: self.nick_name.as_ref().map(|name| name.peek().clone()), card_last_four: None, card_token: None, + card_holder_name: self.card_holder_name.clone(), }; value1 @@ -119,6 +120,7 @@ impl Vaultable for domain::Card { card_issuing_country: None, card_type: None, nick_name: value1.nickname.map(masking::Secret::new), + card_holder_name: value1.card_holder_name, }; let supp_data = SupplementaryVaultData { diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 923f6d24fe83..4771360ea7f2 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1962,6 +1962,7 @@ pub async fn retrieve_card_with_permanent_token( card_issuing_country: None, bank_code: None, nick_name: card_details_from_locker.nick_name.map(masking::Secret::new), + card_holder_name: card_details_from_locker.name_on_card.clone(), }; Ok( @@ -2130,6 +2131,7 @@ pub async fn retrieve_card_with_permanent_token( card_issuing_country: None, bank_code: None, nick_name: card_details_from_locker.nick_name.map(masking::Secret::new), + card_holder_name: card_details_from_locker.name_on_card, }; Ok( @@ -4408,7 +4410,7 @@ pub async fn get_additional_payment_data( bank_code: card_data.bank_code.to_owned(), card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), last4: last4.clone(), card_isin: card_isin.clone(), card_extended_bin: card_extended_bin.clone(), @@ -4441,7 +4443,7 @@ pub async fn get_additional_payment_data( card_extended_bin: card_extended_bin.clone(), card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), // These are filled after calling the processor / connector payment_checks: None, authentication_data: None, @@ -4461,7 +4463,7 @@ pub async fn get_additional_payment_data( card_extended_bin, card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), // These are filled after calling the processor / connector payment_checks: None, authentication_data: None, @@ -4671,7 +4673,7 @@ pub async fn get_additional_payment_data( bank_code: card_data.bank_code.to_owned(), card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), last4: last4.clone(), card_isin: card_isin.clone(), card_extended_bin: card_extended_bin.clone(), @@ -4704,7 +4706,7 @@ pub async fn get_additional_payment_data( card_extended_bin: card_extended_bin.clone(), card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), // These are filled after calling the processor / connector payment_checks: None, authentication_data: None, @@ -4724,7 +4726,7 @@ pub async fn get_additional_payment_data( card_extended_bin, card_exp_month: Some(card_data.card_exp_month.clone()), card_exp_year: Some(card_data.card_exp_year.clone()), - card_holder_name: card_data.nick_name.clone(), //todo! + card_holder_name: card_data.card_holder_name.clone(), // These are filled after calling the processor / connector payment_checks: None, authentication_data: None, diff --git a/crates/router/src/utils/verify_connector.rs b/crates/router/src/utils/verify_connector.rs index 617cb415ee00..b13ba70e6fbd 100644 --- a/crates/router/src/utils/verify_connector.rs +++ b/crates/router/src/utils/verify_connector.rs @@ -23,6 +23,7 @@ pub fn generate_card_from_details( card_type: None, card_issuing_country: None, bank_code: None, + card_holder_name: None, }) } diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs index d8607946b500..2d0272cfa7e6 100644 --- a/crates/router/tests/connectors/aci.rs +++ b/crates/router/tests/connectors/aci.rs @@ -51,6 +51,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), confirm: true, statement_descriptor_suffix: None, @@ -296,6 +297,7 @@ async fn payments_create_failure() { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }); let response = services::api::execute_connector_processing_step( diff --git a/crates/router/tests/connectors/adyen.rs b/crates/router/tests/connectors/adyen.rs index 2146d9590020..c7ad3b69a320 100644 --- a/crates/router/tests/connectors/adyen.rs +++ b/crates/router/tests/connectors/adyen.rs @@ -153,6 +153,7 @@ impl AdyenTest { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), confirm: true, statement_descriptor_suffix: None, diff --git a/crates/router/tests/connectors/airwallex.rs b/crates/router/tests/connectors/airwallex.rs index bbc387a0b226..0e538818d50a 100644 --- a/crates/router/tests/connectors/airwallex.rs +++ b/crates/router/tests/connectors/airwallex.rs @@ -82,6 +82,7 @@ fn payment_method_details() -> Option { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), capture_method: Some(diesel_models::enums::CaptureMethod::Manual), router_return_url: Some("https://google.com".to_string()), diff --git a/crates/router/tests/connectors/fiserv.rs b/crates/router/tests/connectors/fiserv.rs index bfa16d74f548..7f13de310044 100644 --- a/crates/router/tests/connectors/fiserv.rs +++ b/crates/router/tests/connectors/fiserv.rs @@ -53,6 +53,7 @@ fn payment_method_details() -> Option { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), capture_method: Some(diesel_models::enums::CaptureMethod::Manual), ..utils::PaymentAuthorizeType::default().0 diff --git a/crates/router/tests/connectors/rapyd.rs b/crates/router/tests/connectors/rapyd.rs index ff083a37e595..ee6ac303e88e 100644 --- a/crates/router/tests/connectors/rapyd.rs +++ b/crates/router/tests/connectors/rapyd.rs @@ -53,6 +53,7 @@ async fn should_only_authorize_payment() { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), capture_method: Some(diesel_models::enums::CaptureMethod::Manual), ..utils::PaymentAuthorizeType::default().0 @@ -80,6 +81,7 @@ async fn should_authorize_and_capture_payment() { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), ..utils::PaymentAuthorizeType::default().0 }), diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index c08139ae6fe0..18c171d58c57 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -927,6 +927,7 @@ impl Default for CCardType { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }) } } diff --git a/crates/router/tests/connectors/worldline.rs b/crates/router/tests/connectors/worldline.rs index c1be90b59fde..793a1cc15f4a 100644 --- a/crates/router/tests/connectors/worldline.rs +++ b/crates/router/tests/connectors/worldline.rs @@ -83,6 +83,7 @@ impl WorldlineTest { card_issuing_country: None, bank_code: None, nick_name: Some(Secret::new("nick_name".into())), + card_holder_name: Some(Secret::new("card holder name".into())), }), confirm: true, statement_descriptor_suffix: None, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js b/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js index 0c489f6df835..98d8e4c1acb4 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js @@ -59,7 +59,7 @@ const payment_method_data_no3ds = { card_extended_bin: null, card_exp_month: "01", card_exp_year: "50", - card_holder_name: null, + card_holder_name: "joseph Doe", payment_checks: { avs_response: { code: "Y", @@ -83,7 +83,7 @@ const payment_method_data_3ds = { card_extended_bin: null, card_exp_month: "01", card_exp_year: "50", - card_holder_name: null, + card_holder_name: "joseph Doe", payment_checks: null, authentication_data: null, }, diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js b/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js index 4e62c37c5b05..4228a5115355 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js @@ -61,7 +61,7 @@ const payment_method_data_3ds = { card_extended_bin: null, card_exp_month: "10", card_exp_year: "50", - card_holder_name: null, + card_holder_name: "morino", payment_checks: null, authentication_data: null, }, @@ -79,7 +79,7 @@ const payment_method_data_no3ds = { card_extended_bin: null, card_exp_month: "10", card_exp_year: "50", - card_holder_name: null, + card_holder_name: "morino", payment_checks: { cvc_check: "pass", address_line1_check: "pass",