feat: added client_source, client_version in payment_attempt from payments confirm request headers (#4657)

This commit is contained in:
Vrishab Srivatsa
2024-05-17 15:57:30 +05:30
committed by GitHub
parent 853f3b4854
commit 7e44bbca63
17 changed files with 97 additions and 10 deletions

View File

@ -540,9 +540,11 @@ impl RequestSurchargeDetails {
} }
} }
#[derive(Default, Debug, Clone, Copy)] #[derive(Default, Debug, Clone)]
pub struct HeaderPayload { pub struct HeaderPayload {
pub payment_confirm_source: Option<api_enums::PaymentSource>, pub payment_confirm_source: Option<api_enums::PaymentSource>,
pub client_source: Option<String>,
pub client_version: Option<String>,
pub x_hs_latency: Option<bool>, pub x_hs_latency: Option<bool>,
} }

View File

@ -70,6 +70,8 @@ pub struct PaymentAttempt {
pub mandate_data: Option<storage_enums::MandateDetails>, pub mandate_data: Option<storage_enums::MandateDetails>,
pub fingerprint_id: Option<String>, pub fingerprint_id: Option<String>,
pub payment_method_billing_address_id: Option<String>, pub payment_method_billing_address_id: Option<String>,
pub client_source: Option<String>,
pub client_version: Option<String>,
} }
impl PaymentAttempt { impl PaymentAttempt {
@ -150,6 +152,8 @@ pub struct PaymentAttemptNew {
pub mandate_data: Option<storage_enums::MandateDetails>, pub mandate_data: Option<storage_enums::MandateDetails>,
pub fingerprint_id: Option<String>, pub fingerprint_id: Option<String>,
pub payment_method_billing_address_id: Option<String>, pub payment_method_billing_address_id: Option<String>,
pub client_source: Option<String>,
pub client_version: Option<String>,
} }
impl PaymentAttemptNew { impl PaymentAttemptNew {
@ -233,6 +237,8 @@ pub enum PaymentAttemptUpdate {
authentication_connector: Option<String>, authentication_connector: Option<String>,
authentication_id: Option<String>, authentication_id: Option<String>,
payment_method_billing_address_id: Option<String>, payment_method_billing_address_id: Option<String>,
client_source: Option<String>,
client_version: Option<String>,
}, },
VoidUpdate { VoidUpdate {
status: storage_enums::AttemptStatus, status: storage_enums::AttemptStatus,
@ -388,6 +394,8 @@ pub struct PaymentAttemptUpdateInternal {
authentication_id: Option<String>, authentication_id: Option<String>,
fingerprint_id: Option<String>, fingerprint_id: Option<String>,
payment_method_billing_address_id: Option<String>, payment_method_billing_address_id: Option<String>,
client_source: Option<String>,
client_version: Option<String>,
} }
impl PaymentAttemptUpdateInternal { impl PaymentAttemptUpdateInternal {
@ -453,6 +461,8 @@ impl PaymentAttemptUpdate {
authentication_id, authentication_id,
payment_method_billing_address_id, payment_method_billing_address_id,
fingerprint_id, fingerprint_id,
client_source,
client_version,
} = PaymentAttemptUpdateInternal::from(self).populate_derived_fields(&source); } = PaymentAttemptUpdateInternal::from(self).populate_derived_fields(&source);
PaymentAttempt { PaymentAttempt {
amount: amount.unwrap_or(source.amount), amount: amount.unwrap_or(source.amount),
@ -501,6 +511,8 @@ impl PaymentAttemptUpdate {
payment_method_billing_address_id: payment_method_billing_address_id payment_method_billing_address_id: payment_method_billing_address_id
.or(source.payment_method_billing_address_id), .or(source.payment_method_billing_address_id),
fingerprint_id: fingerprint_id.or(source.fingerprint_id), fingerprint_id: fingerprint_id.or(source.fingerprint_id),
client_source: client_source.or(source.client_source),
client_version: client_version.or(source.client_version),
..source ..source
} }
} }
@ -587,6 +599,8 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
payment_method_billing_address_id, payment_method_billing_address_id,
fingerprint_id, fingerprint_id,
payment_method_id, payment_method_id,
client_source,
client_version,
} => Self { } => Self {
amount: Some(amount), amount: Some(amount),
currency: Some(currency), currency: Some(currency),
@ -616,6 +630,8 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
fingerprint_id, fingerprint_id,
payment_method_id, payment_method_id,
capture_method, capture_method,
client_source,
client_version,
..Default::default() ..Default::default()
}, },
PaymentAttemptUpdate::VoidUpdate { PaymentAttemptUpdate::VoidUpdate {

View File

@ -778,6 +778,10 @@ diesel::table! {
fingerprint_id -> Nullable<Varchar>, fingerprint_id -> Nullable<Varchar>,
#[max_length = 64] #[max_length = 64]
payment_method_billing_address_id -> Nullable<Varchar>, payment_method_billing_address_id -> Nullable<Varchar>,
#[max_length = 64]
client_source -> Nullable<Varchar>,
#[max_length = 64]
client_version -> Nullable<Varchar>,
} }
} }

View File

@ -73,6 +73,8 @@ pub struct PaymentAttemptBatchNew {
pub mandate_data: Option<MandateDetails>, pub mandate_data: Option<MandateDetails>,
pub payment_method_billing_address_id: Option<String>, pub payment_method_billing_address_id: Option<String>,
pub fingerprint_id: Option<String>, pub fingerprint_id: Option<String>,
pub client_source: Option<String>,
pub client_version: Option<String>,
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -133,6 +135,8 @@ impl PaymentAttemptBatchNew {
mandate_data: self.mandate_data, mandate_data: self.mandate_data,
payment_method_billing_address_id: self.payment_method_billing_address_id, payment_method_billing_address_id: self.payment_method_billing_address_id,
fingerprint_id: self.fingerprint_id, fingerprint_id: self.fingerprint_id,
client_source: self.client_source,
client_version: self.client_version,
} }
} }
} }

View File

@ -166,6 +166,8 @@ pub struct PaymentAttempt {
pub mandate_data: Option<MandateDetails>, pub mandate_data: Option<MandateDetails>,
pub payment_method_billing_address_id: Option<String>, pub payment_method_billing_address_id: Option<String>,
pub fingerprint_id: Option<String>, pub fingerprint_id: Option<String>,
pub client_source: Option<String>,
pub client_version: Option<String>,
} }
impl PaymentAttempt { impl PaymentAttempt {
@ -249,6 +251,8 @@ pub struct PaymentAttemptNew {
pub mandate_data: Option<MandateDetails>, pub mandate_data: Option<MandateDetails>,
pub payment_method_billing_address_id: Option<String>, pub payment_method_billing_address_id: Option<String>,
pub fingerprint_id: Option<String>, pub fingerprint_id: Option<String>,
pub client_source: Option<String>,
pub client_version: Option<String>,
} }
impl PaymentAttemptNew { impl PaymentAttemptNew {
@ -327,6 +331,8 @@ pub enum PaymentAttemptUpdate {
payment_method_billing_address_id: Option<String>, payment_method_billing_address_id: Option<String>,
fingerprint_id: Option<String>, fingerprint_id: Option<String>,
payment_method_id: Option<String>, payment_method_id: Option<String>,
client_source: Option<String>,
client_version: Option<String>,
}, },
RejectUpdate { RejectUpdate {
status: storage_enums::AttemptStatus, status: storage_enums::AttemptStatus,

View File

@ -294,7 +294,7 @@ where
call_connector_action.clone(), call_connector_action.clone(),
&validate_result, &validate_result,
schedule_time, schedule_time,
header_payload, header_payload.clone(),
#[cfg(feature = "frm")] #[cfg(feature = "frm")]
frm_info.as_ref().and_then(|fi| fi.suggested_action), frm_info.as_ref().and_then(|fi| fi.suggested_action),
#[cfg(not(feature = "frm"))] #[cfg(not(feature = "frm"))]
@ -364,7 +364,7 @@ where
call_connector_action.clone(), call_connector_action.clone(),
&validate_result, &validate_result,
schedule_time, schedule_time,
header_payload, header_payload.clone(),
#[cfg(feature = "frm")] #[cfg(feature = "frm")]
frm_info.as_ref().and_then(|fi| fi.suggested_action), frm_info.as_ref().and_then(|fi| fi.suggested_action),
#[cfg(not(feature = "frm"))] #[cfg(not(feature = "frm"))]
@ -497,7 +497,7 @@ where
frm_info.and_then(|info| info.suggested_action), frm_info.and_then(|info| info.suggested_action),
#[cfg(not(feature = "frm"))] #[cfg(not(feature = "frm"))]
None, None,
header_payload, header_payload.clone(),
) )
.await?; .await?;
} }
@ -528,7 +528,7 @@ where
None, None,
&key_store, &key_store,
None, None,
header_payload, header_payload.clone(),
) )
.await?; .await?;
} }
@ -785,7 +785,7 @@ where
call_connector_action, call_connector_action,
auth_flow, auth_flow,
eligible_routable_connectors, eligible_routable_connectors,
header_payload, header_payload.clone(),
) )
.await?; .await?;
@ -1579,7 +1579,7 @@ where
updated_customer, updated_customer,
key_store, key_store,
frm_suggestion, frm_suggestion,
header_payload, header_payload.clone(),
) )
.await?; .await?;

View File

@ -3554,6 +3554,8 @@ impl AttemptType {
// New payment method billing address can be passed for a retry // New payment method billing address can be passed for a retry
payment_method_billing_address_id: None, payment_method_billing_address_id: None,
fingerprint_id: None, fingerprint_id: None,
client_source: None,
client_version: None,
} }
} }

View File

@ -1069,6 +1069,15 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
.map(|surcharge_details| surcharge_details.final_amount) .map(|surcharge_details| surcharge_details.final_amount)
.unwrap_or(payment_data.payment_attempt.amount); .unwrap_or(payment_data.payment_attempt.amount);
let client_source = header_payload
.client_source
.clone()
.or(payment_data.payment_attempt.client_source.clone());
let client_version = header_payload
.client_version
.clone()
.or(payment_data.payment_attempt.client_version.clone());
let m_payment_data_payment_attempt = payment_data.payment_attempt.clone(); let m_payment_data_payment_attempt = payment_data.payment_attempt.clone();
let m_payment_method_id = payment_data.payment_attempt.payment_method_id.clone(); let m_payment_method_id = payment_data.payment_attempt.payment_method_id.clone();
let m_browser_info = browser_info.clone(); let m_browser_info = browser_info.clone();
@ -1136,6 +1145,8 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
payment_method_billing_address_id, payment_method_billing_address_id,
fingerprint_id: m_fingerprint_id, fingerprint_id: m_fingerprint_id,
payment_method_id: m_payment_method_id, payment_method_id: m_payment_method_id,
client_source,
client_version,
}, },
storage_scheme, storage_scheme,
) )

View File

@ -930,6 +930,8 @@ impl PaymentCreate {
fingerprint_id: None, fingerprint_id: None,
authentication_connector: None, authentication_connector: None,
authentication_id: None, authentication_id: None,
client_source: None,
client_version: None,
}, },
additional_pm_data, additional_pm_data,
)) ))

View File

@ -19,6 +19,7 @@ use crate::{
payments::{self, helpers}, payments::{self, helpers},
utils as core_utils, utils as core_utils,
}, },
headers::X_PAYMENT_CONFIRM_SOURCE,
routes::{metrics, AppState}, routes::{metrics, AppState},
services::{self, RedirectForm}, services::{self, RedirectForm},
types::{ types::{
@ -488,7 +489,7 @@ where
.unwrap_or_default(); .unwrap_or_default();
if let Some(payment_confirm_source) = payment_intent.payment_confirm_source { if let Some(payment_confirm_source) = payment_intent.payment_confirm_source {
headers.push(( headers.push((
"payment_confirm_source".to_string(), X_PAYMENT_CONFIRM_SOURCE.to_string(),
Maskable::new_normal(payment_confirm_source.to_string()), Maskable::new_normal(payment_confirm_source.to_string()),
)) ))
} }

View File

@ -72,6 +72,9 @@ pub mod headers {
pub const X_REQUEST_ID: &str = "X-Request-Id"; pub const X_REQUEST_ID: &str = "X-Request-Id";
pub const STRIPE_COMPATIBLE_WEBHOOK_SIGNATURE: &str = "Stripe-Signature"; pub const STRIPE_COMPATIBLE_WEBHOOK_SIGNATURE: &str = "Stripe-Signature";
pub const STRIPE_COMPATIBLE_CONNECT_ACCOUNT: &str = "Stripe-Account"; pub const STRIPE_COMPATIBLE_CONNECT_ACCOUNT: &str = "Stripe-Account";
pub const X_CLIENT_VERSION: &str = "X-Client-Version";
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 CONTENT_LENGTH: &str = "Content-Length";
} }

View File

@ -497,7 +497,7 @@ pub async fn payments_confirm(
req_state, req_state,
auth.merchant_account, auth.merchant_account,
auth.key_store, auth.key_store,
header_payload, header_payload.clone(),
req, req,
auth_flow, auth_flow,
) )

View File

@ -18,6 +18,7 @@ use masking::{ExposeInterface, PeekInterface};
use super::domain; use super::domain;
use crate::{ use crate::{
core::errors, core::errors,
headers::{X_CLIENT_SOURCE, X_CLIENT_VERSION, X_PAYMENT_CONFIRM_SOURCE},
services::authentication::get_header_value_by_key, services::authentication::get_header_value_by_key,
types::{ types::{
api::{self as api_types, routing as routing_types}, api::{self as api_types, routing as routing_types},
@ -1011,7 +1012,7 @@ impl ForeignTryFrom<&HeaderMap> for payments::HeaderPayload {
type Error = error_stack::Report<errors::ApiErrorResponse>; type Error = error_stack::Report<errors::ApiErrorResponse>;
fn foreign_try_from(headers: &HeaderMap) -> Result<Self, Self::Error> { fn foreign_try_from(headers: &HeaderMap) -> Result<Self, Self::Error> {
let payment_confirm_source: Option<api_enums::PaymentSource> = let payment_confirm_source: Option<api_enums::PaymentSource> =
get_header_value_by_key("payment_confirm_source".into(), headers)? get_header_value_by_key(X_PAYMENT_CONFIRM_SOURCE.into(), headers)?
.map(|source| { .map(|source| {
source source
.to_owned() .to_owned()
@ -1038,8 +1039,17 @@ impl ForeignTryFrom<&HeaderMap> for payments::HeaderPayload {
let x_hs_latency = get_header_value_by_key(X_HS_LATENCY.into(), headers) let x_hs_latency = get_header_value_by_key(X_HS_LATENCY.into(), headers)
.map(|value| value == Some("true")) .map(|value| value == Some("true"))
.unwrap_or(false); .unwrap_or(false);
let client_source =
get_header_value_by_key(X_CLIENT_SOURCE.into(), headers)?.map(|val| val.to_string());
let client_version =
get_header_value_by_key(X_CLIENT_VERSION.into(), headers)?.map(|val| val.to_string());
Ok(Self { Ok(Self {
payment_confirm_source, payment_confirm_source,
client_source,
client_version,
x_hs_latency: Some(x_hs_latency), x_hs_latency: Some(x_hs_latency),
}) })
} }

View File

@ -157,6 +157,8 @@ impl PaymentAttemptInterface for MockDb {
mandate_data: payment_attempt.mandate_data, mandate_data: payment_attempt.mandate_data,
payment_method_billing_address_id: payment_attempt.payment_method_billing_address_id, payment_method_billing_address_id: payment_attempt.payment_method_billing_address_id,
fingerprint_id: payment_attempt.fingerprint_id, fingerprint_id: payment_attempt.fingerprint_id,
client_source: payment_attempt.client_source,
client_version: payment_attempt.client_version,
}; };
payment_attempts.push(payment_attempt.clone()); payment_attempts.push(payment_attempt.clone());
Ok(payment_attempt) Ok(payment_attempt)

View File

@ -410,6 +410,8 @@ impl<T: DatabaseStore> PaymentAttemptInterface for KVRouterStore<T> {
.payment_method_billing_address_id .payment_method_billing_address_id
.clone(), .clone(),
fingerprint_id: payment_attempt.fingerprint_id.clone(), fingerprint_id: payment_attempt.fingerprint_id.clone(),
client_source: payment_attempt.client_source.clone(),
client_version: payment_attempt.client_version.clone(),
}; };
let field = format!("pa_{}", created_attempt.attempt_id); let field = format!("pa_{}", created_attempt.attempt_id);
@ -1164,6 +1166,8 @@ impl DataModelExt for PaymentAttempt {
mandate_data: self.mandate_data.map(|d| d.to_storage_model()), mandate_data: self.mandate_data.map(|d| d.to_storage_model()),
payment_method_billing_address_id: self.payment_method_billing_address_id, payment_method_billing_address_id: self.payment_method_billing_address_id,
fingerprint_id: self.fingerprint_id, fingerprint_id: self.fingerprint_id,
client_source: self.client_source,
client_version: self.client_version,
} }
} }
@ -1228,6 +1232,8 @@ impl DataModelExt for PaymentAttempt {
.map(MandateDetails::from_storage_model), .map(MandateDetails::from_storage_model),
payment_method_billing_address_id: storage_model.payment_method_billing_address_id, payment_method_billing_address_id: storage_model.payment_method_billing_address_id,
fingerprint_id: storage_model.fingerprint_id, fingerprint_id: storage_model.fingerprint_id,
client_source: storage_model.client_source,
client_version: storage_model.client_version,
} }
} }
} }
@ -1290,6 +1296,8 @@ impl DataModelExt for PaymentAttemptNew {
mandate_data: self.mandate_data.map(|d| d.to_storage_model()), mandate_data: self.mandate_data.map(|d| d.to_storage_model()),
payment_method_billing_address_id: self.payment_method_billing_address_id, payment_method_billing_address_id: self.payment_method_billing_address_id,
fingerprint_id: self.fingerprint_id, fingerprint_id: self.fingerprint_id,
client_source: self.client_source,
client_version: self.client_version,
} }
} }
@ -1352,6 +1360,8 @@ impl DataModelExt for PaymentAttemptNew {
.map(MandateDetails::from_storage_model), .map(MandateDetails::from_storage_model),
payment_method_billing_address_id: storage_model.payment_method_billing_address_id, payment_method_billing_address_id: storage_model.payment_method_billing_address_id,
fingerprint_id: storage_model.fingerprint_id, fingerprint_id: storage_model.fingerprint_id,
client_source: storage_model.client_source,
client_version: storage_model.client_version,
} }
} }
} }
@ -1470,6 +1480,8 @@ impl DataModelExt for PaymentAttemptUpdate {
authentication_connector, authentication_connector,
authentication_id, authentication_id,
payment_method_billing_address_id, payment_method_billing_address_id,
client_source,
client_version,
} => DieselPaymentAttemptUpdate::ConfirmUpdate { } => DieselPaymentAttemptUpdate::ConfirmUpdate {
amount, amount,
currency, currency,
@ -1498,6 +1510,8 @@ impl DataModelExt for PaymentAttemptUpdate {
authentication_connector, authentication_connector,
authentication_id, authentication_id,
payment_method_billing_address_id, payment_method_billing_address_id,
client_source,
client_version,
}, },
Self::VoidUpdate { Self::VoidUpdate {
status, status,
@ -1773,6 +1787,8 @@ impl DataModelExt for PaymentAttemptUpdate {
authentication_connector, authentication_connector,
authentication_id, authentication_id,
payment_method_billing_address_id, payment_method_billing_address_id,
client_source,
client_version,
} => Self::ConfirmUpdate { } => Self::ConfirmUpdate {
amount, amount,
currency, currency,
@ -1801,6 +1817,8 @@ impl DataModelExt for PaymentAttemptUpdate {
authentication_connector, authentication_connector,
authentication_id, authentication_id,
payment_method_billing_address_id, payment_method_billing_address_id,
client_source,
client_version,
}, },
DieselPaymentAttemptUpdate::VoidUpdate { DieselPaymentAttemptUpdate::VoidUpdate {
status, status,

View File

@ -0,0 +1,3 @@
-- This file should undo anything in `up.sql`
ALTER TABLE payment_attempt DROP COLUMN IF EXISTS client_version;
ALTER TABLE payment_attempt DROP COLUMN IF EXISTS client_source;

View File

@ -0,0 +1,3 @@
-- Your SQL goes here
ALTER TABLE payment_attempt ADD COLUMN IF NOT EXISTS client_source VARCHAR(64) DEFAULT NULL;
ALTER TABLE payment_attempt ADD COLUMN IF NOT EXISTS client_version VARCHAR(64) DEFAULT NULL;