feat: update surcharge_amount and tax_amount in update_trackers of payment_confirm (#2603)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Hrithikesh
2023-10-18 15:42:32 +05:30
committed by GitHub
parent 7a76d6c01a
commit 2f9a3557f6
31 changed files with 786 additions and 47 deletions

View File

@ -311,7 +311,9 @@ pub struct PaymentsRequest {
pub payment_type: Option<api_enums::PaymentType>,
}
#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize, Copy, ToSchema)]
#[derive(
Default, Debug, Clone, serde::Serialize, serde::Deserialize, Copy, ToSchema, PartialEq,
)]
pub struct RequestSurchargeDetails {
pub surcharge_amount: i64,
pub tax_amount: Option<i64>,
@ -2096,6 +2098,9 @@ pub struct PaymentsResponse {
/// The business profile that is associated with this payment
pub profile_id: Option<String>,
/// details of surcharge applied on this payment
pub surcharge_details: Option<RequestSurchargeDetails>,
/// total number of attempts associated with this payment
pub attempt_count: i16,

View File

@ -250,6 +250,8 @@ pub enum PaymentAttemptUpdate {
error_code: Option<Option<String>>,
error_message: Option<Option<String>>,
amount_capturable: Option<i64>,
surcharge_amount: Option<i64>,
tax_amount: Option<i64>,
updated_by: String,
},
RejectUpdate {
@ -307,11 +309,6 @@ pub enum PaymentAttemptUpdate {
multiple_capture_count: i16,
updated_by: String,
},
SurchargeAmountUpdate {
surcharge_amount: Option<i64>,
tax_amount: Option<i64>,
updated_by: String,
},
AmountToCaptureUpdate {
status: storage_enums::AttemptStatus,
amount_capturable: i64,

View File

@ -166,6 +166,8 @@ pub enum PaymentAttemptUpdate {
error_code: Option<Option<String>>,
error_message: Option<Option<String>>,
amount_capturable: Option<i64>,
surcharge_amount: Option<i64>,
tax_amount: Option<i64>,
updated_by: String,
},
VoidUpdate {
@ -228,11 +230,6 @@ pub enum PaymentAttemptUpdate {
amount_capturable: i64,
updated_by: String,
},
SurchargeAmountUpdate {
surcharge_amount: Option<i64>,
tax_amount: Option<i64>,
updated_by: String,
},
PreprocessingUpdate {
status: storage_enums::AttemptStatus,
payment_method_id: Option<Option<String>>,
@ -378,6 +375,8 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
error_code,
error_message,
amount_capturable,
surcharge_amount,
tax_amount,
updated_by,
} => Self {
amount: Some(amount),
@ -397,6 +396,8 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
error_code,
error_message,
amount_capturable,
surcharge_amount,
tax_amount,
updated_by,
..Default::default()
},
@ -561,16 +562,6 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
updated_by,
..Default::default()
},
PaymentAttemptUpdate::SurchargeAmountUpdate {
surcharge_amount,
tax_amount,
updated_by,
} => Self {
surcharge_amount,
tax_amount,
updated_by,
..Default::default()
},
}
}
}

View File

@ -216,6 +216,10 @@ impl ConnectorValidation for Paypal {
),
}
}
fn validate_if_surcharge_implemented(&self) -> CustomResult<(), errors::ConnectorError> {
Ok(())
}
}
impl

View File

@ -148,7 +148,11 @@ impl ConnectorCommon for Trustpay {
}
}
impl ConnectorValidation for Trustpay {}
impl ConnectorValidation for Trustpay {
fn validate_if_surcharge_implemented(&self) -> CustomResult<(), errors::ConnectorError> {
Ok(())
}
}
impl api::Payment for Trustpay {}

View File

@ -73,6 +73,12 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
.connector
.validate_capture_method(self.request.capture_method)
.to_payment_failed_response()?;
if self.request.surcharge_details.is_some() {
connector
.connector
.validate_if_surcharge_implemented()
.to_payment_failed_response()?;
}
if self.should_proceed_with_authorize() {
self.decide_authentication_type();

View File

@ -82,7 +82,10 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
helpers::validate_status_with_capture_method(payment_intent.status, capture_method)?;
helpers::validate_amount_to_capture(payment_intent.amount, request.amount_to_capture)?;
helpers::validate_amount_to_capture(
payment_attempt.amount_capturable,
request.amount_to_capture,
)?;
helpers::validate_capture_method(capture_method)?;

View File

@ -1,6 +1,6 @@
use std::marker::PhantomData;
use api_models::enums::FrmSuggestion;
use api_models::{enums::FrmSuggestion, payment_methods};
use async_trait::async_trait;
use common_utils::ext_traits::{AsyncExt, Encode};
use error_stack::ResultExt;
@ -335,6 +335,19 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
sm
});
// populate payment_data.surcharge_details from request
let surcharge_details = request.surcharge_details.map(|surcharge_details| {
payment_methods::SurchargeDetailsResponse {
surcharge: payment_methods::Surcharge::Fixed(surcharge_details.surcharge_amount),
tax_on_surcharge: None,
surcharge_amount: surcharge_details.surcharge_amount,
tax_on_surcharge_amount: surcharge_details.tax_amount.unwrap_or(0),
final_amount: payment_attempt.amount
+ surcharge_details.surcharge_amount
+ surcharge_details.tax_amount.unwrap_or(0),
}
});
Ok((
Box::new(self),
PaymentData {
@ -368,7 +381,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
ephemeral_key: None,
multiple_capture_data: None,
redirect_response: None,
surcharge_details: None,
surcharge_details,
frm_message: None,
payment_link_data: None,
},
@ -543,7 +556,19 @@ impl<F: Clone, Ctx: PaymentMethodRetrieve>
.take();
let order_details = payment_data.payment_intent.order_details.clone();
let metadata = payment_data.payment_intent.metadata.clone();
let authorized_amount = payment_data.payment_attempt.amount;
let surcharge_amount = payment_data
.surcharge_details
.as_ref()
.map(|surcharge_details| surcharge_details.surcharge_amount);
let tax_amount = payment_data
.surcharge_details
.as_ref()
.map(|surcharge_details| surcharge_details.tax_on_surcharge_amount);
let authorized_amount = payment_data
.surcharge_details
.as_ref()
.map(|surcharge_details| surcharge_details.final_amount)
.unwrap_or(payment_data.payment_attempt.amount);
let payment_attempt_fut = db
.update_payment_attempt_with_attempt_id(
payment_data.payment_attempt,
@ -564,6 +589,8 @@ impl<F: Clone, Ctx: PaymentMethodRetrieve>
error_code,
error_message,
amount_capturable: Some(authorized_amount),
surcharge_amount,
tax_amount,
updated_by: storage_scheme.to_string(),
},
storage_scheme,

View File

@ -559,7 +559,7 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
payment_attempt_update = Some(storage::PaymentAttemptUpdate::AmountToCaptureUpdate {
status: multiple_capture_data.get_attempt_status(authorized_amount),
amount_capturable: payment_data.payment_attempt.amount
amount_capturable: authorized_amount
- multiple_capture_data.get_total_blocked_amount(),
updated_by: storage_scheme.to_string(),
});

View File

@ -1,6 +1,6 @@
use std::{fmt::Debug, marker::PhantomData, str::FromStr};
use api_models::payments::FrmMessage;
use api_models::payments::{FrmMessage, RequestSurchargeDetails};
use common_utils::{consts::X_HS_LATENCY, fp_utils};
use diesel_models::ephemeral_key;
use error_stack::{IntoReport, ResultExt};
@ -424,7 +424,13 @@ where
.change_context(errors::ApiErrorResponse::InvalidDataValue {
field_name: "payment_method_data",
})?;
let surcharge_details =
payment_attempt
.surcharge_amount
.map(|surcharge_amount| RequestSurchargeDetails {
surcharge_amount,
tax_amount: payment_attempt.tax_amount,
});
let merchant_decision = payment_intent.merchant_decision.to_owned();
let frm_message = payment_data.frm_message.map(FrmMessage::foreign_from);
@ -557,6 +563,7 @@ where
.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))
@ -743,6 +750,7 @@ where
reference_id: payment_attempt.connector_response_reference_id,
attempt_count: payment_intent.attempt_count,
payment_link: payment_link_data,
surcharge_details,
..Default::default()
},
headers,

View File

@ -96,6 +96,14 @@ pub trait ConnectorValidation: ConnectorCommon {
fn is_webhook_source_verification_mandatory(&self) -> bool {
false
}
fn validate_if_surcharge_implemented(&self) -> CustomResult<(), errors::ConnectorError> {
Err(errors::ConnectorError::NotImplemented(format!(
"Surcharge not implemented for {}",
self.id()
))
.into())
}
}
#[async_trait::async_trait]

View File

@ -1181,6 +1181,8 @@ impl DataModelExt for PaymentAttemptUpdate {
error_code,
error_message,
amount_capturable,
surcharge_amount,
tax_amount,
updated_by,
} => DieselPaymentAttemptUpdate::ConfirmUpdate {
amount,
@ -1199,6 +1201,8 @@ impl DataModelExt for PaymentAttemptUpdate {
error_code,
error_message,
amount_capturable,
surcharge_amount,
tax_amount,
updated_by,
},
Self::VoidUpdate {
@ -1333,15 +1337,6 @@ impl DataModelExt for PaymentAttemptUpdate {
surcharge_metadata,
updated_by,
},
Self::SurchargeAmountUpdate {
surcharge_amount,
tax_amount,
updated_by,
} => DieselPaymentAttemptUpdate::SurchargeAmountUpdate {
surcharge_amount,
tax_amount,
updated_by,
},
}
}
@ -1413,6 +1408,8 @@ impl DataModelExt for PaymentAttemptUpdate {
error_code,
error_message,
amount_capturable,
surcharge_amount,
tax_amount,
updated_by,
} => Self::ConfirmUpdate {
amount,
@ -1431,6 +1428,8 @@ impl DataModelExt for PaymentAttemptUpdate {
error_code,
error_message,
amount_capturable,
surcharge_amount,
tax_amount,
updated_by,
},
DieselPaymentAttemptUpdate::VoidUpdate {
@ -1565,15 +1564,6 @@ impl DataModelExt for PaymentAttemptUpdate {
surcharge_metadata,
updated_by,
},
DieselPaymentAttemptUpdate::SurchargeAmountUpdate {
surcharge_amount,
tax_amount,
updated_by,
} => Self::SurchargeAmountUpdate {
surcharge_amount,
tax_amount,
updated_by,
},
}
}
}

View File

@ -9738,6 +9738,14 @@
"description": "The business profile that is associated with this payment",
"nullable": true
},
"surcharge_details": {
"allOf": [
{
"$ref": "#/components/schemas/RequestSurchargeDetails"
}
],
"nullable": true
},
"attempt_count": {
"type": "integer",
"format": "int32",

View File

@ -0,0 +1,8 @@
{
"childrenOrder": [
"Payments - Create",
"Payments - Confirm",
"Payments - Capture",
"Payments - Retrieve"
]
}

View File

@ -0,0 +1,116 @@
// Validate status 2xx
pm.test("[POST]::/payments/:id/capture - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test(
"[POST]::/payments/:id/capture - Content-Type is application/json",
function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
},
);
// Validate if response has JSON Body
pm.test("[POST]::/payments/:id/capture - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set payment_id as variable for jsonData.payment_id
if (jsonData?.payment_id) {
pm.collectionVariables.set("payment_id", jsonData.payment_id);
console.log(
"- use {{payment_id}} as collection variable for value",
jsonData.payment_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payment_id}}, as jsonData.payment_id is undefined.",
);
}
// pm.collectionVariables - Set mandate_id as variable for jsonData.mandate_id
if (jsonData?.mandate_id) {
pm.collectionVariables.set("mandate_id", jsonData.mandate_id);
console.log(
"- use {{mandate_id}} as collection variable for value",
jsonData.mandate_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{mandate_id}}, as jsonData.mandate_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}
// Response body should have value "processing" for "status"
if (jsonData?.status) {
pm.test(
"[POST]:://payments/:id/capture - Content check if value for 'status' matches 'processing'",
function () {
pm.expect(jsonData.status).to.eql("processing");
},
);
}
// Validate the connector
pm.test("[POST]::/payments - connector", function () {
pm.expect(jsonData.connector).to.eql("paypal");
});
// Response body should have value "6540" for "amount"
if (jsonData?.amount) {
pm.test(
"[post]:://payments/:id/capture - Content check if value for 'amount' matches '6540'",
function () {
pm.expect(jsonData.amount).to.eql(6540);
},
);
}
// Response body should have value "6000" for "amount_received"
if (jsonData?.amount_received) {
pm.test(
"[POST]::/payments:id/capture - Content check if value for 'amount_received' matches '6000'",
function () {
pm.expect(jsonData.amount_received).to.eql(6000);
},
);
}
// Response body should have value "6540" for "amount_capturable"
if (jsonData?.amount_capturable) {
pm.test(
"[post]:://payments/:id/capture - Content check if value for 'amount_capturable' matches 0",
function () {
pm.expect(jsonData.amount_capturable).to.eql(0);
},
);
}
// Response body should have a valid surcharge_details field"
pm.test("Check if valid 'surcharge_details' is present in the response", function () {
pm.response.to.have.jsonBody('surcharge_details');
pm.expect(jsonData.surcharge_details.surcharge_amount).to.eql(5);
pm.expect(jsonData.surcharge_details.tax_amount).to.eql(5);
});

View File

@ -0,0 +1,39 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount_to_capture": 6000,
"statement_descriptor_name": "Joseph",
"statement_descriptor_suffix": "JS"
}
},
"url": {
"raw": "{{baseUrl}}/payments/:id/capture",
"host": ["{{baseUrl}}"],
"path": ["payments", ":id", "capture"],
"variable": [
{
"key": "id",
"value": "{{payment_id}}",
"description": "(Required) unique payment id"
}
]
},
"description": "To capture the funds for an uncaptured payment"
}

View File

@ -0,0 +1,116 @@
// Validate status 2xx
pm.test("[POST]::/payments/:id/confirm - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test(
"[POST]::/payments/:id/confirm - Content-Type is application/json",
function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
},
);
// Validate if response has JSON Body
pm.test("[POST]::/payments/:id/confirm - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set payment_id as variable for jsonData.payment_id
if (jsonData?.payment_id) {
pm.collectionVariables.set("payment_id", jsonData.payment_id);
console.log(
"- use {{payment_id}} as collection variable for value",
jsonData.payment_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payment_id}}, as jsonData.payment_id is undefined.",
);
}
// pm.collectionVariables - Set mandate_id as variable for jsonData.mandate_id
if (jsonData?.mandate_id) {
pm.collectionVariables.set("mandate_id", jsonData.mandate_id);
console.log(
"- use {{mandate_id}} as collection variable for value",
jsonData.mandate_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{mandate_id}}, as jsonData.mandate_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}
// Validate the connector
pm.test("[POST]::/payments - connector", function () {
pm.expect(jsonData.connector).to.eql("paypal");
});
// Response body should have value "requires_capture" for "status"
if (jsonData?.status) {
pm.test(
"[POST]::/payments - Content check if value for 'status' matches 'requires_capture'",
function () {
pm.expect(jsonData.status).to.eql("requires_capture");
},
);
}
// Response body should have value "6540" for "amount"
if (jsonData?.amount) {
pm.test(
"[post]:://payments/:id/capture - Content check if value for 'amount' matches '6540'",
function () {
pm.expect(jsonData.amount).to.eql(6540);
},
);
}
// Response body should have value "null" for "amount_received"
if (jsonData?.amount_received) {
pm.test(
"[post]:://payments/:id/capture - Content check if value for 'amount_received' matches 'null'",
function () {
pm.expect(jsonData.amount_received).to.eql(null);
},
);
}
// Response body should have value "6540" for "amount_capturable"
if (jsonData?.amount_capturable) {
pm.test(
"[post]:://payments/:id/capture - Content check if value for 'amount_capturable' matches 'amount - 0'",
function () {
pm.expect(jsonData.amount_capturable).to.eql(6550);
},
);
}
// Response body should have a valid surcharge_details field"
pm.test("Check if valid 'surcharge_details' is present in the response", function () {
pm.response.to.have.jsonBody('surcharge_details');
pm.expect(jsonData.surcharge_details.surcharge_amount).to.eql(5);
pm.expect(jsonData.surcharge_details.tax_amount).to.eql(5);
});

View File

@ -0,0 +1,60 @@
{
"auth": {
"type": "apikey",
"apikey": [
{
"key": "value",
"value": "{{publishable_key}}",
"type": "string"
},
{
"key": "key",
"value": "api-key",
"type": "string"
},
{
"key": "in",
"value": "header",
"type": "string"
}
]
},
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"client_secret": "{{client_secret}}",
"surcharge_details": {
"surcharge_amount": 5,
"tax_amount": 5
}
}
},
"url": {
"raw": "{{baseUrl}}/payments/:id/confirm",
"host": ["{{baseUrl}}"],
"path": ["payments", ":id", "confirm"],
"variable": [
{
"key": "id",
"value": "{{payment_id}}"
}
]
},
"description": "To process a payment you will have to create a payment, attach a payment method and confirm. Depending on the user journey you wish to achieve, you may opt to all the steps in a single request or in a sequence of API request using following APIs: (i) Payments - Update, (ii) Payments - Confirm, and (iii) Payments - Capture"
}

View File

@ -0,0 +1,101 @@
// Validate status 2xx
pm.test("[POST]::/payments - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test("[POST]::/payments - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payments - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set payment_id as variable for jsonData.payment_id
if (jsonData?.payment_id) {
pm.collectionVariables.set("payment_id", jsonData.payment_id);
console.log(
"- use {{payment_id}} as collection variable for value",
jsonData.payment_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payment_id}}, as jsonData.payment_id is undefined.",
);
}
// pm.collectionVariables - Set mandate_id as variable for jsonData.mandate_id
if (jsonData?.mandate_id) {
pm.collectionVariables.set("mandate_id", jsonData.mandate_id);
console.log(
"- use {{mandate_id}} as collection variable for value",
jsonData.mandate_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{mandate_id}}, as jsonData.mandate_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}
// Response body should have value "requires_confirmation" for "status"
if (jsonData?.status) {
pm.test(
"[POST]::/payments - Content check if value for 'status' matches 'requires_capture'",
function () {
pm.expect(jsonData.status).to.eql("requires_confirmation");
},
);
}
// Response body should have value "6540" for "amount"
if (jsonData?.amount) {
pm.test(
"[post]:://payments/:id/capture - Content check if value for 'amount' matches '6540'",
function () {
pm.expect(jsonData.amount).to.eql(6540);
},
);
}
// Response body should have value "null" for "amount_received"
if (jsonData?.amount_received) {
pm.test(
"[post]:://payments/:id/capture - Content check if value for 'amount_received' matches 'null'",
function () {
pm.expect(jsonData.amount_received).to.eql(null);
},
);
}
// Response body should have value "6540" for "amount_capturable"
if (jsonData?.amount_capturable) {
pm.test(
"[post]:://payments/:id/capture - Content check if value for 'amount_capturable' matches 'amount - 6540'",
function () {
pm.expect(jsonData.amount_capturable).to.eql(6540);
},
);
}

View File

@ -0,0 +1,87 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 6540,
"currency": "USD",
"confirm": false,
"capture_method": "manual",
"capture_on": "2022-09-10T10:11:12Z",
"customer_id": "StripeCustomer",
"email": "guest@example.com",
"name": "John Doe",
"phone": "999999999",
"phone_country_code": "+1",
"description": "Its my first payment request",
"authentication_type": "no_three_ds",
"return_url": "https://duck.com",
"payment_method": "card",
"payment_method_data": {
"card": {
"card_number": "4005519200000004",
"card_exp_month": "10",
"card_exp_year": "25",
"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": "PiX"
}
},
"shipping": {
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "California",
"zip": "94122",
"country": "US",
"first_name": "PiX"
}
},
"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": "paypal"
}
}
},
"url": {
"raw": "{{baseUrl}}/payments",
"host": ["{{baseUrl}}"],
"path": ["payments"]
},
"description": "To process a payment you will have to create a payment, attach a payment method and confirm. Depending on the user journey you wish to achieve, you may opt to all the steps in a single request or in a sequence of API request using following APIs: (i) Payments - Update, (ii) Payments - Confirm, and (iii) Payments - Capture"
}

View File

@ -0,0 +1,113 @@
// Validate status 2xx
pm.test("[GET]::/payments/:id - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test("[GET]::/payments/:id - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[GET]::/payments/:id - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) {}
// pm.collectionVariables - Set payment_id as variable for jsonData.payment_id
if (jsonData?.payment_id) {
pm.collectionVariables.set("payment_id", jsonData.payment_id);
console.log(
"- use {{payment_id}} as collection variable for value",
jsonData.payment_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payment_id}}, as jsonData.payment_id is undefined.",
);
}
// pm.collectionVariables - Set mandate_id as variable for jsonData.mandate_id
if (jsonData?.mandate_id) {
pm.collectionVariables.set("mandate_id", jsonData.mandate_id);
console.log(
"- use {{mandate_id}} as collection variable for value",
jsonData.mandate_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{mandate_id}}, as jsonData.mandate_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}
// Response body should have value "processing" for "status"
if (jsonData?.status) {
pm.test(
"[POST]::/payments - Content check if value for 'status' matches 'processing'",
function () {
pm.expect(jsonData.status).to.eql("processing");
},
);
}
// Validate the connector
pm.test("[POST]::/payments - connector", function () {
pm.expect(jsonData.connector).to.eql("paypal");
});
// Response body should have value "6540" for "amount"
if (jsonData?.amount) {
pm.test(
"[post]:://payments/:id/capture - Content check if value for 'amount' matches '6540'",
function () {
pm.expect(jsonData.amount).to.eql(6540);
},
);
}
// Response body should have value "6000" for "amount_received"
if (jsonData?.amount_received) {
pm.test(
"[POST]::/payments:id/capture - Content check if value for 'amount_received' matches '6000'",
function () {
pm.expect(jsonData.amount_received).to.eql(6000);
},
);
}
// Response body should have value "6540" for "amount_capturable"
if (jsonData?.amount_capturable) {
pm.test(
"[post]:://payments/:id/capture - Content check if value for 'amount_capturable' matches 'amount - 540'",
function () {
pm.expect(jsonData.amount_capturable).to.eql(540);
},
);
}
// Response body should have a valid surcharge_details field"
pm.test("Check if valid 'surcharge_details' is present in the response", function () {
pm.response.to.have.jsonBody('surcharge_details');
pm.expect(jsonData.surcharge_details.surcharge_amount).to.eql(5);
pm.expect(jsonData.surcharge_details.tax_amount).to.eql(5);
});

View File

@ -0,0 +1,28 @@
{
"method": "GET",
"header": [
{
"key": "Accept",
"value": "application/json"
}
],
"url": {
"raw": "{{baseUrl}}/payments/:id?force_sync=true",
"host": ["{{baseUrl}}"],
"path": ["payments", ":id"],
"query": [
{
"key": "force_sync",
"value": "true"
}
],
"variable": [
{
"key": "id",
"value": "{{payment_id}}",
"description": "(Required) unique payment id"
}
]
},
"description": "To retrieve the properties of a Payment. This may be used to get the status of a previously initiated payment or next action for an ongoing payment"
}

View File

@ -79,6 +79,10 @@
"metadata": {
"city": "NY",
"unit": "245"
},
"routing_algorithm": {
"type": "single",
"data": "paypal"
}
}
},