diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index c8a87f1a6174..9375fe58f20b 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -6280,6 +6280,22 @@ }, "transaction_currency_code": { "$ref": "#/components/schemas/Currency" + }, + "phone_number": { + "type": "string", + "example": "9123456789", + "nullable": true, + "maxLength": 255 + }, + "email": { + "type": "string", + "example": "johntest@test.com", + "nullable": true, + "maxLength": 255 + }, + "phone_country_code": { + "type": "string", + "nullable": true } } }, diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 57e4ac1948a4..9037b2d99714 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -8882,6 +8882,22 @@ }, "transaction_currency_code": { "$ref": "#/components/schemas/Currency" + }, + "phone_number": { + "type": "string", + "example": "9123456789", + "nullable": true, + "maxLength": 255 + }, + "email": { + "type": "string", + "example": "johntest@test.com", + "nullable": true, + "maxLength": 255 + }, + "phone_country_code": { + "type": "string", + "nullable": true } } }, diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 632d40a09519..a74a42a0c62f 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -6997,6 +6997,11 @@ pub struct ClickToPaySessionResponse { pub transaction_amount: StringMajorUnit, #[schema(value_type = Currency)] pub transaction_currency_code: common_enums::Currency, + #[schema(value_type = Option, max_length = 255, example = "9123456789")] + pub phone_number: Option>, + #[schema(max_length = 255, value_type = Option, example = "johntest@test.com")] + pub email: Option, + pub phone_country_code: Option, } #[cfg(feature = "v1")] diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index e942288078da..1902770a2f74 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -37,6 +37,7 @@ use error_stack::{report, ResultExt}; use events::EventInfo; use futures::future::join_all; use helpers::{decrypt_paze_token, ApplePayData}; +use hyperswitch_domain_models::payments::payment_intent::CustomerData; #[cfg(feature = "v2")] use hyperswitch_domain_models::payments::{ PaymentConfirmData, PaymentIntentData, PaymentStatusData, @@ -3399,7 +3400,7 @@ pub async fn get_session_token_for_click_to_pay( payment_intent: &hyperswitch_domain_models::payments::PaymentIntent, ) -> RouterResult { use common_utils::{id_type::MerchantConnectorAccountId, types::AmountConvertor}; - use hyperswitch_domain_models::payments::ClickToPayMetaData; + use hyperswitch_domain_models::payments::{payment_intent::CustomerData, ClickToPayMetaData}; use crate::consts::CLICK_TO_PAY; @@ -3439,6 +3440,19 @@ pub async fn get_session_token_for_click_to_pay( .change_context(errors::ApiErrorResponse::PreconditionFailed { message: "Failed to convert amount to string major unit for clickToPay".to_string(), })?; + + let customer_details_value = payment_intent + .customer_details + .clone() + .get_required_value("customer_details")?; + + let customer_details: CustomerData = customer_details_value + .parse_value("CustomerData") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Error while parsing customer data from payment intent")?; + + validate_customer_details_for_click_to_pay(&customer_details)?; + Ok(api_models::payments::SessionToken::ClickToPay(Box::new( api_models::payments::ClickToPaySessionResponse { dpa_id: click_to_pay_metadata.dpa_id, @@ -3451,10 +3465,38 @@ pub async fn get_session_token_for_click_to_pay( merchant_country_code: click_to_pay_metadata.merchant_country_code, transaction_amount, transaction_currency_code: transaction_currency, + phone_number: customer_details.phone.clone(), + email: customer_details.email.clone(), + phone_country_code: customer_details.phone_country_code.clone(), }, ))) } +fn validate_customer_details_for_click_to_pay(customer_details: &CustomerData) -> RouterResult<()> { + match ( + customer_details.phone.as_ref(), + customer_details.phone_country_code.as_ref(), + customer_details.email.as_ref() + ) { + (None, None, Some(_)) => Ok(()), + (Some(_), Some(_), Some(_)) => Ok(()), + (Some(_), Some(_), None) => Ok(()), + (Some(_), None, Some(_)) => Ok(()), + (None, Some(_), None) => Err(errors::ApiErrorResponse::MissingRequiredField { + field_name: "phone", + }) + .attach_printable("phone number is not present in payment_intent.customer_details"), + (Some(_), None, None) => Err(errors::ApiErrorResponse::MissingRequiredField { + field_name: "phone_country_code", + }) + .attach_printable("phone_country_code is not present in payment_intent.customer_details"), + (_, _, _) => Err(errors::ApiErrorResponse::MissingRequiredFields { + field_names: vec!["phone", "phone_country_code", "email"], + }) + .attach_printable("either of phone, phone_country_code or email is not present in payment_intent.customer_details"), + } +} + #[cfg(feature = "v1")] pub async fn call_create_connector_customer_if_required( state: &SessionState,