mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +08:00
feat: added client_source, client_version in payment_attempt from payments confirm request headers (#4657)
This commit is contained in:
@ -540,9 +540,11 @@ impl RequestSurchargeDetails {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct HeaderPayload {
|
||||
pub payment_confirm_source: Option<api_enums::PaymentSource>,
|
||||
pub client_source: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
pub x_hs_latency: Option<bool>,
|
||||
}
|
||||
|
||||
|
||||
@ -70,6 +70,8 @@ pub struct PaymentAttempt {
|
||||
pub mandate_data: Option<storage_enums::MandateDetails>,
|
||||
pub fingerprint_id: Option<String>,
|
||||
pub payment_method_billing_address_id: Option<String>,
|
||||
pub client_source: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
}
|
||||
|
||||
impl PaymentAttempt {
|
||||
@ -150,6 +152,8 @@ pub struct PaymentAttemptNew {
|
||||
pub mandate_data: Option<storage_enums::MandateDetails>,
|
||||
pub fingerprint_id: Option<String>,
|
||||
pub payment_method_billing_address_id: Option<String>,
|
||||
pub client_source: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
}
|
||||
|
||||
impl PaymentAttemptNew {
|
||||
@ -233,6 +237,8 @@ pub enum PaymentAttemptUpdate {
|
||||
authentication_connector: Option<String>,
|
||||
authentication_id: Option<String>,
|
||||
payment_method_billing_address_id: Option<String>,
|
||||
client_source: Option<String>,
|
||||
client_version: Option<String>,
|
||||
},
|
||||
VoidUpdate {
|
||||
status: storage_enums::AttemptStatus,
|
||||
@ -388,6 +394,8 @@ pub struct PaymentAttemptUpdateInternal {
|
||||
authentication_id: Option<String>,
|
||||
fingerprint_id: Option<String>,
|
||||
payment_method_billing_address_id: Option<String>,
|
||||
client_source: Option<String>,
|
||||
client_version: Option<String>,
|
||||
}
|
||||
|
||||
impl PaymentAttemptUpdateInternal {
|
||||
@ -453,6 +461,8 @@ impl PaymentAttemptUpdate {
|
||||
authentication_id,
|
||||
payment_method_billing_address_id,
|
||||
fingerprint_id,
|
||||
client_source,
|
||||
client_version,
|
||||
} = PaymentAttemptUpdateInternal::from(self).populate_derived_fields(&source);
|
||||
PaymentAttempt {
|
||||
amount: amount.unwrap_or(source.amount),
|
||||
@ -501,6 +511,8 @@ impl PaymentAttemptUpdate {
|
||||
payment_method_billing_address_id: payment_method_billing_address_id
|
||||
.or(source.payment_method_billing_address_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
|
||||
}
|
||||
}
|
||||
@ -587,6 +599,8 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
|
||||
payment_method_billing_address_id,
|
||||
fingerprint_id,
|
||||
payment_method_id,
|
||||
client_source,
|
||||
client_version,
|
||||
} => Self {
|
||||
amount: Some(amount),
|
||||
currency: Some(currency),
|
||||
@ -616,6 +630,8 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
|
||||
fingerprint_id,
|
||||
payment_method_id,
|
||||
capture_method,
|
||||
client_source,
|
||||
client_version,
|
||||
..Default::default()
|
||||
},
|
||||
PaymentAttemptUpdate::VoidUpdate {
|
||||
|
||||
@ -778,6 +778,10 @@ diesel::table! {
|
||||
fingerprint_id -> Nullable<Varchar>,
|
||||
#[max_length = 64]
|
||||
payment_method_billing_address_id -> Nullable<Varchar>,
|
||||
#[max_length = 64]
|
||||
client_source -> Nullable<Varchar>,
|
||||
#[max_length = 64]
|
||||
client_version -> Nullable<Varchar>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -73,6 +73,8 @@ pub struct PaymentAttemptBatchNew {
|
||||
pub mandate_data: Option<MandateDetails>,
|
||||
pub payment_method_billing_address_id: Option<String>,
|
||||
pub fingerprint_id: Option<String>,
|
||||
pub client_source: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -133,6 +135,8 @@ impl PaymentAttemptBatchNew {
|
||||
mandate_data: self.mandate_data,
|
||||
payment_method_billing_address_id: self.payment_method_billing_address_id,
|
||||
fingerprint_id: self.fingerprint_id,
|
||||
client_source: self.client_source,
|
||||
client_version: self.client_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,6 +166,8 @@ pub struct PaymentAttempt {
|
||||
pub mandate_data: Option<MandateDetails>,
|
||||
pub payment_method_billing_address_id: Option<String>,
|
||||
pub fingerprint_id: Option<String>,
|
||||
pub client_source: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
}
|
||||
|
||||
impl PaymentAttempt {
|
||||
@ -249,6 +251,8 @@ pub struct PaymentAttemptNew {
|
||||
pub mandate_data: Option<MandateDetails>,
|
||||
pub payment_method_billing_address_id: Option<String>,
|
||||
pub fingerprint_id: Option<String>,
|
||||
pub client_source: Option<String>,
|
||||
pub client_version: Option<String>,
|
||||
}
|
||||
|
||||
impl PaymentAttemptNew {
|
||||
@ -327,6 +331,8 @@ pub enum PaymentAttemptUpdate {
|
||||
payment_method_billing_address_id: Option<String>,
|
||||
fingerprint_id: Option<String>,
|
||||
payment_method_id: Option<String>,
|
||||
client_source: Option<String>,
|
||||
client_version: Option<String>,
|
||||
},
|
||||
RejectUpdate {
|
||||
status: storage_enums::AttemptStatus,
|
||||
|
||||
@ -294,7 +294,7 @@ where
|
||||
call_connector_action.clone(),
|
||||
&validate_result,
|
||||
schedule_time,
|
||||
header_payload,
|
||||
header_payload.clone(),
|
||||
#[cfg(feature = "frm")]
|
||||
frm_info.as_ref().and_then(|fi| fi.suggested_action),
|
||||
#[cfg(not(feature = "frm"))]
|
||||
@ -364,7 +364,7 @@ where
|
||||
call_connector_action.clone(),
|
||||
&validate_result,
|
||||
schedule_time,
|
||||
header_payload,
|
||||
header_payload.clone(),
|
||||
#[cfg(feature = "frm")]
|
||||
frm_info.as_ref().and_then(|fi| fi.suggested_action),
|
||||
#[cfg(not(feature = "frm"))]
|
||||
@ -497,7 +497,7 @@ where
|
||||
frm_info.and_then(|info| info.suggested_action),
|
||||
#[cfg(not(feature = "frm"))]
|
||||
None,
|
||||
header_payload,
|
||||
header_payload.clone(),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
@ -528,7 +528,7 @@ where
|
||||
None,
|
||||
&key_store,
|
||||
None,
|
||||
header_payload,
|
||||
header_payload.clone(),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
@ -785,7 +785,7 @@ where
|
||||
call_connector_action,
|
||||
auth_flow,
|
||||
eligible_routable_connectors,
|
||||
header_payload,
|
||||
header_payload.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@ -1579,7 +1579,7 @@ where
|
||||
updated_customer,
|
||||
key_store,
|
||||
frm_suggestion,
|
||||
header_payload,
|
||||
header_payload.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@ -3554,6 +3554,8 @@ impl AttemptType {
|
||||
// New payment method billing address can be passed for a retry
|
||||
payment_method_billing_address_id: None,
|
||||
fingerprint_id: None,
|
||||
client_source: None,
|
||||
client_version: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1069,6 +1069,15 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
|
||||
.map(|surcharge_details| surcharge_details.final_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_method_id = payment_data.payment_attempt.payment_method_id.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,
|
||||
fingerprint_id: m_fingerprint_id,
|
||||
payment_method_id: m_payment_method_id,
|
||||
client_source,
|
||||
client_version,
|
||||
},
|
||||
storage_scheme,
|
||||
)
|
||||
|
||||
@ -930,6 +930,8 @@ impl PaymentCreate {
|
||||
fingerprint_id: None,
|
||||
authentication_connector: None,
|
||||
authentication_id: None,
|
||||
client_source: None,
|
||||
client_version: None,
|
||||
},
|
||||
additional_pm_data,
|
||||
))
|
||||
|
||||
@ -19,6 +19,7 @@ use crate::{
|
||||
payments::{self, helpers},
|
||||
utils as core_utils,
|
||||
},
|
||||
headers::X_PAYMENT_CONFIRM_SOURCE,
|
||||
routes::{metrics, AppState},
|
||||
services::{self, RedirectForm},
|
||||
types::{
|
||||
@ -488,7 +489,7 @@ where
|
||||
.unwrap_or_default();
|
||||
if let Some(payment_confirm_source) = payment_intent.payment_confirm_source {
|
||||
headers.push((
|
||||
"payment_confirm_source".to_string(),
|
||||
X_PAYMENT_CONFIRM_SOURCE.to_string(),
|
||||
Maskable::new_normal(payment_confirm_source.to_string()),
|
||||
))
|
||||
}
|
||||
|
||||
@ -72,6 +72,9 @@ pub mod headers {
|
||||
pub const X_REQUEST_ID: &str = "X-Request-Id";
|
||||
pub const STRIPE_COMPATIBLE_WEBHOOK_SIGNATURE: &str = "Stripe-Signature";
|
||||
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";
|
||||
}
|
||||
|
||||
|
||||
@ -497,7 +497,7 @@ pub async fn payments_confirm(
|
||||
req_state,
|
||||
auth.merchant_account,
|
||||
auth.key_store,
|
||||
header_payload,
|
||||
header_payload.clone(),
|
||||
req,
|
||||
auth_flow,
|
||||
)
|
||||
|
||||
@ -18,6 +18,7 @@ use masking::{ExposeInterface, PeekInterface};
|
||||
use super::domain;
|
||||
use crate::{
|
||||
core::errors,
|
||||
headers::{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},
|
||||
@ -1011,7 +1012,7 @@ impl ForeignTryFrom<&HeaderMap> for payments::HeaderPayload {
|
||||
type Error = error_stack::Report<errors::ApiErrorResponse>;
|
||||
fn foreign_try_from(headers: &HeaderMap) -> Result<Self, Self::Error> {
|
||||
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| {
|
||||
source
|
||||
.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)
|
||||
.map(|value| value == Some("true"))
|
||||
.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 {
|
||||
payment_confirm_source,
|
||||
client_source,
|
||||
client_version,
|
||||
x_hs_latency: Some(x_hs_latency),
|
||||
})
|
||||
}
|
||||
|
||||
@ -157,6 +157,8 @@ impl PaymentAttemptInterface for MockDb {
|
||||
mandate_data: payment_attempt.mandate_data,
|
||||
payment_method_billing_address_id: payment_attempt.payment_method_billing_address_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());
|
||||
Ok(payment_attempt)
|
||||
|
||||
@ -410,6 +410,8 @@ impl<T: DatabaseStore> PaymentAttemptInterface for KVRouterStore<T> {
|
||||
.payment_method_billing_address_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);
|
||||
@ -1164,6 +1166,8 @@ impl DataModelExt for PaymentAttempt {
|
||||
mandate_data: self.mandate_data.map(|d| d.to_storage_model()),
|
||||
payment_method_billing_address_id: self.payment_method_billing_address_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),
|
||||
payment_method_billing_address_id: storage_model.payment_method_billing_address_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()),
|
||||
payment_method_billing_address_id: self.payment_method_billing_address_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),
|
||||
payment_method_billing_address_id: storage_model.payment_method_billing_address_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_id,
|
||||
payment_method_billing_address_id,
|
||||
client_source,
|
||||
client_version,
|
||||
} => DieselPaymentAttemptUpdate::ConfirmUpdate {
|
||||
amount,
|
||||
currency,
|
||||
@ -1498,6 +1510,8 @@ impl DataModelExt for PaymentAttemptUpdate {
|
||||
authentication_connector,
|
||||
authentication_id,
|
||||
payment_method_billing_address_id,
|
||||
client_source,
|
||||
client_version,
|
||||
},
|
||||
Self::VoidUpdate {
|
||||
status,
|
||||
@ -1773,6 +1787,8 @@ impl DataModelExt for PaymentAttemptUpdate {
|
||||
authentication_connector,
|
||||
authentication_id,
|
||||
payment_method_billing_address_id,
|
||||
client_source,
|
||||
client_version,
|
||||
} => Self::ConfirmUpdate {
|
||||
amount,
|
||||
currency,
|
||||
@ -1801,6 +1817,8 @@ impl DataModelExt for PaymentAttemptUpdate {
|
||||
authentication_connector,
|
||||
authentication_id,
|
||||
payment_method_billing_address_id,
|
||||
client_source,
|
||||
client_version,
|
||||
},
|
||||
DieselPaymentAttemptUpdate::VoidUpdate {
|
||||
status,
|
||||
|
||||
@ -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;
|
||||
@ -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;
|
||||
Reference in New Issue
Block a user