diff --git a/crates/diesel_models/src/mandate.rs b/crates/diesel_models/src/mandate.rs index 09a4ab17d0..7ed37dc2fd 100644 --- a/crates/diesel_models/src/mandate.rs +++ b/crates/diesel_models/src/mandate.rs @@ -35,6 +35,8 @@ pub struct Mandate { pub original_payment_id: Option, pub merchant_connector_id: Option, pub updated_by: Option, + // This is the extended version of customer user agent that can store string upto 2048 characters unlike customer user agent that can store 255 characters at max + pub customer_user_agent_extended: Option, } #[derive( @@ -73,6 +75,7 @@ pub struct MandateNew { pub original_payment_id: Option, pub merchant_connector_id: Option, pub updated_by: Option, + pub customer_user_agent_extended: Option, } impl MandateNew { @@ -216,7 +219,7 @@ impl From<&MandateNew> for Mandate { mandate_type: mandate_new.mandate_type, customer_accepted_at: mandate_new.customer_accepted_at, customer_ip_address: mandate_new.customer_ip_address.clone(), - customer_user_agent: mandate_new.customer_user_agent.clone(), + customer_user_agent: None, network_transaction_id: mandate_new.network_transaction_id.clone(), previous_attempt_id: mandate_new.previous_attempt_id.clone(), created_at: mandate_new @@ -234,6 +237,11 @@ impl From<&MandateNew> for Mandate { original_payment_id: mandate_new.original_payment_id.clone(), merchant_connector_id: mandate_new.merchant_connector_id.clone(), updated_by: mandate_new.updated_by.clone(), + // Using customer_user_agent as a fallback + customer_user_agent_extended: mandate_new + .customer_user_agent_extended + .clone() + .or_else(|| mandate_new.customer_user_agent.clone()), } } } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 0cf2f2decc..6788f47827 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -723,6 +723,8 @@ diesel::table! { merchant_connector_id -> Nullable, #[max_length = 64] updated_by -> Nullable, + #[max_length = 2048] + customer_user_agent_extended -> Nullable, } } diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index b461741d42..c5579b6c67 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -736,6 +736,8 @@ diesel::table! { merchant_connector_id -> Nullable, #[max_length = 64] updated_by -> Nullable, + #[max_length = 2048] + customer_user_agent_extended -> Nullable, } } diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 0b1758990a..39eeba8223 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -3439,7 +3439,7 @@ pub fn generate_mandate( .get_ip_address() .map(masking::Secret::new), ) - .set_customer_user_agent(customer_acceptance.get_user_agent()) + .set_customer_user_agent_extended(customer_acceptance.get_user_agent()) .set_customer_accepted_at(Some(customer_acceptance.get_accepted_at())) .set_metadata(payment_method_data_option.map(|payment_method_data| { pii::SecretSerdeValue::new( diff --git a/crates/router/src/db/mandate.rs b/crates/router/src/db/mandate.rs index 1d1d712de1..3bd80407fc 100644 --- a/crates/router/src/db/mandate.rs +++ b/crates/router/src/db/mandate.rs @@ -671,7 +671,7 @@ impl MandateInterface for MockDb { mandate_type: mandate_new.mandate_type, customer_accepted_at: mandate_new.customer_accepted_at, customer_ip_address: mandate_new.customer_ip_address, - customer_user_agent: mandate_new.customer_user_agent, + customer_user_agent: None, network_transaction_id: mandate_new.network_transaction_id, previous_attempt_id: mandate_new.previous_attempt_id, created_at: mandate_new @@ -688,6 +688,10 @@ impl MandateInterface for MockDb { connector_mandate_ids: mandate_new.connector_mandate_ids, merchant_connector_id: mandate_new.merchant_connector_id, updated_by: mandate_new.updated_by, + // Using customer_user_agent as a fallback + customer_user_agent_extended: mandate_new + .customer_user_agent_extended + .or_else(|| mandate_new.customer_user_agent.clone()), }; mandates.push(mandate.clone()); Ok(mandate) diff --git a/crates/router/src/types/api/mandates.rs b/crates/router/src/types/api/mandates.rs index e3cb8cf535..343d6e196b 100644 --- a/crates/router/src/types/api/mandates.rs +++ b/crates/router/src/types/api/mandates.rs @@ -106,7 +106,11 @@ impl MandateResponseExt for MandateResponse { accepted_at: mandate.customer_accepted_at, online: Some(api::payments::OnlineMandate { ip_address: mandate.customer_ip_address, - user_agent: mandate.customer_user_agent.unwrap_or_default(), + // Using customer_user_agent as a fallback + user_agent: mandate + .customer_user_agent_extended + .or(mandate.customer_user_agent) + .unwrap_or_default(), }), }), card, diff --git a/migrations/2025-07-24-081357_customer_user_agent_extended/down.sql b/migrations/2025-07-24-081357_customer_user_agent_extended/down.sql new file mode 100644 index 0000000000..9d2c357c3e --- /dev/null +++ b/migrations/2025-07-24-081357_customer_user_agent_extended/down.sql @@ -0,0 +1 @@ +ALTER TABLE mandate DROP COLUMN IF EXISTS customer_user_agent_extended; diff --git a/migrations/2025-07-24-081357_customer_user_agent_extended/up.sql b/migrations/2025-07-24-081357_customer_user_agent_extended/up.sql new file mode 100644 index 0000000000..9f357de689 --- /dev/null +++ b/migrations/2025-07-24-081357_customer_user_agent_extended/up.sql @@ -0,0 +1,4 @@ +ALTER TABLE mandate +ADD COLUMN +IF NOT EXISTS customer_user_agent_extended VARCHAR +(2048);