diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index e763a3e267..f61f6f9a44 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -311,7 +311,9 @@ pub struct PaymentsRequest { pub payment_type: Option, } -#[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, @@ -2096,6 +2098,9 @@ pub struct PaymentsResponse { /// The business profile that is associated with this payment pub profile_id: Option, + /// details of surcharge applied on this payment + pub surcharge_details: Option, + /// total number of attempts associated with this payment pub attempt_count: i16, diff --git a/crates/data_models/src/payments/payment_attempt.rs b/crates/data_models/src/payments/payment_attempt.rs index cf65c3f5de..c31230229d 100644 --- a/crates/data_models/src/payments/payment_attempt.rs +++ b/crates/data_models/src/payments/payment_attempt.rs @@ -250,6 +250,8 @@ pub enum PaymentAttemptUpdate { error_code: Option>, error_message: Option>, amount_capturable: Option, + surcharge_amount: Option, + tax_amount: Option, updated_by: String, }, RejectUpdate { @@ -307,11 +309,6 @@ pub enum PaymentAttemptUpdate { multiple_capture_count: i16, updated_by: String, }, - SurchargeAmountUpdate { - surcharge_amount: Option, - tax_amount: Option, - updated_by: String, - }, AmountToCaptureUpdate { status: storage_enums::AttemptStatus, amount_capturable: i64, diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs index ca73540437..930a9cf959 100644 --- a/crates/diesel_models/src/payment_attempt.rs +++ b/crates/diesel_models/src/payment_attempt.rs @@ -166,6 +166,8 @@ pub enum PaymentAttemptUpdate { error_code: Option>, error_message: Option>, amount_capturable: Option, + surcharge_amount: Option, + tax_amount: Option, updated_by: String, }, VoidUpdate { @@ -228,11 +230,6 @@ pub enum PaymentAttemptUpdate { amount_capturable: i64, updated_by: String, }, - SurchargeAmountUpdate { - surcharge_amount: Option, - tax_amount: Option, - updated_by: String, - }, PreprocessingUpdate { status: storage_enums::AttemptStatus, payment_method_id: Option>, @@ -378,6 +375,8 @@ impl From for PaymentAttemptUpdateInternal { error_code, error_message, amount_capturable, + surcharge_amount, + tax_amount, updated_by, } => Self { amount: Some(amount), @@ -397,6 +396,8 @@ impl From for PaymentAttemptUpdateInternal { error_code, error_message, amount_capturable, + surcharge_amount, + tax_amount, updated_by, ..Default::default() }, @@ -561,16 +562,6 @@ impl From for PaymentAttemptUpdateInternal { updated_by, ..Default::default() }, - PaymentAttemptUpdate::SurchargeAmountUpdate { - surcharge_amount, - tax_amount, - updated_by, - } => Self { - surcharge_amount, - tax_amount, - updated_by, - ..Default::default() - }, } } } diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index 4a1689338f..df5bfc44d8 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -216,6 +216,10 @@ impl ConnectorValidation for Paypal { ), } } + + fn validate_if_surcharge_implemented(&self) -> CustomResult<(), errors::ConnectorError> { + Ok(()) + } } impl diff --git a/crates/router/src/connector/trustpay.rs b/crates/router/src/connector/trustpay.rs index fd2d369a7c..912f1575e1 100644 --- a/crates/router/src/connector/trustpay.rs +++ b/crates/router/src/connector/trustpay.rs @@ -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 {} diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs index a727914758..3164e74dcd 100644 --- a/crates/router/src/core/payments/flows/authorize_flow.rs +++ b/crates/router/src/core/payments/flows/authorize_flow.rs @@ -73,6 +73,12 @@ impl Feature 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(); diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index eeb94f4558..1cfcbce553 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -82,7 +82,10 @@ impl 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)?; diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index a045cee354..0e0d6c2147 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -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 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 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 .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 error_code, error_message, amount_capturable: Some(authorized_amount), + surcharge_amount, + tax_amount, updated_by: storage_scheme.to_string(), }, storage_scheme, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index af84152120..1467da7f81 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -559,7 +559,7 @@ async fn payment_response_update_tracker( 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(), }); diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 66453315d4..d2ced5af34 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -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, diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 492a7a51f4..964a70c0b5 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -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] diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index e1311bda67..518aaa2e3d 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -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, - }, } } } diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index bacefa4b27..507c1000b3 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -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", diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/.meta.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/.meta.json new file mode 100644 index 0000000000..e6b348a60b --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/.meta.json @@ -0,0 +1,8 @@ +{ + "childrenOrder": [ + "Payments - Create", + "Payments - Confirm", + "Payments - Capture", + "Payments - Retrieve" + ] +} diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/.event.meta.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/.event.meta.json new file mode 100644 index 0000000000..0731450e6b --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/.event.meta.json @@ -0,0 +1,3 @@ +{ + "eventOrder": ["event.test.js"] +} diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/event.test.js b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/event.test.js new file mode 100644 index 0000000000..432edf05d3 --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/event.test.js @@ -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); +}); diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/request.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/request.json new file mode 100644 index 0000000000..9fe257ed85 --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/request.json @@ -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" +} diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/response.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/response.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Capture/response.json @@ -0,0 +1 @@ +[] diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/.event.meta.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/.event.meta.json new file mode 100644 index 0000000000..0731450e6b --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/.event.meta.json @@ -0,0 +1,3 @@ +{ + "eventOrder": ["event.test.js"] +} diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/event.test.js b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/event.test.js new file mode 100644 index 0000000000..ba5d852e9b --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/event.test.js @@ -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); +}); \ No newline at end of file diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/request.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/request.json new file mode 100644 index 0000000000..c609894397 --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/request.json @@ -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" +} diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/response.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/response.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Confirm/response.json @@ -0,0 +1 @@ +[] diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/.event.meta.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/.event.meta.json new file mode 100644 index 0000000000..0731450e6b --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/.event.meta.json @@ -0,0 +1,3 @@ +{ + "eventOrder": ["event.test.js"] +} diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/event.test.js b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/event.test.js new file mode 100644 index 0000000000..fe83ca7852 --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/event.test.js @@ -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); + }, + ); +} diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/request.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/request.json new file mode 100644 index 0000000000..b080ff1a6b --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/request.json @@ -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" +} diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/response.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/response.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Create/response.json @@ -0,0 +1 @@ +[] diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/.event.meta.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/.event.meta.json new file mode 100644 index 0000000000..0731450e6b --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/.event.meta.json @@ -0,0 +1,3 @@ +{ + "eventOrder": ["event.test.js"] +} diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/event.test.js b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/event.test.js new file mode 100644 index 0000000000..5097d1cf94 --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/event.test.js @@ -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); +}); diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/request.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/request.json new file mode 100644 index 0000000000..6cd4b7d96c --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/request.json @@ -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" +} diff --git a/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/response.json b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/response.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/postman/collection-dir/paypal/Flow Testcases/Happy Cases/Scenario8-Create payment with Manual capture with confirm false and surcharge_data/Payments - Retrieve/response.json @@ -0,0 +1 @@ +[] diff --git a/postman/collection-dir/paypal/Flow Testcases/QuickStart/Merchant Account - Create/request.json b/postman/collection-dir/paypal/Flow Testcases/QuickStart/Merchant Account - Create/request.json index 7df5315150..5aa155f64c 100644 --- a/postman/collection-dir/paypal/Flow Testcases/QuickStart/Merchant Account - Create/request.json +++ b/postman/collection-dir/paypal/Flow Testcases/QuickStart/Merchant Account - Create/request.json @@ -79,6 +79,10 @@ "metadata": { "city": "NY", "unit": "245" + }, + "routing_algorithm": { + "type": "single", + "data": "paypal" } } },