feat(api): add browser information in payments response (#3963)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Narayan Bhat
2024-04-03 15:16:18 +05:30
committed by GitHub
parent ae37b059e0
commit 4051cbb4e7
9 changed files with 254 additions and 310 deletions

View File

@ -3186,6 +3186,10 @@ pub struct PaymentsResponse {
/// Payment Fingerprint
pub fingerprint: Option<String>,
#[schema(value_type = Option<BrowserInformation>)]
/// The browser information used for this payment
pub browser_info: Option<serde_json::Value>,
/// Payment Method Id
pub payment_method_id: Option<String>,

View File

@ -475,14 +475,12 @@ where
let cloned_payment_data = payment_data.clone();
let cloned_customer = customer.clone();
let cloned_request = req.clone();
crate::utils::trigger_payments_webhook(
merchant_account,
business_profile,
&key_store,
cloned_payment_data,
Some(cloned_request),
cloned_customer,
state,
operation,
@ -687,7 +685,7 @@ where
FData: Send + Sync,
Op: Operation<F, Req, Ctx> + Send + Sync + Clone,
Req: Debug + Authenticate + Clone,
Res: transformers::ToResponse<Req, PaymentData<F>, Op>,
Res: transformers::ToResponse<PaymentData<F>, Op>,
// To create connector flow specific interface data
PaymentData<F>: ConstructFlowSpecificData<F, FData, router_types::PaymentsResponseData>,
router_types::RouterData<F, FData, router_types::PaymentsResponseData>: Feature<F, FData>,
@ -706,7 +704,7 @@ where
.flat_map(|c| c.foreign_try_into())
.collect()
});
let (payment_data, req, customer, connector_http_status_code, external_latency) =
let (payment_data, _req, customer, connector_http_status_code, external_latency) =
payments_operation_core::<_, _, _, _, Ctx>(
&state,
merchant_account,
@ -721,7 +719,6 @@ where
.await?;
Res::generate_response(
Some(req),
payment_data,
customer,
auth_flow,

View File

@ -185,14 +185,13 @@ where
Ok(router_data)
}
pub trait ToResponse<Req, D, Op>
pub trait ToResponse<D, Op>
where
Self: Sized,
Op: Debug,
{
#[allow(clippy::too_many_arguments)]
fn generate_response(
req: Option<Req>,
data: D,
customer: Option<domain::Customer>,
auth_flow: services::AuthFlow,
@ -205,14 +204,13 @@ where
) -> RouterResponse<Self>;
}
impl<F, Req, Op> ToResponse<Req, PaymentData<F>, Op> for api::PaymentsResponse
impl<F, Op> ToResponse<PaymentData<F>, Op> for api::PaymentsResponse
where
F: Clone,
Op: Debug,
{
#[allow(clippy::too_many_arguments)]
fn generate_response(
req: Option<Req>,
payment_data: PaymentData<F>,
customer: Option<domain::Customer>,
auth_flow: services::AuthFlow,
@ -242,7 +240,6 @@ where
});
payments_to_payments_response(
req,
payment_data,
captures,
customer,
@ -257,15 +254,13 @@ where
}
}
impl<F, Req, Op> ToResponse<Req, PaymentData<F>, Op> for api::PaymentsSessionResponse
impl<F, Op> ToResponse<PaymentData<F>, Op> for api::PaymentsSessionResponse
where
Self: From<Req>,
F: Clone,
Op: Debug,
{
#[allow(clippy::too_many_arguments)]
fn generate_response(
_req: Option<Req>,
payment_data: PaymentData<F>,
_customer: Option<domain::Customer>,
_auth_flow: services::AuthFlow,
@ -291,15 +286,13 @@ where
}
}
impl<F, Req, Op> ToResponse<Req, PaymentData<F>, Op> for api::VerifyResponse
impl<F, Op> ToResponse<PaymentData<F>, Op> for api::VerifyResponse
where
Self: From<Req>,
F: Clone,
Op: Debug,
{
#[allow(clippy::too_many_arguments)]
fn generate_response(
_req: Option<Req>,
data: PaymentData<F>,
customer: Option<domain::Customer>,
_auth_flow: services::AuthFlow,
@ -354,8 +347,7 @@ where
// try to use router data here so that already validated things , we don't want to repeat the validations.
// Add internal value not found and external value not found so that we can give 500 / Internal server error for internal value not found
#[allow(clippy::too_many_arguments)]
pub fn payments_to_payments_response<R, Op, F: Clone>(
payment_request: Option<R>,
pub fn payments_to_payments_response<Op, F: Clone>(
payment_data: PaymentData<F>,
captures: Option<Vec<storage::Capture>>,
customer: Option<domain::Customer>,
@ -510,44 +502,42 @@ where
.unwrap_or_default(),
);
let output = Ok(match payment_request {
Some(_request) => {
if payments::is_start_pay(&operation) && payment_attempt.authentication_data.is_some() {
let redirection_data = payment_attempt
.authentication_data
.get_required_value("redirection_data")?;
let output = if payments::is_start_pay(&operation)
&& payment_attempt.authentication_data.is_some()
{
let redirection_data = payment_attempt
.authentication_data
.get_required_value("redirection_data")?;
let form: RedirectForm = serde_json::from_value(redirection_data)
.map_err(|_| errors::ApiErrorResponse::InternalServerError)?;
let form: RedirectForm = serde_json::from_value(redirection_data)
.map_err(|_| errors::ApiErrorResponse::InternalServerError)?;
services::ApplicationResponse::Form(Box::new(services::RedirectionFormData {
redirect_form: form,
payment_method_data: payment_data.payment_method_data,
amount,
currency: currency.to_string(),
}))
} else {
let mut next_action_response = None;
services::ApplicationResponse::Form(Box::new(services::RedirectionFormData {
redirect_form: form,
payment_method_data: payment_data.payment_method_data,
amount,
currency: currency.to_string(),
}))
} else {
let mut next_action_response = None;
let bank_transfer_next_steps =
bank_transfer_next_steps_check(payment_attempt.clone())?;
let bank_transfer_next_steps = bank_transfer_next_steps_check(payment_attempt.clone())?;
let next_action_voucher = voucher_next_steps_check(payment_attempt.clone())?;
let next_action_voucher = voucher_next_steps_check(payment_attempt.clone())?;
let next_action_containing_qr_code_url =
qr_code_next_steps_check(payment_attempt.clone())?;
let next_action_containing_qr_code_url = qr_code_next_steps_check(payment_attempt.clone())?;
let next_action_containing_wait_screen =
wait_screen_next_steps_check(payment_attempt.clone())?;
let next_action_containing_wait_screen =
wait_screen_next_steps_check(payment_attempt.clone())?;
if payment_intent.status == enums::IntentStatus::RequiresCustomerAction
|| bank_transfer_next_steps.is_some()
|| next_action_voucher.is_some()
|| next_action_containing_qr_code_url.is_some()
|| next_action_containing_wait_screen.is_some()
|| payment_data.authentication.is_some()
{
next_action_response = bank_transfer_next_steps
if payment_intent.status == enums::IntentStatus::RequiresCustomerAction
|| bank_transfer_next_steps.is_some()
|| next_action_voucher.is_some()
|| next_action_containing_qr_code_url.is_some()
|| next_action_containing_wait_screen.is_some()
|| payment_data.authentication.is_some()
{
next_action_response = bank_transfer_next_steps
.map(|bank_transfer| {
api_models::payments::NextActionData::DisplayBankTransferInformation {
bank_transfer_steps_and_charges_details: bank_transfer,
@ -610,261 +600,183 @@ where
},
None => None
});
};
};
// next action check for third party sdk session (for ex: Apple pay through trustpay has third party sdk session response)
if third_party_sdk_session_next_action(&payment_attempt, operation) {
next_action_response = Some(
api_models::payments::NextActionData::ThirdPartySdkSessionToken {
session_token: payment_data.sessions_token.first().cloned(),
},
)
}
let mut response: api::PaymentsResponse = Default::default();
let routed_through = payment_attempt.connector.clone();
let connector_label = routed_through.as_ref().and_then(|connector_name| {
core_utils::get_connector_label(
payment_intent.business_country,
payment_intent.business_label.as_ref(),
payment_attempt.business_sub_label.as_ref(),
connector_name,
)
});
services::ApplicationResponse::JsonWithHeaders((
response
.set_net_amount(payment_attempt.net_amount)
.set_payment_id(Some(payment_attempt.payment_id))
.set_merchant_id(Some(payment_attempt.merchant_id))
.set_status(payment_intent.status)
.set_amount(payment_attempt.amount)
.set_amount_capturable(Some(payment_attempt.amount_capturable))
.set_amount_received(payment_intent.amount_captured)
.set_surcharge_details(surcharge_details)
.set_connector(routed_through)
.set_client_secret(payment_intent.client_secret.map(masking::Secret::new))
.set_created(Some(payment_intent.created_at))
.set_currency(currency.to_string())
.set_customer_id(customer.as_ref().map(|cus| cus.clone().customer_id))
.set_email(
customer
.as_ref()
.and_then(|cus| cus.email.as_ref().map(|s| s.to_owned())),
)
.set_name(
customer
.as_ref()
.and_then(|cus| cus.name.as_ref().map(|s| s.to_owned())),
)
.set_phone(
customer
.as_ref()
.and_then(|cus| cus.phone.as_ref().map(|s| s.to_owned())),
)
.set_mandate_id(mandate_id)
.set_mandate_data(
payment_data.setup_mandate.map(|d| api::MandateData {
customer_acceptance: d.customer_acceptance.map(|d| {
api::CustomerAcceptance {
acceptance_type: match d.acceptance_type {
data_models::mandates::AcceptanceType::Online => {
api::AcceptanceType::Online
}
data_models::mandates::AcceptanceType::Offline => {
api::AcceptanceType::Offline
}
},
accepted_at: d.accepted_at,
online: d.online.map(|d| api::OnlineMandate {
ip_address: d.ip_address,
user_agent: d.user_agent,
}),
}
}),
mandate_type: d.mandate_type.map(|d| match d {
data_models::mandates::MandateDataType::MultiUse(Some(i)) => {
api::MandateType::MultiUse(Some(api::MandateAmountData {
amount: i.amount,
currency: i.currency,
start_date: i.start_date,
end_date: i.end_date,
metadata: i.metadata,
}))
}
data_models::mandates::MandateDataType::SingleUse(i) => {
api::MandateType::SingleUse(
api::payments::MandateAmountData {
amount: i.amount,
currency: i.currency,
start_date: i.start_date,
end_date: i.end_date,
metadata: i.metadata,
},
)
}
data_models::mandates::MandateDataType::MultiUse(None) => {
api::MandateType::MultiUse(None)
}
}),
update_mandate_id: d.update_mandate_id,
}),
auth_flow == services::AuthFlow::Merchant,
)
.set_description(payment_intent.description)
.set_refunds(refunds_response) // refunds.iter().map(refund_to_refund_response),
.set_disputes(disputes_response)
.set_attempts(attempts_response)
.set_captures(captures_response)
.set_payment_method(
payment_attempt.payment_method,
auth_flow == services::AuthFlow::Merchant,
)
.set_payment_method_data(
payment_method_data_response,
auth_flow == services::AuthFlow::Merchant,
)
.set_payment_token(payment_attempt.payment_token)
.set_error_message(
payment_attempt
.error_reason
.or(payment_attempt.error_message),
)
.set_error_code(payment_attempt.error_code)
.set_shipping(payment_data.address.get_shipping().cloned())
.set_billing(payment_data.address.get_payment_billing().cloned())
.set_next_action(next_action_response)
.set_return_url(payment_intent.return_url)
.set_cancellation_reason(payment_attempt.cancellation_reason)
.set_authentication_type(payment_attempt.authentication_type)
.set_statement_descriptor_name(payment_intent.statement_descriptor_name)
.set_statement_descriptor_suffix(payment_intent.statement_descriptor_suffix)
.set_setup_future_usage(payment_intent.setup_future_usage)
.set_capture_method(payment_attempt.capture_method)
.set_payment_experience(payment_attempt.payment_experience)
.set_payment_method_type(payment_attempt.payment_method_type)
.set_metadata(payment_intent.metadata)
.set_order_details(payment_intent.order_details)
.set_connector_label(connector_label)
.set_business_country(payment_intent.business_country)
.set_business_label(payment_intent.business_label)
.set_business_sub_label(payment_attempt.business_sub_label)
.set_allowed_payment_method_types(
payment_intent.allowed_payment_method_types,
)
.set_ephemeral_key(
payment_data.ephemeral_key.map(ForeignFrom::foreign_from),
)
.set_frm_message(frm_message)
.set_merchant_decision(merchant_decision)
.set_manual_retry_allowed(helpers::is_manual_retry_allowed(
&payment_intent.status,
&payment_attempt.status,
connector_request_reference_id_config,
&merchant_id,
))
.set_connector_transaction_id(payment_attempt.connector_transaction_id)
.set_feature_metadata(payment_intent.feature_metadata)
.set_connector_metadata(payment_intent.connector_metadata)
.set_reference_id(payment_attempt.connector_response_reference_id)
.set_payment_link(payment_link_data)
.set_profile_id(payment_intent.profile_id)
.set_attempt_count(payment_intent.attempt_count)
.set_merchant_connector_id(payment_attempt.merchant_connector_id)
.set_unified_code(payment_attempt.unified_code)
.set_unified_message(payment_attempt.unified_message)
.set_incremental_authorization_allowed(
payment_intent.incremental_authorization_allowed,
)
.set_external_authentication_details(external_authentication_details)
.set_fingerprint(payment_intent.fingerprint_id)
.set_authorization_count(payment_intent.authorization_count)
.set_incremental_authorizations(incremental_authorizations_response)
.set_expires_on(payment_intent.session_expiry)
.set_external_3ds_authentication_attempted(
payment_attempt.external_three_ds_authentication_attempted,
)
.set_payment_method_id(payment_attempt.payment_method_id)
.set_payment_method_status(
payment_data.payment_method_info.map(|info| info.status),
)
.set_customer(customer_details_response.clone())
.to_owned(),
headers,
))
}
// next action check for third party sdk session (for ex: Apple pay through trustpay has third party sdk session response)
if third_party_sdk_session_next_action(&payment_attempt, operation) {
next_action_response = Some(
api_models::payments::NextActionData::ThirdPartySdkSessionToken {
session_token: payment_data.sessions_token.first().cloned(),
},
)
}
None => services::ApplicationResponse::JsonWithHeaders((
api::PaymentsResponse {
net_amount: payment_attempt.net_amount,
payment_id: Some(payment_attempt.payment_id),
merchant_id: Some(payment_attempt.merchant_id),
status: payment_intent.status,
amount: payment_attempt.amount,
amount_capturable: None,
amount_received: payment_intent.amount_captured,
client_secret: payment_intent.client_secret.map(masking::Secret::new),
created: Some(payment_intent.created_at),
currency: currency.to_string(),
customer_id: payment_intent.customer_id,
description: payment_intent.description,
refunds: refunds_response,
disputes: disputes_response,
attempts: attempts_response,
captures: captures_response,
payment_method: payment_attempt.payment_method,
capture_method: payment_attempt.capture_method,
error_message: payment_attempt
.error_reason
.or(payment_attempt.error_message),
error_code: payment_attempt.error_code,
payment_method_data: payment_method_data_response,
email: customer
.as_ref()
.and_then(|cus| cus.email.as_ref().map(|s| s.to_owned())),
name: customer
.as_ref()
.and_then(|cus| cus.name.as_ref().map(|s| s.to_owned())),
phone: customer
.as_ref()
.and_then(|cus| cus.phone.as_ref().map(|s| s.to_owned())),
mandate_id,
shipping: payment_data.address.get_shipping().cloned(),
billing: payment_data.address.get_payment_billing().cloned(),
cancellation_reason: payment_attempt.cancellation_reason,
payment_token: payment_attempt.payment_token,
metadata: payment_intent.metadata,
manual_retry_allowed: helpers::is_manual_retry_allowed(
let mut response: api::PaymentsResponse = Default::default();
let routed_through = payment_attempt.connector.clone();
let connector_label = routed_through.as_ref().and_then(|connector_name| {
core_utils::get_connector_label(
payment_intent.business_country,
payment_intent.business_label.as_ref(),
payment_attempt.business_sub_label.as_ref(),
connector_name,
)
});
services::ApplicationResponse::JsonWithHeaders((
response
.set_net_amount(payment_attempt.net_amount)
.set_payment_id(Some(payment_attempt.payment_id))
.set_merchant_id(Some(payment_attempt.merchant_id))
.set_status(payment_intent.status)
.set_amount(payment_attempt.amount)
.set_amount_capturable(Some(payment_attempt.amount_capturable))
.set_amount_received(payment_intent.amount_captured)
.set_surcharge_details(surcharge_details)
.set_connector(routed_through)
.set_client_secret(payment_intent.client_secret.map(masking::Secret::new))
.set_created(Some(payment_intent.created_at))
.set_currency(currency.to_string())
.set_customer_id(customer.as_ref().map(|cus| cus.clone().customer_id))
.set_email(
customer
.as_ref()
.and_then(|cus| cus.email.as_ref().map(|s| s.to_owned())),
)
.set_name(
customer
.as_ref()
.and_then(|cus| cus.name.as_ref().map(|s| s.to_owned())),
)
.set_phone(
customer
.as_ref()
.and_then(|cus| cus.phone.as_ref().map(|s| s.to_owned())),
)
.set_mandate_id(mandate_id)
.set_mandate_data(
payment_data.setup_mandate.map(|d| api::MandateData {
customer_acceptance: d.customer_acceptance.map(|d| {
api::CustomerAcceptance {
acceptance_type: match d.acceptance_type {
data_models::mandates::AcceptanceType::Online => {
api::AcceptanceType::Online
}
data_models::mandates::AcceptanceType::Offline => {
api::AcceptanceType::Offline
}
},
accepted_at: d.accepted_at,
online: d.online.map(|d| api::OnlineMandate {
ip_address: d.ip_address,
user_agent: d.user_agent,
}),
}
}),
mandate_type: d.mandate_type.map(|d| match d {
data_models::mandates::MandateDataType::MultiUse(Some(i)) => {
api::MandateType::MultiUse(Some(api::MandateAmountData {
amount: i.amount,
currency: i.currency,
start_date: i.start_date,
end_date: i.end_date,
metadata: i.metadata,
}))
}
data_models::mandates::MandateDataType::SingleUse(i) => {
api::MandateType::SingleUse(api::payments::MandateAmountData {
amount: i.amount,
currency: i.currency,
start_date: i.start_date,
end_date: i.end_date,
metadata: i.metadata,
})
}
data_models::mandates::MandateDataType::MultiUse(None) => {
api::MandateType::MultiUse(None)
}
}),
update_mandate_id: d.update_mandate_id,
}),
auth_flow == services::AuthFlow::Merchant,
)
.set_description(payment_intent.description)
.set_refunds(refunds_response) // refunds.iter().map(refund_to_refund_response),
.set_disputes(disputes_response)
.set_attempts(attempts_response)
.set_captures(captures_response)
.set_payment_method(
payment_attempt.payment_method,
auth_flow == services::AuthFlow::Merchant,
)
.set_payment_method_data(
payment_method_data_response,
auth_flow == services::AuthFlow::Merchant,
)
.set_payment_token(payment_attempt.payment_token)
.set_error_message(
payment_attempt
.error_reason
.or(payment_attempt.error_message),
)
.set_error_code(payment_attempt.error_code)
.set_shipping(payment_data.address.get_shipping().cloned())
.set_billing(payment_data.address.get_payment_billing().cloned())
.set_next_action(next_action_response)
.set_return_url(payment_intent.return_url)
.set_cancellation_reason(payment_attempt.cancellation_reason)
.set_authentication_type(payment_attempt.authentication_type)
.set_statement_descriptor_name(payment_intent.statement_descriptor_name)
.set_statement_descriptor_suffix(payment_intent.statement_descriptor_suffix)
.set_setup_future_usage(payment_intent.setup_future_usage)
.set_capture_method(payment_attempt.capture_method)
.set_payment_experience(payment_attempt.payment_experience)
.set_payment_method_type(payment_attempt.payment_method_type)
.set_metadata(payment_intent.metadata)
.set_order_details(payment_intent.order_details)
.set_connector_label(connector_label)
.set_business_country(payment_intent.business_country)
.set_business_label(payment_intent.business_label)
.set_business_sub_label(payment_attempt.business_sub_label)
.set_allowed_payment_method_types(payment_intent.allowed_payment_method_types)
.set_ephemeral_key(payment_data.ephemeral_key.map(ForeignFrom::foreign_from))
.set_frm_message(frm_message)
.set_merchant_decision(merchant_decision)
.set_manual_retry_allowed(helpers::is_manual_retry_allowed(
&payment_intent.status,
&payment_attempt.status,
connector_request_reference_id_config,
&merchant_id,
),
order_details: payment_intent.order_details,
frm_message,
connector_transaction_id: payment_attempt.connector_transaction_id,
feature_metadata: payment_intent.feature_metadata,
connector_metadata: payment_intent.connector_metadata,
allowed_payment_method_types: payment_intent.allowed_payment_method_types,
reference_id: payment_attempt.connector_response_reference_id,
attempt_count: payment_intent.attempt_count,
payment_link: payment_link_data,
surcharge_details,
unified_code: payment_attempt.unified_code,
unified_message: payment_attempt.unified_message,
incremental_authorization_allowed: payment_intent.incremental_authorization_allowed,
authorization_count: payment_intent.authorization_count,
incremental_authorizations: incremental_authorizations_response,
external_authentication_details,
expires_on: payment_intent.session_expiry,
external_3ds_authentication_attempted: payment_attempt
.external_three_ds_authentication_attempted,
customer: customer_details_response,
..Default::default()
},
))
.set_connector_transaction_id(payment_attempt.connector_transaction_id)
.set_feature_metadata(payment_intent.feature_metadata)
.set_connector_metadata(payment_intent.connector_metadata)
.set_reference_id(payment_attempt.connector_response_reference_id)
.set_payment_link(payment_link_data)
.set_profile_id(payment_intent.profile_id)
.set_attempt_count(payment_intent.attempt_count)
.set_merchant_connector_id(payment_attempt.merchant_connector_id)
.set_unified_code(payment_attempt.unified_code)
.set_unified_message(payment_attempt.unified_message)
.set_incremental_authorization_allowed(
payment_intent.incremental_authorization_allowed,
)
.set_external_authentication_details(external_authentication_details)
.set_fingerprint(payment_intent.fingerprint_id)
.set_authorization_count(payment_intent.authorization_count)
.set_incremental_authorizations(incremental_authorizations_response)
.set_expires_on(payment_intent.session_expiry)
.set_external_3ds_authentication_attempted(
payment_attempt.external_three_ds_authentication_attempted,
)
.set_payment_method_id(payment_attempt.payment_method_id)
.set_payment_method_status(payment_data.payment_method_info.map(|info| info.status))
.set_customer(customer_details_response.clone())
.set_browser_info(payment_attempt.browser_info)
.to_owned(),
headers,
)),
});
))
};
metrics::PAYMENT_OPS_COUNT.add(
&metrics::CONTEXT,
@ -877,7 +789,7 @@ where
],
);
output
Ok(output)
}
pub fn third_party_sdk_session_next_action<Op>(

View File

@ -736,12 +736,11 @@ pub fn add_apple_pay_payment_status_metrics(
}
#[allow(clippy::too_many_arguments)]
pub async fn trigger_payments_webhook<F, Req, Op>(
pub async fn trigger_payments_webhook<F, Op>(
merchant_account: domain::MerchantAccount,
business_profile: diesel_models::business_profile::BusinessProfile,
key_store: &domain::MerchantKeyStore,
payment_data: crate::core::payments::PaymentData<F>,
req: Option<Req>,
customer: Option<domain::Customer>,
state: &crate::routes::AppState,
operation: Op,
@ -770,7 +769,6 @@ where
| enums::IntentStatus::PartiallyCaptured
) {
let payments_response = crate::core::payments::transformers::payments_to_payments_response(
req,
payment_data,
captures,
customer,

View File

@ -176,16 +176,11 @@ impl ProcessTrackerWorkflow<AppState> for PaymentsSyncWorkflow {
// Trigger the outgoing webhook to notify the merchant about failed payment
let operation = operations::PaymentStatus;
Box::pin(utils::trigger_payments_webhook::<
_,
api_models::payments::PaymentsRequest,
_,
>(
Box::pin(utils::trigger_payments_webhook(
merchant_account,
business_profile,
&key_store,
payment_data,
None,
customer,
state,
operation,

View File

@ -14761,6 +14761,14 @@
"description": "Payment Fingerprint",
"nullable": true
},
"browser_info": {
"allOf": [
{
"$ref": "#/components/schemas/BrowserInformation"
}
],
"nullable": true
},
"payment_method_id": {
"type": "string",
"description": "Payment Method Id",

View File

@ -19,7 +19,7 @@ pm.test("[POST]::/payments - Response has JSON Body", function () {
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
} catch (e) { }
// pm.collectionVariables - Set payment_id as variable for jsonData.payment_id
if (jsonData?.payment_id) {
@ -78,3 +78,12 @@ pm.test(
.true;
},
);
// Response body should have "browser_info"
pm.test(
"[POST]::/payments - Content check if 'browser_info' exists",
function () {
pm.expect(typeof jsonData.browser_info !== "undefined").to.be
.true;
},
);

View File

@ -54,6 +54,18 @@
"card_cvc": "123"
}
},
"browser_info": {
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
"accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"language": "nl-NL",
"color_depth": 24,
"screen_height": 723,
"screen_width": 1536,
"time_zone": 0,
"java_enabled": true,
"java_script_enabled": true,
"ip_address": "127.0.0.1"
},
"billing": {
"address": {
"line1": "1467",

View File

@ -7085,7 +7085,7 @@
"let jsonData = {};",
"try {",
" jsonData = pm.response.json();",
"} catch (e) {}",
"} catch (e) { }",
"",
"// pm.collectionVariables - Set payment_id as variable for jsonData.payment_id",
"if (jsonData?.payment_id) {",
@ -7144,6 +7144,15 @@
" .true;",
" },",
");",
"",
"// Response body should have \"browser_info\"",
"pm.test(",
" \"[POST]::/payments - Content check if 'browser_info' exists\",",
" function () {",
" pm.expect(typeof jsonData.browser_info !== \"undefined\").to.be",
" .true;",
" },",
");",
""
],
"type": "text/javascript"
@ -7169,7 +7178,7 @@
"language": "json"
}
},
"raw": "{\"amount\":6540,\"currency\":\"USD\",\"confirm\":true,\"business_country\":\"US\",\"business_label\":\"default\",\"capture_method\":\"automatic\",\"capture_on\":\"2022-09-10T10:11:12Z\",\"amount_to_capture\":6540,\"customer_id\":\"bernard123\",\"email\":\"guest@example.com\",\"name\":\"John Doe\",\"phone\":\"999999999\",\"phone_country_code\":\"+65\",\"description\":\"Its my first payment request\",\"authentication_type\":\"no_three_ds\",\"return_url\":\"https://duck.com\",\"setup_future_usage\":\"on_session\",\"customer_acceptance\":{\"acceptance_type\":\"online\",\"accepted_at\":\"2022-09-10T10:11:12Z\",\"online\":{\"ip_address\":\"123.32.25.123\",\"user_agent\":\"Mozilla/5.0 (Linux; Android 12; SM-S906N Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.119 Mobile Safari/537.36\"}},\"payment_method\":\"card\",\"payment_method_type\":\"debit\",\"payment_method_data\":{\"card\":{\"card_number\":\"4242424242424242\",\"card_exp_month\":\"01\",\"card_exp_year\":\"26\",\"card_holder_name\":\"joseph Doe\",\"card_cvc\":\"123\"}},\"billing\":{\"address\":{\"line1\":\"1467\",\"line2\":\"Harrison Street\",\"line3\":\"Harrison Street\",\"city\":\"San Fransico\",\"state\":\"California\",\"zip\":\"94122\",\"country\":\"US\",\"first_name\":\"sundari\",\"last_name\":\"sundari\"}},\"shipping\":{\"address\":{\"line1\":\"1467\",\"line2\":\"Harrison Street\",\"line3\":\"Harrison Street\",\"city\":\"San Fransico\",\"state\":\"California\",\"zip\":\"94122\",\"country\":\"US\",\"first_name\":\"sundari\",\"last_name\":\"sundari\"}},\"statement_descriptor_name\":\"joseph\",\"statement_descriptor_suffix\":\"JS\",\"metadata\":{\"udf1\":\"value1\",\"new_customer\":\"true\",\"login_date\":\"2019-09-10T10:11:12Z\"},\"routing\":{\"type\":\"single\",\"data\":\"stripe\"}}"
"raw": "{\"amount\":6540,\"currency\":\"USD\",\"confirm\":true,\"business_country\":\"US\",\"business_label\":\"default\",\"capture_method\":\"automatic\",\"capture_on\":\"2022-09-10T10:11:12Z\",\"amount_to_capture\":6540,\"customer_id\":\"bernard123\",\"email\":\"guest@example.com\",\"name\":\"John Doe\",\"phone\":\"999999999\",\"phone_country_code\":\"+65\",\"description\":\"Its my first payment request\",\"authentication_type\":\"no_three_ds\",\"return_url\":\"https://duck.com\",\"setup_future_usage\":\"on_session\",\"customer_acceptance\":{\"acceptance_type\":\"online\",\"accepted_at\":\"2022-09-10T10:11:12Z\",\"online\":{\"ip_address\":\"123.32.25.123\",\"user_agent\":\"Mozilla/5.0 (Linux; Android 12; SM-S906N Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.119 Mobile Safari/537.36\"}},\"payment_method\":\"card\",\"payment_method_type\":\"debit\",\"payment_method_data\":{\"card\":{\"card_number\":\"4242424242424242\",\"card_exp_month\":\"01\",\"card_exp_year\":\"26\",\"card_holder_name\":\"joseph Doe\",\"card_cvc\":\"123\"}},\"browser_info\":{\"user_agent\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36\",\"accept_header\":\"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\",\"language\":\"nl-NL\",\"color_depth\":24,\"screen_height\":723,\"screen_width\":1536,\"time_zone\":0,\"java_enabled\":true,\"java_script_enabled\":true,\"ip_address\":\"127.0.0.1\"},\"billing\":{\"address\":{\"line1\":\"1467\",\"line2\":\"Harrison Street\",\"line3\":\"Harrison Street\",\"city\":\"San Fransico\",\"state\":\"California\",\"zip\":\"94122\",\"country\":\"US\",\"first_name\":\"sundari\",\"last_name\":\"sundari\"}},\"shipping\":{\"address\":{\"line1\":\"1467\",\"line2\":\"Harrison Street\",\"line3\":\"Harrison Street\",\"city\":\"San Fransico\",\"state\":\"California\",\"zip\":\"94122\",\"country\":\"US\",\"first_name\":\"sundari\",\"last_name\":\"sundari\"}},\"statement_descriptor_name\":\"joseph\",\"statement_descriptor_suffix\":\"JS\",\"metadata\":{\"udf1\":\"value1\",\"new_customer\":\"true\",\"login_date\":\"2019-09-10T10:11:12Z\"},\"routing\":{\"type\":\"single\",\"data\":\"stripe\"}}"
},
"url": {
"raw": "{{baseUrl}}/payments",