feat(payment): customer ip field inclusion (#1370)

Co-authored-by: shashank_attarde <shashank.attarde@juspay.in>
This commit is contained in:
Prajjwal Kumar
2023-06-09 12:30:39 +05:30
committed by GitHub
parent 795500797d
commit 11a827a76d
12 changed files with 462 additions and 124 deletions

View File

@ -1,5 +1,6 @@
use api_models::{enums, payments, webhooks};
use cards::CardNumber;
use error_stack::ResultExt;
use masking::PeekInterface;
use reqwest::Url;
use serde::{Deserialize, Serialize};
@ -19,6 +20,7 @@ use crate::{
storage::enums as storage_enums,
transformers::ForeignFrom,
},
utils::OptionExt,
};
type Error = error_stack::Report<errors::ConnectorError>;
@ -839,25 +841,73 @@ fn get_recurring_processing_model(
}
}
fn get_browser_info(item: &types::PaymentsAuthorizeRouterData) -> Option<AdyenBrowserInfo> {
fn get_browser_info(
item: &types::PaymentsAuthorizeRouterData,
) -> Result<Option<AdyenBrowserInfo>, Error> {
if item.auth_type == storage_enums::AuthenticationType::ThreeDs
|| item.payment_method == storage_enums::PaymentMethod::BankRedirect
{
item.request
.browser_info
.as_ref()
.map(|info| AdyenBrowserInfo {
accept_header: info.accept_header.clone(),
language: info.language.clone(),
screen_height: info.screen_height,
screen_width: info.screen_width,
color_depth: info.color_depth,
user_agent: info.user_agent.clone(),
time_zone_offset: info.time_zone,
java_enabled: info.java_enabled,
.map(|info| {
Ok(AdyenBrowserInfo {
accept_header: info
.accept_header
.clone()
.get_required_value("accept_header")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "accept_header",
})?,
language: info
.language
.clone()
.get_required_value("language")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "language",
})?,
screen_height: info
.screen_height
.get_required_value("screen_height")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "screen_height",
})?,
screen_width: info
.screen_width
.get_required_value("screen_width")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "screen_width",
})?,
color_depth: info
.color_depth
.get_required_value("color_depth")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "color_depth",
})?,
user_agent: info
.user_agent
.clone()
.get_required_value("user_agent")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "user_agent",
})?,
time_zone_offset: info
.time_zone
.get_required_value("time_zone_offset")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "time_zone_offset",
})?,
java_enabled: info
.java_enabled
.get_required_value("java_enabled")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "java_enabled",
})?,
})
})
.transpose()
} else {
None
Ok(None)
}
}
@ -1246,7 +1296,7 @@ impl<'a>
let shopper_interaction = AdyenShopperInteraction::from(item);
let (recurring_processing_model, store_payment_method, shopper_reference) =
get_recurring_processing_model(item)?;
let browser_info = get_browser_info(item);
let browser_info = get_browser_info(item)?;
let additional_data = get_additional_data(item);
let return_url = item.request.get_return_url()?;
let payment_method = match mandate_ref_id {
@ -1318,7 +1368,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::Card)> for AdyenPay
let shopper_interaction = AdyenShopperInteraction::from(item);
let (recurring_processing_model, store_payment_method, shopper_reference) =
get_recurring_processing_model(item)?;
let browser_info = get_browser_info(item);
let browser_info = get_browser_info(item)?;
let additional_data = get_additional_data(item);
let return_url = item.request.get_return_url()?;
let payment_method = AdyenPaymentMethod::try_from(card_data)?;
@ -1365,7 +1415,7 @@ impl<'a>
let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?;
let shopper_interaction = AdyenShopperInteraction::from(item);
let recurring_processing_model = get_recurring_processing_model(item)?.0;
let browser_info = get_browser_info(item);
let browser_info = get_browser_info(item)?;
let additional_data = get_additional_data(item);
let return_url = item.request.get_return_url()?;
let payment_method = AdyenPaymentMethod::try_from(bank_debit_data)?;
@ -1414,7 +1464,7 @@ impl<'a>
let shopper_interaction = AdyenShopperInteraction::from(item);
let (recurring_processing_model, store_payment_method, shopper_reference) =
get_recurring_processing_model(item)?;
let browser_info = get_browser_info(item);
let browser_info = get_browser_info(item)?;
let additional_data = get_additional_data(item);
let return_url = item.request.get_return_url()?;
let payment_method = AdyenPaymentMethod::try_from(bank_redirect_data)?;
@ -1478,7 +1528,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::WalletData)>
let (item, wallet_data) = value;
let amount = get_amount_data(item);
let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?;
let browser_info = get_browser_info(item);
let browser_info = get_browser_info(item)?;
let additional_data = get_additional_data(item);
let payment_method = AdyenPaymentMethod::try_from(wallet_data)?;
let shopper_interaction = AdyenShopperInteraction::from(item);
@ -1519,7 +1569,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::PayLaterData)>
let (item, paylater_data) = value;
let amount = get_amount_data(item);
let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?;
let browser_info = get_browser_info(item);
let browser_info = get_browser_info(item)?;
let additional_data = get_additional_data(item);
let payment_method = AdyenPaymentMethod::try_from(paylater_data)?;
let shopper_interaction = AdyenShopperInteraction::from(item);

View File

@ -10,6 +10,7 @@ use crate::{
core::errors,
services,
types::{self, api, storage::enums},
utils::OptionExt,
};
#[derive(Default, Debug, Serialize, Eq, PartialEq)]
@ -55,24 +56,77 @@ pub struct BamboraPaymentsRequest {
card: BamboraCard,
}
fn get_browser_info(item: &types::PaymentsAuthorizeRouterData) -> Option<BamboraBrowserInfo> {
fn get_browser_info(
item: &types::PaymentsAuthorizeRouterData,
) -> Result<Option<BamboraBrowserInfo>, error_stack::Report<errors::ConnectorError>> {
if matches!(item.auth_type, enums::AuthenticationType::ThreeDs) {
item.request
.browser_info
.as_ref()
.map(|info| BamboraBrowserInfo {
accept_header: info.accept_header.clone(),
java_enabled: info.java_enabled,
language: info.language.clone(),
color_depth: info.color_depth,
screen_height: info.screen_height,
screen_width: info.screen_width,
time_zone: info.time_zone,
user_agent: info.user_agent.clone(),
javascript_enabled: info.java_script_enabled,
.map(|info| {
Ok(BamboraBrowserInfo {
accept_header: info
.accept_header
.clone()
.get_required_value("accept_header")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "accept_header",
})?,
java_enabled: info
.java_enabled
.get_required_value("java_enabled")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "java_enabled",
})?,
language: info
.language
.clone()
.get_required_value("language")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "language",
})?,
screen_height: info
.screen_height
.get_required_value("screen_height")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "screen_height",
})?,
screen_width: info
.screen_width
.get_required_value("screen_width")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "screen_width",
})?,
color_depth: info
.color_depth
.get_required_value("color_depth")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "color_depth",
})?,
user_agent: info
.user_agent
.clone()
.get_required_value("user_agent")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "user_agent",
})?,
time_zone: info
.time_zone
.get_required_value("time_zone")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "time_zone",
})?,
javascript_enabled: info
.java_script_enabled
.get_required_value("javascript_enabled")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "javascript_enabled",
})?,
})
})
.transpose()
} else {
None
Ok(None)
}
}
@ -104,7 +158,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BamboraPaymentsRequest {
let three_ds = match item.auth_type {
enums::AuthenticationType::ThreeDs => Some(ThreeDSecure {
enabled: true,
browser: get_browser_info(item),
browser: get_browser_info(item)?,
version: Some(2),
auth_required: Some(true),
}),

View File

@ -760,19 +760,72 @@ fn get_card_info<F>(
let three_d = if item.is_three_ds() {
Some(ThreeD {
browser_details: Some(BrowserDetails {
accept_header: browser_info.accept_header,
ip: browser_info.ip_address,
java_enabled: browser_info.java_enabled.to_string().to_uppercase(),
java_script_enabled: browser_info
.java_script_enabled
accept_header: browser_info
.accept_header
.get_required_value("accept_header")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "accept_header",
})?,
ip: Some(
browser_info
.ip_address
.get_required_value("ip_address")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "ip_address",
})?,
),
java_enabled: browser_info
.java_enabled
.get_required_value("java_enabled")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "java_enabled",
})?
.to_string()
.to_uppercase(),
language: browser_info.language,
color_depth: browser_info.color_depth,
screen_height: browser_info.screen_height,
screen_width: browser_info.screen_width,
time_zone: browser_info.time_zone,
user_agent: browser_info.user_agent,
java_script_enabled: browser_info
.java_script_enabled
.get_required_value("java_script_enabled")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "java_script_enabled",
})?
.to_string()
.to_uppercase(),
language: browser_info
.language
.get_required_value("language")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "language",
})?,
color_depth: browser_info
.color_depth
.get_required_value("color_depth")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "color_depth",
})?,
screen_height: browser_info
.screen_height
.get_required_value("screen_height")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "screen_height",
})?,
screen_width: browser_info
.screen_width
.get_required_value("screen_width")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "screen_width",
})?,
time_zone: browser_info
.time_zone
.get_required_value("time_zone_offset")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "time_zone_offset",
})?,
user_agent: browser_info
.user_agent
.get_required_value("user_agent")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "user_agent",
})?,
}),
v2_additional_params: additional_params,
notification_url: item.request.complete_authorize_url.clone(),

View File

@ -15,6 +15,7 @@ use crate::{
core::errors,
services,
types::{self, api, storage::enums, BrowserInformation},
utils::OptionExt,
};
type Error = error_stack::Report<errors::ConnectorError>;
@ -218,35 +219,91 @@ fn get_card_request_data(
amount: String,
ccard: &api_models::payments::Card,
return_url: String,
) -> TrustpayPaymentsRequest {
TrustpayPaymentsRequest::CardsPaymentRequest(Box::new(PaymentRequestCards {
amount,
currency: item.request.currency.to_string(),
pan: ccard.card_number.clone(),
cvv: ccard.card_cvc.clone(),
expiry_date: ccard.get_card_expiry_month_year_2_digit_with_delimiter("/".to_owned()),
cardholder: ccard.card_holder_name.clone(),
reference: item.attempt_id.clone(),
redirect_url: return_url,
billing_city: params.billing_city,
billing_country: params.billing_country,
billing_street1: params.billing_street1,
billing_postcode: params.billing_postcode,
customer_email: item.request.email.clone(),
customer_ip_address: browser_info.ip_address,
browser_accept_header: browser_info.accept_header.clone(),
browser_language: browser_info.language.clone(),
browser_screen_height: browser_info.screen_height.clone().to_string(),
browser_screen_width: browser_info.screen_width.clone().to_string(),
browser_timezone: browser_info.time_zone.clone().to_string(),
browser_user_agent: browser_info.user_agent.clone(),
browser_java_enabled: browser_info.java_enabled.clone().to_string(),
browser_java_script_enabled: browser_info.java_script_enabled.clone().to_string(),
browser_screen_color_depth: browser_info.color_depth.clone().to_string(),
browser_challenge_window: "1".to_string(),
payment_action: None,
payment_type: "Plain".to_string(),
}))
) -> Result<TrustpayPaymentsRequest, Error> {
Ok(TrustpayPaymentsRequest::CardsPaymentRequest(Box::new(
PaymentRequestCards {
amount,
currency: item.request.currency.to_string(),
pan: ccard.card_number.clone(),
cvv: ccard.card_cvc.clone(),
expiry_date: ccard.get_card_expiry_month_year_2_digit_with_delimiter("/".to_owned()),
cardholder: ccard.card_holder_name.clone(),
reference: item.attempt_id.clone(),
redirect_url: return_url,
billing_city: params.billing_city,
billing_country: params.billing_country,
billing_street1: params.billing_street1,
billing_postcode: params.billing_postcode,
customer_email: item.request.email.clone(),
customer_ip_address: browser_info.ip_address,
browser_accept_header: browser_info
.accept_header
.clone()
.get_required_value("accept_header")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "accept_header",
})?,
browser_language: browser_info
.language
.clone()
.get_required_value("language")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "language",
})?,
browser_screen_height: browser_info
.screen_height
.get_required_value("screen_height")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "screen_height",
})?
.to_string(),
browser_screen_width: browser_info
.screen_width
.get_required_value("screen_width")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "screen_width",
})?
.to_string(),
browser_timezone: browser_info
.time_zone
.get_required_value("time_zone_offset")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "time_zone_offset",
})?
.to_string(),
browser_user_agent: browser_info
.user_agent
.clone()
.get_required_value("user_agent")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "user_agent",
})?,
browser_java_enabled: browser_info
.java_enabled
.get_required_value("java_enabled")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "java_enabled",
})?
.to_string(),
browser_java_script_enabled: browser_info
.java_script_enabled
.get_required_value("java_script_enabled")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "java_script_enabled",
})?
.to_string(),
browser_screen_color_depth: browser_info
.color_depth
.get_required_value("color_depth")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "color_depth",
})?
.to_string(),
browser_challenge_window: "1".to_string(),
payment_action: None,
payment_type: "Plain".to_string(),
},
)))
}
fn get_bank_redirection_request_data(
@ -284,15 +341,15 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for TrustpayPaymentsRequest {
type Error = Error;
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
let default_browser_info = BrowserInformation {
color_depth: 24,
java_enabled: false,
java_script_enabled: true,
language: "en-US".to_string(),
screen_height: 1080,
screen_width: 1920,
time_zone: 3600,
accept_header: "*".to_string(),
user_agent: "none".to_string(),
color_depth: Some(24),
java_enabled: Some(false),
java_script_enabled: Some(true),
language: Some("en-US".to_string()),
screen_height: Some(1080),
screen_width: Some(1920),
time_zone: Some(3600),
accept_header: Some("*".to_string()),
user_agent: Some("none".to_string()),
ip_address: None,
};
let browser_info = item
@ -318,7 +375,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for TrustpayPaymentsRequest {
amount,
ccard,
item.request.get_return_url()?,
)),
)?),
api::PaymentMethodData::BankRedirect(ref bank_redirection_data) => {
get_bank_redirection_request_data(item, bank_redirection_data, amount, auth)
}

View File

@ -13,11 +13,11 @@ use crate::{
connector::utils::{
self, BrowserInformationData, CardData, PaymentsAuthorizeRequestData, RouterData,
},
core::errors,
core::errors::{self, CustomResult},
services::{self, Method},
types::{self, api, storage::enums, transformers::ForeignTryFrom, BrowserInformation},
types::{self, api, storage::enums, transformers::ForeignTryFrom},
utils::OptionExt,
};
// Auth Struct
pub struct ZenAuthType {
pub(super) api_key: String,
@ -345,9 +345,23 @@ fn get_item_object(
}
fn get_browser_details(
browser_info: &BrowserInformation,
) -> Result<ZenBrowserDetails, error_stack::Report<errors::ConnectorError>> {
let window_size = match (browser_info.screen_height, browser_info.screen_width) {
browser_info: &types::BrowserInformation,
) -> CustomResult<ZenBrowserDetails, errors::ConnectorError> {
let screen_height = browser_info
.screen_height
.get_required_value("screen_height")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "screen_height",
})?;
let screen_width = browser_info
.screen_width
.get_required_value("screen_width")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "screen_width",
})?;
let window_size = match (screen_height, screen_width) {
(250, 400) => "01",
(390, 400) => "02",
(500, 600) => "03",
@ -355,16 +369,52 @@ fn get_browser_details(
_ => "05",
}
.to_string();
Ok(ZenBrowserDetails {
color_depth: browser_info.color_depth.to_string(),
java_enabled: browser_info.java_enabled,
lang: browser_info.language.clone(),
screen_height: browser_info.screen_height.to_string(),
screen_width: browser_info.screen_width.to_string(),
timezone: browser_info.time_zone.to_string(),
accept_header: browser_info.accept_header.clone(),
color_depth: browser_info
.color_depth
.get_required_value("color_depth")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "color_depth",
})?
.to_string(),
java_enabled: browser_info
.java_enabled
.get_required_value("java_enabled")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "java_enabled",
})?,
lang: browser_info
.language
.clone()
.get_required_value("language")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "language",
})?,
screen_height: screen_height.to_string(),
screen_width: screen_width.to_string(),
timezone: browser_info
.time_zone
.get_required_value("time_zone")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "time_zone",
})?
.to_string(),
accept_header: browser_info
.accept_header
.clone()
.get_required_value("accept_header")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "accept_header",
})?,
user_agent: browser_info
.user_agent
.clone()
.get_required_value("user_agent")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "user_agent",
})?,
window_size,
user_agent: browser_info.user_agent.clone(),
})
}

View File

@ -9,7 +9,7 @@ pub mod transformers;
use std::{fmt::Debug, marker::PhantomData, ops::Deref, time::Instant};
use api_models::payments::Metadata;
use common_utils::pii::Email;
use common_utils::pii;
use error_stack::{IntoReport, ResultExt};
use futures::future::join_all;
use masking::Secret;
@ -970,7 +970,7 @@ where
pub disputes: Vec<storage::Dispute>,
pub sessions_token: Vec<api::SessionToken>,
pub card_cvc: Option<Secret<String>>,
pub email: Option<Email>,
pub email: Option<pii::Email>,
pub creds_identifier: Option<String>,
pub pm_token: Option<String>,
pub connector_customer_id: Option<String>,
@ -982,7 +982,7 @@ where
pub struct CustomerDetails {
pub customer_id: Option<String>,
pub name: Option<Secret<String, masking::WithType>>,
pub email: Option<Email>,
pub email: Option<pii::Email>,
pub phone: Option<Secret<String, masking::WithType>>,
pub phone_country_code: Option<String>,
}

View File

@ -56,6 +56,7 @@ pub mod headers {
pub const TOKEN: &str = "token";
pub const X_API_KEY: &str = "X-API-KEY";
pub const X_API_VERSION: &str = "X-ApiVersion";
pub const X_FORWARDED_FOR: &str = "X-Forwarded-For";
pub const X_MERCHANT_ID: &str = "X-Merchant-Id";
pub const X_LOGIN: &str = "X-Login";
pub const X_TRANS_KEY: &str = "X-Trans-Key";

View File

@ -1,3 +1,5 @@
pub mod helpers;
use actix_web::{web, Responder};
use error_stack::report;
use router_env::{instrument, tracing, Flow};
@ -321,6 +323,10 @@ pub async fn payments_confirm(
return http_not_implemented();
};
if let Err(err) = helpers::populate_ip_into_browser_info(&req, &mut payload) {
return api::log_and_return_error_response(err);
}
let payment_id = path.into_inner();
payload.payment_id = Some(payment_types::PaymentIdType::PaymentIntentId(payment_id));
payload.confirm = Some(true);

View File

@ -0,0 +1,67 @@
use error_stack::ResultExt;
use crate::{
core::errors::{self, RouterResult},
headers, logger,
types::{self, api::payments as payment_types},
utils::{Encode, ValueExt},
};
pub fn populate_ip_into_browser_info(
req: &actix_web::HttpRequest,
payload: &mut payment_types::PaymentsRequest,
) -> RouterResult<()> {
let mut browser_info: types::BrowserInformation = payload
.browser_info
.clone()
.map(|v| v.parse_value("BrowserInformation"))
.transpose()
.change_context_lazy(|| errors::ApiErrorResponse::InvalidRequestData {
message: "invalid format for 'browser_info' provided".to_string(),
})?
.unwrap_or(types::BrowserInformation {
color_depth: None,
java_enabled: None,
java_script_enabled: None,
language: None,
screen_height: None,
screen_width: None,
time_zone: None,
accept_header: None,
user_agent: None,
ip_address: None,
});
browser_info.ip_address = browser_info
.ip_address
.or_else(|| {
// Parse the IP Address from the "X-Forwarded-For" header
// This header will contain multiple IP addresses for each ALB hop which has
// a comma separated list of IP addresses: 'X.X.X.X, Y.Y.Y.Y, Z.Z.Z.Z'
// The first one here will be the client IP which we want to retrieve
req.headers()
.get(headers::X_FORWARDED_FOR)
.map(|val| val.to_str())
.transpose()
.unwrap_or_else(|e| {
logger::error!(error=?e, message="failed to retrieve ip address from X-Forwarded-For header");
None
})
.and_then(|ips| ips.split(',').next())
.map(|ip| ip.parse())
.transpose()
.unwrap_or_else(|e| {
logger::error!(error=?e, message="failed to parse ip address from X-Forwarded-For");
None
})
});
let encoded = Encode::<types::BrowserInformation>::encode_to_value(&browser_info)
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable(
"failed to re-encode browser information to json after setting ip address",
)?;
payload.browser_info = Some(encoded);
Ok(())
}

View File

@ -444,16 +444,16 @@ pub struct RefundsData {
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct BrowserInformation {
pub color_depth: u8,
pub java_enabled: bool,
pub java_script_enabled: bool,
pub language: String,
pub screen_height: u32,
pub screen_width: u32,
pub time_zone: i32,
pub color_depth: Option<u8>,
pub java_enabled: Option<bool>,
pub java_script_enabled: Option<bool>,
pub language: Option<String>,
pub screen_height: Option<u32>,
pub screen_width: Option<u32>,
pub time_zone: Option<i32>,
pub ip_address: Option<std::net::IpAddr>,
pub accept_header: String,
pub user_agent: String,
pub accept_header: Option<String>,
pub user_agent: Option<String>,
}
#[derive(Debug, Clone)]

View File

@ -36,15 +36,15 @@ impl utils::Connector for TrustpayTest {
fn get_default_browser_info() -> BrowserInformation {
BrowserInformation {
color_depth: 24,
java_enabled: false,
java_script_enabled: true,
language: "en-US".to_string(),
screen_height: 1080,
screen_width: 1920,
time_zone: 3600,
accept_header: "*".to_string(),
user_agent: "none".to_string(),
color_depth: Some(24),
java_enabled: Some(false),
java_script_enabled: Some(true),
language: Some("en-US".to_string()),
screen_height: Some(1080),
screen_width: Some(1920),
time_zone: Some(3600),
accept_header: Some("*".to_string()),
user_agent: Some("none".to_string()),
ip_address: None,
}
}

View File

@ -549,15 +549,15 @@ impl Default for PaymentCancelType {
impl Default for BrowserInfoType {
fn default() -> Self {
let data = types::BrowserInformation {
user_agent: "".to_string(),
accept_header: "".to_string(),
language: "nl-NL".to_string(),
color_depth: 24,
screen_height: 723,
screen_width: 1536,
time_zone: 0,
java_enabled: true,
java_script_enabled: true,
user_agent: Some("".to_string()),
accept_header: Some("".to_string()),
language: Some("nl-NL".to_string()),
color_depth: Some(24),
screen_height: Some(723),
screen_width: Some(1536),
time_zone: Some(0),
java_enabled: Some(true),
java_script_enabled: Some(true),
ip_address: Some("127.0.0.1".parse().unwrap()),
};
Self(data)