diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index a61bacd91e..1576a1edf4 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -5201,6 +5201,13 @@ } } }, + "ApplepayInitiative": { + "type": "string", + "enum": [ + "web", + "ios" + ] + }, "ApplepayPaymentMethod": { "type": "object", "required": [ @@ -5226,14 +5233,18 @@ "ApplepaySessionTokenResponse": { "type": "object", "required": [ - "session_token_data", "connector", "delayed_session_token", "sdk_next_action" ], "properties": { "session_token_data": { - "$ref": "#/components/schemas/ApplePaySessionResponse" + "allOf": [ + { + "$ref": "#/components/schemas/ApplePaySessionResponse" + } + ], + "nullable": true }, "payment_request_data": { "allOf": [ @@ -19434,8 +19445,7 @@ "certificate_keys", "merchant_identifier", "display_name", - "initiative", - "initiative_context" + "initiative" ], "properties": { "certificate": { @@ -19451,10 +19461,11 @@ "type": "string" }, "initiative": { - "type": "string" + "$ref": "#/components/schemas/ApplepayInitiative" }, "initiative_context": { - "type": "string" + "type": "string", + "nullable": true }, "merchant_business_country": { "allOf": [ diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 777e876b1b..bf275a0dd0 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -20,6 +20,7 @@ use serde::{ ser::Serializer, Deserialize, Deserializer, Serialize, }; +use strum::Display; use time::{Date, PrimitiveDateTime}; use url::Url; use utoipa::ToSchema; @@ -592,6 +593,8 @@ pub struct HeaderPayload { pub client_source: Option, pub client_version: Option, pub x_hs_latency: Option, + pub browser_name: Option, + pub x_client_platform: Option, } impl HeaderPayload { @@ -4299,14 +4302,21 @@ pub struct SessionTokenInfo { pub certificate_keys: Secret, pub merchant_identifier: String, pub display_name: String, - pub initiative: String, - pub initiative_context: String, + pub initiative: ApplepayInitiative, + pub initiative_context: Option, #[schema(value_type = Option)] pub merchant_business_country: Option, #[serde(flatten)] pub payment_processing_details_at: Option, } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Display, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum ApplepayInitiative { + Web, + Ios, +} + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] #[serde(tag = "payment_processing_details_at")] pub enum PaymentProcessingDetailsAt { @@ -4421,7 +4431,9 @@ pub struct PaypalSessionTokenResponse { #[serde(rename_all = "lowercase")] pub struct ApplepaySessionTokenResponse { /// Session object for Apple Pay - pub session_token_data: ApplePaySessionResponse, + /// The session_token_data will be null for iOS devices because the Apple Pay session call is skipped, as there is no web domain involved + #[serde(skip_serializing_if = "Option::is_none")] + pub session_token_data: Option, /// Payment request object for Apple Pay pub payment_request_data: Option, /// The session token is w.r.t this connector diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index c3aa895e1c..5ee0bae6d6 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -2258,6 +2258,24 @@ pub enum PaymentSource { ExternalAuthenticator, } +#[derive(Default, Debug, Clone, serde::Deserialize, serde::Serialize, strum::EnumString)] +pub enum BrowserName { + #[default] + Safari, + #[serde(other)] + Unknown, +} + +#[derive(Default, Debug, Clone, serde::Deserialize, serde::Serialize, strum::EnumString)] +#[strum(serialize_all = "snake_case")] +pub enum ClientPlatform { + #[default] + Web, + Ios, + #[serde(other)] + Unknown, +} + impl PaymentSource { pub fn is_for_internal_use_only(&self) -> bool { match self { diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index 0c24fba34c..a259559c51 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -317,6 +317,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::ApplepayConnectorMetadataRequest, api_models::payments::SessionTokenInfo, api_models::payments::PaymentProcessingDetailsAt, + api_models::payments::ApplepayInitiative, api_models::payments::PaymentProcessingDetails, api_models::payments::PaymentMethodDataResponseWithBilling, api_models::payments::PaymentMethodDataResponse, diff --git a/crates/router/src/connector/bluesnap/transformers.rs b/crates/router/src/connector/bluesnap/transformers.rs index 909e8120c6..fbc7c661e4 100644 --- a/crates/router/src/connector/bluesnap/transformers.rs +++ b/crates/router/src/connector/bluesnap/transformers.rs @@ -461,10 +461,16 @@ impl TryFrom<&types::PaymentsSessionRouterData> for BluesnapCreateWalletToken { }) } }?; + let domain_name = session_token_data.initiative_context.ok_or( + errors::ConnectorError::MissingRequiredField { + field_name: "apple pay initiative_context", + }, + )?; + Ok(Self { wallet_type: "APPLE_PAY".to_string(), validation_url: consts::APPLEPAY_VALIDATION_URL.to_string().into(), - domain_name: session_token_data.initiative_context, + domain_name, display_name: Some(session_token_data.display_name), }) } @@ -529,8 +535,8 @@ impl response: Ok(types::PaymentsResponseData::SessionResponse { session_token: api::SessionToken::ApplePay(Box::new( payments::ApplepaySessionTokenResponse { - session_token_data: payments::ApplePaySessionResponse::NoThirdPartySdk( - session_response, + session_token_data: Some( + payments::ApplePaySessionResponse::NoThirdPartySdk(session_response), ), payment_request_data: Some(payments::ApplePayPaymentRequest { country_code: item.data.get_billing_country()?, diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 5cb025816d..47942d7de4 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -553,8 +553,9 @@ impl _, ))) => Some(api_models::payments::SessionToken::ApplePay(Box::new( api_models::payments::ApplepaySessionTokenResponse { - session_token_data: + session_token_data: Some( api_models::payments::ApplePaySessionResponse::NoSessionResponse, + ), payment_request_data: Some( api_models::payments::ApplePayPaymentRequest { country_code: item.data.get_billing_country()?, diff --git a/crates/router/src/connector/trustpay/transformers.rs b/crates/router/src/connector/trustpay/transformers.rs index b48c52c76f..77d85393d2 100644 --- a/crates/router/src/connector/trustpay/transformers.rs +++ b/crates/router/src/connector/trustpay/transformers.rs @@ -1209,12 +1209,13 @@ pub fn get_apple_pay_session( pre_processing_id: types::PreprocessingResponseId::ConnectorTransactionId(instance_id), session_token: Some(types::api::SessionToken::ApplePay(Box::new( api_models::payments::ApplepaySessionTokenResponse { - session_token_data: + session_token_data: Some( api_models::payments::ApplePaySessionResponse::ThirdPartySdk( api_models::payments::ThirdPartySdkSessionResponse { secrets: secrets.to_owned().into(), }, ), + ), payment_request_data: Some(api_models::payments::ApplePayPaymentRequest { country_code: apple_pay_init_result.country_code, currency_code: apple_pay_init_result.currency_code, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 459ada8fb4..8290177f21 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -461,6 +461,7 @@ where &customer, session_surcharge_details, &business_profile, + header_payload.clone(), )) .await? } @@ -1610,6 +1611,7 @@ where call_connector_action, connector_request, business_profile, + header_payload.clone(), ) .await } else { @@ -1673,6 +1675,7 @@ pub async fn call_multiple_connectors_service( customer: &Option, session_surcharge_details: Option, business_profile: &storage::business_profile::BusinessProfile, + header_payload: HeaderPayload, ) -> RouterResult> where Op: Debug, @@ -1736,6 +1739,7 @@ where CallConnectorAction::Trigger, None, business_profile, + header_payload.clone(), ); join_handlers.push(res); diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index f460946520..aa5be3924a 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -47,6 +47,7 @@ pub trait Feature { call_connector_action: payments::CallConnectorAction, connector_request: Option, business_profile: &storage::business_profile::BusinessProfile, + header_payload: api_models::payments::HeaderPayload, ) -> RouterResult where Self: Sized, diff --git a/crates/router/src/core/payments/flows/approve_flow.rs b/crates/router/src/core/payments/flows/approve_flow.rs index f15274ba5b..f4f8409912 100644 --- a/crates/router/src/core/payments/flows/approve_flow.rs +++ b/crates/router/src/core/payments/flows/approve_flow.rs @@ -52,6 +52,7 @@ impl Feature _call_connector_action: payments::CallConnectorAction, _connector_request: Option, _business_profile: &storage::business_profile::BusinessProfile, + _header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { Err(ApiErrorResponse::NotImplemented { message: NotImplementedMessage::Reason("Flow not supported".to_string()), diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs index 5909b0841f..23971f3696 100644 --- a/crates/router/src/core/payments/flows/authorize_flow.rs +++ b/crates/router/src/core/payments/flows/authorize_flow.rs @@ -65,6 +65,7 @@ impl Feature for types::PaymentsAu call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &storage::business_profile::BusinessProfile, + _header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::Authorize, diff --git a/crates/router/src/core/payments/flows/cancel_flow.rs b/crates/router/src/core/payments/flows/cancel_flow.rs index 0914bd0e90..d61730117a 100644 --- a/crates/router/src/core/payments/flows/cancel_flow.rs +++ b/crates/router/src/core/payments/flows/cancel_flow.rs @@ -52,6 +52,7 @@ impl Feature call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &storage::business_profile::BusinessProfile, + _header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { metrics::PAYMENT_CANCEL_COUNT.add( &metrics::CONTEXT, diff --git a/crates/router/src/core/payments/flows/capture_flow.rs b/crates/router/src/core/payments/flows/capture_flow.rs index a2c2abe7d8..3e09804354 100644 --- a/crates/router/src/core/payments/flows/capture_flow.rs +++ b/crates/router/src/core/payments/flows/capture_flow.rs @@ -52,6 +52,7 @@ impl Feature call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &storage::business_profile::BusinessProfile, + _header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::Capture, diff --git a/crates/router/src/core/payments/flows/complete_authorize_flow.rs b/crates/router/src/core/payments/flows/complete_authorize_flow.rs index e735278609..bb56cb5a7c 100644 --- a/crates/router/src/core/payments/flows/complete_authorize_flow.rs +++ b/crates/router/src/core/payments/flows/complete_authorize_flow.rs @@ -66,6 +66,7 @@ impl Feature call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &storage::business_profile::BusinessProfile, + _header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::CompleteAuthorize, diff --git a/crates/router/src/core/payments/flows/incremental_authorization_flow.rs b/crates/router/src/core/payments/flows/incremental_authorization_flow.rs index 673bb8a1ac..2aa808f953 100644 --- a/crates/router/src/core/payments/flows/incremental_authorization_flow.rs +++ b/crates/router/src/core/payments/flows/incremental_authorization_flow.rs @@ -59,6 +59,7 @@ impl Feature, _business_profile: &storage::business_profile::BusinessProfile, + _header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::IncrementalAuthorization, diff --git a/crates/router/src/core/payments/flows/psync_flow.rs b/crates/router/src/core/payments/flows/psync_flow.rs index eae1d8cfd7..5b0d1a48e6 100644 --- a/crates/router/src/core/payments/flows/psync_flow.rs +++ b/crates/router/src/core/payments/flows/psync_flow.rs @@ -55,6 +55,7 @@ impl Feature call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &storage::business_profile::BusinessProfile, + _header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::PSync, diff --git a/crates/router/src/core/payments/flows/reject_flow.rs b/crates/router/src/core/payments/flows/reject_flow.rs index 020e6ff101..cb1dcd5b19 100644 --- a/crates/router/src/core/payments/flows/reject_flow.rs +++ b/crates/router/src/core/payments/flows/reject_flow.rs @@ -51,6 +51,7 @@ impl Feature _call_connector_action: payments::CallConnectorAction, _connector_request: Option, _business_profile: &storage::business_profile::BusinessProfile, + _header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { Err(ApiErrorResponse::NotImplemented { message: NotImplementedMessage::Reason("Flow not supported".to_string()), diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index 0774f0a859..1223d861eb 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -65,6 +65,7 @@ impl Feature for types::PaymentsSessio call_connector_action: payments::CallConnectorAction, _connector_request: Option, business_profile: &storage::business_profile::BusinessProfile, + header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { metrics::SESSION_TOKEN_CREATED.add( &metrics::CONTEXT, @@ -77,6 +78,7 @@ impl Feature for types::PaymentsSessio Some(true), call_connector_action, business_profile, + header_payload, ) .await } @@ -155,6 +157,7 @@ async fn create_applepay_session_token( router_data: &types::PaymentsSessionRouterData, connector: &api::ConnectorData, business_profile: &storage::business_profile::BusinessProfile, + header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { let delayed_response = is_session_response_delayed(state, connector); if delayed_response { @@ -188,9 +191,10 @@ async fn create_applepay_session_token( // Get payment request data , apple pay session request and merchant keys let ( payment_request_data, - apple_pay_session_request, + apple_pay_session_request_optional, apple_pay_merchant_cert, apple_pay_merchant_cert_key, + apple_pay_merchant_identifier, merchant_business_country, ) = match apple_pay_metadata { payment_types::ApplepaySessionTokenMetadata::ApplePayCombined( @@ -213,7 +217,7 @@ async fn create_applepay_session_token( let merchant_business_country = session_token_data.merchant_business_country; let apple_pay_session_request = get_session_request_for_simplified_apple_pay( - merchant_identifier, + merchant_identifier.clone(), session_token_data, ); @@ -233,9 +237,10 @@ async fn create_applepay_session_token( ( payment_request_data, - apple_pay_session_request, + Ok(apple_pay_session_request), apple_pay_merchant_cert, apple_pay_merchant_cert_key, + merchant_identifier, merchant_business_country, ) } @@ -255,6 +260,7 @@ async fn create_applepay_session_token( apple_pay_session_request, session_token_data.certificate.clone(), session_token_data.certificate_keys, + session_token_data.merchant_identifier, merchant_business_country, ) } @@ -273,7 +279,11 @@ async fn create_applepay_session_token( apple_pay_metadata.payment_request_data, apple_pay_session_request, apple_pay_metadata.session_token_data.certificate.clone(), - apple_pay_metadata.session_token_data.certificate_keys, + apple_pay_metadata + .session_token_data + .certificate_keys + .clone(), + apple_pay_metadata.session_token_data.merchant_identifier, merchant_business_country, ) } @@ -323,48 +333,63 @@ async fn create_applepay_session_token( amount_info, payment_request_data, router_data.request.to_owned(), - apple_pay_session_request.merchant_identifier.as_str(), + apple_pay_merchant_identifier.as_str(), merchant_business_country, required_billing_contact_fields, required_shipping_contact_fields, )?; - let applepay_session_request = build_apple_pay_session_request( - state, - apple_pay_session_request, - apple_pay_merchant_cert, - apple_pay_merchant_cert_key, - )?; - let response = services::call_connector_api( - state, - applepay_session_request, - "create_apple_pay_session_token", - ) - .await; + let apple_pay_session_response = match ( + header_payload.browser_name, + header_payload.x_client_platform, + ) { + (Some(common_enums::BrowserName::Safari), Some(common_enums::ClientPlatform::Web)) + | (None, None) => { + let apple_pay_session_request = apple_pay_session_request_optional + .attach_printable("Failed to obtain apple pay session request")?; + let applepay_session_request = build_apple_pay_session_request( + state, + apple_pay_session_request, + apple_pay_merchant_cert, + apple_pay_merchant_cert_key, + )?; - // logging the error if present in session call response - log_session_response_if_error(&response); + let response = services::call_connector_api( + state, + applepay_session_request, + "create_apple_pay_session_token", + ) + .await; - let apple_pay_session_response = response - .ok() - .and_then(|apple_pay_res| { - apple_pay_res - .map(|res| { - let response: Result< - payment_types::NoThirdPartySdkSessionResponse, - Report, - > = res.response.parse_struct("NoThirdPartySdkSessionResponse"); + // logging the error if present in session call response + log_session_response_if_error(&response); - // logging the parsing failed error - if let Err(error) = response.as_ref() { - logger::error!(?error); - }; - - response.ok() - }) + response .ok() - }) - .flatten(); + .and_then(|apple_pay_res| { + apple_pay_res + .map(|res| { + let response: Result< + payment_types::NoThirdPartySdkSessionResponse, + Report, + > = res.response.parse_struct("NoThirdPartySdkSessionResponse"); + + // logging the parsing failed error + if let Err(error) = response.as_ref() { + logger::error!(?error); + }; + + response.ok() + }) + .ok() + }) + .flatten() + } + _ => { + logger::debug!("Skipping apple pay session call based on the browser name"); + None + } + }; let session_response = apple_pay_session_response.map(payment_types::ApplePaySessionResponse::NoThirdPartySdk); @@ -394,13 +419,17 @@ fn get_session_request_for_simplified_apple_pay( fn get_session_request_for_manual_apple_pay( session_token_data: payment_types::SessionTokenInfo, -) -> payment_types::ApplepaySessionRequest { - payment_types::ApplepaySessionRequest { +) -> RouterResult { + let initiative_context = session_token_data + .initiative_context + .ok_or(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to get initiative_context for apple pay session call")?; + Ok(payment_types::ApplepaySessionRequest { merchant_identifier: session_token_data.merchant_identifier.clone(), display_name: session_token_data.display_name.clone(), - initiative: session_token_data.initiative.clone(), - initiative_context: session_token_data.initiative_context, - } + initiative: session_token_data.initiative.to_string(), + initiative_context, + }) } fn get_apple_pay_amount_info( @@ -461,7 +490,7 @@ fn create_apple_pay_session_response( response: Ok(types::PaymentsResponseData::SessionResponse { session_token: payment_types::SessionToken::ApplePay(Box::new( payment_types::ApplepaySessionTokenResponse { - session_token_data: response, + session_token_data: Some(response), payment_request_data: apple_pay_payment_request, connector: connector_name, delayed_session_token: delayed_response, @@ -476,7 +505,18 @@ fn create_apple_pay_session_response( }), None => Ok(types::PaymentsSessionRouterData { response: Ok(types::PaymentsResponseData::SessionResponse { - session_token: payment_types::SessionToken::NoSessionTokenReceived, + session_token: payment_types::SessionToken::ApplePay(Box::new( + payment_types::ApplepaySessionTokenResponse { + session_token_data: None, + payment_request_data: apple_pay_payment_request, + connector: connector_name, + delayed_session_token: delayed_response, + sdk_next_action: { payment_types::SdkNextAction { next_action } }, + connector_reference_id: None, + connector_sdk_public_key: None, + connector_merchant_id: None, + }, + )), }), ..router_data.clone() }), @@ -650,6 +690,7 @@ where _confirm: Option, call_connector_action: payments::CallConnectorAction, business_profile: &storage::business_profile::BusinessProfile, + header_payload: api_models::payments::HeaderPayload, ) -> RouterResult; } @@ -698,13 +739,21 @@ impl RouterDataSession for types::PaymentsSessionRouterData { _confirm: Option, call_connector_action: payments::CallConnectorAction, business_profile: &storage::business_profile::BusinessProfile, + header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { match connector.get_token { api::GetToken::GpayMetadata => { create_gpay_session_token(state, self, connector, business_profile) } api::GetToken::ApplePayMetadata => { - create_applepay_session_token(state, self, connector, business_profile).await + create_applepay_session_token( + state, + self, + connector, + business_profile, + header_payload, + ) + .await } api::GetToken::PaypalSdkMetadata => { create_paypal_sdk_session_token(state, self, connector, business_profile) diff --git a/crates/router/src/core/payments/flows/setup_mandate_flow.rs b/crates/router/src/core/payments/flows/setup_mandate_flow.rs index 7a87677903..07803a0c0f 100644 --- a/crates/router/src/core/payments/flows/setup_mandate_flow.rs +++ b/crates/router/src/core/payments/flows/setup_mandate_flow.rs @@ -57,6 +57,7 @@ impl Feature for types::Setup call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &storage::business_profile::BusinessProfile, + _header_payload: api_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::SetupMandate, diff --git a/crates/router/src/lib.rs b/crates/router/src/lib.rs index c543be8cc9..f0d332514d 100644 --- a/crates/router/src/lib.rs +++ b/crates/router/src/lib.rs @@ -77,6 +77,8 @@ pub mod headers { pub const X_CLIENT_SOURCE: &str = "X-Client-Source"; pub const X_PAYMENT_CONFIRM_SOURCE: &str = "X-Payment-Confirm-Source"; pub const CONTENT_LENGTH: &str = "Content-Length"; + pub const BROWSER_NAME: &str = "browsername"; + pub const X_CLIENT_PLATFORM: &str = "x-client-platform"; } pub mod pii { diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index 912421f465..84c7986dd8 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -8,7 +8,7 @@ use actix_web::{web, Responder}; use api_models::payments::HeaderPayload; use error_stack::report; use masking::PeekInterface; -use router_env::{env, instrument, tracing, types, Flow}; +use router_env::{env, instrument, logger, tracing, types, Flow}; use super::app::ReqState; use crate::{ @@ -593,6 +593,14 @@ pub async fn payments_connector_session( let flow = Flow::PaymentsSessionToken; let payload = json_payload.into_inner(); + let header_payload = match HeaderPayload::foreign_try_from(req.headers()) { + Ok(headers) => headers, + Err(err) => { + logger::error!(?err, "Failed to get headers in payments_connector_session"); + HeaderPayload::default() + } + }; + tracing::Span::current().record("payment_id", &payload.payment_id); let locking_action = payload.get_locking_input(flow.clone()); @@ -619,7 +627,7 @@ pub async fn payments_connector_session( api::AuthFlow::Client, payments::CallConnectorAction::Trigger, None, - HeaderPayload::default(), + header_payload.clone(), ) }, &auth::PublishableKeyAuth, diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index f754b31e0b..57fc613af7 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -19,7 +19,10 @@ use masking::{ExposeInterface, PeekInterface}; use super::domain; use crate::{ core::errors, - headers::{X_CLIENT_SOURCE, X_CLIENT_VERSION, X_PAYMENT_CONFIRM_SOURCE}, + headers::{ + BROWSER_NAME, X_CLIENT_PLATFORM, X_CLIENT_SOURCE, X_CLIENT_VERSION, + X_PAYMENT_CONFIRM_SOURCE, + }, services::authentication::get_header_value_by_key, types::{ api::{self as api_types, routing as routing_types}, @@ -1106,11 +1109,32 @@ impl ForeignTryFrom<&HeaderMap> for payments::HeaderPayload { let client_version = get_header_value_by_key(X_CLIENT_VERSION.into(), headers)?.map(|val| val.to_string()); + let browser_name_str = + get_header_value_by_key(BROWSER_NAME.into(), headers)?.map(|val| val.to_string()); + + let browser_name: Option = browser_name_str.map(|browser_name| { + browser_name + .parse_enum("BrowserName") + .unwrap_or(api_enums::BrowserName::Unknown) + }); + + let x_client_platform_str = + get_header_value_by_key(X_CLIENT_PLATFORM.into(), headers)?.map(|val| val.to_string()); + + let x_client_platform: Option = + x_client_platform_str.map(|x_client_platform| { + x_client_platform + .parse_enum("ClientPlatform") + .unwrap_or(api_enums::ClientPlatform::Unknown) + }); + Ok(Self { payment_confirm_source, client_source, client_version, x_hs_latency: Some(x_hs_latency), + browser_name, + x_client_platform, }) } } diff --git a/crates/router/tests/connectors/payme.rs b/crates/router/tests/connectors/payme.rs index 590ad15d7f..605f63d0f6 100644 --- a/crates/router/tests/connectors/payme.rs +++ b/crates/router/tests/connectors/payme.rs @@ -68,6 +68,7 @@ fn get_default_payment_info() -> Option { return_url: None, connector_customer: None, payment_method_token: None, + #[cfg(feature = "payouts")] currency: None, #[cfg(feature = "payouts")] payout_method_data: None, diff --git a/crates/router/tests/connectors/square.rs b/crates/router/tests/connectors/square.rs index 322708c1da..f7b633e8a1 100644 --- a/crates/router/tests/connectors/square.rs +++ b/crates/router/tests/connectors/square.rs @@ -47,6 +47,7 @@ fn get_default_payment_info(payment_method_token: Option) -> Option, #[cfg(feature = "payouts")] pub payout_method_data: Option, + #[cfg(feature = "payouts")] pub currency: Option, }