From d2d317ce61c0c00ca38af9774bd1b45247d30c82 Mon Sep 17 00:00:00 2001 From: Sanchith Hegde <22217505+SanchithHegde@users.noreply.github.com> Date: Fri, 31 May 2024 15:01:12 +0530 Subject: [PATCH 01/25] chore: enable `clippy::large_futures` lint (#4822) --- .cargo/config.toml | 1 + crates/router/src/core/disputes.rs | 4 ++-- crates/router/src/core/fraud_check.rs | 4 ++-- crates/router/src/core/payment_methods/cards.rs | 14 +++++++------- crates/router/src/core/payments/tokenization.rs | 4 ++-- crates/router/src/core/refunds.rs | 4 ++-- crates/router/src/core/webhooks.rs | 4 ++-- .../router/src/core/webhooks/webhook_events.rs | 4 ++-- crates/router/src/routes/cards_info.rs | 4 ++-- crates/router/src/routes/customers.rs | 4 ++-- crates/router/src/routes/disputes.rs | 8 ++++---- crates/router/src/routes/mandates.rs | 4 ++-- crates/router/src/routes/payment_link.rs | 4 ++-- crates/router/src/routes/payments.rs | 16 ++++++++-------- crates/router/src/routes/poll.rs | 4 ++-- crates/router/src/routes/refunds.rs | 16 ++++++++-------- crates/router/src/routes/routing.rs | 16 ++++++++-------- crates/router/src/routes/webhook_events.rs | 12 ++++++------ .../src/workflows/outgoing_webhook_retry.rs | 8 ++++---- 19 files changed, 68 insertions(+), 67 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 852384da785e..e643b41ec053 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -6,6 +6,7 @@ rustflags = [ "-Wclippy::expect_used", "-Wclippy::index_refutable_slice", "-Wclippy::indexing_slicing", + "-Wclippy::large_futures", "-Wclippy::match_on_vec_items", "-Wclippy::missing_panics_doc", "-Wclippy::out_of_bounds_indexing", diff --git a/crates/router/src/core/disputes.rs b/crates/router/src/core/disputes.rs index 4928dc949dc9..f608100c08a7 100644 --- a/crates/router/src/core/disputes.rs +++ b/crates/router/src/core/disputes.rs @@ -358,12 +358,12 @@ pub async fn attach_evidence( }) }, )?; - let create_file_response = files::files_create_core( + let create_file_response = Box::pin(files::files_create_core( state.clone(), merchant_account, key_store, attach_evidence_request.create_file_request, - ) + )) .await?; let file_id = match &create_file_response { services::ApplicationResponse::Json(res) => res.file_id.clone(), diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index 63bf80bac020..dddcf581296f 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -563,7 +563,7 @@ where frm_routing_algorithm.zip(frm_connector_label) { if let Some(frm_configs) = frm_configs.clone() { - let mut updated_frm_info = make_frm_data_and_fraud_check_operation( + let mut updated_frm_info = Box::pin(make_frm_data_and_fraud_check_operation( db, state, merchant_account, @@ -572,7 +572,7 @@ where profile_id, frm_configs.clone(), customer, - ) + )) .await?; if is_frm_enabled { diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 33103b7a901c..02e29f24a672 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -286,7 +286,7 @@ pub async fn get_client_secret_or_add_payment_method( let condition = req.card.is_some() || req.bank_transfer.is_some() || req.wallet.is_some(); if condition { - add_payment_method(state, req, merchant_account, key_store).await + Box::pin(add_payment_method(state, req, merchant_account, key_store)).await } else { let payment_method_id = generate_id(consts::ID_LENGTH, "pm"); @@ -393,14 +393,14 @@ pub async fn add_payment_method_data( match pmd { api_models::payment_methods::PaymentMethodCreateData::Card(card) => { helpers::validate_card_expiry(&card.card_exp_month, &card.card_exp_year)?; - let resp = add_card_to_locker( + let resp = Box::pin(add_card_to_locker( &state, req.clone(), &card, &customer_id, &merchant_account, None, - ) + )) .await .change_context(errors::ApiErrorResponse::InternalServerError); @@ -555,14 +555,14 @@ pub async fn add_payment_method( api_enums::PaymentMethod::Card => match req.card.clone() { Some(card) => { helpers::validate_card_expiry(&card.card_exp_month, &card.card_exp_year)?; - add_card_to_locker( + Box::pin(add_card_to_locker( &state, req.clone(), &card, &customer_id, merchant_account, None, - ) + )) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Add Card Failed") @@ -888,14 +888,14 @@ pub async fn update_customer_payment_method( .await?; // Add the updated payment method data to locker - let (mut add_card_resp, _) = add_card_to_locker( + let (mut add_card_resp, _) = Box::pin(add_card_to_locker( &state, new_pm.clone(), &updated_card_details, &pm.customer_id, &merchant_account, Some(pm.locker_id.as_ref().unwrap_or(&pm.payment_method_id)), - ) + )) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to add updated payment method to locker")?; diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 3341011bb5d6..c19c8c45753c 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -660,14 +660,14 @@ pub async fn save_in_locker( .clone() .get_required_value("customer_id")?; match payment_method_request.card.clone() { - Some(card) => payment_methods::cards::add_card_to_locker( + Some(card) => Box::pin(payment_methods::cards::add_card_to_locker( state, payment_method_request, &card, &customer_id, merchant_account, None, - ) + )) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Add Card Failed"), diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index 9ab1ec0eb880..d2d2db71ef36 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -726,7 +726,7 @@ pub async fn validate_and_create_refund( .await { Ok(refund) => { - schedule_refund_execution( + Box::pin(schedule_refund_execution( state, refund.clone(), refund_type, @@ -736,7 +736,7 @@ pub async fn validate_and_create_refund( payment_intent, creds_identifier, charges, - ) + )) .await? } Err(err) => { diff --git a/crates/router/src/core/webhooks.rs b/crates/router/src/core/webhooks.rs index 7e29036c40fe..c5055d4c8c25 100644 --- a/crates/router/src/core/webhooks.rs +++ b/crates/router/src/core/webhooks.rs @@ -1070,7 +1070,7 @@ pub(crate) async fn create_event_and_trigger_outgoing_webhook( // may have an actix arbiter tokio::spawn( async move { - trigger_webhook_and_raise_event( + Box::pin(trigger_webhook_and_raise_event( state, business_profile, &cloned_key_store, @@ -1079,7 +1079,7 @@ pub(crate) async fn create_event_and_trigger_outgoing_webhook( delivery_attempt, Some(content), process_tracker, - ) + )) .await; } .in_current_span(), diff --git a/crates/router/src/core/webhooks/webhook_events.rs b/crates/router/src/core/webhooks/webhook_events.rs index 6db214c2b054..f248edd652bf 100644 --- a/crates/router/src/core/webhooks/webhook_events.rs +++ b/crates/router/src/core/webhooks/webhook_events.rs @@ -231,7 +231,7 @@ pub async fn retry_delivery_attempt( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to parse webhook event request information")?; - super::trigger_webhook_and_raise_event( + Box::pin(super::trigger_webhook_and_raise_event( state.clone(), business_profile, &key_store, @@ -240,7 +240,7 @@ pub async fn retry_delivery_attempt( delivery_attempt, None, None, - ) + )) .await; let updated_event = store diff --git a/crates/router/src/routes/cards_info.rs b/crates/router/src/routes/cards_info.rs index 4d65fc720368..ca59e072a900 100644 --- a/crates/router/src/routes/cards_info.rs +++ b/crates/router/src/routes/cards_info.rs @@ -41,7 +41,7 @@ pub async fn card_iin_info( Err(e) => return api::log_and_return_error_response(e), }; - api::server_wrap( + Box::pin(api::server_wrap( Flow::CardsInfo, state, &req, @@ -49,6 +49,6 @@ pub async fn card_iin_info( |state, auth, req, _| cards_info::retrieve_card_info(state, auth.merchant_account, req), &*auth, api_locking::LockAction::NotApplicable, - ) + )) .await } diff --git a/crates/router/src/routes/customers.rs b/crates/router/src/routes/customers.rs index b97cfc3fa0d8..4d86ae829e08 100644 --- a/crates/router/src/routes/customers.rs +++ b/crates/router/src/routes/customers.rs @@ -53,7 +53,7 @@ pub async fn customers_retrieve( } }; - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -61,7 +61,7 @@ pub async fn customers_retrieve( |state, auth, req, _| retrieve_customer(state, auth.merchant_account, auth.key_store, req), &*auth, api_locking::LockAction::NotApplicable, - ) + )) .await } diff --git a/crates/router/src/routes/disputes.rs b/crates/router/src/routes/disputes.rs index a4a6c7507a4f..4c7199f2f29d 100644 --- a/crates/router/src/routes/disputes.rs +++ b/crates/router/src/routes/disputes.rs @@ -38,7 +38,7 @@ pub async fn retrieve_dispute( let dispute_id = dispute_types::DisputeId { dispute_id: path.into_inner(), }; - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -50,7 +50,7 @@ pub async fn retrieve_dispute( req.headers(), ), api_locking::LockAction::NotApplicable, - ) + )) .await } /// Disputes - List Disputes @@ -85,7 +85,7 @@ pub async fn retrieve_disputes_list( ) -> HttpResponse { let flow = Flow::DisputesList; let payload = payload.into_inner(); - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -97,7 +97,7 @@ pub async fn retrieve_disputes_list( req.headers(), ), api_locking::LockAction::NotApplicable, - ) + )) .await } /// Disputes - Accept Dispute diff --git a/crates/router/src/routes/mandates.rs b/crates/router/src/routes/mandates.rs index 365f9a432483..c2ed58ae40b4 100644 --- a/crates/router/src/routes/mandates.rs +++ b/crates/router/src/routes/mandates.rs @@ -36,7 +36,7 @@ pub async fn get_mandate( let mandate_id = mandates::MandateId { mandate_id: path.into_inner(), }; - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -46,7 +46,7 @@ pub async fn get_mandate( }, &auth::ApiKeyAuth, api_locking::LockAction::NotApplicable, - ) + )) .await } /// Mandates - Revoke Mandate diff --git a/crates/router/src/routes/payment_link.rs b/crates/router/src/routes/payment_link.rs index 7742f6c1c0e0..f375a18ab614 100644 --- a/crates/router/src/routes/payment_link.rs +++ b/crates/router/src/routes/payment_link.rs @@ -112,7 +112,7 @@ pub async fn payments_link_list( ) -> impl Responder { let flow = Flow::PaymentLinkList; let payload = payload.into_inner(); - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -120,7 +120,7 @@ pub async fn payments_link_list( |state, auth, payload, _| list_payment_link(state, auth.merchant_account, payload), &auth::ApiKeyAuth, api_locking::LockAction::NotApplicable, - ) + )) .await } diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index f28cad89004f..ab6b0f450db1 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -949,7 +949,7 @@ pub async fn payments_list( ) -> impl Responder { let flow = Flow::PaymentsList; let payload = payload.into_inner(); - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -961,7 +961,7 @@ pub async fn payments_list( req.headers(), ), api_locking::LockAction::NotApplicable, - ) + )) .await } #[instrument(skip_all, fields(flow = ?Flow::PaymentsList))] @@ -973,7 +973,7 @@ pub async fn payments_list_by_filter( ) -> impl Responder { let flow = Flow::PaymentsList; let payload = payload.into_inner(); - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -983,7 +983,7 @@ pub async fn payments_list_by_filter( }, &auth::JWTAuth(Permission::PaymentRead), api_locking::LockAction::NotApplicable, - ) + )) .await } #[instrument(skip_all, fields(flow = ?Flow::PaymentsList))] @@ -995,7 +995,7 @@ pub async fn get_filters_for_payments( ) -> impl Responder { let flow = Flow::PaymentsList; let payload = payload.into_inner(); - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -1005,7 +1005,7 @@ pub async fn get_filters_for_payments( }, &auth::JWTAuth(Permission::PaymentRead), api_locking::LockAction::NotApplicable, - ) + )) .await } @@ -1016,7 +1016,7 @@ pub async fn get_payment_filters( req: actix_web::HttpRequest, ) -> impl Responder { let flow = Flow::PaymentsFilters; - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -1026,7 +1026,7 @@ pub async fn get_payment_filters( }, &auth::JWTAuth(Permission::PaymentRead), api_locking::LockAction::NotApplicable, - ) + )) .await } diff --git a/crates/router/src/routes/poll.rs b/crates/router/src/routes/poll.rs index 39bb63832a93..e4591b403275 100644 --- a/crates/router/src/routes/poll.rs +++ b/crates/router/src/routes/poll.rs @@ -33,7 +33,7 @@ pub async fn retrieve_poll_status( let poll_id = PollId { poll_id: path.into_inner(), }; - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -41,6 +41,6 @@ pub async fn retrieve_poll_status( |state, auth, req, _| poll::retrieve_poll_status(state, req, auth.merchant_account), &auth::PublishableKeyAuth, api_locking::LockAction::NotApplicable, - ) + )) .await } diff --git a/crates/router/src/routes/refunds.rs b/crates/router/src/routes/refunds.rs index 3df6c8716682..50e0c0c917f6 100644 --- a/crates/router/src/routes/refunds.rs +++ b/crates/router/src/routes/refunds.rs @@ -182,7 +182,7 @@ pub async fn refunds_update( let flow = Flow::RefundsUpdate; let mut refund_update_req = json_payload.into_inner(); refund_update_req.refund_id = path.into_inner(); - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -190,7 +190,7 @@ pub async fn refunds_update( |state, auth, req, _| refund_update_core(state, auth.merchant_account, req), &auth::ApiKeyAuth, api_locking::LockAction::NotApplicable, - ) + )) .await } /// Refunds - List @@ -215,7 +215,7 @@ pub async fn refunds_list( payload: web::Json, ) -> HttpResponse { let flow = Flow::RefundsList; - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -227,7 +227,7 @@ pub async fn refunds_list( req.headers(), ), api_locking::LockAction::NotApplicable, - ) + )) .await } @@ -253,7 +253,7 @@ pub async fn refunds_filter_list( payload: web::Json, ) -> HttpResponse { let flow = Flow::RefundsList; - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -265,7 +265,7 @@ pub async fn refunds_filter_list( req.headers(), ), api_locking::LockAction::NotApplicable, - ) + )) .await } @@ -286,7 +286,7 @@ pub async fn refunds_filter_list( #[cfg(feature = "olap")] pub async fn get_refunds_filters(state: web::Data, req: HttpRequest) -> HttpResponse { let flow = Flow::RefundsFilters; - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -298,6 +298,6 @@ pub async fn get_refunds_filters(state: web::Data, req: HttpRequest) - req.headers(), ), api_locking::LockAction::NotApplicable, - ) + )) .await } diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs index 556e91d86946..74bd61765b0d 100644 --- a/crates/router/src/routes/routing.rs +++ b/crates/router/src/routes/routing.rs @@ -259,7 +259,7 @@ pub async fn routing_update_default_config( json_payload: web::Json>, transaction_type: &enums::TransactionType, ) -> impl Responder { - oss_api::server_wrap( + Box::pin(oss_api::server_wrap( Flow::RoutingUpdateDefaultConfig, state, &req, @@ -281,7 +281,7 @@ pub async fn routing_update_default_config( #[cfg(feature = "release")] &auth::JWTAuth(Permission::RoutingWrite), api_locking::LockAction::NotApplicable, - ) + )) .await } @@ -292,7 +292,7 @@ pub async fn routing_retrieve_default_config( req: HttpRequest, transaction_type: &enums::TransactionType, ) -> impl Responder { - oss_api::server_wrap( + Box::pin(oss_api::server_wrap( Flow::RoutingRetrieveDefaultConfig, state, &req, @@ -309,7 +309,7 @@ pub async fn routing_retrieve_default_config( #[cfg(feature = "release")] &auth::JWTAuth(Permission::RoutingRead), api_locking::LockAction::NotApplicable, - ) + )) .await } @@ -573,7 +573,7 @@ pub async fn routing_retrieve_default_config_for_profiles( req: HttpRequest, transaction_type: &enums::TransactionType, ) -> impl Responder { - oss_api::server_wrap( + Box::pin(oss_api::server_wrap( Flow::RoutingRetrieveDefaultConfig, state, &req, @@ -598,7 +598,7 @@ pub async fn routing_retrieve_default_config_for_profiles( req.headers(), ), api_locking::LockAction::NotApplicable, - ) + )) .await } @@ -615,7 +615,7 @@ pub async fn routing_update_default_config_for_profile( updated_config: json_payload.into_inner(), profile_id: path.into_inner(), }; - oss_api::server_wrap( + Box::pin(oss_api::server_wrap( Flow::RoutingUpdateDefaultConfig, state, &req, @@ -638,6 +638,6 @@ pub async fn routing_update_default_config_for_profile( #[cfg(feature = "release")] &auth::JWTAuth(Permission::RoutingWrite), api_locking::LockAction::NotApplicable, - ) + )) .await } diff --git a/crates/router/src/routes/webhook_events.rs b/crates/router/src/routes/webhook_events.rs index ef1d64f54e95..b4839f5bd075 100644 --- a/crates/router/src/routes/webhook_events.rs +++ b/crates/router/src/routes/webhook_events.rs @@ -27,7 +27,7 @@ pub async fn list_initial_webhook_delivery_attempts( constraints, }; - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -48,7 +48,7 @@ pub async fn list_initial_webhook_delivery_attempts( req.headers(), ), api_locking::LockAction::NotApplicable, - ) + )) .await } @@ -66,7 +66,7 @@ pub async fn list_webhook_delivery_attempts( initial_attempt_id, }; - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -87,7 +87,7 @@ pub async fn list_webhook_delivery_attempts( req.headers(), ), api_locking::LockAction::NotApplicable, - ) + )) .await } @@ -105,7 +105,7 @@ pub async fn retry_webhook_delivery_attempt( event_id, }; - api::server_wrap( + Box::pin(api::server_wrap( flow, state, &req, @@ -126,6 +126,6 @@ pub async fn retry_webhook_delivery_attempt( req.headers(), ), api_locking::LockAction::NotApplicable, - ) + )) .await } diff --git a/crates/router/src/workflows/outgoing_webhook_retry.rs b/crates/router/src/workflows/outgoing_webhook_retry.rs index 726cbf9de09b..63bdb7ec9894 100644 --- a/crates/router/src/workflows/outgoing_webhook_retry.rs +++ b/crates/router/src/workflows/outgoing_webhook_retry.rs @@ -114,7 +114,7 @@ impl ProcessTrackerWorkflow for OutgoingWebhookRetryWorkflow { .peek() .parse_struct("OutgoingWebhookRequestContent")?; - webhooks_core::trigger_webhook_and_raise_event( + Box::pin(webhooks_core::trigger_webhook_and_raise_event( state.clone(), business_profile, &key_store, @@ -123,7 +123,7 @@ impl ProcessTrackerWorkflow for OutgoingWebhookRetryWorkflow { delivery_attempt, None, Some(process), - ) + )) .await; } @@ -168,7 +168,7 @@ impl ProcessTrackerWorkflow for OutgoingWebhookRetryWorkflow { errors::ProcessTrackerError::EApiErrorResponse })?; - webhooks_core::trigger_webhook_and_raise_event( + Box::pin(webhooks_core::trigger_webhook_and_raise_event( state.clone(), business_profile, &key_store, @@ -177,7 +177,7 @@ impl ProcessTrackerWorkflow for OutgoingWebhookRetryWorkflow { delivery_attempt, Some(content), Some(process), - ) + )) .await; } // Resource status has changed since the event was created, finish task From 48dac12cedc7f11b76c6a9ef8ba4ce04ae2456bf Mon Sep 17 00:00:00 2001 From: Pa1NarK <69745008+pixincreate@users.noreply.github.com> Date: Fri, 31 May 2024 15:05:43 +0530 Subject: [PATCH 02/25] feat(cypress): add trustpay, adyen bank redirects and corresponding refactor (#4766) --- cypress-tests/cypress.config.js | 17 +- .../ConnectorTest/00016-BankTransfers.cy.js | 81 ++ .../ConnectorTest/00017-BankRedirect.cy.js | 325 ++++++ .../cypress/e2e/ConnectorUtils/Adyen.js | 831 +++++++++------- .../cypress/e2e/ConnectorUtils/Commons.js | 507 ++++++++++ .../cypress/e2e/ConnectorUtils/Trustpay.js | 926 ++++++++++-------- .../cypress/e2e/ConnectorUtils/utils.js | 76 +- .../cypress/fixtures/confirm-body.json | 15 +- .../fixtures/create-connector-body.json | 72 ++ cypress-tests/cypress/support/commands.js | 350 ++++--- .../cypress/support/redirectionhandler.js | 319 ++++++ cypress-tests/package.json | 5 +- 12 files changed, 2605 insertions(+), 919 deletions(-) create mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00016-BankTransfers.cy.js create mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00017-BankRedirect.cy.js create mode 100644 cypress-tests/cypress/e2e/ConnectorUtils/Commons.js create mode 100644 cypress-tests/cypress/support/redirectionhandler.js diff --git a/cypress-tests/cypress.config.js b/cypress-tests/cypress.config.js index 7def1f1b9f46..e36f68e80e24 100644 --- a/cypress-tests/cypress.config.js +++ b/cypress-tests/cypress.config.js @@ -1,25 +1,24 @@ - let globalState; module.exports = { e2e: { setupNodeEvents(on, config) { - on('task', { + on("task", { setGlobalState: (val) => { - return (globalState = (val || {})) + return (globalState = val || {}); }, getGlobalState: () => { - return (globalState || {}) + return globalState || {}; }, cli_log: (message) => { console.log("Logging console message from task"); console.log(message); return null; - } - }) + }, + }); }, - experimentalRunAllSpecs: true + experimentalRunAllSpecs: true, }, chromeWebSecurity: false, defaultCommandTimeout: 10000, - pageLoadTimeout: 20000 -}; \ No newline at end of file + pageLoadTimeout: 20000, +}; diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00016-BankTransfers.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00016-BankTransfers.cy.js new file mode 100644 index 000000000000..ae5f09871024 --- /dev/null +++ b/cypress-tests/cypress/e2e/ConnectorTest/00016-BankTransfers.cy.js @@ -0,0 +1,81 @@ +import confirmBody from "../../fixtures/confirm-body.json"; +import createPaymentBody from "../../fixtures/create-payment-body.json"; +import State from "../../utils/State"; +import getConnectorDetails, * as utils from "../ConnectorUtils/utils"; + +let globalState; + +describe("Bank Transfers", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + console.log("seeding globalState -> " + JSON.stringify(globalState)); + }); + }); + + after("flush global state", () => { + console.log("flushing globalState -> " + JSON.stringify(globalState)); + cy.task("setGlobalState", globalState.data); + }); + + context("Bank transfer - Pix forward flow", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_transfer_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "automatic", + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.task("cli_log", "PM CALL "); + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm bank transfer", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_transfer_pm" + ]["Pix"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); + cy.confirmBankTransferCallTest( + confirmBody, + req_data, + res_data, + true, + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle bank transfer redirection", () => { + let expected_redirection = confirmBody["return_url"]; + let payment_method_type = globalState.get("paymentMethodType"); + cy.handleBankTransferRedirection( + globalState, + payment_method_type, + expected_redirection + ); + }); + }); +}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00017-BankRedirect.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00017-BankRedirect.cy.js new file mode 100644 index 000000000000..c08468022a80 --- /dev/null +++ b/cypress-tests/cypress/e2e/ConnectorTest/00017-BankRedirect.cy.js @@ -0,0 +1,325 @@ +import confirmBody from "../../fixtures/confirm-body.json"; +import createPaymentBody from "../../fixtures/create-payment-body.json"; +import State from "../../utils/State"; +import getConnectorDetails, * as utils from "../ConnectorUtils/utils"; + +let globalState; + +describe("Bank Redirect tests", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + console.log("seeding globalState -> " + JSON.stringify(globalState)); + }); + }); + + after("flush global state", () => { + console.log("flushing globalState -> " + JSON.stringify(globalState)); + cy.task("setGlobalState", globalState.data); + }); + + afterEach("flush global state", () => { + console.log("flushing globalState -> " + JSON.stringify(globalState)); + cy.task("setGlobalState", globalState.data); + cy.task( + "cli_log", + " FLUSHING GLOBAL STATE -> " + JSON.stringify(globalState) + ); + }); + + context("Blik Create and Confirm flow test", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_redirect_pm" + ]["blikPaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "automatic", + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.task("cli_log", "PM CALL "); + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm bank redirect", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_redirect_pm" + ]["blik"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); + cy.confirmBankRedirectCallTest( + confirmBody, + req_data, + res_data, + true, + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }); + + context("EPS Create and Confirm flow test", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_redirect_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "automatic", + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.task("cli_log", "PM CALL "); + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm bank redirect", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_redirect_pm" + ]["eps"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); + cy.confirmBankRedirectCallTest( + confirmBody, + req_data, + res_data, + true, + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle bank redirect redirection", () => { + // return_url is a static url (https://hyperswitch.io) taken from confirm-body fixture and is not updated + let expected_redirection = confirmBody["return_url"]; + let payment_method_type = globalState.get("paymentMethodType"); + cy.handleBankRedirectRedirection( + globalState, + payment_method_type, + expected_redirection + ); + }); + }); + + context("iDEAL Create and Confirm flow test", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_redirect_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "automatic", + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.task("cli_log", "PM CALL "); + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm bank redirect", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_redirect_pm" + ]["ideal"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); + cy.confirmBankRedirectCallTest( + confirmBody, + req_data, + res_data, + true, + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle bank redirect redirection", () => { + // return_url is a static url (https://hyperswitch.io) taken from confirm-body fixture and is not updated + let expected_redirection = confirmBody["return_url"]; + let payment_method_type = globalState.get("paymentMethodType"); + cy.handleBankRedirectRedirection( + globalState, + payment_method_type, + expected_redirection + ); + }); + }); + + context("Giropay Create and Confirm flow test", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_redirect_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "automatic", + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.task("cli_log", "PM CALL "); + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm bank redirect", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_redirect_pm" + ]["giropay"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); + cy.confirmBankRedirectCallTest( + confirmBody, + req_data, + res_data, + true, + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle bank redirect redirection", () => { + // return_url is a static url (https://hyperswitch.io) taken from confirm-body fixture and is not updated + let expected_redirection = confirmBody["return_url"]; + let payment_method_type = globalState.get("paymentMethodType"); + cy.handleBankRedirectRedirection( + globalState, + payment_method_type, + expected_redirection + ); + }); + }); + + context("Sofort Create and Confirm flow test", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_redirect_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "automatic", + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.task("cli_log", "PM CALL "); + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm bank redirect", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "bank_redirect_pm" + ]["sofort"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); + cy.confirmBankRedirectCallTest( + confirmBody, + req_data, + res_data, + true, + globalState + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle bank redirect redirection", () => { + // return_url is a static url (https://hyperswitch.io) taken from confirm-body fixture and is not updated + let expected_redirection = confirmBody["return_url"]; + let payment_method_type = globalState.get("paymentMethodType"); + cy.handleBankRedirectRedirection( + globalState, + payment_method_type, + expected_redirection + ); + }); + }); +}); diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/Adyen.js b/cypress-tests/cypress/e2e/ConnectorUtils/Adyen.js index 1bbbbbd4b5b5..19b6f342249a 100644 --- a/cypress-tests/cypress/e2e/ConnectorUtils/Adyen.js +++ b/cypress-tests/cypress/e2e/ConnectorUtils/Adyen.js @@ -1,382 +1,531 @@ +import { getCustomExchange } from "./Commons"; const successfulNo3DSCardDetails = { - "card_number": "371449635398431", - "card_exp_month": "03", - "card_exp_year": "30", - "card_holder_name": "John Doe", - "card_cvc": "7373" + card_number: "371449635398431", + card_exp_month: "03", + card_exp_year: "30", + card_holder_name: "John Doe", + card_cvc: "7373", }; const successfulThreeDSTestCardDetails = { - "card_number": "4917610000000000", - "card_exp_month": "03", - "card_exp_year": "30", - "card_holder_name": "Joseph Doe", - "card_cvc": "737" + card_number: "4917610000000000", + card_exp_month: "03", + card_exp_year: "30", + card_holder_name: "Joseph Doe", + card_cvc: "737", }; export const connectorDetails = { -card_pm:{ - "PaymentIntent": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_payment_method" - } - } + card_pm: { + PaymentIntent: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, }, "3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "processing" - } - } + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, }, "3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, }, - "No3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } + No3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, }, - "No3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } + No3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, }, - "Capture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body":{ - "status": "processing", - "amount": 6500, - "amount_capturable": 6500, - "amount_received": 0, - - } - } + Capture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + amount_received: 0, + }, + }, }, - "PartialCapture": { - "Request": { - }, - "Response": { - "status": 200, - "body": { - "status": "processing", - "amount": 6500, - "amount_capturable": 6500, - "amount_received": 0, - } - - } + PartialCapture: { + Request: {}, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + amount_received: 0, + }, + }, }, - "Void":{ - "Request": { - }, - "Response": { - "status": 200, - "body":{ - status: "processing" - - } - } + Void: { + Request: {}, + Response: { + status: 200, + body: { + status: "processing", + }, + }, }, - "Refund": { - "Request": { - - "currency": "USD", - - }, - "Response": { - "status": 400, - "body": { - "status": "pending", - } - - } + Refund: { + Request: { + currency: "USD", + }, + Response: { + status: 200, + body: { + status: "pending", + }, + status: 200, + body: { + status: "pending", + }, + }, }, - "PartialRefund": { - "Request": { - - "currency": "USD", - - }, - "Response": { - "status": 200, - "body": { - "status": "pending", - } - - } + PartialRefund: { + Request: { + currency: "USD", + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, }, - "SyncRefund": { - "Request": { - - "currency": "USD", - - }, - "Response": { - "status": 200, - "body": { - "status": "pending", - } - - } + SyncRefund: { + Request: { + currency: "USD", + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, }, - "MandateSingleUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - + MandateSingleUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, }, - "MandateSingleUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "requires_customer_action" - } - } - + MandateSingleUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, }, - "MandateSingleUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } + MandateSingleUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, }, - "MandateSingleUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "processing" - } - } + MandateSingleUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, }, - "MandateMultiUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } + MandateMultiUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, }, - "MandateMultiUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } + MandateMultiUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, }, - "MandateMultiUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } + MandateMultiUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + ZeroAuthMandate: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + }, + bank_transfer_pm: { + PaymentIntent: { + Request: { + currency: "BRL", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }, + Pix: { + Request: { + payment_method: "bank_transfer", + payment_method_type: "pix", + payment_method_data: { + bank_transfer: { + pix: {}, + }, + }, + currency: "BRL", + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, + }, + }, + bank_redirect_pm: { + PaymentIntent: getCustomExchange({ + Request: { + currency: "EUR", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }), + ideal: { + Request: { + payment_method: "bank_redirect", + payment_method_type: "ideal", + payment_method_data: { + bank_redirect: { + ideal: { + bank_name: "ing", + country: "NL", }, + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } + }, }, - "MandateMultiUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } + giropay: { + Request: { + payment_method: "bank_redirect", + payment_method_type: "giropay", + payment_method_data: { + bank_redirect: { + giropay: { + bank_name: "", + bank_account_bic: "", + bank_account_iban: "", + preferred_language: "en", + country: "DE", }, + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } + }, }, - "ZeroAuthMandate": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } + sofort: { + Request: { + payment_method: "bank_redirect", + payment_method_type: "sofort", + payment_method_data: { + bank_redirect: { + sofort: { + country: "DE", + preferred_language: "en", + }, + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, }, - "SaveCardUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } + eps: { + Request: { + payment_method: "bank_redirect", + payment_method_type: "eps", + payment_method_data: { + bank_redirect: { + eps: { + bank_name: "ing", }, + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } + }, }, - "SaveCardUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } + blik: { + Request: { + payment_method: "bank_redirect", + payment_method_type: "blik", + payment_method_data: { + bank_redirect: { + blik: { + name: "John Doe", + email: "example@email.com", + blik_code: "777987", }, + }, }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } + billing: { + address: { + line1: "1467", + line2: "Harrison Street", + line3: "Harrison Street", + city: "San Fransico", + state: "California", + zip: "94122", + country: "PL", + first_name: "john", + last_name: "doe", + }, + }, + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, }, -} -}; \ No newline at end of file + }, +}; diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/Commons.js b/cypress-tests/cypress/e2e/ConnectorUtils/Commons.js new file mode 100644 index 000000000000..9436f334068b --- /dev/null +++ b/cypress-tests/cypress/e2e/ConnectorUtils/Commons.js @@ -0,0 +1,507 @@ +// This file is the default. To override, add to connector.js +import State from "../../utils/State"; + +const globalState = new State({ + connectorId: Cypress.env("CONNECTOR"), + baseUrl: Cypress.env("BASEURL"), + adminApiKey: Cypress.env("ADMINAPIKEY"), + connectorAuthFilePath: Cypress.env("CONNECTOR_AUTH_FILE_PATH"), +}); + +const connectorId = globalState.get("connectorId"); + +const successfulNo3DSCardDetails = { + card_number: "4111111111111111", + card_exp_month: "08", + card_exp_year: "25", + card_holder_name: "joseph Doe", + card_cvc: "999", +}; + +const successfulThreeDSTestCardDetails = { + card_number: "4111111111111111", + card_exp_month: "10", + card_exp_year: "25", + card_holder_name: "morino", + card_cvc: "999", +}; + +/* +`getDefaultExchange` contains the default Request and Response to be considered if none provided. +`getCustomExchange` takes in 2 optional fields named as Request and Response. +with `getCustomExchange`, if 501 response is expected, there is no need to pass Response as it considers default values. +*/ + +// Const to get default PaymentExchange object +const getDefaultExchange = () => ({ + Request: { + currency: "EUR", + }, + Response: { + status: 501, + body: { + error: { + type: "invalid_request", + message: `Selected payment method through ${connectorId} is not implemented`, + code: "IR_00", + }, + }, + }, +}); + +// Const to get PaymentExchange with overridden properties +export const getCustomExchange = (overrides) => { + const defaultExchange = getDefaultExchange(); + + return { + ...defaultExchange, + Request: { + ...defaultExchange.Request, + ...(overrides.Request || {}), + }, + Response: { + ...defaultExchange.Response, + ...(overrides.Response || {}), + }, + }; +}; + +export const connectorDetails = { + card_pm: { + PaymentIntent: getCustomExchange({ + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }), + "3DSManualCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + "3DSAutoCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + No3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + No3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + Capture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + }, + }, + }, + PartialCapture: { + Request: {}, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + }, + }, + }, + Void: { + Request: {}, + Response: { + status: 400, + body: { + error: { + code: "IR_16", + message: + "You cannot cancel this payment because it has status processing", + type: "invalid_request", + }, + }, + }, + }, + Refund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: + "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", + code: "IR_14", + }, + }, + }, + }, + PartialRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: + "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", + code: "IR_14", + }, + }, + }, + }, + SyncRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: + "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", + code: "IR_14", + }, + }, + }, + }, + MandateSingleUse3DSAutoCapture: getCustomExchange({ + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + }), + MandateSingleUse3DSManualCapture: getCustomExchange({ + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + }), + MandateSingleUseNo3DSAutoCapture: getCustomExchange({ + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + }), + MandateSingleUseNo3DSManualCapture: getCustomExchange({ + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + }), + MandateMultiUseNo3DSAutoCapture: getCustomExchange({ + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + }), + MandateMultiUseNo3DSManualCapture: getCustomExchange({ + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + }), + MandateMultiUse3DSAutoCapture: getCustomExchange({ + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + }), + MandateMultiUse3DSManualCapture: getCustomExchange({ + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + }), + ZeroAuthMandate: getCustomExchange({ + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + }), + SaveCardUseNo3DSAutoCapture: getCustomExchange({ + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + }), + SaveCardUseNo3DSManualCapture: getCustomExchange({ + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + }), + }, + bank_transfer_pm: { + PaymentIntent: getCustomExchange({ + Request: { + currency: "BRL", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }), + Pix: getCustomExchange({ + Request: { + payment_method: "bank_transfer", + payment_method_type: "pix", + payment_method_data: { + bank_transfer: { + pix: {}, + }, + }, + currency: "BRL", + }, + }), + }, + bank_redirect_pm: { + PaymentIntent: getCustomExchange({ + Request: { + currency: "EUR", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }), + ideal: getCustomExchange({ + Request: { + payment_method: "bank_redirect", + payment_method_type: "ideal", + payment_method_data: { + bank_redirect: { + ideal: { + bank_name: "ing", + country: "NL", + }, + }, + }, + }, + }), + giropay: getCustomExchange({ + Request: { + payment_method: "bank_redirect", + payment_method_type: "giropay", + payment_method_data: { + bank_redirect: { + giropay: { + bank_name: "", + bank_account_bic: "", + bank_account_iban: "", + preferred_language: "en", + country: "DE", + }, + }, + }, + }, + }), + sofort: getCustomExchange({ + Request: { + payment_method: "bank_redirect", + payment_method_type: "sofort", + payment_method_data: { + bank_redirect: { + sofort: { + country: "DE", + preferred_language: "en", + }, + }, + }, + }, + }), + eps: getCustomExchange({ + Request: { + payment_method: "bank_redirect", + payment_method_type: "eps", + payment_method_data: { + bank_redirect: { + eps: { + bank_name: "ing", + }, + }, + }, + }, + }), + blikPaymentIntent: getCustomExchange({ + Request: { + currency: "PLN", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }), + blik: getCustomExchange({ + Request: { + payment_method: "bank_redirect", + payment_method_type: "blik", + payment_method_data: { + bank_redirect: { + blik: { + blik_code: "777987", + }, + }, + }, + billing: { + address: { + line1: "1467", + line2: "Harrison Street", + line3: "Harrison Street", + city: "San Fransico", + state: "California", + zip: "94122", + country: "PL", + first_name: "john", + last_name: "doe", + }, + }, + }, + }), + }, +}; diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/Trustpay.js b/cypress-tests/cypress/e2e/ConnectorUtils/Trustpay.js index 182d10857ece..d2a8b956b9d6 100644 --- a/cypress-tests/cypress/e2e/ConnectorUtils/Trustpay.js +++ b/cypress-tests/cypress/e2e/ConnectorUtils/Trustpay.js @@ -1,434 +1,560 @@ +import { getCustomExchange } from "./Commons"; + const successfulNo3DSCardDetails = { - "card_number": "4200000000000000", - "card_exp_month": "10", - "card_exp_year": "25", - "card_holder_name": "joseph Doe", - "card_cvc": "123" + card_number: "4200000000000000", + card_exp_month: "10", + card_exp_year: "25", + card_holder_name: "joseph Doe", + card_cvc: "123", }; const successfulThreeDSTestCardDetails = { - "card_number": "4200000000000067", - "card_exp_month": "03", - "card_exp_year": "2030", - "card_holder_name": "John Doe", - "card_cvc": "737", + card_number: "4200000000000067", + card_exp_month: "03", + card_exp_year: "2030", + card_holder_name: "John Doe", + card_cvc: "737", }; export const connectorDetails = { -card_pm:{ - "PaymentIntent": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_payment_method" - } - } - }, + card_pm: { + PaymentIntent: getCustomExchange({ + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }), "3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, }, "3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "manual is not supported by trustpay" - } - } - } + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "manual is not supported by trustpay", + }, + }, + }, }, - "No3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } + No3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, }, - "No3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "manual is not supported by trustpay" - } - } - } + No3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "manual is not supported by trustpay", + }, + }, + }, }, - "Capture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "This Payment could not be captured because it has a payment.status of requires_payment_method. The expected state is requires_capture, partially_captured_and_capturable, processing", - "code": "IR_14", - } - } - } + Capture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: + "This Payment could not be captured because it has a payment.status of requires_payment_method. The expected state is requires_capture, partially_captured_and_capturable, processing", + code: "IR_14", + }, + }, + }, }, - "PartialCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "paymentSuccessfulStatus": "succeeded", - "paymentSyncStatus": "succeeded", - "refundStatus": "succeeded", - "refundSyncStatus": "succeeded", - "customer_acceptance": null, - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "This Payment could not be captured because it has a payment.status of requires_payment_method. The expected state is requires_capture, partially_captured_and_capturable, processing", - "code": "IR_14", - } - } - } + PartialCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + paymentSuccessfulStatus: "succeeded", + paymentSyncStatus: "succeeded", + refundStatus: "succeeded", + refundSyncStatus: "succeeded", + customer_acceptance: null, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: + "This Payment could not be captured because it has a payment.status of requires_payment_method. The expected state is requires_capture, partially_captured_and_capturable, processing", + code: "IR_14", + }, + }, + }, }, - "Void":{ - "Request": { - }, - "Response": { - "status": 200, - "body":{ - status: "cancelled" - - } - } + Void: { + Request: {}, + Response: { + status: 200, + body: { + status: "cancelled", + }, + }, }, - "Refund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded", - } - - } + Refund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, }, - "PartialRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "error_code": "1", - "error_message": "transaction declined (invalid amount)", - } - - } + PartialRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + error_code: "1", + error_message: "transaction declined (invalid amount)", + }, + }, }, - "SyncRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded", - } - - } + SyncRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, }, - "MandateSingleUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - } - } - } - + MandateSingleUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + }, + }, + }, }, - "MandateSingleUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - } - } - } - + MandateSingleUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + }, + }, + }, }, - "MandateSingleUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - } - } - } + MandateSingleUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + }, + }, + }, }, - "MandateSingleUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - } - } - } + MandateSingleUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + }, + }, + }, }, - "MandateMultiUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - } - } - } + MandateMultiUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + }, + }, + }, }, - "MandateMultiUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - } - } - } + MandateMultiUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + }, + }, + }, }, - "MandateMultiUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } + MandateMultiUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateMultiUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + }, + }, + }, + }, + ZeroAuthMandate: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 501, + body: { + error: { + type: "invalid_request", + message: "Setup Mandate flow for Trustpay is not implemented", + code: "IR_00", + }, + }, + }, + }, + SaveCardUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + }, + }, + }, + }, + }, + bank_redirect_pm: { + PaymentIntent: getCustomExchange({ + Request: { + currency: "EUR", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }), + ideal: { + Request: { + payment_method: "bank_redirect", + payment_method_type: "ideal", + payment_method_data: { + bank_redirect: { + ideal: { + bank_name: "ing", + country: "NL", + }, + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, }, - "MandateMultiUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - } - } - } + giropay: { + Request: { + payment_method: "bank_redirect", + payment_method_type: "giropay", + payment_method_data: { + bank_redirect: { + giropay: { + bank_name: "", + bank_account_bic: "", + bank_account_iban: "", + preferred_language: "en", + country: "DE", + }, + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, }, - "ZeroAuthMandate": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 501, - "body": { - "error": { - "type": "invalid_request", - "message": "Setup Mandate flow for Trustpay is not implemented", - "code": "IR_00", - } - } - } + sofort: { + Request: { + payment_method: "bank_redirect", + payment_method_type: "sofort", + payment_method_data: { + bank_redirect: { + sofort: { + country: "DE", + preferred_language: "en", + }, + }, + }, + }, + Response: { + status: 200, + body: { + status: "failed", + error_code: "1133001", + }, + }, }, - "SaveCardUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } + eps: { + Request: { + payment_method: "bank_redirect", + payment_method_type: "eps", + payment_method_data: { + bank_redirect: { + eps: { + bank_name: "ing", }, + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } + }, }, - "SaveCardUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } + blik: { + Request: { + payment_method: "bank_redirect", + payment_method_type: "blik", + payment_method_data: { + bank_redirect: { + blik: { + name: "John Doe", + email: "example@email.com", }, + }, }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - } - } - } + billing: { + address: { + line1: "1467", + line2: "Harrison Street", + line3: "Harrison Street", + city: "San Fransico", + state: "California", + zip: "94122", + country: "PL", + first_name: "john", + last_name: "doe", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, }, -} -} \ No newline at end of file + }, +}; diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/utils.js b/cypress-tests/cypress/e2e/ConnectorUtils/utils.js index 960481a1252a..f14c68ce94c4 100644 --- a/cypress-tests/cypress/e2e/ConnectorUtils/utils.js +++ b/cypress-tests/cypress/e2e/ConnectorUtils/utils.js @@ -1,6 +1,7 @@ import { connectorDetails as adyenConnectorDetails } from "./Adyen.js"; import { connectorDetails as bankOfAmericaConnectorDetails } from "./BankOfAmerica.js"; import { connectorDetails as bluesnapConnectorDetails } from "./Bluesnap.js"; +import { connectorDetails as CommonConnectorDetails } from "./Commons.js"; import { connectorDetails as cybersourceConnectorDetails } from "./Cybersource.js"; import { connectorDetails as nmiConnectorDetails } from "./Nmi.js"; import { connectorDetails as paypalConnectorDetails } from "./Paypal.js"; @@ -8,28 +9,62 @@ import { connectorDetails as stripeConnectorDetails } from "./Stripe.js"; import { connectorDetails as trustpayConnectorDetails } from "./Trustpay.js"; const connectorDetails = { - "adyen": adyenConnectorDetails, - "bankofamerica": bankOfAmericaConnectorDetails, - "bluesnap": bluesnapConnectorDetails, - "cybersource": cybersourceConnectorDetails, - "nmi": nmiConnectorDetails, - "paypal": paypalConnectorDetails, - "stripe": stripeConnectorDetails, - "trustpay": trustpayConnectorDetails + adyen: adyenConnectorDetails, + bankofamerica: bankOfAmericaConnectorDetails, + bluesnap: bluesnapConnectorDetails, + commons: CommonConnectorDetails, + cybersource: cybersourceConnectorDetails, + nmi: nmiConnectorDetails, + paypal: paypalConnectorDetails, + stripe: stripeConnectorDetails, + trustpay: trustpayConnectorDetails, +}; +export default function getConnectorDetails(connectorId) { + let x = mergeDetails(connectorId); + return x; +} +function mergeDetails(connectorId) { + const connectorData = getValueByKey(connectorDetails, connectorId); + const fallbackData = getValueByKey(connectorDetails, "commons"); + // Merge data, prioritizing connectorData and filling missing data from fallbackData + const mergedDetails = mergeConnectorDetails(connectorData, fallbackData); + return mergedDetails; } +function mergeConnectorDetails(source, fallback) { + const merged = {}; -export default function getConnectorDetails(connectorId) { - let x = getValueByKey(connectorDetails, connectorId); - return x; + // Loop through each key in the source object + for (const key in source) { + merged[key] = { ...source[key] }; // Copy properties from source + + // Check if fallback has the same key and properties are missing in source + if (fallback[key]) { + for (const subKey in fallback[key]) { + if (!merged[key][subKey]) { + merged[key][subKey] = fallback[key][subKey]; + } + } + } + } + + // Add missing keys from fallback that are not present in source + for (const key in fallback) { + if (!merged[key]) { + merged[key] = fallback[key]; + } + } + + return merged; } function getValueByKey(jsonObject, key) { - const data = typeof jsonObject === 'string' ? JSON.parse(jsonObject) : jsonObject; + const data = + typeof jsonObject === "string" ? JSON.parse(jsonObject) : jsonObject; - if (data && typeof data === 'object' && key in data) { + if (data && typeof data === "object" && key in data) { return data[key]; } else { return null; @@ -37,10 +72,13 @@ function getValueByKey(jsonObject, key) { } export const should_continue_further = (res_data) => { - if(res_data.body.error !== undefined || res_data.body.error_code !== undefined || res_data.body.error_message !== undefined){ - return false; - } - else { - return true; + if ( + res_data.body.error !== undefined || + res_data.body.error_code !== undefined || + res_data.body.error_message !== undefined + ) { + return false; + } else { + return true; } -} \ No newline at end of file +}; diff --git a/cypress-tests/cypress/fixtures/confirm-body.json b/cypress-tests/cypress/fixtures/confirm-body.json index 32b9a7108be7..fbf23a2016b6 100644 --- a/cypress-tests/cypress/fixtures/confirm-body.json +++ b/cypress-tests/cypress/fixtures/confirm-body.json @@ -1,20 +1,9 @@ { "client_secret": "", "return_url": "https://hyperswitch.io", - "payment_method": "card", "confirm": true, - "payment_method_data": { - "card": { - "_comment": "these details are fetched from utils", - "card_number": "YourCardNumberHere", - "card_exp_month": "04", - "card_exp_year": "24", - "card_holder_name": "xyz", - "card_cvc": "424", - "card_issuer": "", - "card_network": "Visa" - } - }, + "payment_method": "card", + "payment_method_data": {}, "customer_acceptance": { "acceptance_type": "offline", "accepted_at": "1963-05-03T04:07:52.723Z", diff --git a/cypress-tests/cypress/fixtures/create-connector-body.json b/cypress-tests/cypress/fixtures/create-connector-body.json index d3575c0b2ccf..9ab253565ed7 100644 --- a/cypress-tests/cypress/fixtures/create-connector-body.json +++ b/cypress-tests/cypress/fixtures/create-connector-body.json @@ -52,6 +52,78 @@ "installment_payment_enabled": true } ] + }, + { + "payment_method": "bank_transfer", + "payment_method_types": [ + { + "payment_method_type": "pix", + "minimum_amount": 0, + "maximum_amount": 68607706, + "recurring_enabled": false, + "installment_payment_enabled": true + } + ] + }, + { + "payment_method": "bank_redirect", + "payment_method_types": [ + { + "payment_method_type": "ideal", + "payment_experience": null, + "card_networks": null, + "accepted_currencies": null, + "accepted_countries": null, + "minimum_amount": 1, + "maximum_amount": 68607706, + "recurring_enabled": true, + "installment_payment_enabled": true + }, + { + "payment_method_type": "giropay", + "payment_experience": null, + "card_networks": null, + "accepted_currencies": null, + "accepted_countries": null, + "minimum_amount": 1, + "maximum_amount": 68607706, + "recurring_enabled": true, + "installment_payment_enabled": true + }, + { + "payment_method_type": "sofort", + "payment_experience": null, + "card_networks": null, + "accepted_currencies": null, + "accepted_countries": null, + "minimum_amount": 1, + "maximum_amount": 68607706, + "recurring_enabled": true, + "installment_payment_enabled": true + }, + { + "payment_method_type": "eps", + "payment_experience": null, + "card_networks": null, + "accepted_currencies": null, + "accepted_countries": null, + "minimum_amount": 1, + "maximum_amount": 68607706, + "recurring_enabled": true, + "installment_payment_enabled": true + }, + { + "payment_method_type": "blik", + "payment_experience": null, + "card_networks": null, + "accepted_currencies": null, + "accepted_countries": null, + "minimum_amount": 1, + "maximum_amount": 68607706, + "recurring_enabled": true, + "installment_payment_enabled": true + } + ] } ], "metadata": { diff --git a/cypress-tests/cypress/support/commands.js b/cypress-tests/cypress/support/commands.js index e78802e366fe..4842ed017344 100644 --- a/cypress-tests/cypress/support/commands.js +++ b/cypress-tests/cypress/support/commands.js @@ -26,6 +26,7 @@ // commands.js or your custom support file import * as RequestBodyUtils from "../utils/RequestBodyUtils"; +import { handleRedirection } from "./redirectionHandler"; function logRequestId(xRequestId) { if (xRequestId) { @@ -35,6 +36,13 @@ function logRequestId(xRequestId) { } } +function defaultErrorHandler(response, response_data) { + expect(response.body).to.have.property("error"); + for (const key in response_data.body.error) { + expect(response_data.body.error[key]).to.equal(response.body.error[key]); + } +} + Cypress.Commands.add("merchantCreateCallTest", (merchantCreateBody, globalState) => { const randomMerchantId = RequestBodyUtils.generateRandomString(); RequestBodyUtils.setMerchantId(merchantCreateBody, randomMerchantId); @@ -171,10 +179,7 @@ Cypress.Commands.add("createPaymentIntentTest", (request, req_data, res_data, au expect(request.amount).to.equal(response.body.amount_capturable); } else { - expect(response.body).to.have.property("error"); - for(const key in res_data.body.error) { - expect(res_data.body.error[key]).to.equal(response.body.error[key]); - } + defaultErrorHandler(response, res_data); } }); }); @@ -219,7 +224,6 @@ Cypress.Commands.add("confirmCallTest", (confirmBody, req_data, res_data, confir body: confirmBody, }).then((response) => { logRequestId(response.headers['x-request-id']); - expect(res_data.status).to.equal(response.status); expect(response.headers["content-type"]).to.include("application/json"); if(response.status === 200){ @@ -227,15 +231,14 @@ Cypress.Commands.add("confirmCallTest", (confirmBody, req_data, res_data, confir if (response.body.capture_method === "automatic") { if (response.body.authentication_type === "three_ds") { expect(response.body).to.have.property("next_action") - .to.have.property("redirect_to_url"); + .to.have.property("redirect_to_url"); globalState.set("nextActionUrl", response.body.next_action.redirect_to_url); } else if (response.body.authentication_type === "no_three_ds") { for(const key in res_data.body) { expect(res_data.body[key]).to.equal(response.body[key]); } } else { - // Handle other authentication types as needed - throw new Error(`Unsupported authentication type: ${authentication_type}`); + defaultErrorHandler(response, res_data); } } else if (response.body.capture_method === "manual") { if (response.body.authentication_type === "three_ds") { @@ -244,24 +247,158 @@ Cypress.Commands.add("confirmCallTest", (confirmBody, req_data, res_data, confir globalState.set("nextActionUrl", response.body.next_action.redirect_to_url); } else if (response.body.authentication_type === "no_three_ds") { - for(const key in res_data.body) { + for (const key in res_data.body) { expect(res_data.body[key]).to.equal(response.body[key]); - } } else { - // Handle other authentication types as needed - throw new Error(`Unsupported authentication type: ${authentication_type}`); + } + } else { + defaultErrorHandler(response, res_data); } } } else { - expect(response.body).to.have.property("error"); - for(const key in res_data.body.error) { - expect(res_data.body.error[key]).to.equal(response.body.error[key]); - } + defaultErrorHandler(response, res_data); } - }); }); +Cypress.Commands.add( + "confirmBankRedirectCallTest", + (confirmBody, req_data, res_data, confirm, globalState) => { + const paymentIntentId = globalState.get("paymentID"); + const connectorId = globalState.get("connectorId"); + for (const key in req_data) { + confirmBody[key] = req_data[key]; + } + confirmBody.confirm = confirm; + confirmBody.client_secret = globalState.get("clientSecret"); + + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payments/${paymentIntentId}/confirm`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("publishableKey"), + }, + failOnStatusCode: false, + body: confirmBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + globalState.set("paymentID", paymentIntentId); + globalState.set("paymentMethodType", confirmBody.payment_method_type); + + switch (response.body.authentication_type) { + case "three_ds": + if ( + response.body.capture_method === "automatic" || + response.body.capture_method === "manual" + ) { + if (response.body.status !== "failed") { // we get many statuses here, hence this verification + if (connectorId === "adyen" && response.body.payment_method_type === "blik") { + expect(response.body) + .to.have.property("next_action") + .to.have.property("type") + .to.equal("wait_screen_information"); + } else { + expect(response.body) + .to.have.property("next_action") + .to.have.property("redirect_to_url"); + globalState.set( + "nextActionUrl", + response.body.next_action.redirect_to_url + ); + } + } else if (response.body.status === "failed") { + expect(response.body.error_code).to.equal(res_data.body.error_code); + } + } else { + defaultErrorHandler(response, res_data); + } + break; + case "no_three_ds": + if ( + response.body.capture_method === "automatic" || + response.body.capture_method === "manual" + ) { + expect(response.body) + .to.have.property("next_action") + .to.have.property("redirect_to_url"); + globalState.set( + "nextActionUrl", + response.body.next_action.redirect_to_url + ); + } else { + defaultErrorHandler(response, res_data); + } + break; + default: + defaultErrorHandler(response, res_data); + } + }); + } +); + +Cypress.Commands.add( + "confirmBankTransferCallTest", + (confirmBody, req_data, res_data, confirm, globalState) => { + const paymentIntentID = globalState.get("paymentID"); + for (const key in req_data) { + confirmBody[key] = req_data[key]; + } + confirmBody.confirm = confirm; + confirmBody.client_secret = globalState.get("clientSecret"); + globalState.set("paymentMethodType", confirmBody.payment_method_type); + + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payments/${paymentIntentID}/confirm`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("publishableKey"), + }, + failOnStatusCode: false, + body: confirmBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + globalState.set("paymentID", paymentIntentID); + if (response.status === 200) { + if ( + response.body.capture_method === "automatic" || + response.body.capture_method === "manual" + ) { + switch (response.body.payment_method_type) { + case "pix": + expect(response.body) + .to.have.property("next_action") + .to.have.property("qr_code_url"); + globalState.set( + "nextActionUrl", // This is intentionally kept as nextActionUrl to avoid issues during handleRedirection call, + response.body.next_action.qr_code_url + ); + break; + default: + expect(response.body) + .to.have.property("next_action") + .to.have.property("redirect_to_url"); + globalState.set( + "nextActionUrl", + response.body.next_action.redirect_to_url + ); + break; + } + } else { + defaultErrorHandler(response, res_data); + } + } else { + defaultErrorHandler(response, res_data); + } + }); + } +); + Cypress.Commands.add("createConfirmPaymentTest", (createConfirmPaymentBody, req_data, res_data, authentication_type, capture_method, globalState) => { createConfirmPaymentBody.payment_method_data.card = req_data.card; createConfirmPaymentBody.authentication_type = authentication_type; @@ -301,8 +438,7 @@ Cypress.Commands.add("createConfirmPaymentTest", (createConfirmPaymentBody, req_ expect(res_data.body[key]).to.equal(response.body[key]); } } else { - // Handle other authentication types as needed - throw new Error(`Unsupported authentication type: ${authentication_type}`); + defaultErrorHandler(response, res_data); } } else if (response.body.capture_method === "manual") { @@ -317,28 +453,24 @@ Cypress.Commands.add("createConfirmPaymentTest", (createConfirmPaymentBody, req_ else if (response.body.authentication_type === "no_three_ds") { for(const key in res_data.body) { expect(res_data.body[key]).to.equal(response.body[key]); - } } else { - // Handle other authentication types as needed - throw new Error(`Unsupported authentication type: ${authentication_type}`); + } + } else { + defaultErrorHandler(response, res_data); } } } else{ - expect(response.body).to.have.property("error"); - for(const key in res_data.body.error) { - expect(res_data.body.error[key]).to.equal(response.body.error[key]); - } + defaultErrorHandler(response, res_data); } }); }); // This is consequent saved card payment confirm call test(Using payment token) -Cypress.Commands.add("saveCardConfirmCallTest", (SaveCardConfirmBody, req_data, res_data,globalState) => { +Cypress.Commands.add("saveCardConfirmCallTest", (saveCardConfirmBody, req_data, res_data,globalState) => { const paymentIntentID = globalState.get("paymentID"); - SaveCardConfirmBody.card_cvc = req_data.card.card_cvc; - SaveCardConfirmBody.payment_token = globalState.get("paymentToken"); - SaveCardConfirmBody.client_secret = globalState.get("clientSecret"); - console.log("conf conn ->" + globalState.get("connectorId")); + saveCardConfirmBody.card_cvc = req_data.card.card_cvc; + saveCardConfirmBody.payment_token = globalState.get("paymentToken"); + saveCardConfirmBody.client_secret = globalState.get("clientSecret"); cy.request({ method: "POST", url: `${globalState.get("baseUrl")}/payments/${paymentIntentID}/confirm`, @@ -347,7 +479,7 @@ Cypress.Commands.add("saveCardConfirmCallTest", (SaveCardConfirmBody, req_data, "api-key": globalState.get("publishableKey"), }, failOnStatusCode: false, - body: SaveCardConfirmBody, + body: saveCardConfirmBody, }) .then((response) => { logRequestId(response.headers['x-request-id']); @@ -368,7 +500,7 @@ Cypress.Commands.add("saveCardConfirmCallTest", (SaveCardConfirmBody, req_data, expect(response.body.customer_id).to.equal(globalState.get("customerId")); } else { // Handle other authentication types as needed - throw new Error(`Unsupported authentication type: ${authentication_type}`); + defaultErrorHandler(response, res_data); } } else if (response.body.capture_method === "manual") { if (response.body.authentication_type === "three_ds") { @@ -378,18 +510,16 @@ Cypress.Commands.add("saveCardConfirmCallTest", (SaveCardConfirmBody, req_data, else if (response.body.authentication_type === "no_three_ds") { for(const key in res_data.body) { expect(res_data.body[key]).to.equal(response.body[key]); - } expect(response.body.customer_id).to.equal(globalState.get("customerId")); + } + expect(response.body.customer_id).to.equal(globalState.get("customerId")); } else { // Handle other authentication types as needed - throw new Error(`Unsupported authentication type: ${authentication_type}`); + defaultErrorHandler(response, res_data); } } } else { - expect(response.body).to.have.property("error"); - for(const key in res_data.body.error) { - expect(res_data.body.error[key]).to.equal(response.body.error[key]); - } + defaultErrorHandler(response, res_data); } }); }); @@ -419,12 +549,8 @@ Cypress.Commands.add("captureCallTest", (requestBody, req_data, res_data, amount } } else{ - expect(response.body).to.have.property("error"); - for(const key in res_data.body.error) { - expect(res_data.body.error[key]).to.equal(response.body.error[key]); - } + defaultErrorHandler(response, res_data); } - }); }); @@ -450,16 +576,12 @@ Cypress.Commands.add("voidCallTest", (requestBody, req_data, res_data, globalSta } } else{ - expect(response.body).to.have.property("error"); - for(const key in res_data.body.error) { - expect(res_data.body.error[key]).to.equal(response.body.error[key]); - } + defaultErrorHandler(response, res_data); } }); }); Cypress.Commands.add("retrievePaymentCallTest", (globalState) => { - console.log("syncpaymentID ->" + globalState.get("paymentID")); const payment_id = globalState.get("paymentID"); cy.request({ method: "GET", @@ -476,7 +598,6 @@ Cypress.Commands.add("retrievePaymentCallTest", (globalState) => { expect(response.body.payment_id).to.equal(payment_id); expect(response.body.amount).to.equal(globalState.get("paymentAmount")); globalState.set("paymentID", response.body.payment_id); - }); }); @@ -506,10 +627,7 @@ Cypress.Commands.add("refundCallTest", (requestBody, req_data, res_data, refund_ expect(response.body.payment_id).to.equal(payment_id); } else{ - expect(response.body).to.have.property("error"); - for(const key in res_data.body.error) { - expect(res_data.body.error[key]).to.equal(response.body.error[key]); - } + defaultErrorHandler(response, res_data); } }); @@ -591,10 +709,7 @@ Cypress.Commands.add("citForMandatesCallTest", (requestBody, req_data, res_data, } } else{ - expect(response.body).to.have.property("error"); - for(const key in res_data.body.error) { - expect(res_data.body.error[key]).to.equal(response.body.error[key]); - } + defaultErrorHandler(response, res_data); } }); }); @@ -606,7 +721,6 @@ Cypress.Commands.add("mitForMandatesCallTest", (requestBody, amount, confirm, ca requestBody.mandate_id = globalState.get("mandateId"); requestBody.customer_id = globalState.get("customerId"); globalState.set("paymentAmount", requestBody.amount); - console.log("mit body " + JSON.stringify(requestBody)); cy.request({ method: "POST", url: `${globalState.get("baseUrl")}/payments`, @@ -620,7 +734,6 @@ Cypress.Commands.add("mitForMandatesCallTest", (requestBody, amount, confirm, ca logRequestId(response.headers['x-request-id']); expect(response.headers["content-type"]).to.include("application/json"); globalState.set("paymentID", response.body.payment_id); - console.log("mit statusss-> " + response.body.status); if (response.body.capture_method === "automatic") { if (response.body.authentication_type === "three_ds") { expect(response.body).to.have.property("next_action") @@ -631,8 +744,7 @@ Cypress.Commands.add("mitForMandatesCallTest", (requestBody, amount, confirm, ca } else if (response.body.authentication_type === "no_three_ds") { expect(response.body.status).to.equal("succeeded"); } else { - // Handle other authentication types as needed - throw new Error(`Unsupported authentication type: ${authentication_type}`); + defaultErrorHandler(response, res_data); } } else if (response.body.capture_method === "manual") { @@ -645,8 +757,7 @@ Cypress.Commands.add("mitForMandatesCallTest", (requestBody, amount, confirm, ca } else if (response.body.authentication_type === "no_three_ds") { expect(response.body.status).to.equal("requires_capture"); } else { - // Handle other authentication types as needed - throw new Error(`Unsupported authentication type: ${authentication_type}`); + defaultErrorHandler(response, res_data); } } }); @@ -698,82 +809,53 @@ Cypress.Commands.add("revokeMandateCallTest", (globalState) => { }); }); - Cypress.Commands.add("handleRedirection", (globalState, expected_redirection) => { let connectorId = globalState.get("connectorId"); let expected_url = new URL(expected_redirection); let redirection_url = new URL(globalState.get("nextActionUrl")); - cy.visit(redirection_url.href); - if (globalState.get("connectorId") == "adyen") { - cy.get('iframe') - .its('0.contentDocument.body') - .within((body) => { - cy.get('input[type="password"]').click(); - cy.get('input[type="password"]').type("password"); - cy.get('#buttonSubmit').click(); - }) - } - else if (globalState.get("connectorId") === "cybersource" || globalState.get("connectorId") === "bankofamerica") { - cy.get('iframe', { timeout: 15000 }) - .its('0.contentDocument.body') - .within((body) => { - cy.get('input[type="text"]').click().type("1234"); - cy.get('input[value="SUBMIT"]').click(); - }) - } - else if (globalState.get("connectorId") === "nmi" || globalState.get("connectorId") === "noon") { - cy.get('iframe', { timeout: 150000 }) - .its('0.contentDocument.body') - .within((body) => { - cy.get('iframe', { timeout: 20000 }) - .its('0.contentDocument.body') - .within((body) => { - cy.get('form[name="cardholderInput"]', { timeout: 20000 }).should('exist').then(form => { - cy.get('input[name="challengeDataEntry"]').click().type("1234"); - cy.get('input[value="SUBMIT"]').click(); - }) - }) - }) - } - - else if (globalState.get("connectorId") === "stripe") { - cy.get('iframe', { timeout: 30000 }) - .its('0.contentDocument.body') - .within((body) => { - cy.get('iframe') - .its('0.contentDocument.body') - .within((body) => { - cy.get('#test-source-authorize-3ds').click(); - }) - }) - } - else if (globalState.get("connectorId") === "trustpay") { - cy.get('form[name="challengeForm"]', { timeout: 10000 }).should('exist').then(form => { - cy.get('#outcomeSelect').select('Approve').should('have.value', 'Y') - cy.get('button[type="submit"]').click(); - }) - } - + handleRedirection( + "three_ds", + { redirection_url, expected_url }, + connectorId, + null + ); +}); - else { - // If connectorId is neither of adyen, trustpay, nmi, stripe, bankofamerica or cybersource, wait for 10 seconds - cy.wait(10000); +Cypress.Commands.add( + "handleBankRedirectRedirection", + (globalState, payment_method_type, expected_redirection) => { + let connectorId = globalState.get("connectorId"); + let expected_url = new URL(expected_redirection); + let redirection_url = new URL(globalState.get("nextActionUrl")); + // explicitly restricting `sofort` payment method by adyen from running as it stops other tests from running + // trying to handle that specific case results in stripe 3ds tests to fail + if (!(connectorId == "adyen" && payment_method_type == "sofort")) { + handleRedirection( + "bank_redirect", + { redirection_url, expected_url }, + connectorId, + payment_method_type + ); + } } - - // Handling redirection - if (redirection_url.host.endsWith(expected_url.host)) { - // No CORS workaround needed - cy.window().its('location.origin').should('eq', expected_url.origin); - } else { - // Workaround for CORS to allow cross-origin iframe - cy.origin(expected_url.origin, { args: { expected_url: expected_url.origin } }, ({ expected_url }) => { - cy.window().its('location.origin').should('eq', expected_url); - }) +); + +Cypress.Commands.add( + "handleBankTransferRedirection", + (globalState, payment_method_type, expected_redirection) => { + let connectorId = globalState.get("connectorId"); + let redirection_url = new URL(globalState.get("nextActionUrl")); + cy.log(payment_method_type); + handleRedirection( + "bank_transfer", + { redirection_url, expected_redirection }, + connectorId, + payment_method_type + ); } -}); +); Cypress.Commands.add("listCustomerPMCallTest", (globalState) => { - console.log("customerID ->" + globalState.get("customerId")); const customerId = globalState.get("customerId"); cy.request({ method: "GET", @@ -792,7 +874,7 @@ Cypress.Commands.add("listCustomerPMCallTest", (globalState) => { expect(paymentToken).to.equal(globalState.get("paymentToken")); // Verify paymentToken } else { - throw new Error(`Payment token not found`); + defaultErrorHandler(response, res_data); } }); }); @@ -808,11 +890,7 @@ Cypress.Commands.add("listRefundCallTest", (requestBody, globalState) => { body: requestBody, }).then((response) => { logRequestId(response.headers['x-request-id']); - expect(response.headers["content-type"]).to.include("application/json"); expect(response.body.data).to.be.an('array').and.not.empty; - }); }); - - diff --git a/cypress-tests/cypress/support/redirectionhandler.js b/cypress-tests/cypress/support/redirectionhandler.js new file mode 100644 index 000000000000..6e4818581531 --- /dev/null +++ b/cypress-tests/cypress/support/redirectionhandler.js @@ -0,0 +1,319 @@ +import jsQR from "jsqr"; + +export function handleRedirection( + redirection_type, + urls, + connectorId, + payment_method_type +) { + switch (redirection_type) { + case "three_ds": + threeDsRedirection(urls.redirection_url, urls.expected_url, connectorId); + break; + case "bank_redirect": + bankRedirectRedirection( + urls.redirection_url, + urls.expected_url, + connectorId, + payment_method_type + ); + break; + case "bank_transfer": + bankTransferRedirection( + urls.redirection_url, + urls.expected_url, + connectorId, + payment_method_type + ); + break; + default: + throw new Error(`Redirection known: ${redirection_type}`); + } +} + +function bankTransferRedirection( + redirection_url, + expected_url, + connectorId, + payment_method_type +) { + cy.request(redirection_url.href).then((response) => { + switch (connectorId) { + case "adyen": + switch (payment_method_type) { + case "pix": + expect(response.status).to.eq(200); + fetchAndParseQRCode(redirection_url.href).then((qrCodeData) => { + expect(qrCodeData).to.eq("TestQRCodeEMVToken"); + }); + break; + default: + verifyReturnUrl(redirection_url, expected_url, true); + // expected_redirection can be used here to handle other payment methods + } + break; + default: + verifyReturnUrl(redirection_url, expected_url, true); + } + }); +} + +function threeDsRedirection(redirection_url, expected_url, connectorId) { + cy.visit(redirection_url.href); + if (connectorId == "adyen") { + cy.get("iframe") + .its("0.contentDocument.body") + .within((body) => { + cy.get('input[type="password"]').click(); + cy.get('input[type="password"]').type("password"); + cy.get("#buttonSubmit").click(); + }); + } else if (connectorId === "bankofamerica" || connectorId === "cybersource") { + cy.get("iframe", { timeout: 15000 }) + .its("0.contentDocument.body") + .within((body) => { + cy.get('input[type="text"]').click().type("1234"); + cy.get('input[value="SUBMIT"]').click(); + }); + } else if (connectorId === "nmi" || connectorId === "noon") { + cy.get("iframe", { timeout: 150000 }) + .its("0.contentDocument.body") + .within((body) => { + cy.get("iframe", { timeout: 20000 }) + .its("0.contentDocument.body") + .within((body) => { + cy.get('form[name="cardholderInput"]', { timeout: 20000 }) + .should("exist") + .then((form) => { + cy.get('input[name="challengeDataEntry"]').click().type("1234"); + cy.get('input[value="SUBMIT"]').click(); + }); + }); + }); + } else if (connectorId === "stripe") { + cy.get("iframe", { timeout: 15000 }) + .its("0.contentDocument.body") + .within((body) => { + cy.get("iframe") + .its("0.contentDocument.body") + .within((body) => { + cy.get("#test-source-authorize-3ds").click(); + }); + }); + } else if (connectorId === "trustpay") { + cy.get('form[name="challengeForm"]', { timeout: 10000 }) + .should("exist") + .then((form) => { + cy.get("#outcomeSelect").select("Approve").should("have.value", "Y"); + cy.get('button[type="submit"]').click(); + }); + } else { + // If connectorId is neither of adyen, trustpay, nmi, stripe, bankofamerica or cybersource, wait for 10 seconds + cy.wait(10000); + } + + verifyReturnUrl(redirection_url, expected_url, true); +} + +function bankRedirectRedirection( + redirection_url, + expected_url, + connectorId, + payment_method_type +) { + let verifyUrl = false; + cy.visit(redirection_url.href); + + switch (connectorId) { + case "adyen": + switch (payment_method_type) { + case "eps": + cy.get("h1").should("contain.text", "Acquirer Simulator"); + cy.get('[value="authorised"]').click(); + cy.url().should("include", "status=succeeded"); + cy.wait(5000); + break; + case "ideal": + cy.get(":nth-child(4) > td > p").should( + "contain.text", + "Your Payment was Authorised/Refused/Cancelled (It may take up to five minutes to show on the Payment List)" + ); + cy.get(".btnLink").click(); + cy.url().should("include", "status=succeeded"); + cy.wait(5000); + break; + case "giropay": + cy.get( + ".rds-cookies-overlay__allow-all-cookies-btn > .rds-button" + ).click(); + cy.wait(5000); + cy.get(".normal-3").should( + "contain.text", + "Bank suchen ‑ mit giropay zahlen." + ); + cy.get("#bankSearch").type("giropay TestBank{enter}"); + cy.get(".normal-2 > div").click(); + cy.get('[data-testid="customerIban"]').type("DE48499999601234567890"); + cy.get('[data-testid="customerIdentification"]').type("1234567890"); + cy.get(":nth-child(3) > .rds-button").click(); + cy.get('[data-testid="onlineBankingPin"]').type("1234"); + cy.get(".rds-button--primary").click(); + cy.get(":nth-child(5) > .rds-radio-input-group__label").click(); + cy.get(".rds-button--primary").click(); + cy.get('[data-testid="photoTan"]').type("123456"); + cy.get(".rds-button--primary").click(); + cy.wait(5000); + cy.url().should("include", "status=succeeded"); + cy.wait(5000); + break; + case "sofort": + cy.get(".modal-overlay.modal-shown.in", { timeout: 5000 }).then( + ($modal) => { + // If modal is found, handle it + if ($modal.length > 0) { + cy.get("button.cookie-modal-deny-all.button-tertiary") + .should("be.visible") + .should("contain", "Reject All") + .click({ force: true, multiple: true }); + cy.get("div#TopBanks.top-banks-multistep") + .should("contain", "Demo Bank") + .as("btn") + .click(); + cy.get("@btn").click(); + } else { + cy.get("input.phone").type("9123456789"); + cy.get("#button.onContinue") + .should("contain", "Continue") + .click(); + } + } + ); + break; + case "trustly": + break; + default: + throw new Error( + `Unsupported payment method type: ${payment_method_type}` + ); + } + verifyUrl = true; + break; + case "trustpay": + switch (payment_method_type) { + case "eps": + cy.get("._transactionId__header__iXVd_").should( + "contain.text", + "Bank suchen ‑ mit eps zahlen." + ); + cy.get(".BankSearch_searchInput__uX_9l").type( + "Allgemeine Sparkasse Oberösterreich Bank AG{enter}" + ); + cy.get(".BankSearch_searchResultItem__lbcKm").click(); + cy.get("._transactionId__primaryButton__nCa0r").click(); + cy.get("#loginTitle").should( + "contain.text", + "eps Online-Ãœberweisung Login" + ); + cy.get("#user") + .should("be.visible") + .should("be.enabled") + .focus() + .type("Verfügernummer"); + cy.get("input#submitButton.btn.btn-primary").click(); + break; + case "ideal": + cy.get("p").should( + "contain.text", + "Choose your iDeal Issuer Bank please" + ); + cy.get("#issuerSearchInput").click(); + cy.get("#issuerSearchInput").type("ING{enter}"); + cy.get("#trustpay__selectIssuer_submit").click(); + break; + case "giropay": + cy.get("._transactionId__header__iXVd_").should( + "contain.text", + "Bank suchen ‑ mit giropay zahlen." + ); + cy.get(".BankSearch_searchInput__uX_9l").type( + "Volksbank Hildesheim{enter}" + ); + cy.get(".BankSearch_searchIcon__EcVO7").click(); + cy.get(".BankSearch_bankWrapper__R5fUK").click(); + cy.get("._transactionId__primaryButton__nCa0r").click(); + cy.get(".normal-3").should("contain.text", "Kontoauswahl"); + break; + case "sofort": + break; + case "trustly": + break; + default: + throw new Error( + `Unsupported payment method type: ${payment_method_type}` + ); + } + verifyUrl = false; + break; + default: + throw new Error(`Unsupported connector: ${connectorId}`); + } + verifyReturnUrl(redirection_url, expected_url, verifyUrl); +} + +function verifyReturnUrl(redirection_url, expected_url, forward_flow) { + if (forward_flow) { + // Handling redirection + if (redirection_url.host.endsWith(expected_url.host)) { + // No CORS workaround needed + cy.window().its("location.origin").should("eq", expected_url.origin); + } else { + // Workaround for CORS to allow cross-origin iframe + cy.origin( + expected_url.origin, + { args: { expected_url: expected_url.origin } }, + ({ expected_url }) => { + cy.window().its("location.origin").should("eq", expected_url); + } + ); + } + } +} + +async function fetchAndParseQRCode(url) { + const response = await fetch(url, { encoding: "binary" }); + if (!response.ok) { + throw new Error(`Failed to fetch QR code image: ${response.statusText}`); + } + const blob = await response.blob(); + const reader = new FileReader(); + return await new Promise((resolve, reject) => { + reader.onload = () => { + const base64Image = reader.result.split(",")[1]; // Remove data URI prefix + const image = new Image(); + image.src = base64Image; + + image.onload = () => { + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d"); + canvas.width = image.width; + canvas.height = image.height; + ctx.drawImage(image, 0, 0); + + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + const qrCodeData = jsQR( + imageData.data, + imageData.width, + imageData.height + ); + + if (qrCodeData) { + resolve(qrCodeData.data); + } else { + reject(new Error("Failed to decode QR code")); + } + }; + image.onerror = reject; // Handle image loading errors + }; + reader.readAsDataURL(blob); + }); +} diff --git a/cypress-tests/package.json b/cypress-tests/package.json index fff8cd8b3f17..af4b0244fbd5 100644 --- a/cypress-tests/package.json +++ b/cypress-tests/package.json @@ -9,5 +9,8 @@ "cypress:ci": "npx cypress run --headless" }, "author": "", - "license": "ISC" + "license": "ISC", + "dependencies": { + "jsqr": "^1.4.0" + } } From 5cb84f66e4c59f6ffbd12bf4e91ab0152ac1c2c5 Mon Sep 17 00:00:00 2001 From: Narayan Bhat <48803246+Narayanbhat166@users.noreply.github.com> Date: Fri, 31 May 2024 16:38:52 +0530 Subject: [PATCH 03/25] refactor(first_name): check if first_name is sent as empty string (#4832) --- crates/api_models/src/payments.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 30329e132b83..f4e49058c9b2 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -2904,7 +2904,11 @@ impl AddressDetails { pub fn unify_address_details(self, other: Option<&Self>) -> Self { if let Some(other) = other { - let (first_name, last_name) = if self.first_name.is_some() { + let (first_name, last_name) = if self + .first_name + .as_ref() + .is_some_and(|first_name| !first_name.is_empty_after_trim()) + { (self.first_name, self.last_name) } else { (other.first_name.clone(), other.last_name.clone()) From f74b9b622e5565a00bf9ee8223c64a3def37b776 Mon Sep 17 00:00:00 2001 From: Prajjwal Kumar Date: Fri, 31 May 2024 18:31:50 +0530 Subject: [PATCH 04/25] Refactor(core): Reverts Inclusion of constraint graph for merchant Payment Method list (#4839) --- crates/euclid/src/enums.rs | 2 - crates/router/src/core/payment_methods.rs | 1 - .../router/src/core/payment_methods/cards.rs | 684 ++++++++++----- .../router/src/core/payment_methods/utils.rs | 828 ------------------ .../src/db/merchant_connector_account.rs | 6 - crates/storage_impl/src/redis/cache.rs | 12 - crates/storage_impl/src/redis/pub_sub.rs | 9 +- 7 files changed, 458 insertions(+), 1084 deletions(-) delete mode 100644 crates/router/src/core/payment_methods/utils.rs diff --git a/crates/euclid/src/enums.rs b/crates/euclid/src/enums.rs index 8e65d23d5ea9..1aba6338d9d2 100644 --- a/crates/euclid/src/enums.rs +++ b/crates/euclid/src/enums.rs @@ -79,8 +79,6 @@ pub enum MandateAcceptanceType { pub enum PaymentType { SetupMandate, NonMandate, - NewMandate, - UpdateMandate, } #[derive( diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 4b4eb34b7e2d..71f0bdac03a9 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -1,7 +1,6 @@ pub mod cards; pub mod surcharge_decision_configs; pub mod transformers; -pub mod utils; pub mod vault; pub use api_models::enums::Connector; diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 02e29f24a672..66a695b2b0c5 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -5,7 +5,7 @@ use std::{ }; use api_models::{ - admin::PaymentMethodsEnabled, + admin::{self, PaymentMethodsEnabled}, enums::{self as api_enums}, payment_methods::{ BankAccountTokenData, Card, CardDetailUpdate, CardDetailsPaymentMethod, CardNetworkTypes, @@ -19,22 +19,18 @@ use api_models::{ pm_auth::PaymentMethodAuthConfig, surcharge_decision_configs as api_surcharge_decision_configs, }; -use cgraph::ConstraintGraph; use common_enums::enums::MerchantStorageScheme; use common_utils::{ consts, ext_traits::{AsyncExt, Encode, StringExt, ValueExt}, generate_id, id_type, }; -use diesel_models::{business_profile::BusinessProfile, encryption::Encryption, payment_method}; +use diesel_models::{ + business_profile::BusinessProfile, encryption::Encryption, enums as storage_enums, + payment_method, +}; use domain::CustomerUpdate; use error_stack::{report, ResultExt}; -use euclid::{ - dssa::graph::{AnalysisContext, CgraphExt}, - frontend::dir, -}; -use hyperswitch_constraint_graph as cgraph; -use kgraph_utils::transformers::IntoDirValue; use masking::Secret; use router_env::{instrument, tracing}; use strum::IntoEnumIterator; @@ -49,11 +45,7 @@ use crate::{ configs::settings, core::{ errors::{self, StorageErrorExt}, - payment_methods::{ - transformers as payment_methods, - utils::{get_merchant_pm_filter_graph, make_pm_graph, refresh_pm_filters_cache}, - vault, - }, + payment_methods::{transformers as payment_methods, vault}, payments::{ helpers, routing::{self, SessionFlowRoutingInput}, @@ -1885,94 +1877,31 @@ pub async fn list_payment_methods( .await?; // filter out connectors based on the business country - let filtered_mcas = - helpers::filter_mca_based_on_business_profile(all_mcas.clone(), profile_id.clone()); + let filtered_mcas = helpers::filter_mca_based_on_business_profile(all_mcas, profile_id); logger::debug!(mca_before_filtering=?filtered_mcas); let mut response: Vec = vec![]; + for mca in &filtered_mcas { + let payment_methods = match &mca.payment_methods_enabled { + Some(pm) => pm.clone(), + None => continue, + }; - // Key creation for storing PM_FILTER_CGRAPH - #[cfg(feature = "business_profile_routing")] - let key = { - let profile_id = profile_id - .clone() - .get_required_value("profile_id") - .change_context(errors::ApiErrorResponse::GenericNotFoundError { - message: "Profile id not found".to_string(), - })?; - format!( - "pm_filters_cgraph_{}_{}", - &merchant_account.merchant_id, profile_id + filter_payment_methods( + payment_methods, + &mut req, + &mut response, + payment_intent.as_ref(), + payment_attempt.as_ref(), + billing_address.as_ref(), + mca.connector_name.clone(), + pm_config_mapping, + &state.conf.mandates.supported_payment_methods, + &state.conf.mandates.update_mandate_supported, + &state.conf.saved_payment_methods, ) - }; - - #[cfg(not(feature = "business_profile_routing"))] - let key = { format!("pm_filters_cgraph_{}", &merchant_account.merchant_id) }; - - if let Some(graph) = get_merchant_pm_filter_graph(&key).await { - // Derivation of PM_FILTER_CGRAPH from MokaCache successful - for mca in &filtered_mcas { - let payment_methods = match &mca.payment_methods_enabled { - Some(pm) => pm, - None => continue, - }; - filter_payment_methods( - &graph, - payment_methods, - &mut req, - &mut response, - payment_intent.as_ref(), - payment_attempt.as_ref(), - billing_address.as_ref(), - mca.connector_name.clone(), - &state.conf.saved_payment_methods, - ) - .await?; - } - } else { - // No PM_FILTER_CGRAPH Cache present in MokaCache - let mut builder = cgraph::ConstraintGraphBuilder::<'static, _>::new(); - for mca in &filtered_mcas { - let payment_methods = match &mca.payment_methods_enabled { - Some(pm) => pm, - None => continue, - }; - if let Err(e) = make_pm_graph( - &mut builder, - payment_methods, - mca.connector_name.clone(), - pm_config_mapping, - &state.conf.mandates.supported_payment_methods, - &state.conf.mandates.update_mandate_supported, - ) { - logger::error!( - "Failed to construct constraint graph for list payment methods {e:?}" - ); - } - } - - // Refreshing our CGraph cache - let graph = refresh_pm_filters_cache(&key, builder.build()).await; - - for mca in &filtered_mcas { - let payment_methods = match &mca.payment_methods_enabled { - Some(pm) => pm, - None => continue, - }; - filter_payment_methods( - &graph, - payment_methods, - &mut req, - &mut response, - payment_intent.as_ref(), - payment_attempt.as_ref(), - billing_address.as_ref(), - mca.connector_name.clone(), - &state.conf.saved_payment_methods, - ) - .await?; - } + .await?; } // Filter out wallet payment method from mca if customer has already saved it @@ -2829,18 +2758,20 @@ pub async fn call_surcharge_decision_management_for_saved_card( #[allow(clippy::too_many_arguments)] pub async fn filter_payment_methods( - graph: &ConstraintGraph<'_, dir::DirValue>, - payment_methods: &[serde_json::Value], + payment_methods: Vec, req: &mut api::PaymentMethodListRequest, resp: &mut Vec, payment_intent: Option<&storage::PaymentIntent>, payment_attempt: Option<&storage::PaymentAttempt>, address: Option<&domain::Address>, connector: String, + config: &settings::ConnectorFilters, + supported_payment_methods_for_mandate: &settings::SupportedPaymentMethodsForMandate, + supported_payment_methods_for_update_mandate: &settings::SupportedPaymentMethodsForMandate, saved_payment_methods: &settings::EligiblePaymentMethods, ) -> errors::CustomResult<(), errors::ApiErrorResponse> { - for payment_method in payment_methods.iter() { - let parse_result = serde_json::from_value::(payment_method.clone()); + for payment_method in payment_methods.into_iter() { + let parse_result = serde_json::from_value::(payment_method); if let Ok(payment_methods_enabled) = parse_result { let payment_method = payment_methods_enabled.payment_method; @@ -2871,13 +2802,57 @@ pub async fn filter_payment_methods( .map(|minor_amount| minor_amount.get_amount_as_i64()), ) { - let payment_method_object = payment_method_type_info.clone(); + let mut payment_method_object = payment_method_type_info; + + let filter; + ( + payment_method_object.accepted_countries, + req.accepted_countries, + filter, + ) = filter_pm_country_based( + &payment_method_object.accepted_countries, + &req.accepted_countries, + ); + let filter2; + ( + payment_method_object.accepted_currencies, + req.accepted_currencies, + filter2, + ) = filter_pm_currencies_based( + &payment_method_object.accepted_currencies, + &req.accepted_currencies, + ); - let pm_dir_value: dir::DirValue = - (payment_method_type_info.payment_method_type, payment_method) - .into_dir_value() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("pm_value_node not created")?; + let filter4 = filter_pm_card_network_based( + payment_method_object.card_networks.as_ref(), + req.card_networks.as_ref(), + &payment_method_object.payment_method_type, + ); + + let filter3 = if let Some(payment_intent) = payment_intent { + filter_payment_country_based(&payment_method_object, address).await? + && filter_payment_currency_based(payment_intent, &payment_method_object) + && filter_payment_amount_based(payment_intent, &payment_method_object) + && filter_payment_mandate_based(payment_attempt, &payment_method_object) + .await? + } else { + true + }; + + let filter5 = filter_pm_based_on_config( + config, + &connector, + &payment_method_object.payment_method_type, + payment_attempt, + &mut payment_method_object.card_networks, + &address.and_then(|inner| inner.country), + payment_attempt.and_then(|value| value.currency), + ); + + let filter6 = filter_pm_based_on_allowed_types( + allowed_payment_method_types.as_ref(), + &payment_method_object.payment_method_type, + ); let connector_variant = api_enums::Connector::from_str(connector.as_str()) .change_context(errors::ConnectorError::InvalidConnectorName) @@ -2887,98 +2862,35 @@ pub async fn filter_payment_methods( .attach_printable_lazy(|| { format!("unable to parse connector name {connector:?}") })?; - - let mut context_values: Vec = Vec::new(); - context_values.push(pm_dir_value.clone()); - - payment_intent.map(|intent| { - intent.currency.map(|currency| { - context_values.push(dir::DirValue::PaymentCurrency(currency)) - }) - }); - address.map(|address| { - address.country.map(|country| { - context_values.push(dir::DirValue::BillingCountry( - common_enums::Country::from_alpha2(country), - )) - }) - }); - - let filter_pm_based_on_allowed_types = filter_pm_based_on_allowed_types( - allowed_payment_method_types.as_ref(), - &payment_method_object.payment_method_type, - ); - - if payment_attempt + let filter7 = payment_attempt .and_then(|attempt| attempt.mandate_details.as_ref()) - .is_some() - { - context_values.push(dir::DirValue::PaymentType( - euclid::enums::PaymentType::NewMandate, - )); - if let Ok(connector) = api_enums::RoutableConnectors::from_str( - connector_variant.to_string().as_str(), - ) { - context_values.push(dir::DirValue::Connector(Box::new( - api_models::routing::ast::ConnectorChoice { - connector, - #[cfg(not(feature = "connector_choice_mca_id"))] - sub_label: None, - }, - ))); - }; - }; + .map(|_mandate_details| { + filter_pm_based_on_supported_payments_for_mandate( + supported_payment_methods_for_mandate, + &payment_method, + &payment_method_object.payment_method_type, + connector_variant, + ) + }) + .unwrap_or(true); - payment_attempt + let filter8 = payment_attempt .and_then(|attempt| attempt.mandate_data.as_ref()) .map(|mandate_detail| { if mandate_detail.update_mandate_id.is_some() { - context_values.push(dir::DirValue::PaymentType( - euclid::enums::PaymentType::UpdateMandate, - )); - if let Ok(connector) = api_enums::RoutableConnectors::from_str( - connector_variant.to_string().as_str(), - ) { - context_values.push(dir::DirValue::Connector(Box::new( - api_models::routing::ast::ConnectorChoice { - connector, - #[cfg(not(feature = "connector_choice_mca_id"))] - sub_label: None, - }, - ))); - }; + filter_pm_based_on_update_mandate_support_for_connector( + supported_payment_methods_for_update_mandate, + &payment_method, + &payment_method_object.payment_method_type, + connector_variant, + ) + } else { + true } - }); - - payment_attempt - .map(|attempt| { - attempt.mandate_data.is_none() && attempt.mandate_details.is_none() }) - .and_then(|res| { - res.then(|| { - context_values.push(dir::DirValue::PaymentType( - euclid::enums::PaymentType::NonMandate, - )) - }) - }); - - payment_attempt - .and_then(|inner| inner.capture_method) - .and_then(|capture_method| { - (capture_method == common_enums::CaptureMethod::Manual).then(|| { - context_values.push(dir::DirValue::CaptureMethod( - common_enums::CaptureMethod::Manual, - )); - }) - }); - - let filter_pm_card_network_based = filter_pm_card_network_based( - payment_method_object.card_networks.as_ref(), - req.card_networks.as_ref(), - &payment_method_object.payment_method_type, - ); + .unwrap_or(true); - let saved_payment_methods_filter = req + let filter9 = req .client_secret .as_ref() .map(|cs| { @@ -2992,28 +2904,25 @@ pub async fn filter_payment_methods( }) .unwrap_or(true); - let context = AnalysisContext::from_dir_values(context_values.clone()); + let connector = connector.clone(); - let result = graph.key_value_analysis( - pm_dir_value.clone(), - &context, - &mut cgraph::Memoization::new(), - &mut cgraph::CycleCheck::new(), - None, + let response_pm_type = ResponsePaymentMethodIntermediate::new( + payment_method_object, + connector, + payment_method, ); - if filter_pm_based_on_allowed_types - && filter_pm_card_network_based - && saved_payment_methods_filter - && matches!(result, Ok(())) + + if filter + && filter2 + && filter3 + && filter4 + && filter5 + && filter6 + && filter7 + && filter8 + && filter9 { - let response_pm_type = ResponsePaymentMethodIntermediate::new( - payment_method_object, - connector.clone(), - payment_method, - ); resp.push(response_pm_type); - } else { - logger::error!("Filtering Payment Methods Failed"); } } } @@ -3021,12 +2930,287 @@ pub async fn filter_payment_methods( } Ok(()) } +pub fn filter_pm_based_on_update_mandate_support_for_connector( + supported_payment_methods_for_mandate: &settings::SupportedPaymentMethodsForMandate, + payment_method: &api_enums::PaymentMethod, + payment_method_type: &api_enums::PaymentMethodType, + connector: api_enums::Connector, +) -> bool { + if payment_method == &api_enums::PaymentMethod::Card { + supported_payment_methods_for_mandate + .0 + .get(payment_method) + .map(|payment_method_type_hm| { + let pm_credit = payment_method_type_hm + .0 + .get(&api_enums::PaymentMethodType::Credit) + .map(|conn| conn.connector_list.clone()) + .unwrap_or_default(); + let pm_debit = payment_method_type_hm + .0 + .get(&api_enums::PaymentMethodType::Debit) + .map(|conn| conn.connector_list.clone()) + .unwrap_or_default(); + &pm_credit | &pm_debit + }) + .map(|supported_connectors| supported_connectors.contains(&connector)) + .unwrap_or(false) + } else { + supported_payment_methods_for_mandate + .0 + .get(payment_method) + .and_then(|payment_method_type_hm| payment_method_type_hm.0.get(payment_method_type)) + .map(|supported_connectors| supported_connectors.connector_list.contains(&connector)) + .unwrap_or(false) + } +} -fn filter_pm_based_on_allowed_types( - allowed_types: Option<&Vec>, +fn filter_pm_based_on_supported_payments_for_mandate( + supported_payment_methods_for_mandate: &settings::SupportedPaymentMethodsForMandate, + payment_method: &api_enums::PaymentMethod, payment_method_type: &api_enums::PaymentMethodType, + connector: api_enums::Connector, ) -> bool { - allowed_types.map_or(true, |pm| pm.contains(payment_method_type)) + supported_payment_methods_for_mandate + .0 + .get(payment_method) + .and_then(|payment_method_type_hm| payment_method_type_hm.0.get(payment_method_type)) + .map(|supported_connectors| supported_connectors.connector_list.contains(&connector)) + .unwrap_or(false) +} + +fn filter_pm_based_on_config<'a>( + config: &'a settings::ConnectorFilters, + connector: &'a str, + payment_method_type: &'a api_enums::PaymentMethodType, + payment_attempt: Option<&storage::PaymentAttempt>, + card_network: &mut Option>, + country: &Option, + currency: Option, +) -> bool { + config + .0 + .get(connector) + .or_else(|| config.0.get("default")) + .and_then(|inner| match payment_method_type { + api_enums::PaymentMethodType::Credit | api_enums::PaymentMethodType::Debit => { + let country_currency_filter = inner + .0 + .get(&settings::PaymentMethodFilterKey::PaymentMethodType( + *payment_method_type, + )) + .map(|value| global_country_currency_filter(value, country, currency)); + + card_network_filter(country, currency, card_network, inner); + + let capture_method_filter = payment_attempt + .and_then(|inner| inner.capture_method) + .and_then(|capture_method| { + (capture_method == storage_enums::CaptureMethod::Manual).then(|| { + filter_pm_based_on_capture_method_used(inner, payment_method_type) + }) + }); + + Some( + country_currency_filter.unwrap_or(true) + && capture_method_filter.unwrap_or(true), + ) + } + payment_method_type => inner + .0 + .get(&settings::PaymentMethodFilterKey::PaymentMethodType( + *payment_method_type, + )) + .map(|value| global_country_currency_filter(value, country, currency)), + }) + .unwrap_or(true) +} + +///Filters the payment method list on basis of Capture methods, checks whether the connector issues Manual payments using cards or not if not it won't be visible in payment methods list +fn filter_pm_based_on_capture_method_used( + payment_method_filters: &settings::PaymentMethodFilters, + payment_method_type: &api_enums::PaymentMethodType, +) -> bool { + payment_method_filters + .0 + .get(&settings::PaymentMethodFilterKey::PaymentMethodType( + *payment_method_type, + )) + .and_then(|v| v.not_available_flows) + .and_then(|v| v.capture_method) + .map(|v| !matches!(v, api_enums::CaptureMethod::Manual)) + .unwrap_or(true) +} + +fn card_network_filter( + country: &Option, + currency: Option, + card_network: &mut Option>, + payment_method_filters: &settings::PaymentMethodFilters, +) { + if let Some(value) = card_network.as_mut() { + let filtered_card_networks = value + .iter() + .filter(|&element| { + let key = settings::PaymentMethodFilterKey::CardNetwork(element.clone()); + payment_method_filters + .0 + .get(&key) + .map(|value| global_country_currency_filter(value, country, currency)) + .unwrap_or(true) + }) + .cloned() + .collect::>(); + *value = filtered_card_networks; + } +} + +fn global_country_currency_filter( + item: &settings::CurrencyCountryFlowFilter, + country: &Option, + currency: Option, +) -> bool { + let country_condition = item + .country + .as_ref() + .zip(country.as_ref()) + .map(|(lhs, rhs)| lhs.contains(rhs)); + let currency_condition = item + .currency + .as_ref() + .zip(currency) + .map(|(lhs, rhs)| lhs.contains(&rhs)); + country_condition.unwrap_or(true) && currency_condition.unwrap_or(true) +} + +fn filter_pm_card_network_based( + pm_card_networks: Option<&Vec>, + request_card_networks: Option<&Vec>, + pm_type: &api_enums::PaymentMethodType, +) -> bool { + match pm_type { + api_enums::PaymentMethodType::Credit | api_enums::PaymentMethodType::Debit => { + match (pm_card_networks, request_card_networks) { + (Some(pm_card_networks), Some(request_card_networks)) => request_card_networks + .iter() + .all(|card_network| pm_card_networks.contains(card_network)), + (None, Some(_)) => false, + _ => true, + } + } + _ => true, + } +} +fn filter_pm_country_based( + accepted_countries: &Option, + req_country_list: &Option>, +) -> ( + Option, + Option>, + bool, +) { + match (accepted_countries, req_country_list) { + (None, None) => (None, None, true), + (None, Some(ref r)) => ( + Some(admin::AcceptedCountries::EnableOnly(r.to_vec())), + Some(r.to_vec()), + true, + ), + (Some(l), None) => (Some(l.to_owned()), None, true), + (Some(l), Some(ref r)) => { + let updated = match l { + admin::AcceptedCountries::EnableOnly(acc) => { + filter_accepted_enum_based(&Some(acc.clone()), &Some(r.to_owned())) + .map(admin::AcceptedCountries::EnableOnly) + } + + admin::AcceptedCountries::DisableOnly(den) => { + filter_disabled_enum_based(&Some(den.clone()), &Some(r.to_owned())) + .map(admin::AcceptedCountries::DisableOnly) + } + + admin::AcceptedCountries::AllAccepted => { + Some(admin::AcceptedCountries::AllAccepted) + } + }; + + (updated, Some(r.to_vec()), true) + } + } +} + +fn filter_pm_currencies_based( + accepted_currency: &Option, + req_currency_list: &Option>, +) -> ( + Option, + Option>, + bool, +) { + match (accepted_currency, req_currency_list) { + (None, None) => (None, None, true), + (None, Some(ref r)) => ( + Some(admin::AcceptedCurrencies::EnableOnly(r.to_vec())), + Some(r.to_vec()), + true, + ), + (Some(l), None) => (Some(l.to_owned()), None, true), + (Some(l), Some(ref r)) => { + let updated = match l { + admin::AcceptedCurrencies::EnableOnly(acc) => { + filter_accepted_enum_based(&Some(acc.clone()), &Some(r.to_owned())) + .map(admin::AcceptedCurrencies::EnableOnly) + } + + admin::AcceptedCurrencies::DisableOnly(den) => { + filter_disabled_enum_based(&Some(den.clone()), &Some(r.to_owned())) + .map(admin::AcceptedCurrencies::DisableOnly) + } + + admin::AcceptedCurrencies::AllAccepted => { + Some(admin::AcceptedCurrencies::AllAccepted) + } + }; + + (updated, Some(r.to_vec()), true) + } + } +} + +fn filter_accepted_enum_based( + left: &Option>, + right: &Option>, +) -> Option> { + match (left, right) { + (Some(ref l), Some(ref r)) => { + let a: HashSet<&T> = HashSet::from_iter(l.iter()); + let b: HashSet<&T> = HashSet::from_iter(r.iter()); + + let y: Vec = a.intersection(&b).map(|&i| i.to_owned()).collect(); + Some(y) + } + (Some(ref l), None) => Some(l.to_vec()), + (_, _) => None, + } +} + +fn filter_disabled_enum_based( + left: &Option>, + right: &Option>, +) -> Option> { + match (left, right) { + (Some(ref l), Some(ref r)) => { + let mut enabled = Vec::new(); + for element in r { + if !l.contains(element) { + enabled.push(element.to_owned()); + } + } + Some(enabled) + } + (None, Some(r)) => Some(r.to_vec()), + (_, _) => None, + } } fn filter_amount_based(payment_method: &RequestPaymentMethodTypes, amount: Option) -> bool { @@ -3044,9 +3228,24 @@ fn filter_amount_based(payment_method: &RequestPaymentMethodTypes, amount: Optio .map(|max_amt| amt <= max_amt.into()) }) .unwrap_or(true); + // let min_check = match (amount, payment_method.minimum_amount) { + // (Some(amt), Some(min_amt)) => amt >= min_amt, + // (_, _) => true, + // }; + // let max_check = match (amount, payment_method.maximum_amount) { + // (Some(amt), Some(max_amt)) => amt <= max_amt, + // (_, _) => true, + // }; (min_check && max_check) || amount == Some(0) } +fn filter_pm_based_on_allowed_types( + allowed_types: Option<&Vec>, + payment_method_type: &api_enums::PaymentMethodType, +) -> bool { + allowed_types.map_or(true, |pm| pm.contains(payment_method_type)) +} + fn filter_recurring_based( payment_method: &RequestPaymentMethodTypes, recurring_enabled: Option, @@ -3063,23 +3262,54 @@ fn filter_installment_based( }) } -fn filter_pm_card_network_based( - pm_card_networks: Option<&Vec>, - request_card_networks: Option<&Vec>, - pm_type: &api_enums::PaymentMethodType, +async fn filter_payment_country_based( + pm: &RequestPaymentMethodTypes, + address: Option<&domain::Address>, +) -> errors::CustomResult { + Ok(address.map_or(true, |address| { + address.country.as_ref().map_or(true, |country| { + pm.accepted_countries.as_ref().map_or(true, |ac| match ac { + admin::AcceptedCountries::EnableOnly(acc) => acc.contains(country), + admin::AcceptedCountries::DisableOnly(den) => !den.contains(country), + admin::AcceptedCountries::AllAccepted => true, + }) + }) + })) +} + +fn filter_payment_currency_based( + payment_intent: &storage::PaymentIntent, + pm: &RequestPaymentMethodTypes, ) -> bool { - match pm_type { - api_enums::PaymentMethodType::Credit | api_enums::PaymentMethodType::Debit => { - match (pm_card_networks, request_card_networks) { - (Some(pm_card_networks), Some(request_card_networks)) => request_card_networks - .iter() - .all(|card_network| pm_card_networks.contains(card_network)), - (None, Some(_)) => false, - _ => true, - } - } - _ => true, - } + payment_intent.currency.map_or(true, |currency| { + pm.accepted_currencies.as_ref().map_or(true, |ac| match ac { + admin::AcceptedCurrencies::EnableOnly(acc) => acc.contains(¤cy), + admin::AcceptedCurrencies::DisableOnly(den) => !den.contains(¤cy), + admin::AcceptedCurrencies::AllAccepted => true, + }) + }) +} + +fn filter_payment_amount_based( + payment_intent: &storage::PaymentIntent, + pm: &RequestPaymentMethodTypes, +) -> bool { + let amount = payment_intent.amount.get_amount_as_i64(); + (pm.maximum_amount.map_or(true, |amt| amount <= amt.into()) + && pm.minimum_amount.map_or(true, |amt| amount >= amt.into())) + || payment_intent.amount.get_amount_as_i64() == 0 +} + +async fn filter_payment_mandate_based( + payment_attempt: Option<&storage::PaymentAttempt>, + pm: &RequestPaymentMethodTypes, +) -> errors::CustomResult { + let recurring_filter = if !pm.recurring_enabled { + payment_attempt.map_or(true, |pa| pa.mandate_id.is_none()) + } else { + true + }; + Ok(recurring_filter) } pub async fn do_list_customer_pm_fetch_customer_if_not_passed( diff --git a/crates/router/src/core/payment_methods/utils.rs b/crates/router/src/core/payment_methods/utils.rs deleted file mode 100644 index fc7416bf7edf..000000000000 --- a/crates/router/src/core/payment_methods/utils.rs +++ /dev/null @@ -1,828 +0,0 @@ -use std::{str::FromStr, sync::Arc}; - -use api_models::{ - admin::{self, PaymentMethodsEnabled}, - enums as api_enums, - payment_methods::RequestPaymentMethodTypes, -}; -use common_enums::enums; -use euclid::frontend::dir; -use hyperswitch_constraint_graph as cgraph; -use kgraph_utils::{error::KgraphError, transformers::IntoDirValue}; -use storage_impl::redis::cache::PM_FILTERS_CGRAPH_CACHE; - -use crate::configs::settings; - -pub fn make_pm_graph( - builder: &mut cgraph::ConstraintGraphBuilder<'_, dir::DirValue>, - payment_methods: &[serde_json::value::Value], - connector: String, - pm_config_mapping: &settings::ConnectorFilters, - supported_payment_methods_for_mandate: &settings::SupportedPaymentMethodsForMandate, - supported_payment_methods_for_update_mandate: &settings::SupportedPaymentMethodsForMandate, -) -> Result<(), KgraphError> { - for payment_method in payment_methods.iter() { - let pm_enabled = serde_json::from_value::(payment_method.clone()); - if let Ok(payment_methods_enabled) = pm_enabled { - compile_pm_graph( - builder, - payment_methods_enabled.clone(), - connector.clone(), - pm_config_mapping, - supported_payment_methods_for_mandate, - supported_payment_methods_for_update_mandate, - )?; - }; - } - Ok(()) -} - -pub async fn get_merchant_pm_filter_graph<'a>( - key: &str, -) -> Option>> { - PM_FILTERS_CGRAPH_CACHE - .get_val::>>(key) - .await -} - -pub async fn refresh_pm_filters_cache( - key: &str, - graph: cgraph::ConstraintGraph<'static, dir::DirValue>, -) -> Arc> { - let pm_filter_graph = Arc::new(graph); - PM_FILTERS_CGRAPH_CACHE - .push(key.to_string(), pm_filter_graph.clone()) - .await; - pm_filter_graph -} - -fn compile_pm_graph( - builder: &mut cgraph::ConstraintGraphBuilder<'_, dir::DirValue>, - pm_enabled: PaymentMethodsEnabled, - connector: String, - config: &settings::ConnectorFilters, - supported_payment_methods_for_mandate: &settings::SupportedPaymentMethodsForMandate, - supported_payment_methods_for_update_mandate: &settings::SupportedPaymentMethodsForMandate, -) -> Result<(), KgraphError> { - if let Some(payment_method_types) = pm_enabled.payment_method_types { - for pmt in payment_method_types { - let mut agg_nodes: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = - Vec::new(); - let mut agg_or_nodes_for_mandate_filters: Vec<( - cgraph::NodeId, - cgraph::Relation, - cgraph::Strength, - )> = Vec::new(); - - // Connector supported for Update mandate filter - let res = construct_supported_connectors_for_update_mandate_node( - builder, - supported_payment_methods_for_update_mandate, - pmt.clone(), - &pm_enabled.payment_method, - ); - if let Ok(Some(connector_eligible_for_update_mandates_node)) = res { - agg_or_nodes_for_mandate_filters.push(( - connector_eligible_for_update_mandates_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - )) - } - - // Connector supported for mandates filter - if let Some(supported_pm_for_mandates) = supported_payment_methods_for_mandate - .0 - .get(&pm_enabled.payment_method) - { - if let Some(supported_connector_for_mandates) = - supported_pm_for_mandates.0.get(&pmt.payment_method_type) - { - let supported_connectors: Vec = - supported_connector_for_mandates - .connector_list - .clone() - .into_iter() - .collect(); - if let Ok(Some(connector_eligible_for_mandates_node)) = - construct_supported_connectors_for_mandate_node( - builder, - supported_connectors, - ) - { - agg_or_nodes_for_mandate_filters.push(( - connector_eligible_for_mandates_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - )) - } - } - } - - // Non Prominent Mandate flows - let payment_type_non_mandate_value_node = builder.make_value_node( - cgraph::NodeValue::Value(dir::DirValue::PaymentType( - euclid::enums::PaymentType::NonMandate, - )), - None, - None::<()>, - ); - let payment_type_setup_mandate_value_node = builder.make_value_node( - cgraph::NodeValue::Value(dir::DirValue::PaymentType( - euclid::enums::PaymentType::SetupMandate, - )), - None, - None::<()>, - ); - - let non_major_mandate_any_node = builder - .make_any_aggregator( - &[ - ( - payment_type_non_mandate_value_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ( - payment_type_setup_mandate_value_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ], - None, - None::<()>, - None, - ) - .map_err(KgraphError::GraphConstructionError)?; - - agg_or_nodes_for_mandate_filters.push(( - non_major_mandate_any_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - )); - - let agg_or_node = builder - .make_any_aggregator(&agg_or_nodes_for_mandate_filters, None, None::<()>, None) - .map_err(KgraphError::GraphConstructionError)?; - - agg_nodes.push(( - agg_or_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - )); - - // Capture Method filter - config - .0 - .get(connector.as_str()) - .or_else(|| config.0.get("default")) - .map(|inner| { - if let Ok(Some(capture_method_filter)) = - construct_capture_method_node(builder, inner, &pmt.payment_method_type) - { - agg_nodes.push(( - capture_method_filter, - cgraph::Relation::Negative, - cgraph::Strength::Strong, - )) - } - }); - - // Country filter - if let Some(pm_object_countries) = pmt.accepted_countries { - if let Ok(Some(country_node)) = compile_accepted_countries_for_mca( - builder, - &pmt.payment_method_type, - pm_object_countries, - config, - connector.clone(), - ) { - agg_nodes.push(( - country_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - )) - } - } - - // Currency filter - if let Some(pm_object_currencies) = pmt.accepted_currencies { - if let Ok(Some(currency_node)) = compile_accepted_currency_for_mca( - builder, - &pmt.payment_method_type, - pm_object_currencies, - config, - connector.clone(), - ) { - agg_nodes.push(( - currency_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - )) - } - } - - let and_node_for_all_the_filters = builder - .make_all_aggregator(&agg_nodes, None, None::<()>, None) - .map_err(KgraphError::GraphConstructionError)?; - - // Making our output node - let pmt_info = "PaymentMethodType"; - let dir_node: cgraph::NodeValue = - (pmt.payment_method_type, pm_enabled.payment_method) - .into_dir_value() - .map(Into::into)?; - let payment_method_type_value_node = - builder.make_value_node(dir_node, Some(pmt_info), None::<()>); - - builder - .make_edge( - and_node_for_all_the_filters, - payment_method_type_value_node, - cgraph::Strength::Strong, - cgraph::Relation::Positive, - None::, - ) - .map_err(KgraphError::GraphConstructionError)?; - } - } - Ok(()) -} - -fn construct_capture_method_node( - builder: &mut cgraph::ConstraintGraphBuilder<'_, dir::DirValue>, - payment_method_filters: &settings::PaymentMethodFilters, - payment_method_type: &api_enums::PaymentMethodType, -) -> Result, KgraphError> { - if !payment_method_filters - .0 - .get(&settings::PaymentMethodFilterKey::PaymentMethodType( - *payment_method_type, - )) - .and_then(|v| v.not_available_flows) - .and_then(|v| v.capture_method) - .map(|v| !matches!(v, api_enums::CaptureMethod::Manual)) - .unwrap_or(true) - { - return Ok(Some(builder.make_value_node( - cgraph::NodeValue::Value(dir::DirValue::CaptureMethod( - common_enums::CaptureMethod::Manual, - )), - None, - None::<()>, - ))); - } - Ok(None) -} - -fn construct_supported_connectors_for_update_mandate_node( - builder: &mut cgraph::ConstraintGraphBuilder<'_, dir::DirValue>, - supported_payment_methods_for_update_mandate: &settings::SupportedPaymentMethodsForMandate, - pmt: RequestPaymentMethodTypes, - payment_method: &enums::PaymentMethod, -) -> Result, KgraphError> { - let card_value_node = builder.make_value_node( - cgraph::NodeValue::Value(dir::DirValue::PaymentMethod(enums::PaymentMethod::Card)), - None, - None::<()>, - ); - - let payment_type_value_node = builder.make_value_node( - cgraph::NodeValue::Value(dir::DirValue::PaymentType( - euclid::enums::PaymentType::UpdateMandate, - )), - None, - None::<()>, - ); - - let mut agg_nodes: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = Vec::new(); - let mut card_dir_values = Vec::new(); - let mut non_card_dir_values = Vec::new(); - - if let Some(supported_pm_for_mandates) = supported_payment_methods_for_update_mandate - .0 - .get(payment_method) - { - if payment_method == &enums::PaymentMethod::Card { - if let Some(credit_connector_list) = supported_pm_for_mandates - .0 - .get(&api_enums::PaymentMethodType::Credit) - { - card_dir_values.extend( - credit_connector_list - .connector_list - .clone() - .into_iter() - .filter_map(|connector| { - api_enums::RoutableConnectors::from_str(connector.to_string().as_str()) - .ok() - .map(|connector| { - dir::DirValue::Connector(Box::new( - api_models::routing::ast::ConnectorChoice { - connector, - #[cfg(not(feature = "connector_choice_mca_id"))] - sub_label: None, - }, - )) - }) - }), - ); - } - - if let Some(debit_connector_list) = supported_pm_for_mandates - .0 - .get(&api_enums::PaymentMethodType::Debit) - { - card_dir_values.extend( - debit_connector_list - .connector_list - .clone() - .into_iter() - .filter_map(|connector| { - api_enums::RoutableConnectors::from_str(connector.to_string().as_str()) - .ok() - .map(|connector| { - dir::DirValue::Connector(Box::new( - api_models::routing::ast::ConnectorChoice { - connector, - #[cfg(not(feature = "connector_choice_mca_id"))] - sub_label: None, - }, - )) - }) - }), - ); - } - let card_in_node = builder - .make_in_aggregator(card_dir_values, None, None::<()>) - .map_err(KgraphError::GraphConstructionError)?; - - let card_and_node = builder - .make_all_aggregator( - &[ - ( - card_value_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ( - payment_type_value_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ( - card_in_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ], - None, - None::<()>, - None, - ) - .map_err(KgraphError::GraphConstructionError)?; - - agg_nodes.push(( - card_and_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - )); - } else if let Some(connector_list) = - supported_pm_for_mandates.0.get(&pmt.payment_method_type) - { - non_card_dir_values.extend( - connector_list - .connector_list - .clone() - .into_iter() - .filter_map(|connector| { - api_enums::RoutableConnectors::from_str(connector.to_string().as_str()) - .ok() - .map(|connector| { - dir::DirValue::Connector(Box::new( - api_models::routing::ast::ConnectorChoice { - connector, - #[cfg(not(feature = "connector_choice_mca_id"))] - sub_label: None, - }, - )) - }) - }), - ); - let non_card_mandate_in_node = builder - .make_in_aggregator(non_card_dir_values, None, None::<()>) - .map_err(KgraphError::GraphConstructionError)?; - - let non_card_and_node = builder - .make_all_aggregator( - &[ - ( - card_value_node, - cgraph::Relation::Negative, - cgraph::Strength::Strong, - ), - ( - payment_type_value_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ( - non_card_mandate_in_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ], - None, - None::<()>, - None, - ) - .map_err(KgraphError::GraphConstructionError)?; - - agg_nodes.push(( - non_card_and_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - )); - } - } - - Ok(Some( - builder - .make_any_aggregator( - &agg_nodes, - Some("any node for card and non card pm"), - None::<()>, - None, - ) - .map_err(KgraphError::GraphConstructionError)?, - )) -} - -fn construct_supported_connectors_for_mandate_node( - builder: &mut cgraph::ConstraintGraphBuilder<'_, dir::DirValue>, - eligible_connectors: Vec, -) -> Result, KgraphError> { - let payment_type_value_node = builder.make_value_node( - cgraph::NodeValue::Value(dir::DirValue::PaymentType( - euclid::enums::PaymentType::NewMandate, - )), - None, - None::<()>, - ); - let connectors_from_config: Vec = eligible_connectors - .into_iter() - .filter_map(|connector| { - match api_enums::RoutableConnectors::from_str(connector.to_string().as_str()) { - Ok(connector) => Some(dir::DirValue::Connector(Box::new( - api_models::routing::ast::ConnectorChoice { - connector, - #[cfg(not(feature = "connector_choice_mca_id"))] - sub_label: None, - }, - ))), - Err(_) => None, - } - }) - .collect(); - - if connectors_from_config.is_empty() { - Ok(None) - } else { - let connector_in_aggregator = builder - .make_in_aggregator(connectors_from_config, None, None::<()>) - .map_err(KgraphError::GraphConstructionError)?; - Ok(Some( - builder - .make_all_aggregator( - &[ - ( - payment_type_value_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ( - connector_in_aggregator, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ], - None, - None::<()>, - None, - ) - .map_err(KgraphError::GraphConstructionError)?, - )) - } -} - -// fn construct_card_network_nodes( -// builder: &mut cgraph::ConstraintGraphBuilder<'_, dir::DirValue>, -// mca_card_networks: Vec, -// ) -> Result, KgraphError> { -// Ok(Some( -// builder -// .make_in_aggregator( -// mca_card_networks -// .into_iter() -// .map(dir::DirValue::CardNetwork) -// .collect(), -// None, -// None::<()>, -// ) -// .map_err(KgraphError::GraphConstructionError)?, -// )) -// } - -fn compile_accepted_countries_for_mca( - builder: &mut cgraph::ConstraintGraphBuilder<'_, dir::DirValue>, - payment_method_type: &enums::PaymentMethodType, - pm_obj_countries: admin::AcceptedCountries, - config: &settings::ConnectorFilters, - connector: String, -) -> Result, KgraphError> { - match pm_obj_countries { - admin::AcceptedCountries::EnableOnly(countries) => { - // Country from the MCA - let pm_object_country_value_node = builder - .make_in_aggregator( - countries - .into_iter() - .map(|country| { - dir::DirValue::BillingCountry(common_enums::Country::from_alpha2( - country, - )) - }) - .collect(), - None, - None::<()>, - ) - .map_err(KgraphError::GraphConstructionError)?; - if let Some(config) = config - .0 - .get(connector.as_str()) - .or_else(|| config.0.get("default")) - { - if let Some(value) = - config - .0 - .get(&settings::PaymentMethodFilterKey::PaymentMethodType( - *payment_method_type, - )) - { - // country from config - if let Some(config_countries) = value.country.as_ref() { - let config_countries: Vec = - Vec::from_iter(config_countries) - .into_iter() - .map(|country| common_enums::Country::from_alpha2(*country)) - .collect(); - let dir_countries: Vec = config_countries - .into_iter() - .map(dir::DirValue::BillingCountry) - .collect(); - - let config_country_agg_node = builder - .make_in_aggregator(dir_countries, None, None::<()>) - .map_err(KgraphError::GraphConstructionError)?; - - let node = builder - .make_all_aggregator( - &[ - ( - pm_object_country_value_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ( - config_country_agg_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ], - None, - None::<()>, - None, - ) - .map_err(KgraphError::GraphConstructionError)?; - return Ok(Some(node)); - } - } - } - } - admin::AcceptedCountries::DisableOnly(countries) => { - if let Some(config) = config - .0 - .get(connector.as_str()) - .or_else(|| config.0.get("default")) - { - // Country from the MCA - let pm_object_country_value_node = builder - .make_in_aggregator( - countries - .into_iter() - .map(|country| { - dir::DirValue::BillingCountry(common_enums::Country::from_alpha2( - country, - )) - }) - .collect(), - None, - None::<()>, - ) - .map_err(KgraphError::GraphConstructionError)?; - - if let Some(value) = - config - .0 - .get(&settings::PaymentMethodFilterKey::PaymentMethodType( - *payment_method_type, - )) - { - // country from config - if let Some(config_countries) = value.country.as_ref() { - let config_countries: Vec = - Vec::from_iter(config_countries) - .into_iter() - .map(|country| common_enums::Country::from_alpha2(*country)) - .collect(); - let dir_countries: Vec = config_countries - .into_iter() - .map(dir::DirValue::BillingCountry) - .collect(); - - let config_country_agg_node = builder - .make_in_aggregator(dir_countries, None, None::<()>) - .map_err(KgraphError::GraphConstructionError)?; - - let node = builder - .make_all_aggregator( - &[ - ( - pm_object_country_value_node, - cgraph::Relation::Negative, - cgraph::Strength::Strong, - ), - ( - config_country_agg_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ], - None, - None::<()>, - None, - ) - .map_err(KgraphError::GraphConstructionError)?; - return Ok(Some(node)); - } - } - } - } - admin::AcceptedCountries::AllAccepted => return Ok(None), - } - Ok(None) -} - -fn compile_accepted_currency_for_mca( - builder: &mut cgraph::ConstraintGraphBuilder<'_, dir::DirValue>, - payment_method_type: &enums::PaymentMethodType, - pm_obj_currency: admin::AcceptedCurrencies, - config: &settings::ConnectorFilters, - connector: String, -) -> Result, KgraphError> { - match pm_obj_currency { - admin::AcceptedCurrencies::EnableOnly(currency) => { - // Currency from the MCA - let pm_object_currency_value_node = builder - .make_in_aggregator( - currency - .into_iter() - .map(dir::DirValue::PaymentCurrency) - .collect(), - None, - None::<()>, - ) - .map_err(KgraphError::GraphConstructionError)?; - - if let Some(config) = config - .0 - .get(connector.as_str()) - .or_else(|| config.0.get("default")) - { - if let Some(value) = - config - .0 - .get(&settings::PaymentMethodFilterKey::PaymentMethodType( - *payment_method_type, - )) - { - // Currency from config - if let Some(config_currencies) = value.currency.as_ref() { - let config_currency: Vec = - Vec::from_iter(config_currencies) - .into_iter() - .cloned() - .collect(); - - let dir_currencies: Vec = config_currency - .into_iter() - .map(dir::DirValue::PaymentCurrency) - .collect(); - - let config_currency_agg_node = builder - .make_in_aggregator(dir_currencies, None, None::<()>) - .map_err(KgraphError::GraphConstructionError)?; - - let node = builder - .make_all_aggregator( - &[ - ( - pm_object_currency_value_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ( - config_currency_agg_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ], - None, - None::<()>, - None, - ) - .map_err(KgraphError::GraphConstructionError)?; - return Ok(Some(node)); - } - } - } - } - admin::AcceptedCurrencies::DisableOnly(currency) => { - // Currency from the MCA - let pm_object_currency_value_node = builder - .make_in_aggregator( - currency - .into_iter() - .map(dir::DirValue::PaymentCurrency) - .collect(), - None, - None::<()>, - ) - .map_err(KgraphError::GraphConstructionError)?; - - if let Some(config) = config - .0 - .get(connector.as_str()) - .or_else(|| config.0.get("default")) - { - if let Some(value) = - config - .0 - .get(&settings::PaymentMethodFilterKey::PaymentMethodType( - *payment_method_type, - )) - { - // Currency from config - if let Some(config_currencies) = value.currency.as_ref() { - let config_currency: Vec = - Vec::from_iter(config_currencies) - .into_iter() - .cloned() - .collect(); - - let dir_currencies: Vec = config_currency - .into_iter() - .map(dir::DirValue::PaymentCurrency) - .collect(); - - let config_currency_agg_node = builder - .make_in_aggregator(dir_currencies, None, None::<()>) - .map_err(KgraphError::GraphConstructionError)?; - - let node = builder - .make_all_aggregator( - &[ - ( - pm_object_currency_value_node, - cgraph::Relation::Negative, - cgraph::Strength::Strong, - ), - ( - config_currency_agg_node, - cgraph::Relation::Positive, - cgraph::Strength::Strong, - ), - ], - None, - None::<()>, - None, - ) - .map_err(KgraphError::GraphConstructionError)?; - return Ok(Some(node)); - } - } - } - } - admin::AcceptedCurrencies::AllAccepted => return Ok(None), - } - Ok(None) -} diff --git a/crates/router/src/db/merchant_connector_account.rs b/crates/router/src/db/merchant_connector_account.rs index be37fd9fd6fd..b0f57367dbee 100644 --- a/crates/router/src/db/merchant_connector_account.rs +++ b/crates/router/src/db/merchant_connector_account.rs @@ -430,9 +430,6 @@ impl MerchantConnectorAccountInterface for Store { cache::CacheKind::CGraph( format!("cgraph_{}_{_profile_id}", _merchant_id).into(), ), - cache::CacheKind::PmFiltersCGraph( - format!("pm_filters_cgraph_{}_{_profile_id}", _merchant_id).into(), - ), ], update_call, ) @@ -490,9 +487,6 @@ impl MerchantConnectorAccountInterface for Store { cache::CacheKind::CGraph( format!("cgraph_{}_{_profile_id}", mca.merchant_id).into(), ), - cache::CacheKind::PmFiltersCGraph( - format!("pm_filters_cgraph_{}_{_profile_id}", mca.merchant_id).into(), - ), ], delete_call, ) diff --git a/crates/storage_impl/src/redis/cache.rs b/crates/storage_impl/src/redis/cache.rs index 68f04936daf5..4a72b86fefb7 100644 --- a/crates/storage_impl/src/redis/cache.rs +++ b/crates/storage_impl/src/redis/cache.rs @@ -31,9 +31,6 @@ const ROUTING_CACHE_PREFIX: &str = "routing"; /// Prefix for cgraph cache key const CGRAPH_CACHE_PREFIX: &str = "cgraph"; -/// Prefix for PM Filter cgraph cache key -const PM_FILTERS_CGRAPH_CACHE_PREFIX: &str = "pm_filters_cgraph"; - /// Prefix for all kinds of cache key const ALL_CACHE_PREFIX: &str = "all_cache_kind"; @@ -61,10 +58,6 @@ pub static ROUTING_CACHE: Lazy = pub static CGRAPH_CACHE: Lazy = Lazy::new(|| Cache::new(CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); -/// PM Filter CGraph Cache -pub static PM_FILTERS_CGRAPH_CACHE: Lazy = - Lazy::new(|| Cache::new(CACHE_TTL, CACHE_TTI, Some(MAX_CAPACITY))); - /// Trait which defines the behaviour of types that's gonna be stored in Cache pub trait Cacheable: Any + Send + Sync + DynClone { fn as_any(&self) -> &dyn Any; @@ -75,7 +68,6 @@ pub enum CacheKind<'a> { Accounts(Cow<'a, str>), Routing(Cow<'a, str>), CGraph(Cow<'a, str>), - PmFiltersCGraph(Cow<'a, str>), All(Cow<'a, str>), } @@ -86,7 +78,6 @@ impl<'a> From> for RedisValue { CacheKind::Accounts(s) => format!("{ACCOUNTS_CACHE_PREFIX},{s}"), CacheKind::Routing(s) => format!("{ROUTING_CACHE_PREFIX},{s}"), CacheKind::CGraph(s) => format!("{CGRAPH_CACHE_PREFIX},{s}"), - CacheKind::PmFiltersCGraph(s) => format!("{PM_FILTERS_CGRAPH_CACHE_PREFIX},{s}"), CacheKind::All(s) => format!("{ALL_CACHE_PREFIX},{s}"), }; Self::from_string(value) @@ -106,9 +97,6 @@ impl<'a> TryFrom for CacheKind<'a> { CONFIG_CACHE_PREFIX => Ok(Self::Config(Cow::Owned(split.1.to_string()))), ROUTING_CACHE_PREFIX => Ok(Self::Routing(Cow::Owned(split.1.to_string()))), CGRAPH_CACHE_PREFIX => Ok(Self::CGraph(Cow::Owned(split.1.to_string()))), - PM_FILTERS_CGRAPH_CACHE_PREFIX => { - Ok(Self::PmFiltersCGraph(Cow::Owned(split.1.to_string()))) - } ALL_CACHE_PREFIX => Ok(Self::All(Cow::Owned(split.1.to_string()))), _ => Err(validation_err.into()), } diff --git a/crates/storage_impl/src/redis/pub_sub.rs b/crates/storage_impl/src/redis/pub_sub.rs index 7b23cb25ad38..830f6251d6b6 100644 --- a/crates/storage_impl/src/redis/pub_sub.rs +++ b/crates/storage_impl/src/redis/pub_sub.rs @@ -2,9 +2,7 @@ use error_stack::ResultExt; use redis_interface::{errors as redis_errors, PubsubInterface, RedisValue}; use router_env::{logger, tracing::Instrument}; -use crate::redis::cache::{ - CacheKind, ACCOUNTS_CACHE, CGRAPH_CACHE, CONFIG_CACHE, PM_FILTERS_CGRAPH_CACHE, ROUTING_CACHE, -}; +use crate::redis::cache::{CacheKind, ACCOUNTS_CACHE, CGRAPH_CACHE, CONFIG_CACHE, ROUTING_CACHE}; #[async_trait::async_trait] pub trait PubSubInterface { @@ -84,10 +82,6 @@ impl PubSubInterface for std::sync::Arc { CGRAPH_CACHE.remove(key.as_ref()).await; key } - CacheKind::PmFiltersCGraph(key) => { - PM_FILTERS_CGRAPH_CACHE.remove(key.as_ref()).await; - key - } CacheKind::Routing(key) => { ROUTING_CACHE.remove(key.as_ref()).await; key @@ -96,7 +90,6 @@ impl PubSubInterface for std::sync::Arc { CONFIG_CACHE.remove(key.as_ref()).await; ACCOUNTS_CACHE.remove(key.as_ref()).await; CGRAPH_CACHE.remove(key.as_ref()).await; - PM_FILTERS_CGRAPH_CACHE.remove(key.as_ref()).await; ROUTING_CACHE.remove(key.as_ref()).await; key } From df7cf96c96d7a4a0d9245cba6e5b686ab6b6e5ea Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 13:22:06 +0000 Subject: [PATCH 05/25] chore(version): 2024.05.31.1 --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ece80bdb3c83..0d88ba7053e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,26 @@ All notable changes to HyperSwitch will be documented here. - - - +## 2024.05.31.1 + +### Features + +- **cypress:** Add trustpay, adyen bank redirects and corresponding refactor ([#4766](https://github.com/juspay/hyperswitch/pull/4766)) ([`48dac12`](https://github.com/juspay/hyperswitch/commit/48dac12cedc7f11b76c6a9ef8ba4ce04ae2456bf)) + +### Refactors + +- **core:** Reverts Inclusion of constraint graph for merchant Payment Method list ([#4839](https://github.com/juspay/hyperswitch/pull/4839)) ([`f74b9b6`](https://github.com/juspay/hyperswitch/commit/f74b9b622e5565a00bf9ee8223c64a3def37b776)) +- **first_name:** Check if first_name is sent as empty string ([#4832](https://github.com/juspay/hyperswitch/pull/4832)) ([`5cb84f6`](https://github.com/juspay/hyperswitch/commit/5cb84f66e4c59f6ffbd12bf4e91ab0152ac1c2c5)) + +### Miscellaneous Tasks + +- **euclid_wasm:** Update paypal payment experience ([#4811](https://github.com/juspay/hyperswitch/pull/4811)) ([`121b611`](https://github.com/juspay/hyperswitch/commit/121b61123f31db9d94888fa708532cdabca4bbc8)) +- Enable `clippy::large_futures` lint ([#4822](https://github.com/juspay/hyperswitch/pull/4822)) ([`d2d317c`](https://github.com/juspay/hyperswitch/commit/d2d317ce61c0c00ca38af9774bd1b45247d30c82)) + +**Full Changelog:** [`2024.05.31.0...2024.05.31.1`](https://github.com/juspay/hyperswitch/compare/2024.05.31.0...2024.05.31.1) + +- - - + ## 2024.05.31.0 ### Features From d84e62441f39c165af7dc1c8d893344ff85c1711 Mon Sep 17 00:00:00 2001 From: Pa1NarK <69745008+pixincreate@users.noreply.github.com> Date: Mon, 3 Jun 2024 12:06:34 +0530 Subject: [PATCH 06/25] chore(cypress): remove logs that expose `globalState` (#4844) --- .../e2e/ConnectorTest/00000-AccountCreate.cy.js | 2 -- .../ConnectorTest/00001-CustomerCreate.cy.js | 2 -- .../ConnectorTest/00002-ConnectorCreate.cy.js | 2 -- .../00003-NoThreeDSAutoCapture.cy.js | 4 ---- .../00004-ThreeDSAutoCapture.cy.js | 6 ------ .../00005-NoThreeDSManualCapture.cy.js | 2 -- .../e2e/ConnectorTest/00006-VoidPayment.cy.js | 2 -- .../e2e/ConnectorTest/00007-SyncPayment.cy.js | 2 -- .../e2e/ConnectorTest/00008-RefundPayment.cy.js | 4 ---- .../e2e/ConnectorTest/00009-SyncRefund.cy.js | 2 -- .../00010-CreateSingleuseMandate.cy.js | 2 -- .../00011-CreateMultiuseMandate.cy.js | 2 -- .../00012-ListAndRevokeMandate.cy.js | 2 -- .../e2e/ConnectorTest/00013-SaveCardFlow.cy.js | 1 - .../ConnectorTest/00014-ZeroAuthMandate.cy.js | 2 -- .../00015-ThreeDSManualCapture.cy.js | 2 -- .../e2e/ConnectorTest/00016-BankTransfers.cy.js | 4 ---- .../e2e/ConnectorTest/00017-BankRedirect.cy.js | 17 ----------------- 18 files changed, 60 deletions(-) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00000-AccountCreate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00000-AccountCreate.cy.js index 4c16fef8df41..aed901c29972 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00000-AccountCreate.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00000-AccountCreate.cy.js @@ -9,11 +9,9 @@ describe("Account Create flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00001-CustomerCreate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00001-CustomerCreate.cy.js index c21152ca896e..5e8bcb5aa14c 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00001-CustomerCreate.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00001-CustomerCreate.cy.js @@ -9,11 +9,9 @@ describe("Customer Create flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) it("customer-create-call-test", () => { diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00002-ConnectorCreate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00002-ConnectorCreate.cy.js index 1241048f2862..927f0d020110 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00002-ConnectorCreate.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00002-ConnectorCreate.cy.js @@ -8,12 +8,10 @@ describe("Connector Account Create flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00003-NoThreeDSAutoCapture.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00003-NoThreeDSAutoCapture.cy.js index 4dc3f2a3e78f..ec36fa16023e 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00003-NoThreeDSAutoCapture.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00003-NoThreeDSAutoCapture.cy.js @@ -13,12 +13,10 @@ describe("Card - NoThreeDS payment flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) @@ -78,7 +76,5 @@ describe("Card - NoThreeDS payment flow test", () => { it("retrieve-payment-call-test", () => { cy.retrievePaymentCallTest(globalState); }); - - }); }); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00004-ThreeDSAutoCapture.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00004-ThreeDSAutoCapture.cy.js index c970d9716eff..3178170021c5 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00004-ThreeDSAutoCapture.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00004-ThreeDSAutoCapture.cy.js @@ -19,16 +19,12 @@ describe("Card - ThreeDS payment flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); - cy.task('cli_log', "SEEDING GLOBAL STATE -> " + JSON.stringify(globalState)); }) }) afterEach("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); - cy.task('cli_log', " FLUSHING GLOBAL STATE -> " + JSON.stringify(globalState)); }) @@ -41,7 +37,6 @@ describe("Card - ThreeDS payment flow test", () => { }); it("payment_methods-call-test", () => { - cy.task('cli_log', "PM CALL "); cy.paymentMethodsCallTest(globalState); }); @@ -49,7 +44,6 @@ describe("Card - ThreeDS payment flow test", () => { let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSAutoCapture"]; let req_data = data["Request"]; let res_data = data["Response"]; - cy.task('cli_log', "GLOBAL STATE -> " + JSON.stringify(globalState.data)); cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); if(should_continue) should_continue = utils.should_continue_further(res_data); }); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00005-NoThreeDSManualCapture.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00005-NoThreeDSManualCapture.cy.js index 48a22f5a5c03..4ee4483c961a 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00005-NoThreeDSManualCapture.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00005-NoThreeDSManualCapture.cy.js @@ -14,12 +14,10 @@ describe("Card - NoThreeDS Manual payment flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00006-VoidPayment.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00006-VoidPayment.cy.js index 15f2e0e7930a..ef8157775688 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00006-VoidPayment.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00006-VoidPayment.cy.js @@ -13,12 +13,10 @@ describe("Card - NoThreeDS Manual payment flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00007-SyncPayment.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00007-SyncPayment.cy.js index 10c16f7ff6e9..1920cdd09dbc 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00007-SyncPayment.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00007-SyncPayment.cy.js @@ -19,12 +19,10 @@ describe("Card - Sync payment flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) it("create-payment-call-test", () => { diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00008-RefundPayment.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00008-RefundPayment.cy.js index 028e48a41dc8..672c5cf8f4aa 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00008-RefundPayment.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00008-RefundPayment.cy.js @@ -18,13 +18,11 @@ describe("Card - Refund flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) afterEach("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) @@ -534,13 +532,11 @@ describe("Card - Refund flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) afterEach("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00009-SyncRefund.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00009-SyncRefund.cy.js index 31e5e6855d6a..f0cdc9a68903 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00009-SyncRefund.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00009-SyncRefund.cy.js @@ -20,12 +20,10 @@ describe("Card - Sync Refund flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00010-CreateSingleuseMandate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00010-CreateSingleuseMandate.cy.js index 4ece0319324e..ec85017f55d3 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00010-CreateSingleuseMandate.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00010-CreateSingleuseMandate.cy.js @@ -13,12 +13,10 @@ describe("Card - SingleUse Mandates flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00011-CreateMultiuseMandate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00011-CreateMultiuseMandate.cy.js index 898258c8d6a3..3e14d69db88e 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00011-CreateMultiuseMandate.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00011-CreateMultiuseMandate.cy.js @@ -13,12 +13,10 @@ describe("Card - MultiUse Mandates flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00012-ListAndRevokeMandate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00012-ListAndRevokeMandate.cy.js index 8de48fbf95a4..1f9782f22740 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00012-ListAndRevokeMandate.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00012-ListAndRevokeMandate.cy.js @@ -13,12 +13,10 @@ describe("Card - SingleUse Mandates flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00013-SaveCardFlow.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00013-SaveCardFlow.cy.js index 1168a5690893..828fb5101ac7 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00013-SaveCardFlow.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00013-SaveCardFlow.cy.js @@ -15,7 +15,6 @@ describe("Card - SaveCard payment flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00014-ZeroAuthMandate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00014-ZeroAuthMandate.cy.js index ee0edcb94ac2..7a0eba4b6ad9 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00014-ZeroAuthMandate.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00014-ZeroAuthMandate.cy.js @@ -12,12 +12,10 @@ describe("Card - SingleUse Mandates flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00015-ThreeDSManualCapture.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00015-ThreeDSManualCapture.cy.js index 4c3d2a1cd0b5..50d136b59600 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00015-ThreeDSManualCapture.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00015-ThreeDSManualCapture.cy.js @@ -15,13 +15,11 @@ describe("Card - ThreeDS Manual payment flow test", () => { cy.task('getGlobalState').then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }) }) afterEach("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task('setGlobalState', globalState.data); }) diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00016-BankTransfers.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00016-BankTransfers.cy.js index ae5f09871024..da4fab34b8e5 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00016-BankTransfers.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00016-BankTransfers.cy.js @@ -9,12 +9,10 @@ describe("Bank Transfers", () => { before("seed global state", () => { cy.task("getGlobalState").then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }); }); after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task("setGlobalState", globalState.data); }); @@ -46,7 +44,6 @@ describe("Bank Transfers", () => { }); it("payment_methods-call-test", () => { - cy.task("cli_log", "PM CALL "); cy.paymentMethodsCallTest(globalState); }); @@ -56,7 +53,6 @@ describe("Bank Transfers", () => { ]["Pix"]; let req_data = data["Request"]; let res_data = data["Response"]; - cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); cy.confirmBankTransferCallTest( confirmBody, req_data, diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00017-BankRedirect.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00017-BankRedirect.cy.js index c08468022a80..3a636b2020a0 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00017-BankRedirect.cy.js +++ b/cypress-tests/cypress/e2e/ConnectorTest/00017-BankRedirect.cy.js @@ -9,22 +9,15 @@ describe("Bank Redirect tests", () => { before("seed global state", () => { cy.task("getGlobalState").then((state) => { globalState = new State(state); - console.log("seeding globalState -> " + JSON.stringify(globalState)); }); }); after("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task("setGlobalState", globalState.data); }); afterEach("flush global state", () => { - console.log("flushing globalState -> " + JSON.stringify(globalState)); cy.task("setGlobalState", globalState.data); - cy.task( - "cli_log", - " FLUSHING GLOBAL STATE -> " + JSON.stringify(globalState) - ); }); context("Blik Create and Confirm flow test", () => { @@ -55,7 +48,6 @@ describe("Bank Redirect tests", () => { }); it("payment_methods-call-test", () => { - cy.task("cli_log", "PM CALL "); cy.paymentMethodsCallTest(globalState); }); @@ -65,7 +57,6 @@ describe("Bank Redirect tests", () => { ]["blik"]; let req_data = data["Request"]; let res_data = data["Response"]; - cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); cy.confirmBankRedirectCallTest( confirmBody, req_data, @@ -105,7 +96,6 @@ describe("Bank Redirect tests", () => { }); it("payment_methods-call-test", () => { - cy.task("cli_log", "PM CALL "); cy.paymentMethodsCallTest(globalState); }); @@ -115,7 +105,6 @@ describe("Bank Redirect tests", () => { ]["eps"]; let req_data = data["Request"]; let res_data = data["Response"]; - cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); cy.confirmBankRedirectCallTest( confirmBody, req_data, @@ -167,7 +156,6 @@ describe("Bank Redirect tests", () => { }); it("payment_methods-call-test", () => { - cy.task("cli_log", "PM CALL "); cy.paymentMethodsCallTest(globalState); }); @@ -177,7 +165,6 @@ describe("Bank Redirect tests", () => { ]["ideal"]; let req_data = data["Request"]; let res_data = data["Response"]; - cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); cy.confirmBankRedirectCallTest( confirmBody, req_data, @@ -228,7 +215,6 @@ describe("Bank Redirect tests", () => { }); it("payment_methods-call-test", () => { - cy.task("cli_log", "PM CALL "); cy.paymentMethodsCallTest(globalState); }); @@ -238,7 +224,6 @@ describe("Bank Redirect tests", () => { ]["giropay"]; let req_data = data["Request"]; let res_data = data["Response"]; - cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); cy.confirmBankRedirectCallTest( confirmBody, req_data, @@ -289,7 +274,6 @@ describe("Bank Redirect tests", () => { }); it("payment_methods-call-test", () => { - cy.task("cli_log", "PM CALL "); cy.paymentMethodsCallTest(globalState); }); @@ -299,7 +283,6 @@ describe("Bank Redirect tests", () => { ]["sofort"]; let req_data = data["Request"]; let res_data = data["Response"]; - cy.task("cli_log", "GLOBAL STATE -> " + JSON.stringify(globalState.data)); cy.confirmBankRedirectCallTest( confirmBody, req_data, From 69b2f76be7a2c0deba2c069a87c10a33253e2216 Mon Sep 17 00:00:00 2001 From: Hrithikesh <61539176+hrithikesh026@users.noreply.github.com> Date: Mon, 3 Jun 2024 13:22:44 +0530 Subject: [PATCH 07/25] fix(connector): make few fields optional in struct NetceteraErrorDetails (#4827) --- crates/router/src/connector/netcetera.rs | 2 +- .../router/src/connector/netcetera/transformers.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/router/src/connector/netcetera.rs b/crates/router/src/connector/netcetera.rs index 43df87db40f4..714873cfb531 100644 --- a/crates/router/src/connector/netcetera.rs +++ b/crates/router/src/connector/netcetera.rs @@ -107,7 +107,7 @@ impl ConnectorCommon for Netcetera { status_code: res.status_code, code: response.error_details.error_code, message: response.error_details.error_description, - reason: Some(response.error_details.error_detail), + reason: response.error_details.error_detail, attempt_status: None, connector_transaction_id: None, }) diff --git a/crates/router/src/connector/netcetera/transformers.rs b/crates/router/src/connector/netcetera/transformers.rs index 66813716fb91..0fcecadef249 100644 --- a/crates/router/src/connector/netcetera/transformers.rs +++ b/crates/router/src/connector/netcetera/transformers.rs @@ -105,8 +105,8 @@ impl NetceteraPreAuthenticationResponse::Failure(error_response) => { Err(types::ErrorResponse { code: error_response.error_details.error_code, - message: error_response.error_details.error_detail, - reason: Some(error_response.error_details.error_description), + message: error_response.error_details.error_description, + reason: error_response.error_details.error_detail, status_code: item.http_code, attempt_status: None, connector_transaction_id: None, @@ -174,8 +174,8 @@ impl } NetceteraAuthenticationResponse::Error(error_response) => Err(types::ErrorResponse { code: error_response.error_details.error_code, - message: error_response.error_details.error_detail, - reason: Some(error_response.error_details.error_description), + message: error_response.error_details.error_description, + reason: error_response.error_details.error_detail, status_code: item.http_code, attempt_status: None, connector_transaction_id: None, @@ -235,20 +235,20 @@ pub struct NetceteraErrorDetails { pub error_code: String, /// Code indicating the 3-D Secure component that identified the error. - pub error_component: String, + pub error_component: Option, /// Text describing the problem identified. pub error_description: String, /// Additional detail regarding the problem identified. - pub error_detail: String, + pub error_detail: Option, /// Universally unique identifier for the transaction assigned by the 3DS SDK. #[serde(rename = "sdkTransID")] pub sdk_trans_id: Option, /// The Message Type that was identified as erroneous. - pub error_message_type: String, + pub error_message_type: Option, } #[derive(Debug, Serialize, Deserialize)] From 865007717c5c7e617ca1b447ea5f9bb3d274cac3 Mon Sep 17 00:00:00 2001 From: Swangi Kumari <85639103+swangi-kumari@users.noreply.github.com> Date: Mon, 3 Jun 2024 13:24:56 +0530 Subject: [PATCH 08/25] refactor(connector): [Klarna] Add shipping Address in Klarna Session and Payment Request (#4836) --- crates/router/src/connector/klarna.rs | 1 + .../src/connector/klarna/transformers.rs | 40 ++++++++ crates/router/src/connector/utils.rs | 95 +++++++++++++++++++ 3 files changed, 136 insertions(+) diff --git a/crates/router/src/connector/klarna.rs b/crates/router/src/connector/klarna.rs index 3258e08ba991..2059b00ac363 100644 --- a/crates/router/src/connector/klarna.rs +++ b/crates/router/src/connector/klarna.rs @@ -665,6 +665,7 @@ impl req, ))?; let connector_req = klarna::KlarnaPaymentsRequest::try_from(&connector_router_data)?; + Ok(RequestContent::Json(Box::new(connector_req))) } diff --git a/crates/router/src/connector/klarna/transformers.rs b/crates/router/src/connector/klarna/transformers.rs index c14af3aad318..69b9dfc67bb9 100644 --- a/crates/router/src/connector/klarna/transformers.rs +++ b/crates/router/src/connector/klarna/transformers.rs @@ -75,6 +75,7 @@ pub struct KlarnaPaymentsRequest { purchase_country: enums::CountryAlpha2, purchase_currency: enums::Currency, merchant_reference1: Option, + shipping_address: Option, } #[derive(Debug, Deserialize, Serialize)] @@ -90,6 +91,21 @@ pub struct KlarnaSessionRequest { purchase_currency: enums::Currency, order_amount: i64, order_lines: Vec, + shipping_address: Option, +} + +#[derive(Debug, Serialize)] +pub struct KlarnaShippingAddress { + city: Option, + country: Option, + email: Option, + given_name: Option>, + family_name: Option>, + phone: Option>, + postal_code: Option>, + region: Option>, + street_address: Option>, + street_address2: Option>, } #[derive(Deserialize, Serialize, Debug)] @@ -123,6 +139,18 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsSessionRouterData>> for KlarnaSes total_amount: i64::from(data.quantity) * (data.amount), }) .collect(), + shipping_address: Some(KlarnaShippingAddress { + city: item.router_data.get_optional_shipping_city(), + country: item.router_data.get_optional_shipping_country(), + email: item.router_data.get_optional_shipping_email(), + given_name: item.router_data.get_optional_shipping_first_name(), + family_name: item.router_data.get_optional_shipping_last_name(), + phone: item.router_data.get_optional_shipping_phone_number(), + postal_code: item.router_data.get_optional_shipping_zip(), + region: item.router_data.get_optional_shipping_state(), + street_address: item.router_data.get_optional_shipping_line1(), + street_address2: item.router_data.get_optional_shipping_line2(), + }), }), None => Err(report!(errors::ConnectorError::MissingRequiredField { field_name: "order_details", @@ -176,6 +204,18 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsAuthorizeRouterData>> for KlarnaP .collect(), merchant_reference1: Some(item.router_data.connector_request_reference_id.clone()), auto_capture: request.is_auto_capture()?, + shipping_address: Some(KlarnaShippingAddress { + city: item.router_data.get_optional_shipping_city(), + country: item.router_data.get_optional_shipping_country(), + email: item.router_data.get_optional_shipping_email(), + given_name: item.router_data.get_optional_shipping_first_name(), + family_name: item.router_data.get_optional_shipping_last_name(), + phone: item.router_data.get_optional_shipping_phone_number(), + postal_code: item.router_data.get_optional_shipping_zip(), + region: item.router_data.get_optional_shipping_state(), + street_address: item.router_data.get_optional_shipping_line1(), + street_address2: item.router_data.get_optional_shipping_line2(), + }), }), None => Err(report!(errors::ConnectorError::MissingRequiredField { field_name: "order_details" diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index ba0ef166808c..6737bbf3af0f 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -101,6 +101,16 @@ pub trait RouterData { fn get_optional_billing(&self) -> Option<&api::Address>; fn get_optional_shipping(&self) -> Option<&api::Address>; + fn get_optional_shipping_line1(&self) -> Option>; + fn get_optional_shipping_line2(&self) -> Option>; + fn get_optional_shipping_city(&self) -> Option; + fn get_optional_shipping_country(&self) -> Option; + fn get_optional_shipping_zip(&self) -> Option>; + fn get_optional_shipping_state(&self) -> Option>; + fn get_optional_shipping_first_name(&self) -> Option>; + fn get_optional_shipping_last_name(&self) -> Option>; + fn get_optional_shipping_phone_number(&self) -> Option>; + fn get_optional_shipping_email(&self) -> Option; fn get_optional_billing_full_name(&self) -> Option>; fn get_optional_billing_line1(&self) -> Option>; @@ -199,6 +209,91 @@ impl RouterData for types::RouterData Option> { + self.address.get_shipping().and_then(|shipping_address| { + shipping_address + .clone() + .address + .and_then(|shipping_address_details| shipping_address_details.first_name) + }) + } + + fn get_optional_shipping_last_name(&self) -> Option> { + self.address.get_shipping().and_then(|shipping_address| { + shipping_address + .clone() + .address + .and_then(|shipping_address_details| shipping_address_details.last_name) + }) + } + + fn get_optional_shipping_line1(&self) -> Option> { + self.address.get_shipping().and_then(|shipping_address| { + shipping_address + .clone() + .address + .and_then(|shipping_address_details| shipping_address_details.line1) + }) + } + + fn get_optional_shipping_line2(&self) -> Option> { + self.address.get_shipping().and_then(|shipping_address| { + shipping_address + .clone() + .address + .and_then(|shipping_address_details| shipping_address_details.line2) + }) + } + + fn get_optional_shipping_city(&self) -> Option { + self.address.get_shipping().and_then(|shipping_address| { + shipping_address + .clone() + .address + .and_then(|shipping_address_details| shipping_address_details.city) + }) + } + + fn get_optional_shipping_state(&self) -> Option> { + self.address.get_shipping().and_then(|shipping_address| { + shipping_address + .clone() + .address + .and_then(|shipping_address_details| shipping_address_details.state) + }) + } + + fn get_optional_shipping_country(&self) -> Option { + self.address.get_shipping().and_then(|shipping_address| { + shipping_address + .clone() + .address + .and_then(|shipping_address_details| shipping_address_details.country) + }) + } + + fn get_optional_shipping_zip(&self) -> Option> { + self.address.get_shipping().and_then(|shipping_address| { + shipping_address + .clone() + .address + .and_then(|shipping_address_details| shipping_address_details.zip) + }) + } + + fn get_optional_shipping_email(&self) -> Option { + self.address + .get_shipping() + .and_then(|shipping_address| shipping_address.clone().email) + } + + fn get_optional_shipping_phone_number(&self) -> Option> { + self.address + .get_shipping() + .and_then(|shipping_address| shipping_address.clone().phone) + .and_then(|phone_details| phone_details.get_number_with_country_code().ok()) + } + fn get_description(&self) -> Result { self.description .clone() From ccee1a9ce9e860bfa04e74329fb47fd73f010b23 Mon Sep 17 00:00:00 2001 From: ivor-juspay <138492857+ivor-juspay@users.noreply.github.com> Date: Mon, 3 Jun 2024 14:46:17 +0530 Subject: [PATCH 09/25] feat(consolidated-kafka-events): add consolidated kafka payment events (#4798) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: Sampras Lopes --- config/config.example.toml | 26 ++-- config/deployments/env_specific.toml | 1 + config/development.toml | 6 +- config/docker_compose.toml | 10 +- crates/router/src/events.rs | 1 + crates/router/src/services/kafka.rs | 105 +++++++++++++--- .../src/services/kafka/dispute_event.rs | 77 ++++++++++++ .../services/kafka/payment_attempt_event.rs | 119 ++++++++++++++++++ .../services/kafka/payment_intent_event.rs | 75 +++++++++++ .../router/src/services/kafka/refund_event.rs | 74 +++++++++++ 10 files changed, 455 insertions(+), 39 deletions(-) create mode 100644 crates/router/src/services/kafka/dispute_event.rs create mode 100644 crates/router/src/services/kafka/payment_attempt_event.rs create mode 100644 crates/router/src/services/kafka/payment_intent_event.rs create mode 100644 crates/router/src/services/kafka/refund_event.rs diff --git a/config/config.example.toml b/config/config.example.toml index 5433d7a8e46e..5d40d0e55ef9 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -263,8 +263,7 @@ stripe = { banks = "alior_bank,bank_millennium,bank_nowy_bfg_sa,bank_pekao_sa,ba # This data is used to call respective connectors for wallets and cards [connectors.supported] -wallets = ["klarna", - "mifinity", "braintree", "applepay"] +wallets = ["klarna", "mifinity", "braintree", "applepay"] rewards = ["cashtocode", "zen"] cards = [ "adyen", @@ -352,8 +351,8 @@ email_role_arn = "" # The amazon resource name ( arn ) of the role which sts_role_session_name = "" # An identifier for the assumed role session, used to uniquely identify a session. [user] -password_validity_in_days = 90 # Number of days after which password should be updated -two_factor_auth_expiry_in_secs = 300 # Number of seconds after which 2FA should be done again if doing update/change from inside +password_validity_in_days = 90 # Number of days after which password should be updated +two_factor_auth_expiry_in_secs = 300 # Number of seconds after which 2FA should be done again if doing update/change from inside #tokenization configuration which describe token lifetime and payment method for specific connector [tokenization] @@ -364,7 +363,7 @@ stax = { long_lived_token = true, payment_method = "card,bank_debit" } square = { long_lived_token = false, payment_method = "card" } braintree = { long_lived_token = false, payment_method = "card" } gocardless = { long_lived_token = true, payment_method = "bank_debit" } -billwerk = {long_lived_token = false, payment_method = "card"} +billwerk = { long_lived_token = false, payment_method = "card" } [temp_locker_enable_config] stripe = { payment_method = "bank_transfer" } @@ -397,16 +396,16 @@ slack_invite_url = "https://www.example.com/" # Slack invite url for hyperswit discord_invite_url = "https://www.example.com/" # Discord invite url for hyperswitch [mandates.supported_payment_methods] -card.credit = { connector_list = "stripe,adyen,cybersource,bankofamerica"} # Mandate supported payment method type and connector for card -wallet.paypal = { connector_list = "adyen" } # Mandate supported payment method type and connector for wallets -pay_later.klarna = { connector_list = "adyen" } # Mandate supported payment method type and connector for pay_later -bank_debit.ach = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit -bank_debit.becs = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit -bank_debit.sepa = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit -bank_redirect.ideal = { connector_list = "stripe,adyen,globalpay" } # Mandate supported payment method type and connector for bank_redirect +card.credit = { connector_list = "stripe,adyen,cybersource,bankofamerica" } # Mandate supported payment method type and connector for card +wallet.paypal = { connector_list = "adyen" } # Mandate supported payment method type and connector for wallets +pay_later.klarna = { connector_list = "adyen" } # Mandate supported payment method type and connector for pay_later +bank_debit.ach = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit +bank_debit.becs = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit +bank_debit.sepa = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit +bank_redirect.ideal = { connector_list = "stripe,adyen,globalpay" } # Mandate supported payment method type and connector for bank_redirect bank_redirect.sofort = { connector_list = "stripe,adyen,globalpay" } wallet.apple_pay = { connector_list = "stripe,adyen,cybersource,noon,bankofamerica" } -wallet.google_pay = { connector_list = "bankofamerica"} +wallet.google_pay = { connector_list = "bankofamerica" } bank_redirect.giropay = { connector_list = "adyen,globalpay" } @@ -589,6 +588,7 @@ outgoing_webhook_logs_topic = "topic" # Kafka topic to be used for outgoing webh dispute_analytics_topic = "topic" # Kafka topic to be used for Dispute events audit_events_topic = "topic" # Kafka topic to be used for Payment Audit events payout_analytics_topic = "topic" # Kafka topic to be used for Payouts and PayoutAttempt events +consolidated_events_topic = "topic" # Kafka topic to be used for Consolidated events # File storage configuration [file_storage] diff --git a/config/deployments/env_specific.toml b/config/deployments/env_specific.toml index fc02335dcf53..7215e1931a40 100644 --- a/config/deployments/env_specific.toml +++ b/config/deployments/env_specific.toml @@ -81,6 +81,7 @@ outgoing_webhook_logs_topic = "topic" # Kafka topic to be used for outgoing webh dispute_analytics_topic = "topic" # Kafka topic to be used for Dispute events audit_events_topic = "topic" # Kafka topic to be used for Payment Audit events payout_analytics_topic = "topic" # Kafka topic to be used for Payouts and PayoutAttempt events +consolidated_events_topic = "topic" # Kafka topic to be used for Consolidated events # File storage configuration [file_storage] diff --git a/config/development.toml b/config/development.toml index 56d74e674897..496ce6477a8d 100644 --- a/config/development.toml +++ b/config/development.toml @@ -89,8 +89,7 @@ vault_private_key = "" tunnel_private_key = "" [connectors.supported] -wallets = ["klarna", - "mifinity", "braintree", "applepay", "adyen"] +wallets = ["klarna", "mifinity", "braintree", "applepay", "adyen"] rewards = ["cashtocode", "zen"] cards = [ "aci", @@ -559,7 +558,7 @@ redis_lock_expiry_seconds = 180 # 3 * 60 seconds delay_between_retries_in_milliseconds = 500 [kv_config] -ttl = 900 # 15 * 60 seconds +ttl = 900 # 15 * 60 seconds soft_kill = false [frm] @@ -579,6 +578,7 @@ outgoing_webhook_logs_topic = "hyperswitch-outgoing-webhook-events" dispute_analytics_topic = "hyperswitch-dispute-events" audit_events_topic = "hyperswitch-audit-events" payout_analytics_topic = "hyperswitch-payout-events" +consolidated_events_topic = "hyperswitch-consolidated-events" [analytics] source = "sqlx" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index 3dac84e21d83..b94b5c8afbb6 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -180,8 +180,7 @@ zsl.base_url = "https://api.sitoffalb.net/" apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US,KR,VN,MA,ZA,VA,CL,SV,GT,HN,PA", currency = "AED,AUD,CHF,CAD,EUR,GBP,HKD,SGD,USD" } [connectors.supported] -wallets = ["klarna", - "mifinity", "braintree", "applepay"] +wallets = ["klarna", "mifinity", "braintree", "applepay"] rewards = ["cashtocode", "zen"] cards = [ "aci", @@ -239,7 +238,7 @@ cards = [ "worldline", "worldpay", "zen", - "zsl" + "zsl", ] [delayed_session_response] @@ -269,7 +268,7 @@ stax = { long_lived_token = true, payment_method = "card,bank_debit" } square = { long_lived_token = false, payment_method = "card" } braintree = { long_lived_token = false, payment_method = "card" } gocardless = { long_lived_token = true, payment_method = "bank_debit" } -billwerk = {long_lived_token = false, payment_method = "card"} +billwerk = { long_lived_token = false, payment_method = "card" } [temp_locker_enable_config] stripe = { payment_method = "bank_transfer" } @@ -433,6 +432,7 @@ outgoing_webhook_logs_topic = "hyperswitch-outgoing-webhook-events" dispute_analytics_topic = "hyperswitch-dispute-events" audit_events_topic = "hyperswitch-audit-events" payout_analytics_topic = "hyperswitch-payout-events" +consolidated_events_topic = "hyperswitch-consolidated-events" [analytics] source = "sqlx" @@ -454,7 +454,7 @@ connection_timeout = 10 queue_strategy = "Fifo" [kv_config] -ttl = 900 # 15 * 60 seconds +ttl = 900 # 15 * 60 seconds soft_kill = false [frm] diff --git a/crates/router/src/events.rs b/crates/router/src/events.rs index 4bca58248351..e1ecd09804cf 100644 --- a/crates/router/src/events.rs +++ b/crates/router/src/events.rs @@ -30,6 +30,7 @@ pub enum EventType { AuditEvent, #[cfg(feature = "payouts")] Payout, + Consolidated, } #[derive(Debug, Default, Deserialize, Clone)] diff --git a/crates/router/src/services/kafka.rs b/crates/router/src/services/kafka.rs index 6f2aa9fcd100..3523ab9261fd 100644 --- a/crates/router/src/services/kafka.rs +++ b/crates/router/src/services/kafka.rs @@ -12,9 +12,13 @@ use rdkafka::{ pub mod payout; use crate::events::EventType; mod dispute; +mod dispute_event; mod payment_attempt; +mod payment_attempt_event; mod payment_intent; +mod payment_intent_event; mod refund; +mod refund_event; use diesel_models::refund::Refund; use hyperswitch_domain_models::payments::{payment_attempt::PaymentAttempt, PaymentIntent}; use serde::Serialize; @@ -23,8 +27,10 @@ use time::{OffsetDateTime, PrimitiveDateTime}; #[cfg(feature = "payouts")] use self::payout::KafkaPayout; use self::{ - dispute::KafkaDispute, payment_attempt::KafkaPaymentAttempt, - payment_intent::KafkaPaymentIntent, refund::KafkaRefund, + dispute::KafkaDispute, dispute_event::KafkaDisputeEvent, payment_attempt::KafkaPaymentAttempt, + payment_attempt_event::KafkaPaymentAttemptEvent, payment_intent::KafkaPaymentIntent, + payment_intent_event::KafkaPaymentIntentEvent, refund::KafkaRefund, + refund_event::KafkaRefundEvent, }; use crate::types::storage::Dispute; @@ -89,6 +95,42 @@ impl<'a, T: KafkaMessage> KafkaMessage for KafkaEvent<'a, T> { } } +#[derive(serde::Serialize, Debug)] +struct KafkaConsolidatedLog<'a, T: KafkaMessage> { + #[serde(flatten)] + event: &'a T, + tenant_id: TenantID, +} + +#[derive(serde::Serialize, Debug)] +struct KafkaConsolidatedEvent<'a, T: KafkaMessage> { + log: KafkaConsolidatedLog<'a, T>, + log_type: EventType, +} + +impl<'a, T: KafkaMessage> KafkaConsolidatedEvent<'a, T> { + fn new(event: &'a T, tenant_id: TenantID) -> Self { + Self { + log: KafkaConsolidatedLog { event, tenant_id }, + log_type: event.event_type(), + } + } +} + +impl<'a, T: KafkaMessage> KafkaMessage for KafkaConsolidatedEvent<'a, T> { + fn key(&self) -> String { + self.log.event.key() + } + + fn event_type(&self) -> EventType { + EventType::Consolidated + } + + fn creation_timestamp(&self) -> Option { + self.log.event.creation_timestamp() + } +} + #[derive(Debug, serde::Deserialize, Clone, Default)] #[serde(default)] pub struct KafkaSettings { @@ -103,6 +145,7 @@ pub struct KafkaSettings { audit_events_topic: String, #[cfg(feature = "payouts")] payout_analytics_topic: String, + consolidated_events_topic: String, } impl KafkaSettings { @@ -175,6 +218,12 @@ impl KafkaSettings { )) })?; + common_utils::fp_utils::when(self.consolidated_events_topic.is_default_or_empty(), || { + Err(ApplicationError::InvalidConfigurationValueError( + "Consolidated Events topic must not be empty".into(), + )) + })?; + Ok(()) } } @@ -192,6 +241,7 @@ pub struct KafkaProducer { audit_events_topic: String, #[cfg(feature = "payouts")] payout_analytics_topic: String, + consolidated_events_topic: String, } struct RdKafkaProducer(ThreadedProducer); @@ -233,23 +283,13 @@ impl KafkaProducer { audit_events_topic: conf.audit_events_topic.clone(), #[cfg(feature = "payouts")] payout_analytics_topic: conf.payout_analytics_topic.clone(), + consolidated_events_topic: conf.consolidated_events_topic.clone(), }) } pub fn log_event(&self, event: &T) -> MQResult<()> { router_env::logger::debug!("Logging Kafka Event {event:?}"); - let topic = match event.event_type() { - EventType::PaymentIntent => &self.intent_analytics_topic, - EventType::PaymentAttempt => &self.attempt_analytics_topic, - EventType::Refund => &self.refund_analytics_topic, - EventType::ApiLogs => &self.api_logs_topic, - EventType::ConnectorApiLogs => &self.connector_logs_topic, - EventType::OutgoingWebhookLogs => &self.outgoing_webhook_logs_topic, - EventType::Dispute => &self.dispute_analytics_topic, - EventType::AuditEvent => &self.audit_events_topic, - #[cfg(feature = "payouts")] - EventType::Payout => &self.payout_analytics_topic, - }; + let topic = self.get_topic(event.event_type()); self.producer .0 .send( @@ -281,11 +321,18 @@ impl KafkaProducer { format!("Failed to add negative attempt event {negative_event:?}") })?; }; + self.log_event(&KafkaEvent::new( &KafkaPaymentAttempt::from_storage(attempt), tenant_id.clone(), )) - .attach_printable_lazy(|| format!("Failed to add positive attempt event {attempt:?}")) + .attach_printable_lazy(|| format!("Failed to add positive attempt event {attempt:?}"))?; + + self.log_event(&KafkaConsolidatedEvent::new( + &KafkaPaymentAttemptEvent::from_storage(attempt), + tenant_id.clone(), + )) + .attach_printable_lazy(|| format!("Failed to add consolidated attempt event {attempt:?}")) } pub async fn log_payment_attempt_delete( @@ -317,11 +364,18 @@ impl KafkaProducer { format!("Failed to add negative intent event {negative_event:?}") })?; }; + self.log_event(&KafkaEvent::new( &KafkaPaymentIntent::from_storage(intent), tenant_id.clone(), )) - .attach_printable_lazy(|| format!("Failed to add positive intent event {intent:?}")) + .attach_printable_lazy(|| format!("Failed to add positive intent event {intent:?}"))?; + + self.log_event(&KafkaConsolidatedEvent::new( + &KafkaPaymentIntentEvent::from_storage(intent), + tenant_id.clone(), + )) + .attach_printable_lazy(|| format!("Failed to add consolidated intent event {intent:?}")) } pub async fn log_payment_intent_delete( @@ -353,11 +407,18 @@ impl KafkaProducer { format!("Failed to add negative refund event {negative_event:?}") })?; }; + self.log_event(&KafkaEvent::new( &KafkaRefund::from_storage(refund), tenant_id.clone(), )) - .attach_printable_lazy(|| format!("Failed to add positive refund event {refund:?}")) + .attach_printable_lazy(|| format!("Failed to add positive refund event {refund:?}"))?; + + self.log_event(&KafkaConsolidatedEvent::new( + &KafkaRefundEvent::from_storage(refund), + tenant_id.clone(), + )) + .attach_printable_lazy(|| format!("Failed to add consolidated refund event {refund:?}")) } pub async fn log_refund_delete( @@ -389,11 +450,18 @@ impl KafkaProducer { format!("Failed to add negative dispute event {negative_event:?}") })?; }; + self.log_event(&KafkaEvent::new( &KafkaDispute::from_storage(dispute), tenant_id.clone(), )) - .attach_printable_lazy(|| format!("Failed to add positive dispute event {dispute:?}")) + .attach_printable_lazy(|| format!("Failed to add positive dispute event {dispute:?}"))?; + + self.log_event(&KafkaConsolidatedEvent::new( + &KafkaDisputeEvent::from_storage(dispute), + tenant_id.clone(), + )) + .attach_printable_lazy(|| format!("Failed to add consolidated dispute event {dispute:?}")) } #[cfg(feature = "payouts")] @@ -437,6 +505,7 @@ impl KafkaProducer { EventType::AuditEvent => &self.audit_events_topic, #[cfg(feature = "payouts")] EventType::Payout => &self.payout_analytics_topic, + EventType::Consolidated => &self.consolidated_events_topic, } } } diff --git a/crates/router/src/services/kafka/dispute_event.rs b/crates/router/src/services/kafka/dispute_event.rs new file mode 100644 index 000000000000..71e0a11e04d5 --- /dev/null +++ b/crates/router/src/services/kafka/dispute_event.rs @@ -0,0 +1,77 @@ +use diesel_models::enums as storage_enums; +use masking::Secret; +use time::OffsetDateTime; + +use crate::types::storage::dispute::Dispute; + +#[serde_with::skip_serializing_none] +#[derive(serde::Serialize, Debug)] +pub struct KafkaDisputeEvent<'a> { + pub dispute_id: &'a String, + pub dispute_amount: i64, + pub currency: &'a String, + pub dispute_stage: &'a storage_enums::DisputeStage, + pub dispute_status: &'a storage_enums::DisputeStatus, + pub payment_id: &'a String, + pub attempt_id: &'a String, + pub merchant_id: &'a String, + pub connector_status: &'a String, + pub connector_dispute_id: &'a String, + pub connector_reason: Option<&'a String>, + pub connector_reason_code: Option<&'a String>, + #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + pub challenge_required_by: Option, + #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + pub connector_created_at: Option, + #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + pub connector_updated_at: Option, + #[serde(default, with = "time::serde::timestamp::milliseconds")] + pub created_at: OffsetDateTime, + #[serde(default, with = "time::serde::timestamp::milliseconds")] + pub modified_at: OffsetDateTime, + pub connector: &'a String, + pub evidence: &'a Secret, + pub profile_id: Option<&'a String>, + pub merchant_connector_id: Option<&'a String>, +} + +impl<'a> KafkaDisputeEvent<'a> { + pub fn from_storage(dispute: &'a Dispute) -> Self { + Self { + dispute_id: &dispute.dispute_id, + dispute_amount: dispute.amount.parse::().unwrap_or_default(), + currency: &dispute.currency, + dispute_stage: &dispute.dispute_stage, + dispute_status: &dispute.dispute_status, + payment_id: &dispute.payment_id, + attempt_id: &dispute.attempt_id, + merchant_id: &dispute.merchant_id, + connector_status: &dispute.connector_status, + connector_dispute_id: &dispute.connector_dispute_id, + connector_reason: dispute.connector_reason.as_ref(), + connector_reason_code: dispute.connector_reason_code.as_ref(), + challenge_required_by: dispute.challenge_required_by.map(|i| i.assume_utc()), + connector_created_at: dispute.connector_created_at.map(|i| i.assume_utc()), + connector_updated_at: dispute.connector_updated_at.map(|i| i.assume_utc()), + created_at: dispute.created_at.assume_utc(), + modified_at: dispute.modified_at.assume_utc(), + connector: &dispute.connector, + evidence: &dispute.evidence, + profile_id: dispute.profile_id.as_ref(), + merchant_connector_id: dispute.merchant_connector_id.as_ref(), + } + } +} + +impl<'a> super::KafkaMessage for KafkaDisputeEvent<'a> { + fn key(&self) -> String { + format!( + "{}_{}_{}", + self.merchant_id, self.payment_id, self.dispute_id + ) + } + + fn event_type(&self) -> crate::events::EventType { + crate::events::EventType::Dispute + } +} diff --git a/crates/router/src/services/kafka/payment_attempt_event.rs b/crates/router/src/services/kafka/payment_attempt_event.rs new file mode 100644 index 000000000000..bb4d69eda27f --- /dev/null +++ b/crates/router/src/services/kafka/payment_attempt_event.rs @@ -0,0 +1,119 @@ +// use diesel_models::enums::MandateDetails; +use common_utils::types::MinorUnit; +use diesel_models::enums as storage_enums; +use hyperswitch_domain_models::{ + mandates::MandateDetails, payments::payment_attempt::PaymentAttempt, +}; +use time::OffsetDateTime; + +#[serde_with::skip_serializing_none] +#[derive(serde::Serialize, Debug)] +pub struct KafkaPaymentAttemptEvent<'a> { + pub payment_id: &'a String, + pub merchant_id: &'a String, + pub attempt_id: &'a String, + pub status: storage_enums::AttemptStatus, + pub amount: MinorUnit, + pub currency: Option, + pub save_to_locker: Option, + pub connector: Option<&'a String>, + pub error_message: Option<&'a String>, + pub offer_amount: Option, + pub surcharge_amount: Option, + pub tax_amount: Option, + pub payment_method_id: Option<&'a String>, + pub payment_method: Option, + pub connector_transaction_id: Option<&'a String>, + pub capture_method: Option, + #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + pub capture_on: Option, + pub confirm: bool, + pub authentication_type: Option, + #[serde(with = "time::serde::timestamp::milliseconds")] + pub created_at: OffsetDateTime, + #[serde(with = "time::serde::timestamp::milliseconds")] + pub modified_at: OffsetDateTime, + #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + pub last_synced: Option, + pub cancellation_reason: Option<&'a String>, + pub amount_to_capture: Option, + pub mandate_id: Option<&'a String>, + pub browser_info: Option, + pub error_code: Option<&'a String>, + pub connector_metadata: Option, + // TODO: These types should implement copy ideally + pub payment_experience: Option<&'a storage_enums::PaymentExperience>, + pub payment_method_type: Option<&'a storage_enums::PaymentMethodType>, + pub payment_method_data: Option, + pub error_reason: Option<&'a String>, + pub multiple_capture_count: Option, + pub amount_capturable: MinorUnit, + pub merchant_connector_id: Option<&'a String>, + pub net_amount: MinorUnit, + pub unified_code: Option<&'a String>, + pub unified_message: Option<&'a String>, + pub mandate_data: Option<&'a MandateDetails>, + pub client_source: Option<&'a String>, + pub client_version: Option<&'a String>, +} + +impl<'a> KafkaPaymentAttemptEvent<'a> { + pub fn from_storage(attempt: &'a PaymentAttempt) -> Self { + Self { + payment_id: &attempt.payment_id, + merchant_id: &attempt.merchant_id, + attempt_id: &attempt.attempt_id, + status: attempt.status, + amount: attempt.amount, + currency: attempt.currency, + save_to_locker: attempt.save_to_locker, + connector: attempt.connector.as_ref(), + error_message: attempt.error_message.as_ref(), + offer_amount: attempt.offer_amount, + surcharge_amount: attempt.surcharge_amount, + tax_amount: attempt.tax_amount, + payment_method_id: attempt.payment_method_id.as_ref(), + payment_method: attempt.payment_method, + connector_transaction_id: attempt.connector_transaction_id.as_ref(), + capture_method: attempt.capture_method, + capture_on: attempt.capture_on.map(|i| i.assume_utc()), + confirm: attempt.confirm, + authentication_type: attempt.authentication_type, + created_at: attempt.created_at.assume_utc(), + modified_at: attempt.modified_at.assume_utc(), + last_synced: attempt.last_synced.map(|i| i.assume_utc()), + cancellation_reason: attempt.cancellation_reason.as_ref(), + amount_to_capture: attempt.amount_to_capture, + mandate_id: attempt.mandate_id.as_ref(), + browser_info: attempt.browser_info.as_ref().map(|v| v.to_string()), + error_code: attempt.error_code.as_ref(), + connector_metadata: attempt.connector_metadata.as_ref().map(|v| v.to_string()), + payment_experience: attempt.payment_experience.as_ref(), + payment_method_type: attempt.payment_method_type.as_ref(), + payment_method_data: attempt.payment_method_data.as_ref().map(|v| v.to_string()), + error_reason: attempt.error_reason.as_ref(), + multiple_capture_count: attempt.multiple_capture_count, + amount_capturable: attempt.amount_capturable, + merchant_connector_id: attempt.merchant_connector_id.as_ref(), + net_amount: attempt.net_amount, + unified_code: attempt.unified_code.as_ref(), + unified_message: attempt.unified_message.as_ref(), + mandate_data: attempt.mandate_data.as_ref(), + client_source: attempt.client_source.as_ref(), + client_version: attempt.client_version.as_ref(), + } + } +} + +impl<'a> super::KafkaMessage for KafkaPaymentAttemptEvent<'a> { + fn key(&self) -> String { + format!( + "{}_{}_{}", + self.merchant_id, self.payment_id, self.attempt_id + ) + } + + fn event_type(&self) -> crate::events::EventType { + crate::events::EventType::PaymentAttempt + } +} diff --git a/crates/router/src/services/kafka/payment_intent_event.rs b/crates/router/src/services/kafka/payment_intent_event.rs new file mode 100644 index 000000000000..a3fbd9ddc458 --- /dev/null +++ b/crates/router/src/services/kafka/payment_intent_event.rs @@ -0,0 +1,75 @@ +use common_utils::{id_type, types::MinorUnit}; +use diesel_models::enums as storage_enums; +use hyperswitch_domain_models::payments::PaymentIntent; +use time::OffsetDateTime; + +#[serde_with::skip_serializing_none] +#[derive(serde::Serialize, Debug)] +pub struct KafkaPaymentIntentEvent<'a> { + pub payment_id: &'a String, + pub merchant_id: &'a String, + pub status: storage_enums::IntentStatus, + pub amount: MinorUnit, + pub currency: Option, + pub amount_captured: Option, + pub customer_id: Option<&'a id_type::CustomerId>, + pub description: Option<&'a String>, + pub return_url: Option<&'a String>, + pub connector_id: Option<&'a String>, + pub statement_descriptor_name: Option<&'a String>, + pub statement_descriptor_suffix: Option<&'a String>, + #[serde(with = "time::serde::timestamp::milliseconds")] + pub created_at: OffsetDateTime, + #[serde(with = "time::serde::timestamp::milliseconds")] + pub modified_at: OffsetDateTime, + #[serde(default, with = "time::serde::timestamp::milliseconds::option")] + pub last_synced: Option, + pub setup_future_usage: Option, + pub off_session: Option, + pub client_secret: Option<&'a String>, + pub active_attempt_id: String, + pub business_country: Option, + pub business_label: Option<&'a String>, + pub attempt_count: i16, + pub payment_confirm_source: Option, +} + +impl<'a> KafkaPaymentIntentEvent<'a> { + pub fn from_storage(intent: &'a PaymentIntent) -> Self { + Self { + payment_id: &intent.payment_id, + merchant_id: &intent.merchant_id, + status: intent.status, + amount: intent.amount, + currency: intent.currency, + amount_captured: intent.amount_captured, + customer_id: intent.customer_id.as_ref(), + description: intent.description.as_ref(), + return_url: intent.return_url.as_ref(), + connector_id: intent.connector_id.as_ref(), + statement_descriptor_name: intent.statement_descriptor_name.as_ref(), + statement_descriptor_suffix: intent.statement_descriptor_suffix.as_ref(), + created_at: intent.created_at.assume_utc(), + modified_at: intent.modified_at.assume_utc(), + last_synced: intent.last_synced.map(|i| i.assume_utc()), + setup_future_usage: intent.setup_future_usage, + off_session: intent.off_session, + client_secret: intent.client_secret.as_ref(), + active_attempt_id: intent.active_attempt.get_id(), + business_country: intent.business_country, + business_label: intent.business_label.as_ref(), + attempt_count: intent.attempt_count, + payment_confirm_source: intent.payment_confirm_source, + } + } +} + +impl<'a> super::KafkaMessage for KafkaPaymentIntentEvent<'a> { + fn key(&self) -> String { + format!("{}_{}", self.merchant_id, self.payment_id) + } + + fn event_type(&self) -> crate::events::EventType { + crate::events::EventType::PaymentIntent + } +} diff --git a/crates/router/src/services/kafka/refund_event.rs b/crates/router/src/services/kafka/refund_event.rs new file mode 100644 index 000000000000..6aa80b243c11 --- /dev/null +++ b/crates/router/src/services/kafka/refund_event.rs @@ -0,0 +1,74 @@ +use common_utils::types::MinorUnit; +use diesel_models::{enums as storage_enums, refund::Refund}; +use time::OffsetDateTime; + +#[serde_with::skip_serializing_none] +#[derive(serde::Serialize, Debug)] +pub struct KafkaRefundEvent<'a> { + pub internal_reference_id: &'a String, + pub refund_id: &'a String, //merchant_reference id + pub payment_id: &'a String, + pub merchant_id: &'a String, + pub connector_transaction_id: &'a String, + pub connector: &'a String, + pub connector_refund_id: Option<&'a String>, + pub external_reference_id: Option<&'a String>, + pub refund_type: &'a storage_enums::RefundType, + pub total_amount: &'a MinorUnit, + pub currency: &'a storage_enums::Currency, + pub refund_amount: &'a MinorUnit, + pub refund_status: &'a storage_enums::RefundStatus, + pub sent_to_gateway: &'a bool, + pub refund_error_message: Option<&'a String>, + pub refund_arn: Option<&'a String>, + #[serde(default, with = "time::serde::timestamp::milliseconds")] + pub created_at: OffsetDateTime, + #[serde(default, with = "time::serde::timestamp::milliseconds")] + pub modified_at: OffsetDateTime, + pub description: Option<&'a String>, + pub attempt_id: &'a String, + pub refund_reason: Option<&'a String>, + pub refund_error_code: Option<&'a String>, +} + +impl<'a> KafkaRefundEvent<'a> { + pub fn from_storage(refund: &'a Refund) -> Self { + Self { + internal_reference_id: &refund.internal_reference_id, + refund_id: &refund.refund_id, + payment_id: &refund.payment_id, + merchant_id: &refund.merchant_id, + connector_transaction_id: &refund.connector_transaction_id, + connector: &refund.connector, + connector_refund_id: refund.connector_refund_id.as_ref(), + external_reference_id: refund.external_reference_id.as_ref(), + refund_type: &refund.refund_type, + total_amount: &refund.total_amount, + currency: &refund.currency, + refund_amount: &refund.refund_amount, + refund_status: &refund.refund_status, + sent_to_gateway: &refund.sent_to_gateway, + refund_error_message: refund.refund_error_message.as_ref(), + refund_arn: refund.refund_arn.as_ref(), + created_at: refund.created_at.assume_utc(), + modified_at: refund.updated_at.assume_utc(), + description: refund.description.as_ref(), + attempt_id: &refund.attempt_id, + refund_reason: refund.refund_reason.as_ref(), + refund_error_code: refund.refund_error_code.as_ref(), + } + } +} + +impl<'a> super::KafkaMessage for KafkaRefundEvent<'a> { + fn key(&self) -> String { + format!( + "{}_{}_{}_{}", + self.merchant_id, self.payment_id, self.attempt_id, self.refund_id + ) + } + + fn event_type(&self) -> crate::events::EventType { + crate::events::EventType::Refund + } +} From 67f017f6f035b102ce7a0102b157a884ce9d4109 Mon Sep 17 00:00:00 2001 From: Sai Harsha Vardhan <56996463+sai-harsha-vardhan@users.noreply.github.com> Date: Mon, 3 Jun 2024 16:04:12 +0530 Subject: [PATCH 10/25] feat(router): send `three_ds_requestor_url` in authentication_response for external 3ds flow (#4828) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- crates/api_models/src/payments.rs | 2 ++ crates/router/src/core/authentication.rs | 6 ++++-- .../src/core/authentication/transformers.rs | 18 ++++-------------- crates/router/src/core/payments.rs | 18 +++++++++++++++++- openapi/openapi_spec.json | 7 ++++++- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index f4e49058c9b2..cda13289aa52 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -4595,6 +4595,8 @@ pub struct PaymentsExternalAuthenticationResponse { pub three_dsserver_trans_id: Option, /// Contains the JWS object created by the ACS for the ARes message pub acs_signed_content: Option, + /// Three DS Requestor URL + pub three_ds_requestor_url: String, } #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] diff --git a/crates/router/src/core/authentication.rs b/crates/router/src/core/authentication.rs index 5acd14bb3ee2..7828473df607 100644 --- a/crates/router/src/core/authentication.rs +++ b/crates/router/src/core/authentication.rs @@ -20,13 +20,13 @@ use crate::{ #[allow(clippy::too_many_arguments)] pub async fn perform_authentication( state: &AppState, + merchant_id: String, authentication_connector: String, payment_method_data: payments::PaymentMethodData, payment_method: common_enums::PaymentMethod, billing_address: payments::Address, shipping_address: Option, browser_details: Option, - business_profile: storage::BusinessProfile, merchant_connector_account: payments_core::helpers::MerchantConnectorAccountType, amount: Option, currency: Option, @@ -38,8 +38,10 @@ pub async fn perform_authentication( threeds_method_comp_ind: payments::ThreeDsCompletionIndicator, email: Option, webhook_url: String, + three_ds_requestor_url: String, ) -> CustomResult { let router_data = transformers::construct_authentication_router_data( + merchant_id, authentication_connector.clone(), payment_method_data, payment_method, @@ -50,7 +52,6 @@ pub async fn perform_authentication( currency, message_category, device_channel, - business_profile, merchant_connector_account, authentication_data.clone(), return_url, @@ -58,6 +59,7 @@ pub async fn perform_authentication( threeds_method_comp_ind, email, webhook_url, + three_ds_requestor_url, )?; let response = utils::do_auth_connector_call(state, authentication_connector.clone(), router_data).await?; diff --git a/crates/router/src/core/authentication/transformers.rs b/crates/router/src/core/authentication/transformers.rs index e0e9ee0b5263..2255e1ff5820 100644 --- a/crates/router/src/core/authentication/transformers.rs +++ b/crates/router/src/core/authentication/transformers.rs @@ -26,6 +26,7 @@ const IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID_IN_AUTHENTICATION_FLOW: &str = #[allow(clippy::too_many_arguments)] pub fn construct_authentication_router_data( + merchant_id: String, authentication_connector: String, payment_method_data: payments::PaymentMethodData, payment_method: PaymentMethod, @@ -36,7 +37,6 @@ pub fn construct_authentication_router_data( currency: Option, message_category: types::api::authentication::MessageCategory, device_channel: payments::DeviceChannel, - business_profile: storage::BusinessProfile, merchant_connector_account: payments_helpers::MerchantConnectorAccountType, authentication_data: storage::Authentication, return_url: Option, @@ -44,18 +44,8 @@ pub fn construct_authentication_router_data( threeds_method_comp_ind: payments::ThreeDsCompletionIndicator, email: Option, webhook_url: String, + three_ds_requestor_url: String, ) -> RouterResult { - let authentication_details: api_models::admin::AuthenticationConnectorDetails = - business_profile - .authentication_connector_details - .clone() - .get_required_value("authentication_details") - .attach_printable("authentication_details not configured by the merchant")? - .parse_value("AuthenticationDetails") - .change_context(errors::ApiErrorResponse::UnprocessableEntity { - message: "Invalid data format found for authentication_details".into(), - }) - .attach_printable("Error while parsing authentication_details from merchant_account")?; let router_request = types::authentication::ConnectorAuthenticationRequestData { payment_method_data: From::from(payment_method_data), billing_address, @@ -71,14 +61,14 @@ pub fn construct_authentication_router_data( return_url, sdk_information, email, - three_ds_requestor_url: authentication_details.three_ds_requestor_url, + three_ds_requestor_url, threeds_method_comp_ind, webhook_url, }; construct_router_data( authentication_connector, payment_method, - business_profile.merchant_id.clone(), + merchant_id.clone(), types::PaymentAddress::default(), router_request, &merchant_connector_account, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 7bc0b532239e..a5f9c2a5e462 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -3918,8 +3918,23 @@ pub async fn payment_external_authentication( id: profile_id.to_string(), })?; + let authentication_details: api_models::admin::AuthenticationConnectorDetails = + business_profile + .authentication_connector_details + .clone() + .get_required_value("authentication_connector_details") + .attach_printable("authentication_connector_details not configured by the merchant")? + .parse_value("AuthenticationConnectorDetails") + .change_context(errors::ApiErrorResponse::UnprocessableEntity { + message: "Invalid data format found for authentication_connector_details".into(), + }) + .attach_printable( + "Error while parsing authentication_connector_details from business_profile", + )?; + let authentication_response = Box::pin(authentication_core::perform_authentication( &state, + business_profile.merchant_id, authentication_connector, payment_method_details.0, payment_method_details.1, @@ -3931,7 +3946,6 @@ pub async fn payment_external_authentication( })?, shipping_address.as_ref().map(|address| address.into()), browser_info, - business_profile, merchant_connector_account, Some(amount), Some(currency), @@ -3943,6 +3957,7 @@ pub async fn payment_external_authentication( req.threeds_method_comp_ind, optional_customer.and_then(|customer| customer.email.map(pii::Email::from)), webhook_url, + authentication_details.three_ds_requestor_url.clone(), )) .await?; Ok(services::ApplicationResponse::Json( @@ -3957,6 +3972,7 @@ pub async fn payment_external_authentication( acs_trans_id: authentication_response.acs_trans_id, three_dsserver_trans_id: authentication_response.three_dsserver_trans_id, acs_signed_content: authentication_response.acs_signed_content, + three_ds_requestor_url: authentication_details.three_ds_requestor_url, }, )) } diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index fe3c934f4ab1..f42481798a49 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -14594,7 +14594,8 @@ "PaymentsExternalAuthenticationResponse": { "type": "object", "required": [ - "trans_status" + "trans_status", + "three_ds_requestor_url" ], "properties": { "trans_status": { @@ -14629,6 +14630,10 @@ "type": "string", "description": "Contains the JWS object created by the ACS for the ARes message", "nullable": true + }, + "three_ds_requestor_url": { + "type": "string", + "description": "Three DS Requestor URL" } } }, From e5da133fe00b5736dc3c55bf4ee86fa77158dbe7 Mon Sep 17 00:00:00 2001 From: Hrithikesh <61539176+hrithikesh026@users.noreply.github.com> Date: Mon, 3 Jun 2024 16:21:49 +0530 Subject: [PATCH 11/25] refactor(connector): airwallex convert init payment to preprocessing (#4842) --- crates/api_models/src/enums.rs | 3 + crates/router/src/connector/airwallex.rs | 60 +-- .../src/connector/airwallex/transformers.rs | 21 +- crates/router/src/core/payments.rs | 8 + crates/router/src/core/payments/flows.rs | 1 - .../src/core/payments/flows/authorize_flow.rs | 7 +- .../.meta.json | 7 + .../Payments - Capture/.event.meta.json | 3 + .../Payments - Capture/event.test.js | 94 +++++ .../Payments - Capture/request.json | 39 ++ .../Payments - Capture/response.json | 1 + .../Payments - Create/.event.meta.json | 3 + .../Payments - Create/event.test.js | 71 ++++ .../Payments - Create/request.json | 84 ++++ .../Payments - Create/response.json | 1 + .../Payments - Retrieve/.event.meta.json | 3 + .../Payments - Retrieve/event.test.js | 71 ++++ .../Payments - Retrieve/request.json | 28 ++ .../Payments - Retrieve/response.json | 1 + .../Payments - Capture/event.test.js | 2 +- .../Payments - Capture/request.json | 2 +- .../airwallex.postman_collection.json | 396 +++++++++++++++++- 22 files changed, 851 insertions(+), 55 deletions(-) create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/.meta.json create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/.event.meta.json create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/event.test.js create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/request.json create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/response.json create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/.event.meta.json create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/event.test.js create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/request.json create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/response.json create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/.event.meta.json create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/event.test.js create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/request.json create mode 100644 postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/response.json diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 19ce82e59bb4..81e50b020e73 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -249,6 +249,9 @@ impl Connector { Self::Checkout | Self::Nmi| Self::Cybersource => true, } } + pub fn is_pre_processing_required_before_authorize(&self) -> bool { + matches!(self, Self::Airwallex) + } } #[derive( diff --git a/crates/router/src/connector/airwallex.rs b/crates/router/src/connector/airwallex.rs index ca511534b974..fbc25909489c 100644 --- a/crates/router/src/connector/airwallex.rs +++ b/crates/router/src/connector/airwallex.rs @@ -18,7 +18,7 @@ use crate::{ payments, }, events::connector_api_logs::ConnectorEvent, - headers, logger, routes, + headers, logger, services::{ self, request::{self, Mask}, @@ -27,7 +27,6 @@ use crate::{ types::{ self, api::{self, ConnectorCommon, ConnectorCommonExt}, - transformers::ForeignFrom, ErrorResponse, Response, RouterData, }, utils::{crypto, BytesExt}, @@ -123,6 +122,7 @@ impl ConnectorValidation for Airwallex { } impl api::Payment for Airwallex {} +impl api::PaymentsPreProcessing for Airwallex {} impl api::PaymentsCompleteAuthorize for Airwallex {} impl api::MandateSetup for Airwallex {} impl @@ -242,14 +242,14 @@ impl ConnectorIntegration for Airwallex { fn get_headers( &self, - req: &types::PaymentsInitRouterData, + req: &types::PaymentsPreProcessingRouterData, connectors: &settings::Connectors, ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) @@ -261,7 +261,7 @@ impl fn get_url( &self, - _req: &types::PaymentsInitRouterData, + _req: &types::PaymentsPreProcessingRouterData, connectors: &settings::Connectors, ) -> CustomResult { Ok(format!( @@ -273,7 +273,7 @@ impl fn get_request_body( &self, - req: &types::PaymentsInitRouterData, + req: &types::PaymentsPreProcessingRouterData, _connectors: &settings::Connectors, ) -> CustomResult { let req_obj = airwallex::AirwallexIntentRequest::try_from(req)?; @@ -282,16 +282,20 @@ impl fn build_request( &self, - req: &types::PaymentsInitRouterData, + req: &types::PaymentsPreProcessingRouterData, connectors: &settings::Connectors, ) -> CustomResult, errors::ConnectorError> { Ok(Some( services::RequestBuilder::new() .method(services::Method::Post) - .url(&types::PaymentsInitType::get_url(self, req, connectors)?) + .url(&types::PaymentsPreProcessingType::get_url( + self, req, connectors, + )?) .attach_default_headers() - .headers(types::PaymentsInitType::get_headers(self, req, connectors)?) - .set_body(types::PaymentsInitType::get_request_body( + .headers(types::PaymentsPreProcessingType::get_headers( + self, req, connectors, + )?) + .set_body(types::PaymentsPreProcessingType::get_request_body( self, req, connectors, )?) .build(), @@ -300,10 +304,10 @@ impl fn handle_response( &self, - data: &types::PaymentsInitRouterData, + data: &types::PaymentsPreProcessingRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: airwallex::AirwallexPaymentsResponse = res .response .parse_struct("airwallex AirwallexPaymentsResponse") @@ -335,36 +339,6 @@ impl api::PaymentAuthorize for Airwallex {} impl ConnectorIntegration for Airwallex { - async fn execute_pretasks( - &self, - router_data: &mut types::PaymentsAuthorizeRouterData, - app_state: &routes::AppState, - ) -> CustomResult<(), errors::ConnectorError> { - let integ: Box< - &(dyn ConnectorIntegration< - api::InitPayment, - types::PaymentsAuthorizeData, - types::PaymentsResponseData, - > + Send - + Sync - + 'static), - > = Box::new(&Self); - let authorize_data = &types::PaymentsInitRouterData::foreign_from(( - &router_data.to_owned(), - router_data.request.clone(), - )); - let resp = services::execute_connector_processing_step( - app_state, - integ, - authorize_data, - payments::CallConnectorAction::Trigger, - None, - ) - .await?; - router_data.reference_id = resp.reference_id; - Ok(()) - } - fn get_headers( &self, req: &types::PaymentsAuthorizeRouterData, diff --git a/crates/router/src/connector/airwallex/transformers.rs b/crates/router/src/connector/airwallex/transformers.rs index 587a14caedfd..56a6ebe2e448 100644 --- a/crates/router/src/connector/airwallex/transformers.rs +++ b/crates/router/src/connector/airwallex/transformers.rs @@ -41,13 +41,26 @@ pub struct AirwallexIntentRequest { //ID created in merchant's order system that corresponds to this PaymentIntent. merchant_order_id: String, } -impl TryFrom<&types::PaymentsInitRouterData> for AirwallexIntentRequest { +impl TryFrom<&types::PaymentsPreProcessingRouterData> for AirwallexIntentRequest { type Error = error_stack::Report; - fn try_from(item: &types::PaymentsInitRouterData) -> Result { + fn try_from(item: &types::PaymentsPreProcessingRouterData) -> Result { + // amount and currency will always be Some since PaymentsPreProcessingData is constructed using PaymentsAuthorizeData + let amount = item + .request + .amount + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "amount", + })?; + let currency = + item.request + .currency + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "currency", + })?; Ok(Self { request_id: Uuid::new_v4().to_string(), - amount: utils::to_currency_base_unit(item.request.amount, item.request.currency)?, - currency: item.request.currency, + amount: utils::to_currency_base_unit(amount, currency)?, + currency, merchant_order_id: item.connector_request_reference_id.clone(), }) } diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index a5f9c2a5e462..3988f3d4fd0d 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -1885,6 +1885,14 @@ where dyn api::Connector: services::api::ConnectorIntegration, { + if !is_operation_complete_authorize(&operation) + && connector + .connector_name + .is_pre_processing_required_before_authorize() + { + router_data = router_data.preprocessing_steps(state, connector).await?; + return Ok((router_data, should_continue_payment)); + } //TODO: For ACH transfers, if preprocessing_step is not required for connectors encountered in future, add the check let router_data_and_should_continue_payment = match payment_data.payment_method_data.clone() { Some(api_models::payments::PaymentMethodData::BankTransfer(data)) => match data.deref() { diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index bf924c25982f..158e28e69678 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -928,7 +928,6 @@ impl default_imp_for_pre_processing_steps!( connector::Aci, - connector::Airwallex, connector::Authorizedotnet, connector::Bambora, connector::Billwerk, diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs index 931ea26a9f8e..5990b29f372a 100644 --- a/crates/router/src/core/payments/flows/authorize_flow.rs +++ b/crates/router/src/core/payments/flows/authorize_flow.rs @@ -322,13 +322,14 @@ pub async fn authorize_preprocessing_steps( ), ], ); - - let authorize_router_data = helpers::router_data_type_conversion::<_, F, _, _, _, _>( + let mut authorize_router_data = helpers::router_data_type_conversion::<_, F, _, _, _, _>( resp.clone(), router_data.request.to_owned(), resp.response, ); - + if connector.connector_name == api_models::enums::Connector::Airwallex { + authorize_router_data.reference_id = resp.reference_id; + } Ok(authorize_router_data) } else { Ok(router_data.clone()) diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/.meta.json b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/.meta.json new file mode 100644 index 000000000000..e4ef30e39e8d --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/.meta.json @@ -0,0 +1,7 @@ +{ + "childrenOrder": [ + "Payments - Create", + "Payments - Capture", + "Payments - Retrieve" + ] +} diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/.event.meta.json b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/.event.meta.json new file mode 100644 index 000000000000..0731450e6b25 --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/.event.meta.json @@ -0,0 +1,3 @@ +{ + "eventOrder": ["event.test.js"] +} diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/event.test.js b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/event.test.js new file mode 100644 index 000000000000..f560d84ea730 --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/event.test.js @@ -0,0 +1,94 @@ +// 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 "succeeded" for "status" +if (jsonData?.status) { + pm.test( + "[POST]:://payments/:id/capture - Content check if value for 'status' matches 'partially_captured'", + function () { + pm.expect(jsonData.status).to.eql("partially_captured"); + }, + ); +} + +// 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); + }, + ); +} diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/request.json b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/request.json new file mode 100644 index 000000000000..9fe257ed85e6 --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/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/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/response.json b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/response.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Capture/response.json @@ -0,0 +1 @@ +[] diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/.event.meta.json b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/.event.meta.json new file mode 100644 index 000000000000..0731450e6b25 --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/.event.meta.json @@ -0,0 +1,3 @@ +{ + "eventOrder": ["event.test.js"] +} diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/event.test.js b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/event.test.js new file mode 100644 index 000000000000..d683186aa007 --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/event.test.js @@ -0,0 +1,71 @@ +// 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_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"); + }, + ); +} diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/request.json b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/request.json new file mode 100644 index 000000000000..0cc6a0477a98 --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/request.json @@ -0,0 +1,84 @@ +{ + "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": true, + "capture_method": "manual", + "capture_on": "2022-09-10T10:11:12Z", + "amount_to_capture": 6540, + "customer_id": "AirwallexCustomer", + "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", + "payment_method": "card", + "payment_method_data": { + "card": { + "card_number": "4035501000000008", + "card_exp_month": "10", + "card_exp_year": "2025", + "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" + } + } + }, + "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/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/response.json b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/response.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Create/response.json @@ -0,0 +1 @@ +[] diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/.event.meta.json b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/.event.meta.json new file mode 100644 index 000000000000..0731450e6b25 --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/.event.meta.json @@ -0,0 +1,3 @@ +{ + "eventOrder": ["event.test.js"] +} diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/event.test.js b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/event.test.js new file mode 100644 index 000000000000..ca68dd7045be --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/event.test.js @@ -0,0 +1,71 @@ +// 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 "succeeded" for "status" +if (jsonData?.status) { + pm.test( + "[POST]::/payments - Content check if value for 'status' matches 'partially_captured'", + function () { + pm.expect(jsonData.status).to.eql("partially_captured"); + }, + ); +} diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/request.json b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/request.json new file mode 100644 index 000000000000..6cd4b7d96c52 --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/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/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/response.json b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/response.json new file mode 100644 index 000000000000..fe51488c7066 --- /dev/null +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario11-Create payment with Manual Partial capture/Payments - Retrieve/response.json @@ -0,0 +1 @@ +[] diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario4-Create payment with Manual capture/Payments - Capture/event.test.js b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario4-Create payment with Manual capture/Payments - Capture/event.test.js index 2d7dbc507fb0..2681a4daa9e9 100644 --- a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario4-Create payment with Manual capture/Payments - Capture/event.test.js +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario4-Create payment with Manual capture/Payments - Capture/event.test.js @@ -88,7 +88,7 @@ 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); + pm.expect(jsonData.amount_received).to.eql(6540); }, ); } diff --git a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario4-Create payment with Manual capture/Payments - Capture/request.json b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario4-Create payment with Manual capture/Payments - Capture/request.json index 9fe257ed85e6..cceb2b55f0a7 100644 --- a/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario4-Create payment with Manual capture/Payments - Capture/request.json +++ b/postman/collection-dir/airwallex/Flow Testcases/Happy Cases/Scenario4-Create payment with Manual capture/Payments - Capture/request.json @@ -18,7 +18,7 @@ } }, "raw_json_formatted": { - "amount_to_capture": 6000, + "amount_to_capture": 6540, "statement_descriptor_name": "Joseph", "statement_descriptor_suffix": "JS" } diff --git a/postman/collection-json/airwallex.postman_collection.json b/postman/collection-json/airwallex.postman_collection.json index 3e6b467f9bd4..ce92a22c8bb1 100644 --- a/postman/collection-json/airwallex.postman_collection.json +++ b/postman/collection-json/airwallex.postman_collection.json @@ -806,6 +806,398 @@ { "name": "Happy Cases", "item": [ + { + "name": "Scenario11-Create payment with Manual Partial capture", + "item": [ + { + "name": "Payments - Create", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// 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_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\");", + " },", + " );", + "}", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "options": { + "raw": { + "language": "json" + } + }, + "raw": "{\"amount\":6540,\"currency\":\"USD\",\"confirm\":true,\"capture_method\":\"manual\",\"capture_on\":\"2022-09-10T10:11:12Z\",\"amount_to_capture\":6540,\"customer_id\":\"AirwallexCustomer\",\"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\",\"payment_method\":\"card\",\"payment_method_data\":{\"card\":{\"card_number\":\"4035501000000008\",\"card_exp_month\":\"10\",\"card_exp_year\":\"2025\",\"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\"}}" + }, + "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" + }, + "response": [] + }, + { + "name": "Payments - Capture", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// 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 \"succeeded\" for \"status\"", + "if (jsonData?.status) {", + " pm.test(", + " \"[POST]:://payments/:id/capture - Content check if value for 'status' matches 'partially_captured'\",", + " function () {", + " pm.expect(jsonData.status).to.eql(\"partially_captured\");", + " },", + " );", + "}", + "", + "// 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);", + " },", + " );", + "}", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Accept", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "options": { + "raw": { + "language": "json" + } + }, + "raw": "{\"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" + }, + "response": [] + }, + { + "name": "Payments - Retrieve", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "// 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 \"succeeded\" for \"status\"", + "if (jsonData?.status) {", + " pm.test(", + " \"[POST]::/payments - Content check if value for 'status' matches 'partially_captured'\",", + " function () {", + " pm.expect(jsonData.status).to.eql(\"partially_captured\");", + " },", + " );", + "}", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "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" + }, + "response": [] + } + ] + }, { "name": "Scenario1-Create payment with confirm true", "item": [ @@ -2050,7 +2442,7 @@ " pm.test(", " \"[POST]::/payments:id/capture - Content check if value for 'amount_received' matches '6000'\",", " function () {", - " pm.expect(jsonData.amount_received).to.eql(6000);", + " pm.expect(jsonData.amount_received).to.eql(6540);", " },", " );", "}", @@ -2079,7 +2471,7 @@ "language": "json" } }, - "raw": "{\"amount_to_capture\":6000,\"statement_descriptor_name\":\"Joseph\",\"statement_descriptor_suffix\":\"JS\"}" + "raw": "{\"amount_to_capture\":6540,\"statement_descriptor_name\":\"Joseph\",\"statement_descriptor_suffix\":\"JS\"}" }, "url": { "raw": "{{baseUrl}}/payments/:id/capture", From a1788b8da942f0e32a80b37eac4eecece2bef77d Mon Sep 17 00:00:00 2001 From: DEEPANSHU BANSAL <41580413+deepanshu-iiitu@users.noreply.github.com> Date: Mon, 3 Jun 2024 16:37:37 +0530 Subject: [PATCH 12/25] feat(connector): [AUTHORIZEDOTNET] Support payment_method_id in recurring mandate payment (#4841) --- .../connector/authorizedotnet/transformers.rs | 106 +++++++++--------- 1 file changed, 54 insertions(+), 52 deletions(-) diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs index b281d0a0a773..15aedad7599d 100644 --- a/crates/router/src/connector/authorizedotnet/transformers.rs +++ b/crates/router/src/connector/authorizedotnet/transformers.rs @@ -1,16 +1,15 @@ use common_utils::{ errors::CustomResult, ext_traits::{Encode, ValueExt}, - id_type, pii, }; use error_stack::ResultExt; use masking::{ExposeInterface, PeekInterface, Secret, StrongSecret}; +use rand::distributions::{Alphanumeric, DistString}; use serde::{Deserialize, Serialize}; use crate::{ connector::utils::{ - self, missing_field_err, CardData, PaymentsSyncRequestData, RefundsRequestData, RouterData, - WalletData, + self, CardData, PaymentsSyncRequestData, RefundsRequestData, RouterData, WalletData, }, core::errors, services, @@ -179,7 +178,7 @@ struct PaymentProfileDetails { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct CustomerDetails { - id: id_type::CustomerId, + id: String, } #[derive(Debug, Serialize)] @@ -273,10 +272,7 @@ pub struct AuthorizedotnetZeroMandateRequest { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct Profile { - merchant_customer_id: id_type::CustomerId, - #[serde(skip_serializing_if = "Option::is_none")] - description: Option, - email: Option, + description: String, payment_profiles: PaymentProfiles, } @@ -318,12 +314,8 @@ impl TryFrom<&types::SetupMandateRouterData> for CreateCustomerProfileRequest { create_customer_profile_request: AuthorizedotnetZeroMandateRequest { merchant_authentication, profile: Profile { - merchant_customer_id: item - .customer_id - .clone() - .ok_or_else(missing_field_err("customer_id"))?, - description: item.description.clone(), - email: item.request.email.clone(), + //The payment ID is included in the description because the connector requires unique description when creating a mandate. + description: item.payment_id.clone(), payment_profiles: PaymentProfiles { customer_type: CustomerType::Individual, payment: PaymentDetails::CreditCard(CreditCardDetails { @@ -393,16 +385,18 @@ impl response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, redirection_data: None, - mandate_reference: item.response.customer_profile_id.map(|mandate_id| { - types::MandateReference { - connector_mandate_id: Some(mandate_id), - payment_method_id: item + mandate_reference: item.response.customer_profile_id.map( + |customer_profile_id| types::MandateReference { + connector_mandate_id: item .response .customer_payment_profile_id_list .first() - .cloned(), - } - }), + .map(|payment_profile_id| { + format!("{customer_profile_id}-{payment_profile_id}") + }), + payment_method_id: None, + }, + ), connector_metadata: None, network_txn_id: None, connector_response_reference_id: None, @@ -635,27 +629,24 @@ impl api_models::payments::ConnectorMandateReferenceId, ), ) -> Result { + let mandate_id = connector_mandate_id + .connector_mandate_id + .ok_or(errors::ConnectorError::MissingConnectorMandateID)?; Ok(Self { transaction_type: TransactionType::try_from(item.router_data.request.capture_method)?, amount: item.amount, currency_code: item.router_data.request.currency, payment: None, - profile: Some(ProfileDetails::CustomerProfileDetails( - CustomerProfileDetails { - customer_profile_id: Secret::from( - connector_mandate_id - .connector_mandate_id - .ok_or(errors::ConnectorError::MissingConnectorMandateID)?, - ), - payment_profile: PaymentProfileDetails { - payment_profile_id: Secret::from( - connector_mandate_id - .payment_method_id - .ok_or(errors::ConnectorError::MissingConnectorMandateID)?, - ), - }, - }, - )), + profile: mandate_id + .split_once('-') + .map(|(customer_profile_id, payment_profile_id)| { + ProfileDetails::CustomerProfileDetails(CustomerProfileDetails { + customer_profile_id: Secret::from(customer_profile_id.to_string()), + payment_profile: PaymentProfileDetails { + payment_profile_id: Secret::from(payment_profile_id.to_string()), + }, + }) + }), order: Order { description: item.router_data.connector_request_reference_id.clone(), }, @@ -709,11 +700,13 @@ impl create_profile: true, })), Some(CustomerDetails { - id: item - .router_data - .customer_id - .clone() - .ok_or_else(missing_field_err("customer_id"))?, + //The payment ID is included in the customer details because the connector requires unique customer information with a length of fewer than 20 characters when creating a mandate. + //If the length exceeds 20 characters, a random alphanumeric string is used instead. + id: if item.router_data.payment_id.len() <= 20 { + item.router_data.payment_id.clone() + } else { + Alphanumeric.sample_string(&mut rand::thread_rng(), 20) + }, }), ) } else { @@ -1087,6 +1080,24 @@ impl .and_then(|x| x.secure_acceptance_url.to_owned()); let redirection_data = url.map(|url| services::RedirectForm::from((url, services::Method::Get))); + let mandate_reference = item.response.profile_response.map(|profile_response| { + let payment_profile_id = profile_response + .customer_payment_profile_id_list + .and_then(|customer_payment_profile_id_list| { + customer_payment_profile_id_list.first().cloned() + }); + types::MandateReference { + connector_mandate_id: profile_response.customer_profile_id.and_then( + |customer_profile_id| { + payment_profile_id.map(|payment_profile_id| { + format!("{customer_profile_id}-{payment_profile_id}") + }) + }, + ), + payment_method_id: None, + } + }); + Ok(Self { status, response: match error { @@ -1096,16 +1107,7 @@ impl transaction_response.transaction_id.clone(), ), redirection_data, - mandate_reference: item.response.profile_response.map( - |profile_response| types::MandateReference { - connector_mandate_id: profile_response.customer_profile_id, - payment_method_id: profile_response - .customer_payment_profile_id_list - .and_then(|customer_payment_profile_id_list| { - customer_payment_profile_id_list.first().cloned() - }), - }, - ), + mandate_reference, connector_metadata: metadata, network_txn_id: transaction_response .network_trans_id From 15d6c3e846a77dec6b6a5165d86044a9b9fd52f1 Mon Sep 17 00:00:00 2001 From: Jagan Date: Mon, 3 Jun 2024 17:57:30 +0530 Subject: [PATCH 13/25] feat(multitenancy): add support for multitenancy and handle the same in router, producer, consumer, drainer and analytics (#4630) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: Arun Raj M --- config/config.example.toml | 6 + config/deployments/env_specific.toml | 7 +- config/development.toml | 6 + config/docker_compose.toml | 6 + crates/analytics/src/lib.rs | 8 +- crates/analytics/src/sqlx.rs | 14 +- crates/common_utils/src/consts.rs | 3 + crates/common_utils/src/lib.rs | 23 ++ crates/drainer/src/connection.rs | 17 +- crates/drainer/src/handler.rs | 77 +++--- crates/drainer/src/health_check.rs | 48 ++-- crates/drainer/src/lib.rs | 13 +- crates/drainer/src/main.rs | 19 +- crates/drainer/src/secrets_transformers.rs | 1 + crates/drainer/src/services.rs | 20 +- crates/drainer/src/settings.rs | 52 ++++- .../src/errors/api_error_response.rs | 10 + crates/redis_interface/src/commands.rs | 100 +++++--- crates/redis_interface/src/lib.rs | 31 ++- crates/router/src/bin/scheduler.rs | 72 ++++-- .../src/compatibility/stripe/customers.rs | 2 +- .../router/src/compatibility/stripe/errors.rs | 7 +- crates/router/src/compatibility/wrap.rs | 7 +- crates/router/src/configs/defaults.rs | 1 - .../src/configs/secrets_transformers.rs | 1 + crates/router/src/configs/settings.rs | 41 +++- crates/router/src/connector/nuvei.rs | 2 +- crates/router/src/connector/shift4.rs | 2 +- crates/router/src/connector/square.rs | 2 +- crates/router/src/connector/wise.rs | 2 +- crates/router/src/core/admin.rs | 46 ++-- crates/router/src/core/api_keys.rs | 12 +- crates/router/src/core/api_locking.rs | 6 +- crates/router/src/core/authentication.rs | 8 +- .../router/src/core/authentication/utils.rs | 10 +- crates/router/src/core/blocklist.rs | 10 +- .../router/src/core/blocklist/transformers.rs | 4 +- crates/router/src/core/blocklist/utils.rs | 20 +- crates/router/src/core/cache.rs | 4 +- crates/router/src/core/cards_info.rs | 2 +- crates/router/src/core/conditional_config.rs | 8 +- crates/router/src/core/configs.rs | 10 +- .../router/src/core/connector_onboarding.rs | 10 +- .../src/core/connector_onboarding/paypal.rs | 16 +- crates/router/src/core/currency.rs | 6 +- crates/router/src/core/customers.rs | 12 +- crates/router/src/core/disputes.rs | 16 +- .../router/src/core/disputes/transformers.rs | 8 +- crates/router/src/core/files.rs | 8 +- crates/router/src/core/files/helpers.rs | 12 +- crates/router/src/core/fraud_check.rs | 16 +- crates/router/src/core/fraud_check/flows.rs | 4 +- .../core/fraud_check/flows/checkout_flow.rs | 8 +- .../fraud_check/flows/fulfillment_flow.rs | 4 +- .../core/fraud_check/flows/record_return.rs | 8 +- .../src/core/fraud_check/flows/sale_flow.rs | 8 +- .../fraud_check/flows/transaction_flow.rs | 8 +- .../router/src/core/fraud_check/operation.rs | 10 +- .../fraud_check/operation/fraud_check_post.rs | 10 +- .../fraud_check/operation/fraud_check_pre.rs | 8 +- crates/router/src/core/gsm.rs | 10 +- crates/router/src/core/health_check.rs | 2 +- crates/router/src/core/locker_migration.rs | 7 +- crates/router/src/core/mandate.rs | 14 +- crates/router/src/core/mandate/helpers.rs | 4 +- crates/router/src/core/payment_link.rs | 10 +- crates/router/src/core/payment_methods.rs | 6 +- .../router/src/core/payment_methods/cards.rs | 60 ++--- .../surcharge_decision_configs.rs | 8 +- .../router/src/core/payment_methods/vault.rs | 21 +- crates/router/src/core/payments.rs | 79 +++---- .../router/src/core/payments/access_token.rs | 6 +- .../src/core/payments/conditional_configs.rs | 6 +- crates/router/src/core/payments/customers.rs | 6 +- crates/router/src/core/payments/flows.rs | 16 +- .../src/core/payments/flows/approve_flow.rs | 10 +- .../src/core/payments/flows/authorize_flow.rs | 18 +- .../src/core/payments/flows/cancel_flow.rs | 10 +- .../src/core/payments/flows/capture_flow.rs | 10 +- .../payments/flows/complete_authorize_flow.rs | 16 +- .../flows/incremental_authorization_flow.rs | 10 +- .../src/core/payments/flows/psync_flow.rs | 14 +- .../src/core/payments/flows/reject_flow.rs | 10 +- .../src/core/payments/flows/session_flow.rs | 23 +- .../core/payments/flows/setup_mandate_flow.rs | 14 +- crates/router/src/core/payments/helpers.rs | 57 +++-- crates/router/src/core/payments/operations.rs | 48 ++-- .../payments/operations/payment_approve.rs | 6 +- .../payments/operations/payment_cancel.rs | 6 +- .../payments/operations/payment_capture.rs | 6 +- .../operations/payment_complete_authorize.rs | 14 +- .../payments/operations/payment_confirm.rs | 22 +- .../payments/operations/payment_create.rs | 20 +- .../payments/operations/payment_reject.rs | 6 +- .../payments/operations/payment_response.rs | 34 +-- .../payments/operations/payment_session.rs | 12 +- .../core/payments/operations/payment_start.rs | 12 +- .../payments/operations/payment_status.rs | 16 +- .../payments/operations/payment_update.rs | 14 +- .../payments_incremental_authorization.rs | 12 +- crates/router/src/core/payments/retry.rs | 12 +- crates/router/src/core/payments/routing.rs | 56 +++-- .../router/src/core/payments/tokenization.rs | 8 +- .../router/src/core/payments/transformers.rs | 28 +-- crates/router/src/core/payments/types.rs | 6 +- crates/router/src/core/payouts.rs | 52 ++--- .../router/src/core/payouts/access_token.rs | 8 +- crates/router/src/core/payouts/helpers.rs | 16 +- crates/router/src/core/payouts/retry.rs | 12 +- crates/router/src/core/payouts/validator.rs | 4 +- crates/router/src/core/pm_auth.rs | 23 +- crates/router/src/core/poll.rs | 6 +- crates/router/src/core/refunds.rs | 32 +-- crates/router/src/core/routing.rs | 22 +- .../src/core/surcharge_decision_config.rs | 8 +- crates/router/src/core/user.rs | 85 +++---- .../src/core/user/dashboard_metadata.rs | 14 +- crates/router/src/core/user/sample_data.rs | 6 +- crates/router/src/core/user_role.rs | 18 +- crates/router/src/core/user_role/role.rs | 18 +- crates/router/src/core/utils.rs | 20 +- crates/router/src/core/verification.rs | 6 +- crates/router/src/core/verification/utils.rs | 4 +- crates/router/src/core/verify_connector.rs | 4 +- crates/router/src/core/webhooks.rs | 46 ++-- .../src/core/webhooks/webhook_events.rs | 10 +- crates/router/src/db/api_keys.rs | 19 +- crates/router/src/db/kafka_store.rs | 3 +- .../src/db/merchant_connector_account.rs | 10 +- crates/router/src/lib.rs | 2 +- crates/router/src/routes.rs | 3 +- crates/router/src/routes/app.rs | 221 +++++++++++++----- crates/router/src/routes/customers.rs | 2 +- .../router/src/routes/dummy_connector/core.rs | 16 +- .../src/routes/dummy_connector/utils.rs | 12 +- crates/router/src/routes/health.rs | 4 +- crates/router/src/routes/payment_methods.rs | 35 ++- crates/router/src/routes/payments.rs | 5 +- crates/router/src/routes/recon.rs | 10 +- crates/router/src/services.rs | 22 +- crates/router/src/services/api.rs | 70 ++++-- crates/router/src/services/api/client.rs | 8 +- crates/router/src/services/authentication.rs | 104 +++++---- .../src/services/authentication/blacklist.rs | 26 +-- crates/router/src/services/authorization.rs | 12 +- .../src/services/authorization/roles.rs | 4 +- crates/router/src/services/email/types.rs | 4 +- crates/router/src/services/pm_auth.rs | 4 +- crates/router/src/types/api/mandates.rs | 6 +- .../router/src/types/api/verify_connector.rs | 6 +- .../src/types/api/verify_connector/paypal.rs | 4 +- crates/router/src/types/api/webhooks.rs | 2 +- crates/router/src/types/domain/user.rs | 45 ++-- .../src/types/domain/user/decision_manager.rs | 24 +- .../src/types/storage/payment_attempt.rs | 27 ++- crates/router/src/utils.rs | 4 +- .../router/src/utils/connector_onboarding.rs | 8 +- .../src/utils/connector_onboarding/paypal.rs | 4 +- crates/router/src/utils/currency.rs | 34 +-- crates/router/src/utils/user.rs | 20 +- .../src/utils/user/dashboard_metadata.rs | 14 +- crates/router/src/utils/user/sample_data.rs | 4 +- .../router/src/utils/user/two_factor_auth.rs | 16 +- crates/router/src/utils/user_role.rs | 10 +- crates/router/src/workflows/api_key_expiry.rs | 10 +- .../attach_payout_account_workflow.rs | 8 +- .../src/workflows/outgoing_webhook_retry.rs | 10 +- crates/router/src/workflows/payment_sync.rs | 12 +- crates/router/src/workflows/refund_router.rs | 8 +- crates/router/src/workflows/tokenized_data.rs | 8 +- crates/router/tests/cache.rs | 36 ++- crates/router/tests/connectors/aci.rs | 22 +- crates/router/tests/connectors/utils.rs | 52 ++++- crates/router/tests/payments.rs | 12 +- crates/router/tests/payments2.rs | 12 +- crates/router/tests/services.rs | 14 +- crates/scheduler/src/consumer.rs | 63 +++-- crates/scheduler/src/consumer/workflows.rs | 4 +- crates/scheduler/src/errors.rs | 2 + crates/scheduler/src/producer.rs | 29 ++- crates/scheduler/src/scheduler.rs | 36 ++- crates/scheduler/src/utils.rs | 19 +- crates/storage_impl/src/config.rs | 24 ++ crates/storage_impl/src/database/store.rs | 52 +++-- crates/storage_impl/src/lib.rs | 72 +++--- crates/storage_impl/src/redis/cache.rs | 168 ++++++++++--- crates/storage_impl/src/redis/pub_sub.rs | 62 ++++- loadtest/config/development.toml | 6 + 188 files changed, 2261 insertions(+), 1415 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index 5d40d0e55ef9..8aa0ca9e52f2 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -629,3 +629,9 @@ disputes = "hyperswitch-dispute-events" [saved_payment_methods] sdk_eligible_payment_methods = "card" + +[multitenancy] +enabled = false + +[multitenancy.tenants] +public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = ""} # schema -> Postgres db schema, redis_key_prefix -> redis key distinguisher, base_url -> url of the tenant \ No newline at end of file diff --git a/config/deployments/env_specific.toml b/config/deployments/env_specific.toml index 7215e1931a40..a097e1b66dcd 100644 --- a/config/deployments/env_specific.toml +++ b/config/deployments/env_specific.toml @@ -230,7 +230,6 @@ recon_admin_api_key = "recon_test_admin" # recon_admin API key for recon authent # Server configuration [server] -base_url = "https://server_base_url" workers = 8 port = 8080 host = "127.0.0.1" @@ -253,3 +252,9 @@ encryption_manager = "aws_kms" # Encryption manager client to be used [encryption_management.aws_kms] key_id = "kms_key_id" # The AWS key ID used by the KMS SDK for decrypting data. region = "kms_region" # The AWS region used by the KMS SDK for decrypting data. + +[multitenancy] +enabled = false + +[multitenancy.tenants] +public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = ""} \ No newline at end of file diff --git a/config/development.toml b/config/development.toml index 496ce6477a8d..d12a667b6315 100644 --- a/config/development.toml +++ b/config/development.toml @@ -628,3 +628,9 @@ disputes = "hyperswitch-dispute-events" [saved_payment_methods] sdk_eligible_payment_methods = "card" + +[multitenancy] +enabled = false + +[multitenancy.tenants] +public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = ""} \ No newline at end of file diff --git a/config/docker_compose.toml b/config/docker_compose.toml index b94b5c8afbb6..3f6c9523e933 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -492,3 +492,9 @@ disputes = "hyperswitch-dispute-events" [saved_payment_methods] sdk_eligible_payment_methods = "card" + +[multitenancy] +enabled = false + +[multitenancy.tenants] +public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = ""} \ No newline at end of file diff --git a/crates/analytics/src/lib.rs b/crates/analytics/src/lib.rs index 1deca1e07519..f658f6790972 100644 --- a/crates/analytics/src/lib.rs +++ b/crates/analytics/src/lib.rs @@ -601,20 +601,20 @@ impl AnalyticsProvider { } } - pub async fn from_conf(config: &AnalyticsConfig) -> Self { + pub async fn from_conf(config: &AnalyticsConfig, tenant: &str) -> Self { match config { - AnalyticsConfig::Sqlx { sqlx } => Self::Sqlx(SqlxClient::from_conf(sqlx).await), + AnalyticsConfig::Sqlx { sqlx } => Self::Sqlx(SqlxClient::from_conf(sqlx, tenant).await), AnalyticsConfig::Clickhouse { clickhouse } => Self::Clickhouse(ClickhouseClient { config: Arc::new(clickhouse.clone()), }), AnalyticsConfig::CombinedCkh { sqlx, clickhouse } => Self::CombinedCkh( - SqlxClient::from_conf(sqlx).await, + SqlxClient::from_conf(sqlx, tenant).await, ClickhouseClient { config: Arc::new(clickhouse.clone()), }, ), AnalyticsConfig::CombinedSqlx { sqlx, clickhouse } => Self::CombinedSqlx( - SqlxClient::from_conf(sqlx).await, + SqlxClient::from_conf(sqlx, tenant).await, ClickhouseClient { config: Arc::new(clickhouse.clone()), }, diff --git a/crates/analytics/src/sqlx.rs b/crates/analytics/src/sqlx.rs index d3cb24a00c26..3a1b7f2d4685 100644 --- a/crates/analytics/src/sqlx.rs +++ b/crates/analytics/src/sqlx.rs @@ -4,12 +4,14 @@ use api_models::{ analytics::refunds::RefundType, enums::{DisputeStage, DisputeStatus}, }; -use common_utils::errors::{CustomResult, ParsingError}; +use common_utils::{ + errors::{CustomResult, ParsingError}, + DbConnectionParams, +}; use diesel_models::enums::{ AttemptStatus, AuthenticationType, Currency, PaymentMethod, RefundStatus, }; use error_stack::ResultExt; -use masking::PeekInterface; use sqlx::{ postgres::{PgArgumentBuffer, PgPoolOptions, PgRow, PgTypeInfo, PgValueRef}, Decode, Encode, @@ -49,12 +51,8 @@ impl Default for SqlxClient { } impl SqlxClient { - pub async fn from_conf(conf: &Database) -> Self { - let password = &conf.password.peek(); - let database_url = format!( - "postgres://{}:{}@{}:{}/{}", - conf.username, password, conf.host, conf.port, conf.dbname - ); + pub async fn from_conf(conf: &Database, schema: &str) -> Self { + let database_url = conf.get_database_url(schema); #[allow(clippy::expect_used)] let pool = PgPoolOptions::new() .max_connections(conf.pool_size) diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs index 0ea826d15cdd..0fe5cd7d7c7b 100644 --- a/crates/common_utils/src/consts.rs +++ b/crates/common_utils/src/consts.rs @@ -84,6 +84,9 @@ pub const DEFAULT_TTL_FOR_EXTENDED_CARD_INFO: u16 = 15 * 60; /// Max ttl for Extended card info in redis (in seconds) pub const MAX_TTL_FOR_EXTENDED_CARD_INFO: u16 = 60 * 60 * 2; +/// Default tenant to be used when multitenancy is disabled +pub const DEFAULT_TENANT: &str = "public"; + /// Max Length for MerchantReferenceId pub const MAX_ALLOWED_MERCHANT_REFERENCE_ID_LENGTH: u8 = 64; diff --git a/crates/common_utils/src/lib.rs b/crates/common_utils/src/lib.rs index d77442ad40f1..4e515e3d6a74 100644 --- a/crates/common_utils/src/lib.rs +++ b/crates/common_utils/src/lib.rs @@ -2,6 +2,8 @@ #![warn(missing_docs, missing_debug_implementations)] #![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR" ), "/", "README.md"))] +use masking::{PeekInterface, Secret}; + use crate::{ consts::ID_LENGTH, id_type::{CustomerId, MerchantReferenceId}, @@ -224,6 +226,27 @@ pub fn generate_time_ordered_id(prefix: &str) -> String { format!("{prefix}_{}", uuid::Uuid::now_v7().as_simple()) } +#[allow(missing_docs)] +pub trait DbConnectionParams { + fn get_username(&self) -> &str; + fn get_password(&self) -> Secret; + fn get_host(&self) -> &str; + fn get_port(&self) -> u16; + fn get_dbname(&self) -> &str; + fn get_database_url(&self, schema: &str) -> String { + format!( + "postgres://{}:{}@{}:{}/{}?application_name={}&options=-c search_path%3D{}", + self.get_username(), + self.get_password().peek(), + self.get_host(), + self.get_port(), + self.get_dbname(), + schema, + schema, + ) + } +} + #[cfg(test)] mod nanoid_tests { #![allow(clippy::unwrap_used)] diff --git a/crates/drainer/src/connection.rs b/crates/drainer/src/connection.rs index c539e9a734ce..ec3bc44973b6 100644 --- a/crates/drainer/src/connection.rs +++ b/crates/drainer/src/connection.rs @@ -1,6 +1,6 @@ use bb8::PooledConnection; +use common_utils::DbConnectionParams; use diesel::PgConnection; -use masking::PeekInterface; use crate::{settings::Database, Settings}; @@ -18,15 +18,12 @@ pub async fn redis_connection(conf: &Settings) -> redis_interface::RedisConnecti /// /// Will panic if could not create a db pool #[allow(clippy::expect_used)] -pub async fn diesel_make_pg_pool(database: &Database, _test_transaction: bool) -> PgPool { - let database_url = format!( - "postgres://{}:{}@{}:{}/{}", - database.username, - database.password.peek(), - database.host, - database.port, - database.dbname - ); +pub async fn diesel_make_pg_pool( + database: &Database, + _test_transaction: bool, + schema: &str, +) -> PgPool { + let database_url = database.get_database_url(schema); let manager = async_bb8_diesel::ConnectionManager::::new(database_url); let pool = bb8::Pool::builder() .max_size(database.pool_size) diff --git a/crates/drainer/src/handler.rs b/crates/drainer/src/handler.rs index 35ad467d5feb..77aefb422aff 100644 --- a/crates/drainer/src/handler.rs +++ b/crates/drainer/src/handler.rs @@ -1,4 +1,7 @@ -use std::sync::{atomic, Arc}; +use std::{ + collections::HashMap, + sync::{atomic, Arc}, +}; use router_env::tracing::Instrument; use tokio::{ @@ -31,12 +34,12 @@ pub struct HandlerInner { loop_interval: Duration, active_tasks: Arc, conf: DrainerSettings, - store: Arc, + stores: HashMap>, running: Arc, } impl Handler { - pub fn from_conf(conf: DrainerSettings, store: Arc) -> Self { + pub fn from_conf(conf: DrainerSettings, stores: HashMap>) -> Self { let shutdown_interval = Duration::from_millis(conf.shutdown_interval.into()); let loop_interval = Duration::from_millis(conf.loop_interval.into()); @@ -49,7 +52,7 @@ impl Handler { loop_interval, active_tasks, conf, - store, + stores, running, }; @@ -68,21 +71,23 @@ impl Handler { while self.running.load(atomic::Ordering::SeqCst) { metrics::DRAINER_HEALTH.add(&metrics::CONTEXT, 1, &[]); - if self.store.is_stream_available(stream_index).await { - let _task_handle = tokio::spawn( - drainer_handler( - self.store.clone(), - stream_index, - self.conf.max_read_count, - self.active_tasks.clone(), - jobs_picked.clone(), - ) - .in_current_span(), - ); + for store in self.stores.values() { + if store.is_stream_available(stream_index).await { + let _task_handle = tokio::spawn( + drainer_handler( + store.clone(), + stream_index, + self.conf.max_read_count, + self.active_tasks.clone(), + jobs_picked.clone(), + ) + .in_current_span(), + ); + } } stream_index = utils::increment_stream_index( (stream_index, jobs_picked.clone()), - self.store.config.drainer_num_partitions, + self.conf.num_partitions, ) .await; time::sleep(self.loop_interval).await; @@ -116,18 +121,33 @@ impl Handler { pub fn spawn_error_handlers(&self, tx: mpsc::Sender<()>) -> errors::DrainerResult<()> { let (redis_error_tx, redis_error_rx) = oneshot::channel(); + let redis_conn_clone = self + .stores + .values() + .next() + .map(|store| store.redis_conn.clone()); + match redis_conn_clone { + None => { + logger::error!("No redis connection found"); + Err( + errors::DrainerError::UnexpectedError("No redis connection found".to_string()) + .into(), + ) + } + Some(redis_conn_clone) => { + // Spawn a task to monitor if redis is down or not + let _task_handle = tokio::spawn( + async move { redis_conn_clone.on_error(redis_error_tx).await } + .in_current_span(), + ); - let redis_conn_clone = self.store.redis_conn.clone(); - - // Spawn a task to monitor if redis is down or not - let _task_handle = tokio::spawn( - async move { redis_conn_clone.on_error(redis_error_tx).await }.in_current_span(), - ); - - //Spawns a task to send shutdown signal if redis goes down - let _task_handle = tokio::spawn(redis_error_receiver(redis_error_rx, tx).in_current_span()); + //Spawns a task to send shutdown signal if redis goes down + let _task_handle = + tokio::spawn(redis_error_receiver(redis_error_rx, tx).in_current_span()); - Ok(()) + Ok(()) + } + } } } @@ -208,7 +228,10 @@ async fn drainer( }; // parse_stream_entries returns error if no entries is found, handle it - let entries = utils::parse_stream_entries(&stream_read, stream_name)?; + let entries = utils::parse_stream_entries( + &stream_read, + store.redis_conn.add_prefix(stream_name).as_str(), + )?; let read_count = entries.len(); metrics::JOBS_PICKED_PER_STREAM.add( diff --git a/crates/drainer/src/health_check.rs b/crates/drainer/src/health_check.rs index 443cb5b6f3fb..10514108991b 100644 --- a/crates/drainer/src/health_check.rs +++ b/crates/drainer/src/health_check.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; use actix_web::{web, Scope}; use async_bb8_diesel::{AsyncConnection, AsyncRunQueryDsl}; @@ -8,9 +8,9 @@ use error_stack::ResultExt; use router_env::{instrument, logger, tracing}; use crate::{ - connection::{pg_connection, redis_connection}, + connection::pg_connection, errors::HealthCheckError, - services::{self, Store}, + services::{self, log_and_return_error_response, Store}, Settings, }; @@ -20,10 +20,10 @@ pub const TEST_STREAM_DATA: &[(&str, &str)] = &[("data", "sample_data")]; pub struct Health; impl Health { - pub fn server(conf: Settings, store: Arc) -> Scope { + pub fn server(conf: Settings, stores: HashMap>) -> Scope { web::scope("health") .app_data(web::Data::new(conf)) - .app_data(web::Data::new(store)) + .app_data(web::Data::new(stores)) .service(web::resource("").route(web::get().to(health))) .service(web::resource("/ready").route(web::get().to(deep_health_check))) } @@ -38,25 +38,35 @@ pub async fn health() -> impl actix_web::Responder { #[instrument(skip_all)] pub async fn deep_health_check( conf: web::Data, - store: web::Data>, + stores: web::Data>>, ) -> impl actix_web::Responder { - match deep_health_check_func(conf, store).await { - Ok(response) => services::http_response_json( - serde_json::to_string(&response) + let mut deep_health_res = HashMap::new(); + for (tenant, store) in stores.iter() { + logger::info!("Tenant: {:?}", tenant); + + let response = match deep_health_check_func(conf.clone(), store).await { + Ok(response) => serde_json::to_string(&response) .map_err(|err| { logger::error!(serialization_error=?err); }) .unwrap_or_default(), - ), - - Err(err) => services::log_and_return_error_response(err), + Err(err) => return log_and_return_error_response(err), + }; + deep_health_res.insert(tenant.clone(), response); } + services::http_response_json( + serde_json::to_string(&deep_health_res) + .map_err(|err| { + logger::error!(serialization_error=?err); + }) + .unwrap_or_default(), + ) } #[instrument(skip_all)] pub async fn deep_health_check_func( conf: web::Data, - store: web::Data>, + store: &Arc, ) -> Result> { logger::info!("Deep health check was called"); @@ -146,8 +156,11 @@ impl HealthCheckInterface for Store { Ok(()) } - async fn health_check_redis(&self, conf: &Settings) -> CustomResult<(), HealthCheckRedisError> { - let redis_conn = redis_connection(conf).await; + async fn health_check_redis( + &self, + _conf: &Settings, + ) -> CustomResult<(), HealthCheckRedisError> { + let redis_conn = self.redis_conn.clone(); redis_conn .serialize_and_set_key_with_expiry("test_key", "test_value", 30) @@ -181,15 +194,14 @@ impl HealthCheckInterface for Store { logger::debug!("Stream append succeeded"); - let output = self - .redis_conn + let output = redis_conn .stream_read_entries(TEST_STREAM_NAME, "0-0", Some(10)) .await .change_context(HealthCheckRedisError::StreamReadFailed)?; logger::debug!("Stream read succeeded"); let (_, id_to_trim) = output - .get(TEST_STREAM_NAME) + .get(&redis_conn.add_prefix(TEST_STREAM_NAME)) .and_then(|entries| { entries .last() diff --git a/crates/drainer/src/lib.rs b/crates/drainer/src/lib.rs index cb2b55d202f9..5b67640663c6 100644 --- a/crates/drainer/src/lib.rs +++ b/crates/drainer/src/lib.rs @@ -10,7 +10,7 @@ pub mod settings; mod stream; mod types; mod utils; -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; mod secrets_transformers; use actix_web::dev::Server; @@ -30,8 +30,11 @@ use crate::{ connection::pg_connection, services::Store, settings::DrainerSettings, types::StreamData, }; -pub async fn start_drainer(store: Arc, conf: DrainerSettings) -> errors::DrainerResult<()> { - let drainer_handler = handler::Handler::from_conf(conf, store); +pub async fn start_drainer( + stores: HashMap>, + conf: DrainerSettings, +) -> errors::DrainerResult<()> { + let drainer_handler = handler::Handler::from_conf(conf, stores); let (tx, rx) = mpsc::channel::<()>(1); @@ -59,11 +62,11 @@ pub async fn start_drainer(store: Arc, conf: DrainerSettings) -> errors:: pub async fn start_web_server( conf: Settings, - store: Arc, + stores: HashMap>, ) -> Result { let server = conf.server.clone(); let web_server = actix_web::HttpServer::new(move || { - actix_web::App::new().service(health_check::Health::server(conf.clone(), store.clone())) + actix_web::App::new().service(health_check::Health::server(conf.clone(), stores.clone())) }) .bind((server.host.as_str(), server.port))? .run(); diff --git a/crates/drainer/src/main.rs b/crates/drainer/src/main.rs index 64e66619d744..f3f822129c34 100644 --- a/crates/drainer/src/main.rs +++ b/crates/drainer/src/main.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use drainer::{ errors::DrainerResult, logger::logger, services, settings, start_drainer, start_web_server, }; @@ -17,7 +19,11 @@ async fn main() -> DrainerResult<()> { let state = settings::AppState::new(conf.clone()).await; - let store = std::sync::Arc::new(services::Store::new(&state.conf, false).await); + let mut stores = HashMap::new(); + for (tenant_name, tenant) in conf.multitenancy.get_tenants() { + let store = std::sync::Arc::new(services::Store::new(&state.conf, false, tenant).await); + stores.insert(tenant_name.clone(), store); + } #[cfg(feature = "vergen")] println!("Starting drainer (Version: {})", router_env::git_tag!()); @@ -29,9 +35,12 @@ async fn main() -> DrainerResult<()> { ); #[allow(clippy::expect_used)] - let web_server = Box::pin(start_web_server(state.conf.as_ref().clone(), store.clone())) - .await - .expect("Failed to create the server"); + let web_server = Box::pin(start_web_server( + state.conf.as_ref().clone(), + stores.clone(), + )) + .await + .expect("Failed to create the server"); tokio::spawn( async move { @@ -44,7 +53,7 @@ async fn main() -> DrainerResult<()> { logger::debug!(startup_config=?conf); logger::info!("Drainer started [{:?}] [{:?}]", conf.drainer, conf.log); - start_drainer(store.clone(), conf.drainer).await?; + start_drainer(stores.clone(), conf.drainer).await?; Ok(()) } diff --git a/crates/drainer/src/secrets_transformers.rs b/crates/drainer/src/secrets_transformers.rs index 4ffb584a1529..0582ccd798b1 100644 --- a/crates/drainer/src/secrets_transformers.rs +++ b/crates/drainer/src/secrets_transformers.rs @@ -45,5 +45,6 @@ pub async fn fetch_raw_secrets( drainer: conf.drainer, encryption_management: conf.encryption_management, secrets_management: conf.secrets_management, + multitenancy: conf.multitenancy, } } diff --git a/crates/drainer/src/services.rs b/crates/drainer/src/services.rs index 9e0165548a01..55ffe0c4e7fa 100644 --- a/crates/drainer/src/services.rs +++ b/crates/drainer/src/services.rs @@ -2,16 +2,18 @@ use std::sync::Arc; use actix_web::{body, HttpResponse, ResponseError}; use error_stack::Report; +use redis_interface::RedisConnectionPool; use crate::{ connection::{diesel_make_pg_pool, PgPool}, logger, + settings::Tenant, }; #[derive(Clone)] pub struct Store { pub master_pool: PgPool, - pub redis_conn: Arc, + pub redis_conn: Arc, pub config: StoreConfig, pub request_id: Option, } @@ -28,11 +30,19 @@ impl Store { /// Panics if there is a failure while obtaining the HashiCorp client using the provided configuration. /// This panic indicates a critical failure in setting up external services, and the application cannot proceed without a valid HashiCorp client. /// - pub async fn new(config: &crate::Settings, test_transaction: bool) -> Self { + pub async fn new(config: &crate::Settings, test_transaction: bool, tenant: &Tenant) -> Self { + let redis_conn = crate::connection::redis_connection(config).await; Self { - master_pool: diesel_make_pg_pool(config.master_database.get_inner(), test_transaction) - .await, - redis_conn: Arc::new(crate::connection::redis_connection(config).await), + master_pool: diesel_make_pg_pool( + config.master_database.get_inner(), + test_transaction, + &tenant.schema, + ) + .await, + redis_conn: Arc::new(RedisConnectionPool::clone( + &redis_conn, + &tenant.redis_key_prefix, + )), config: StoreConfig { drainer_stream_name: config.drainer.stream_name.clone(), drainer_num_partitions: config.drainer.num_partitions, diff --git a/crates/drainer/src/settings.rs b/crates/drainer/src/settings.rs index e68ede9e8b2e..311cee0cede7 100644 --- a/crates/drainer/src/settings.rs +++ b/crates/drainer/src/settings.rs @@ -1,6 +1,6 @@ -use std::{path::PathBuf, sync::Arc}; +use std::{collections::HashMap, path::PathBuf, sync::Arc}; -use common_utils::ext_traits::ConfigExt; +use common_utils::{ext_traits::ConfigExt, DbConnectionParams}; use config::{Environment, File}; use external_services::managers::{ encryption_management::EncryptionManagementConfig, secrets_management::SecretsManagementConfig, @@ -73,6 +73,7 @@ pub struct Settings { pub drainer: DrainerSettings, pub encryption_management: EncryptionManagementConfig, pub secrets_management: SecretsManagementConfig, + pub multitenancy: Multitenancy, } #[derive(Debug, Deserialize, Clone)] @@ -87,6 +88,24 @@ pub struct Database { pub connection_timeout: u64, } +impl DbConnectionParams for Database { + fn get_username(&self) -> &str { + &self.username + } + fn get_password(&self) -> Secret { + self.password.clone() + } + fn get_host(&self) -> &str { + &self.host + } + fn get_port(&self) -> u16 { + self.port + } + fn get_dbname(&self) -> &str { + &self.dbname + } +} + #[derive(Debug, Clone, Deserialize)] #[serde(default)] pub struct DrainerSettings { @@ -97,6 +116,35 @@ pub struct DrainerSettings { pub loop_interval: u32, // in milliseconds } +#[derive(Debug, Deserialize, Clone, Default)] +pub struct Multitenancy { + pub enabled: bool, + pub tenants: TenantConfig, +} +impl Multitenancy { + pub fn get_tenants(&self) -> &HashMap { + &self.tenants.0 + } + pub fn get_tenant_names(&self) -> Vec { + self.tenants.0.keys().cloned().collect() + } + pub fn get_tenant(&self, tenant_id: &str) -> Option<&Tenant> { + self.tenants.0.get(tenant_id) + } +} + +#[derive(Debug, Deserialize, Clone, Default)] +#[serde(transparent)] +pub struct TenantConfig(pub HashMap); + +#[derive(Debug, Deserialize, Clone, Default)] +pub struct Tenant { + pub name: String, + pub base_url: String, + pub schema: String, + pub redis_key_prefix: String, +} + #[derive(Debug, Deserialize, Clone)] #[serde(default)] pub struct Server { diff --git a/crates/hyperswitch_domain_models/src/errors/api_error_response.rs b/crates/hyperswitch_domain_models/src/errors/api_error_response.rs index 26a6f1618fa5..053eb493ce48 100644 --- a/crates/hyperswitch_domain_models/src/errors/api_error_response.rs +++ b/crates/hyperswitch_domain_models/src/errors/api_error_response.rs @@ -271,6 +271,10 @@ pub enum ApiErrorResponse { InvalidCookie, #[error(error_type = ErrorType::InvalidRequestError, code = "IR_27", message = "Extended card info does not exist")] ExtendedCardInfoNotFound, + #[error(error_type = ErrorType::ProcessingError, code = "HE_06", message = "Missing tenant id")] + MissingTenantId, + #[error(error_type = ErrorType::ProcessingError, code = "HE_06", message = "Invalid tenant id: {tenant_id}")] + InvalidTenant { tenant_id: String }, } #[derive(Clone)] @@ -603,6 +607,12 @@ impl ErrorSwitch for ApiErrorRespon Self::ExtendedCardInfoNotFound => { AER::NotFound(ApiError::new("IR", 27, "Extended card info does not exist", None)) } + Self::MissingTenantId => { + AER::InternalServerError(ApiError::new("HE", 6, "Missing Tenant ID in the request".to_string(), None)) + } + Self::InvalidTenant { tenant_id } => { + AER::InternalServerError(ApiError::new("HE", 6, format!("Invalid Tenant {tenant_id}"), None)) + } } } } diff --git a/crates/redis_interface/src/commands.rs b/crates/redis_interface/src/commands.rs index 504820822c08..ccfeb3e5b12e 100644 --- a/crates/redis_interface/src/commands.rs +++ b/crates/redis_interface/src/commands.rs @@ -31,6 +31,13 @@ use crate::{ }; impl super::RedisConnectionPool { + pub fn add_prefix(&self, key: &str) -> String { + if self.key_prefix.is_empty() { + key.to_string() + } else { + format!("{}:{}", self.key_prefix, key) + } + } #[instrument(level = "DEBUG", skip(self))] pub async fn set_key(&self, key: &str, value: V) -> CustomResult<(), errors::RedisError> where @@ -39,7 +46,7 @@ impl super::RedisConnectionPool { { self.pool .set( - key, + self.add_prefix(key), value, Some(Expiration::EX(self.config.default_ttl.into())), None, @@ -144,7 +151,7 @@ impl super::RedisConnectionPool { self.pool .set( - key, + self.add_prefix(key), serialized.as_slice(), Some(Expiration::EX(seconds)), None, @@ -160,7 +167,7 @@ impl super::RedisConnectionPool { V: FromRedis + Unpin + Send + 'static, { self.pool - .get(key) + .get(self.add_prefix(key)) .await .change_context(errors::RedisError::GetFailed) } @@ -171,7 +178,7 @@ impl super::RedisConnectionPool { V: Into + Unpin + Send + 'static, { self.pool - .exists(key) + .exists(self.add_prefix(key)) .await .change_context(errors::RedisError::GetFailed) } @@ -197,7 +204,7 @@ impl super::RedisConnectionPool { #[instrument(level = "DEBUG", skip(self))] pub async fn delete_key(&self, key: &str) -> CustomResult { self.pool - .del(key) + .del(self.add_prefix(key)) .await .change_context(errors::RedisError::DeleteFailed) } @@ -214,7 +221,13 @@ impl super::RedisConnectionPool { V::Error: Into + Send + Sync, { self.pool - .set(key, value, Some(Expiration::EX(seconds)), None, false) + .set( + self.add_prefix(key), + value, + Some(Expiration::EX(seconds)), + None, + false, + ) .await .change_context(errors::RedisError::SetExFailed) } @@ -232,7 +245,7 @@ impl super::RedisConnectionPool { { self.pool .set( - key, + self.add_prefix(key), value, Some(Expiration::EX( seconds.unwrap_or(self.config.default_ttl.into()), @@ -251,7 +264,7 @@ impl super::RedisConnectionPool { seconds: i64, ) -> CustomResult<(), errors::RedisError> { self.pool - .expire(key, seconds) + .expire(self.add_prefix(key), seconds) .await .change_context(errors::RedisError::SetExpiryFailed) } @@ -263,7 +276,7 @@ impl super::RedisConnectionPool { timestamp: i64, ) -> CustomResult<(), errors::RedisError> { self.pool - .expire_at(key, timestamp) + .expire_at(self.add_prefix(key), timestamp) .await .change_context(errors::RedisError::SetExpiryFailed) } @@ -281,7 +294,7 @@ impl super::RedisConnectionPool { { let output: Result<(), _> = self .pool - .hset(key, values) + .hset(self.add_prefix(key), values) .await .change_context(errors::RedisError::SetHashFailed); // setting expiry for the key @@ -306,7 +319,7 @@ impl super::RedisConnectionPool { { let output: Result = self .pool - .hsetnx(key, field, value) + .hsetnx(self.add_prefix(key), field, value) .await .change_context(errors::RedisError::SetHashFieldFailed); @@ -368,7 +381,7 @@ impl super::RedisConnectionPool { Ok(self .pool .next() - .hscan::<&str, &str>(key, pattern, count) + .hscan::<&str, &str>(&self.add_prefix(key), pattern, count) .filter_map(|value| async move { match value { Ok(mut v) => { @@ -419,7 +432,7 @@ impl super::RedisConnectionPool { V: FromRedis + Unpin + Send + 'static, { self.pool - .hget(key, field) + .hget(self.add_prefix(key), field) .await .change_context(errors::RedisError::GetHashFieldFailed) } @@ -456,7 +469,7 @@ impl super::RedisConnectionPool { V::Error: Into + Send, { self.pool - .sadd(key, members) + .sadd(self.add_prefix(key), members) .await .change_context(errors::RedisError::SetAddMembersFailed) } @@ -473,7 +486,7 @@ impl super::RedisConnectionPool { F::Error: Into + Send + Sync, { self.pool - .xadd(stream, false, None, entry_id, fields) + .xadd(self.add_prefix(stream), false, None, entry_id, fields) .await .change_context(errors::RedisError::StreamAppendFailed) } @@ -488,7 +501,7 @@ impl super::RedisConnectionPool { Ids: Into + Debug + Send + Sync, { self.pool - .xdel(stream, ids) + .xdel(self.add_prefix(stream), ids) .await .change_context(errors::RedisError::StreamDeleteFailed) } @@ -504,7 +517,7 @@ impl super::RedisConnectionPool { C::Error: Into + Send + Sync, { self.pool - .xtrim(stream, xcap) + .xtrim(self.add_prefix(stream), xcap) .await .change_context(errors::RedisError::StreamTrimFailed) } @@ -520,22 +533,34 @@ impl super::RedisConnectionPool { Ids: Into + Debug + Send + Sync, { self.pool - .xack(stream, group, ids) + .xack(self.add_prefix(stream), group, ids) .await .change_context(errors::RedisError::StreamAcknowledgeFailed) } #[instrument(level = "DEBUG", skip(self))] - pub async fn stream_get_length(&self, stream: K) -> CustomResult - where - K: Into + Debug + Send + Sync, - { + pub async fn stream_get_length(&self, stream: &str) -> CustomResult { self.pool - .xlen(stream) + .xlen(self.add_prefix(stream)) .await .change_context(errors::RedisError::GetLengthFailed) } + pub fn get_keys_with_prefix(&self, keys: K) -> MultipleKeys + where + K: Into + Debug + Send + Sync, + { + let multiple_keys: MultipleKeys = keys.into(); + let res = multiple_keys + .inner() + .iter() + .filter_map(|key| key.as_str()) + .map(|k| self.add_prefix(k)) + .map(RedisKey::from) + .collect::>(); + MultipleKeys::from(res) + } + #[instrument(level = "DEBUG", skip(self))] pub async fn stream_read_entries( &self, @@ -547,11 +572,12 @@ impl super::RedisConnectionPool { K: Into + Debug + Send + Sync, Ids: Into + Debug + Send + Sync, { + let strms = self.get_keys_with_prefix(streams); self.pool .xread_map( Some(read_count.unwrap_or(self.config.default_stream_read_count)), None, - streams, + strms, ids, ) .await @@ -579,10 +605,22 @@ impl super::RedisConnectionPool { match group { Some((group_name, consumer_name)) => { self.pool - .xreadgroup_map(group_name, consumer_name, count, block, false, streams, ids) + .xreadgroup_map( + group_name, + consumer_name, + count, + block, + false, + self.get_keys_with_prefix(streams), + ids, + ) + .await + } + None => { + self.pool + .xread_map(count, block, self.get_keys_with_prefix(streams), ids) .await } - None => self.pool.xread_map(count, block, streams, ids).await, } .map_err(|err| match err.kind() { RedisErrorKind::NotFound | RedisErrorKind::Parse => { @@ -610,7 +648,7 @@ impl super::RedisConnectionPool { } self.pool - .xgroup_create(stream, group, id, true) + .xgroup_create(self.add_prefix(stream), group, id, true) .await .change_context(errors::RedisError::ConsumerGroupCreateFailed) } @@ -622,7 +660,7 @@ impl super::RedisConnectionPool { group: &str, ) -> CustomResult { self.pool - .xgroup_destroy(stream, group) + .xgroup_destroy(self.add_prefix(stream), group) .await .change_context(errors::RedisError::ConsumerGroupDestroyFailed) } @@ -636,7 +674,7 @@ impl super::RedisConnectionPool { consumer: &str, ) -> CustomResult { self.pool - .xgroup_delconsumer(stream, group, consumer) + .xgroup_delconsumer(self.add_prefix(stream), group, consumer) .await .change_context(errors::RedisError::ConsumerGroupRemoveConsumerFailed) } @@ -649,7 +687,7 @@ impl super::RedisConnectionPool { id: &RedisEntryId, ) -> CustomResult { self.pool - .xgroup_setid(stream, group, id) + .xgroup_setid(self.add_prefix(stream), group, id) .await .change_context(errors::RedisError::ConsumerGroupSetIdFailed) } @@ -669,7 +707,7 @@ impl super::RedisConnectionPool { { self.pool .xclaim( - stream, + self.add_prefix(stream), group, consumer, min_idle_time, diff --git a/crates/redis_interface/src/lib.rs b/crates/redis_interface/src/lib.rs index df74d728331f..dc4fd3bbc9cc 100644 --- a/crates/redis_interface/src/lib.rs +++ b/crates/redis_interface/src/lib.rs @@ -30,10 +30,11 @@ use fred::{interfaces::ClientLike, prelude::EventInterface}; pub use self::types::*; pub struct RedisConnectionPool { - pub pool: fred::prelude::RedisPool, - config: RedisConfig, - pub subscriber: SubscriberClient, - pub publisher: RedisClient, + pub pool: Arc, + pub key_prefix: String, + pub config: Arc, + pub subscriber: Arc, + pub publisher: Arc, pub is_redis_available: Arc, } @@ -166,14 +167,24 @@ impl RedisConnectionPool { let config = RedisConfig::from(conf); Ok(Self { - pool, - config, + pool: Arc::new(pool), + config: Arc::new(config), is_redis_available: Arc::new(atomic::AtomicBool::new(true)), - subscriber, - publisher, + subscriber: Arc::new(subscriber), + publisher: Arc::new(publisher), + key_prefix: String::default(), }) } - + pub fn clone(&self, key_prefix: &str) -> Self { + Self { + pool: Arc::clone(&self.pool), + key_prefix: key_prefix.to_string(), + config: Arc::clone(&self.config), + subscriber: Arc::clone(&self.subscriber), + publisher: Arc::clone(&self.publisher), + is_redis_available: Arc::clone(&self.is_redis_available), + } + } pub async fn on_error(&self, tx: tokio::sync::oneshot::Sender<()>) { use futures::StreamExt; use tokio_stream::wrappers::BroadcastStream; @@ -211,7 +222,7 @@ impl RedisConnectionPool { } } -struct RedisConfig { +pub struct RedisConfig { default_ttl: u32, default_stream_read_count: u64, default_hash_ttl: u32, diff --git a/crates/router/src/bin/scheduler.rs b/crates/router/src/bin/scheduler.rs index 5341a1b09c1e..7e78a355e5c4 100644 --- a/crates/router/src/bin/scheduler.rs +++ b/crates/router/src/bin/scheduler.rs @@ -1,5 +1,5 @@ #![recursion_limit = "256"] -use std::{str::FromStr, sync::Arc}; +use std::{collections::HashMap, str::FromStr, sync::Arc}; use actix_web::{dev::Server, web, Scope}; use api_models::health_check::SchedulerHealthCheckResponse; @@ -22,7 +22,7 @@ use router_env::{ }; use scheduler::{ consumer::workflows::ProcessTrackerWorkflow, errors::ProcessTrackerError, - workflows::ProcessTrackerWorkflows, SchedulerAppState, + workflows::ProcessTrackerWorkflows, SchedulerSessionState, }; use storage_impl::errors::ApplicationError; use tokio::sync::{mpsc, oneshot}; @@ -146,24 +146,54 @@ pub async fn deep_health_check( state: web::Data, service: web::Data, ) -> impl actix_web::Responder { - let report = deep_health_check_func(state, service).await; - match report { - Ok(response) => services::http_response_json( - serde_json::to_string(&response) - .map_err(|err| { - logger::error!(serialization_error=?err); - }) - .unwrap_or_default(), - ), - Err(err) => api::log_and_return_error_response(err), + let mut checks = HashMap::new(); + let stores = state.stores.clone(); + let app_state = Arc::clone(&state.into_inner()); + let service_name = service.into_inner(); + for (tenant, _) in stores { + let session_state_res = app_state.clone().get_session_state(&tenant, || { + errors::ApiErrorResponse::MissingRequiredField { + field_name: "tenant_id", + } + .into() + }); + let session_state = match session_state_res { + Ok(state) => state, + Err(err) => { + return api::log_and_return_error_response(err); + } + }; + let report = deep_health_check_func(session_state, &service_name).await; + match report { + Ok(response) => { + checks.insert( + tenant, + serde_json::to_string(&response) + .map_err(|err| { + logger::error!(serialization_error=?err); + }) + .unwrap_or_default(), + ); + } + Err(err) => { + return api::log_and_return_error_response(err); + } + } } + services::http_response_json( + serde_json::to_string(&checks) + .map_err(|err| { + logger::error!(serialization_error=?err); + }) + .unwrap_or_default(), + ) } #[instrument(skip_all)] pub async fn deep_health_check_func( - state: web::Data, - service: web::Data, + state: routes::SessionState, + service: &str, ) -> errors::RouterResult { - logger::info!("{} deep health check was called", service.into_inner()); + logger::info!("{} deep health check was called", service); logger::debug!("Database health check begin"); @@ -215,10 +245,10 @@ pub async fn deep_health_check_func( pub struct WorkflowRunner; #[async_trait::async_trait] -impl ProcessTrackerWorkflows for WorkflowRunner { +impl ProcessTrackerWorkflows for WorkflowRunner { async fn trigger_workflow<'a>( &'a self, - state: &'a routes::AppState, + state: &'a routes::SessionState, process: storage::ProcessTracker, ) -> CustomResult<(), ProcessTrackerError> { let runner = process @@ -233,7 +263,7 @@ impl ProcessTrackerWorkflows for WorkflowRunner { .attach_printable("Failed to parse workflow runner name")?; let get_operation = |runner: storage::ProcessTrackerRunner| -> CustomResult< - Box>, + Box>, ProcessTrackerError, > { match runner { @@ -286,7 +316,7 @@ impl ProcessTrackerWorkflows for WorkflowRunner { let operation = get_operation(runner)?; let app_state = &state.clone(); - let output = operation.execute_workflow(app_state, process.clone()).await; + let output = operation.execute_workflow(state, process.clone()).await; match output { Ok(_) => operation.success_handler(app_state, process).await, Err(error) => match operation @@ -327,6 +357,10 @@ async fn start_scheduler( Arc::new(scheduler_settings), channel, WorkflowRunner {}, + |state, tenant| { + Arc::new(state.clone()) + .get_session_state(tenant, || ProcessTrackerError::TenantNotFound.into()) + }, ) .await } diff --git a/crates/router/src/compatibility/stripe/customers.rs b/crates/router/src/compatibility/stripe/customers.rs index 67c0f973b969..65abb012b9a7 100644 --- a/crates/router/src/compatibility/stripe/customers.rs +++ b/crates/router/src/compatibility/stripe/customers.rs @@ -155,7 +155,7 @@ pub async fn customer_delete( state.into_inner(), &req, payload, - |state, auth, req, _| { + |state, auth: auth::AuthenticationData, req, _| { customers::delete_customer(state, auth.merchant_account, req, auth.key_store) }, &auth::ApiKeyAuth, diff --git a/crates/router/src/compatibility/stripe/errors.rs b/crates/router/src/compatibility/stripe/errors.rs index 528381061cf5..17fcea9b828f 100644 --- a/crates/router/src/compatibility/stripe/errors.rs +++ b/crates/router/src/compatibility/stripe/errors.rs @@ -264,6 +264,8 @@ pub enum StripeErrorCode { PaymentMethodDeleteFailed, #[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "Extended card info does not exist")] ExtendedCardInfoNotFound, + #[error(error_type = StripeErrorType::InvalidRequestError, code = "IR_28", message = "Invalid tenant")] + InvalidTenant, // [#216]: https://github.com/juspay/hyperswitch/issues/216 // Implement the remaining stripe error codes @@ -646,6 +648,8 @@ impl From for StripeErrorCode { Self::InvalidWalletToken { wallet_name } } errors::ApiErrorResponse::ExtendedCardInfoNotFound => Self::ExtendedCardInfoNotFound, + errors::ApiErrorResponse::InvalidTenant { tenant_id: _ } + | errors::ApiErrorResponse::MissingTenantId => Self::InvalidTenant, } } } @@ -725,7 +729,8 @@ impl actix_web::ResponseError for StripeErrorCode { | Self::InternalServerError | Self::MandateActive | Self::CustomerRedacted - | Self::WebhookProcessingError => StatusCode::INTERNAL_SERVER_ERROR, + | Self::WebhookProcessingError + | Self::InvalidTenant => StatusCode::INTERNAL_SERVER_ERROR, Self::ReturnUrlUnavailable => StatusCode::SERVICE_UNAVAILABLE, Self::ExternalConnectorError { status_code, .. } => { StatusCode::from_u16(*status_code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR) diff --git a/crates/router/src/compatibility/wrap.rs b/crates/router/src/compatibility/wrap.rs index 96163727da37..b6012c425a58 100644 --- a/crates/router/src/compatibility/wrap.rs +++ b/crates/router/src/compatibility/wrap.rs @@ -10,7 +10,7 @@ use crate::{ events::api_logs::ApiEventMetric, routes::{ app::{AppStateInfo, ReqState}, - metrics, AppState, + metrics, AppState, SessionState, }, services::{self, api, authentication as auth, logger}, }; @@ -22,11 +22,11 @@ pub async fn compatibility_api_wrap<'a, 'b, U, T, Q, F, Fut, S, E, E2>( request: &'a HttpRequest, payload: T, func: F, - api_authentication: &dyn auth::AuthenticateAndFetch, + api_authentication: &dyn auth::AuthenticateAndFetch, lock_action: api_locking::LockAction, ) -> HttpResponse where - F: Fn(AppState, U, T, ReqState) -> Fut, + F: Fn(SessionState, U, T, ReqState) -> Fut, Fut: Future, E2>>, E2: ErrorSwitch + std::error::Error + Send + Sync + 'static, Q: Serialize + std::fmt::Debug + 'a + ApiEventMetric, @@ -49,6 +49,7 @@ where api::server_wrap_util( &flow, state.clone().into(), + request.headers(), req_state, request, payload, diff --git a/crates/router/src/configs/defaults.rs b/crates/router/src/configs/defaults.rs index 77f424d8333a..c989e4c04c0d 100644 --- a/crates/router/src/configs/defaults.rs +++ b/crates/router/src/configs/defaults.rs @@ -11,7 +11,6 @@ impl Default for super::settings::Server { workers: num_cpus::get_physical(), host: "localhost".into(), request_body_limit: 16 * 1024, // POST request body is limited to 16KiB - base_url: "http://localhost:8080".into(), shutdown_timeout: 30, } } diff --git a/crates/router/src/configs/secrets_transformers.rs b/crates/router/src/configs/secrets_transformers.rs index dc8b5dd6bd53..2f90833905e6 100644 --- a/crates/router/src/configs/secrets_transformers.rs +++ b/crates/router/src/configs/secrets_transformers.rs @@ -367,5 +367,6 @@ pub(crate) async fn fetch_raw_secrets( cors: conf.cors, unmasked_headers: conf.unmasked_headers, saved_payment_methods: conf.saved_payment_methods, + multitenancy: conf.multitenancy, } } diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index 8ac27cce3189..c71ed4496b08 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -120,9 +120,49 @@ pub struct Settings { #[cfg(feature = "olap")] pub connector_onboarding: SecretStateContainer, pub unmasked_headers: UnmaskedHeaders, + pub multitenancy: Multitenancy, pub saved_payment_methods: EligiblePaymentMethods, } +#[derive(Debug, Deserialize, Clone, Default)] +pub struct Multitenancy { + pub tenants: TenantConfig, + pub enabled: bool, +} + +impl Multitenancy { + pub fn get_tenants(&self) -> &HashMap { + &self.tenants.0 + } + pub fn get_tenant_names(&self) -> Vec { + self.tenants.0.keys().cloned().collect() + } + pub fn get_tenant(&self, tenant_id: &str) -> Option<&Tenant> { + self.tenants.0.get(tenant_id) + } +} + +#[derive(Debug, Deserialize, Clone, Default)] +#[serde(transparent)] +pub struct TenantConfig(pub HashMap); + +#[derive(Debug, Deserialize, Clone, Default)] +pub struct Tenant { + pub name: String, + pub base_url: String, + pub schema: String, + pub redis_key_prefix: String, +} + +impl storage_impl::config::TenantConfig for Tenant { + fn get_schema(&self) -> &str { + self.schema.as_str() + } + fn get_redis_key_prefix(&self) -> &str { + self.redis_key_prefix.as_str() + } +} + #[derive(Debug, Deserialize, Clone, Default)] pub struct UnmaskedHeaders { #[serde(deserialize_with = "deserialize_hashset")] @@ -447,7 +487,6 @@ pub struct Server { pub workers: usize, pub host: String, pub request_body_limit: usize, - pub base_url: String, pub shutdown_timeout: u64, } diff --git a/crates/router/src/connector/nuvei.rs b/crates/router/src/connector/nuvei.rs index bc556336c3ce..132311f87844 100644 --- a/crates/router/src/connector/nuvei.rs +++ b/crates/router/src/connector/nuvei.rs @@ -526,7 +526,7 @@ impl ConnectorIntegration CustomResult<(), errors::ConnectorError> { let integ: Box< &(dyn ConnectorIntegration< diff --git a/crates/router/src/connector/shift4.rs b/crates/router/src/connector/shift4.rs index 6c54c7019c83..f314d621de41 100644 --- a/crates/router/src/connector/shift4.rs +++ b/crates/router/src/connector/shift4.rs @@ -216,7 +216,7 @@ impl ConnectorIntegration CustomResult<(), errors::ConnectorError> { if router_data.auth_type == enums::AuthenticationType::ThreeDs && router_data.payment_method == enums::PaymentMethod::Card diff --git a/crates/router/src/connector/square.rs b/crates/router/src/connector/square.rs index f9a81031b07a..4e0812d16124 100644 --- a/crates/router/src/connector/square.rs +++ b/crates/router/src/connector/square.rs @@ -196,7 +196,7 @@ impl async fn execute_pretasks( &self, router_data: &mut types::TokenizationRouterData, - app_state: &crate::routes::AppState, + app_state: &crate::routes::SessionState, ) -> CustomResult<(), errors::ConnectorError> { let integ: Box< &(dyn ConnectorIntegration< diff --git a/crates/router/src/connector/wise.rs b/crates/router/src/connector/wise.rs index 667e182b674b..763adca1eeec 100644 --- a/crates/router/src/connector/wise.rs +++ b/crates/router/src/connector/wise.rs @@ -506,7 +506,7 @@ impl services::ConnectorIntegration, - app_state: &routes::AppState, + app_state: &routes::SessionState, ) -> CustomResult<(), errors::ConnectorError> { // Create a quote let quote_router_data = diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index bac825a341c7..6b582c2c9579 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -26,7 +26,7 @@ use crate::{ utils as core_utils, }, db::StorageInterface, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services::{self, api as service_api}, types::{ self, api, @@ -50,7 +50,7 @@ pub fn create_merchant_publishable_key() -> String { } pub async fn create_merchant_account( - state: AppState, + state: SessionState, req: api::MerchantAccountCreate, ) -> RouterResponse { let db = state.store.as_ref(); @@ -287,7 +287,7 @@ pub async fn create_merchant_account( #[cfg(feature = "olap")] pub async fn list_merchant_account( - state: AppState, + state: SessionState, req: api_models::admin::MerchantAccountListRequest, ) -> RouterResponse> { let merchant_accounts = state @@ -311,7 +311,7 @@ pub async fn list_merchant_account( } pub async fn get_merchant_account( - state: AppState, + state: SessionState, req: api::MerchantId, ) -> RouterResponse { let db = state.store.as_ref(); @@ -399,7 +399,7 @@ pub async fn create_business_profile_from_business_labels( /// For backwards compatibility /// If any of the fields of merchant account are updated, then update these fields in business profiles pub async fn update_business_profile_cascade( - state: AppState, + state: SessionState, merchant_account_update: api::MerchantAccountUpdate, merchant_id: String, ) -> RouterResult<()> { @@ -463,7 +463,7 @@ pub async fn update_business_profile_cascade( } pub async fn merchant_account_update( - state: AppState, + state: SessionState, merchant_id: &String, req: api::MerchantAccountUpdate, ) -> RouterResponse { @@ -617,7 +617,7 @@ pub async fn merchant_account_update( } pub async fn merchant_account_delete( - state: AppState, + state: SessionState, merchant_id: String, ) -> RouterResponse { let mut is_deleted = false; @@ -733,7 +733,7 @@ fn validate_certificate_in_mca_metadata( } pub async fn create_payment_connector( - state: AppState, + state: SessionState, req: api::MerchantConnectorCreate, merchant_id: &String, ) -> RouterResponse { @@ -1084,7 +1084,7 @@ async fn validate_pm_auth( } pub async fn retrieve_payment_connector( - state: AppState, + state: SessionState, merchant_id: String, merchant_connector_id: String, ) -> RouterResponse { @@ -1117,7 +1117,7 @@ pub async fn retrieve_payment_connector( } pub async fn list_payment_connectors( - state: AppState, + state: SessionState, merchant_id: String, ) -> RouterResponse> { let store = state.store.as_ref(); @@ -1154,7 +1154,7 @@ pub async fn list_payment_connectors( } pub async fn update_payment_connector( - state: AppState, + state: SessionState, merchant_id: &str, merchant_connector_id: &str, req: api_models::admin::MerchantConnectorUpdate, @@ -1305,7 +1305,7 @@ pub async fn update_payment_connector( } pub async fn delete_payment_connector( - state: AppState, + state: SessionState, merchant_id: String, merchant_connector_id: String, ) -> RouterResponse { @@ -1350,7 +1350,7 @@ pub async fn delete_payment_connector( } pub async fn kv_for_merchant( - state: AppState, + state: SessionState, merchant_id: String, enable: bool, ) -> RouterResponse { @@ -1417,7 +1417,7 @@ pub async fn kv_for_merchant( } pub async fn toggle_kv_for_all_merchants( - state: AppState, + state: SessionState, enable: bool, ) -> RouterResponse { let db = state.store.as_ref(); @@ -1447,7 +1447,7 @@ pub async fn toggle_kv_for_all_merchants( } pub async fn check_merchant_account_kv_status( - state: AppState, + state: SessionState, merchant_id: String, ) -> RouterResponse { let db = state.store.as_ref(); @@ -1519,7 +1519,7 @@ pub async fn create_and_insert_business_profile( } pub async fn create_business_profile( - state: AppState, + state: SessionState, request: api::BusinessProfileCreate, merchant_id: &str, ) -> RouterResponse { @@ -1566,7 +1566,7 @@ pub async fn create_business_profile( } pub async fn list_business_profile( - state: AppState, + state: SessionState, merchant_id: String, ) -> RouterResponse> { let db = state.store.as_ref(); @@ -1586,7 +1586,7 @@ pub async fn list_business_profile( } pub async fn retrieve_business_profile( - state: AppState, + state: SessionState, profile_id: String, ) -> RouterResponse { let db = state.store.as_ref(); @@ -1604,7 +1604,7 @@ pub async fn retrieve_business_profile( } pub async fn delete_business_profile( - state: AppState, + state: SessionState, profile_id: String, merchant_id: &str, ) -> RouterResponse { @@ -1620,7 +1620,7 @@ pub async fn delete_business_profile( } pub async fn update_business_profile( - state: AppState, + state: SessionState, profile_id: &str, merchant_id: &str, request: api::BusinessProfileUpdate, @@ -1738,7 +1738,7 @@ pub async fn update_business_profile( } pub async fn extended_card_info_toggle( - state: AppState, + state: SessionState, profile_id: &str, ext_card_info_choice: admin_types::ExtendedCardInfoChoice, ) -> RouterResponse { @@ -1771,7 +1771,7 @@ pub async fn extended_card_info_toggle( } pub async fn connector_agnostic_mit_toggle( - state: AppState, + state: SessionState, merchant_id: &str, profile_id: &str, connector_agnostic_mit_choice: admin_types::ConnectorAgnosticMitChoice, @@ -2085,7 +2085,7 @@ pub(crate) fn validate_auth_and_metadata_type( #[cfg(feature = "dummy_connector")] pub async fn validate_dummy_connector_enabled( - state: &AppState, + state: &SessionState, connector_name: &api_enums::Connector, ) -> Result<(), errors::ApiErrorResponse> { if !state.conf.dummy_connector.enabled diff --git a/crates/router/src/core/api_keys.rs b/crates/router/src/core/api_keys.rs index 7f2b343b9681..8fe536731d3d 100644 --- a/crates/router/src/core/api_keys.rs +++ b/crates/router/src/core/api_keys.rs @@ -9,7 +9,7 @@ use crate::{ configs::settings, consts, core::errors::{self, RouterResponse, StorageErrorExt}, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services::ApplicationResponse, types::{api, storage, transformers::ForeignInto}, utils, @@ -110,7 +110,7 @@ impl PlaintextApiKey { #[instrument(skip_all)] pub async fn create_api_key( - state: AppState, + state: SessionState, api_key: api::CreateApiKeyRequest, merchant_id: String, ) -> RouterResponse { @@ -244,7 +244,7 @@ pub async fn add_api_key_expiry_task( #[instrument(skip_all)] pub async fn retrieve_api_key( - state: AppState, + state: SessionState, merchant_id: &str, key_id: &str, ) -> RouterResponse { @@ -261,7 +261,7 @@ pub async fn retrieve_api_key( #[instrument(skip_all)] pub async fn update_api_key( - state: AppState, + state: SessionState, api_key: api::UpdateApiKeyRequest, ) -> RouterResponse { let merchant_id = api_key.merchant_id.clone(); @@ -395,7 +395,7 @@ pub async fn update_api_key_expiry_task( #[instrument(skip_all)] pub async fn revoke_api_key( - state: AppState, + state: SessionState, merchant_id: &str, key_id: &str, ) -> RouterResponse { @@ -463,7 +463,7 @@ pub async fn revoke_api_key_expiry_task( #[instrument(skip_all)] pub async fn list_api_keys( - state: AppState, + state: SessionState, merchant_id: String, limit: Option, offset: Option, diff --git a/crates/router/src/core/api_locking.rs b/crates/router/src/core/api_locking.rs index ec205f524271..8723c5fc1417 100644 --- a/crates/router/src/core/api_locking.rs +++ b/crates/router/src/core/api_locking.rs @@ -6,7 +6,7 @@ use redis_interface as redis; use router_env::{instrument, logger, tracing}; use super::errors::{self, RouterResult}; -use crate::routes::{app::AppStateInfo, lock_utils}; +use crate::routes::{app::SessionStateInfo, lock_utils}; pub const API_LOCK_PREFIX: &str = "API_LOCK"; @@ -50,7 +50,7 @@ impl LockAction { #[instrument(skip_all)] pub async fn perform_locking_action(self, state: &A, merchant_id: String) -> RouterResult<()> where - A: AppStateInfo, + A: SessionStateInfo, { match self { Self::Hold { input } => { @@ -111,7 +111,7 @@ impl LockAction { #[instrument(skip_all)] pub async fn free_lock_action(self, state: &A, merchant_id: String) -> RouterResult<()> where - A: AppStateInfo, + A: SessionStateInfo, { match self { Self::Hold { input } => { diff --git a/crates/router/src/core/authentication.rs b/crates/router/src/core/authentication.rs index 7828473df607..ec799365f7a4 100644 --- a/crates/router/src/core/authentication.rs +++ b/crates/router/src/core/authentication.rs @@ -12,14 +12,14 @@ use masking::ExposeInterface; use super::errors::StorageErrorExt; use crate::{ core::{errors::ApiErrorResponse, payments as payments_core}, - routes::AppState, + routes::SessionState, types::{self as core_types, api, domain, storage}, utils::check_if_pull_mechanism_for_external_3ds_enabled_from_connector_metadata, }; #[allow(clippy::too_many_arguments)] pub async fn perform_authentication( - state: &AppState, + state: &SessionState, merchant_id: String, authentication_connector: String, payment_method_data: payments::PaymentMethodData, @@ -78,7 +78,7 @@ pub async fn perform_authentication( } pub async fn perform_post_authentication( - state: &AppState, + state: &SessionState, key_store: &domain::MerchantKeyStore, business_profile: storage::BusinessProfile, authentication_id: String, @@ -117,7 +117,7 @@ pub async fn perform_post_authentication( } pub async fn perform_pre_authentication( - state: &AppState, + state: &SessionState, key_store: &domain::MerchantKeyStore, card_number: cards::CardNumber, token: String, diff --git a/crates/router/src/core/authentication/utils.rs b/crates/router/src/core/authentication/utils.rs index 6128352f2bd9..ec44f299c70e 100644 --- a/crates/router/src/core/authentication/utils.rs +++ b/crates/router/src/core/authentication/utils.rs @@ -8,7 +8,7 @@ use crate::{ payments, }, errors::RouterResult, - routes::AppState, + routes::SessionState, services::{self, execute_connector_processing_step}, types::{ api, authentication::AuthenticationResponseData, domain, storage, @@ -48,7 +48,7 @@ pub fn get_connector_data_if_separate_authn_supported( } pub async fn update_trackers( - state: &AppState, + state: &SessionState, router_data: RouterData, authentication: storage::Authentication, acquirer_details: Option, @@ -171,7 +171,7 @@ impl ForeignFrom for common_enums::AttemptSt } pub async fn create_new_authentication( - state: &AppState, + state: &SessionState, merchant_id: String, authentication_connector: String, token: String, @@ -228,7 +228,7 @@ pub async fn create_new_authentication( } pub async fn do_auth_connector_call( - state: &AppState, + state: &SessionState, authentication_connector_name: String, router_data: RouterData, ) -> RouterResult> @@ -255,7 +255,7 @@ where } pub async fn get_authentication_connector_data( - state: &AppState, + state: &SessionState, key_store: &domain::MerchantKeyStore, business_profile: &storage::BusinessProfile, ) -> RouterResult<( diff --git a/crates/router/src/core/blocklist.rs b/crates/router/src/core/blocklist.rs index 12a0802517c4..947acc506dff 100644 --- a/crates/router/src/core/blocklist.rs +++ b/crates/router/src/core/blocklist.rs @@ -5,13 +5,13 @@ use api_models::blocklist as api_blocklist; use crate::{ core::errors::{self, RouterResponse}, - routes::AppState, + routes::SessionState, services, types::domain, }; pub async fn add_entry_to_blocklist( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, body: api_blocklist::AddToBlocklistRequest, ) -> RouterResponse { @@ -21,7 +21,7 @@ pub async fn add_entry_to_blocklist( } pub async fn remove_entry_from_blocklist( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, body: api_blocklist::DeleteFromBlocklistRequest, ) -> RouterResponse { @@ -31,7 +31,7 @@ pub async fn remove_entry_from_blocklist( } pub async fn list_blocklist_entries( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, query: api_blocklist::ListBlocklistQuery, ) -> RouterResponse> { @@ -41,7 +41,7 @@ pub async fn list_blocklist_entries( } pub async fn toggle_blocklist_guard( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, query: api_blocklist::ToggleBlocklistQuery, ) -> RouterResponse { diff --git a/crates/router/src/core/blocklist/transformers.rs b/crates/router/src/core/blocklist/transformers.rs index a2583e5b6045..c3499445602d 100644 --- a/crates/router/src/core/blocklist/transformers.rs +++ b/crates/router/src/core/blocklist/transformers.rs @@ -111,7 +111,7 @@ async fn generate_jwe_payload_for_request( #[instrument(skip_all)] pub async fn generate_fingerprint( - state: &routes::AppState, + state: &routes::SessionState, card_number: StrongSecret, hash_key: StrongSecret, locker_choice: api_enums::LockerChoice, @@ -129,7 +129,7 @@ pub async fn generate_fingerprint( #[instrument(skip_all)] async fn call_to_locker_for_fingerprint( - state: &routes::AppState, + state: &routes::SessionState, payload: &blocklist::GenerateFingerprintRequest, locker_choice: api_enums::LockerChoice, ) -> CustomResult { diff --git a/crates/router/src/core/blocklist/utils.rs b/crates/router/src/core/blocklist/utils.rs index bc8724da8235..6c0d3fcd6c3b 100644 --- a/crates/router/src/core/blocklist/utils.rs +++ b/crates/router/src/core/blocklist/utils.rs @@ -5,7 +5,7 @@ use diesel_models::configs; use error_stack::ResultExt; use masking::StrongSecret; -use super::{errors, transformers::generate_fingerprint, AppState}; +use super::{errors, transformers::generate_fingerprint, SessionState}; use crate::{ consts, core::{ @@ -18,7 +18,7 @@ use crate::{ }; pub async fn delete_entry_from_blocklist( - state: &AppState, + state: &SessionState, merchant_id: String, request: api_blocklist::DeleteFromBlocklistRequest, ) -> RouterResult { @@ -44,7 +44,7 @@ pub async fn delete_entry_from_blocklist( } pub async fn toggle_blocklist_guard_for_merchant( - state: &AppState, + state: &SessionState, merchant_id: String, query: api_blocklist::ToggleBlocklistQuery, ) -> CustomResult { @@ -94,7 +94,7 @@ pub fn get_blocklist_guard_key(merchant_id: &str) -> String { } pub async fn list_blocklist_entries_for_merchant( - state: &AppState, + state: &SessionState, merchant_id: String, query: api_blocklist::ListBlocklistQuery, ) -> RouterResult> { @@ -138,7 +138,7 @@ fn validate_extended_card_bin(bin: &str) -> RouterResult<()> { } pub async fn insert_entry_into_blocklist( - state: &AppState, + state: &SessionState, merchant_id: String, to_block: api_blocklist::AddToBlocklistRequest, ) -> RouterResult { @@ -207,7 +207,7 @@ pub async fn insert_entry_into_blocklist( } pub async fn get_merchant_fingerprint_secret( - state: &AppState, + state: &SessionState, merchant_id: &str, ) -> RouterResult { let key = get_merchant_fingerprint_secret_key(merchant_id); @@ -246,7 +246,7 @@ fn get_merchant_fingerprint_secret_key(merchant_id: &str) -> String { async fn duplicate_check_insert_bin( bin: &str, - state: &AppState, + state: &SessionState, merchant_id: &str, data_kind: common_enums::BlocklistDataKind, ) -> RouterResult { @@ -287,7 +287,7 @@ async fn duplicate_check_insert_bin( } async fn delete_card_bin_blocklist_entry( - state: &AppState, + state: &SessionState, bin: &str, merchant_id: &str, ) -> RouterResult { @@ -301,7 +301,7 @@ async fn delete_card_bin_blocklist_entry( } pub async fn validate_data_for_blocklist( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, payment_data: &mut PaymentData, ) -> CustomResult @@ -452,7 +452,7 @@ where } pub async fn generate_payment_fingerprint( - state: &AppState, + state: &SessionState, merchant_id: String, payment_method_data: Option, ) -> CustomResult, errors::ApiErrorResponse> { diff --git a/crates/router/src/core/cache.rs b/crates/router/src/core/cache.rs index 8f3cf765e920..8cda60cf7009 100644 --- a/crates/router/src/core/cache.rs +++ b/crates/router/src/core/cache.rs @@ -3,10 +3,10 @@ use error_stack::{report, ResultExt}; use storage_impl::redis::cache::{publish_into_redact_channel, CacheKind}; use super::errors; -use crate::{routes::AppState, services}; +use crate::{routes::SessionState, services}; pub async fn invalidate( - state: AppState, + state: SessionState, key: &str, ) -> CustomResult, errors::ApiErrorResponse> { let store = state.store.as_ref(); diff --git a/crates/router/src/core/cards_info.rs b/crates/router/src/core/cards_info.rs index 4352e1808c73..bc01a786d154 100644 --- a/crates/router/src/core/cards_info.rs +++ b/crates/router/src/core/cards_info.rs @@ -21,7 +21,7 @@ fn verify_iin_length(card_iin: &str) -> Result<(), errors::ApiErrorResponse> { #[instrument(skip_all)] pub async fn retrieve_card_info( - state: routes::AppState, + state: routes::SessionState, merchant_account: domain::MerchantAccount, request: api_models::cards_info::CardsInfoRequest, ) -> RouterResponse { diff --git a/crates/router/src/core/conditional_config.rs b/crates/router/src/core/conditional_config.rs index c352e825052a..a8bc8a797dc3 100644 --- a/crates/router/src/core/conditional_config.rs +++ b/crates/router/src/core/conditional_config.rs @@ -12,14 +12,14 @@ use super::routing::helpers::{ }; use crate::{ core::errors::{self, RouterResponse}, - routes::AppState, + routes::SessionState, services::api as service_api, types::domain, utils::OptionExt, }; pub async fn upsert_conditional_config( - state: AppState, + state: SessionState, key_store: domain::MerchantKeyStore, merchant_account: domain::MerchantAccount, request: DecisionManager, @@ -149,7 +149,7 @@ pub async fn upsert_conditional_config( } pub async fn delete_conditional_config( - state: AppState, + state: SessionState, key_store: domain::MerchantKeyStore, merchant_account: domain::MerchantAccount, ) -> RouterResponse<()> { @@ -177,7 +177,7 @@ pub async fn delete_conditional_config( } pub async fn retrieve_conditional_config( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, ) -> RouterResponse { let db = state.store.as_ref(); diff --git a/crates/router/src/core/configs.rs b/crates/router/src/core/configs.rs index ba2303167d76..be8dfc83828d 100644 --- a/crates/router/src/core/configs.rs +++ b/crates/router/src/core/configs.rs @@ -2,12 +2,12 @@ use error_stack::ResultExt; use crate::{ core::errors::{self, utils::StorageErrorExt, RouterResponse}, - routes::AppState, + routes::SessionState, services::ApplicationResponse, types::{api, transformers::ForeignInto}, }; -pub async fn set_config(state: AppState, config: api::Config) -> RouterResponse { +pub async fn set_config(state: SessionState, config: api::Config) -> RouterResponse { let store = state.store.as_ref(); let config = store .insert_config(diesel_models::configs::ConfigNew { @@ -21,7 +21,7 @@ pub async fn set_config(state: AppState, config: api::Config) -> RouterResponse< Ok(ApplicationResponse::Json(config.foreign_into())) } -pub async fn read_config(state: AppState, key: &str) -> RouterResponse { +pub async fn read_config(state: SessionState, key: &str) -> RouterResponse { let store = state.store.as_ref(); let config = store .find_config_by_key(key) @@ -31,7 +31,7 @@ pub async fn read_config(state: AppState, key: &str) -> RouterResponse RouterResponse { let store = state.store.as_ref(); @@ -42,7 +42,7 @@ pub async fn update_config( Ok(ApplicationResponse::Json(config.foreign_into())) } -pub async fn config_delete(state: AppState, key: String) -> RouterResponse { +pub async fn config_delete(state: SessionState, key: String) -> RouterResponse { let store = state.store.as_ref(); let config = store .delete_config_by_key(&key) diff --git a/crates/router/src/core/connector_onboarding.rs b/crates/router/src/core/connector_onboarding.rs index b69b2996a6ac..d6c20cc28104 100644 --- a/crates/router/src/core/connector_onboarding.rs +++ b/crates/router/src/core/connector_onboarding.rs @@ -7,18 +7,18 @@ use crate::{ services::{authentication as auth, ApplicationResponse}, types as oss_types, utils::connector_onboarding as utils, - AppState, + SessionState, }; pub mod paypal; #[async_trait::async_trait] pub trait AccessToken { - async fn access_token(state: &AppState) -> RouterResult; + async fn access_token(state: &SessionState) -> RouterResult; } pub async fn get_action_url( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, request: api::ActionUrlRequest, _req_state: ReqState, @@ -53,7 +53,7 @@ pub async fn get_action_url( } pub async fn sync_onboarding_status( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, request: api::OnboardingSyncRequest, _req_state: ReqState, @@ -107,7 +107,7 @@ pub async fn sync_onboarding_status( } pub async fn reset_tracking_id( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, request: api::ResetTrackingIdRequest, _req_state: ReqState, diff --git a/crates/router/src/core/connector_onboarding/paypal.rs b/crates/router/src/core/connector_onboarding/paypal.rs index 616fcbdc8cc3..6f28cfcbf8ec 100644 --- a/crates/router/src/core/connector_onboarding/paypal.rs +++ b/crates/router/src/core/connector_onboarding/paypal.rs @@ -11,10 +11,10 @@ use crate::{ services::{send_request, ApplicationResponse, Request}, types::{self as oss_types, api as oss_api_types, api::connector_onboarding as types}, utils::connector_onboarding as utils, - AppState, + SessionState, }; -fn build_referral_url(state: AppState) -> String { +fn build_referral_url(state: SessionState) -> String { format!( "{}v2/customer/partner-referrals", state.conf.connectors.paypal.base_url @@ -22,7 +22,7 @@ fn build_referral_url(state: AppState) -> String { } async fn build_referral_request( - state: AppState, + state: SessionState, tracking_id: String, return_url: String, ) -> RouterResult { @@ -37,7 +37,7 @@ async fn build_referral_request( } pub async fn get_action_url_from_paypal( - state: AppState, + state: SessionState, tracking_id: String, return_url: String, ) -> RouterResult { @@ -61,7 +61,7 @@ pub async fn get_action_url_from_paypal( parsed_response.extract_action_url() } -fn merchant_onboarding_status_url(state: AppState, tracking_id: String) -> String { +fn merchant_onboarding_status_url(state: SessionState, tracking_id: String) -> String { let partner_id = state .conf .connector_onboarding @@ -78,7 +78,7 @@ fn merchant_onboarding_status_url(state: AppState, tracking_id: String) -> Strin } pub async fn sync_merchant_onboarding_status( - state: AppState, + state: SessionState, tracking_id: String, ) -> RouterResult { let access_token = utils::paypal::generate_access_token(state.clone()).await?; @@ -113,7 +113,7 @@ pub async fn sync_merchant_onboarding_status( } async fn find_paypal_merchant_by_tracking_id( - state: AppState, + state: SessionState, tracking_id: String, access_token: &oss_types::AccessToken, ) -> RouterResult> { @@ -139,7 +139,7 @@ async fn find_paypal_merchant_by_tracking_id( } pub async fn update_mca( - state: &AppState, + state: &SessionState, merchant_id: String, connector_id: String, auth_details: oss_types::ConnectorAuthType, diff --git a/crates/router/src/core/currency.rs b/crates/router/src/core/currency.rs index f2791deb7b6e..96d75098271b 100644 --- a/crates/router/src/core/currency.rs +++ b/crates/router/src/core/currency.rs @@ -5,11 +5,11 @@ use crate::{ core::errors::ApiErrorResponse, services::ApplicationResponse, utils::currency::{self, convert_currency, get_forex_rates}, - AppState, + SessionState, }; pub async fn retrieve_forex( - state: AppState, + state: SessionState, ) -> CustomResult, ApiErrorResponse> { let forex_api = state.conf.forex_api.get_inner(); Ok(ApplicationResponse::Json( @@ -27,7 +27,7 @@ pub async fn retrieve_forex( } pub async fn convert_forex( - state: AppState, + state: SessionState, amount: i64, to_currency: String, from_currency: String, diff --git a/crates/router/src/core/customers.rs b/crates/router/src/core/customers.rs index 1c983dcde950..ad1a292df090 100644 --- a/crates/router/src/core/customers.rs +++ b/crates/router/src/core/customers.rs @@ -13,7 +13,7 @@ use crate::{ payment_methods::cards, }, pii::PeekInterface, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services, types::{ api::customers, @@ -30,7 +30,7 @@ pub const REDACTED: &str = "Redacted"; #[instrument(skip(state))] pub async fn create_customer( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, mut customer_data: customers::CustomerRequest, @@ -142,7 +142,7 @@ pub async fn create_customer( #[instrument(skip(state))] pub async fn retrieve_customer( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: customers::CustomerId, @@ -172,7 +172,7 @@ pub async fn retrieve_customer( #[instrument(skip(state))] pub async fn list_customers( - state: AppState, + state: SessionState, merchant_id: String, key_store: domain::MerchantKeyStore, ) -> errors::CustomerResponse> { @@ -193,7 +193,7 @@ pub async fn list_customers( #[instrument(skip_all)] pub async fn delete_customer( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, req: customers::CustomerId, key_store: domain::MerchantKeyStore, @@ -348,7 +348,7 @@ pub async fn delete_customer( #[instrument(skip(state))] pub async fn update_customer( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, update_customer: customers::CustomerRequest, key_store: domain::MerchantKeyStore, diff --git a/crates/router/src/core/disputes.rs b/crates/router/src/core/disputes.rs index f608100c08a7..883612869039 100644 --- a/crates/router/src/core/disputes.rs +++ b/crates/router/src/core/disputes.rs @@ -10,7 +10,7 @@ use super::{ }; use crate::{ core::{files, payments, utils as core_utils}, - routes::AppState, + routes::SessionState, services, types::{ api::{self, disputes}, @@ -24,7 +24,7 @@ use crate::{ #[instrument(skip(state))] pub async fn retrieve_dispute( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, req: disputes::DisputeId, ) -> RouterResponse { @@ -41,7 +41,7 @@ pub async fn retrieve_dispute( #[instrument(skip(state))] pub async fn retrieve_disputes_list( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, constraints: api_models::disputes::DisputeListConstraints, ) -> RouterResponse> { @@ -60,7 +60,7 @@ pub async fn retrieve_disputes_list( #[instrument(skip(state))] pub async fn accept_dispute( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: disputes::DisputeId, @@ -161,7 +161,7 @@ pub async fn accept_dispute( #[instrument(skip(state))] pub async fn submit_evidence( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: dispute_models::SubmitEvidenceRequest, @@ -324,7 +324,7 @@ pub async fn submit_evidence( } pub async fn attach_evidence( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, attach_evidence_request: api::AttachEvidenceRequest, @@ -401,7 +401,7 @@ pub async fn attach_evidence( #[instrument(skip(state))] pub async fn retrieve_dispute_evidence( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, req: disputes::DisputeId, ) -> RouterResponse> { @@ -424,7 +424,7 @@ pub async fn retrieve_dispute_evidence( } pub async fn delete_evidence( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, delete_evidence_request: dispute_models::DeleteEvidenceRequest, ) -> RouterResponse { diff --git a/crates/router/src/core/disputes/transformers.rs b/crates/router/src/core/disputes/transformers.rs index 936184fc9937..d37410d5ef83 100644 --- a/crates/router/src/core/disputes/transformers.rs +++ b/crates/router/src/core/disputes/transformers.rs @@ -4,7 +4,7 @@ use error_stack::ResultExt; use crate::{ core::{errors, files::helpers::retrieve_file_and_provider_file_id_from_file_id}, - routes::AppState, + routes::SessionState, types::{ api::{self, DisputeEvidence}, domain, @@ -14,7 +14,7 @@ use crate::{ }; pub async fn get_evidence_request_data( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, evidence_request: api_models::disputes::SubmitEvidenceRequest, @@ -203,7 +203,7 @@ pub fn update_dispute_evidence( } pub async fn get_dispute_evidence_block( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, evidence_type: EvidenceType, file_id: String, @@ -271,7 +271,7 @@ pub fn delete_evidence_file( } pub async fn get_dispute_evidence_vec( - state: &AppState, + state: &SessionState, merchant_account: domain::MerchantAccount, dispute_evidence: DisputeEvidence, ) -> CustomResult, errors::ApiErrorResponse> { diff --git a/crates/router/src/core/files.rs b/crates/router/src/core/files.rs index 5dedcb148633..9ba5c29ce760 100644 --- a/crates/router/src/core/files.rs +++ b/crates/router/src/core/files.rs @@ -6,13 +6,13 @@ use error_stack::ResultExt; use super::errors::{self, RouterResponse}; use crate::{ consts, - routes::AppState, + routes::SessionState, services::ApplicationResponse, types::{api, domain}, }; pub async fn files_create_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, create_file_request: api::CreateFileRequest, @@ -78,7 +78,7 @@ pub async fn files_create_core( } pub async fn files_delete_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, req: api::FileId, ) -> RouterResponse { @@ -94,7 +94,7 @@ pub async fn files_delete_core( } pub async fn files_retrieve_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: api::FileId, diff --git a/crates/router/src/core/files/helpers.rs b/crates/router/src/core/files/helpers.rs index 0c6a88d8270c..0be198377b86 100644 --- a/crates/router/src/core/files/helpers.rs +++ b/crates/router/src/core/files/helpers.rs @@ -8,7 +8,7 @@ use crate::{ errors::{self, StorageErrorExt}, payments, utils, }, - routes::AppState, + routes::SessionState, services, types::{self, api, domain, transformers::ForeignTryFrom}, }; @@ -31,7 +31,7 @@ pub async fn get_file_purpose(field: &mut Field) -> Option { } pub async fn validate_file_upload( - state: &AppState, + state: &SessionState, merchant_account: domain::MerchantAccount, create_file_request: api::CreateFileRequest, ) -> CustomResult<(), errors::ApiErrorResponse> { @@ -81,7 +81,7 @@ pub async fn validate_file_upload( } pub async fn delete_file_using_file_id( - state: &AppState, + state: &SessionState, file_key: String, merchant_account: &domain::MerchantAccount, ) -> CustomResult<(), errors::ApiErrorResponse> { @@ -113,7 +113,7 @@ pub async fn delete_file_using_file_id( } pub async fn retrieve_file_from_connector( - state: &AppState, + state: &SessionState, file_metadata: diesel_models::file::FileMetadata, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -171,7 +171,7 @@ pub async fn retrieve_file_from_connector( } pub async fn retrieve_file_and_provider_file_id_from_file_id( - state: &AppState, + state: &SessionState, file_id: Option, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -227,7 +227,7 @@ pub async fn retrieve_file_and_provider_file_id_from_file_id( //Upload file to connector if it supports / store it in S3 and return file_upload_provider, provider_file_id accordingly pub async fn upload_and_get_provider_provider_file_id_profile_id( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, create_file_request: &api::CreateFileRequest, diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index dddcf581296f..f7f7108c2baa 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -24,7 +24,7 @@ use crate::{ utils as core_utils, }, db::StorageInterface, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ self as oss_types, @@ -50,7 +50,7 @@ pub mod types; #[instrument(skip_all)] pub async fn call_frm_service( - state: &AppState, + state: &SessionState, payment_data: &mut payments::PaymentData, frm_data: &mut FrmData, merchant_account: &domain::MerchantAccount, @@ -302,7 +302,7 @@ where #[allow(clippy::too_many_arguments)] pub async fn make_frm_data_and_fraud_check_operation<'a, F>( _db: &dyn StorageInterface, - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, payment_data: payments::PaymentData, frm_routing_algorithm: FrmRoutingAlgorithm, @@ -370,7 +370,7 @@ where #[allow(clippy::too_many_arguments)] pub async fn pre_payment_frm_core<'a, F, Req>( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, payment_data: &mut payments::PaymentData, frm_info: &mut FrmInfo, @@ -456,7 +456,7 @@ where #[allow(clippy::too_many_arguments)] pub async fn post_payment_frm_core<'a, F>( - state: &AppState, + state: &SessionState, req_state: ReqState, merchant_account: &domain::MerchantAccount, payment_data: &mut payments::PaymentData, @@ -547,7 +547,7 @@ pub async fn call_frm_before_connector_call<'a, F, Req>( operation: &BoxedOperation<'_, F, Req>, merchant_account: &domain::MerchantAccount, payment_data: &mut payments::PaymentData, - state: &AppState, + state: &SessionState, frm_info: &mut Option>, customer: &Option, should_continue_transaction: &mut bool, @@ -643,7 +643,7 @@ impl From for PaymentDetails { #[instrument(skip_all)] pub async fn frm_fulfillment_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: frm_core_types::FrmFulfillmentRequest, @@ -705,7 +705,7 @@ pub async fn make_fulfillment_api_call( db: &dyn StorageInterface, fraud_check: FraudCheck, payment_intent: PaymentIntent, - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: frm_core_types::FrmFulfillmentRequest, diff --git a/crates/router/src/core/fraud_check/flows.rs b/crates/router/src/core/fraud_check/flows.rs index 3d4916a372be..896d062bc14c 100644 --- a/crates/router/src/core/fraud_check/flows.rs +++ b/crates/router/src/core/fraud_check/flows.rs @@ -11,7 +11,7 @@ use crate::{ errors::RouterResult, payments::{self, flows::ConstructFlowSpecificData}, }, - routes::AppState, + routes::SessionState, services, types::{ api::{Connector, FraudCheckConnectorData}, @@ -24,7 +24,7 @@ use crate::{ pub trait FeatureFrm { async fn decide_frm_flows<'a>( self, - state: &AppState, + state: &SessionState, connector: &FraudCheckConnectorData, call_connector_action: payments::CallConnectorAction, merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/fraud_check/flows/checkout_flow.rs b/crates/router/src/core/fraud_check/flows/checkout_flow.rs index c754682f72d5..74353e83b3d5 100644 --- a/crates/router/src/core/fraud_check/flows/checkout_flow.rs +++ b/crates/router/src/core/fraud_check/flows/checkout_flow.rs @@ -19,7 +19,7 @@ use crate::{ storage::enums as storage_enums, BrowserInformation, ConnectorAuthType, ResponseId, RouterData, }, - AppState, + SessionState, }; #[async_trait] @@ -28,7 +28,7 @@ impl ConstructFlowSpecificData( &self, - _state: &AppState, + _state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, @@ -138,7 +138,7 @@ impl ConstructFlowSpecificData for FrmCheckoutRouterData { async fn decide_frm_flows<'a>( mut self, - state: &AppState, + state: &SessionState, connector: &FraudCheckConnectorData, call_connector_action: payments::CallConnectorAction, merchant_account: &domain::MerchantAccount, @@ -156,7 +156,7 @@ impl FeatureFrm for FrmCheckoutRouter pub async fn decide_frm_flow<'a, 'b>( router_data: &'b mut FrmCheckoutRouterData, - state: &'a AppState, + state: &'a SessionState, connector: &FraudCheckConnectorData, call_connector_action: payments::CallConnectorAction, _merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs b/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs index 1f4f2ccebeee..f91d87c808c0 100644 --- a/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs +++ b/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs @@ -13,12 +13,12 @@ use crate::{ fraud_check::{FraudCheckFulfillmentData, FrmFulfillmentRouterData}, storage, ConnectorAuthType, ErrorResponse, PaymentAddress, RouterData, }, - utils, AppState, + utils, SessionState, }; #[instrument(skip_all)] pub async fn construct_fulfillment_router_data<'a>( - state: &'a AppState, + state: &'a SessionState, payment_intent: &'a storage::PaymentIntent, payment_attempt: &storage::PaymentAttempt, merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/fraud_check/flows/record_return.rs b/crates/router/src/core/fraud_check/flows/record_return.rs index b854a3337700..b8f8810f09b3 100644 --- a/crates/router/src/core/fraud_check/flows/record_return.rs +++ b/crates/router/src/core/fraud_check/flows/record_return.rs @@ -19,7 +19,7 @@ use crate::{ storage::enums as storage_enums, ConnectorAuthType, ResponseId, RouterData, }, - utils, AppState, + utils, SessionState, }; #[async_trait] @@ -28,7 +28,7 @@ impl ConstructFlowSpecificData( &self, - _state: &AppState, + _state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, @@ -110,7 +110,7 @@ impl ConstructFlowSpecificData for FrmRecordReturnRouterData { async fn decide_frm_flows<'a>( mut self, - state: &AppState, + state: &SessionState, connector: &FraudCheckConnectorData, call_connector_action: payments::CallConnectorAction, merchant_account: &domain::MerchantAccount, @@ -128,7 +128,7 @@ impl FeatureFrm for FrmRecordReturnRou pub async fn decide_frm_flow<'a, 'b>( router_data: &'b mut FrmRecordReturnRouterData, - state: &'a AppState, + state: &'a SessionState, connector: &FraudCheckConnectorData, call_connector_action: payments::CallConnectorAction, _merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/fraud_check/flows/sale_flow.rs b/crates/router/src/core/fraud_check/flows/sale_flow.rs index 829f8b736b0b..b605c5406568 100644 --- a/crates/router/src/core/fraud_check/flows/sale_flow.rs +++ b/crates/router/src/core/fraud_check/flows/sale_flow.rs @@ -17,7 +17,7 @@ use crate::{ storage::enums as storage_enums, ConnectorAuthType, ResponseId, RouterData, }, - AppState, + SessionState, }; #[async_trait] @@ -26,7 +26,7 @@ impl ConstructFlowSpecificData( &self, - _state: &AppState, + _state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, @@ -119,7 +119,7 @@ impl ConstructFlowSpecificData for FrmSaleRouterData { async fn decide_frm_flows<'a>( mut self, - state: &AppState, + state: &SessionState, connector: &FraudCheckConnectorData, call_connector_action: payments::CallConnectorAction, merchant_account: &domain::MerchantAccount, @@ -137,7 +137,7 @@ impl FeatureFrm for FrmSaleRouterData { pub async fn decide_frm_flow<'a, 'b>( router_data: &'b mut FrmSaleRouterData, - state: &'a AppState, + state: &'a SessionState, connector: &FraudCheckConnectorData, call_connector_action: payments::CallConnectorAction, _merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/fraud_check/flows/transaction_flow.rs b/crates/router/src/core/fraud_check/flows/transaction_flow.rs index 0b851d7b6263..8c496792a81e 100644 --- a/crates/router/src/core/fraud_check/flows/transaction_flow.rs +++ b/crates/router/src/core/fraud_check/flows/transaction_flow.rs @@ -18,7 +18,7 @@ use crate::{ storage::enums as storage_enums, ConnectorAuthType, ResponseId, RouterData, }, - AppState, + SessionState, }; #[async_trait] @@ -31,7 +31,7 @@ impl { async fn construct_router_data<'a>( &self, - _state: &AppState, + _state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, @@ -123,7 +123,7 @@ impl impl FeatureFrm for FrmTransactionRouterData { async fn decide_frm_flows<'a>( mut self, - state: &AppState, + state: &SessionState, connector: &frm_api::FraudCheckConnectorData, call_connector_action: payments::CallConnectorAction, merchant_account: &domain::MerchantAccount, @@ -141,7 +141,7 @@ impl FeatureFrm for FrmTransact pub async fn decide_frm_flow<'a, 'b>( router_data: &'b mut FrmTransactionRouterData, - state: &'a AppState, + state: &'a SessionState, connector: &frm_api::FraudCheckConnectorData, call_connector_action: payments::CallConnectorAction, _merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/fraud_check/operation.rs b/crates/router/src/core/fraud_check/operation.rs index a9b95cdf3b5e..33a370ac8499 100644 --- a/crates/router/src/core/fraud_check/operation.rs +++ b/crates/router/src/core/fraud_check/operation.rs @@ -15,7 +15,7 @@ use crate::{ payments, }, db::StorageInterface, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, types::{domain, fraud_check::FrmRouterData}, }; @@ -40,7 +40,7 @@ pub trait FraudCheckOperation: Send + std::fmt::Debug { pub trait GetTracker: Send { async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: D, frm_connector_details: ConnectorDetailsCore, ) -> RouterResult>; @@ -51,7 +51,7 @@ pub trait GetTracker: Send { pub trait Domain: Send + Sync { async fn post_payment_frm<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, req_state: ReqState, payment_data: &mut payments::PaymentData, frm_data: &mut FrmData, @@ -64,7 +64,7 @@ pub trait Domain: Send + Sync { async fn pre_payment_frm<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut payments::PaymentData, frm_data: &mut FrmData, merchant_account: &domain::MerchantAccount, @@ -79,7 +79,7 @@ pub trait Domain: Send + Sync { #[allow(clippy::too_many_arguments)] async fn execute_post_tasks( &self, - _state: &AppState, + _state: &SessionState, _req_state: ReqState, frm_data: &mut FrmData, _merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/fraud_check/operation/fraud_check_post.rs b/crates/router/src/core/fraud_check/operation/fraud_check_post.rs index 6a310aa131dd..cc4fc0370e97 100644 --- a/crates/router/src/core/fraud_check/operation/fraud_check_post.rs +++ b/crates/router/src/core/fraud_check/operation/fraud_check_post.rs @@ -38,7 +38,7 @@ use crate::{ }, ResponseId, }, - utils, AppState, + utils, SessionState, }; #[derive(Debug, Clone, Copy)] @@ -73,7 +73,7 @@ impl GetTracker for FraudCheckPost { #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: PaymentToFrmData, frm_connector_details: ConnectorDetailsCore, ) -> RouterResult> { @@ -142,7 +142,7 @@ impl Domain for FraudCheckPost { #[instrument(skip_all)] async fn post_payment_frm<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, _req_state: ReqState, payment_data: &mut payments::PaymentData, frm_data: &mut FrmData, @@ -182,7 +182,7 @@ impl Domain for FraudCheckPost { #[instrument(skip_all)] async fn execute_post_tasks( &self, - state: &AppState, + state: &SessionState, req_state: ReqState, frm_data: &mut FrmData, merchant_account: &domain::MerchantAccount, @@ -293,7 +293,7 @@ impl Domain for FraudCheckPost { #[instrument(skip_all)] async fn pre_payment_frm<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut payments::PaymentData, frm_data: &mut FrmData, merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/fraud_check/operation/fraud_check_pre.rs b/crates/router/src/core/fraud_check/operation/fraud_check_pre.rs index ae316e7a1108..272cd5aa7044 100644 --- a/crates/router/src/core/fraud_check/operation/fraud_check_pre.rs +++ b/crates/router/src/core/fraud_check/operation/fraud_check_pre.rs @@ -32,7 +32,7 @@ use crate::{ }, ResponseId, }, - AppState, + SessionState, }; #[derive(Debug, Clone, Copy)] @@ -67,7 +67,7 @@ impl GetTracker for FraudCheckPre { #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: PaymentToFrmData, frm_connector_details: ConnectorDetailsCore, ) -> RouterResult> { @@ -139,7 +139,7 @@ impl Domain for FraudCheckPre { #[instrument(skip_all)] async fn post_payment_frm<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, _req_state: ReqState, payment_data: &mut payments::PaymentData, frm_data: &mut FrmData, @@ -178,7 +178,7 @@ impl Domain for FraudCheckPre { async fn pre_payment_frm<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut payments::PaymentData, frm_data: &mut FrmData, merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/gsm.rs b/crates/router/src/core/gsm.rs index 668c1773e2cd..4a678a5c4089 100644 --- a/crates/router/src/core/gsm.rs +++ b/crates/router/src/core/gsm.rs @@ -11,12 +11,12 @@ use crate::{ db::gsm::GsmInterface, services, types::transformers::ForeignInto, - AppState, + SessionState, }; #[instrument(skip_all)] pub async fn create_gsm_rule( - state: AppState, + state: SessionState, gsm_rule: gsm_api_types::GsmCreateRequest, ) -> RouterResponse { let db = state.store.as_ref(); @@ -30,7 +30,7 @@ pub async fn create_gsm_rule( #[instrument(skip_all)] pub async fn retrieve_gsm_rule( - state: AppState, + state: SessionState, gsm_request: gsm_api_types::GsmRetrieveRequest, ) -> RouterResponse { let db = state.store.as_ref(); @@ -51,7 +51,7 @@ pub async fn retrieve_gsm_rule( #[instrument(skip_all)] pub async fn update_gsm_rule( - state: AppState, + state: SessionState, gsm_request: gsm_api_types::GsmUpdateRequest, ) -> RouterResponse { let db = state.store.as_ref(); @@ -94,7 +94,7 @@ pub async fn update_gsm_rule( #[instrument(skip_all)] pub async fn delete_gsm_rule( - state: AppState, + state: SessionState, gsm_request: gsm_api_types::GsmDeleteRequest, ) -> RouterResponse { let db = state.store.as_ref(); diff --git a/crates/router/src/core/health_check.rs b/crates/router/src/core/health_check.rs index e90fe77e8087..6092ac8bbb98 100644 --- a/crates/router/src/core/health_check.rs +++ b/crates/router/src/core/health_check.rs @@ -31,7 +31,7 @@ pub trait HealthCheckInterface { } #[async_trait::async_trait] -impl HealthCheckInterface for app::AppState { +impl HealthCheckInterface for app::SessionState { async fn health_check_db(&self) -> CustomResult { let db = &*self.store; db.health_check_db().await?; diff --git a/crates/router/src/core/locker_migration.rs b/crates/router/src/core/locker_migration.rs index 9dbc54287484..d968e62bea88 100644 --- a/crates/router/src/core/locker_migration.rs +++ b/crates/router/src/core/locker_migration.rs @@ -7,13 +7,13 @@ use futures::TryFutureExt; use super::{errors::StorageErrorExt, payment_methods::cards}; use crate::{ errors, - routes::AppState, + routes::SessionState, services::{self, logger}, types::{api, domain}, }; pub async fn rust_locker_migration( - state: AppState, + state: SessionState, merchant_id: &str, ) -> CustomResult, errors::ApiErrorResponse> { let db = state.store.as_ref(); @@ -75,7 +75,7 @@ pub async fn rust_locker_migration( } pub async fn call_to_locker( - state: &AppState, + state: &SessionState, payment_methods: Vec, customer_id: &id_type::CustomerId, merchant_id: &str, @@ -140,6 +140,7 @@ pub async fn call_to_locker( merchant_account, api_enums::LockerChoice::HyperswitchCardVault, Some(pm.locker_id.as_ref().unwrap_or(&pm.payment_method_id)), + ) .await .change_context(errors::ApiErrorResponse::InternalServerError) diff --git a/crates/router/src/core/mandate.rs b/crates/router/src/core/mandate.rs index 839f55dea2db..f484467f3547 100644 --- a/crates/router/src/core/mandate.rs +++ b/crates/router/src/core/mandate.rs @@ -14,7 +14,7 @@ use crate::{ payments::CallConnectorAction, }, db::StorageInterface, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services, types::{ self, @@ -32,7 +32,7 @@ use crate::{ #[instrument(skip(state))] pub async fn get_mandate( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: mandates::MandateId, @@ -60,7 +60,7 @@ pub async fn get_mandate( #[instrument(skip(state))] pub async fn revoke_mandate( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: mandates::MandateId, @@ -223,7 +223,7 @@ pub async fn update_connector_mandate_id( #[instrument(skip(state))] pub async fn get_customer_mandates( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: customers::CustomerId, @@ -271,7 +271,7 @@ where } } pub async fn update_mandate_procedure( - state: &AppState, + state: &SessionState, resp: types::RouterData, mandate: Mandate, merchant_id: &str, @@ -342,7 +342,7 @@ where } pub async fn mandate_procedure( - state: &AppState, + state: &SessionState, resp: &types::RouterData, customer_id: &Option, pm_id: Option, @@ -472,7 +472,7 @@ where #[instrument(skip(state))] pub async fn retrieve_mandates_list( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, constraints: api_models::mandates::MandateListConstraints, diff --git a/crates/router/src/core/mandate/helpers.rs b/crates/router/src/core/mandate/helpers.rs index 4e9d07b7f828..b0c727925df5 100644 --- a/crates/router/src/core/mandate/helpers.rs +++ b/crates/router/src/core/mandate/helpers.rs @@ -7,12 +7,12 @@ use hyperswitch_domain_models::mandates::MandateData; use crate::{ core::{errors, payments}, - routes::AppState, + routes::SessionState, types::{api, domain}, }; pub async fn get_profile_id_for_mandate( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, mandate: Mandate, ) -> CustomResult { diff --git a/crates/router/src/core/payment_link.rs b/crates/router/src/core/payment_link.rs index 9b8fd3cbe0ef..e4ef38ae3512 100644 --- a/crates/router/src/core/payment_link.rs +++ b/crates/router/src/core/payment_link.rs @@ -14,7 +14,7 @@ use time::PrimitiveDateTime; use super::errors::{self, RouterResult, StorageErrorExt}; use crate::{ errors::RouterResponse, - routes::AppState, + routes::SessionState, services, types::{ api::payment_link::PaymentLinkResponseExt, domain, storage::enums as storage_enums, @@ -23,7 +23,7 @@ use crate::{ }; pub async fn retrieve_payment_link( - state: AppState, + state: SessionState, payment_link_id: String, ) -> RouterResponse { let db = &*state.store; @@ -47,7 +47,7 @@ pub async fn retrieve_payment_link( } pub async fn initiate_payment_link_flow( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, merchant_id: String, payment_id: String, @@ -287,7 +287,7 @@ fn validate_sdk_requirements( } pub async fn list_payment_link( - state: AppState, + state: SessionState, merchant: domain::MerchantAccount, constraints: api_models::payments::PaymentLinkListConstraints, ) -> RouterResponse> { @@ -501,7 +501,7 @@ fn check_payment_link_invalid_conditions( } pub async fn get_payment_link_status( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, merchant_id: String, payment_id: String, diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 71f0bdac03a9..b6d95248abc6 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -13,7 +13,7 @@ use router_env::{instrument, tracing}; use crate::{ core::{errors::RouterResult, payments::helpers, pm_auth as core_pm_auth}, - routes::AppState, + routes::SessionState, types::{ api::{self, payments}, domain, storage, @@ -23,7 +23,7 @@ use crate::{ #[instrument(skip_all)] pub async fn retrieve_payment_method( pm_data: &Option, - state: &AppState, + state: &SessionState, payment_intent: &PaymentIntent, payment_attempt: &PaymentAttempt, merchant_key_store: &domain::MerchantKeyStore, @@ -95,7 +95,7 @@ pub async fn retrieve_payment_method( #[instrument(skip_all)] pub async fn retrieve_payment_method_with_token( - state: &AppState, + state: &SessionState, merchant_key_store: &domain::MerchantKeyStore, token_data: &storage::PaymentTokenData, payment_intent: &PaymentIntent, diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 66a695b2b0c5..c62f47b5362b 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -263,7 +263,7 @@ pub async fn get_or_insert_payment_method( #[instrument(skip_all)] pub async fn get_client_secret_or_add_payment_method( - state: routes::AppState, + state: routes::SessionState, req: api::PaymentMethodCreate, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -337,7 +337,7 @@ pub fn authenticate_pm_client_secret_and_check_expiry( #[instrument(skip_all)] pub async fn add_payment_method_data( - state: routes::AppState, + state: routes::SessionState, req: api::PaymentMethodCreate, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, @@ -513,7 +513,7 @@ pub async fn add_payment_method_data( #[instrument(skip_all)] pub async fn add_payment_method( - state: routes::AppState, + state: routes::SessionState, req: api::PaymentMethodCreate, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -761,7 +761,7 @@ pub async fn insert_payment_method( #[instrument(skip_all)] pub async fn update_customer_payment_method( - state: routes::AppState, + state: routes::SessionState, merchant_account: domain::MerchantAccount, req: api::PaymentMethodUpdate, payment_method_id: &str, @@ -1017,7 +1017,7 @@ pub fn validate_payment_method_update( #[cfg(feature = "payouts")] pub async fn add_bank_to_locker( - state: &routes::AppState, + state: &routes::SessionState, req: api::PaymentMethodCreate, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -1082,7 +1082,7 @@ pub async fn add_bank_to_locker( /// The response will be the tuple of PaymentMethodResponse and the duplication check of payment_method pub async fn add_card_to_locker( - state: &routes::AppState, + state: &routes::SessionState, req: api::PaymentMethodCreate, card: &api::CardDetail, customer_id: &id_type::CustomerId, @@ -1130,7 +1130,7 @@ pub async fn add_card_to_locker( } pub async fn get_card_from_locker( - state: &routes::AppState, + state: &routes::SessionState, customer_id: &id_type::CustomerId, merchant_id: &str, card_reference: &str, @@ -1171,7 +1171,7 @@ pub async fn get_card_from_locker( } pub async fn delete_card_from_locker( - state: &routes::AppState, + state: &routes::SessionState, customer_id: &id_type::CustomerId, merchant_id: &str, card_reference: &str, @@ -1195,7 +1195,7 @@ pub async fn delete_card_from_locker( #[instrument(skip_all)] pub async fn add_card_hs( - state: &routes::AppState, + state: &routes::SessionState, req: api::PaymentMethodCreate, card: &api::CardDetail, customer_id: &id_type::CustomerId, @@ -1259,7 +1259,7 @@ pub async fn decode_and_decrypt_locker_data( #[instrument(skip_all)] pub async fn get_payment_method_from_hs_locker<'a>( - state: &'a routes::AppState, + state: &'a routes::SessionState, key_store: &domain::MerchantKeyStore, customer_id: &id_type::CustomerId, merchant_id: &str, @@ -1321,7 +1321,7 @@ pub async fn get_payment_method_from_hs_locker<'a>( #[instrument(skip_all)] pub async fn call_to_locker_hs<'a>( - state: &routes::AppState, + state: &routes::SessionState, payload: &payment_methods::StoreLockerReq<'a>, customer_id: &id_type::CustomerId, locker_choice: api_enums::LockerChoice, @@ -1394,7 +1394,7 @@ pub async fn update_payment_method_connector_mandate_details( } #[instrument(skip_all)] pub async fn get_card_from_hs_locker<'a>( - state: &'a routes::AppState, + state: &'a routes::SessionState, customer_id: &id_type::CustomerId, merchant_id: &str, card_reference: &'a str, @@ -1447,7 +1447,7 @@ pub async fn get_card_from_hs_locker<'a>( #[instrument(skip_all)] pub async fn delete_card_from_hs_locker<'a>( - state: &routes::AppState, + state: &routes::SessionState, customer_id: &id_type::CustomerId, merchant_id: &str, card_reference: &'a str, @@ -1652,7 +1652,7 @@ pub async fn mock_delete_card<'a>( } //------------------------------------------------------------------------------ pub fn get_banks( - state: &routes::AppState, + state: &routes::SessionState, pm_type: common_enums::enums::PaymentMethodType, connectors: Vec, ) -> Result, errors::ApiErrorResponse> { @@ -1734,7 +1734,7 @@ fn get_val(str: String, val: &serde_json::Value) -> Option { } pub async fn list_payment_methods( - state: routes::AppState, + state: routes::SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, mut req: api::PaymentMethodListRequest, @@ -2660,7 +2660,7 @@ async fn validate_payment_method_and_client_secret( } pub async fn call_surcharge_decision_management( - state: routes::AppState, + state: routes::SessionState, merchant_account: &domain::MerchantAccount, business_profile: &BusinessProfile, payment_attempt: &storage::PaymentAttempt, @@ -2710,7 +2710,7 @@ pub async fn call_surcharge_decision_management( } pub async fn call_surcharge_decision_management_for_saved_card( - state: &routes::AppState, + state: &routes::SessionState, merchant_account: &domain::MerchantAccount, business_profile: &BusinessProfile, payment_attempt: &storage::PaymentAttempt, @@ -3313,7 +3313,7 @@ async fn filter_payment_mandate_based( } pub async fn do_list_customer_pm_fetch_customer_if_not_passed( - state: routes::AppState, + state: routes::SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: Option, @@ -3369,7 +3369,7 @@ pub async fn do_list_customer_pm_fetch_customer_if_not_passed( } pub async fn list_customer_payment_method( - state: &routes::AppState, + state: &routes::SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, payment_intent: Option, @@ -3684,7 +3684,7 @@ pub async fn list_customer_payment_method( Ok(services::ApplicationResponse::Json(response)) } pub async fn get_mca_status( - state: &routes::AppState, + state: &routes::SessionState, key_store: &domain::MerchantKeyStore, merchant_id: &str, connector_mandate_details: Option, @@ -3744,7 +3744,7 @@ where pub async fn get_card_details_with_locker_fallback( pm: &payment_method::PaymentMethod, key: &[u8], - state: &routes::AppState, + state: &routes::SessionState, ) -> errors::RouterResult> { let card_decrypted = decrypt::(pm.payment_method_data.clone(), key) @@ -3775,7 +3775,7 @@ pub async fn get_card_details_with_locker_fallback( pub async fn get_card_details_without_locker_fallback( pm: &payment_method::PaymentMethod, key: &[u8], - state: &routes::AppState, + state: &routes::SessionState, ) -> errors::RouterResult { let card_decrypted = decrypt::(pm.payment_method_data.clone(), key) @@ -3800,7 +3800,7 @@ pub async fn get_card_details_without_locker_fallback( } pub async fn get_card_details_from_locker( - state: &routes::AppState, + state: &routes::SessionState, pm: &storage::PaymentMethod, ) -> errors::RouterResult { let card = get_card_from_locker( @@ -3819,7 +3819,7 @@ pub async fn get_card_details_from_locker( } pub async fn get_lookup_key_from_locker( - state: &routes::AppState, + state: &routes::SessionState, payment_token: &str, pm: &storage::PaymentMethod, merchant_key_store: &domain::MerchantKeyStore, @@ -4004,7 +4004,7 @@ pub async fn set_default_payment_method( pub async fn update_last_used_at( pm_id: &str, - state: &routes::AppState, + state: &routes::SessionState, storage_scheme: MerchantStorageScheme, ) -> errors::RouterResult<()> { let update_last_used = storage::PaymentMethodUpdate::LastUsedUpdate { @@ -4026,7 +4026,7 @@ pub async fn update_last_used_at( } #[cfg(feature = "payouts")] pub async fn get_bank_from_hs_locker( - state: &routes::AppState, + state: &routes::SessionState, key_store: &domain::MerchantKeyStore, temp_token: &str, customer_id: &id_type::CustomerId, @@ -4079,7 +4079,7 @@ pub struct TempLockerCardSupport; impl TempLockerCardSupport { #[instrument(skip_all)] async fn create_payment_method_data_in_temp_locker( - state: &routes::AppState, + state: &routes::SessionState, payment_token: &str, card: api::CardDetailFromLocker, pm: &storage::PaymentMethod, @@ -4161,7 +4161,7 @@ impl TempLockerCardSupport { #[instrument(skip_all)] pub async fn retrieve_payment_method( - state: routes::AppState, + state: routes::SessionState, pm: api::PaymentMethodId, key_store: domain::MerchantKeyStore, merchant_account: domain::MerchantAccount, @@ -4217,7 +4217,7 @@ pub async fn retrieve_payment_method( #[instrument(skip_all)] pub async fn delete_payment_method( - state: routes::AppState, + state: routes::SessionState, merchant_account: domain::MerchantAccount, pm_id: api::PaymentMethodId, key_store: domain::MerchantKeyStore, @@ -4342,7 +4342,7 @@ where } pub async fn list_countries_currencies_for_connector_payment_method( - state: routes::AppState, + state: routes::SessionState, req: ListCountriesCurrenciesRequest, ) -> errors::RouterResponse { Ok(services::ApplicationResponse::Json( diff --git a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs index 76881950e3bf..14beb6be1310 100644 --- a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs +++ b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs @@ -26,7 +26,7 @@ use crate::{ storage::{self, payment_attempt::PaymentAttemptExt}, transformers::ForeignTryFrom, }, - AppState, + SessionState, }; static CONF_CACHE: StaticCache = StaticCache::new(); @@ -95,7 +95,7 @@ impl SurchargeSource { } pub async fn perform_surcharge_decision_management_for_payment_method_list( - state: &AppState, + state: &SessionState, algorithm_ref: routing::RoutingAlgorithmRef, payment_attempt: &storage::PaymentAttempt, payment_intent: &storage::PaymentIntent, @@ -215,7 +215,7 @@ pub async fn perform_surcharge_decision_management_for_payment_method_list( } pub async fn perform_surcharge_decision_management_for_session_flow( - state: &AppState, + state: &SessionState, algorithm_ref: routing::RoutingAlgorithmRef, payment_data: &mut PaymentData, payment_method_type_list: &Vec, @@ -276,7 +276,7 @@ where Ok(surcharge_metadata) } pub async fn perform_surcharge_decision_management_for_saved_cards( - state: &AppState, + state: &SessionState, algorithm_ref: routing::RoutingAlgorithmRef, payment_attempt: &storage::PaymentAttempt, payment_intent: &storage::PaymentIntent, diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs index e0d8bada65ef..9e20017d57fb 100644 --- a/crates/router/src/core/payment_methods/vault.rs +++ b/crates/router/src/core/payment_methods/vault.rs @@ -818,7 +818,7 @@ pub struct Vault; impl Vault { #[instrument(skip_all)] pub async fn get_payment_method_data_from_locker( - state: &routes::AppState, + state: &routes::SessionState, lookup_key: &str, merchant_key_store: &domain::MerchantKeyStore, ) -> RouterResult<(Option, SupplementaryVaultData)> { @@ -834,7 +834,7 @@ impl Vault { #[instrument(skip_all)] pub async fn store_payment_method_data_in_locker( - state: &routes::AppState, + state: &routes::SessionState, token_id: Option, payment_method: &api::PaymentMethodData, customer_id: Option, @@ -869,7 +869,7 @@ impl Vault { #[cfg(feature = "payouts")] #[instrument(skip_all)] pub async fn get_payout_method_data_from_temporary_locker( - state: &routes::AppState, + state: &routes::SessionState, lookup_key: &str, merchant_key_store: &domain::MerchantKeyStore, ) -> RouterResult<(Option, SupplementaryVaultData)> { @@ -886,7 +886,7 @@ impl Vault { #[cfg(feature = "payouts")] #[instrument(skip_all)] pub async fn store_payout_method_data_in_locker( - state: &routes::AppState, + state: &routes::SessionState, token_id: Option, payout_method: &api::PayoutMethodData, customer_id: Option, @@ -920,7 +920,7 @@ impl Vault { #[instrument(skip_all)] pub async fn delete_locker_payment_method_by_lookup_key( - state: &routes::AppState, + state: &routes::SessionState, lookup_key: &Option, ) { if let Some(lookup_key) = lookup_key { @@ -942,7 +942,7 @@ fn get_redis_locker_key(lookup_key: &str) -> String { #[instrument(skip(state, value1, value2))] pub async fn create_tokenize( - state: &routes::AppState, + state: &routes::SessionState, value1: String, value2: Option, lookup_key: String, @@ -1007,7 +1007,7 @@ pub async fn create_tokenize( #[instrument(skip(state))] pub async fn get_tokenized_data( - state: &routes::AppState, + state: &routes::SessionState, lookup_key: &str, _should_get_value2: bool, encryption_key: &masking::Secret>, @@ -1069,7 +1069,10 @@ pub async fn get_tokenized_data( } #[instrument(skip(state))] -pub async fn delete_tokenized_data(state: &routes::AppState, lookup_key: &str) -> RouterResult<()> { +pub async fn delete_tokenized_data( + state: &routes::SessionState, + lookup_key: &str, +) -> RouterResult<()> { let redis_key = get_redis_locker_key(lookup_key); let func = || async { metrics::DELETED_TOKENIZED_CARD.add(&metrics::CONTEXT, 1, &[]); @@ -1153,7 +1156,7 @@ pub async fn add_delete_tokenized_data_task( } pub async fn start_tokenize_data_workflow( - state: &routes::AppState, + state: &routes::SessionState, tokenize_tracker: &storage::ProcessTracker, ) -> Result<(), errors::ProcessTrackerError> { let db = &*state.store; diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 3988f3d4fd0d..caaecdc8629c 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -77,7 +77,7 @@ use crate::{ }, db::StorageInterface, logger, - routes::{app::ReqState, metrics, payment_methods::ParentPaymentMethodToken, AppState}, + routes::{app::ReqState, metrics, payment_methods::ParentPaymentMethodToken, SessionState}, services::{self, api::Authenticate}, types::{ self as router_types, @@ -97,7 +97,7 @@ use crate::{ #[allow(clippy::too_many_arguments, clippy::type_complexity)] #[instrument(skip_all, fields(payment_id, merchant_id))] pub async fn payments_operation_core( - state: &AppState, + state: &SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, @@ -571,7 +571,7 @@ where #[instrument(skip_all)] pub async fn call_decision_manager( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, payment_data: &mut PaymentData, ) -> RouterResult<()> @@ -606,7 +606,7 @@ where #[instrument(skip_all)] async fn populate_surcharge_details( - state: &AppState, + state: &SessionState, payment_data: &mut PaymentData, ) -> RouterResult<()> where @@ -686,7 +686,7 @@ pub fn get_connector_data( #[instrument(skip_all)] pub async fn call_surcharge_decision_management_for_session_flow( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, payment_data: &mut PaymentData, session_connector_data: &[api::SessionConnectorData], @@ -741,7 +741,7 @@ where } #[allow(clippy::too_many_arguments)] pub async fn payments_core( - state: AppState, + state: SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, @@ -794,7 +794,7 @@ where payment_data, customer, auth_flow, - &state.conf.server, + &state.base_url, operation, &state.conf.connector_request_reference_id_config, connector_http_status_code, @@ -826,7 +826,7 @@ pub trait PaymentRedirectFlow: Sync { #[allow(clippy::too_many_arguments)] async fn call_payment_flow( &self, - state: &AppState, + state: &SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, merchant_key_store: domain::MerchantKeyStore, @@ -848,7 +848,7 @@ pub trait PaymentRedirectFlow: Sync { #[allow(clippy::too_many_arguments)] async fn handle_payments_redirect_response( &self, - state: AppState, + state: SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, @@ -923,7 +923,7 @@ impl PaymentRedirectFlow for PaymentRedirectCompleteAuthorize { #[allow(clippy::too_many_arguments)] async fn call_payment_flow( &self, - state: &AppState, + state: &SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, merchant_key_store: domain::MerchantKeyStore, @@ -1055,7 +1055,7 @@ impl PaymentRedirectFlow for PaymentRedirectSync { #[allow(clippy::too_many_arguments)] async fn call_payment_flow( &self, - state: &AppState, + state: &SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, merchant_key_store: domain::MerchantKeyStore, @@ -1146,7 +1146,7 @@ impl PaymentRedirectFlow for PaymentAuthenticateCompleteAuthorize { #[allow(clippy::too_many_arguments)] async fn call_payment_flow( &self, - state: &AppState, + state: &SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, merchant_key_store: domain::MerchantKeyStore, @@ -1378,7 +1378,7 @@ impl PaymentRedirectFlow for PaymentAuthenticateCompleteAuthorize { #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] pub async fn call_connector_service( - state: &AppState, + state: &SessionState, req_state: ReqState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -1613,7 +1613,7 @@ where } async fn blocklist_guard( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, operation: &BoxedOperation<'_, F, ApiRequest>, payment_data: &mut PaymentData, @@ -1652,7 +1652,7 @@ where #[allow(clippy::too_many_arguments)] pub async fn call_multiple_connectors_service( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connectors: Vec, @@ -1769,7 +1769,7 @@ where } pub async fn call_create_connector_customer_if_required( - state: &AppState, + state: &SessionState, customer: &Option, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -1871,7 +1871,7 @@ where } async fn complete_preprocessing_steps_if_required( - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, payment_data: &PaymentData, mut router_data: RouterData, @@ -2011,7 +2011,7 @@ pub fn is_preprocessing_required_for_wallets(connector_name: String) -> bool { #[instrument(skip_all)] pub async fn construct_profile_id_and_get_mca<'a, F>( - state: &'a AppState, + state: &'a SessionState, merchant_account: &domain::MerchantAccount, payment_data: &mut PaymentData, connector_name: &str, @@ -2049,7 +2049,7 @@ where } fn is_payment_method_tokenization_enabled_for_connector( - state: &AppState, + state: &SessionState, connector_name: &str, payment_method: &storage::enums::PaymentMethod, payment_method_type: &Option, @@ -2168,7 +2168,7 @@ fn is_payment_method_type_allowed_for_connector( } async fn decide_payment_method_tokenize_action( - state: &AppState, + state: &SessionState, connector_name: &str, payment_method: &storage::enums::PaymentMethod, pm_parent_token: Option<&String>, @@ -2241,7 +2241,7 @@ pub enum TokenizationAction { #[allow(clippy::too_many_arguments)] pub async fn get_connector_tokenization_action_when_confirm_true( - state: &AppState, + state: &SessionState, operation: &BoxedOperation<'_, F, Req>, payment_data: &mut PaymentData, validate_result: &operations::ValidateResult<'_>, @@ -2365,7 +2365,7 @@ where } pub async fn tokenize_in_router_when_confirm_false_or_external_authentication( - state: &AppState, + state: &SessionState, operation: &BoxedOperation<'_, F, Req>, payment_data: &mut PaymentData, validate_result: &operations::ValidateResult<'_>, @@ -2616,7 +2616,7 @@ pub fn is_operation_complete_authorize(operation: &Op) -> bool { #[cfg(feature = "olap")] pub async fn list_payments( - state: AppState, + state: SessionState, merchant: domain::MerchantAccount, constraints: api::PaymentListConstraints, ) -> RouterResponse { @@ -2682,7 +2682,7 @@ pub async fn list_payments( } #[cfg(feature = "olap")] pub async fn apply_filters_on_payments( - state: AppState, + state: SessionState, merchant: domain::MerchantAccount, constraints: api::PaymentListFilterConstraints, ) -> RouterResponse { @@ -2735,7 +2735,7 @@ pub async fn apply_filters_on_payments( #[cfg(feature = "olap")] pub async fn get_filters_for_payments( - state: AppState, + state: SessionState, merchant: domain::MerchantAccount, time_range: api::TimeRange, ) -> RouterResponse { @@ -2773,7 +2773,7 @@ pub async fn get_filters_for_payments( #[cfg(feature = "olap")] pub async fn get_payment_filters( - state: AppState, + state: SessionState, merchant: domain::MerchantAccount, ) -> RouterResponse { let merchant_connector_accounts = if let services::ApplicationResponse::Json(data) = @@ -2931,7 +2931,7 @@ where #[allow(clippy::too_many_arguments)] pub async fn get_connector_choice( operation: &BoxedOperation<'_, F, Req>, - state: &AppState, + state: &SessionState, req: &Req, merchant_account: &domain::MerchantAccount, business_profile: &storage::business_profile::BusinessProfile, @@ -3010,7 +3010,7 @@ where #[allow(clippy::too_many_arguments)] pub async fn connector_selection( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, business_profile: &storage::business_profile::BusinessProfile, key_store: &domain::MerchantKeyStore, @@ -3085,7 +3085,7 @@ where #[allow(clippy::too_many_arguments)] pub async fn decide_connector( - state: AppState, + state: SessionState, merchant_account: &domain::MerchantAccount, business_profile: &storage::business_profile::BusinessProfile, key_store: &domain::MerchantKeyStore, @@ -3332,7 +3332,7 @@ where } pub async fn decide_multiplex_connector_for_normal_or_recurring_payment( - state: &AppState, + state: &SessionState, payment_data: &mut PaymentData, routing_data: &mut storage::RoutingData, connectors: Vec, @@ -3511,7 +3511,7 @@ pub async fn decide_multiplex_connector_for_normal_or_recurring_payment, connector: enums::Connector, payment_method_info: &storage::PaymentMethod, @@ -3540,7 +3540,7 @@ pub fn should_add_task_to_process_tracker(payment_data: &PaymentData( - state: AppState, + state: SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, payment_data: &mut PaymentData, @@ -3652,7 +3652,7 @@ where #[allow(clippy::too_many_arguments)] pub async fn route_connector_v1( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, business_profile: &storage::business_profile::BusinessProfile, key_store: &domain::MerchantKeyStore, @@ -3775,7 +3775,7 @@ where #[instrument(skip_all)] pub async fn payment_external_authentication( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: api_models::payments::PaymentsExternalAuthenticationRequest, @@ -3908,15 +3908,12 @@ pub async fn payment_external_authentication( .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable("missing connector in payment_attempt")?; let return_url = Some(helpers::create_authorize_url( - &state.conf.server.base_url, + &state.base_url, &payment_attempt.clone(), payment_connector_name, )); - let webhook_url = helpers::create_webhook_url( - &state.conf.server.base_url, - merchant_id, - &authentication_connector, - ); + let webhook_url = + helpers::create_webhook_url(&state.base_url, merchant_id, &authentication_connector); let business_profile = state .store @@ -3987,7 +3984,7 @@ pub async fn payment_external_authentication( #[instrument(skip_all)] pub async fn get_extended_card_info( - state: AppState, + state: SessionState, merchant_id: String, payment_id: String, ) -> RouterResponse { diff --git a/crates/router/src/core/payments/access_token.rs b/crates/router/src/core/payments/access_token.rs index 0c5aa13eb2f9..4241db6742da 100644 --- a/crates/router/src/core/payments/access_token.rs +++ b/crates/router/src/core/payments/access_token.rs @@ -9,7 +9,7 @@ use crate::{ errors::{self, RouterResult}, payments, }, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services::{self, logger}, types::{self, api as api_types, domain}, }; @@ -53,7 +53,7 @@ pub async fn add_access_token< Req: Debug + Clone + 'static, Res: Debug + Clone + 'static, >( - state: &AppState, + state: &SessionState, connector: &api_types::ConnectorData, merchant_account: &domain::MerchantAccount, router_data: &types::RouterData, @@ -194,7 +194,7 @@ pub async fn add_access_token< } pub async fn refresh_connector_auth( - state: &AppState, + state: &SessionState, connector: &api_types::ConnectorData, _merchant_account: &domain::MerchantAccount, router_data: &types::RouterData< diff --git a/crates/router/src/core/payments/conditional_configs.rs b/crates/router/src/core/payments/conditional_configs.rs index 5dc78d42e5ea..c73fa3659b70 100644 --- a/crates/router/src/core/payments/conditional_configs.rs +++ b/crates/router/src/core/payments/conditional_configs.rs @@ -21,7 +21,7 @@ pub type ConditionalConfigResult = errors::CustomResult; #[instrument(skip_all)] pub async fn perform_decision_management( - state: &routes::AppState, + state: &routes::SessionState, algorithm_ref: routing::RoutingAlgorithmRef, merchant_id: &str, payment_data: &mut payments::PaymentData, @@ -51,7 +51,7 @@ pub async fn perform_decision_management( #[instrument(skip_all)] pub async fn ensure_algorithm_cached( - state: &routes::AppState, + state: &routes::SessionState, merchant_id: &str, timestamp: i64, algorithm_id: &str, @@ -73,7 +73,7 @@ pub async fn ensure_algorithm_cached( #[instrument(skip_all)] pub async fn refresh_routing_cache( - state: &routes::AppState, + state: &routes::SessionState, key: String, algorithm_id: &str, timestamp: i64, diff --git a/crates/router/src/core/payments/customers.rs b/crates/router/src/core/payments/customers.rs index ff56eaf46ebf..448e5fedb8b1 100644 --- a/crates/router/src/core/payments/customers.rs +++ b/crates/router/src/core/payments/customers.rs @@ -6,14 +6,14 @@ use crate::{ payments, }, logger, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services, types::{self, api, domain, storage}, }; #[instrument(skip_all)] pub async fn create_connector_customer( - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, router_data: &types::RouterData, customer_request_data: types::ConnectorCustomerData, @@ -88,7 +88,7 @@ pub fn get_connector_customer_details_if_present<'a>( } pub fn should_call_connector_create_customer<'a>( - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, customer: &'a Option, connector_label: &str, diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index 158e28e69678..674fa4539276 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -19,7 +19,7 @@ use crate::{ errors::{ConnectorError, CustomResult, RouterResult}, payments::{self, helpers}, }, - routes::AppState, + routes::SessionState, services, types::{self, api, domain, storage}, }; @@ -28,7 +28,7 @@ use crate::{ pub trait ConstructFlowSpecificData { async fn construct_router_data<'a>( &self, - state: &AppState, + state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -42,7 +42,7 @@ pub trait ConstructFlowSpecificData { pub trait Feature { async fn decide_flows<'a>( self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, connector_request: Option, @@ -55,7 +55,7 @@ pub trait Feature { async fn add_access_token<'a>( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, ) -> RouterResult @@ -66,7 +66,7 @@ pub trait Feature { async fn add_payment_method_token<'a>( &mut self, - _state: &AppState, + _state: &SessionState, _connector: &api::ConnectorData, _tokenization_action: &payments::TokenizationAction, ) -> RouterResult> @@ -80,7 +80,7 @@ pub trait Feature { async fn preprocessing_steps<'a>( self, - _state: &AppState, + _state: &SessionState, _connector: &api::ConnectorData, ) -> RouterResult where @@ -93,7 +93,7 @@ pub trait Feature { async fn create_connector_customer<'a>( &self, - _state: &AppState, + _state: &SessionState, _connector: &api::ConnectorData, ) -> RouterResult> where @@ -107,7 +107,7 @@ pub trait Feature { /// Returns the connector request and a bool which specifies whether to proceed with further async fn build_flow_specific_connector_request( &mut self, - _state: &AppState, + _state: &SessionState, _connector: &api::ConnectorData, _call_connector_action: payments::CallConnectorAction, ) -> RouterResult<(Option, bool)> { diff --git a/crates/router/src/core/payments/flows/approve_flow.rs b/crates/router/src/core/payments/flows/approve_flow.rs index 95ca0c3e31c7..6d4a88c0bf0e 100644 --- a/crates/router/src/core/payments/flows/approve_flow.rs +++ b/crates/router/src/core/payments/flows/approve_flow.rs @@ -6,7 +6,7 @@ use crate::{ errors::{ApiErrorResponse, NotImplementedMessage, RouterResult}, payments::{self, access_token, helpers, transformers, PaymentData}, }, - routes::AppState, + routes::SessionState, services, types::{self, api, domain, storage}, }; @@ -18,7 +18,7 @@ impl { async fn construct_router_data<'a>( &self, - state: &AppState, + state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -47,7 +47,7 @@ impl Feature { async fn decide_flows<'a>( self, - _state: &AppState, + _state: &SessionState, _connector: &api::ConnectorData, _call_connector_action: payments::CallConnectorAction, _connector_request: Option, @@ -61,7 +61,7 @@ impl Feature async fn add_access_token<'a>( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, ) -> RouterResult { @@ -70,7 +70,7 @@ impl Feature async fn build_flow_specific_connector_request( &mut self, - _state: &AppState, + _state: &SessionState, _connector: &api::ConnectorData, _call_connector_action: payments::CallConnectorAction, ) -> RouterResult<(Option, bool)> { diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs index 5990b29f372a..d672da99910d 100644 --- a/crates/router/src/core/payments/flows/authorize_flow.rs +++ b/crates/router/src/core/payments/flows/authorize_flow.rs @@ -11,7 +11,7 @@ use crate::{ }, }, logger, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services, types::{self, api, domain, storage}, }; @@ -26,7 +26,7 @@ impl { async fn construct_router_data<'a>( &self, - state: &AppState, + state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -58,7 +58,7 @@ impl impl Feature for types::PaymentsAuthorizeRouterData { async fn decide_flows<'a>( mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, connector_request: Option, @@ -93,7 +93,7 @@ impl Feature for types::PaymentsAu async fn add_access_token<'a>( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, ) -> RouterResult { @@ -102,7 +102,7 @@ impl Feature for types::PaymentsAu async fn add_payment_method_token<'a>( &mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, tokenization_action: &payments::TokenizationAction, ) -> RouterResult> { @@ -119,7 +119,7 @@ impl Feature for types::PaymentsAu async fn preprocessing_steps<'a>( self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, ) -> RouterResult { authorize_preprocessing_steps(state, &self, true, connector).await @@ -127,7 +127,7 @@ impl Feature for types::PaymentsAu async fn create_connector_customer<'a>( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, ) -> RouterResult> { customers::create_connector_customer( @@ -141,7 +141,7 @@ impl Feature for types::PaymentsAu async fn build_flow_specific_connector_request( &mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, ) -> RouterResult<(Option, bool)> { @@ -266,7 +266,7 @@ impl mandate::MandateBehaviour for types::PaymentsAuthorizeData { } pub async fn authorize_preprocessing_steps( - state: &AppState, + state: &SessionState, router_data: &types::RouterData, confirm: bool, connector: &api::ConnectorData, diff --git a/crates/router/src/core/payments/flows/cancel_flow.rs b/crates/router/src/core/payments/flows/cancel_flow.rs index 0e90ab40b696..d7e8cc3d9b57 100644 --- a/crates/router/src/core/payments/flows/cancel_flow.rs +++ b/crates/router/src/core/payments/flows/cancel_flow.rs @@ -6,7 +6,7 @@ use crate::{ errors::{ConnectorErrorExt, RouterResult}, payments::{self, access_token, helpers, transformers, PaymentData}, }, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services, types::{self, api, domain, storage}, }; @@ -17,7 +17,7 @@ impl ConstructFlowSpecificData( &self, - state: &AppState, + state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -46,7 +46,7 @@ impl Feature { async fn decide_flows<'a>( self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, connector_request: Option, @@ -83,7 +83,7 @@ impl Feature async fn add_access_token<'a>( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, ) -> RouterResult { @@ -92,7 +92,7 @@ impl Feature async fn build_flow_specific_connector_request( &mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, ) -> RouterResult<(Option, bool)> { diff --git a/crates/router/src/core/payments/flows/capture_flow.rs b/crates/router/src/core/payments/flows/capture_flow.rs index b979eb2a337d..268281e51573 100644 --- a/crates/router/src/core/payments/flows/capture_flow.rs +++ b/crates/router/src/core/payments/flows/capture_flow.rs @@ -6,7 +6,7 @@ use crate::{ errors::{ConnectorErrorExt, RouterResult}, payments::{self, access_token, helpers, transformers, Feature, PaymentData}, }, - routes::AppState, + routes::SessionState, services, types::{self, api, domain, storage}, }; @@ -18,7 +18,7 @@ impl { async fn construct_router_data<'a>( &self, - state: &AppState, + state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -47,7 +47,7 @@ impl Feature { async fn decide_flows<'a>( self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, connector_request: Option, @@ -75,7 +75,7 @@ impl Feature async fn add_access_token<'a>( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, ) -> RouterResult { @@ -84,7 +84,7 @@ impl Feature async fn build_flow_specific_connector_request( &mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, ) -> RouterResult<(Option, bool)> { diff --git a/crates/router/src/core/payments/flows/complete_authorize_flow.rs b/crates/router/src/core/payments/flows/complete_authorize_flow.rs index c14cf6c80892..5d0cb9f9f381 100644 --- a/crates/router/src/core/payments/flows/complete_authorize_flow.rs +++ b/crates/router/src/core/payments/flows/complete_authorize_flow.rs @@ -6,7 +6,7 @@ use crate::{ errors::{ConnectorErrorExt, RouterResult}, payments::{self, access_token, helpers, transformers, PaymentData}, }, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services, types::{self, api, domain, storage}, }; @@ -21,7 +21,7 @@ impl { async fn construct_router_data<'a>( &self, - state: &AppState, + state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -60,7 +60,7 @@ impl Feature { async fn decide_flows<'a>( mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, connector_request: Option, @@ -88,7 +88,7 @@ impl Feature async fn add_access_token<'a>( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, ) -> RouterResult { @@ -97,7 +97,7 @@ impl Feature async fn add_payment_method_token<'a>( &mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, _tokenization_action: &payments::TokenizationAction, ) -> RouterResult> { @@ -119,7 +119,7 @@ impl Feature async fn build_flow_specific_connector_request( &mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, ) -> RouterResult<(Option, bool)> { @@ -144,7 +144,7 @@ impl Feature async fn preprocessing_steps<'a>( self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, ) -> RouterResult { complete_authorize_preprocessing_steps(state, &self, true, connector).await @@ -152,7 +152,7 @@ impl Feature } pub async fn complete_authorize_preprocessing_steps( - state: &AppState, + state: &SessionState, router_data: &types::RouterData, confirm: bool, connector: &api::ConnectorData, diff --git a/crates/router/src/core/payments/flows/incremental_authorization_flow.rs b/crates/router/src/core/payments/flows/incremental_authorization_flow.rs index 716228d73f7b..58e5db8fbdef 100644 --- a/crates/router/src/core/payments/flows/incremental_authorization_flow.rs +++ b/crates/router/src/core/payments/flows/incremental_authorization_flow.rs @@ -6,7 +6,7 @@ use crate::{ errors::{ConnectorErrorExt, RouterResult}, payments::{self, access_token, helpers, transformers, Feature, PaymentData}, }, - routes::AppState, + routes::SessionState, services, types::{self, api, domain, storage}, }; @@ -21,7 +21,7 @@ impl { async fn construct_router_data<'a>( &self, - state: &AppState, + state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -54,7 +54,7 @@ impl Feature( self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, connector_request: Option, @@ -82,7 +82,7 @@ impl Feature( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, ) -> RouterResult { @@ -91,7 +91,7 @@ impl Feature RouterResult<(Option, bool)> { diff --git a/crates/router/src/core/payments/flows/psync_flow.rs b/crates/router/src/core/payments/flows/psync_flow.rs index 51627e2d68b7..bec29f97e93f 100644 --- a/crates/router/src/core/payments/flows/psync_flow.rs +++ b/crates/router/src/core/payments/flows/psync_flow.rs @@ -8,7 +8,7 @@ use crate::{ errors::{ApiErrorResponse, ConnectorErrorExt, RouterResult}, payments::{self, access_token, helpers, transformers, PaymentData}, }, - routes::AppState, + routes::SessionState, services::{self, logger}, types::{self, api, domain, storage}, }; @@ -19,7 +19,7 @@ impl ConstructFlowSpecificData( &self, - state: &AppState, + state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -50,7 +50,7 @@ impl Feature { async fn decide_flows<'a>( mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, connector_request: Option, @@ -101,7 +101,7 @@ impl Feature async fn add_access_token<'a>( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, ) -> RouterResult { @@ -110,7 +110,7 @@ impl Feature async fn build_flow_specific_connector_request( &mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, ) -> RouterResult<(Option, bool)> { @@ -152,7 +152,7 @@ where { async fn execute_connector_processing_step_for_each_capture( &self, - _state: &AppState, + _state: &SessionState, _pending_connector_capture_id_list: Vec, _call_connector_action: payments::CallConnectorAction, _connector_integration: services::BoxedConnectorIntegration< @@ -170,7 +170,7 @@ impl RouterDataPSync { async fn execute_connector_processing_step_for_each_capture( &self, - state: &AppState, + state: &SessionState, pending_connector_capture_id_list: Vec, call_connector_action: payments::CallConnectorAction, connector_integration: services::BoxedConnectorIntegration< diff --git a/crates/router/src/core/payments/flows/reject_flow.rs b/crates/router/src/core/payments/flows/reject_flow.rs index 638efa054eb8..865c6ea201d0 100644 --- a/crates/router/src/core/payments/flows/reject_flow.rs +++ b/crates/router/src/core/payments/flows/reject_flow.rs @@ -6,7 +6,7 @@ use crate::{ errors::{ApiErrorResponse, NotImplementedMessage, RouterResult}, payments::{self, access_token, helpers, transformers, PaymentData}, }, - routes::AppState, + routes::SessionState, services, types::{self, api, domain, storage}, }; @@ -17,7 +17,7 @@ impl ConstructFlowSpecificData( &self, - state: &AppState, + state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -46,7 +46,7 @@ impl Feature { async fn decide_flows<'a>( self, - _state: &AppState, + _state: &SessionState, _connector: &api::ConnectorData, _call_connector_action: payments::CallConnectorAction, _connector_request: Option, @@ -60,7 +60,7 @@ impl Feature async fn add_access_token<'a>( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, ) -> RouterResult { @@ -69,7 +69,7 @@ impl Feature async fn build_flow_specific_connector_request( &mut self, - _state: &AppState, + _state: &SessionState, _connector: &api::ConnectorData, _call_connector_action: payments::CallConnectorAction, ) -> RouterResult<(Option, bool)> { diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index c74ed4bae153..76441f40759d 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -28,7 +28,7 @@ impl { async fn construct_router_data<'a>( &self, - state: &routes::AppState, + state: &routes::SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -55,7 +55,7 @@ impl impl Feature for types::PaymentsSessionRouterData { async fn decide_flows<'a>( self, - state: &routes::AppState, + state: &routes::SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, _connector_request: Option, @@ -81,7 +81,7 @@ impl Feature for types::PaymentsSessio async fn add_access_token<'a>( &self, - state: &routes::AppState, + state: &routes::SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, ) -> RouterResult { @@ -123,7 +123,7 @@ fn is_dynamic_fields_required( } fn build_apple_pay_session_request( - state: &routes::AppState, + state: &routes::SessionState, request: payment_types::ApplepaySessionRequest, apple_pay_merchant_cert: masking::Secret, apple_pay_merchant_cert_key: masking::Secret, @@ -147,7 +147,7 @@ fn build_apple_pay_session_request( } async fn create_applepay_session_token( - state: &routes::AppState, + state: &routes::SessionState, router_data: &types::PaymentsSessionRouterData, connector: &api::ConnectorData, business_profile: &storage::business_profile::BusinessProfile, @@ -467,7 +467,7 @@ fn create_apple_pay_session_response( } fn create_gpay_session_token( - state: &routes::AppState, + state: &routes::SessionState, router_data: &types::PaymentsSessionRouterData, connector: &api::ConnectorData, business_profile: &storage::business_profile::BusinessProfile, @@ -598,7 +598,10 @@ fn create_gpay_session_token( } } -fn is_session_response_delayed(state: &routes::AppState, connector: &api::ConnectorData) -> bool { +fn is_session_response_delayed( + state: &routes::SessionState, + connector: &api::ConnectorData, +) -> bool { let connectors_with_delayed_response = &state .conf .delayed_session_response @@ -626,7 +629,7 @@ where { async fn decide_flow<'a, 'b>( &'b self, - state: &'a routes::AppState, + state: &'a routes::SessionState, connector: &api::ConnectorData, _confirm: Option, call_connector_action: payments::CallConnectorAction, @@ -635,7 +638,7 @@ where } fn create_paypal_sdk_session_token( - _state: &routes::AppState, + _state: &routes::SessionState, router_data: &types::PaymentsSessionRouterData, connector: &api::ConnectorData, _business_profile: &storage::business_profile::BusinessProfile, @@ -674,7 +677,7 @@ fn create_paypal_sdk_session_token( impl RouterDataSession for types::PaymentsSessionRouterData { async fn decide_flow<'a, 'b>( &'b self, - state: &'a routes::AppState, + state: &'a routes::SessionState, connector: &api::ConnectorData, _confirm: Option, call_connector_action: payments::CallConnectorAction, diff --git a/crates/router/src/core/payments/flows/setup_mandate_flow.rs b/crates/router/src/core/payments/flows/setup_mandate_flow.rs index b0fa39d5258d..987d3f33803a 100644 --- a/crates/router/src/core/payments/flows/setup_mandate_flow.rs +++ b/crates/router/src/core/payments/flows/setup_mandate_flow.rs @@ -9,7 +9,7 @@ use crate::{ self, access_token, customers, helpers, tokenization, transformers, PaymentData, }, }, - routes::AppState, + routes::SessionState, services, types::{self, api, domain, storage}, }; @@ -24,7 +24,7 @@ impl { async fn construct_router_data<'a>( &self, - state: &AppState, + state: &SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -51,7 +51,7 @@ impl impl Feature for types::SetupMandateRouterData { async fn decide_flows<'a>( self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, connector_request: Option, @@ -78,7 +78,7 @@ impl Feature for types::Setup async fn add_access_token<'a>( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, ) -> RouterResult { @@ -87,7 +87,7 @@ impl Feature for types::Setup async fn add_payment_method_token<'a>( &mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, tokenization_action: &payments::TokenizationAction, ) -> RouterResult> { @@ -104,7 +104,7 @@ impl Feature for types::Setup async fn create_connector_customer<'a>( &self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, ) -> RouterResult> { customers::create_connector_customer( @@ -118,7 +118,7 @@ impl Feature for types::Setup async fn build_flow_specific_connector_request( &mut self, - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, call_connector_action: payments::CallConnectorAction, ) -> RouterResult<(Option, bool)> { diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 8f7ed4da2565..a58a6ae32b21 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -34,7 +34,7 @@ use super::{ CustomerDetails, PaymentData, }; use crate::{ - configs::settings::{ConnectorRequestReferenceIdConfig, Server, TempLockerEnableConfig}, + configs::settings::{ConnectorRequestReferenceIdConfig, TempLockerEnableConfig}, connector, consts::{self, BASE64_ENGINE}, core::{ @@ -46,7 +46,7 @@ use crate::{ pm_auth::retrieve_payment_method_from_auth_service, }, db::StorageInterface, - routes::{metrics, payment_methods as payment_methods_handler, AppState}, + routes::{metrics, payment_methods as payment_methods_handler, SessionState}, services, types::{ api::{self, admin, enums as api_enums, MandateValidationFieldsExt}, @@ -427,7 +427,7 @@ pub async fn get_address_by_id( } pub async fn get_token_pm_type_mandate_details( - state: &AppState, + state: &SessionState, request: &api::PaymentsRequest, mandate_type: Option, merchant_account: &domain::MerchantAccount, @@ -579,7 +579,7 @@ pub async fn get_token_pm_type_mandate_details( } pub async fn get_token_for_recurring_mandate( - state: &AppState, + state: &SessionState, req: &api::PaymentsRequest, merchant_account: &domain::MerchantAccount, merchant_key_store: &domain::MerchantKeyStore, @@ -1023,16 +1023,13 @@ pub fn validate_customer_id_mandatory_cases( } pub fn create_startpay_url( - server: &Server, + base_url: &str, payment_attempt: &PaymentAttempt, payment_intent: &PaymentIntent, ) -> String { format!( "{}/payments/redirect/{}/{}/{}", - server.base_url, - payment_intent.payment_id, - payment_intent.merchant_id, - payment_attempt.attempt_id + base_url, payment_intent.payment_id, payment_intent.merchant_id, payment_attempt.attempt_id ) } @@ -1050,7 +1047,7 @@ pub fn create_redirect_url( } pub fn create_authentication_url( - router_base_url: &String, + router_base_url: &str, payment_attempt: &PaymentAttempt, ) -> String { format!( @@ -1060,7 +1057,7 @@ pub fn create_authentication_url( } pub fn create_authorize_url( - router_base_url: &String, + router_base_url: &str, payment_attempt: &PaymentAttempt, connector_name: &String, ) -> String { @@ -1205,7 +1202,7 @@ pub fn payment_intent_status_fsm( } pub async fn add_domain_task_to_pt( operation: &Op, - state: &AppState, + state: &SessionState, payment_attempt: &PaymentAttempt, requeue: bool, schedule_time: Option, @@ -1494,7 +1491,7 @@ pub fn get_customer_details_from_request( } pub async fn get_connector_default( - _state: &AppState, + _state: &SessionState, request_connector: Option, ) -> CustomResult { Ok(request_connector.map_or( @@ -1676,7 +1673,7 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R>( } pub async fn retrieve_payment_method_with_temporary_token( - state: &AppState, + state: &SessionState, token: &str, payment_intent: &PaymentIntent, merchant_key_store: &domain::MerchantKeyStore, @@ -1773,7 +1770,7 @@ pub async fn retrieve_payment_method_with_temporary_token( } pub async fn retrieve_card_with_permanent_token( - state: &AppState, + state: &SessionState, locker_id: &str, payment_method_id: &str, payment_intent: &PaymentIntent, @@ -1838,7 +1835,7 @@ pub async fn retrieve_card_with_permanent_token( } pub async fn retrieve_payment_method_from_db_with_token_data( - state: &AppState, + state: &SessionState, token_data: &storage::PaymentTokenData, storage_scheme: storage::enums::MerchantStorageScheme, ) -> RouterResult> { @@ -1873,7 +1870,7 @@ pub async fn retrieve_payment_method_from_db_with_token_data( } pub async fn retrieve_payment_token_data( - state: &AppState, + state: &SessionState, token: String, payment_method: Option, ) -> RouterResult { @@ -1924,7 +1921,7 @@ pub async fn retrieve_payment_token_data( pub async fn make_pm_data<'a, F: Clone, R>( operation: BoxedOperation<'a, F, R>, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut PaymentData, merchant_key_store: &domain::MerchantKeyStore, customer: &Option, @@ -2021,7 +2018,7 @@ pub async fn make_pm_data<'a, F: Clone, R>( } pub async fn store_in_vault_and_generate_ppmt( - state: &AppState, + state: &SessionState, payment_method_data: &api_models::payments::PaymentMethodData, payment_intent: &PaymentIntent, payment_attempt: &PaymentAttempt, @@ -2057,7 +2054,7 @@ pub async fn store_in_vault_and_generate_ppmt( } pub async fn store_payment_method_data_in_vault( - state: &AppState, + state: &SessionState, payment_attempt: &PaymentAttempt, payment_intent: &PaymentIntent, payment_method: enums::PaymentMethod, @@ -2541,7 +2538,7 @@ pub fn make_merchant_url_with_response( } pub async fn make_ephemeral_key( - state: AppState, + state: SessionState, customer_id: id_type::CustomerId, merchant_id: String, ) -> errors::RouterResponse { @@ -2563,7 +2560,7 @@ pub async fn make_ephemeral_key( } pub async fn delete_ephemeral_key( - state: AppState, + state: SessionState, ek_id: String, ) -> errors::RouterResponse { let db = state.store.as_ref(); @@ -3207,7 +3204,7 @@ impl MerchantConnectorAccountType { /// If profile_id is passed use it, or use connector_label to query merchant connector account #[instrument(skip_all)] pub async fn get_merchant_connector_account( - state: &AppState, + state: &SessionState, merchant_id: &str, creds_identifier: Option, key_store: &domain::MerchantKeyStore, @@ -3962,7 +3959,7 @@ pub fn get_applepay_metadata( } pub async fn get_apple_pay_retryable_connectors( - state: AppState, + state: SessionState, merchant_account: &domain::MerchantAccount, payment_data: &mut PaymentData, key_store: &domain::MerchantKeyStore, @@ -4067,7 +4064,7 @@ impl ApplePayData { pub async fn decrypt( &self, - state: &AppState, + state: &SessionState, ) -> CustomResult { let merchant_id = self.merchant_id(state).await?; let shared_secret = self.shared_secret(state).await?; @@ -4080,7 +4077,7 @@ impl ApplePayData { pub async fn merchant_id( &self, - state: &AppState, + state: &SessionState, ) -> CustomResult { let cert_data = state .conf @@ -4125,7 +4122,7 @@ impl ApplePayData { pub async fn shared_secret( &self, - state: &AppState, + state: &SessionState, ) -> CustomResult, errors::ApplePayDecryptionError> { let public_ec_bytes = BASE64_ENGINE .decode(self.header.ephemeral_public_key.peek().as_bytes()) @@ -4301,7 +4298,7 @@ pub fn validate_payment_link_request( } pub async fn get_gsm_record( - state: &AppState, + state: &SessionState, error_code: Option, error_message: Option, connector_name: String, @@ -4438,7 +4435,7 @@ pub fn update_additional_payment_data_with_connector_response_pm_data( } pub async fn get_payment_method_details_from_payment_token( - state: &AppState, + state: &SessionState, payment_attempt: &PaymentAttempt, payment_intent: &PaymentIntent, key_store: &domain::MerchantKeyStore, @@ -4589,7 +4586,7 @@ pub enum PaymentExternalAuthenticationFlow { } pub async fn get_payment_external_authentication_flow_during_confirm( - state: &AppState, + state: &SessionState, key_store: &domain::MerchantKeyStore, business_profile: &storage::BusinessProfile, payment_data: &mut PaymentData, diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index 35fc2897ea48..45e45bbe9cb6 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -29,7 +29,7 @@ use super::{helpers, CustomerDetails, PaymentData}; use crate::{ core::errors::{self, CustomResult, RouterResult}, db::StorageInterface, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ self, @@ -102,7 +102,7 @@ pub trait GetTracker: Send { #[allow(clippy::too_many_arguments)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, request: &R, merchant_account: &domain::MerchantAccount, @@ -127,7 +127,7 @@ pub trait Domain: Send + Sync { #[allow(clippy::too_many_arguments)] async fn make_pm_data<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut PaymentData, storage_scheme: enums::MerchantStorageScheme, merchant_key_store: &domain::MerchantKeyStore, @@ -140,7 +140,7 @@ pub trait Domain: Send + Sync { async fn add_task_to_process_tracker<'a>( &'a self, - _db: &'a AppState, + _db: &'a SessionState, _payment_attempt: &storage::PaymentAttempt, _requeue: bool, _schedule_time: Option, @@ -151,7 +151,7 @@ pub trait Domain: Send + Sync { async fn get_connector<'a>( &'a self, merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, request: &R, payment_intent: &storage::PaymentIntent, mechant_key_store: &domain::MerchantKeyStore, @@ -159,7 +159,7 @@ pub trait Domain: Send + Sync { async fn populate_payment_data<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _payment_data: &mut PaymentData, _merchant_account: &domain::MerchantAccount, ) -> CustomResult<(), errors::ApiErrorResponse> { @@ -168,7 +168,7 @@ pub trait Domain: Send + Sync { async fn call_external_three_ds_authentication_if_eligible<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _payment_data: &mut PaymentData, _should_continue_confirm_transaction: &mut bool, _connector_call_type: &ConnectorCallType, @@ -181,7 +181,7 @@ pub trait Domain: Send + Sync { #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut PaymentData, ) -> CustomResult { @@ -190,7 +190,7 @@ pub trait Domain: Send + Sync { async fn store_extended_card_info_temporarily<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _payment_id: &str, _business_profile: &storage::BusinessProfile, _payment_method_data: &Option, @@ -204,7 +204,7 @@ pub trait Domain: Send + Sync { pub trait UpdateTracker: Send { async fn update_trackers<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, req_state: ReqState, payment_data: D, customer: Option, @@ -222,7 +222,7 @@ pub trait UpdateTracker: Send { pub trait PostUpdateTracker: Send { async fn update_tracker<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, payment_id: &api::PaymentIdType, payment_data: D, response: types::RouterData, @@ -233,7 +233,7 @@ pub trait PostUpdateTracker: Send { async fn save_pm_and_mandate<'b>( &self, - _state: &AppState, + _state: &SessionState, _resp: &types::RouterData, _merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, @@ -285,7 +285,7 @@ where async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, _request: &api::PaymentsRetrieveRequest, _payment_intent: &storage::PaymentIntent, _merchant_key_store: &domain::MerchantKeyStore, @@ -296,7 +296,7 @@ where #[instrument(skip_all)] async fn make_pm_data<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut PaymentData, storage_scheme: enums::MerchantStorageScheme, merchant_key_store: &domain::MerchantKeyStore, @@ -320,7 +320,7 @@ where #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut PaymentData, ) -> CustomResult { @@ -365,7 +365,7 @@ where #[instrument(skip_all)] async fn make_pm_data<'a>( &'a self, - _state: &'a AppState, + _state: &'a SessionState, _payment_data: &mut PaymentData, _storage_scheme: enums::MerchantStorageScheme, _merchant_key_store: &domain::MerchantKeyStore, @@ -381,7 +381,7 @@ where async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, _request: &api::PaymentsCaptureRequest, _payment_intent: &storage::PaymentIntent, _merchant_key_store: &domain::MerchantKeyStore, @@ -392,7 +392,7 @@ where #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut PaymentData, ) -> CustomResult { @@ -438,7 +438,7 @@ where #[instrument(skip_all)] async fn make_pm_data<'a>( &'a self, - _state: &'a AppState, + _state: &'a SessionState, _payment_data: &mut PaymentData, _storage_scheme: enums::MerchantStorageScheme, _merchant_key_store: &domain::MerchantKeyStore, @@ -454,7 +454,7 @@ where async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, _request: &api::PaymentsCancelRequest, _payment_intent: &storage::PaymentIntent, _merchant_key_store: &domain::MerchantKeyStore, @@ -465,7 +465,7 @@ where #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut PaymentData, ) -> CustomResult { @@ -500,7 +500,7 @@ where #[instrument(skip_all)] async fn make_pm_data<'a>( &'a self, - _state: &'a AppState, + _state: &'a SessionState, _payment_data: &mut PaymentData, _storage_scheme: enums::MerchantStorageScheme, _merchant_key_store: &domain::MerchantKeyStore, @@ -516,7 +516,7 @@ where async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, _request: &api::PaymentsRejectRequest, _payment_intent: &storage::PaymentIntent, _merchant_key_store: &domain::MerchantKeyStore, @@ -527,7 +527,7 @@ where #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut PaymentData, ) -> CustomResult { diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs index 52325db753a6..a492cb760389 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -12,7 +12,7 @@ use crate::{ errors::{self, RouterResult, StorageErrorExt}, payments::{helpers, operations, PaymentData}, }, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ api::{self, PaymentIdTypeExt}, @@ -34,7 +34,7 @@ impl GetTracker, api::PaymentsCaptureRequest> #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, _request: &api::PaymentsCaptureRequest, merchant_account: &domain::MerchantAccount, @@ -194,7 +194,7 @@ impl UpdateTracker, api::PaymentsCaptureRequest> for #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, _req_state: ReqState, mut payment_data: PaymentData, _customer: Option, diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs index 64114fc40e65..ce79f9392c80 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -14,7 +14,7 @@ use crate::{ payments::{helpers, operations, PaymentData}, }, events::audit_events::{AuditEvent, AuditEventType}, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ self as core_types, @@ -34,7 +34,7 @@ impl GetTracker, api::PaymentsCancelRequest> #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, request: &api::PaymentsCancelRequest, merchant_account: &domain::MerchantAccount, @@ -207,7 +207,7 @@ impl UpdateTracker, api::PaymentsCancelRequest> for #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, req_state: ReqState, mut payment_data: PaymentData, _customer: Option, diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index ec86d1d17245..447f7b929066 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -12,7 +12,7 @@ use crate::{ errors::{self, RouterResult, StorageErrorExt}, payments::{self, helpers, operations, types::MultipleCaptureData}, }, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ self as core_types, @@ -34,7 +34,7 @@ impl GetTracker, api::PaymentsCaptu #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, request: &api::PaymentsCaptureRequest, merchant_account: &domain::MerchantAccount, @@ -254,7 +254,7 @@ impl UpdateTracker, api::PaymentsCaptureRe #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, _req_state: ReqState, mut payment_data: payments::PaymentData, _customer: Option, diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs index 49fe8ce20114..1ff95c37f667 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -15,7 +15,7 @@ use crate::{ utils as core_utils, }, db::StorageInterface, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ api::{self, PaymentIdTypeExt}, @@ -34,7 +34,7 @@ impl GetTracker, api::PaymentsRequest> for Co #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, request: &api::PaymentsRequest, merchant_account: &domain::MerchantAccount, @@ -367,7 +367,7 @@ impl Domain for CompleteAuthorize { #[instrument(skip_all)] async fn make_pm_data<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut PaymentData, storage_scheme: storage_enums::MerchantStorageScheme, merchant_key_store: &domain::MerchantKeyStore, @@ -392,7 +392,7 @@ impl Domain for CompleteAuthorize { #[instrument(skip_all)] async fn add_task_to_process_tracker<'a>( &'a self, - _state: &'a AppState, + _state: &'a SessionState, _payment_attempt: &storage::PaymentAttempt, _requeue: bool, _schedule_time: Option, @@ -403,7 +403,7 @@ impl Domain for CompleteAuthorize { async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, request: &api::PaymentsRequest, _payment_intent: &storage::PaymentIntent, _key_store: &domain::MerchantKeyStore, @@ -416,7 +416,7 @@ impl Domain for CompleteAuthorize { #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut PaymentData, ) -> CustomResult { @@ -429,7 +429,7 @@ impl UpdateTracker, api::PaymentsRequest> for Comple #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, - state: &'b AppState, + state: &'b SessionState, _req_state: ReqState, mut payment_data: PaymentData, _customer: Option, diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index edda62d79f7c..ea5f2c0ecb43 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -29,7 +29,7 @@ use crate::{ utils as core_utils, }, db::StorageInterface, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ self, @@ -48,7 +48,7 @@ impl GetTracker, api::PaymentsRequest> for Pa #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, request: &api::PaymentsRequest, merchant_account: &domain::MerchantAccount, @@ -687,7 +687,7 @@ impl Domain for PaymentConfirm { #[instrument(skip_all)] async fn make_pm_data<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut PaymentData, storage_scheme: storage_enums::MerchantStorageScheme, key_store: &domain::MerchantKeyStore, @@ -717,7 +717,7 @@ impl Domain for PaymentConfirm { #[instrument(skip_all)] async fn add_task_to_process_tracker<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_attempt: &storage::PaymentAttempt, requeue: bool, schedule_time: Option, @@ -732,7 +732,7 @@ impl Domain for PaymentConfirm { async move { helpers::add_domain_task_to_pt( &m_self, - m_state.as_ref(), + &m_state, &m_payment_attempt, requeue, schedule_time, @@ -748,7 +748,7 @@ impl Domain for PaymentConfirm { async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, request: &api::PaymentsRequest, _payment_intent: &storage::PaymentIntent, _key_store: &domain::MerchantKeyStore, @@ -761,7 +761,7 @@ impl Domain for PaymentConfirm { #[instrument(skip_all)] async fn populate_payment_data<'a>( &'a self, - state: &AppState, + state: &SessionState, payment_data: &mut PaymentData, _merchant_account: &domain::MerchantAccount, ) -> CustomResult<(), errors::ApiErrorResponse> { @@ -770,7 +770,7 @@ impl Domain for PaymentConfirm { async fn call_external_three_ds_authentication_if_eligible<'a>( &'a self, - state: &AppState, + state: &SessionState, payment_data: &mut PaymentData, should_continue_confirm_transaction: &mut bool, connector_call_type: &ConnectorCallType, @@ -857,7 +857,7 @@ impl Domain for PaymentConfirm { #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, payment_data: &mut PaymentData, ) -> CustomResult { @@ -867,7 +867,7 @@ impl Domain for PaymentConfirm { #[instrument(skip_all)] async fn store_extended_card_info_temporarily<'a>( &'a self, - state: &AppState, + state: &SessionState, payment_id: &str, business_profile: &storage::BusinessProfile, payment_method_data: &Option, @@ -934,7 +934,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, - state: &'b AppState, + state: &'b SessionState, _req_state: ReqState, mut payment_data: PaymentData, customer: Option, diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 9a4e87890582..bb249e9a9cd1 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -30,7 +30,7 @@ use crate::{ utils as core_utils, }, db::StorageInterface, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ api::{self, PaymentIdTypeExt}, @@ -54,7 +54,7 @@ impl GetTracker, api::PaymentsRequest> for Pa #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, request: &api::PaymentsRequest, merchant_account: &domain::MerchantAccount, @@ -215,7 +215,7 @@ impl GetTracker, api::PaymentsRequest> for Pa .map(|merchant_name| merchant_name.into_inner().peek().to_owned()) .unwrap_or_default(); - let default_domain_name = state.conf.server.base_url.clone(); + let default_domain_name = state.base_url.clone(); let (payment_link_config, domain_name) = payment_link::get_payment_link_config_based_on_priority( @@ -497,7 +497,7 @@ impl Domain for PaymentCreate { #[instrument(skip_all)] async fn make_pm_data<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut PaymentData, storage_scheme: enums::MerchantStorageScheme, merchant_key_store: &domain::MerchantKeyStore, @@ -521,7 +521,7 @@ impl Domain for PaymentCreate { #[instrument(skip_all)] async fn add_task_to_process_tracker<'a>( &'a self, - _state: &'a AppState, + _state: &'a SessionState, _payment_attempt: &PaymentAttempt, _requeue: bool, _schedule_time: Option, @@ -532,7 +532,7 @@ impl Domain for PaymentCreate { async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, request: &api::PaymentsRequest, _payment_intent: &storage::PaymentIntent, _merchant_key_store: &domain::MerchantKeyStore, @@ -543,7 +543,7 @@ impl Domain for PaymentCreate { #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut PaymentData, ) -> CustomResult { @@ -556,7 +556,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, - state: &'b AppState, + state: &'b SessionState, _req_state: ReqState, mut payment_data: PaymentData, _customer: Option, @@ -771,7 +771,7 @@ impl PaymentCreate { payment_method_type: Option, request: &api::PaymentsRequest, browser_info: Option, - state: &AppState, + state: &SessionState, payment_method_billing_address_id: Option, payment_method_info: &Option, key_store: &domain::MerchantKeyStore, @@ -1074,7 +1074,7 @@ impl PaymentCreate { #[instrument(skip_all)] pub async fn get_ephemeral_key( request: &api::PaymentsRequest, - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, ) -> Option { match request.customer_id.clone() { diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs index 60061d655c1c..cf8217718cbc 100644 --- a/crates/router/src/core/payments/operations/payment_reject.rs +++ b/crates/router/src/core/payments/operations/payment_reject.rs @@ -12,7 +12,7 @@ use crate::{ errors::{self, RouterResult, StorageErrorExt}, payments::{helpers, operations, PaymentAddress, PaymentData}, }, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ api::{self, PaymentIdTypeExt}, @@ -31,7 +31,7 @@ impl GetTracker, PaymentsCancelRequest> for P #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, _request: &PaymentsCancelRequest, merchant_account: &domain::MerchantAccount, @@ -191,7 +191,7 @@ impl UpdateTracker, PaymentsCancelRequest> for Payme #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, - state: &'b AppState, + state: &'b SessionState, _req_state: ReqState, mut payment_data: PaymentData, _customer: Option, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 3b5bd9fd43ba..4843d1145d50 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -28,7 +28,7 @@ use crate::{ }, utils as core_utils, }, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, types::{ self, api, domain, storage::{self, enums}, @@ -51,7 +51,7 @@ impl PostUpdateTracker, types::PaymentsAuthor { async fn update_tracker<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData< @@ -82,7 +82,7 @@ impl PostUpdateTracker, types::PaymentsAuthor async fn save_pm_and_mandate<'b>( &self, - state: &AppState, + state: &SessionState, resp: &types::RouterData, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -237,7 +237,7 @@ impl PostUpdateTracker, types::PaymentsIncrementalAu { async fn update_tracker<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, _payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData< @@ -368,7 +368,7 @@ impl PostUpdateTracker, types::PaymentsIncrementalAu impl PostUpdateTracker, types::PaymentsSyncData> for PaymentResponse { async fn update_tracker<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, payment_id: &api::PaymentIdType, payment_data: PaymentData, router_data: types::RouterData, @@ -389,7 +389,7 @@ impl PostUpdateTracker, types::PaymentsSyncData> for async fn save_pm_and_mandate<'b>( &self, - state: &AppState, + state: &SessionState, resp: &types::RouterData, merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, @@ -418,7 +418,7 @@ impl PostUpdateTracker, types::PaymentsSessionData> { async fn update_tracker<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, @@ -446,7 +446,7 @@ impl PostUpdateTracker, types::PaymentsCaptureData> { async fn update_tracker<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, @@ -472,7 +472,7 @@ impl PostUpdateTracker, types::PaymentsCaptureData> impl PostUpdateTracker, types::PaymentsCancelData> for PaymentResponse { async fn update_tracker<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, @@ -501,7 +501,7 @@ impl PostUpdateTracker, types::PaymentsApproveData> { async fn update_tracker<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, @@ -528,7 +528,7 @@ impl PostUpdateTracker, types::PaymentsApproveData> impl PostUpdateTracker, types::PaymentsRejectData> for PaymentResponse { async fn update_tracker<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, @@ -557,7 +557,7 @@ impl PostUpdateTracker, types::SetupMandateRequestDa { async fn update_tracker<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData< @@ -590,7 +590,7 @@ impl PostUpdateTracker, types::SetupMandateRequestDa async fn save_pm_and_mandate<'b>( &self, - state: &AppState, + state: &SessionState, resp: &types::RouterData, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -658,7 +658,7 @@ impl PostUpdateTracker, types::CompleteAuthorizeData { async fn update_tracker<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, payment_id: &api::PaymentIdType, payment_data: PaymentData, response: types::RouterData, @@ -679,7 +679,7 @@ impl PostUpdateTracker, types::CompleteAuthorizeData async fn save_pm_and_mandate<'b>( &self, - state: &AppState, + state: &SessionState, resp: &types::RouterData, merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, @@ -704,7 +704,7 @@ impl PostUpdateTracker, types::CompleteAuthorizeData #[instrument(skip_all)] async fn payment_response_update_tracker( - state: &AppState, + state: &SessionState, _payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, @@ -1235,7 +1235,7 @@ async fn payment_response_update_tracker( } async fn update_payment_method_status_and_ntid( - state: &AppState, + state: &SessionState, payment_data: &mut PaymentData, attempt_status: common_enums::AttemptStatus, payment_response: Result, diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index 2aa01cd587fa..4d81914aca5f 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -14,7 +14,7 @@ use crate::{ payments::{self, helpers, operations, PaymentData}, }, db::StorageInterface, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ api::{self, PaymentIdTypeExt}, @@ -35,7 +35,7 @@ impl GetTracker, api::PaymentsSessionRequest> #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, request: &api::PaymentsSessionRequest, merchant_account: &domain::MerchantAccount, @@ -218,7 +218,7 @@ impl UpdateTracker, api::PaymentsSessionRequest> for #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, - state: &'b AppState, + state: &'b SessionState, _req_state: ReqState, mut payment_data: PaymentData, _customer: Option, @@ -316,7 +316,7 @@ where #[instrument(skip_all)] async fn make_pm_data<'b>( &'b self, - _state: &'b AppState, + _state: &'b SessionState, _payment_data: &mut PaymentData, _storage_scheme: storage_enums::MerchantStorageScheme, _merchant_key_store: &domain::MerchantKeyStore, @@ -342,7 +342,7 @@ where async fn get_connector<'a>( &'a self, merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, request: &api::PaymentsSessionRequest, payment_intent: &storage::PaymentIntent, key_store: &domain::MerchantKeyStore, @@ -458,7 +458,7 @@ where #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut PaymentData, ) -> errors::CustomResult { diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index e5567e5b4748..7c1c117a7288 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -13,7 +13,7 @@ use crate::{ payments::{helpers, operations, CustomerDetails, PaymentAddress, PaymentData}, }, db::StorageInterface, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ api::{self, PaymentIdTypeExt}, @@ -32,7 +32,7 @@ impl GetTracker, api::PaymentsStartRequest> f #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, _request: &api::PaymentsStartRequest, merchant_account: &domain::MerchantAccount, @@ -203,7 +203,7 @@ impl UpdateTracker, api::PaymentsStartRequest> for P #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, - _state: &'b AppState, + _state: &'b SessionState, _req_state: ReqState, payment_data: PaymentData, _customer: Option, @@ -290,7 +290,7 @@ where #[instrument(skip_all)] async fn make_pm_data<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut PaymentData, storage_scheme: storage_enums::MerchantStorageScheme, merchant_key_store: &domain::MerchantKeyStore, @@ -324,7 +324,7 @@ where async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, _request: &api::PaymentsStartRequest, _payment_intent: &storage::PaymentIntent, _mechant_key_store: &domain::MerchantKeyStore, @@ -335,7 +335,7 @@ where #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut PaymentData, ) -> CustomResult { diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index 0bedd70b921e..9971ea76aa3d 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -17,7 +17,7 @@ use crate::{ }, }, db::StorageInterface, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ api, domain, @@ -85,7 +85,7 @@ impl Domain for PaymentStatus { #[instrument(skip_all)] async fn make_pm_data<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut PaymentData, storage_scheme: enums::MerchantStorageScheme, merchant_key_store: &domain::MerchantKeyStore, @@ -109,7 +109,7 @@ impl Domain for PaymentStatus { #[instrument(skip_all)] async fn add_task_to_process_tracker<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_attempt: &storage::PaymentAttempt, requeue: bool, schedule_time: Option, @@ -120,7 +120,7 @@ impl Domain for PaymentStatus { async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, request: &api::PaymentsRequest, _payment_intent: &storage::PaymentIntent, _key_store: &domain::MerchantKeyStore, @@ -131,7 +131,7 @@ impl Domain for PaymentStatus { #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut PaymentData, ) -> CustomResult { @@ -143,7 +143,7 @@ impl Domain for PaymentStatus { impl UpdateTracker, api::PaymentsRequest> for PaymentStatus { async fn update_trackers<'b>( &'b self, - _state: &'b AppState, + _state: &'b SessionState, _req_state: ReqState, payment_data: PaymentData, _customer: Option, @@ -164,7 +164,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen impl UpdateTracker, api::PaymentsRetrieveRequest> for PaymentStatus { async fn update_trackers<'b>( &'b self, - _state: &'b AppState, + _state: &'b SessionState, _req_state: ReqState, payment_data: PaymentData, _customer: Option, @@ -191,7 +191,7 @@ impl GetTracker, api::PaymentsRetrieveRequest #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, request: &api::PaymentsRetrieveRequest, merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index e44dc0c1f2c1..ffa122e54af3 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -18,7 +18,7 @@ use crate::{ utils as core_utils, }, db::StorageInterface, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services, types::{ api::{self, PaymentIdTypeExt}, @@ -37,7 +37,7 @@ impl GetTracker, api::PaymentsRequest> for Pa #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, request: &api::PaymentsRequest, merchant_account: &domain::MerchantAccount, @@ -500,7 +500,7 @@ impl Domain for PaymentUpdate { #[instrument(skip_all)] async fn make_pm_data<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_data: &mut PaymentData, storage_scheme: storage_enums::MerchantStorageScheme, merchant_key_store: &domain::MerchantKeyStore, @@ -524,7 +524,7 @@ impl Domain for PaymentUpdate { #[instrument(skip_all)] async fn add_task_to_process_tracker<'a>( &'a self, - _state: &'a AppState, + _state: &'a SessionState, _payment_attempt: &storage::PaymentAttempt, _requeue: bool, _schedule_time: Option, @@ -535,7 +535,7 @@ impl Domain for PaymentUpdate { async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, request: &api::PaymentsRequest, _payment_intent: &storage::PaymentIntent, _key_store: &domain::MerchantKeyStore, @@ -546,7 +546,7 @@ impl Domain for PaymentUpdate { #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut PaymentData, ) -> CustomResult { @@ -559,7 +559,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, - state: &'b AppState, + state: &'b SessionState, _req_state: ReqState, mut payment_data: PaymentData, customer: Option, diff --git a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs index 56665d65a32d..26ffd65035d6 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -18,7 +18,7 @@ use crate::{ }, routes::{ app::{ReqState, StorageInterface}, - AppState, + SessionState, }, services, types::{ @@ -41,7 +41,7 @@ impl #[instrument(skip_all)] async fn get_trackers<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, payment_id: &api::PaymentIdType, request: &PaymentsIncrementalAuthorizationRequest, merchant_account: &domain::MerchantAccount, @@ -174,7 +174,7 @@ impl UpdateTracker, PaymentsIncrementalAut #[instrument(skip_all)] async fn update_trackers<'b>( &'b self, - db: &'b AppState, + db: &'b SessionState, _req_state: ReqState, mut payment_data: payments::PaymentData, _customer: Option, @@ -307,7 +307,7 @@ impl Domain #[instrument(skip_all)] async fn make_pm_data<'a>( &'a self, - _state: &'a AppState, + _state: &'a SessionState, _payment_data: &mut payments::PaymentData, _storage_scheme: enums::MerchantStorageScheme, _merchant_key_store: &domain::MerchantKeyStore, @@ -323,7 +323,7 @@ impl Domain async fn get_connector<'a>( &'a self, _merchant_account: &domain::MerchantAccount, - state: &AppState, + state: &SessionState, _request: &PaymentsIncrementalAuthorizationRequest, _payment_intent: &storage::PaymentIntent, _merchant_key_store: &domain::MerchantKeyStore, @@ -334,7 +334,7 @@ impl Domain #[instrument(skip_all)] async fn guard_payment_against_blocklist<'a>( &'a self, - _state: &AppState, + _state: &SessionState, _merchant_account: &domain::MerchantAccount, _payment_data: &mut payments::PaymentData, ) -> CustomResult { diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index 3bafd7774099..af41e3e4897b 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -31,7 +31,7 @@ use crate::{ #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] pub async fn do_gsm_actions( - state: &app::AppState, + state: &app::SessionState, req_state: ReqState, payment_data: &mut payments::PaymentData, mut connectors: IntoIter, @@ -165,7 +165,7 @@ where #[instrument(skip_all)] pub async fn is_step_up_enabled_for_merchant_connector( - state: &app::AppState, + state: &app::SessionState, merchant_id: &str, connector_name: types::Connector, ) -> bool { @@ -189,7 +189,7 @@ pub async fn is_step_up_enabled_for_merchant_connector( #[instrument(skip_all)] pub async fn get_retries( - state: &app::AppState, + state: &app::SessionState, retries: Option, merchant_id: &str, ) -> Option { @@ -219,7 +219,7 @@ pub async fn get_retries( #[instrument(skip_all)] pub async fn get_gsm( - state: &app::AppState, + state: &app::SessionState, router_data: &types::RouterData, ) -> RouterResult> { let error_response = router_data.response.as_ref().err(); @@ -269,7 +269,7 @@ fn get_flow_name() -> RouterResult { #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] pub async fn do_retry( - state: &routes::AppState, + state: &routes::SessionState, req_state: ReqState, connector: api::ConnectorData, operation: &operations::BoxedOperation<'_, F, ApiRequest>, @@ -326,7 +326,7 @@ where #[instrument(skip_all)] pub async fn modify_trackers( - state: &routes::AppState, + state: &routes::SessionState, connector: String, payment_data: &mut payments::PaymentData, storage_scheme: storage_enums::MerchantStorageScheme, diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index d45f804268b3..145800ebc6aa 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -32,7 +32,7 @@ use rand::{ SeedableRng, }; use rustc_hash::FxHashMap; -use storage_impl::redis::cache::{CGRAPH_CACHE, ROUTING_CACHE}; +use storage_impl::redis::cache::{CacheKey, CGRAPH_CACHE, ROUTING_CACHE}; #[cfg(feature = "payouts")] use crate::core::payouts; @@ -50,7 +50,7 @@ use crate::{ transformers::{ForeignFrom, ForeignInto}, }, utils::{OptionExt, ValueExt}, - AppState, + SessionState, }; pub enum CachedAlgorithm { @@ -61,7 +61,7 @@ pub enum CachedAlgorithm { } pub struct SessionFlowRoutingInput<'a> { - pub state: &'a AppState, + pub state: &'a SessionState, pub country: Option, pub key_store: &'a domain::MerchantKeyStore, pub merchant_account: &'a domain::MerchantAccount, @@ -71,7 +71,7 @@ pub struct SessionFlowRoutingInput<'a> { } pub struct SessionRoutingPmTypeInput<'a> { - state: &'a AppState, + state: &'a SessionState, key_store: &'a domain::MerchantKeyStore, attempt_id: &'a str, routing_algorithm: &'a MerchantAccountRoutingAlgorithm, @@ -262,7 +262,7 @@ where } pub async fn perform_static_routing_v1( - state: &AppState, + state: &SessionState, merchant_id: &str, algorithm_ref: routing_types::RoutingAlgorithmRef, transaction_data: &routing::TransactionData<'_, F>, @@ -330,7 +330,7 @@ pub async fn perform_static_routing_v1( } async fn ensure_algorithm_cached_v1( - state: &AppState, + state: &SessionState, merchant_id: &str, algorithm_id: &str, #[cfg(feature = "business_profile_routing")] profile_id: Option, @@ -366,7 +366,10 @@ async fn ensure_algorithm_cached_v1( }; let cached_algorithm = ROUTING_CACHE - .get_val::>(key.as_str()) + .get_val::>(CacheKey { + key: key.clone(), + prefix: state.tenant.clone(), + }) .await; let algorithm = if let Some(algo) = cached_algorithm { @@ -428,7 +431,7 @@ fn execute_dsl_and_get_connector_v1( } pub async fn refresh_routing_cache_v1( - state: &AppState, + state: &SessionState, key: String, algorithm_id: &str, #[cfg(feature = "business_profile_routing")] profile_id: Option, @@ -483,7 +486,15 @@ pub async fn refresh_routing_cache_v1( let arc_cached_algorithm = Arc::new(cached_algorithm); - ROUTING_CACHE.push(key, arc_cached_algorithm.clone()).await; + ROUTING_CACHE + .push( + CacheKey { + key, + prefix: state.tenant.clone(), + }, + arc_cached_algorithm.clone(), + ) + .await; Ok(arc_cached_algorithm) } @@ -523,7 +534,7 @@ pub fn perform_volume_split( } pub async fn get_merchant_cgraph<'a>( - state: &AppState, + state: &SessionState, key_store: &domain::MerchantKeyStore, #[cfg(feature = "business_profile_routing")] profile_id: Option, transaction_type: &api_enums::TransactionType, @@ -554,7 +565,10 @@ pub async fn get_merchant_cgraph<'a>( let cached_cgraph = CGRAPH_CACHE .get_val::>>( - key.as_str(), + CacheKey { + key: key.clone(), + prefix: state.tenant.clone(), + }, ) .await; @@ -576,7 +590,7 @@ pub async fn get_merchant_cgraph<'a>( } pub async fn refresh_cgraph_cache<'a>( - state: &AppState, + state: &SessionState, key_store: &domain::MerchantKeyStore, key: String, #[cfg(feature = "business_profile_routing")] profile_id: Option, @@ -650,14 +664,22 @@ pub async fn refresh_cgraph_cache<'a>( .attach_printable("when construction cgraph")?, ); - CGRAPH_CACHE.push(key, Arc::clone(&cgraph)).await; + CGRAPH_CACHE + .push( + CacheKey { + key, + prefix: state.tenant.clone(), + }, + Arc::clone(&cgraph), + ) + .await; Ok(cgraph) } #[allow(clippy::too_many_arguments)] async fn perform_cgraph_filtering( - state: &AppState, + state: &SessionState, key_store: &domain::MerchantKeyStore, chosen: Vec, backend_input: dsl_inputs::BackendInput, @@ -708,7 +730,7 @@ async fn perform_cgraph_filtering( } pub async fn perform_eligibility_analysis( - state: &AppState, + state: &SessionState, key_store: &domain::MerchantKeyStore, chosen: Vec, transaction_data: &routing::TransactionData<'_, F>, @@ -735,7 +757,7 @@ pub async fn perform_eligibility_analysis( } pub async fn perform_fallback_routing( - state: &AppState, + state: &SessionState, key_store: &domain::MerchantKeyStore, transaction_data: &routing::TransactionData<'_, F>, eligible_connectors: Option<&Vec>, @@ -781,7 +803,7 @@ pub async fn perform_fallback_routing( } pub async fn perform_eligibility_analysis_with_fallback( - state: &AppState, + state: &SessionState, key_store: &domain::MerchantKeyStore, chosen: Vec, transaction_data: &routing::TransactionData<'_, F>, diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index c19c8c45753c..48637a0d2b32 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -18,7 +18,7 @@ use crate::{ mandate, payment_methods, payments, }, logger, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services, types::{ self, @@ -54,7 +54,7 @@ impl From<&types::RouterData #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] pub async fn save_payment_method( - state: &AppState, + state: &SessionState, connector_name: String, merchant_connector_id: Option, save_payment_method_data: SavePaymentMethodData, @@ -646,7 +646,7 @@ async fn skip_saving_card_in_locker( } pub async fn save_in_locker( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, payment_method_request: api::PaymentMethodCreate, ) -> RouterResult<( @@ -719,7 +719,7 @@ pub fn create_payment_method_metadata( } pub async fn add_payment_method_token( - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, tokenization_action: &payments::TokenizationAction, router_data: &mut types::RouterData, diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index a5859ea6dc6e..8eca589ca28e 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -15,7 +15,7 @@ use router_env::{instrument, tracing}; use super::{flows::Feature, types::AuthenticationData, PaymentData}; use crate::{ - configs::settings::{ConnectorRequestReferenceIdConfig, Server}, + configs::settings::ConnectorRequestReferenceIdConfig, connector::{Helcim, Nexinets}, core::{ errors::{self, RouterResponse, RouterResult}, @@ -23,7 +23,7 @@ use crate::{ utils as core_utils, }, headers::X_PAYMENT_CONFIRM_SOURCE, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services::{self, RedirectForm}, types::{ self, api, domain, @@ -36,7 +36,7 @@ use crate::{ #[instrument(skip_all)] pub async fn construct_payment_router_data<'a, F, T>( - state: &'a AppState, + state: &'a SessionState, payment_data: PaymentData, connector_id: &str, merchant_account: &domain::MerchantAccount, @@ -93,7 +93,7 @@ where }); let additional_data = PaymentAdditionalData { - router_base_url: state.conf.server.base_url.clone(), + router_base_url: state.base_url.clone(), connector_name: connector_id.to_string(), payment_data: payment_data.clone(), state, @@ -204,7 +204,7 @@ where data: D, customer: Option, auth_flow: services::AuthFlow, - server: &Server, + base_url: &str, operation: Op, connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig, connector_http_status_code: Option, @@ -223,7 +223,7 @@ where payment_data: PaymentData, customer: Option, auth_flow: services::AuthFlow, - server: &Server, + base_url: &str, operation: Op, connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig, connector_http_status_code: Option, @@ -253,7 +253,7 @@ where captures, customer, auth_flow, - server, + base_url, &operation, connector_request_reference_id_config, connector_http_status_code, @@ -273,7 +273,7 @@ where payment_data: PaymentData, _customer: Option, _auth_flow: services::AuthFlow, - _server: &Server, + _base_url: &str, _operation: Op, _connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig, _connector_http_status_code: Option, @@ -305,7 +305,7 @@ where data: PaymentData, customer: Option, _auth_flow: services::AuthFlow, - _server: &Server, + _base_url: &str, _operation: Op, _connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig, _connector_http_status_code: Option, @@ -361,7 +361,7 @@ pub fn payments_to_payments_response( captures: Option>, customer: Option, auth_flow: services::AuthFlow, - server: &Server, + base_url: &str, operation: &Op, connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig, connector_http_status_code: Option, @@ -589,7 +589,7 @@ where .or(payment_attempt.authentication_data.as_ref().map(|_| { api_models::payments::NextActionData::RedirectToUrl { redirect_to_url: helpers::create_startpay_url( - server, + base_url, &payment_attempt, &payment_intent, ), @@ -606,9 +606,9 @@ where .get_required_value("connector")?; Some(api_models::payments::NextActionData::ThreeDsInvoke { three_ds_data: api_models::payments::ThreeDsData { - three_ds_authentication_url: helpers::create_authentication_url(&server.base_url, &payment_attempt), + three_ds_authentication_url: helpers::create_authentication_url(base_url, &payment_attempt), three_ds_authorize_url: helpers::create_authorize_url( - &server.base_url, + base_url, &payment_attempt, payment_connector_name, ), @@ -1144,7 +1144,7 @@ where router_base_url: String, connector_name: String, payment_data: PaymentData, - state: &'a AppState, + state: &'a SessionState, customer_data: &'a Option, } impl TryFrom> for types::PaymentsAuthorizeData { diff --git a/crates/router/src/core/payments/types.rs b/crates/router/src/core/payments/types.rs index 92c9eec5ff80..1f16c4d667ea 100644 --- a/crates/router/src/core/payments/types.rs +++ b/crates/router/src/core/payments/types.rs @@ -18,7 +18,7 @@ use router_env::{instrument, tracing}; use crate::{ consts as router_consts, core::errors::{self, RouterResult}, - routes::AppState, + routes::SessionState, types::{ storage::{self, enums as storage_enums}, transformers::ForeignTryFrom, @@ -290,7 +290,7 @@ impl SurchargeMetadata { #[instrument(skip_all)] pub async fn persist_individual_surcharge_details_in_redis( &self, - state: &AppState, + state: &SessionState, business_profile: &BusinessProfile, ) -> RouterResult<()> { if !self.is_empty_result() { @@ -325,7 +325,7 @@ impl SurchargeMetadata { #[instrument(skip_all)] pub async fn get_individual_surcharge_detail_from_redis( - state: &AppState, + state: &SessionState, surcharge_key: SurchargeKey, payment_attempt_id: &str, ) -> CustomResult { diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 7aaf215ab51c..93c634b07fc9 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -34,7 +34,7 @@ use crate::{ utils as core_utils, }, db::StorageInterface, - routes::AppState, + routes::SessionState, services, types::{ self, @@ -71,7 +71,7 @@ pub fn get_next_connector( #[cfg(feature = "payouts")] pub async fn get_connector_choice( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector: Option, @@ -152,7 +152,7 @@ pub async fn get_connector_choice( #[instrument(skip_all)] pub async fn make_connector_decision( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_call_type: api::ConnectorCallType, @@ -254,7 +254,7 @@ pub async fn make_connector_decision( #[instrument(skip_all)] pub async fn payouts_core( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, payout_data: &mut PayoutData, @@ -288,7 +288,7 @@ pub async fn payouts_core( #[instrument(skip_all)] pub async fn payouts_create_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: payouts::PayoutCreateRequest, @@ -339,7 +339,7 @@ pub async fn payouts_create_core( } pub async fn payouts_update_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: payouts::PayoutCreateRequest, @@ -470,7 +470,7 @@ pub async fn payouts_update_core( #[instrument(skip_all)] pub async fn payouts_retrieve_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: payouts::PayoutRetrieveRequest, @@ -488,7 +488,7 @@ pub async fn payouts_retrieve_core( #[instrument(skip_all)] pub async fn payouts_cancel_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: payouts::PayoutActionRequest, @@ -584,7 +584,7 @@ pub async fn payouts_cancel_core( #[instrument(skip_all)] pub async fn payouts_fulfill_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: payouts::PayoutActionRequest, @@ -670,7 +670,7 @@ pub async fn payouts_fulfill_core( #[cfg(feature = "olap")] pub async fn payouts_list_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, constraints: payouts::PayoutListConstraints, @@ -767,7 +767,7 @@ pub async fn payouts_list_core( #[cfg(feature = "olap")] pub async fn payouts_filtered_list_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, filters: payouts::PayoutListFilterConstraints, @@ -817,7 +817,7 @@ pub async fn payouts_filtered_list_core( #[cfg(feature = "olap")] pub async fn payouts_list_available_filters_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, time_range: api::TimeRange, ) -> RouterResponse { @@ -852,7 +852,7 @@ pub async fn payouts_list_available_filters_core( // ********************************************** HELPERS ********************************************** pub async fn call_connector_payout( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_data: &api::ConnectorData, @@ -962,7 +962,7 @@ pub async fn call_connector_payout( } pub async fn complete_create_recipient( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_data: &api::ConnectorData, @@ -989,7 +989,7 @@ pub async fn complete_create_recipient( } pub async fn create_recipient( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_data: &api::ConnectorData, @@ -1124,7 +1124,7 @@ pub async fn create_recipient( } pub async fn complete_payout_eligibility( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_data: &api::ConnectorData, @@ -1167,7 +1167,7 @@ pub async fn complete_payout_eligibility( } pub async fn check_payout_eligibility( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_data: &api::ConnectorData, @@ -1281,7 +1281,7 @@ pub async fn check_payout_eligibility( } pub async fn complete_create_payout( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_data: &api::ConnectorData, @@ -1343,7 +1343,7 @@ pub async fn complete_create_payout( } pub async fn create_payout( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_data: &api::ConnectorData, @@ -1473,7 +1473,7 @@ pub async fn create_payout( } pub async fn complete_create_recipient_disburse_account( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_data: &api::ConnectorData, @@ -1500,7 +1500,7 @@ pub async fn complete_create_recipient_disburse_account( } pub async fn create_recipient_disburse_account( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_data: &api::ConnectorData, @@ -1586,7 +1586,7 @@ pub async fn create_recipient_disburse_account( } pub async fn cancel_payout( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_data: &api::ConnectorData, @@ -1692,7 +1692,7 @@ pub async fn cancel_payout( } pub async fn fulfill_payout( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, connector_data: &api::ConnectorData, @@ -1904,7 +1904,7 @@ pub async fn response_handler( // DB entries #[allow(clippy::too_many_arguments)] pub async fn payout_create_db_entries( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, req: &payouts::PayoutCreateRequest, @@ -2061,7 +2061,7 @@ pub async fn payout_create_db_entries( } pub async fn make_payout_data( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, req: &payouts::PayoutRequest, @@ -2169,7 +2169,7 @@ pub async fn add_external_account_addition_task( } async fn validate_and_get_business_profile( - state: &AppState, + state: &SessionState, profile_id: &String, merchant_id: &str, ) -> RouterResult { diff --git a/crates/router/src/core/payouts/access_token.rs b/crates/router/src/core/payouts/access_token.rs index 8dddc0c570c9..af4f9e5f2883 100644 --- a/crates/router/src/core/payouts/access_token.rs +++ b/crates/router/src/core/payouts/access_token.rs @@ -7,7 +7,7 @@ use crate::{ errors::{self, RouterResult}, payments, }, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services, types::{self, api as api_types, domain, storage::enums}, }; @@ -17,7 +17,7 @@ use crate::{ /// There was an error, cannot proceed further #[cfg(feature = "payouts")] pub async fn create_access_token( - state: &AppState, + state: &SessionState, connector_data: &api_types::ConnectorData, merchant_account: &domain::MerchantAccount, router_data: &mut types::PayoutsRouterData, @@ -48,7 +48,7 @@ pub async fn create_access_token( #[cfg(feature = "payouts")] pub async fn add_access_token_for_payout( - state: &AppState, + state: &SessionState, connector: &api_types::ConnectorData, merchant_account: &domain::MerchantAccount, router_data: &types::PayoutsRouterData, @@ -132,7 +132,7 @@ pub async fn add_access_token_for_payout( #[cfg(feature = "payouts")] pub async fn refresh_connector_auth( - state: &AppState, + state: &SessionState, connector: &api_types::ConnectorData, _merchant_account: &domain::MerchantAccount, router_data: &types::RouterData< diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index 3059d3a4164c..6f8a7784aebb 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -25,7 +25,7 @@ use crate::{ routing::TransactionData, }, db::StorageInterface, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services, types::{ api::{self, enums as api_enums}, @@ -41,7 +41,7 @@ use crate::{ #[allow(clippy::too_many_arguments)] pub async fn make_payout_method_data<'a>( - state: &'a AppState, + state: &'a SessionState, payout_method_data: Option<&api::PayoutMethodData>, payout_token: Option<&str>, customer_id: &id_type::CustomerId, @@ -186,7 +186,7 @@ pub async fn make_payout_method_data<'a>( } pub async fn save_payout_data_to_locker( - state: &AppState, + state: &SessionState, payout_data: &mut PayoutData, payout_method_data: &api::PayoutMethodData, merchant_account: &domain::MerchantAccount, @@ -574,7 +574,7 @@ pub async fn save_payout_data_to_locker( } pub async fn get_or_create_customer_details( - state: &AppState, + state: &SessionState, customer_details: &CustomerDetails, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -638,7 +638,7 @@ pub async fn get_or_create_customer_details( } pub async fn decide_payout_connector( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, request_straight_through: Option, @@ -795,7 +795,7 @@ pub async fn decide_payout_connector( } pub async fn get_default_payout_connector( - _state: &AppState, + _state: &SessionState, request_connector: Option, ) -> CustomResult { Ok(request_connector.map_or( @@ -805,7 +805,7 @@ pub async fn get_default_payout_connector( } pub fn should_call_payout_connector_create_customer<'a>( - state: &AppState, + state: &SessionState, connector: &api::ConnectorData, customer: &'a Option, connector_label: &str, @@ -834,7 +834,7 @@ pub fn should_call_payout_connector_create_customer<'a>( } pub async fn get_gsm_record( - state: &AppState, + state: &SessionState, error_code: Option, error_message: Option, connector_name: Option, diff --git a/crates/router/src/core/payouts/retry.rs b/crates/router/src/core/payouts/retry.rs index 7cb929db94a2..792309920cb9 100644 --- a/crates/router/src/core/payouts/retry.rs +++ b/crates/router/src/core/payouts/retry.rs @@ -28,7 +28,7 @@ pub enum PayoutRetryType { #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] pub async fn do_gsm_multiple_connector_actions( - state: &app::AppState, + state: &app::SessionState, mut connectors: IntoIter, original_connector_data: api::ConnectorData, payout_data: &mut PayoutData, @@ -95,7 +95,7 @@ pub async fn do_gsm_multiple_connector_actions( #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] pub async fn do_gsm_single_connector_actions( - state: &app::AppState, + state: &app::SessionState, original_connector_data: api::ConnectorData, payout_data: &mut PayoutData, merchant_account: &domain::MerchantAccount, @@ -158,7 +158,7 @@ pub async fn do_gsm_single_connector_actions( #[instrument(skip_all)] pub async fn get_retries( - state: &app::AppState, + state: &app::SessionState, retries: Option, merchant_id: &str, retry_type: PayoutRetryType, @@ -196,7 +196,7 @@ pub async fn get_retries( #[instrument(skip_all)] pub async fn get_gsm( - state: &app::AppState, + state: &app::SessionState, original_connector_data: &api::ConnectorData, payout_data: &PayoutData, ) -> RouterResult> { @@ -236,7 +236,7 @@ pub fn get_gsm_decision( #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] pub async fn do_retry( - state: &routes::AppState, + state: &routes::SessionState, connector: api::ConnectorData, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -251,7 +251,7 @@ pub async fn do_retry( #[instrument(skip_all)] pub async fn modify_trackers( - state: &routes::AppState, + state: &routes::SessionState, connector: &api::ConnectorData, merchant_account: &domain::MerchantAccount, payout_data: &mut PayoutData, diff --git a/crates/router/src/core/payouts/validator.rs b/crates/router/src/core/payouts/validator.rs index 1819c5152e0b..58972cf4276e 100644 --- a/crates/router/src/core/payouts/validator.rs +++ b/crates/router/src/core/payouts/validator.rs @@ -11,7 +11,7 @@ use crate::{ utils as core_utils, }, db::StorageInterface, - routes::AppState, + routes::SessionState, types::{api::payouts, domain, storage}, utils, }; @@ -45,7 +45,7 @@ pub async fn validate_uniqueness_of_payout_id_against_merchant_id( /// - payout_id is unique against merchant_id /// - payout_token provided is legitimate pub async fn validate_create_request( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, req: &payouts::PayoutCreateRequest, merchant_key_store: &domain::MerchantKeyStore, diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index f184e166e22d..09d18963a29e 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -36,15 +36,12 @@ use crate::{ errors::{self, ApiErrorResponse, RouterResponse, RouterResult, StorageErrorExt}, payment_methods::cards, payments::helpers as oss_helpers, - pm_auth::helpers::{self as pm_auth_helpers}, + pm_auth::helpers as pm_auth_helpers, }, db::StorageInterface, logger, - routes::AppState, - services::{ - pm_auth::{self as pm_auth_services}, - ApplicationResponse, - }, + routes::SessionState, + services::{pm_auth as pm_auth_services, ApplicationResponse}, types::{ self, domain::{self, types::decrypt}, @@ -55,7 +52,7 @@ use crate::{ }; pub async fn create_link_token( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, payload: api_models::pm_auth::LinkTokenCreateRequest, @@ -160,7 +157,7 @@ pub async fn create_link_token( }; let connector_resp = pm_auth_services::execute_connector_processing_step( - state.as_ref(), + &state, connector_integration, &router_data, &connector.connector_name, @@ -205,7 +202,7 @@ impl ForeignTryFrom<&types::ConnectorAuthType> for PlaidAuthType { } pub async fn exchange_token_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, payload: api_models::pm_auth::ExchangeTokenCreateRequest, @@ -270,7 +267,7 @@ async fn store_bank_details_in_payment_methods( key_store: domain::MerchantKeyStore, payload: api_models::pm_auth::ExchangeTokenCreateRequest, merchant_account: domain::MerchantAccount, - state: AppState, + state: SessionState, bank_account_details_resp: pm_auth_types::BankAccountCredentialsResponse, connector_details: (&str, Secret), mca_id: String, @@ -523,7 +520,7 @@ pub async fn get_bank_account_creds( connector_name: &str, access_token: &Secret, auth_type: pm_auth_types::ConnectorAuthType, - state: &AppState, + state: &SessionState, bank_account_id: Option>, ) -> RouterResult { let connector_integration_bank_details: BoxedConnectorIntegration< @@ -578,7 +575,7 @@ async fn get_access_token_from_exchange_api( connector_name: &str, payload: &api_models::pm_auth::ExchangeTokenCreateRequest, auth_type: &pm_auth_types::ConnectorAuthType, - state: &AppState, + state: &SessionState, ) -> RouterResult> { let connector_integration: BoxedConnectorIntegration< '_, @@ -662,7 +659,7 @@ async fn get_selected_config_from_redis( } pub async fn retrieve_payment_method_from_auth_service( - state: &AppState, + state: &SessionState, key_store: &domain::MerchantKeyStore, auth_token: &payment_methods::BankAccountTokenData, payment_intent: &PaymentIntent, diff --git a/crates/router/src/core/poll.rs b/crates/router/src/core/poll.rs index 32a7b0f547ce..53b4b02e610e 100644 --- a/crates/router/src/core/poll.rs +++ b/crates/router/src/core/poll.rs @@ -4,11 +4,13 @@ use error_stack::ResultExt; use router_env::{instrument, tracing}; use super::errors; -use crate::{core::errors::RouterResponse, services::ApplicationResponse, types::domain, AppState}; +use crate::{ + core::errors::RouterResponse, services::ApplicationResponse, types::domain, SessionState, +}; #[instrument(skip_all)] pub async fn retrieve_poll_status( - state: AppState, + state: SessionState, req: crate::types::api::PollId, merchant_account: domain::MerchantAccount, ) -> RouterResponse { diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index d2d2db71ef36..0d441e95382d 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -24,7 +24,7 @@ use crate::{ utils as core_utils, }, db, logger, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services, types::{ self, @@ -42,7 +42,7 @@ use crate::{ #[instrument(skip_all)] pub async fn refund_create_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, req: refunds::RefundRequest, @@ -134,7 +134,7 @@ pub async fn refund_create_core( #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] pub async fn trigger_refund_to_gateway( - state: &AppState, + state: &SessionState, refund: &storage::Refund, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -317,14 +317,14 @@ pub async fn trigger_refund_to_gateway( // ********************************************** REFUND SYNC ********************************************** pub async fn refund_response_wrapper<'a, F, Fut, T, Req>( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, request: Req, f: F, ) -> RouterResponse where - F: Fn(AppState, domain::MerchantAccount, domain::MerchantKeyStore, Req) -> Fut, + F: Fn(SessionState, domain::MerchantAccount, domain::MerchantKeyStore, Req) -> Fut, Fut: futures::Future>, T: ForeignInto, { @@ -337,7 +337,7 @@ where #[instrument(skip_all)] pub async fn refund_retrieve_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, request: refunds::RefundsRetrieveRequest, @@ -432,7 +432,7 @@ fn should_call_refund(refund: &diesel_models::refund::Refund, force_sync: bool) #[instrument(skip_all)] pub async fn sync_refund_with_gateway( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, payment_attempt: &storage::PaymentAttempt, @@ -546,7 +546,7 @@ pub async fn sync_refund_with_gateway( // ********************************************** REFUND UPDATE ********************************************** pub async fn refund_update_core( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, req: refunds::RefundUpdateRequest, ) -> RouterResponse { @@ -584,7 +584,7 @@ pub async fn refund_update_core( #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] pub async fn validate_and_create_refund( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, payment_attempt: &storage::PaymentAttempt, @@ -767,7 +767,7 @@ pub async fn validate_and_create_refund( #[instrument(skip_all)] #[cfg(feature = "olap")] pub async fn refund_list( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, req: api_models::refunds::RefundListRequest, ) -> RouterResponse { @@ -812,7 +812,7 @@ pub async fn refund_list( #[instrument(skip_all)] #[cfg(feature = "olap")] pub async fn refund_filter_list( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, req: api_models::payments::TimeRange, ) -> RouterResponse { @@ -832,7 +832,7 @@ pub async fn refund_filter_list( #[instrument(skip_all)] #[cfg(feature = "olap")] pub async fn get_filters_for_refunds( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, ) -> RouterResponse { let merchant_connector_accounts = if let services::ApplicationResponse::Json(data) = @@ -900,7 +900,7 @@ impl ForeignFrom for api::RefundResponse { #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] pub async fn schedule_refund_execution( - state: &AppState, + state: &SessionState, refund: storage::Refund, refund_type: api_models::refunds::RefundType, merchant_account: &domain::MerchantAccount, @@ -979,7 +979,7 @@ pub async fn schedule_refund_execution( #[instrument(skip_all)] pub async fn sync_refund_with_gateway_workflow( - state: &AppState, + state: &SessionState, refund_tracker: &storage::ProcessTracker, ) -> Result<(), errors::ProcessTrackerError> { let refund_core = @@ -1048,7 +1048,7 @@ pub async fn sync_refund_with_gateway_workflow( #[instrument(skip_all)] pub async fn start_refund_workflow( - state: &AppState, + state: &SessionState, refund_tracker: &storage::ProcessTracker, ) -> Result<(), errors::ProcessTrackerError> { match refund_tracker.name.as_deref() { @@ -1064,7 +1064,7 @@ pub async fn start_refund_workflow( #[instrument(skip_all)] pub async fn trigger_refund_execute_workflow( - state: &AppState, + state: &SessionState, refund_tracker: &storage::ProcessTracker, ) -> Result<(), errors::ProcessTrackerError> { let db = &*state.store; diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs index 31825617398a..a64dadaa35d9 100644 --- a/crates/router/src/core/routing.rs +++ b/crates/router/src/core/routing.rs @@ -27,7 +27,7 @@ use crate::{ errors::{RouterResponse, StorageErrorExt}, metrics, utils as core_utils, }, - routes::AppState, + routes::SessionState, types::domain, utils::{self, OptionExt, ValueExt}, }; @@ -46,7 +46,7 @@ where } pub async fn retrieve_merchant_routing_dictionary( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, #[cfg(feature = "business_profile_routing")] query_params: RoutingRetrieveQuery, #[cfg(feature = "business_profile_routing")] transaction_type: &enums::TransactionType, @@ -93,7 +93,7 @@ pub async fn retrieve_merchant_routing_dictionary( } pub async fn create_routing_config( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, request: routing_types::RoutingConfigRequest, @@ -248,7 +248,7 @@ pub async fn create_routing_config( } pub async fn link_routing_config( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, #[cfg(not(feature = "business_profile_routing"))] key_store: domain::MerchantKeyStore, algorithm_id: String, @@ -371,7 +371,7 @@ pub async fn link_routing_config( } pub async fn retrieve_routing_config( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, algorithm_id: RoutingAlgorithmId, ) -> RouterResponse { @@ -445,7 +445,7 @@ pub async fn retrieve_routing_config( } } pub async fn unlink_routing_config( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, #[cfg(not(feature = "business_profile_routing"))] key_store: domain::MerchantKeyStore, #[cfg(feature = "business_profile_routing")] request: routing_types::RoutingConfigRequest, @@ -630,7 +630,7 @@ pub async fn unlink_routing_config( } pub async fn update_default_routing_config( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, updated_config: Vec, transaction_type: &enums::TransactionType, @@ -679,7 +679,7 @@ pub async fn update_default_routing_config( } pub async fn retrieve_default_routing_config( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, transaction_type: &enums::TransactionType, ) -> RouterResponse> { @@ -699,7 +699,7 @@ pub async fn retrieve_default_routing_config( } pub async fn retrieve_linked_routing_config( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, #[cfg(feature = "business_profile_routing")] query_params: RoutingRetrieveLinkQuery, #[cfg(feature = "business_profile_routing")] transaction_type: &enums::TransactionType, @@ -808,7 +808,7 @@ pub async fn retrieve_linked_routing_config( } pub async fn retrieve_default_routing_config_for_profiles( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, transaction_type: &enums::TransactionType, ) -> RouterResponse> { @@ -847,7 +847,7 @@ pub async fn retrieve_default_routing_config_for_profiles( } pub async fn update_default_routing_config_for_profile( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, updated_config: Vec, profile_id: String, diff --git a/crates/router/src/core/surcharge_decision_config.rs b/crates/router/src/core/surcharge_decision_config.rs index b489b92cdf1f..7f451e6008fe 100644 --- a/crates/router/src/core/surcharge_decision_config.rs +++ b/crates/router/src/core/surcharge_decision_config.rs @@ -15,14 +15,14 @@ use super::routing::helpers::{ }; use crate::{ core::errors::{self, RouterResponse}, - routes::AppState, + routes::SessionState, services::api as service_api, types::domain, utils::OptionExt, }; pub async fn upsert_surcharge_decision_config( - state: AppState, + state: SessionState, key_store: domain::MerchantKeyStore, merchant_account: domain::MerchantAccount, request: SurchargeDecisionConfigReq, @@ -139,7 +139,7 @@ pub async fn upsert_surcharge_decision_config( } pub async fn delete_surcharge_decision_config( - state: AppState, + state: SessionState, key_store: domain::MerchantKeyStore, merchant_account: domain::MerchantAccount, ) -> RouterResponse<()> { @@ -167,7 +167,7 @@ pub async fn delete_surcharge_decision_config( } pub async fn retrieve_surcharge_decision_config( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, ) -> RouterResponse { let db = state.store.as_ref(); diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs index 9db47b74dc51..c259e87c93de 100644 --- a/crates/router/src/core/user.rs +++ b/crates/router/src/core/user.rs @@ -21,7 +21,7 @@ use super::errors::{StorageErrorExt, UserErrors, UserResponse, UserResult}; use crate::services::email::types as email_types; use crate::{ consts, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services::{authentication as auth, authorization::roles, ApplicationResponse}, types::{domain, transformers::ForeignInto}, utils::{self, user::two_factor_auth as tfa_utils}, @@ -33,7 +33,7 @@ pub mod sample_data; #[cfg(feature = "email")] pub async fn signup_with_merchant_id( - state: AppState, + state: SessionState, request: user_api::SignUpWithMerchantIdRequest, ) -> UserResponse { let new_user = domain::NewUser::try_from(request.clone())?; @@ -79,7 +79,7 @@ pub async fn signup_with_merchant_id( } pub async fn get_user_details( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, ) -> UserResponse { let user = user_from_token.get_user_from_db(&state).await?; @@ -99,7 +99,7 @@ pub async fn get_user_details( } pub async fn signup( - state: AppState, + state: SessionState, request: user_api::SignUpRequest, ) -> UserResponse> { let new_user = domain::NewUser::try_from(request)?; @@ -128,7 +128,7 @@ pub async fn signup( } pub async fn signup_token_only_flow( - state: AppState, + state: SessionState, request: user_api::SignUpRequest, ) -> UserResponse> { let new_user = domain::NewUser::try_from(request)?; @@ -163,7 +163,7 @@ pub async fn signup_token_only_flow( } pub async fn signin( - state: AppState, + state: SessionState, request: user_api::SignInRequest, ) -> UserResponse> { let user_from_db: domain::UserFromStorage = state @@ -207,7 +207,7 @@ pub async fn signin( } pub async fn signin_token_only_flow( - state: AppState, + state: SessionState, request: user_api::SignInRequest, ) -> UserResponse> { let user_from_db: domain::UserFromStorage = state @@ -233,7 +233,7 @@ pub async fn signin_token_only_flow( #[cfg(feature = "email")] pub async fn connect_account( - state: AppState, + state: SessionState, request: user_api::ConnectAccountRequest, ) -> UserResponse { let find_user = state.store.find_user_by_email(&request.email).await; @@ -324,13 +324,16 @@ pub async fn connect_account( } } -pub async fn signout(state: AppState, user_from_token: auth::UserFromToken) -> UserResponse<()> { +pub async fn signout( + state: SessionState, + user_from_token: auth::UserFromToken, +) -> UserResponse<()> { auth::blacklist::insert_user_in_blacklist(&state, &user_from_token.user_id).await?; auth::cookies::remove_cookie_response() } pub async fn change_password( - state: AppState, + state: SessionState, request: user_api::ChangePasswordRequest, user_from_token: auth::UserFromToken, ) -> UserResponse<()> { @@ -386,7 +389,7 @@ pub async fn change_password( #[cfg(feature = "email")] pub async fn forgot_password( - state: AppState, + state: SessionState, request: user_api::ForgotPasswordRequest, ) -> UserResponse<()> { let user_email = domain::UserEmail::from_pii_email(request.email)?; @@ -424,7 +427,7 @@ pub async fn forgot_password( } pub async fn rotate_password( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, request: user_api::RotatePasswordRequest, _req_state: ReqState, @@ -463,7 +466,7 @@ pub async fn rotate_password( #[cfg(feature = "email")] pub async fn reset_password_token_only_flow( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, request: user_api::ResetPasswordRequest, ) -> UserResponse<()> { @@ -517,7 +520,7 @@ pub async fn reset_password_token_only_flow( #[cfg(feature = "email")] pub async fn reset_password( - state: AppState, + state: SessionState, request: user_api::ResetPasswordRequest, ) -> UserResponse<()> { let token = request.token.expose(); @@ -569,7 +572,7 @@ pub async fn reset_password( } pub async fn invite_multiple_user( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, requests: Vec, req_state: ReqState, @@ -598,7 +601,7 @@ pub async fn invite_multiple_user( } async fn handle_invitation( - state: &AppState, + state: &SessionState, user_from_token: &auth::UserFromToken, request: &user_api::InviteUserRequest, req_state: &ReqState, @@ -656,7 +659,7 @@ async fn handle_invitation( //TODO: send email async fn handle_existing_user_invitation( - state: &AppState, + state: &SessionState, user_from_token: &auth::UserFromToken, request: &user_api::InviteUserRequest, invitee_user_from_db: domain::UserFromStorage, @@ -727,7 +730,7 @@ async fn handle_existing_user_invitation( } async fn handle_new_user_invitation( - state: &AppState, + state: &SessionState, user_from_token: &auth::UserFromToken, request: &user_api::InviteUserRequest, req_state: ReqState, @@ -839,7 +842,7 @@ async fn handle_new_user_invitation( #[cfg(feature = "email")] pub async fn resend_invite( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, request: user_api::ReInviteUserRequest, _req_state: ReqState, @@ -901,7 +904,7 @@ pub async fn resend_invite( #[cfg(feature = "email")] pub async fn accept_invite_from_email( - state: AppState, + state: SessionState, request: user_api::AcceptInviteFromEmailRequest, ) -> UserResponse { let token = request.token.expose(); @@ -968,7 +971,7 @@ pub async fn accept_invite_from_email( #[cfg(feature = "email")] pub async fn accept_invite_from_email_token_only_flow( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, request: user_api::AcceptInviteFromEmailRequest, ) -> UserResponse> { @@ -1034,7 +1037,7 @@ pub async fn accept_invite_from_email_token_only_flow( } pub async fn create_internal_user( - state: AppState, + state: SessionState, request: user_api::CreateInternalUserRequest, ) -> UserResponse<()> { let new_user = domain::NewUser::try_from(request)?; @@ -1097,7 +1100,7 @@ pub async fn create_internal_user( } pub async fn switch_merchant_id( - state: AppState, + state: SessionState, request: user_api::SwitchMerchantIdRequest, user_from_token: auth::UserFromToken, ) -> UserResponse { @@ -1196,7 +1199,7 @@ pub async fn switch_merchant_id( } pub async fn create_merchant_account( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, req: user_api::UserMerchantCreate, ) -> UserResponse<()> { @@ -1227,7 +1230,7 @@ pub async fn create_merchant_account( } pub async fn list_merchants_for_user( - state: AppState, + state: SessionState, user_from_token: Box, ) -> UserResponse> { let user_roles = state @@ -1260,7 +1263,7 @@ pub async fn list_merchants_for_user( } pub async fn get_user_details_in_merchant_account( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, request: user_api::GetUserRoleDetailsRequest, _req_state: ReqState, @@ -1304,7 +1307,7 @@ pub async fn get_user_details_in_merchant_account( } pub async fn list_users_for_merchant_account( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, ) -> UserResponse { let users_and_user_roles = state @@ -1352,7 +1355,7 @@ pub async fn list_users_for_merchant_account( #[cfg(feature = "email")] pub async fn verify_email( - state: AppState, + state: SessionState, req: user_api::VerifyEmailRequest, ) -> UserResponse { let token = req.token.clone().expose(); @@ -1411,7 +1414,7 @@ pub async fn verify_email( #[cfg(feature = "email")] pub async fn verify_email_token_only_flow( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, req: user_api::VerifyEmailRequest, ) -> UserResponse> { @@ -1469,7 +1472,7 @@ pub async fn verify_email_token_only_flow( #[cfg(feature = "email")] pub async fn send_verification_mail( - state: AppState, + state: SessionState, req: user_api::SendVerifyEmailRequest, ) -> UserResponse<()> { let user_email = domain::UserEmail::try_from(req.email)?; @@ -1509,7 +1512,7 @@ pub async fn send_verification_mail( #[cfg(feature = "recon")] pub async fn verify_token( - state: AppState, + state: SessionState, req: auth::ReconUser, ) -> UserResponse { let user = state @@ -1537,7 +1540,7 @@ pub async fn verify_token( } pub async fn update_user_details( - state: AppState, + state: SessionState, user_token: auth::UserFromToken, req: user_api::UpdateUserAccountDetailsRequest, _req_state: ReqState, @@ -1582,7 +1585,7 @@ pub async fn update_user_details( #[cfg(feature = "email")] pub async fn user_from_email( - state: AppState, + state: SessionState, req: user_api::UserFromEmailRequest, ) -> UserResponse { let token = req.token.expose(); @@ -1616,7 +1619,7 @@ pub async fn user_from_email( } pub async fn begin_totp( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, ) -> UserResponse { let user_from_db: domain::UserFromStorage = state @@ -1645,7 +1648,7 @@ pub async fn begin_totp( } pub async fn reset_totp( - state: AppState, + state: SessionState, user_token: auth::UserFromToken, ) -> UserResponse { let user_from_db: domain::UserFromStorage = state @@ -1678,7 +1681,7 @@ pub async fn reset_totp( } pub async fn verify_totp( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, req: user_api::VerifyTotpRequest, ) -> UserResponse { @@ -1714,7 +1717,7 @@ pub async fn verify_totp( } pub async fn update_totp( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, req: user_api::VerifyTotpRequest, ) -> UserResponse<()> { @@ -1779,7 +1782,7 @@ pub async fn update_totp( } pub async fn generate_recovery_codes( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, ) -> UserResponse { if !tfa_utils::check_totp_in_redis(&state, &user_token.user_id).await? { @@ -1811,7 +1814,7 @@ pub async fn generate_recovery_codes( } pub async fn verify_recovery_code( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, req: user_api::VerifyRecoveryCodeRequest, ) -> UserResponse { @@ -1856,7 +1859,7 @@ pub async fn verify_recovery_code( } pub async fn terminate_two_factor_auth( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, skip_two_factor_auth: bool, ) -> UserResponse { @@ -1908,7 +1911,7 @@ pub async fn terminate_two_factor_auth( } pub async fn check_two_factor_auth_status( - state: AppState, + state: SessionState, user_token: auth::UserFromToken, ) -> UserResponse { Ok(ApplicationResponse::Json( diff --git a/crates/router/src/core/user/dashboard_metadata.rs b/crates/router/src/core/user/dashboard_metadata.rs index ee1693b0c9d4..364898462946 100644 --- a/crates/router/src/core/user/dashboard_metadata.rs +++ b/crates/router/src/core/user/dashboard_metadata.rs @@ -12,14 +12,14 @@ use router_env::logger; use crate::services::email::types as email_types; use crate::{ core::errors::{UserErrors, UserResponse, UserResult}, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services::{authentication::UserFromToken, ApplicationResponse}, types::domain::{self, user::dashboard_metadata as types, MerchantKeyStore}, utils::user::dashboard_metadata as utils, }; pub async fn set_metadata( - state: AppState, + state: SessionState, user: UserFromToken, request: api::SetMetaDataRequest, _req_state: ReqState, @@ -33,7 +33,7 @@ pub async fn set_metadata( } pub async fn get_multiple_metadata( - state: AppState, + state: SessionState, user: UserFromToken, request: GetMultipleMetaDataPayload, _req_state: ReqState, @@ -230,7 +230,7 @@ fn into_response( } async fn insert_metadata( - state: &AppState, + state: &SessionState, user: UserFromToken, metadata_key: DBEnum, metadata_value: types::MetaData, @@ -571,7 +571,7 @@ async fn insert_metadata( } async fn fetch_metadata( - state: &AppState, + state: &SessionState, user: &UserFromToken, metadata_keys: Vec, ) -> UserResult> { @@ -606,7 +606,7 @@ async fn fetch_metadata( } pub async fn backfill_metadata( - state: &AppState, + state: &SessionState, user: &UserFromToken, key: &DBEnum, ) -> UserResult> { @@ -705,7 +705,7 @@ pub async fn backfill_metadata( } pub async fn get_merchant_connector_account_by_name( - state: &AppState, + state: &SessionState, merchant_id: &str, connector_name: &str, key_store: &MerchantKeyStore, diff --git a/crates/router/src/core/user/sample_data.rs b/crates/router/src/core/user/sample_data.rs index e1bde652305f..bab620620fa6 100644 --- a/crates/router/src/core/user/sample_data.rs +++ b/crates/router/src/core/user/sample_data.rs @@ -7,13 +7,13 @@ pub type SampleDataApiResponse = SampleDataResult>; use crate::{ core::errors::sample_data::SampleDataResult, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services::{authentication::UserFromToken, ApplicationResponse}, utils::user::sample_data::generate_sample_data, }; pub async fn generate_sample_data_for_user( - state: AppState, + state: SessionState, user_from_token: UserFromToken, req: SampleDataRequest, _req_state: ReqState, @@ -57,7 +57,7 @@ pub async fn generate_sample_data_for_user( } pub async fn delete_sample_data_for_user( - state: AppState, + state: SessionState, user_from_token: UserFromToken, _req: SampleDataRequest, _req_state: ReqState, diff --git a/crates/router/src/core/user_role.rs b/crates/router/src/core/user_role.rs index 0d196e1c4af6..8b636f9935b8 100644 --- a/crates/router/src/core/user_role.rs +++ b/crates/router/src/core/user_role.rs @@ -6,7 +6,7 @@ use router_env::logger; use crate::{ consts, core::errors::{StorageErrorExt, UserErrors, UserResponse}, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services::{ authentication as auth, authorization::{info, roles}, @@ -20,7 +20,7 @@ pub mod role; // TODO: To be deprecated once groups are stable pub async fn get_authorization_info_with_modules( - _state: AppState, + _state: SessionState, ) -> UserResponse { Ok(ApplicationResponse::Json( user_role_api::AuthorizationInfoResponse( @@ -33,7 +33,7 @@ pub async fn get_authorization_info_with_modules( } pub async fn get_authorization_info_with_groups( - _state: AppState, + _state: SessionState, ) -> UserResponse { Ok(ApplicationResponse::Json( user_role_api::AuthorizationInfoResponse( @@ -46,7 +46,7 @@ pub async fn get_authorization_info_with_groups( } pub async fn update_user_role( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, req: user_role_api::UpdateUserRoleRequest, _req_state: ReqState, @@ -117,7 +117,7 @@ pub async fn update_user_role( } pub async fn transfer_org_ownership( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, req: user_role_api::TransferOrgOwnershipRequest, _req_state: ReqState, @@ -169,7 +169,7 @@ pub async fn transfer_org_ownership( } pub async fn accept_invitation( - state: AppState, + state: SessionState, user_token: auth::UserFromToken, req: user_role_api::AcceptInvitationRequest, ) -> UserResponse<()> { @@ -199,7 +199,7 @@ pub async fn accept_invitation( } pub async fn merchant_select( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, req: user_role_api::MerchantSelectRequest, ) -> UserResponse> { @@ -253,7 +253,7 @@ pub async fn merchant_select( } pub async fn merchant_select_token_only_flow( - state: AppState, + state: SessionState, user_token: auth::UserFromSinglePurposeToken, req: user_role_api::MerchantSelectRequest, ) -> UserResponse> { @@ -303,7 +303,7 @@ pub async fn merchant_select_token_only_flow( } pub async fn delete_user_role( - state: AppState, + state: SessionState, user_from_token: auth::UserFromToken, request: user_role_api::DeleteUserRoleRequest, _req_state: ReqState, diff --git a/crates/router/src/core/user_role/role.rs b/crates/router/src/core/user_role/role.rs index 504d5dd632be..386156f58e74 100644 --- a/crates/router/src/core/user_role/role.rs +++ b/crates/router/src/core/user_role/role.rs @@ -7,7 +7,7 @@ use error_stack::{report, ResultExt}; use crate::{ consts, core::errors::{StorageErrorExt, UserErrors, UserResponse}, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services::{ authentication::{blacklist, UserFromToken}, authorization::roles::{self, predefined_roles::PREDEFINED_ROLES}, @@ -18,7 +18,7 @@ use crate::{ }; pub async fn get_role_from_token_with_permissions( - state: AppState, + state: SessionState, user_from_token: UserFromToken, ) -> UserResponse { let role_info = user_from_token @@ -38,7 +38,7 @@ pub async fn get_role_from_token_with_permissions( } pub async fn get_role_from_token_with_groups( - state: AppState, + state: SessionState, user_from_token: UserFromToken, ) -> UserResponse { let role_info = user_from_token @@ -54,7 +54,7 @@ pub async fn get_role_from_token_with_groups( } pub async fn create_role( - state: AppState, + state: SessionState, user_from_token: UserFromToken, req: role_api::CreateRoleRequest, _req_state: ReqState, @@ -107,7 +107,7 @@ pub async fn create_role( // TODO: To be deprecated once groups are stable pub async fn list_invitable_roles_with_permissions( - state: AppState, + state: SessionState, user_from_token: UserFromToken, ) -> UserResponse { let predefined_roles_map = PREDEFINED_ROLES @@ -156,7 +156,7 @@ pub async fn list_invitable_roles_with_permissions( } pub async fn list_invitable_roles_with_groups( - state: AppState, + state: SessionState, user_from_token: UserFromToken, ) -> UserResponse { let predefined_roles_map = PREDEFINED_ROLES @@ -198,7 +198,7 @@ pub async fn list_invitable_roles_with_groups( // TODO: To be deprecated once groups are stable pub async fn get_role_with_permissions( - state: AppState, + state: SessionState, user_from_token: UserFromToken, role: role_api::GetRoleRequest, ) -> UserResponse { @@ -232,7 +232,7 @@ pub async fn get_role_with_permissions( } pub async fn get_role_with_groups( - state: AppState, + state: SessionState, user_from_token: UserFromToken, role: role_api::GetRoleRequest, ) -> UserResponse { @@ -260,7 +260,7 @@ pub async fn get_role_with_groups( } pub async fn update_role( - state: AppState, + state: SessionState, user_from_token: UserFromToken, req: role_api::UpdateRoleRequest, role_id: &str, diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index e585724e96a0..679838a6dd53 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -25,7 +25,7 @@ use crate::{ consts, core::errors::{self, RouterResult, StorageErrorExt}, db::StorageInterface, - routes::AppState, + routes::SessionState, types::{ self, domain, storage::{self, enums}, @@ -45,7 +45,7 @@ const IRRELEVANT_ATTEMPT_ID_IN_DISPUTE_FLOW: &str = "irrelevant_attempt_id_in_di #[cfg(feature = "payouts")] #[instrument(skip_all)] pub async fn get_mca_for_payout<'a>( - state: &'a AppState, + state: &'a SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -72,7 +72,7 @@ pub async fn get_mca_for_payout<'a>( #[cfg(feature = "payouts")] #[instrument(skip_all)] pub async fn construct_payout_router_data<'a, F>( - state: &'a AppState, + state: &'a SessionState, connector_name: &api_models::enums::Connector, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -214,7 +214,7 @@ pub async fn construct_payout_router_data<'a, F>( #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] pub async fn construct_refund_router_data<'a, F>( - state: &'a AppState, + state: &'a SessionState, connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, @@ -263,7 +263,7 @@ pub async fn construct_refund_router_data<'a, F>( .change_context(errors::ApiErrorResponse::InternalServerError)?; let webhook_url = Some(helpers::create_webhook_url( - &state.conf.server.base_url.clone(), + &state.base_url.clone(), &merchant_account.merchant_id, &connector_id.to_string(), )); @@ -513,7 +513,7 @@ pub fn validate_dispute_stage_and_dispute_status( #[instrument(skip_all)] pub async fn construct_accept_dispute_router_data<'a>( - state: &'a AppState, + state: &'a SessionState, payment_intent: &'a storage::PaymentIntent, payment_attempt: &storage::PaymentAttempt, merchant_account: &domain::MerchantAccount, @@ -607,7 +607,7 @@ pub async fn construct_accept_dispute_router_data<'a>( #[instrument(skip_all)] pub async fn construct_submit_evidence_router_data<'a>( - state: &'a AppState, + state: &'a SessionState, payment_intent: &'a storage::PaymentIntent, payment_attempt: &storage::PaymentAttempt, merchant_account: &domain::MerchantAccount, @@ -701,7 +701,7 @@ pub async fn construct_submit_evidence_router_data<'a>( #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] pub async fn construct_upload_file_router_data<'a>( - state: &'a AppState, + state: &'a SessionState, payment_intent: &'a storage::PaymentIntent, payment_attempt: &storage::PaymentAttempt, merchant_account: &domain::MerchantAccount, @@ -799,7 +799,7 @@ pub async fn construct_upload_file_router_data<'a>( #[instrument(skip_all)] pub async fn construct_defend_dispute_router_data<'a>( - state: &'a AppState, + state: &'a SessionState, payment_intent: &'a storage::PaymentIntent, payment_attempt: &storage::PaymentAttempt, merchant_account: &domain::MerchantAccount, @@ -895,7 +895,7 @@ pub async fn construct_defend_dispute_router_data<'a>( #[instrument(skip_all)] pub async fn construct_retrieve_file_router_data<'a>( - state: &'a AppState, + state: &'a SessionState, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, file_metadata: &diesel_models::file::FileMetadata, diff --git a/crates/router/src/core/verification.rs b/crates/router/src/core/verification.rs index 802a4ec3c638..b6e71b2828fa 100644 --- a/crates/router/src/core/verification.rs +++ b/crates/router/src/core/verification.rs @@ -4,12 +4,12 @@ use common_utils::{errors::CustomResult, request::RequestContent}; use error_stack::ResultExt; use masking::ExposeInterface; -use crate::{core::errors, headers, logger, routes::AppState, services}; +use crate::{core::errors, headers, logger, routes::SessionState, services}; const APPLEPAY_INTERNAL_MERCHANT_NAME: &str = "Applepay_merchant"; pub async fn verify_merchant_creds_for_applepay( - state: AppState, + state: SessionState, body: verifications::ApplepayMerchantVerificationRequest, merchant_id: String, ) -> CustomResult, errors::ApiErrorResponse> @@ -83,7 +83,7 @@ pub async fn verify_merchant_creds_for_applepay( } pub async fn get_verified_apple_domains_with_mid_mca_id( - state: AppState, + state: SessionState, merchant_id: String, merchant_connector_id: String, ) -> CustomResult< diff --git a/crates/router/src/core/verification/utils.rs b/crates/router/src/core/verification/utils.rs index 56960d3cb480..7518091ee871 100644 --- a/crates/router/src/core/verification/utils.rs +++ b/crates/router/src/core/verification/utils.rs @@ -4,13 +4,13 @@ use error_stack::{Report, ResultExt}; use crate::{ core::errors::{self, utils::StorageErrorExt}, logger, - routes::AppState, + routes::SessionState, types, types::storage, }; pub async fn check_existence_and_add_domain_to_db( - state: &AppState, + state: &SessionState, merchant_id: String, merchant_connector_id: String, domain_from_req: Vec, diff --git a/crates/router/src/core/verify_connector.rs b/crates/router/src/core/verify_connector.rs index 8a8b0a14f7db..f42f9336a18b 100644 --- a/crates/router/src/core/verify_connector.rs +++ b/crates/router/src/core/verify_connector.rs @@ -13,11 +13,11 @@ use crate::{ transformers::ForeignInto, }, utils::verify_connector as utils, - AppState, + SessionState, }; pub async fn verify_connector_credentials( - state: AppState, + state: SessionState, req: VerifyConnectorRequest, ) -> errors::RouterResponse<()> { let boxed_connector = api::ConnectorData::get_connector_by_name( diff --git a/crates/router/src/core/webhooks.rs b/crates/router/src/core/webhooks.rs index c5055d4c8c25..7962e86e1228 100644 --- a/crates/router/src/core/webhooks.rs +++ b/crates/router/src/core/webhooks.rs @@ -39,10 +39,10 @@ use crate::{ }, logger, routes::{ - app::{AppStateInfo, ReqState}, + app::{ReqState, SessionStateInfo}, lock_utils, metrics::request::add_attributes, - AppState, + SessionState, }, services::{self, authentication as auth}, types::{ @@ -59,7 +59,7 @@ const OUTGOING_WEBHOOK_TIMEOUT_SECS: u64 = 5; const MERCHANT_ID: &str = "merchant_id"; pub async fn payments_incoming_webhook_flow( - state: AppState, + state: SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, business_profile: diesel_models::business_profile::BusinessProfile, @@ -204,7 +204,7 @@ pub async fn payments_incoming_webhook_flow( #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] pub async fn refunds_incoming_webhook_flow( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, business_profile: diesel_models::business_profile::BusinessProfile, key_store: domain::MerchantKeyStore, @@ -302,7 +302,7 @@ pub async fn refunds_incoming_webhook_flow( } pub async fn get_payment_attempt_from_object_reference_id( - state: &AppState, + state: &SessionState, object_reference_id: webhooks::ObjectReferenceId, merchant_account: &domain::MerchantAccount, ) -> CustomResult< @@ -342,7 +342,7 @@ pub async fn get_payment_attempt_from_object_reference_id( #[allow(clippy::too_many_arguments)] pub async fn get_or_update_dispute_object( - state: AppState, + state: SessionState, option_dispute: Option, dispute_details: api::disputes::DisputePayload, merchant_id: &str, @@ -418,7 +418,7 @@ pub async fn get_or_update_dispute_object( #[allow(clippy::too_many_arguments)] pub async fn external_authentication_incoming_webhook_flow( - state: AppState, + state: SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, @@ -592,7 +592,7 @@ pub async fn external_authentication_incoming_webhook_flow( } pub async fn mandates_incoming_webhook_flow( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, business_profile: diesel_models::business_profile::BusinessProfile, key_store: domain::MerchantKeyStore, @@ -680,7 +680,7 @@ pub async fn mandates_incoming_webhook_flow( #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] pub(crate) async fn frm_incoming_webhook_flow( - state: AppState, + state: SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, @@ -792,7 +792,7 @@ pub(crate) async fn frm_incoming_webhook_flow( #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] pub async fn disputes_incoming_webhook_flow( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, business_profile: diesel_models::business_profile::BusinessProfile, key_store: domain::MerchantKeyStore, @@ -862,7 +862,7 @@ pub async fn disputes_incoming_webhook_flow( } async fn bank_transfer_webhook_flow( - state: AppState, + state: SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, business_profile: diesel_models::business_profile::BusinessProfile, @@ -951,7 +951,7 @@ async fn bank_transfer_webhook_flow( #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] pub(crate) async fn create_event_and_trigger_outgoing_webhook( - state: AppState, + state: SessionState, merchant_account: domain::MerchantAccount, business_profile: diesel_models::business_profile::BusinessProfile, merchant_key_store: &domain::MerchantKeyStore, @@ -1091,7 +1091,7 @@ pub(crate) async fn create_event_and_trigger_outgoing_webhook( #[allow(clippy::too_many_arguments)] #[instrument(skip_all)] pub(crate) async fn trigger_webhook_and_raise_event( - state: AppState, + state: SessionState, business_profile: diesel_models::business_profile::BusinessProfile, merchant_key_store: &domain::MerchantKeyStore, event: domain::Event, @@ -1123,7 +1123,7 @@ pub(crate) async fn trigger_webhook_and_raise_event( } async fn trigger_webhook_to_merchant( - state: AppState, + state: SessionState, business_profile: diesel_models::business_profile::BusinessProfile, merchant_key_store: &domain::MerchantKeyStore, event: domain::Event, @@ -1189,7 +1189,7 @@ async fn trigger_webhook_to_merchant( logger::debug!(outgoing_webhook_response=?response); let update_event_if_client_error = - |state: AppState, + |state: SessionState, merchant_key_store: domain::MerchantKeyStore, merchant_id: String, event_id: String, @@ -1234,7 +1234,7 @@ async fn trigger_webhook_to_merchant( }; let api_client_error_handler = - |state: AppState, + |state: SessionState, merchant_key_store: domain::MerchantKeyStore, merchant_id: String, event_id: String, @@ -1261,7 +1261,7 @@ async fn trigger_webhook_to_merchant( Ok::<_, error_stack::Report>(()) }; - let update_event_in_storage = |state: AppState, + let update_event_in_storage = |state: SessionState, merchant_key_store: domain::MerchantKeyStore, merchant_id: String, event_id: String, @@ -1339,7 +1339,7 @@ async fn trigger_webhook_to_merchant( ) }; let success_response_handler = - |state: AppState, + |state: SessionState, merchant_id: String, process_tracker: Option, business_status: &'static str| async move { @@ -1521,7 +1521,7 @@ async fn trigger_webhook_to_merchant( } fn raise_webhooks_analytics_event( - state: AppState, + state: SessionState, trigger_webhook_result: CustomResult<(), errors::WebhooksFlowError>, content: Option, merchant_id: String, @@ -1558,7 +1558,7 @@ fn raise_webhooks_analytics_event( #[allow(clippy::too_many_arguments)] pub async fn webhooks_wrapper( flow: &impl router_env::types::FlowMetric, - state: AppState, + state: SessionState, req_state: ReqState, req: &actix_web::HttpRequest, merchant_account: domain::MerchantAccount, @@ -1622,7 +1622,7 @@ pub async fn webhooks_wrapper( #[instrument(skip_all)] pub async fn webhooks_core( - state: AppState, + state: SessionState, req_state: ReqState, req: &actix_web::HttpRequest, merchant_account: domain::MerchantAccount, @@ -2019,7 +2019,7 @@ pub async fn get_payment_id( } fn get_connector_by_connector_name( - state: &AppState, + state: &SessionState, connector_name: &str, merchant_connector_id: Option, ) -> CustomResult<(&'static (dyn api::Connector + Sync), String), errors::ApiErrorResponse> { @@ -2067,7 +2067,7 @@ fn get_connector_by_connector_name( /// This function fetches the merchant connector account ( if the url used is /{merchant_connector_id}) /// if merchant connector id is not passed in the request, then this will return None for mca async fn fetch_optional_mca_and_connector( - state: &AppState, + state: &SessionState, merchant_account: &domain::MerchantAccount, connector_name_or_mca_id: &str, key_store: &domain::MerchantKeyStore, diff --git a/crates/router/src/core/webhooks/webhook_events.rs b/crates/router/src/core/webhooks/webhook_events.rs index f248edd652bf..2cb16a53b3a8 100644 --- a/crates/router/src/core/webhooks/webhook_events.rs +++ b/crates/router/src/core/webhooks/webhook_events.rs @@ -4,7 +4,7 @@ use router_env::{instrument, tracing}; use crate::{ core::errors::{self, RouterResponse, StorageErrorExt}, - routes::AppState, + routes::SessionState, services::ApplicationResponse, types::{api, domain, storage, transformers::ForeignTryFrom}, utils::{OptionExt, StringExt}, @@ -20,7 +20,7 @@ enum MerchantAccountOrBusinessProfile { #[instrument(skip(state))] pub async fn list_initial_delivery_attempts( - state: AppState, + state: SessionState, merchant_id_or_profile_id: String, constraints: api::webhook_events::EventListConstraints, ) -> RouterResponse> { @@ -108,7 +108,7 @@ pub async fn list_initial_delivery_attempts( #[instrument(skip(state))] pub async fn list_delivery_attempts( - state: AppState, + state: SessionState, merchant_id_or_profile_id: String, initial_attempt_id: String, ) -> RouterResponse> { @@ -157,7 +157,7 @@ pub async fn list_delivery_attempts( #[instrument(skip(state))] pub async fn retry_delivery_attempt( - state: AppState, + state: SessionState, merchant_id_or_profile_id: String, event_id: String, ) -> RouterResponse { @@ -254,7 +254,7 @@ pub async fn retry_delivery_attempt( } async fn determine_identifier_and_get_key_store( - state: AppState, + state: SessionState, merchant_id_or_profile_id: String, ) -> errors::RouterResult<(MerchantAccountOrBusinessProfile, domain::MerchantKeyStore)> { let store = state.store.as_ref(); diff --git a/crates/router/src/db/api_keys.rs b/crates/router/src/db/api_keys.rs index 5d2f1c57a2a1..ea63a8817043 100644 --- a/crates/router/src/db/api_keys.rs +++ b/crates/router/src/db/api_keys.rs @@ -373,7 +373,7 @@ impl ApiKeyInterface for MockDb { #[cfg(test)] mod tests { use storage_impl::redis::{ - cache::{self, CacheKind, ACCOUNTS_CACHE}, + cache::{self, CacheKey, CacheKind, ACCOUNTS_CACHE}, kv_store::RedisConnInterface, pub_sub::PubSubInterface, }; @@ -525,15 +525,12 @@ mod tests { .await .unwrap(); - assert!( - ACCOUNTS_CACHE - .get_val::(&format!( - "{}_{}", - merchant_id, - hashed_api_key.into_inner() - ),) - .await - .is_none() - ) + assert!(ACCOUNTS_CACHE + .get_val::(CacheKey { + key: format!("{}_{}", merchant_id, hashed_api_key.into_inner()), + prefix: String::default(), + },) + .await + .is_none()) } } diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 0e3b365ae075..910ad085f631 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -1098,8 +1098,9 @@ impl QueueInterface for KafkaStore { entry_id: &RedisEntryId, fields: Vec<(&str, String)>, ) -> CustomResult<(), RedisError> { + let stream_name = format!("{}_{}", &self.tenant_id.0, stream); self.diesel_store - .stream_append_entry(stream, entry_id, fields) + .stream_append_entry(&stream_name, entry_id, fields) .await } diff --git a/crates/router/src/db/merchant_connector_account.rs b/crates/router/src/db/merchant_connector_account.rs index b0f57367dbee..aea37b517be6 100644 --- a/crates/router/src/db/merchant_connector_account.rs +++ b/crates/router/src/db/merchant_connector_account.rs @@ -769,7 +769,7 @@ mod merchant_connector_account_cache_tests { use error_stack::ResultExt; use masking::PeekInterface; use storage_impl::redis::{ - cache::{self, CacheKind, ACCOUNTS_CACHE}, + cache::{self, CacheKey, CacheKind, ACCOUNTS_CACHE}, kv_store::RedisConnInterface, pub_sub::PubSubInterface, }; @@ -902,10 +902,10 @@ mod merchant_connector_account_cache_tests { .unwrap(); assert!(ACCOUNTS_CACHE - .get_val::(&format!( - "{}_{}", - merchant_id, connector_label - ),) + .get_val::(CacheKey { + key: format!("{}_{}", merchant_id, connector_label), + prefix: String::default(), + },) .await .is_none()) } diff --git a/crates/router/src/lib.rs b/crates/router/src/lib.rs index 2e9ecc13dcb1..7344b85d150d 100644 --- a/crates/router/src/lib.rs +++ b/crates/router/src/lib.rs @@ -32,7 +32,7 @@ use actix_web::{ use http::StatusCode; use hyperswitch_interfaces::secrets_interface::secret_state::SecuredSecret; use router_env::tracing::Instrument; -use routes::AppState; +use routes::{AppState, SessionState}; use storage_impl::errors::ApplicationResult; use tokio::sync::{mpsc, oneshot}; diff --git a/crates/router/src/routes.rs b/crates/router/src/routes.rs index cd216cb0e81b..9f13635ca901 100644 --- a/crates/router/src/routes.rs +++ b/crates/router/src/routes.rs @@ -60,7 +60,8 @@ pub use self::app::Recon; pub use self::app::{ ApiKeys, AppState, BusinessProfile, Cache, Cards, Configs, ConnectorOnboarding, Customers, Disputes, EphemeralKey, Files, Gsm, Health, Mandates, MerchantAccount, - MerchantConnectorAccount, PaymentLink, PaymentMethods, Payments, Poll, Refunds, User, Webhooks, + MerchantConnectorAccount, PaymentLink, PaymentMethods, Payments, Poll, Refunds, SessionState, + User, Webhooks, }; #[cfg(feature = "olap")] pub use self::app::{Blocklist, Routing, Verify, WebhookEvents}; diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index a7d17e602d53..5af3a2bef25c 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; use actix_web::{web, Scope}; #[cfg(all(feature = "business_profile_routing", feature = "olap"))] @@ -14,7 +14,7 @@ use hyperswitch_interfaces::{ }; use router_env::tracing_actix_web::RequestId; use scheduler::SchedulerInterface; -use storage_impl::MockDb; +use storage_impl::{config::TenantConfig, redis::RedisStore, MockDb}; use tokio::sync::oneshot; #[cfg(feature = "olap")] @@ -43,7 +43,8 @@ use super::{ephemeral_key::*, webhooks::*}; use super::{pm_auth, poll::retrieve_poll_status}; #[cfg(feature = "olap")] pub use crate::analytics::opensearch::OpenSearchClient; -use crate::configs::secrets_transformers; +#[cfg(feature = "olap")] +use crate::analytics::AnalyticsProvider; #[cfg(all(feature = "frm", feature = "oltp"))] use crate::routes::fraud_check as frm_routes; #[cfg(all(feature = "recon", feature = "olap"))] @@ -56,7 +57,11 @@ pub use crate::{ db::{StorageImpl, StorageInterface}, events::EventsHandler, routes::cards_info::card_iin_info, - services::get_store, + services::{get_cache_store, get_store}, +}; +use crate::{ + configs::{secrets_transformers, Settings}, + db::kafka_store::{KafkaStore, TenantID}, }; #[derive(Clone)] @@ -64,33 +69,87 @@ pub struct ReqState { pub event_context: events::EventContext, } +#[derive(Clone)] +pub struct SessionState { + pub store: Box, + pub conf: Arc>, + pub api_client: Box, + pub event_handler: EventsHandler, + #[cfg(feature = "email")] + pub email_client: Arc, + #[cfg(feature = "olap")] + pub pool: AnalyticsProvider, + pub file_storage_client: Box, + pub request_id: Option, + pub base_url: String, + pub tenant: String, + #[cfg(feature = "olap")] + pub opensearch_client: Arc, +} +impl scheduler::SchedulerSessionState for SessionState { + fn get_db(&self) -> Box { + self.store.get_scheduler_db() + } +} +impl SessionState { + pub fn get_req_state(&self) -> ReqState { + ReqState { + event_context: events::EventContext::new(self.event_handler.clone()), + } + } +} + +pub trait SessionStateInfo { + fn conf(&self) -> settings::Settings; + fn store(&self) -> Box; + fn event_handler(&self) -> EventsHandler; + fn get_request_id(&self) -> Option; + fn add_request_id(&mut self, request_id: RequestId); +} + +impl SessionStateInfo for SessionState { + fn store(&self) -> Box { + self.store.to_owned() + } + fn conf(&self) -> settings::Settings { + self.conf.as_ref().to_owned() + } + fn event_handler(&self) -> EventsHandler { + self.event_handler.clone() + } + fn get_request_id(&self) -> Option { + self.api_client.get_request_id() + } + fn add_request_id(&mut self, request_id: RequestId) { + self.api_client.add_request_id(request_id); + self.store.add_request_id(request_id.to_string()); + self.request_id.replace(request_id); + } +} #[derive(Clone)] pub struct AppState { pub flow_name: String, - pub store: Box, + pub stores: HashMap>, pub conf: Arc>, pub event_handler: EventsHandler, #[cfg(feature = "email")] pub email_client: Arc, pub api_client: Box, #[cfg(feature = "olap")] - pub pool: crate::analytics::AnalyticsProvider, + pub pools: HashMap, #[cfg(feature = "olap")] - pub opensearch_client: OpenSearchClient, + pub opensearch_client: Arc, pub request_id: Option, pub file_storage_client: Box, pub encryption_client: Box, } - impl scheduler::SchedulerAppState for AppState { - fn get_db(&self) -> Box { - self.store.get_scheduler_db() + fn get_tenants(&self) -> Vec { + self.conf.multitenancy.get_tenant_names() } } - pub trait AppStateInfo { fn conf(&self) -> settings::Settings; - fn store(&self) -> Box; fn event_handler(&self) -> EventsHandler; #[cfg(feature = "email")] fn email_client(&self) -> Arc; @@ -104,9 +163,6 @@ impl AppStateInfo for AppState { fn conf(&self) -> settings::Settings { self.conf.as_ref().to_owned() } - fn store(&self) -> Box { - self.store.to_owned() - } #[cfg(feature = "email")] fn email_client(&self) -> Arc { self.email_client.to_owned() @@ -116,7 +172,6 @@ impl AppStateInfo for AppState { } fn add_request_id(&mut self, request_id: RequestId) { self.api_client.add_request_id(request_id); - self.store.add_request_id(request_id.to_string()); self.request_id.replace(request_id); } @@ -183,43 +238,38 @@ impl AppState { #[allow(clippy::expect_used)] #[cfg(feature = "olap")] - let opensearch_client = conf - .opensearch - .get_opensearch_client() - .await - .expect("Failed to create opensearch client"); - - let store: Box = match storage_impl { - StorageImpl::Postgresql | StorageImpl::PostgresqlTest => match &event_handler { - EventsHandler::Kafka(kafka_client) => Box::new( - crate::db::KafkaStore::new( - #[allow(clippy::expect_used)] - get_store(&conf.clone(), shut_down_signal, testable) - .await - .expect("Failed to create store"), - kafka_client.clone(), - crate::db::kafka_store::TenantID("default".to_string()), - ) - .await, - ), - EventsHandler::Logs(_) => Box::new( - #[allow(clippy::expect_used)] - get_store(&conf, shut_down_signal, testable) - .await - .expect("Failed to create store"), - ), - }, - #[allow(clippy::expect_used)] - StorageImpl::Mock => Box::new( - MockDb::new(&conf.redis) - .await - .expect("Failed to create mock store"), - ), - }; + let opensearch_client = Arc::new( + conf.opensearch + .get_opensearch_client() + .await + .expect("Failed to create opensearch client"), + ); #[cfg(feature = "olap")] - let pool = - crate::analytics::AnalyticsProvider::from_conf(conf.analytics.get_inner()).await; + let mut pools: HashMap = HashMap::new(); + let mut stores = HashMap::new(); + #[allow(clippy::expect_used)] + let cache_store = get_cache_store(&conf.clone(), shut_down_signal, testable) + .await + .expect("Failed to create store"); + for (tenant_name, tenant) in conf.clone().multitenancy.get_tenants() { + let store: Box = Self::get_store_interface( + &storage_impl, + &event_handler, + &conf, + tenant, + Arc::clone(&cache_store), + testable, + ) + .await; + stores.insert(tenant_name.clone(), store); + #[cfg(feature = "olap")] + let pool = + AnalyticsProvider::from_conf(conf.analytics.get_inner(), tenant_name.as_str()) + .await; + #[cfg(feature = "olap")] + pools.insert(tenant_name.clone(), pool); + } #[cfg(feature = "email")] let email_client = Arc::new(create_email_client(&conf).await); @@ -228,14 +278,14 @@ impl AppState { Self { flow_name: String::from("default"), - store, + stores, conf: Arc::new(conf), #[cfg(feature = "email")] email_client, api_client, event_handler, #[cfg(feature = "olap")] - pool, + pools, #[cfg(feature = "olap")] opensearch_client, request_id: None, @@ -246,6 +296,43 @@ impl AppState { .await } + async fn get_store_interface( + storage_impl: &StorageImpl, + event_handler: &EventsHandler, + conf: &Settings, + tenant: &settings::Tenant, + cache_store: Arc, + testable: bool, + ) -> Box { + match storage_impl { + StorageImpl::Postgresql | StorageImpl::PostgresqlTest => match event_handler { + EventsHandler::Kafka(kafka_client) => Box::new( + KafkaStore::new( + #[allow(clippy::expect_used)] + get_store(&conf.clone(), tenant, Arc::clone(&cache_store), testable) + .await + .expect("Failed to create store"), + kafka_client.clone(), + TenantID(tenant.get_schema().to_string()), + ) + .await, + ), + EventsHandler::Logs(_) => Box::new( + #[allow(clippy::expect_used)] + get_store(conf, tenant, Arc::clone(&cache_store), testable) + .await + .expect("Failed to create store"), + ), + }, + #[allow(clippy::expect_used)] + StorageImpl::Mock => Box::new( + MockDb::new(&conf.redis) + .await + .expect("Failed to create mock store"), + ), + } + } + pub async fn new( conf: settings::Settings, shut_down_signal: oneshot::Sender<()>, @@ -265,6 +352,34 @@ impl AppState { event_context: events::EventContext::new(self.event_handler.clone()), } } + pub fn get_session_state(self: Arc, tenant: &str, err: F) -> Result + where + F: FnOnce() -> E + Copy, + { + Ok(SessionState { + store: self.stores.get(tenant).ok_or_else(err)?.clone(), + conf: Arc::clone(&self.conf), + api_client: self.api_client.clone(), + event_handler: self.event_handler.clone(), + #[cfg(feature = "olap")] + pool: self.pools.get(tenant).ok_or_else(err)?.clone(), + file_storage_client: self.file_storage_client.clone(), + request_id: self.request_id, + base_url: self + .conf + .multitenancy + .get_tenant(tenant) + .ok_or_else(err)? + .clone() + .base_url + .clone(), + tenant: tenant.to_string().clone(), + #[cfg(feature = "email")] + email_client: Arc::clone(&self.email_client), + #[cfg(feature = "olap")] + opensearch_client: Arc::clone(&self.opensearch_client), + }) + } } pub struct Health; diff --git a/crates/router/src/routes/customers.rs b/crates/router/src/routes/customers.rs index 4d86ae829e08..87366cf5c6d9 100644 --- a/crates/router/src/routes/customers.rs +++ b/crates/router/src/routes/customers.rs @@ -47,7 +47,7 @@ pub async fn customers_retrieve( let auth = if auth::is_jwt_auth(req.headers()) { Box::new(auth::JWTAuth(Permission::CustomerRead)) } else { - match auth::is_ephemeral_auth(req.headers(), &*state.store, &payload.customer_id).await { + match auth::is_ephemeral_auth(req.headers(), &payload.customer_id) { Ok(auth) => auth, Err(err) => return api::log_and_return_error_response(err), } diff --git a/crates/router/src/routes/dummy_connector/core.rs b/crates/router/src/routes/dummy_connector/core.rs index e8f84b3047eb..513a586d193a 100644 --- a/crates/router/src/routes/dummy_connector/core.rs +++ b/crates/router/src/routes/dummy_connector/core.rs @@ -1,4 +1,4 @@ -use app::AppState; +use app::SessionState; use common_utils::generate_id_with_default_len; use error_stack::ResultExt; @@ -10,7 +10,7 @@ use crate::{ }; pub async fn payment( - state: AppState, + state: SessionState, req: types::DummyConnectorPaymentRequest, ) -> types::DummyConnectorResponse { utils::tokio_mock_sleep( @@ -41,7 +41,7 @@ pub async fn payment( } pub async fn payment_data( - state: AppState, + state: SessionState, req: types::DummyConnectorPaymentRetrieveRequest, ) -> types::DummyConnectorResponse { utils::tokio_mock_sleep( @@ -55,7 +55,7 @@ pub async fn payment_data( } pub async fn payment_authorize( - state: AppState, + state: SessionState, req: types::DummyConnectorPaymentConfirmRequest, ) -> types::DummyConnectorResponse { let payment_data = utils::get_payment_data_by_attempt_id(&state, req.attempt_id.clone()).await; @@ -64,7 +64,7 @@ pub async fn payment_authorize( if let Ok(payment_data_inner) = payment_data { let return_url = format!( "{}/dummy-connector/complete/{}", - state.conf.server.base_url, req.attempt_id + state.base_url, req.attempt_id ); Ok(api::ApplicationResponse::FileData(( utils::get_authorize_page(payment_data_inner, return_url, dummy_connector_conf) @@ -83,7 +83,7 @@ pub async fn payment_authorize( } pub async fn payment_complete( - state: AppState, + state: SessionState, req: types::DummyConnectorPaymentCompleteRequest, ) -> types::DummyConnectorResponse<()> { utils::tokio_mock_sleep( @@ -145,7 +145,7 @@ pub async fn payment_complete( } pub async fn refund_payment( - state: AppState, + state: SessionState, req: types::DummyConnectorRefundRequest, ) -> types::DummyConnectorResponse { utils::tokio_mock_sleep( @@ -197,7 +197,7 @@ pub async fn refund_payment( } pub async fn refund_data( - state: AppState, + state: SessionState, req: types::DummyConnectorRefundRetrieveRequest, ) -> types::DummyConnectorResponse { let refund_id = req.refund_id; diff --git a/crates/router/src/routes/dummy_connector/utils.rs b/crates/router/src/routes/dummy_connector/utils.rs index 8bba182ad0a5..6211c3abf800 100644 --- a/crates/router/src/routes/dummy_connector/utils.rs +++ b/crates/router/src/routes/dummy_connector/utils.rs @@ -11,7 +11,7 @@ use super::{ consts, errors, types::{self, GetPaymentMethodDetails}, }; -use crate::{configs::settings, routes::AppState}; +use crate::{configs::settings, routes::SessionState}; pub async fn tokio_mock_sleep(delay: u64, tolerance: u64) { let mut rng = rand::thread_rng(); @@ -26,7 +26,7 @@ pub async fn tokio_mock_sleep(delay: u64, tolerance: u64) { } pub async fn store_data_in_redis( - state: &AppState, + state: &SessionState, key: String, data: impl serde::Serialize + Debug, ttl: i64, @@ -46,7 +46,7 @@ pub async fn store_data_in_redis( } pub async fn get_payment_data_from_payment_id( - state: &AppState, + state: &SessionState, payment_id: String, ) -> types::DummyConnectorResult { let redis_conn = state @@ -65,7 +65,7 @@ pub async fn get_payment_data_from_payment_id( } pub async fn get_payment_data_by_attempt_id( - state: &AppState, + state: &SessionState, attempt_id: String, ) -> types::DummyConnectorResult { let redis_conn = state @@ -336,12 +336,12 @@ impl ProcessPaymentAttempt for types::DummyConnectorPaymentMethodData { impl types::DummyConnectorPaymentData { pub fn process_payment_attempt( - state: &AppState, + state: &SessionState, payment_attempt: types::DummyConnectorPaymentAttempt, ) -> types::DummyConnectorResult { let redirect_url = format!( "{}/dummy-connector/authorize/{}", - state.conf.server.base_url, payment_attempt.attempt_id + state.base_url, payment_attempt.attempt_id ); payment_attempt .clone() diff --git a/crates/router/src/routes/health.rs b/crates/router/src/routes/health.rs index 7d35a91a31eb..721dbd6a78dd 100644 --- a/crates/router/src/routes/health.rs +++ b/crates/router/src/routes/health.rs @@ -40,7 +40,9 @@ pub async fn deep_health_check( .await } -async fn deep_health_check_func(state: app::AppState) -> RouterResponse { +async fn deep_health_check_func( + state: app::SessionState, +) -> RouterResponse { logger::info!("Deep health check was called"); logger::debug!("Database health check begin"); diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs index 96daf95d1156..e36a8fc3ea51 100644 --- a/crates/router/src/routes/payment_methods.rs +++ b/crates/router/src/routes/payment_methods.rs @@ -5,7 +5,7 @@ use error_stack::ResultExt; use router_env::{instrument, logger, tracing, Flow}; use time::PrimitiveDateTime; -use super::app::AppState; +use super::app::{AppState, SessionState}; use crate::{ core::{api_locking, errors, payment_methods::cards}, services::{api, authentication as auth, authorization::permissions::Permission}, @@ -139,11 +139,10 @@ pub async fn list_customer_payment_method_api( let payload = query_payload.into_inner(); let customer_id = customer_id.into_inner().0; - let ephemeral_auth = - match auth::is_ephemeral_auth(req.headers(), &*state.store, &customer_id).await { - Ok(auth) => auth, - Err(err) => return api::log_and_return_error_response(err), - }; + let ephemeral_auth = match auth::is_ephemeral_auth(req.headers(), &customer_id) { + Ok(auth) => auth, + Err(err) => return api::log_and_return_error_response(err), + }; Box::pin(api::server_wrap( flow, state, @@ -343,28 +342,28 @@ pub async fn default_payment_method_set_api( ) -> HttpResponse { let flow = Flow::DefaultPaymentMethodsSet; let payload = path.into_inner(); - let customer_id = payload.clone().customer_id; + let pc = payload.clone(); + let customer_id = &pc.customer_id; - let ephemeral_auth = - match auth::is_ephemeral_auth(req.headers(), &*state.store, &customer_id).await { - Ok(auth) => auth, - Err(err) => return api::log_and_return_error_response(err), - }; - let db = &*state.store.clone(); + let ephemeral_auth = match auth::is_ephemeral_auth(req.headers(), customer_id) { + Ok(auth) => auth, + Err(err) => return api::log_and_return_error_response(err), + }; Box::pin(api::server_wrap( flow, state, &req, payload, - |_state, auth: auth::AuthenticationData, default_payment_method, _| { + |state, auth: auth::AuthenticationData, default_payment_method, _| async move { cards::set_default_payment_method( - db, + &*state.clone().store, auth.merchant_account.merchant_id, auth.key_store, - &customer_id, + customer_id, default_payment_method.payment_method_id, auth.merchant_account.storage_scheme, ) + .await }, &*ephemeral_auth, api_locking::LockAction::NotApplicable, @@ -416,7 +415,7 @@ impl ParentPaymentMethodToken { &self, intent_created_at: Option, token: PaymentTokenData, - state: &AppState, + state: &SessionState, ) -> CustomResult<(), errors::ApiErrorResponse> { let token_json_str = token .encode_to_string_of_json() @@ -452,7 +451,7 @@ impl ParentPaymentMethodToken { .contains(&status) } - pub async fn delete(&self, state: &AppState) -> CustomResult<(), errors::ApiErrorResponse> { + pub async fn delete(&self, state: &SessionState) -> CustomResult<(), errors::ApiErrorResponse> { let redis_conn = state .store .get_redis_conn() diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index ab6b0f450db1..a89410a2b0f9 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -681,6 +681,7 @@ pub async fn payments_redirect_response( auth.merchant_account, auth.key_store, req, + ) }, &auth::MerchantIdAuth(merchant_id), @@ -742,6 +743,7 @@ pub async fn payments_redirect_response_with_creds_identifier( auth.merchant_account, auth.key_store, req, + ) }, &auth::MerchantIdAuth(merchant_id), @@ -786,6 +788,7 @@ pub async fn payments_complete_authorize_redirect( auth.merchant_account, auth.key_store, req, + ) }, &auth::MerchantIdAuth(merchant_id), @@ -1142,7 +1145,7 @@ pub async fn payments_reject( #[allow(clippy::too_many_arguments)] async fn authorize_verify_select( operation: Op, - state: app::AppState, + state: app::SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, diff --git a/crates/router/src/routes/recon.rs b/crates/router/src/routes/recon.rs index fc0794ff9e0b..053037b57a5f 100644 --- a/crates/router/src/routes/recon.rs +++ b/crates/router/src/routes/recon.rs @@ -4,7 +4,7 @@ use error_stack::ResultExt; use masking::{ExposeInterface, PeekInterface, Secret}; use router_env::Flow; -use super::AppState; +use super::{AppState, SessionState}; use crate::{ core::{ api_locking, @@ -70,7 +70,7 @@ pub async fn get_recon_token(state: web::Data, req: HttpRequest) -> Ht } pub async fn send_recon_request( - state: AppState, + state: SessionState, user: UserFromToken, ) -> RouterResponse { let db = &*state.store; @@ -150,7 +150,7 @@ pub async fn send_recon_request( } pub async fn recon_merchant_account_update( - state: AppState, + state: SessionState, req: recon_api::ReconUpdateMerchantRequest, ) -> RouterResponse { let merchant_id = &req.merchant_id.clone(); @@ -217,7 +217,7 @@ pub async fn recon_merchant_account_update( } pub async fn generate_recon_token( - state: AppState, + state: SessionState, req: ReconUser, ) -> RouterResponse { let db = &*state.store; @@ -243,7 +243,7 @@ pub async fn generate_recon_token( pub async fn get_recon_auth_token( user: UserFromStorage, - state: AppState, + state: SessionState, ) -> RouterResult> { ReconToken::new_token(user.0.user_id.clone(), &state.conf).await } diff --git a/crates/router/src/services.rs b/crates/router/src/services.rs index bb50e27b8cd6..5c860aa8a615 100644 --- a/crates/router/src/services.rs +++ b/crates/router/src/services.rs @@ -13,12 +13,14 @@ pub mod recon; #[cfg(feature = "email")] pub mod email; +use std::sync::Arc; + use error_stack::ResultExt; use hyperswitch_domain_models::errors::StorageResult; use masking::{ExposeInterface, StrongSecret}; #[cfg(feature = "kv_store")] use storage_impl::KVRouterStore; -use storage_impl::RouterStore; +use storage_impl::{redis::RedisStore, RouterStore}; use tokio::sync::oneshot; pub use self::{api::*, encryption::*}; @@ -40,7 +42,8 @@ pub type Store = KVRouterStore; #[allow(clippy::expect_used)] pub async fn get_store( config: &Settings, - shut_down_signal: oneshot::Sender<()>, + tenant: &crate::configs::settings::Tenant, + cache_store: Arc, test_transaction: bool, ) -> StorageResult { let master_config = config.master_database.clone().into_inner(); @@ -61,13 +64,13 @@ pub async fn get_store( let conf = (master_config.into(), replica_config.into()); let store: RouterStore = if test_transaction { - RouterStore::test_store(conf, &config.redis, master_enc_key).await? + RouterStore::test_store(conf, tenant, &config.redis, master_enc_key).await? } else { RouterStore::from_config( conf, - &config.redis, + tenant, master_enc_key, - shut_down_signal, + cache_store, storage_impl::redis::cache::PUB_SUB_CHANNEL, ) .await? @@ -85,6 +88,15 @@ pub async fn get_store( Ok(store) } +#[allow(clippy::expect_used)] +pub async fn get_cache_store( + config: &Settings, + shut_down_signal: oneshot::Sender<()>, + _test_transaction: bool, +) -> StorageResult> { + RouterStore::::cache_store(&config.redis, shut_down_signal).await +} + #[inline] pub fn generate_aes256_key() -> errors::CustomResult<[u8; 32], common_utils::errors::CryptoError> { use ring::rand::SecureRandom; diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 5f69a9d40339..098060e144b2 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -1,14 +1,16 @@ pub mod client; pub mod request; use std::{ - collections::HashMap, + collections::{HashMap, HashSet}, error::Error, fmt::Debug, future::Future, str, + sync::Arc, time::{Duration, Instant}, }; +use actix_http::header::HeaderMap; use actix_web::{ body, http::header::HeaderValue, web, FromRequest, HttpRequest, HttpResponse, Responder, ResponseError, @@ -45,9 +47,9 @@ use crate::{ }, logger, routes::{ - app::{AppStateInfo, ReqState}, + app::{AppStateInfo, ReqState, SessionStateInfo}, metrics::{self, request as metrics_request}, - AppState, + AppState, SessionState, }, types::{ self, @@ -174,7 +176,7 @@ pub trait ConnectorIntegration: ConnectorIntegrationAny, - _app_state: &AppState, + _app_state: &SessionState, ) -> CustomResult<(), errors::ConnectorError> { Ok(()) } @@ -184,7 +186,7 @@ pub trait ConnectorIntegration: ConnectorIntegrationAny, - _app_state: &AppState, + _app_state: &SessionState, ) -> CustomResult<(), errors::ConnectorError> { Ok(()) } @@ -297,7 +299,7 @@ pub async fn execute_connector_processing_step< Req: Debug + Clone + 'static, Resp: Debug + Clone + 'static, >( - state: &'b AppState, + state: &'b SessionState, connector_integration: BoxedConnectorIntegration<'a, T, Req, Resp>, req: &'b types::RouterData, call_connector_action: payments::CallConnectorAction, @@ -555,7 +557,7 @@ where #[instrument(skip_all)] pub async fn call_connector_api( - state: &AppState, + state: &SessionState, request: Request, flow_name: &str, ) -> CustomResult, errors::ApiClientError> { @@ -591,7 +593,7 @@ pub async fn call_connector_api( #[instrument(skip_all)] pub async fn send_request( - state: &AppState, + state: &SessionState, request: Request, option_timeout_secs: Option, ) -> CustomResult { @@ -915,15 +917,16 @@ pub enum AuthFlow { pub async fn server_wrap_util<'a, 'b, U, T, Q, F, Fut, E, OErr>( flow: &'a impl router_env::types::FlowMetric, state: web::Data, + incoming_request_header: &HeaderMap, mut request_state: ReqState, request: &'a HttpRequest, payload: T, func: F, - api_auth: &dyn AuthenticateAndFetch, + api_auth: &dyn AuthenticateAndFetch, lock_action: api_locking::LockAction, ) -> CustomResult, OErr> where - F: Fn(AppState, U, T, ReqState) -> Fut, + F: Fn(SessionState, U, T, ReqState) -> Fut, 'b: 'a, Fut: Future, E>>, Q: Serialize + Debug + 'a + ApiEventMetric, @@ -945,17 +948,49 @@ where let mut app_state = state.get_ref().clone(); - app_state.add_request_id(request_id); let start_instant = Instant::now(); let serialized_request = masking::masked_serialize(&payload) .attach_printable("Failed to serialize json request") .change_context(errors::ApiErrorResponse::InternalServerError.switch())?; let mut event_type = payload.get_api_event_type(); + let tenants: HashSet<_> = state + .conf + .multitenancy + .get_tenant_names() + .into_iter() + .collect(); + let tenant_id = if !state.conf.multitenancy.enabled { + common_utils::consts::DEFAULT_TENANT.to_string() + } else { + incoming_request_header + .get("x-tenant-id") + .and_then(|value| value.to_str().ok()) + .ok_or_else(|| errors::ApiErrorResponse::MissingTenantId.switch()) + .map(|req_tenant_id| { + if !tenants.contains(req_tenant_id) { + Err(errors::ApiErrorResponse::InvalidTenant { + tenant_id: req_tenant_id.to_string(), + } + .switch()) + } else { + Ok(req_tenant_id.to_string()) + } + })?? + }; + // let tenant_id = "public".to_string(); + let mut session_state = + Arc::new(app_state.clone()).get_session_state(tenant_id.as_str(), || { + errors::ApiErrorResponse::InvalidTenant { + tenant_id: tenant_id.clone(), + } + .switch() + })?; + session_state.add_request_id(request_id); // Currently auth failures are not recorded as API events let (auth_out, auth_type) = api_auth - .authenticate_and_fetch(request.headers(), &app_state) + .authenticate_and_fetch(request.headers(), &session_state) .await .switch()?; @@ -975,14 +1010,14 @@ where let output = { lock_action .clone() - .perform_locking_action(&app_state, merchant_id.to_owned()) + .perform_locking_action(&session_state, merchant_id.to_owned()) .await .switch()?; - let res = func(app_state.clone(), auth_out, payload, request_state) + let res = func(session_state.clone(), auth_out, payload, request_state) .await .switch(); lock_action - .free_lock_action(&app_state, merchant_id.to_owned()) + .free_lock_action(&session_state, merchant_id.to_owned()) .await .switch()?; res @@ -1064,11 +1099,11 @@ pub async fn server_wrap<'a, T, U, Q, F, Fut, E>( request: &'a HttpRequest, payload: T, func: F, - api_auth: &dyn AuthenticateAndFetch, + api_auth: &dyn AuthenticateAndFetch, lock_action: api_locking::LockAction, ) -> HttpResponse where - F: Fn(AppState, U, T, ReqState) -> Fut, + F: Fn(SessionState, U, T, ReqState) -> Fut, Fut: Future, E>>, Q: Serialize + Debug + ApiEventMetric + 'a, T: Debug + Serialize + ApiEventMetric, @@ -1109,6 +1144,7 @@ where server_wrap_util( &flow, state.clone(), + incoming_request_header, req_state, request, payload, diff --git a/crates/router/src/services/api/client.rs b/crates/router/src/services/api/client.rs index d6c55baf602b..add93e991194 100644 --- a/crates/router/src/services/api/client.rs +++ b/crates/router/src/services/api/client.rs @@ -15,7 +15,7 @@ use crate::{ errors::{ApiClientError, CustomResult}, payments, }, - routes::AppState, + routes::SessionState, }; static NON_PROXIED_CLIENT: OnceCell = OnceCell::new(); @@ -165,7 +165,7 @@ where async fn send_request( &self, - state: &AppState, + state: &SessionState, request: Request, option_timeout_secs: Option, forward_to_kafka: bool, @@ -340,7 +340,7 @@ impl ApiClient for ProxyClient { } async fn send_request( &self, - state: &AppState, + state: &SessionState, request: Request, option_timeout_secs: Option, _forward_to_kafka: bool, @@ -392,7 +392,7 @@ impl ApiClient for MockApiClient { async fn send_request( &self, - _state: &AppState, + _state: &SessionState, _request: Request, _option_timeout_secs: Option, _forward_to_kafka: bool, diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index 64a7c8069f78..28f9ccd1a778 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -25,14 +25,13 @@ use crate::consts; #[cfg(feature = "olap")] use crate::core::errors::UserResult; #[cfg(feature = "recon")] -use crate::routes::AppState; +use crate::routes::SessionState; use crate::{ core::{ api_keys, errors::{self, utils::StorageErrorExt, RouterResult}, }, - db::StorageInterface, - routes::app::AppStateInfo, + routes::app::SessionStateInfo, services::api, types::domain, utils::OptionExt, @@ -226,7 +225,7 @@ impl GetUserIdFromAuth for UserFromSinglePurposeToken { #[async_trait] pub trait AuthenticateAndFetch where - A: AppStateInfo, + A: SessionStateInfo, { async fn authenticate_and_fetch( &self, @@ -243,7 +242,7 @@ pub struct NoAuth; #[async_trait] impl AuthenticateAndFetch<(), A> for NoAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -257,7 +256,7 @@ where #[async_trait] impl AuthenticateAndFetch for ApiKeyAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -335,7 +334,7 @@ pub(crate) struct SinglePurposeJWTAuth(pub TokenPurpose); #[async_trait] impl AuthenticateAndFetch for SinglePurposeJWTAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -368,7 +367,7 @@ where #[async_trait] impl AuthenticateAndFetch, A> for SinglePurposeJWTAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -403,7 +402,7 @@ pub struct AdminApiAuth; #[async_trait] impl AuthenticateAndFetch<(), A> for AdminApiAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -425,13 +424,42 @@ where } } +#[derive(Debug)] +pub struct EphemeralKeyAuth(pub id_type::CustomerId); + +#[async_trait] +impl AuthenticateAndFetch for EphemeralKeyAuth +where + A: SessionStateInfo + Sync, +{ + async fn authenticate_and_fetch( + &self, + request_headers: &HeaderMap, + state: &A, + ) -> RouterResult<(AuthenticationData, AuthenticationType)> { + let api_key = + get_api_key(request_headers).change_context(errors::ApiErrorResponse::Unauthorized)?; + let ephemeral_key = state + .store() + .get_ephemeral_key(api_key) + .await + .change_context(errors::ApiErrorResponse::Unauthorized)?; + + if ephemeral_key.customer_id.ne(&self.0) { + return Err(report!(errors::ApiErrorResponse::InvalidEphemeralKey)); + } + MerchantIdAuth(ephemeral_key.merchant_id) + .authenticate_and_fetch(request_headers, state) + .await + } +} #[derive(Debug)] pub struct MerchantIdAuth(pub String); #[async_trait] impl AuthenticateAndFetch for MerchantIdAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -485,7 +513,7 @@ pub struct PublishableKeyAuth; #[async_trait] impl AuthenticateAndFetch for PublishableKeyAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -529,7 +557,7 @@ struct JwtAuthPayloadFetchUnit { #[async_trait] impl AuthenticateAndFetch<(), A> for JWTAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -558,7 +586,7 @@ where #[async_trait] impl AuthenticateAndFetch for JWTAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -596,7 +624,7 @@ pub struct JWTAuthMerchantFromRoute { #[async_trait] impl AuthenticateAndFetch<(), A> for JWTAuthMerchantFromRoute where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -633,7 +661,7 @@ pub struct JWTAuthMerchantOrProfileFromRoute { #[async_trait] impl AuthenticateAndFetch<(), A> for JWTAuthMerchantOrProfileFromRoute where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -690,7 +718,7 @@ where pub async fn parse_jwt_payload(headers: &HeaderMap, state: &A) -> RouterResult where T: serde::de::DeserializeOwned, - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { let token = match get_cookie_from_header(headers).and_then(cookies::parse_cookie) { Ok(cookies) => cookies, @@ -708,7 +736,7 @@ where #[async_trait] impl AuthenticateAndFetch for JWTAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -758,7 +786,7 @@ pub type AuthenticationDataWithUserId = (AuthenticationData, String); #[async_trait] impl AuthenticateAndFetch for JWTAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -809,7 +837,7 @@ pub struct DashboardNoPermissionAuth; #[async_trait] impl AuthenticateAndFetch for DashboardNoPermissionAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -840,7 +868,7 @@ where #[async_trait] impl AuthenticateAndFetch, A> for DashboardNoPermissionAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -871,7 +899,7 @@ where #[async_trait] impl AuthenticateAndFetch<(), A> for DashboardNoPermissionAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -890,7 +918,7 @@ where #[async_trait] impl AuthenticateAndFetch for DashboardNoPermissionAuth where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -987,7 +1015,7 @@ impl ClientSecretFetch for api_models::payment_methods::PaymentMethodUpdate { } } -pub fn get_auth_type_and_flow( +pub fn get_auth_type_and_flow( headers: &HeaderMap, ) -> RouterResult<( Box>, @@ -1009,7 +1037,7 @@ pub fn check_client_secret_and_get_auth( api::AuthFlow, )> where - T: AppStateInfo, + T: SessionStateInfo, ApiKeyAuth: AuthenticateAndFetch, PublishableKeyAuth: AuthenticateAndFetch, { @@ -1034,27 +1062,17 @@ where Ok((Box::new(ApiKeyAuth), api::AuthFlow::Merchant)) } -pub async fn is_ephemeral_auth( +pub fn is_ephemeral_auth( headers: &HeaderMap, - db: &dyn StorageInterface, customer_id: &id_type::CustomerId, ) -> RouterResult>> { let api_key = get_api_key(headers)?; if !api_key.starts_with("epk") { - return Ok(Box::new(ApiKeyAuth)); + Ok(Box::new(ApiKeyAuth)) + } else { + Ok(Box::new(EphemeralKeyAuth(customer_id.to_owned()))) } - - let ephemeral_key = db - .get_ephemeral_key(api_key) - .await - .change_context(errors::ApiErrorResponse::Unauthorized)?; - - if ephemeral_key.customer_id.ne(customer_id) { - return Err(report!(errors::ApiErrorResponse::InvalidEphemeralKey)); - } - - Ok(Box::new(MerchantIdAuth(ephemeral_key.merchant_id))) } pub fn is_jwt_auth(headers: &HeaderMap) -> bool { @@ -1064,7 +1082,7 @@ pub fn is_jwt_auth(headers: &HeaderMap) -> bool { .is_ok() } -pub async fn decode_jwt(token: &str, state: &impl AppStateInfo) -> RouterResult +pub async fn decode_jwt(token: &str, state: &impl SessionStateInfo) -> RouterResult where T: serde::de::DeserializeOwned, { @@ -1140,7 +1158,7 @@ pub struct ReconAdmin; #[cfg(feature = "recon")] impl AuthenticateAndFetch<(), A> for ReconAdmin where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { async fn authenticate_and_fetch( &self, @@ -1176,13 +1194,13 @@ impl AuthInfo for ReconUser { } #[cfg(all(feature = "olap", feature = "recon"))] #[async_trait] -impl AuthenticateAndFetch for ReconJWT { +impl AuthenticateAndFetch for ReconJWT { async fn authenticate_and_fetch( &self, request_headers: &HeaderMap, - state: &AppState, + state: &SessionState, ) -> RouterResult<(ReconUser, AuthenticationType)> { - let payload = parse_jwt_payload::(request_headers, state).await?; + let payload = parse_jwt_payload::(request_headers, state).await?; Ok(( ReconUser { diff --git a/crates/router/src/services/authentication/blacklist.rs b/crates/router/src/services/authentication/blacklist.rs index c1abb0647525..8a3aefd8fc04 100644 --- a/crates/router/src/services/authentication/blacklist.rs +++ b/crates/router/src/services/authentication/blacklist.rs @@ -13,17 +13,17 @@ use crate::consts::{EMAIL_TOKEN_BLACKLIST_PREFIX, EMAIL_TOKEN_TIME_IN_SECS}; use crate::{ consts::{JWT_TOKEN_TIME_IN_SECS, ROLE_BLACKLIST_PREFIX, USER_BLACKLIST_PREFIX}, core::errors::{ApiErrorResponse, RouterResult}, - routes::app::AppStateInfo, + routes::app::SessionStateInfo, }; #[cfg(feature = "olap")] use crate::{ core::errors::{UserErrors, UserResult}, - routes::AppState, + routes::SessionState, services::authorization as authz, }; #[cfg(feature = "olap")] -pub async fn insert_user_in_blacklist(state: &AppState, user_id: &str) -> UserResult<()> { +pub async fn insert_user_in_blacklist(state: &SessionState, user_id: &str) -> UserResult<()> { let user_blacklist_key = format!("{}{}", USER_BLACKLIST_PREFIX, user_id); let expiry = expiry_to_i64(JWT_TOKEN_TIME_IN_SECS).change_context(UserErrors::InternalServerError)?; @@ -39,7 +39,7 @@ pub async fn insert_user_in_blacklist(state: &AppState, user_id: &str) -> UserRe } #[cfg(feature = "olap")] -pub async fn insert_role_in_blacklist(state: &AppState, role_id: &str) -> UserResult<()> { +pub async fn insert_role_in_blacklist(state: &SessionState, role_id: &str) -> UserResult<()> { let role_blacklist_key = format!("{}{}", ROLE_BLACKLIST_PREFIX, role_id); let expiry = expiry_to_i64(JWT_TOKEN_TIME_IN_SECS).change_context(UserErrors::InternalServerError)?; @@ -58,7 +58,7 @@ pub async fn insert_role_in_blacklist(state: &AppState, role_id: &str) -> UserRe } #[cfg(feature = "olap")] -async fn invalidate_role_cache(state: &AppState, role_id: &str) -> RouterResult<()> { +async fn invalidate_role_cache(state: &SessionState, role_id: &str) -> RouterResult<()> { let redis_conn = get_redis_connection(state)?; redis_conn .delete_key(authz::get_cache_key_from_role_id(role_id).as_str()) @@ -67,7 +67,7 @@ async fn invalidate_role_cache(state: &AppState, role_id: &str) -> RouterResult< .change_context(ApiErrorResponse::InternalServerError) } -pub async fn check_user_in_blacklist( +pub async fn check_user_in_blacklist( state: &A, user_id: &str, token_expiry: u64, @@ -82,7 +82,7 @@ pub async fn check_user_in_blacklist( .map(|timestamp| timestamp.map_or(false, |timestamp| timestamp > token_issued_at)) } -pub async fn check_role_in_blacklist( +pub async fn check_role_in_blacklist( state: &A, role_id: &str, token_expiry: u64, @@ -98,7 +98,7 @@ pub async fn check_role_in_blacklist( } #[cfg(feature = "email")] -pub async fn insert_email_token_in_blacklist(state: &AppState, token: &str) -> UserResult<()> { +pub async fn insert_email_token_in_blacklist(state: &SessionState, token: &str) -> UserResult<()> { let redis_conn = get_redis_connection(state).change_context(UserErrors::InternalServerError)?; let blacklist_key = format!("{}{token}", EMAIL_TOKEN_BLACKLIST_PREFIX); let expiry = @@ -110,7 +110,7 @@ pub async fn insert_email_token_in_blacklist(state: &AppState, token: &str) -> U } #[cfg(feature = "email")] -pub async fn check_email_token_in_blacklist(state: &AppState, token: &str) -> UserResult<()> { +pub async fn check_email_token_in_blacklist(state: &SessionState, token: &str) -> UserResult<()> { let redis_conn = get_redis_connection(state).change_context(UserErrors::InternalServerError)?; let blacklist_key = format!("{}{token}", EMAIL_TOKEN_BLACKLIST_PREFIX); let key_exists = redis_conn @@ -124,7 +124,7 @@ pub async fn check_email_token_in_blacklist(state: &AppState, token: &str) -> Us Ok(()) } -fn get_redis_connection(state: &A) -> RouterResult> { +fn get_redis_connection(state: &A) -> RouterResult> { state .store() .get_redis_conn() @@ -140,14 +140,14 @@ fn expiry_to_i64(expiry: u64) -> RouterResult { pub trait BlackList { async fn check_in_blacklist(&self, state: &A) -> RouterResult where - A: AppStateInfo + Sync; + A: SessionStateInfo + Sync; } #[async_trait::async_trait] impl BlackList for AuthToken { async fn check_in_blacklist(&self, state: &A) -> RouterResult where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { Ok( check_user_in_blacklist(state, &self.user_id, self.exp).await? @@ -161,7 +161,7 @@ impl BlackList for AuthToken { impl BlackList for SinglePurposeToken { async fn check_in_blacklist(&self, state: &A) -> RouterResult where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { check_user_in_blacklist(state, &self.user_id, self.exp).await } diff --git a/crates/router/src/services/authorization.rs b/crates/router/src/services/authorization.rs index 33edb173255f..768c57a36d0c 100644 --- a/crates/router/src/services/authorization.rs +++ b/crates/router/src/services/authorization.rs @@ -9,7 +9,7 @@ use super::authentication::AuthToken; use crate::{ consts, core::errors::{ApiErrorResponse, RouterResult, StorageErrorExt}, - routes::app::AppStateInfo, + routes::app::SessionStateInfo, }; #[cfg(feature = "olap")] @@ -23,7 +23,7 @@ pub async fn get_permissions( token: &AuthToken, ) -> RouterResult> where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { if let Some(permissions) = get_permissions_from_predefined_roles(&token.role_id) { return Ok(permissions); @@ -55,7 +55,7 @@ async fn get_permissions_from_cache( role_id: &str, ) -> RouterResult> where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { let redis_conn = get_redis_connection(state)?; @@ -82,7 +82,7 @@ async fn get_permissions_from_db( org_id: &str, ) -> RouterResult> where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { state .store() @@ -99,7 +99,7 @@ pub async fn set_permissions_in_cache( expiry: i64, ) -> RouterResult<()> where - A: AppStateInfo + Sync, + A: SessionStateInfo + Sync, { let redis_conn = get_redis_connection(state)?; @@ -139,7 +139,7 @@ pub fn check_authorization( ) } -fn get_redis_connection(state: &A) -> RouterResult> { +fn get_redis_connection(state: &A) -> RouterResult> { state .store() .get_redis_conn() diff --git a/crates/router/src/services/authorization/roles.rs b/crates/router/src/services/authorization/roles.rs index f99892c565d9..8e5cb6fbeaa9 100644 --- a/crates/router/src/services/authorization/roles.rs +++ b/crates/router/src/services/authorization/roles.rs @@ -4,7 +4,7 @@ use common_enums::{PermissionGroup, RoleScope}; use common_utils::errors::CustomResult; use super::{permission_groups::get_permissions_vec, permissions::Permission}; -use crate::{core::errors, routes::AppState}; +use crate::{core::errors, routes::SessionState}; pub mod predefined_roles; @@ -67,7 +67,7 @@ impl RoleInfo { } pub async fn from_role_id( - state: &AppState, + state: &SessionState, role_id: &str, merchant_id: &str, org_id: &str, diff --git a/crates/router/src/services/email/types.rs b/crates/router/src/services/email/types.rs index ee51d976b40e..d05e6ab22575 100644 --- a/crates/router/src/services/email/types.rs +++ b/crates/router/src/services/email/types.rs @@ -7,7 +7,7 @@ use error_stack::ResultExt; use external_services::email::{EmailContents, EmailData, EmailError}; use masking::{ExposeInterface, PeekInterface, Secret}; -use crate::{configs, consts, routes::AppState}; +use crate::{configs, consts, routes::SessionState}; #[cfg(feature = "olap")] use crate::{ core::errors::{UserErrors, UserResult}, @@ -407,7 +407,7 @@ pub struct BizEmailProd { } impl BizEmailProd { - pub fn new(state: &AppState, data: ProdIntent) -> UserResult { + pub fn new(state: &SessionState, data: ProdIntent) -> UserResult { Ok(Self { recipient_email: (domain::UserEmail::new( consts::user::BUSINESS_EMAIL.to_string().into(), diff --git a/crates/router/src/services/pm_auth.rs b/crates/router/src/services/pm_auth.rs index a54ba8819954..d63dadc8b157 100644 --- a/crates/router/src/services/pm_auth.rs +++ b/crates/router/src/services/pm_auth.rs @@ -7,12 +7,12 @@ use pm_auth::{ use crate::{ core::errors::{self}, logger, - routes::AppState, + routes::SessionState, services::{self}, }; pub async fn execute_connector_processing_step<'b, 'a, T, Req, Resp>( - state: &'b AppState, + state: &'b SessionState, connector_integration: BoxedConnectorIntegration<'a, T, Req, Resp>, req: &'b PaymentAuthRouterData, connector: &pm_auth_types::PaymentMethodAuthConnectors, diff --git a/crates/router/src/types/api/mandates.rs b/crates/router/src/types/api/mandates.rs index 0e80fd224da1..71b90ab41c3d 100644 --- a/crates/router/src/types/api/mandates.rs +++ b/crates/router/src/types/api/mandates.rs @@ -11,7 +11,7 @@ use crate::{ payment_methods, }, newtype, - routes::AppState, + routes::SessionState, types::{ api, domain, storage::{self, enums as storage_enums}, @@ -26,7 +26,7 @@ newtype!( #[async_trait::async_trait] pub(crate) trait MandateResponseExt: Sized { async fn from_db_mandate( - state: &AppState, + state: &SessionState, key_store: domain::MerchantKeyStore, mandate: storage::Mandate, storage_scheme: storage_enums::MerchantStorageScheme, @@ -36,7 +36,7 @@ pub(crate) trait MandateResponseExt: Sized { #[async_trait::async_trait] impl MandateResponseExt for MandateResponse { async fn from_db_mandate( - state: &AppState, + state: &SessionState, key_store: domain::MerchantKeyStore, mandate: storage::Mandate, storage_scheme: storage_enums::MerchantStorageScheme, diff --git a/crates/router/src/types/api/verify_connector.rs b/crates/router/src/types/api/verify_connector.rs index 60749f647891..0b932f9aeb1e 100644 --- a/crates/router/src/types/api/verify_connector.rs +++ b/crates/router/src/types/api/verify_connector.rs @@ -8,7 +8,7 @@ use crate::{ services, services::ConnectorIntegration, types::{self, api, domain, storage::enums as storage_enums}, - AppState, + SessionState, }; #[derive(Clone)] @@ -113,7 +113,7 @@ impl VerifyConnectorData { #[async_trait::async_trait] pub trait VerifyConnector { async fn verify( - state: &AppState, + state: &SessionState, connector_data: VerifyConnectorData, ) -> errors::RouterResponse<()> { let authorize_data = connector_data.get_payment_authorize_data(); @@ -147,7 +147,7 @@ pub trait VerifyConnector { } async fn get_access_token( - _state: &AppState, + _state: &SessionState, _connector_data: VerifyConnectorData, ) -> errors::CustomResult, errors::ApiErrorResponse> { // AccessToken is None for the connectors without the AccessToken Flow. diff --git a/crates/router/src/types/api/verify_connector/paypal.rs b/crates/router/src/types/api/verify_connector/paypal.rs index 2cb2a8061d12..99b7feb66166 100644 --- a/crates/router/src/types/api/verify_connector/paypal.rs +++ b/crates/router/src/types/api/verify_connector/paypal.rs @@ -4,7 +4,7 @@ use super::{VerifyConnector, VerifyConnectorData}; use crate::{ connector, core::errors, - routes::AppState, + routes::SessionState, services, types::{self, api}, }; @@ -12,7 +12,7 @@ use crate::{ #[async_trait::async_trait] impl VerifyConnector for connector::Paypal { async fn get_access_token( - state: &AppState, + state: &SessionState, connector_data: VerifyConnectorData, ) -> errors::CustomResult, errors::ApiErrorResponse> { let token_data: types::AccessTokenRequestData = diff --git a/crates/router/src/types/api/webhooks.rs b/crates/router/src/types/api/webhooks.rs index 964885cae551..726a5a154269 100644 --- a/crates/router/src/types/api/webhooks.rs +++ b/crates/router/src/types/api/webhooks.rs @@ -146,7 +146,7 @@ pub trait IncomingWebhook: ConnectorCommon + Sync { async fn verify_webhook_source_verification_call( &self, - state: &crate::routes::AppState, + state: &crate::routes::SessionState, merchant_account: &domain::MerchantAccount, merchant_connector_account: domain::MerchantConnectorAccount, connector_name: &str, diff --git a/crates/router/src/types/domain/user.rs b/crates/router/src/types/domain/user.rs index 91323b0c16d3..60d75ce81d1b 100644 --- a/crates/router/src/types/domain/user.rs +++ b/crates/router/src/types/domain/user.rs @@ -30,7 +30,7 @@ use crate::{ errors::{self, UserErrors, UserResult}, }, db::StorageInterface, - routes::AppState, + routes::SessionState, services::{self, authentication as auth, authentication::UserFromToken, authorization::info}, types::transformers::ForeignFrom, utils::{self, user::password}, @@ -237,7 +237,7 @@ impl UserCompanyName { pub struct NewUserOrganization(diesel_org::OrganizationNew); impl NewUserOrganization { - pub async fn insert_org_in_db(self, state: AppState) -> UserResult { + pub async fn insert_org_in_db(self, state: SessionState) -> UserResult { state .store .insert_organization(self.0) @@ -351,7 +351,7 @@ impl NewUserMerchant { self.new_organization.clone() } - pub async fn check_if_already_exists_in_db(&self, state: AppState) -> UserResult<()> { + pub async fn check_if_already_exists_in_db(&self, state: SessionState) -> UserResult<()> { if state .store .get_merchant_key_store_by_merchant_id( @@ -370,7 +370,10 @@ impl NewUserMerchant { Ok(()) } - pub async fn create_new_merchant_and_insert_in_db(&self, state: AppState) -> UserResult<()> { + pub async fn create_new_merchant_and_insert_in_db( + &self, + state: SessionState, + ) -> UserResult<()> { self.check_if_already_exists_in_db(state.clone()).await?; Box::pin(admin::create_merchant_account( state.clone(), @@ -554,7 +557,7 @@ impl NewUser { .attach_printable("Error while inserting user") } - pub async fn check_if_already_exists_in_db(&self, state: AppState) -> UserResult<()> { + pub async fn check_if_already_exists_in_db(&self, state: SessionState) -> UserResult<()> { if state .store .find_user_by_email(&self.get_email().into_inner()) @@ -568,7 +571,7 @@ impl NewUser { pub async fn insert_user_and_merchant_in_db( &self, - state: AppState, + state: SessionState, ) -> UserResult { self.check_if_already_exists_in_db(state.clone()).await?; let db = state.store.as_ref(); @@ -585,7 +588,7 @@ impl NewUser { pub async fn insert_user_role_in_db( self, - state: AppState, + state: SessionState, role_id: String, user_status: UserStatus, ) -> UserResult { @@ -790,7 +793,7 @@ impl UserFromStorage { self.0.email.clone() } - pub async fn get_role_from_db(&self, state: AppState) -> UserResult { + pub async fn get_role_from_db(&self, state: SessionState) -> UserResult { state .store .find_user_role_by_user_id(&self.0.user_id) @@ -798,7 +801,7 @@ impl UserFromStorage { .change_context(UserErrors::InternalServerError) } - pub async fn get_roles_from_db(&self, state: &AppState) -> UserResult> { + pub async fn get_roles_from_db(&self, state: &SessionState) -> UserResult> { state .store .list_user_roles_by_user_id(&self.0.user_id) @@ -807,7 +810,7 @@ impl UserFromStorage { } #[cfg(feature = "email")] - pub fn get_verification_days_left(&self, state: &AppState) -> UserResult> { + pub fn get_verification_days_left(&self, state: &SessionState) -> UserResult> { if self.0.is_verified { return Ok(None); } @@ -829,7 +832,7 @@ impl UserFromStorage { Ok(Some(days_left_for_verification.whole_days())) } - pub fn is_password_rotate_required(&self, state: &AppState) -> UserResult { + pub fn is_password_rotate_required(&self, state: &SessionState) -> UserResult { let last_password_modified_at = if let Some(last_password_modified_at) = self.0.last_password_modified_at { last_password_modified_at.date() @@ -855,7 +858,7 @@ impl UserFromStorage { pub async fn get_role_from_db_by_merchant_id( &self, - state: &AppState, + state: &SessionState, merchant_id: &str, ) -> CustomResult { state @@ -866,7 +869,7 @@ impl UserFromStorage { pub async fn get_preferred_or_active_user_role_from_db( &self, - state: &AppState, + state: &SessionState, ) -> CustomResult { if let Some(preferred_merchant_id) = self.get_preferred_merchant_id() { self.get_role_from_db_by_merchant_id(state, &preferred_merchant_id) @@ -887,7 +890,7 @@ impl UserFromStorage { } } - pub async fn get_or_create_key_store(&self, state: &AppState) -> UserResult { + pub async fn get_or_create_key_store(&self, state: &SessionState) -> UserResult { let master_key = state.store.get_master_key(); let key_store_result = state .store @@ -936,7 +939,7 @@ impl UserFromStorage { pub async fn decrypt_and_get_totp_secret( &self, - state: &AppState, + state: &SessionState, ) -> UserResult>> { if self.0.totp_secret.is_none() { return Ok(None); @@ -1023,7 +1026,7 @@ impl SignInWithRoleStrategyType { pub async fn get_signin_response( self, - state: &AppState, + state: &SessionState, ) -> UserResult { match self { Self::SingleRole(strategy) => strategy.get_signin_response(state).await, @@ -1038,7 +1041,10 @@ pub struct SignInWithSingleRoleStrategy { } impl SignInWithSingleRoleStrategy { - async fn get_signin_response(self, state: &AppState) -> UserResult { + async fn get_signin_response( + self, + state: &SessionState, + ) -> UserResult { let token = utils::user::generate_jwt_auth_token(state, &self.user, &self.user_role).await?; utils::user_role::set_role_permissions_in_cache_by_user_role(state, &self.user_role).await; @@ -1058,7 +1064,10 @@ pub struct SignInWithMultipleRolesStrategy { } impl SignInWithMultipleRolesStrategy { - async fn get_signin_response(self, state: &AppState) -> UserResult { + async fn get_signin_response( + self, + state: &SessionState, + ) -> UserResult { let merchant_accounts = state .store .list_multiple_merchant_accounts( diff --git a/crates/router/src/types/domain/user/decision_manager.rs b/crates/router/src/types/domain/user/decision_manager.rs index 5a0388c7f36f..41ae12350fb3 100644 --- a/crates/router/src/types/domain/user/decision_manager.rs +++ b/crates/router/src/types/domain/user/decision_manager.rs @@ -5,7 +5,7 @@ use masking::Secret; use super::UserFromStorage; use crate::{ core::errors::{StorageErrorExt, UserErrors, UserResult}, - routes::AppState, + routes::SessionState, services::authentication as auth, utils, }; @@ -17,7 +17,7 @@ pub enum UserFlow { } impl UserFlow { - async fn is_required(&self, user: &UserFromStorage, state: &AppState) -> UserResult { + async fn is_required(&self, user: &UserFromStorage, state: &SessionState) -> UserResult { match self { Self::SPTFlow(flow) => flow.is_required(user, state).await, Self::JWTFlow(flow) => flow.is_required(user, state).await, @@ -36,7 +36,7 @@ pub enum SPTFlow { } impl SPTFlow { - async fn is_required(&self, user: &UserFromStorage, state: &AppState) -> UserResult { + async fn is_required(&self, user: &UserFromStorage, state: &SessionState) -> UserResult { match self { // TOTP Self::TOTP => Ok(true), @@ -54,7 +54,7 @@ impl SPTFlow { pub async fn generate_spt( self, - state: &AppState, + state: &SessionState, next_flow: &NextFlow, ) -> UserResult> { auth::SinglePurposeToken::new_token( @@ -74,13 +74,17 @@ pub enum JWTFlow { } impl JWTFlow { - async fn is_required(&self, _user: &UserFromStorage, _state: &AppState) -> UserResult { + async fn is_required( + &self, + _user: &UserFromStorage, + _state: &SessionState, + ) -> UserResult { Ok(true) } pub async fn generate_jwt( self, - state: &AppState, + state: &SessionState, next_flow: &NextFlow, user_role: &UserRole, ) -> UserResult> { @@ -183,7 +187,7 @@ impl CurrentFlow { }) } - pub async fn next(&self, user: UserFromStorage, state: &AppState) -> UserResult { + pub async fn next(&self, user: UserFromStorage, state: &SessionState) -> UserResult { let flows = self.origin.get_flows(); let remaining_flows = flows.iter().skip(self.current_flow_index + 1); for flow in remaining_flows { @@ -209,7 +213,7 @@ impl NextFlow { pub async fn from_origin( origin: Origin, user: UserFromStorage, - state: &AppState, + state: &SessionState, ) -> UserResult { let flows = origin.get_flows(); for flow in flows { @@ -228,7 +232,7 @@ impl NextFlow { self.next_flow } - pub async fn get_token(&self, state: &AppState) -> UserResult> { + pub async fn get_token(&self, state: &SessionState) -> UserResult> { match self.next_flow { UserFlow::SPTFlow(spt_flow) => spt_flow.generate_spt(state, self).await, UserFlow::JWTFlow(jwt_flow) => { @@ -251,7 +255,7 @@ impl NextFlow { pub async fn get_token_with_user_role( &self, - state: &AppState, + state: &SessionState, user_role: &UserRole, ) -> UserResult> { match self.next_flow { diff --git a/crates/router/src/types/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index 4ad45f554ce7..1cba84ad9f03 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -124,8 +124,11 @@ mod tests { ..PaymentAttemptNew::default() }; - let response = state - .store + let store = state + .stores + .get(state.conf.multitenancy.get_tenant_names().first().unwrap()) + .unwrap(); + let response = store .insert_payment_attempt(payment_attempt, enums::MerchantStorageScheme::PostgresOnly) .await .unwrap(); @@ -165,14 +168,16 @@ mod tests { attempt_id: attempt_id.clone(), ..PaymentAttemptNew::default() }; - state - .store + let store = state + .stores + .get(state.conf.multitenancy.get_tenant_names().first().unwrap()) + .unwrap(); + store .insert_payment_attempt(payment_attempt, enums::MerchantStorageScheme::PostgresOnly) .await .unwrap(); - let response = state - .store + let response = store .find_payment_attempt_by_payment_id_merchant_id_attempt_id( &payment_id, &merchant_id, @@ -218,14 +223,16 @@ mod tests { attempt_id: uuid.clone(), ..PaymentAttemptNew::default() }; - state - .store + let store = state + .stores + .get(state.conf.multitenancy.get_tenant_names().first().unwrap()) + .unwrap(); + store .insert_payment_attempt(payment_attempt, enums::MerchantStorageScheme::PostgresOnly) .await .unwrap(); - let response = state - .store + let response = store .find_payment_attempt_by_payment_id_merchant_id_attempt_id( &uuid, "1", diff --git a/crates/router/src/utils.rs b/crates/router/src/utils.rs index da6cac195ca2..b83d3138b7ce 100644 --- a/crates/router/src/utils.rs +++ b/crates/router/src/utils.rs @@ -826,7 +826,7 @@ pub async fn trigger_payments_webhook( key_store: &domain::MerchantKeyStore, payment_data: crate::core::payments::PaymentData, customer: Option, - state: &crate::routes::AppState, + state: &crate::routes::SessionState, operation: Op, ) -> RouterResult<()> where @@ -858,7 +858,7 @@ where captures, customer, services::AuthFlow::Merchant, - &state.conf.server, + &state.base_url, &operation, &state.conf.connector_request_reference_id_config, None, diff --git a/crates/router/src/utils/connector_onboarding.rs b/crates/router/src/utils/connector_onboarding.rs index aeea146df292..15ad2eb89540 100644 --- a/crates/router/src/utils/connector_onboarding.rs +++ b/crates/router/src/utils/connector_onboarding.rs @@ -5,7 +5,7 @@ use super::errors::StorageErrorExt; use crate::{ consts, core::errors::{ApiErrorResponse, NotImplementedMessage, RouterResult}, - routes::{app::settings, AppState}, + routes::{app::settings, SessionState}, types::{self, api::enums}, }; @@ -41,7 +41,7 @@ pub fn is_enabled( } pub async fn check_if_connector_exists( - state: &AppState, + state: &SessionState, connector_id: &str, merchant_id: &str, ) -> RouterResult<()> { @@ -70,7 +70,7 @@ pub async fn check_if_connector_exists( } pub async fn set_tracking_id_in_configs( - state: &AppState, + state: &SessionState, connector_id: &str, connector: enums::Connector, ) -> RouterResult<()> { @@ -115,7 +115,7 @@ pub async fn set_tracking_id_in_configs( } pub async fn get_tracking_id_from_configs( - state: &AppState, + state: &SessionState, connector_id: &str, connector: enums::Connector, ) -> RouterResult { diff --git a/crates/router/src/utils/connector_onboarding/paypal.rs b/crates/router/src/utils/connector_onboarding/paypal.rs index 708763a44409..9827a4b09375 100644 --- a/crates/router/src/utils/connector_onboarding/paypal.rs +++ b/crates/router/src/utils/connector_onboarding/paypal.rs @@ -5,7 +5,7 @@ use http::header; use crate::{ connector, core::errors::{ApiErrorResponse, RouterResult}, - routes::AppState, + routes::SessionState, types, types::api::{ enums, @@ -14,7 +14,7 @@ use crate::{ utils::verify_connector as verify_connector_utils, }; -pub async fn generate_access_token(state: AppState) -> RouterResult { +pub async fn generate_access_token(state: SessionState) -> RouterResult { let connector = enums::Connector::Paypal; let boxed_connector = types::api::ConnectorData::convert_connector( &state.conf.connectors, diff --git a/crates/router/src/utils/currency.rs b/crates/router/src/utils/currency.rs index 5cf68635c4e1..c16b46e51870 100644 --- a/crates/router/src/utils/currency.rs +++ b/crates/router/src/utils/currency.rs @@ -14,7 +14,7 @@ use tokio::{sync::RwLock, time::sleep}; use crate::{ logger, routes::app::settings::{Conversion, DefaultExchangeRates}, - services, AppState, + services, SessionState, }; const REDIX_FOREX_CACHE_KEY: &str = "{forex_cache}_lock"; const REDIX_FOREX_CACHE_DATA: &str = "{forex_cache}_data"; @@ -121,7 +121,7 @@ async fn save_forex_to_local( // Alternative handler for handling the case, When no data in local as well as redis #[allow(dead_code)] async fn waited_fetch_and_update_caches( - state: &AppState, + state: &SessionState, local_fetch_retry_delay: u64, local_fetch_retry_count: u64, ) -> CustomResult { @@ -171,7 +171,7 @@ impl From for CurrencyFactors { } } pub async fn get_forex_rates( - state: &AppState, + state: &SessionState, call_delay: i64, local_fetch_retry_delay: u64, local_fetch_retry_count: u64, @@ -197,7 +197,7 @@ pub async fn get_forex_rates( } async fn handler_local_no_data( - state: &AppState, + state: &SessionState, call_delay: i64, _local_fetch_retry_delay: u64, _local_fetch_retry_count: u64, @@ -216,7 +216,7 @@ async fn handler_local_no_data( } async fn successive_fetch_and_save_forex( - state: &AppState, + state: &SessionState, stale_redis_data: Option, ) -> CustomResult { match acquire_redis_lock(state).await { @@ -249,7 +249,7 @@ async fn successive_fetch_and_save_forex( } async fn successive_save_data_to_redis_local( - state: &AppState, + state: &SessionState, forex: FxExchangeRatesCacheEntry, ) -> CustomResult { Ok(save_forex_to_redis(state, &forex) @@ -268,7 +268,7 @@ async fn successive_save_data_to_redis_local( } async fn fallback_forex_redis_check( - state: &AppState, + state: &SessionState, redis_data: FxExchangeRatesCacheEntry, call_delay: i64, ) -> CustomResult { @@ -287,7 +287,7 @@ async fn fallback_forex_redis_check( } async fn handler_local_expired( - state: &AppState, + state: &SessionState, call_delay: i64, local_rates: FxExchangeRatesCacheEntry, ) -> CustomResult { @@ -316,7 +316,7 @@ async fn handler_local_expired( } async fn fetch_forex_rates( - state: &AppState, + state: &SessionState, ) -> Result> { let forex_api_key = state.conf.forex_api.get_inner().api_key.peek(); @@ -371,7 +371,7 @@ async fn fetch_forex_rates( } pub async fn fallback_fetch_forex_rates( - state: &AppState, + state: &SessionState, ) -> CustomResult { let fallback_forex_api_key = state.conf.forex_api.get_inner().fallback_api_key.peek(); @@ -438,7 +438,7 @@ pub async fn fallback_fetch_forex_rates( } async fn release_redis_lock( - state: &AppState, + state: &SessionState, ) -> Result> { state .store @@ -449,9 +449,9 @@ async fn release_redis_lock( .change_context(ForexCacheError::RedisLockReleaseFailed) } -async fn acquire_redis_lock(app_state: &AppState) -> CustomResult { - let forex_api = app_state.conf.forex_api.get_inner(); - app_state +async fn acquire_redis_lock(state: &SessionState) -> CustomResult { + let forex_api = state.conf.forex_api.get_inner(); + state .store .get_redis_conn() .change_context(ForexCacheError::RedisConnectionError)? @@ -472,7 +472,7 @@ async fn acquire_redis_lock(app_state: &AppState) -> CustomResult CustomResult<(), ForexCacheError> { app_state @@ -485,7 +485,7 @@ async fn save_forex_to_redis( } async fn retrieve_forex_from_redis( - app_state: &AppState, + app_state: &SessionState, ) -> CustomResult, ForexCacheError> { app_state .store @@ -510,7 +510,7 @@ async fn is_redis_expired( } pub async fn convert_currency( - state: AppState, + state: SessionState, amount: i64, to_currency: String, from_currency: String, diff --git a/crates/router/src/utils/user.rs b/crates/router/src/utils/user.rs index db1d0ea25088..eaa386d7f6cc 100644 --- a/crates/router/src/utils/user.rs +++ b/crates/router/src/utils/user.rs @@ -8,7 +8,7 @@ use redis_interface::RedisConnectionPool; use crate::{ core::errors::{StorageError, UserErrors, UserResult}, - routes::AppState, + routes::SessionState, services::{ authentication::{AuthToken, UserFromToken}, authorization::roles::RoleInfo, @@ -25,7 +25,7 @@ pub mod two_factor_auth; impl UserFromToken { pub async fn get_merchant_account_from_db( &self, - state: AppState, + state: SessionState, ) -> UserResult { let key_store = state .store @@ -55,7 +55,7 @@ impl UserFromToken { Ok(merchant_account) } - pub async fn get_user_from_db(&self, state: &AppState) -> UserResult { + pub async fn get_user_from_db(&self, state: &SessionState) -> UserResult { let user = state .store .find_user_by_id(&self.user_id) @@ -64,7 +64,7 @@ impl UserFromToken { Ok(user.into()) } - pub async fn get_role_info_from_db(&self, state: &AppState) -> UserResult { + pub async fn get_role_info_from_db(&self, state: &SessionState) -> UserResult { RoleInfo::from_role_id(state, &self.role_id, &self.merchant_id, &self.org_id) .await .change_context(UserErrors::InternalServerError) @@ -72,7 +72,7 @@ impl UserFromToken { } pub async fn generate_jwt_auth_token( - state: &AppState, + state: &SessionState, user: &UserFromStorage, user_role: &UserRole, ) -> UserResult> { @@ -88,7 +88,7 @@ pub async fn generate_jwt_auth_token( } pub async fn generate_jwt_auth_token_with_custom_role_attributes( - state: &AppState, + state: &SessionState, user: &UserFromStorage, merchant_id: String, org_id: String, @@ -106,7 +106,7 @@ pub async fn generate_jwt_auth_token_with_custom_role_attributes( } pub fn get_dashboard_entry_response( - state: &AppState, + state: &SessionState, user: UserFromStorage, user_role: UserRole, token: masking::Secret, @@ -126,7 +126,7 @@ pub fn get_dashboard_entry_response( #[allow(unused_variables)] pub fn get_verification_days_left( - state: &AppState, + state: &SessionState, user: &UserFromStorage, ) -> UserResult> { #[cfg(feature = "email")] @@ -176,7 +176,7 @@ pub fn get_multiple_merchant_details_with_status( } pub async fn get_user_from_db_by_email( - state: &AppState, + state: &SessionState, email: domain::UserEmail, ) -> CustomResult { state @@ -193,7 +193,7 @@ pub fn get_token_from_signin_response(resp: &user_api::SignInResponse) -> maskin } } -pub fn get_redis_connection(state: &AppState) -> UserResult> { +pub fn get_redis_connection(state: &SessionState) -> UserResult> { state .store .get_redis_conn() diff --git a/crates/router/src/utils/user/dashboard_metadata.rs b/crates/router/src/utils/user/dashboard_metadata.rs index 3979a8649447..5622a43f4dcf 100644 --- a/crates/router/src/utils/user/dashboard_metadata.rs +++ b/crates/router/src/utils/user/dashboard_metadata.rs @@ -13,11 +13,11 @@ use masking::Secret; use crate::{ core::errors::{UserErrors, UserResult}, - headers, AppState, + headers, SessionState, }; pub async fn insert_merchant_scoped_metadata_to_db( - state: &AppState, + state: &SessionState, user_id: String, merchant_id: String, org_id: String, @@ -50,7 +50,7 @@ pub async fn insert_merchant_scoped_metadata_to_db( }) } pub async fn insert_user_scoped_metadata_to_db( - state: &AppState, + state: &SessionState, user_id: String, merchant_id: String, org_id: String, @@ -84,7 +84,7 @@ pub async fn insert_user_scoped_metadata_to_db( } pub async fn get_merchant_scoped_metadata_from_db( - state: &AppState, + state: &SessionState, merchant_id: String, org_id: String, metadata_keys: Vec, @@ -97,7 +97,7 @@ pub async fn get_merchant_scoped_metadata_from_db( .attach_printable("DB Error Fetching DashboardMetaData") } pub async fn get_user_scoped_metadata_from_db( - state: &AppState, + state: &SessionState, user_id: String, merchant_id: String, org_id: String, @@ -121,7 +121,7 @@ pub async fn get_user_scoped_metadata_from_db( } pub async fn update_merchant_scoped_metadata( - state: &AppState, + state: &SessionState, user_id: String, merchant_id: String, org_id: String, @@ -149,7 +149,7 @@ pub async fn update_merchant_scoped_metadata( .change_context(UserErrors::InternalServerError) } pub async fn update_user_scoped_metadata( - state: &AppState, + state: &SessionState, user_id: String, merchant_id: String, org_id: String, diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs index ea690af35aeb..9be2ddb57a4e 100644 --- a/crates/router/src/utils/user/sample_data.rs +++ b/crates/router/src/utils/user/sample_data.rs @@ -12,12 +12,12 @@ use time::OffsetDateTime; use crate::{ consts, core::errors::sample_data::{SampleDataError, SampleDataResult}, - AppState, + SessionState, }; #[allow(clippy::type_complexity)] pub async fn generate_sample_data( - state: &AppState, + state: &SessionState, req: SampleDataRequest, merchant_id: &str, ) -> SampleDataResult)>> { diff --git a/crates/router/src/utils/user/two_factor_auth.rs b/crates/router/src/utils/user/two_factor_auth.rs index 6bd693c07f5c..a0915f3ed86e 100644 --- a/crates/router/src/utils/user/two_factor_auth.rs +++ b/crates/router/src/utils/user/two_factor_auth.rs @@ -6,7 +6,7 @@ use totp_rs::{Algorithm, TOTP}; use crate::{ consts, core::errors::{UserErrors, UserResult}, - routes::AppState, + routes::SessionState, }; pub fn generate_default_totp( @@ -31,7 +31,7 @@ pub fn generate_default_totp( .change_context(UserErrors::InternalServerError) } -pub async fn check_totp_in_redis(state: &AppState, user_id: &str) -> UserResult { +pub async fn check_totp_in_redis(state: &SessionState, user_id: &str) -> UserResult { let redis_conn = super::get_redis_connection(state)?; let key = format!("{}{}", consts::user::REDIS_TOTP_PREFIX, user_id); redis_conn @@ -40,7 +40,7 @@ pub async fn check_totp_in_redis(state: &AppState, user_id: &str) -> UserResult< .change_context(UserErrors::InternalServerError) } -pub async fn check_recovery_code_in_redis(state: &AppState, user_id: &str) -> UserResult { +pub async fn check_recovery_code_in_redis(state: &SessionState, user_id: &str) -> UserResult { let redis_conn = super::get_redis_connection(state)?; let key = format!("{}{}", consts::user::REDIS_RECOVERY_CODE_PREFIX, user_id); redis_conn @@ -49,7 +49,7 @@ pub async fn check_recovery_code_in_redis(state: &AppState, user_id: &str) -> Us .change_context(UserErrors::InternalServerError) } -pub async fn insert_totp_in_redis(state: &AppState, user_id: &str) -> UserResult<()> { +pub async fn insert_totp_in_redis(state: &SessionState, user_id: &str) -> UserResult<()> { let redis_conn = super::get_redis_connection(state)?; let key = format!("{}{}", consts::user::REDIS_TOTP_PREFIX, user_id); redis_conn @@ -63,7 +63,7 @@ pub async fn insert_totp_in_redis(state: &AppState, user_id: &str) -> UserResult } pub async fn insert_totp_secret_in_redis( - state: &AppState, + state: &SessionState, user_id: &str, secret: &masking::Secret, ) -> UserResult<()> { @@ -79,7 +79,7 @@ pub async fn insert_totp_secret_in_redis( } pub async fn get_totp_secret_from_redis( - state: &AppState, + state: &SessionState, user_id: &str, ) -> UserResult>> { let redis_conn = super::get_redis_connection(state)?; @@ -90,7 +90,7 @@ pub async fn get_totp_secret_from_redis( .map(|secret| secret.map(Into::into)) } -pub async fn delete_totp_secret_from_redis(state: &AppState, user_id: &str) -> UserResult<()> { +pub async fn delete_totp_secret_from_redis(state: &SessionState, user_id: &str) -> UserResult<()> { let redis_conn = super::get_redis_connection(state)?; redis_conn .delete_key(&get_totp_secret_key(user_id)) @@ -103,7 +103,7 @@ fn get_totp_secret_key(user_id: &str) -> String { format!("{}{}", consts::user::REDIS_TOTP_SECRET_PREFIX, user_id) } -pub async fn insert_recovery_code_in_redis(state: &AppState, user_id: &str) -> UserResult<()> { +pub async fn insert_recovery_code_in_redis(state: &SessionState, user_id: &str) -> UserResult<()> { let redis_conn = super::get_redis_connection(state)?; let key = format!("{}{}", consts::user::REDIS_RECOVERY_CODE_PREFIX, user_id); redis_conn diff --git a/crates/router/src/utils/user_role.rs b/crates/router/src/utils/user_role.rs index ba4c28786670..d0ad08848ca2 100644 --- a/crates/router/src/utils/user_role.rs +++ b/crates/router/src/utils/user_role.rs @@ -9,7 +9,7 @@ use router_env::logger; use crate::{ consts, core::errors::{StorageErrorExt, UserErrors, UserResult}, - routes::AppState, + routes::SessionState, services::authorization::{self as authz, permissions::Permission, roles}, types::domain, }; @@ -73,7 +73,7 @@ pub fn validate_role_groups(groups: &[PermissionGroup]) -> UserResult<()> { } pub async fn validate_role_name( - state: &AppState, + state: &SessionState, role_name: &domain::RoleName, merchant_id: &str, org_id: &str, @@ -101,7 +101,7 @@ pub async fn validate_role_name( } pub async fn set_role_permissions_in_cache_by_user_role( - state: &AppState, + state: &SessionState, user_role: &UserRole, ) -> bool { set_role_permissions_in_cache_if_required( @@ -116,7 +116,7 @@ pub async fn set_role_permissions_in_cache_by_user_role( } pub async fn set_role_permissions_in_cache_if_required( - state: &AppState, + state: &SessionState, role_id: &str, merchant_id: &str, org_id: &str, @@ -143,7 +143,7 @@ pub async fn set_role_permissions_in_cache_if_required( } pub async fn get_multiple_role_info_for_user_roles( - state: &AppState, + state: &SessionState, user_roles: &[UserRole], ) -> UserResult> { futures::future::try_join_all(user_roles.iter().map(|user_role| async { diff --git a/crates/router/src/workflows/api_key_expiry.rs b/crates/router/src/workflows/api_key_expiry.rs index c5914810108c..dff7905a2624 100644 --- a/crates/router/src/workflows/api_key_expiry.rs +++ b/crates/router/src/workflows/api_key_expiry.rs @@ -1,12 +1,12 @@ use common_utils::{errors::ValidationError, ext_traits::ValueExt}; use diesel_models::{enums as storage_enums, ApiKeyExpiryTrackingData}; use router_env::logger; -use scheduler::{workflows::ProcessTrackerWorkflow, SchedulerAppState}; +use scheduler::{workflows::ProcessTrackerWorkflow, SchedulerSessionState}; use crate::{ errors, logger::error, - routes::{metrics, AppState}, + routes::{metrics, SessionState}, services::email::types::ApiKeyExpiryReminder, types::{api, domain::UserEmail, storage}, utils::OptionExt, @@ -15,10 +15,10 @@ use crate::{ pub struct ApiKeyExpiryWorkflow; #[async_trait::async_trait] -impl ProcessTrackerWorkflow for ApiKeyExpiryWorkflow { +impl ProcessTrackerWorkflow for ApiKeyExpiryWorkflow { async fn execute_workflow<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, process: storage::ProcessTracker, ) -> Result<(), errors::ProcessTrackerError> { let db = &*state.store; @@ -137,7 +137,7 @@ impl ProcessTrackerWorkflow for ApiKeyExpiryWorkflow { async fn error_handler<'a>( &'a self, - _state: &'a AppState, + _state: &'a SessionState, process: storage::ProcessTracker, _error: errors::ProcessTrackerError, ) -> errors::CustomResult<(), errors::ProcessTrackerError> { diff --git a/crates/router/src/workflows/attach_payout_account_workflow.rs b/crates/router/src/workflows/attach_payout_account_workflow.rs index 98d3f7844b4e..eb60510ad754 100644 --- a/crates/router/src/workflows/attach_payout_account_workflow.rs +++ b/crates/router/src/workflows/attach_payout_account_workflow.rs @@ -7,17 +7,17 @@ use scheduler::{ use crate::{ core::payouts, errors as core_errors, - routes::AppState, + routes::SessionState, types::{api, storage}, }; pub struct AttachPayoutAccountWorkflow; #[async_trait::async_trait] -impl ProcessTrackerWorkflow for AttachPayoutAccountWorkflow { +impl ProcessTrackerWorkflow for AttachPayoutAccountWorkflow { async fn execute_workflow<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, process: storage::ProcessTracker, ) -> Result<(), errors::ProcessTrackerError> { // Gather context @@ -63,7 +63,7 @@ impl ProcessTrackerWorkflow for AttachPayoutAccountWorkflow { async fn error_handler<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, process: storage::ProcessTracker, error: errors::ProcessTrackerError, ) -> core_errors::CustomResult<(), errors::ProcessTrackerError> { diff --git a/crates/router/src/workflows/outgoing_webhook_retry.rs b/crates/router/src/workflows/outgoing_webhook_retry.rs index 63bdb7ec9894..53b275dfebce 100644 --- a/crates/router/src/workflows/outgoing_webhook_retry.rs +++ b/crates/router/src/workflows/outgoing_webhook_retry.rs @@ -17,18 +17,18 @@ use crate::{ core::webhooks::{self as webhooks_core, types::OutgoingWebhookTrackingData}, db::StorageInterface, errors, logger, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, types::{domain, storage}, }; pub struct OutgoingWebhookRetryWorkflow; #[async_trait::async_trait] -impl ProcessTrackerWorkflow for OutgoingWebhookRetryWorkflow { +impl ProcessTrackerWorkflow for OutgoingWebhookRetryWorkflow { #[instrument(skip_all)] async fn execute_workflow<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, process: storage::ProcessTracker, ) -> Result<(), errors::ProcessTrackerError> { let delivery_attempt = storage::enums::WebhookDeliveryAttempt::AutomaticRetry; @@ -207,7 +207,7 @@ impl ProcessTrackerWorkflow for OutgoingWebhookRetryWorkflow { #[instrument(skip_all)] async fn error_handler<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, process: storage::ProcessTracker, error: errors::ProcessTrackerError, ) -> errors::CustomResult<(), errors::ProcessTrackerError> { @@ -313,7 +313,7 @@ pub(crate) async fn retry_webhook_delivery_task( #[instrument(skip_all)] async fn get_outgoing_webhook_content_and_event_type( - state: AppState, + state: SessionState, req_state: ReqState, merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, diff --git a/crates/router/src/workflows/payment_sync.rs b/crates/router/src/workflows/payment_sync.rs index 14f372789ed3..c34b8ebe73ba 100644 --- a/crates/router/src/workflows/payment_sync.rs +++ b/crates/router/src/workflows/payment_sync.rs @@ -3,7 +3,7 @@ use error_stack::ResultExt; use router_env::logger; use scheduler::{ consumer::{self, types::process_data, workflows::ProcessTrackerWorkflow}, - errors as sch_errors, utils as scheduler_utils, SchedulerAppState, + errors as sch_errors, utils as scheduler_utils, }; use crate::{ @@ -14,7 +14,7 @@ use crate::{ }, db::StorageInterface, errors, - routes::AppState, + routes::SessionState, services, types::{ api, @@ -26,10 +26,10 @@ use crate::{ pub struct PaymentsSyncWorkflow; #[async_trait::async_trait] -impl ProcessTrackerWorkflow for PaymentsSyncWorkflow { +impl ProcessTrackerWorkflow for PaymentsSyncWorkflow { async fn execute_workflow<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, process: storage::ProcessTracker, ) -> Result<(), sch_errors::ProcessTrackerError> { let db: &dyn StorageInterface = &*state.store; @@ -87,7 +87,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow { match &payment_data.payment_attempt.status { status if terminal_status.contains(status) => { state - .get_db() + .store .as_scheduler() .finish_process_with_business_status(process, "COMPLETED_BY_PT".to_string()) .await? @@ -192,7 +192,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow { async fn error_handler<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, process: storage::ProcessTracker, error: sch_errors::ProcessTrackerError, ) -> errors::CustomResult<(), sch_errors::ProcessTrackerError> { diff --git a/crates/router/src/workflows/refund_router.rs b/crates/router/src/workflows/refund_router.rs index 934c208f9115..515e34c06897 100644 --- a/crates/router/src/workflows/refund_router.rs +++ b/crates/router/src/workflows/refund_router.rs @@ -1,16 +1,16 @@ use scheduler::consumer::workflows::ProcessTrackerWorkflow; use crate::{ - core::refunds as refund_flow, errors, logger::error, routes::AppState, types::storage, + core::refunds as refund_flow, errors, logger::error, routes::SessionState, types::storage, }; pub struct RefundWorkflowRouter; #[async_trait::async_trait] -impl ProcessTrackerWorkflow for RefundWorkflowRouter { +impl ProcessTrackerWorkflow for RefundWorkflowRouter { async fn execute_workflow<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, process: storage::ProcessTracker, ) -> Result<(), errors::ProcessTrackerError> { Ok(Box::pin(refund_flow::start_refund_workflow(state, &process)).await?) @@ -18,7 +18,7 @@ impl ProcessTrackerWorkflow for RefundWorkflowRouter { async fn error_handler<'a>( &'a self, - _state: &'a AppState, + _state: &'a SessionState, process: storage::ProcessTracker, _error: errors::ProcessTrackerError, ) -> errors::CustomResult<(), errors::ProcessTrackerError> { diff --git a/crates/router/src/workflows/tokenized_data.rs b/crates/router/src/workflows/tokenized_data.rs index 0674982f92fe..bc1842205ae4 100644 --- a/crates/router/src/workflows/tokenized_data.rs +++ b/crates/router/src/workflows/tokenized_data.rs @@ -1,16 +1,16 @@ use scheduler::consumer::workflows::ProcessTrackerWorkflow; use crate::{ - core::payment_methods::vault, errors, logger::error, routes::AppState, types::storage, + core::payment_methods::vault, errors, logger::error, routes::SessionState, types::storage, }; pub struct DeleteTokenizeDataWorkflow; #[async_trait::async_trait] -impl ProcessTrackerWorkflow for DeleteTokenizeDataWorkflow { +impl ProcessTrackerWorkflow for DeleteTokenizeDataWorkflow { async fn execute_workflow<'a>( &'a self, - state: &'a AppState, + state: &'a SessionState, process: storage::ProcessTracker, ) -> Result<(), errors::ProcessTrackerError> { Ok(vault::start_tokenize_data_workflow(state, &process).await?) @@ -18,7 +18,7 @@ impl ProcessTrackerWorkflow for DeleteTokenizeDataWorkflow { async fn error_handler<'a>( &'a self, - _state: &'a AppState, + _state: &'a SessionState, process: storage::ProcessTracker, _error: errors::ProcessTrackerError, ) -> errors::CustomResult<(), errors::ProcessTrackerError> { diff --git a/crates/router/tests/cache.rs b/crates/router/tests/cache.rs index c6eef06db7b1..f0c79e4dcbc0 100644 --- a/crates/router/tests/cache.rs +++ b/crates/router/tests/cache.rs @@ -1,6 +1,8 @@ #![allow(clippy::unwrap_used)] +use std::sync::Arc; + use router::{configs::settings::Settings, routes, services}; -use storage_impl::redis::cache; +use storage_impl::redis::cache::{self, CacheKey}; mod utils; @@ -9,13 +11,15 @@ async fn invalidate_existing_cache_success() { // Arrange Box::pin(utils::setup()).await; let (tx, _) = tokio::sync::oneshot::channel(); - let state = Box::pin(routes::AppState::new( + let app_state = Box::pin(routes::AppState::new( Settings::default(), tx, Box::new(services::MockApiClient), )) .await; - + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); let cache_key = "cacheKey".to_string(); let cache_key_value = "val".to_string(); let _ = state @@ -29,11 +33,23 @@ async fn invalidate_existing_cache_success() { let client = awc::Client::default(); cache::CONFIG_CACHE - .push(cache_key.clone(), cache_key_value.clone()) + .push( + CacheKey { + key: cache_key.clone(), + prefix: String::default(), + }, + cache_key_value.clone(), + ) .await; cache::ACCOUNTS_CACHE - .push(cache_key.clone(), cache_key_value.clone()) + .push( + CacheKey { + key: cache_key.clone(), + prefix: String::default(), + }, + cache_key_value.clone(), + ) .await; // Act @@ -51,11 +67,17 @@ async fn invalidate_existing_cache_success() { println!("invalidate Cache: {response:?} : {response_body:?}"); assert_eq!(response.status(), awc::http::StatusCode::OK); assert!(cache::CONFIG_CACHE - .get_val::(&cache_key) + .get_val::(CacheKey { + key: cache_key.clone(), + prefix: String::default() + }) .await .is_none()); assert!(cache::ACCOUNTS_CACHE - .get_val::(&cache_key) + .get_val::(CacheKey { + key: cache_key, + prefix: String::default() + }) .await .is_none()); } diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs index 414ab8cd1d5f..10e8b3665303 100644 --- a/crates/router/tests/connectors/aci.rs +++ b/crates/router/tests/connectors/aci.rs @@ -1,4 +1,4 @@ -use std::{marker::PhantomData, str::FromStr}; +use std::{marker::PhantomData, str::FromStr, sync::Arc}; use api_models::payments::{Address, AddressDetails, PhoneDetails}; use common_utils::id_type; @@ -191,13 +191,16 @@ async fn payments_create_success() { let conf = Settings::new().unwrap(); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( conf, StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); static CV: aci::Aci = aci::Aci; let connector = types::api::ConnectorData { @@ -236,13 +239,16 @@ async fn payments_create_failure() { static CV: aci::Aci = aci::Aci; let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( conf, StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); let connector = types::api::ConnectorData { connector: Box::new(&CV), connector_name: types::Connector::Aci, @@ -297,13 +303,16 @@ async fn refund_for_successful_payments() { }; let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( conf, StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); let connector_integration: services::BoxedConnectorIntegration< '_, types::api::Authorize, @@ -366,13 +375,16 @@ async fn refunds_create_failure() { }; let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( conf, StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); let connector_integration: services::BoxedConnectorIntegration< '_, types::api::Execute, diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index b7be24f2a158..0de19f17b54a 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -1,4 +1,4 @@ -use std::{fmt::Debug, marker::PhantomData, str::FromStr, time::Duration}; +use std::{fmt::Debug, marker::PhantomData, str::FromStr, sync::Arc, time::Duration}; use async_trait::async_trait; use common_utils::pii::Email; @@ -95,13 +95,16 @@ pub trait ConnectorActions: Connector { payment_info, ); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( Settings::new().unwrap(), StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); integration.execute_pretasks(&mut request, &state).await?; Box::pin(call_connector(request, integration)).await } @@ -120,13 +123,16 @@ pub trait ConnectorActions: Connector { ); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( Settings::new().unwrap(), StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); integration.execute_pretasks(&mut request, &state).await?; Box::pin(call_connector(request, integration)).await } @@ -145,13 +151,16 @@ pub trait ConnectorActions: Connector { ); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( Settings::new().unwrap(), StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); integration.execute_pretasks(&mut request, &state).await?; Box::pin(call_connector(request, integration)).await } @@ -174,13 +183,16 @@ pub trait ConnectorActions: Connector { ); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( Settings::new().unwrap(), StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); integration.execute_pretasks(&mut request, &state).await?; Box::pin(call_connector(request, integration)).await } @@ -598,13 +610,16 @@ pub trait ConnectorActions: Connector { let mut request = self.get_payout_request(None, payout_type, payment_info); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( Settings::new().unwrap(), StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); connector_integration .execute_pretasks(&mut request, &state) .await?; @@ -639,13 +654,16 @@ pub trait ConnectorActions: Connector { let mut request = self.get_payout_request(connector_payout_id, payout_type, payment_info); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( Settings::new().unwrap(), StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); connector_integration .execute_pretasks(&mut request, &state) .await?; @@ -681,13 +699,16 @@ pub trait ConnectorActions: Connector { request.connector_customer = connector_customer; let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( Settings::new().unwrap(), StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); connector_integration .execute_pretasks(&mut request, &state) .await?; @@ -723,13 +744,16 @@ pub trait ConnectorActions: Connector { self.get_payout_request(Some(connector_payout_id), payout_type, payment_info); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( Settings::new().unwrap(), StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); connector_integration .execute_pretasks(&mut request, &state) .await?; @@ -811,13 +835,16 @@ pub trait ConnectorActions: Connector { let mut request = self.get_payout_request(None, payout_type, payment_info); let tx = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( Settings::new().unwrap(), StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); connector_integration .execute_pretasks(&mut request, &state) .await?; @@ -844,13 +871,16 @@ async fn call_connector< let conf = Settings::new().unwrap(); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( conf, StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); services::api::execute_connector_processing_step( &state, integration, diff --git a/crates/router/tests/payments.rs b/crates/router/tests/payments.rs index e76eee4c1792..ed11f3b8b1cb 100644 --- a/crates/router/tests/payments.rs +++ b/crates/router/tests/payments.rs @@ -2,6 +2,8 @@ mod utils; +use std::sync::Arc; + use common_utils::{id_type, types::MinorUnit}; use router::{ configs, @@ -276,13 +278,16 @@ async fn payments_create_core() { use configs::settings::Settings; let conf = Settings::new().expect("invalid settings"); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( conf, StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); let key_store = state .store @@ -457,13 +462,16 @@ async fn payments_create_core_adyen_no_redirect() { use crate::configs::settings::Settings; let conf = Settings::new().expect("invalid settings"); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( conf, StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); let customer_id = format!("cust_{}", Uuid::new_v4()); let merchant_id = "arunraj".to_string(); diff --git a/crates/router/tests/payments2.rs b/crates/router/tests/payments2.rs index 42cfe3b74c1d..4c178e4122bb 100644 --- a/crates/router/tests/payments2.rs +++ b/crates/router/tests/payments2.rs @@ -2,6 +2,8 @@ mod utils; +use std::sync::Arc; + use common_utils::{id_type, types::MinorUnit}; use router::{ core::payments, @@ -36,13 +38,16 @@ async fn payments_create_core() { use router::configs::settings::Settings; let conf = Settings::new().expect("invalid settings"); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( conf, StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); let key_store = state .store @@ -224,13 +229,16 @@ async fn payments_create_core_adyen_no_redirect() { let conf = Settings::new().expect("invalid settings"); let tx: oneshot::Sender<()> = oneshot::channel().0; - let state = Box::pin(routes::AppState::with_storage( + let app_state = Box::pin(routes::AppState::with_storage( conf, StorageImpl::PostgresqlTest, tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); let customer_id = format!("cust_{}", Uuid::new_v4()); let merchant_id = "arunraj".to_string(); diff --git a/crates/router/tests/services.rs b/crates/router/tests/services.rs index eff7fe7f8738..d907000cccd9 100644 --- a/crates/router/tests/services.rs +++ b/crates/router/tests/services.rs @@ -1,4 +1,4 @@ -use std::sync::atomic; +use std::sync::{atomic, Arc}; use router::{configs::settings::Settings, routes, services}; @@ -6,16 +6,20 @@ mod utils; #[tokio::test] #[should_panic] +#[allow(clippy::unwrap_used)] async fn get_redis_conn_failure() { // Arrange utils::setup().await; let (tx, _) = tokio::sync::oneshot::channel(); - let state = Box::pin(routes::AppState::new( + let app_state = Box::pin(routes::AppState::new( Settings::default(), tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); let _ = state.store.get_redis_conn().map(|conn| { conn.is_redis_available @@ -30,16 +34,20 @@ async fn get_redis_conn_failure() { } #[tokio::test] +#[allow(clippy::unwrap_used)] async fn get_redis_conn_success() { // Arrange Box::pin(utils::setup()).await; let (tx, _) = tokio::sync::oneshot::channel(); - let state = Box::pin(routes::AppState::new( + let app_state = Box::pin(routes::AppState::new( Settings::default(), tx, Box::new(services::MockApiClient), )) .await; + let state = Arc::new(app_state) + .get_session_state("public", || {}) + .unwrap(); // Act let result = state.store.get_redis_conn(); diff --git a/crates/scheduler/src/consumer.rs b/crates/scheduler/src/consumer.rs index a95ac4932471..3e15a7cde0fb 100644 --- a/crates/scheduler/src/consumer.rs +++ b/crates/scheduler/src/consumer.rs @@ -1,6 +1,9 @@ // TODO: Figure out what to log -use std::sync::{self, atomic}; +use std::{ + sync::{self, atomic}, + time as std_time, +}; pub mod types; pub mod workflows; @@ -22,7 +25,7 @@ use super::env::logger; pub use super::workflows::ProcessTrackerWorkflow; use crate::{ configs::settings::SchedulerSettings, db::process_tracker::ProcessTrackerInterface, errors, - metrics, utils as pt_utils, SchedulerAppState, SchedulerInterface, + metrics, utils as pt_utils, SchedulerAppState, SchedulerInterface, SchedulerSessionState, }; // Valid consumer business statuses @@ -31,12 +34,16 @@ pub fn valid_business_statuses() -> Vec<&'static str> { } #[instrument(skip_all)] -pub async fn start_consumer( +pub async fn start_consumer( state: &T, settings: sync::Arc, - workflow_selector: impl workflows::ProcessTrackerWorkflows + 'static + Copy + std::fmt::Debug, + workflow_selector: impl workflows::ProcessTrackerWorkflows + 'static + Copy + std::fmt::Debug, (tx, mut rx): (mpsc::Sender<()>, mpsc::Receiver<()>), -) -> CustomResult<(), errors::ProcessTrackerError> { + app_state_to_session_state: F, +) -> CustomResult<(), errors::ProcessTrackerError> +where + F: Fn(&T, &str) -> CustomResult, +{ use std::time::Duration; use rand::distributions::{Distribution, Uniform}; @@ -77,17 +84,29 @@ pub async fn start_consumer( if settings.consumer.disabled { continue; } + consumer_operation_counter.fetch_add(1, atomic::Ordering::SeqCst); + let start_time = std_time::Instant::now(); + let tenants = state.get_tenants(); + for tenant in tenants { + let session_state = app_state_to_session_state(state, tenant.as_str())?; + pt_utils::consumer_operation_handler( + session_state.clone(), + settings.clone(), + |error| { + logger::error!(?error, "Failed to perform consumer operation"); + }, + workflow_selector, + ) + .await; + } + + let end_time = std_time::Instant::now(); + let duration = end_time.saturating_duration_since(start_time).as_secs_f64(); + logger::debug!("Time taken to execute consumer_operation: {}s", duration); - pt_utils::consumer_operation_handler( - state.clone(), - settings.clone(), - |error| { - logger::error!(?error, "Failed to perform consumer operation"); - }, - sync::Arc::clone(&consumer_operation_counter), - workflow_selector, - ) - .await; + let current_count = + consumer_operation_counter.fetch_sub(1, atomic::Ordering::SeqCst); + logger::info!("Current tasks being executed: {}", current_count); } Ok(()) | Err(mpsc::error::TryRecvError::Disconnected) => { logger::debug!("Awaiting shutdown!"); @@ -116,7 +135,7 @@ pub async fn start_consumer( } #[instrument(skip_all)] -pub async fn consumer_operations( +pub async fn consumer_operations( state: &T, settings: &SchedulerSettings, workflow_selector: impl workflows::ProcessTrackerWorkflows + 'static + Copy + std::fmt::Debug, @@ -125,13 +144,10 @@ pub async fn consumer_operations( let group_name = settings.consumer.consumer_group.clone(); let consumer_name = format!("consumer_{}", Uuid::new_v4()); - let group_created = &mut state + let _group_created = &mut state .get_db() .consumer_group_create(&stream_name, &group_name, &RedisEntryId::AfterLastID) .await; - if group_created.is_err() { - logger::info!("Consumer group {group_name} already exists"); - } let mut tasks = state .get_db() @@ -139,7 +155,9 @@ pub async fn consumer_operations( .fetch_consumer_tasks(&stream_name, &group_name, &consumer_name) .await?; - logger::info!("{} picked {} tasks", consumer_name, tasks.len()); + if !tasks.is_empty() { + logger::info!("{} picked {} tasks", consumer_name, tasks.len()); + } let mut handler = vec![]; for task in tasks.iter_mut() { @@ -216,11 +234,10 @@ pub async fn start_workflow( workflow_selector: impl workflows::ProcessTrackerWorkflows + 'static + std::fmt::Debug, ) -> CustomResult<(), errors::ProcessTrackerError> where - T: SchedulerAppState, + T: SchedulerSessionState, { tracing::Span::current().record("workflow_id", Uuid::new_v4().to_string()); logger::info!(pt.name=?process.name, pt.id=%process.id); - let res = workflow_selector .trigger_workflow(&state.clone(), process.clone()) .await diff --git a/crates/scheduler/src/consumer/workflows.rs b/crates/scheduler/src/consumer/workflows.rs index 3e8a4c8e5028..bbece87f3094 100644 --- a/crates/scheduler/src/consumer/workflows.rs +++ b/crates/scheduler/src/consumer/workflows.rs @@ -3,7 +3,7 @@ use common_utils::errors::CustomResult; pub use diesel_models::process_tracker as storage; use router_env::logger; -use crate::{errors, SchedulerAppState}; +use crate::{errors, SchedulerSessionState}; pub type WorkflowSelectorFn = fn(&storage::ProcessTracker) -> Result<(), errors::ProcessTrackerError>; @@ -26,7 +26,7 @@ pub trait ProcessTrackerWorkflows: Send + Sync { process: storage::ProcessTracker, ) -> CustomResult<(), errors::ProcessTrackerError> where - T: SchedulerAppState, + T: SchedulerSessionState, { let app_state = &state.clone(); let output = operation.execute_workflow(app_state, process.clone()).await; diff --git a/crates/scheduler/src/errors.rs b/crates/scheduler/src/errors.rs index e630287c316a..52ea03e0c470 100644 --- a/crates/scheduler/src/errors.rs +++ b/crates/scheduler/src/errors.rs @@ -59,6 +59,8 @@ pub enum ProcessTrackerError { EEmailError(error_stack::Report), #[error("Type Conversion error")] TypeConversionError, + #[error("Tenant not found")] + TenantNotFound, } #[macro_export] diff --git a/crates/scheduler/src/producer.rs b/crates/scheduler/src/producer.rs index 397aab84e912..6390bc66897a 100644 --- a/crates/scheduler/src/producer.rs +++ b/crates/scheduler/src/producer.rs @@ -16,17 +16,20 @@ use super::{ }; use crate::{ configs::settings::SchedulerSettings, errors, flow::SchedulerFlow, - scheduler::SchedulerInterface, utils::*, SchedulerAppState, + scheduler::SchedulerInterface, utils::*, SchedulerAppState, SchedulerSessionState, }; #[instrument(skip_all)] -pub async fn start_producer( +pub async fn start_producer( state: &T, scheduler_settings: Arc, (tx, mut rx): (mpsc::Sender<()>, mpsc::Receiver<()>), + app_state_to_session_state: F, ) -> CustomResult<(), errors::ProcessTrackerError> where + F: Fn(&T, &str) -> CustomResult, T: SchedulerAppState, + U: SchedulerSessionState, { use std::time::Duration; @@ -64,13 +67,17 @@ where match rx.try_recv() { Err(mpsc::error::TryRecvError::Empty) => { interval.tick().await; - match run_producer_flow(state, &scheduler_settings).await { - Ok(_) => (), - Err(error) => { - // Intentionally not propagating error to caller. - // Any errors that occur in the producer flow must be handled here only, as - // this is the topmost level function which is concerned with the producer flow. - error!(%error); + let tenants = state.get_tenants(); + for tenant in tenants { + let session_state = app_state_to_session_state(state, tenant.as_str())?; + match run_producer_flow(&session_state, &scheduler_settings).await { + Ok(_) => (), + Err(error) => { + // Intentionally not propagating error to caller. + // Any errors that occur in the producer flow must be handled here only, as + // this is the topmost level function which is concerned with the producer flow. + error!(%error); + } } } } @@ -78,7 +85,7 @@ where logger::debug!("Awaiting shutdown!"); rx.close(); shutdown_interval.tick().await; - logger::info!("Terminating consumer"); + logger::info!("Terminating producer"); break; } } @@ -97,7 +104,7 @@ pub async fn run_producer_flow( settings: &SchedulerSettings, ) -> CustomResult<(), errors::ProcessTrackerError> where - T: SchedulerAppState, + T: SchedulerSessionState, { lock_acquire_release::<_, _, _>(state.get_db().as_scheduler(), settings, move || async { let tasks = fetch_producer_tasks(state.get_db().as_scheduler(), settings).await?; diff --git a/crates/scheduler/src/scheduler.rs b/crates/scheduler/src/scheduler.rs index 273f10819f8d..39a45d02ba96 100644 --- a/crates/scheduler/src/scheduler.rs +++ b/crates/scheduler/src/scheduler.rs @@ -52,22 +52,46 @@ impl SchedulerInterface for MockDb {} #[async_trait::async_trait] pub trait SchedulerAppState: Send + Sync + Clone { + fn get_tenants(&self) -> Vec; +} +#[async_trait::async_trait] +pub trait SchedulerSessionState: Send + Sync + Clone { fn get_db(&self) -> Box; } - -pub async fn start_process_tracker( +pub async fn start_process_tracker< + T: SchedulerAppState + 'static, + U: SchedulerSessionState + 'static, + F, +>( state: &T, scheduler_flow: SchedulerFlow, scheduler_settings: Arc, channel: (mpsc::Sender<()>, mpsc::Receiver<()>), - runner_from_task: impl workflows::ProcessTrackerWorkflows + 'static + Copy + std::fmt::Debug, -) -> CustomResult<(), errors::ProcessTrackerError> { + runner_from_task: impl workflows::ProcessTrackerWorkflows + 'static + Copy + std::fmt::Debug, + app_state_to_session_state: F, +) -> CustomResult<(), errors::ProcessTrackerError> +where + F: Fn(&T, &str) -> CustomResult, +{ match scheduler_flow { SchedulerFlow::Producer => { - producer::start_producer(state, scheduler_settings, channel).await? + producer::start_producer( + state, + scheduler_settings, + channel, + app_state_to_session_state, + ) + .await? } SchedulerFlow::Consumer => { - consumer::start_consumer(state, scheduler_settings, runner_from_task, channel).await? + consumer::start_consumer( + state, + scheduler_settings, + runner_from_task, + channel, + app_state_to_session_state, + ) + .await? } SchedulerFlow::Cleaner => { error!("This flow has not been implemented yet!"); diff --git a/crates/scheduler/src/utils.rs b/crates/scheduler/src/utils.rs index 8b80b7c72c1f..7f073a8e10b9 100644 --- a/crates/scheduler/src/utils.rs +++ b/crates/scheduler/src/utils.rs @@ -1,7 +1,4 @@ -use std::{ - sync::{self, atomic}, - time as std_time, -}; +use std::sync; use common_utils::errors::CustomResult; use diesel_models::enums::{self, ProcessTrackerStatus}; @@ -17,7 +14,7 @@ use super::{ }; use crate::{ configs::settings::SchedulerSettings, consumer::types::ProcessTrackerBatch, errors, - flow::SchedulerFlow, metrics, SchedulerAppState, SchedulerInterface, + flow::SchedulerFlow, metrics, SchedulerInterface, SchedulerSessionState, }; pub async fn divide_and_append_tasks( @@ -258,26 +255,16 @@ pub async fn consumer_operation_handler( state: T, settings: sync::Arc, error_handler_fun: E, - consumer_operation_counter: sync::Arc, workflow_selector: impl workflows::ProcessTrackerWorkflows + 'static + Copy + std::fmt::Debug, ) where // Error handler function E: FnOnce(error_stack::Report), - T: SchedulerAppState + Send + Sync + 'static, + T: SchedulerSessionState + Send + Sync + 'static, { - consumer_operation_counter.fetch_add(1, atomic::Ordering::SeqCst); - let start_time = std_time::Instant::now(); - match consumer::consumer_operations(&state, &settings, workflow_selector).await { Ok(_) => (), Err(err) => error_handler_fun(err), } - let end_time = std_time::Instant::now(); - let duration = end_time.saturating_duration_since(start_time).as_secs_f64(); - logger::debug!("Time taken to execute consumer_operation: {}s", duration); - - let current_count = consumer_operation_counter.fetch_sub(1, atomic::Ordering::SeqCst); - logger::info!("Current tasks being executed: {}", current_count); } pub fn add_histogram_metrics( diff --git a/crates/storage_impl/src/config.rs b/crates/storage_impl/src/config.rs index fd95a6d315d6..e371936a04dd 100644 --- a/crates/storage_impl/src/config.rs +++ b/crates/storage_impl/src/config.rs @@ -1,3 +1,4 @@ +use common_utils::DbConnectionParams; use masking::Secret; #[derive(Debug, Clone, serde::Deserialize)] @@ -14,6 +15,29 @@ pub struct Database { pub max_lifetime: Option, } +impl DbConnectionParams for Database { + fn get_username(&self) -> &str { + &self.username + } + fn get_password(&self) -> Secret { + self.password.clone() + } + fn get_host(&self) -> &str { + &self.host + } + fn get_port(&self) -> u16 { + self.port + } + fn get_dbname(&self) -> &str { + &self.dbname + } +} + +pub trait TenantConfig: Send + Sync { + fn get_schema(&self) -> &str; + fn get_redis_key_prefix(&self) -> &str; +} + #[derive(Debug, serde::Deserialize, Clone, Copy, Default)] #[serde(rename_all = "PascalCase")] pub enum QueueStrategy { diff --git a/crates/storage_impl/src/database/store.rs b/crates/storage_impl/src/database/store.rs index 17ae76b5bb03..543cc47870d9 100644 --- a/crates/storage_impl/src/database/store.rs +++ b/crates/storage_impl/src/database/store.rs @@ -1,11 +1,11 @@ use async_bb8_diesel::{AsyncConnection, ConnectionError}; use bb8::CustomizeConnection; +use common_utils::DbConnectionParams; use diesel::PgConnection; use error_stack::ResultExt; use hyperswitch_domain_models::errors::{StorageError, StorageResult}; -use masking::PeekInterface; -use crate::config::Database; +use crate::config::{Database, TenantConfig}; pub type PgPool = bb8::Pool>; pub type PgPooledConn = async_bb8_diesel::Connection; @@ -13,7 +13,11 @@ pub type PgPooledConn = async_bb8_diesel::Connection; #[async_trait::async_trait] pub trait DatabaseStore: Clone + Send + Sync { type Config: Send; - async fn new(config: Self::Config, test_transaction: bool) -> StorageResult; + async fn new( + config: Self::Config, + tenant_config: &dyn TenantConfig, + test_transaction: bool, + ) -> StorageResult; fn get_master_pool(&self) -> &PgPool; fn get_replica_pool(&self) -> &PgPool; } @@ -26,9 +30,14 @@ pub struct Store { #[async_trait::async_trait] impl DatabaseStore for Store { type Config = Database; - async fn new(config: Database, test_transaction: bool) -> StorageResult { + async fn new( + config: Database, + tenant_config: &dyn TenantConfig, + test_transaction: bool, + ) -> StorageResult { Ok(Self { - master_pool: diesel_make_pg_pool(&config, test_transaction).await?, + master_pool: diesel_make_pg_pool(&config, tenant_config.get_schema(), test_transaction) + .await?, }) } @@ -50,14 +59,23 @@ pub struct ReplicaStore { #[async_trait::async_trait] impl DatabaseStore for ReplicaStore { type Config = (Database, Database); - async fn new(config: (Database, Database), test_transaction: bool) -> StorageResult { + async fn new( + config: (Database, Database), + tenant_config: &dyn TenantConfig, + test_transaction: bool, + ) -> StorageResult { let (master_config, replica_config) = config; - let master_pool = diesel_make_pg_pool(&master_config, test_transaction) - .await - .attach_printable("failed to create master pool")?; - let replica_pool = diesel_make_pg_pool(&replica_config, test_transaction) - .await - .attach_printable("failed to create replica pool")?; + let master_pool = + diesel_make_pg_pool(&master_config, tenant_config.get_schema(), test_transaction) + .await + .attach_printable("failed to create master pool")?; + let replica_pool = diesel_make_pg_pool( + &replica_config, + tenant_config.get_schema(), + test_transaction, + ) + .await + .attach_printable("failed to create replica pool")?; Ok(Self { master_pool, replica_pool, @@ -75,16 +93,10 @@ impl DatabaseStore for ReplicaStore { pub async fn diesel_make_pg_pool( database: &Database, + schema: &str, test_transaction: bool, ) -> StorageResult { - let database_url = format!( - "postgres://{}:{}@{}:{}/{}", - database.username, - database.password.peek(), - database.host, - database.port, - database.dbname - ); + let database_url = database.get_database_url(schema); let manager = async_bb8_diesel::ConnectionManager::::new(database_url); let mut pool = bb8::Pool::builder() .max_size(database.pool_size) diff --git a/crates/storage_impl/src/lib.rs b/crates/storage_impl/src/lib.rs index b1582bb6e9af..d55f812c5a21 100644 --- a/crates/storage_impl/src/lib.rs +++ b/crates/storage_impl/src/lib.rs @@ -29,7 +29,7 @@ use database::store::PgPool; #[cfg(not(feature = "payouts"))] use hyperswitch_domain_models::{PayoutAttemptInterface, PayoutsInterface}; pub use mock_db::MockDb; -use redis_interface::{errors::RedisError, SaddReply}; +use redis_interface::{errors::RedisError, RedisConnectionPool, SaddReply}; pub use crate::database::store::DatabaseStore; #[cfg(not(feature = "payouts"))] @@ -38,7 +38,7 @@ pub use crate::database::store::Store; #[derive(Debug, Clone)] pub struct RouterStore { db_store: T, - cache_store: RedisStore, + cache_store: Arc, master_encryption_key: StrongSecret>, pub request_id: Option, } @@ -55,19 +55,23 @@ where tokio::sync::oneshot::Sender<()>, &'static str, ); - async fn new(config: Self::Config, test_transaction: bool) -> StorageResult { + async fn new( + config: Self::Config, + tenant_config: &dyn config::TenantConfig, + test_transaction: bool, + ) -> StorageResult { let (db_conf, cache_conf, encryption_key, cache_error_signal, inmemory_cache_stream) = config; if test_transaction { - Self::test_store(db_conf, &cache_conf, encryption_key) + Self::test_store(db_conf, tenant_config, &cache_conf, encryption_key) .await .attach_printable("failed to create test router store") } else { Self::from_config( db_conf, - &cache_conf, + tenant_config, encryption_key, - cache_error_signal, + Self::cache_store(&cache_conf, cache_error_signal).await?, inmemory_cache_stream, ) .await @@ -83,9 +87,7 @@ where } impl RedisConnInterface for RouterStore { - fn get_redis_conn( - &self, - ) -> error_stack::Result, RedisError> { + fn get_redis_conn(&self) -> error_stack::Result, RedisError> { self.cache_store.get_redis_conn() } } @@ -93,23 +95,26 @@ impl RedisConnInterface for RouterStore { impl RouterStore { pub async fn from_config( db_conf: T::Config, - cache_conf: &redis_interface::RedisSettings, + tenant_config: &dyn config::TenantConfig, encryption_key: StrongSecret>, - cache_error_signal: tokio::sync::oneshot::Sender<()>, + cache_store: Arc, inmemory_cache_stream: &str, ) -> StorageResult { - let db_store = T::new(db_conf, false).await?; - let cache_store = RedisStore::new(cache_conf) - .await - .change_context(StorageError::InitializationError) - .attach_printable("Failed to create cache store")?; - cache_store.set_error_callback(cache_error_signal); + let db_store = T::new(db_conf, tenant_config, false).await?; + let redis_conn = cache_store.redis_conn.clone(); + let cache_store = Arc::new(RedisStore { + redis_conn: Arc::new(RedisConnectionPool::clone( + &redis_conn, + tenant_config.get_redis_key_prefix(), + )), + }); cache_store .redis_conn .subscribe(inmemory_cache_stream) .await .change_context(StorageError::InitializationError) .attach_printable("Failed to subscribe to inmemory cache stream")?; + Ok(Self { db_store, cache_store, @@ -118,6 +123,18 @@ impl RouterStore { }) } + pub async fn cache_store( + cache_conf: &redis_interface::RedisSettings, + cache_error_signal: tokio::sync::oneshot::Sender<()>, + ) -> StorageResult> { + let cache_store = RedisStore::new(cache_conf) + .await + .change_context(StorageError::InitializationError) + .attach_printable("Failed to create cache store")?; + cache_store.set_error_callback(cache_error_signal); + Ok(Arc::new(cache_store)) + } + pub fn master_key(&self) -> &StrongSecret> { &self.master_encryption_key } @@ -127,18 +144,19 @@ impl RouterStore { /// Will panic if `CONNECTOR_AUTH_FILE_PATH` is not set pub async fn test_store( db_conf: T::Config, + tenant_config: &dyn config::TenantConfig, cache_conf: &redis_interface::RedisSettings, encryption_key: StrongSecret>, ) -> StorageResult { // TODO: create an error enum and return proper error here - let db_store = T::new(db_conf, true).await?; + let db_store = T::new(db_conf, tenant_config, true).await?; let cache_store = RedisStore::new(cache_conf) .await .change_context(StorageError::InitializationError) .attach_printable("failed to create redis cache")?; Ok(Self { db_store, - cache_store, + cache_store: Arc::new(cache_store), master_encryption_key: encryption_key, request_id: None, }) @@ -162,9 +180,13 @@ where T: DatabaseStore, { type Config = (RouterStore, String, u8, u32, Option); - async fn new(config: Self::Config, _test_transaction: bool) -> StorageResult { - let (router_store, drainer_stream_name, drainer_num_partitions, ttl_for_kv, soft_kill_mode) = - config; + async fn new( + config: Self::Config, + tenant_config: &dyn config::TenantConfig, + _test_transaction: bool, + ) -> StorageResult { + let (router_store, _, drainer_num_partitions, ttl_for_kv, soft_kill_mode) = config; + let drainer_stream_name = format!("{}_{}", tenant_config.get_schema(), config.1); Ok(Self::from_store( router_store, drainer_stream_name, @@ -182,9 +204,7 @@ where } impl RedisConnInterface for KVRouterStore { - fn get_redis_conn( - &self, - ) -> error_stack::Result, RedisError> { + fn get_redis_conn(&self) -> error_stack::Result, RedisError> { self.router_store.get_redis_conn() } } @@ -282,7 +302,7 @@ pub trait UniqueConstraints { fn table_name(&self) -> &str; async fn check_for_constraints( &self, - redis_conn: &Arc, + redis_conn: &Arc, ) -> CustomResult<(), RedisError> { let constraints = self.unique_constraints(); let sadd_result = redis_conn diff --git a/crates/storage_impl/src/redis/cache.rs b/crates/storage_impl/src/redis/cache.rs index 4a72b86fefb7..c0375773b544 100644 --- a/crates/storage_impl/src/redis/cache.rs +++ b/crates/storage_impl/src/redis/cache.rs @@ -1,4 +1,4 @@ -use std::{any::Any, borrow::Cow, sync::Arc}; +use std::{any::Any, borrow::Cow, fmt::Debug, sync::Arc}; use common_utils::{ errors::{self, CustomResult}, @@ -8,7 +8,7 @@ use dyn_clone::DynClone; use error_stack::{Report, ResultExt}; use moka::future::Cache as MokaCache; use once_cell::sync::Lazy; -use redis_interface::{errors::RedisError, RedisValue}; +use redis_interface::{errors::RedisError, RedisConnectionPool, RedisValue}; use router_env::tracing::{self, instrument}; use crate::{ @@ -118,6 +118,23 @@ pub struct Cache { inner: MokaCache>, } +#[derive(Debug, Clone)] +pub struct CacheKey { + pub key: String, + // #TODO: make it usage specific enum Eg: CacheKind { Tenant(String), NoTenant, Partition(String) } + pub prefix: String, +} + +impl From for String { + fn from(val: CacheKey) -> Self { + if val.prefix.is_empty() { + val.key + } else { + format!("{}:{}", val.prefix, val.key) + } + } +} + impl Cache { /// With given `time_to_live` and `time_to_idle` creates a moka cache. /// @@ -138,44 +155,38 @@ impl Cache { } } - pub async fn push(&self, key: String, val: T) { - self.inner.insert(key, Arc::new(val)).await; + pub async fn push(&self, key: CacheKey, val: T) { + self.inner.insert(key.into(), Arc::new(val)).await; } - pub async fn get_val(&self, key: &str) -> Option { - let val = self.inner.get(key).await?; + pub async fn get_val(&self, key: CacheKey) -> Option { + let val = self.inner.get::(&key.into()).await?; (*val).as_any().downcast_ref::().cloned() } /// Check if a key exists in cache - pub async fn exists(&self, key: &str) -> bool { - self.inner.contains_key(key) + pub async fn exists(&self, key: CacheKey) -> bool { + self.inner.contains_key::(&key.into()) } - pub async fn remove(&self, key: &str) { - self.inner.invalidate(key).await; + pub async fn remove(&self, key: CacheKey) { + self.inner.invalidate::(&key.into()).await; } } #[instrument(skip_all)] pub async fn get_or_populate_redis( - store: &(dyn RedisConnInterface + Send + Sync), + redis: &Arc, key: impl AsRef, fun: F, ) -> CustomResult where - T: serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug, + T: serde::Serialize + serde::de::DeserializeOwned + Debug, F: FnOnce() -> Fut + Send, Fut: futures::Future> + Send, { let type_name = std::any::type_name::(); let key = key.as_ref(); - let redis = &store - .get_redis_conn() - .change_context(StorageError::RedisError( - RedisError::RedisConnectionError.into(), - )) - .attach_printable("Failed to get redis connection")?; let redis_val = redis.get_and_deserialize_key::(key, type_name).await; let get_data_set_redis = || async { let data = fun().await?; @@ -206,16 +217,35 @@ pub async fn get_or_populate_in_memory( cache: &Cache, ) -> CustomResult where - T: Cacheable + serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug + Clone, + T: Cacheable + serde::Serialize + serde::de::DeserializeOwned + Debug + Clone, F: FnOnce() -> Fut + Send, Fut: futures::Future> + Send, { - let cache_val = cache.get_val::(key).await; + let redis = &store + .get_redis_conn() + .change_context(StorageError::RedisError( + RedisError::RedisConnectionError.into(), + )) + .attach_printable("Failed to get redis connection")?; + let cache_val = cache + .get_val::(CacheKey { + key: key.to_string(), + prefix: redis.key_prefix.clone(), + }) + .await; if let Some(val) = cache_val { Ok(val) } else { - let val = get_or_populate_redis(store, key, fun).await?; - cache.push(key.to_string(), val.clone()).await; + let val = get_or_populate_redis(redis, key, fun).await?; + cache + .push( + CacheKey { + key: key.to_string(), + prefix: redis.key_prefix.clone(), + }, + val.clone(), + ) + .await; Ok(val) } } @@ -223,7 +253,7 @@ where #[instrument(skip_all)] pub async fn redact_cache( store: &(dyn RedisConnInterface + Send + Sync), - key: &str, + key: &'static str, fun: F, in_memory: Option<&Cache>, ) -> CustomResult @@ -232,7 +262,6 @@ where Fut: futures::Future> + Send, { let data = fun().await?; - in_memory.async_map(|cache| cache.remove(key)).await; let redis_conn = store .get_redis_conn() @@ -240,6 +269,11 @@ where RedisError::RedisConnectionError.into(), )) .attach_printable("Failed to get redis connection")?; + let tenant_key = CacheKey { + key: key.to_string(), + prefix: redis_conn.key_prefix.clone(), + }; + in_memory.async_map(|cache| cache.remove(tenant_key)).await; redis_conn .delete_key(key) @@ -312,9 +346,22 @@ mod cache_tests { #[tokio::test] async fn construct_and_get_cache() { let cache = Cache::new(1800, 1800, None); - cache.push("key".to_string(), "val".to_string()).await; + cache + .push( + CacheKey { + key: "key".to_string(), + prefix: "prefix".to_string(), + }, + "val".to_string(), + ) + .await; assert_eq!( - cache.get_val::("key").await, + cache + .get_val::(CacheKey { + key: "key".to_string(), + prefix: "prefix".to_string() + }) + .await, Some(String::from("val")) ); } @@ -322,25 +369,78 @@ mod cache_tests { #[tokio::test] async fn eviction_on_size_test() { let cache = Cache::new(2, 2, Some(0)); - cache.push("key".to_string(), "val".to_string()).await; - assert_eq!(cache.get_val::("key").await, None); + cache + .push( + CacheKey { + key: "key".to_string(), + prefix: "prefix".to_string(), + }, + "val".to_string(), + ) + .await; + assert_eq!( + cache + .get_val::(CacheKey { + key: "key".to_string(), + prefix: "prefix".to_string() + }) + .await, + None + ); } #[tokio::test] async fn invalidate_cache_for_key() { let cache = Cache::new(1800, 1800, None); - cache.push("key".to_string(), "val".to_string()).await; + cache + .push( + CacheKey { + key: "key".to_string(), + prefix: "prefix".to_string(), + }, + "val".to_string(), + ) + .await; + + cache + .remove(CacheKey { + key: "key".to_string(), + prefix: "prefix".to_string(), + }) + .await; - cache.remove("key").await; - - assert_eq!(cache.get_val::("key").await, None); + assert_eq!( + cache + .get_val::(CacheKey { + key: "key".to_string(), + prefix: "prefix".to_string() + }) + .await, + None + ); } #[tokio::test] async fn eviction_on_time_test() { let cache = Cache::new(2, 2, None); - cache.push("key".to_string(), "val".to_string()).await; + cache + .push( + CacheKey { + key: "key".to_string(), + prefix: "prefix".to_string(), + }, + "val".to_string(), + ) + .await; tokio::time::sleep(std::time::Duration::from_secs(3)).await; - assert_eq!(cache.get_val::("key").await, None); + assert_eq!( + cache + .get_val::(CacheKey { + key: "key".to_string(), + prefix: "prefix".to_string() + }) + .await, + None + ); } } diff --git a/crates/storage_impl/src/redis/pub_sub.rs b/crates/storage_impl/src/redis/pub_sub.rs index 830f6251d6b6..1f079784243a 100644 --- a/crates/storage_impl/src/redis/pub_sub.rs +++ b/crates/storage_impl/src/redis/pub_sub.rs @@ -2,7 +2,9 @@ use error_stack::ResultExt; use redis_interface::{errors as redis_errors, PubsubInterface, RedisValue}; use router_env::{logger, tracing::Instrument}; -use crate::redis::cache::{CacheKind, ACCOUNTS_CACHE, CGRAPH_CACHE, CONFIG_CACHE, ROUTING_CACHE}; +use crate::redis::cache::{ + CacheKey, CacheKind, ACCOUNTS_CACHE, CGRAPH_CACHE, CONFIG_CACHE, ROUTING_CACHE, +}; #[async_trait::async_trait] pub trait PubSubInterface { @@ -55,7 +57,7 @@ impl PubSubInterface for std::sync::Arc { #[inline] async fn on_message(&self) -> error_stack::Result<(), redis_errors::RedisError> { - logger::debug!("Started on message"); + logger::debug!("Started on message: {:?}", self.key_prefix); let mut rx = self.subscriber.on_message(); while let Ok(message) = rx.recv().await { logger::debug!("Invalidating {message:?}"); @@ -71,26 +73,66 @@ impl PubSubInterface for std::sync::Arc { let key = match key { CacheKind::Config(key) => { - CONFIG_CACHE.remove(key.as_ref()).await; + CONFIG_CACHE + .remove(CacheKey { + key: key.to_string(), + prefix: self.key_prefix.clone(), + }) + .await; key } CacheKind::Accounts(key) => { - ACCOUNTS_CACHE.remove(key.as_ref()).await; + ACCOUNTS_CACHE + .remove(CacheKey { + key: key.to_string(), + prefix: self.key_prefix.clone(), + }) + .await; key } CacheKind::CGraph(key) => { - CGRAPH_CACHE.remove(key.as_ref()).await; + CGRAPH_CACHE + .remove(CacheKey { + key: key.to_string(), + prefix: self.key_prefix.clone(), + }) + .await; key } CacheKind::Routing(key) => { - ROUTING_CACHE.remove(key.as_ref()).await; + ROUTING_CACHE + .remove(CacheKey { + key: key.to_string(), + prefix: self.key_prefix.clone(), + }) + .await; key } CacheKind::All(key) => { - CONFIG_CACHE.remove(key.as_ref()).await; - ACCOUNTS_CACHE.remove(key.as_ref()).await; - CGRAPH_CACHE.remove(key.as_ref()).await; - ROUTING_CACHE.remove(key.as_ref()).await; + CONFIG_CACHE + .remove(CacheKey { + key: key.to_string(), + prefix: self.key_prefix.clone(), + }) + .await; + ACCOUNTS_CACHE + .remove(CacheKey { + key: key.to_string(), + prefix: self.key_prefix.clone(), + }) + .await; + CGRAPH_CACHE + .remove(CacheKey { + key: key.to_string(), + prefix: self.key_prefix.clone(), + }) + .await; + ROUTING_CACHE + .remove(CacheKey { + key: key.to_string(), + prefix: self.key_prefix.clone(), + }) + .await; key } }; diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml index ad60418339c2..2abe90f6086a 100644 --- a/loadtest/config/development.toml +++ b/loadtest/config/development.toml @@ -322,3 +322,9 @@ partner_id = "" [unmasked_headers] keys = "user-agent" + +[multitenancy] +enabled = false + +[multitenancy.tenants] +public = { name = "hyperswitch", base_url = "http://localhost:8080", schema = "public", redis_key_prefix = ""} \ No newline at end of file From 0cbb2928bd054cb8e98c3811f397a837a8887486 Mon Sep 17 00:00:00 2001 From: Mani Chandra <84711804+ThisIsMani@users.noreply.github.com> Date: Mon, 3 Jun 2024 19:22:42 +0530 Subject: [PATCH 14/25] feat(users): Create config for TOTP Issuer (#4776) --- config/config.example.toml | 5 ++-- config/deployments/integration_test.toml | 1 + config/deployments/production.toml | 1 + config/deployments/sandbox.toml | 1 + config/development.toml | 1 + config/docker_compose.toml | 1 + crates/router/src/configs/settings.rs | 1 + crates/router/src/consts/user.rs | 4 ++- crates/router/src/core/user.rs | 25 ++++++++++++++++--- .../router/src/utils/user/two_factor_auth.rs | 3 ++- loadtest/config/development.toml | 1 + 11 files changed, 36 insertions(+), 8 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index 8aa0ca9e52f2..ac428298e73d 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -351,8 +351,9 @@ email_role_arn = "" # The amazon resource name ( arn ) of the role which sts_role_session_name = "" # An identifier for the assumed role session, used to uniquely identify a session. [user] -password_validity_in_days = 90 # Number of days after which password should be updated -two_factor_auth_expiry_in_secs = 300 # Number of seconds after which 2FA should be done again if doing update/change from inside +password_validity_in_days = 90 # Number of days after which password should be updated +two_factor_auth_expiry_in_secs = 300 # Number of seconds after which 2FA should be done again if doing update/change from inside +totp_issuer_name = "Hyperswitch" # Name of the issuer for TOTP #tokenization configuration which describe token lifetime and payment method for specific connector [tokenization] diff --git a/config/deployments/integration_test.toml b/config/deployments/integration_test.toml index f6ed3ca5ea5b..8d76771f897e 100644 --- a/config/deployments/integration_test.toml +++ b/config/deployments/integration_test.toml @@ -114,6 +114,7 @@ slack_invite_url = "https://join.slack.com/t/hyperswitch-io/shared_invite/zt-2aw [user] password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 +totp_issuer_name = "Hyperswitch Integ" [frm] enabled = true diff --git a/config/deployments/production.toml b/config/deployments/production.toml index 37b35eb47e7b..65f8d87215a6 100644 --- a/config/deployments/production.toml +++ b/config/deployments/production.toml @@ -121,6 +121,7 @@ slack_invite_url = "https://join.slack.com/t/hyperswitch-io/shared_invite/zt-2aw [user] password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 +totp_issuer_name = "Hyperswitch Production" [frm] enabled = false diff --git a/config/deployments/sandbox.toml b/config/deployments/sandbox.toml index fc496e34fc30..94f6d4b34302 100644 --- a/config/deployments/sandbox.toml +++ b/config/deployments/sandbox.toml @@ -121,6 +121,7 @@ slack_invite_url = "https://join.slack.com/t/hyperswitch-io/shared_invite/zt-2aw [user] password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 +totp_issuer_name = "Hyperswitch Sandbox" [frm] enabled = true diff --git a/config/development.toml b/config/development.toml index d12a667b6315..25fe55e60575 100644 --- a/config/development.toml +++ b/config/development.toml @@ -270,6 +270,7 @@ sts_role_session_name = "" [user] password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 +totp_issuer_name = "Hyperswitch Dev" [bank_config.eps] stripe = { banks = "arzte_und_apotheker_bank,austrian_anadi_bank_ag,bank_austria,bankhaus_carl_spangler,bankhaus_schelhammer_und_schattera_ag,bawag_psk_ag,bks_bank_ag,brull_kallmus_bank_ag,btv_vier_lander_bank,capital_bank_grawe_gruppe_ag,dolomitenbank,easybank_ag,erste_bank_und_sparkassen,hypo_alpeadriabank_international_ag,hypo_noe_lb_fur_niederosterreich_u_wien,hypo_oberosterreich_salzburg_steiermark,hypo_tirol_bank_ag,hypo_vorarlberg_bank_ag,hypo_bank_burgenland_aktiengesellschaft,marchfelder_bank,oberbank_ag,raiffeisen_bankengruppe_osterreich,schoellerbank_ag,sparda_bank_wien,volksbank_gruppe,volkskreditbank_ag,vr_bank_braunau" } diff --git a/config/docker_compose.toml b/config/docker_compose.toml index 3f6c9523e933..f43ceca893d5 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -54,6 +54,7 @@ recon_admin_api_key = "recon_test_admin" [user] password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 +totp_issuer_name = "Hyperswitch" [locker] host = "" diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index c71ed4496b08..9aa879a43870 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -436,6 +436,7 @@ pub struct Secrets { pub struct UserSettings { pub password_validity_in_days: u16, pub two_factor_auth_expiry_in_secs: i64, + pub totp_issuer_name: String, } #[derive(Debug, Deserialize, Clone)] diff --git a/crates/router/src/consts/user.rs b/crates/router/src/consts/user.rs index 3c6cd8b6ccd3..c7615aa4be4a 100644 --- a/crates/router/src/consts/user.rs +++ b/crates/router/src/consts/user.rs @@ -1,15 +1,17 @@ pub const MAX_NAME_LENGTH: usize = 70; pub const MAX_COMPANY_NAME_LENGTH: usize = 70; pub const BUSINESS_EMAIL: &str = "biz@hyperswitch.io"; + pub const RECOVERY_CODES_COUNT: usize = 8; pub const RECOVERY_CODE_LENGTH: usize = 8; // This is without counting the hyphen in between -pub const TOTP_ISSUER_NAME: &str = "Hyperswitch"; + /// The number of digits composing the auth code. pub const TOTP_DIGITS: usize = 6; /// Duration in seconds of a step. pub const TOTP_VALIDITY_DURATION_IN_SECONDS: u64 = 30; /// Number of totps allowed as network delay. 1 would mean one totp before current totp and one totp after are valids. pub const TOTP_TOLERANCE: u8 = 1; + pub const MAX_PASSWORD_LENGTH: usize = 70; pub const MIN_PASSWORD_LENGTH: usize = 8; diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs index c259e87c93de..f4751c3a55a9 100644 --- a/crates/router/src/core/user.rs +++ b/crates/router/src/core/user.rs @@ -1635,7 +1635,11 @@ pub async fn begin_totp( })); } - let totp = tfa_utils::generate_default_totp(user_from_db.get_email(), None)?; + let totp = tfa_utils::generate_default_totp( + user_from_db.get_email(), + None, + state.conf.user.totp_issuer_name.clone(), + )?; let secret = totp.get_secret_base32().into(); tfa_utils::insert_totp_secret_in_redis(&state, &user_token.user_id, &secret).await?; @@ -1668,7 +1672,12 @@ pub async fn reset_totp( return Err(UserErrors::TwoFactorAuthRequired.into()); } - let totp = tfa_utils::generate_default_totp(user_from_db.get_email(), None)?; + let totp = tfa_utils::generate_default_totp( + user_from_db.get_email(), + None, + state.conf.user.totp_issuer_name.clone(), + )?; + let secret = totp.get_secret_base32().into(); tfa_utils::insert_totp_secret_in_redis(&state, &user_token.user_id, &secret).await?; @@ -1701,7 +1710,11 @@ pub async fn verify_totp( .await? .ok_or(UserErrors::InternalServerError)?; - let totp = tfa_utils::generate_default_totp(user_from_db.get_email(), Some(user_totp_secret))?; + let totp = tfa_utils::generate_default_totp( + user_from_db.get_email(), + Some(user_totp_secret), + state.conf.user.totp_issuer_name.clone(), + )?; if totp .generate_current() @@ -1732,7 +1745,11 @@ pub async fn update_totp( .await? .ok_or(UserErrors::TotpSecretNotFound)?; - let totp = tfa_utils::generate_default_totp(user_from_db.get_email(), Some(new_totp_secret))?; + let totp = tfa_utils::generate_default_totp( + user_from_db.get_email(), + Some(new_totp_secret), + state.conf.user.totp_issuer_name.clone(), + )?; if totp .generate_current() diff --git a/crates/router/src/utils/user/two_factor_auth.rs b/crates/router/src/utils/user/two_factor_auth.rs index a0915f3ed86e..f64eda4dc5a1 100644 --- a/crates/router/src/utils/user/two_factor_auth.rs +++ b/crates/router/src/utils/user/two_factor_auth.rs @@ -12,6 +12,7 @@ use crate::{ pub fn generate_default_totp( email: pii::Email, secret: Option>, + issuer: String, ) -> UserResult { let secret = secret .map(|sec| totp_rs::Secret::Encoded(sec.expose())) @@ -25,7 +26,7 @@ pub fn generate_default_totp( consts::user::TOTP_TOLERANCE, consts::user::TOTP_VALIDITY_DURATION_IN_SECONDS, secret, - Some(consts::user::TOTP_ISSUER_NAME.to_string()), + Some(issuer), email.expose().expose(), ) .change_context(UserErrors::InternalServerError) diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml index 2abe90f6086a..e46a710054e0 100644 --- a/loadtest/config/development.toml +++ b/loadtest/config/development.toml @@ -31,6 +31,7 @@ jwt_secret = "secret" [user] password_validity_in_days = 90 two_factor_auth_expiry_in_secs = 300 +totp_issuer_name = "Hyperswitch" [locker] host = "" From d242850b63173f314fb259451139464f09e0a9e9 Mon Sep 17 00:00:00 2001 From: Mani Chandra <84711804+ThisIsMani@users.noreply.github.com> Date: Mon, 3 Jun 2024 19:40:13 +0530 Subject: [PATCH 15/25] refactor(users): Changes for Home and Signout APIs for TOTP Redis flows (#4851) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- crates/api_models/src/user.rs | 3 +++ crates/router/src/core/user.rs | 6 +++++ .../router/src/utils/user/two_factor_auth.rs | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/crates/api_models/src/user.rs b/crates/api_models/src/user.rs index ee9498cfeee4..a61b9fd7dffa 100644 --- a/crates/api_models/src/user.rs +++ b/crates/api_models/src/user.rs @@ -165,7 +165,10 @@ pub struct GetUserDetailsResponse { #[serde(skip_serializing)] pub user_id: String, pub org_id: String, + pub is_two_factor_auth_setup: bool, + pub recovery_codes_left: Option, } + #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct GetUserRoleDetailsRequest { pub email: pii::Email, diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs index f4751c3a55a9..69a4cfc8a61c 100644 --- a/crates/router/src/core/user.rs +++ b/crates/router/src/core/user.rs @@ -94,6 +94,8 @@ pub async fn get_user_details( verification_days_left, role_id: user_from_token.role_id, org_id: user_from_token.org_id, + is_two_factor_auth_setup: user.get_totp_status() == TotpStatus::Set, + recovery_codes_left: user.get_recovery_codes().map(|codes| codes.len()), }, )) } @@ -328,6 +330,10 @@ pub async fn signout( state: SessionState, user_from_token: auth::UserFromToken, ) -> UserResponse<()> { + tfa_utils::delete_totp_from_redis(&state, &user_from_token.user_id).await?; + tfa_utils::delete_recovery_code_from_redis(&state, &user_from_token.user_id).await?; + tfa_utils::delete_totp_secret_from_redis(&state, &user_from_token.user_id).await?; + auth::blacklist::insert_user_in_blacklist(&state, &user_from_token.user_id).await?; auth::cookies::remove_cookie_response() } diff --git a/crates/router/src/utils/user/two_factor_auth.rs b/crates/router/src/utils/user/two_factor_auth.rs index f64eda4dc5a1..bebe58ebd866 100644 --- a/crates/router/src/utils/user/two_factor_auth.rs +++ b/crates/router/src/utils/user/two_factor_auth.rs @@ -116,3 +116,26 @@ pub async fn insert_recovery_code_in_redis(state: &SessionState, user_id: &str) .await .change_context(UserErrors::InternalServerError) } + +pub async fn delete_totp_from_redis(state: &SessionState, user_id: &str) -> UserResult<()> { + let redis_conn = super::get_redis_connection(state)?; + let key = format!("{}{}", consts::user::REDIS_TOTP_PREFIX, user_id); + redis_conn + .delete_key(&key) + .await + .change_context(UserErrors::InternalServerError) + .map(|_| ()) +} + +pub async fn delete_recovery_code_from_redis( + state: &SessionState, + user_id: &str, +) -> UserResult<()> { + let redis_conn = super::get_redis_connection(state)?; + let key = format!("{}{}", consts::user::REDIS_RECOVERY_CODE_PREFIX, user_id); + redis_conn + .delete_key(&key) + .await + .change_context(UserErrors::InternalServerError) + .map(|_| ()) +} From fa5f5a4eddecd072f974738d2168cd0b7c277d2e Mon Sep 17 00:00:00 2001 From: Vrishab Srivatsa <136090360+vsrivatsa-juspay@users.noreply.github.com> Date: Mon, 3 Jun 2024 23:25:28 +0530 Subject: [PATCH 16/25] fix: include client_version and client_source in retried payments (#4826) --- crates/router/src/core/payments/helpers.rs | 4 ++-- crates/router/src/core/payments/retry.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index a58a6ae32b21..d11d0ef3c847 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -3576,8 +3576,8 @@ impl AttemptType { payment_method_billing_address_id: None, fingerprint_id: None, charge_id: None, - client_source: None, - client_version: None, + client_source: old_payment_attempt.client_source, + client_version: old_payment_attempt.client_version, } } diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index af41e3e4897b..82a08064a3ee 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -510,7 +510,8 @@ pub fn make_new_payment_attempt( mandate_id: old_payment_attempt.mandate_id, browser_info: old_payment_attempt.browser_info, payment_token: old_payment_attempt.payment_token, - + client_source: old_payment_attempt.client_source, + client_version: old_payment_attempt.client_version, created_at, modified_at, last_synced, From e9be4e22411d218009e6cd6c1a5ef9dc8fc430b7 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 00:15:00 +0000 Subject: [PATCH 17/25] chore(version): 2024.06.04.0 --- CHANGELOG.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d88ba7053e4..8d523897086a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,36 @@ All notable changes to HyperSwitch will be documented here. - - - +## 2024.06.04.0 + +### Features + +- **connector:** [AUTHORIZEDOTNET] Support payment_method_id in recurring mandate payment ([#4841](https://github.com/juspay/hyperswitch/pull/4841)) ([`a1788b8`](https://github.com/juspay/hyperswitch/commit/a1788b8da942f0e32a80b37eac4eecece2bef77d)) +- **consolidated-kafka-events:** Add consolidated kafka payment events ([#4798](https://github.com/juspay/hyperswitch/pull/4798)) ([`ccee1a9`](https://github.com/juspay/hyperswitch/commit/ccee1a9ce9e860bfa04e74329fb47fd73f010b23)) +- **multitenancy:** Add support for multitenancy and handle the same in router, producer, consumer, drainer and analytics ([#4630](https://github.com/juspay/hyperswitch/pull/4630)) ([`15d6c3e`](https://github.com/juspay/hyperswitch/commit/15d6c3e846a77dec6b6a5165d86044a9b9fd52f1)) +- **router:** Send `three_ds_requestor_url` in authentication_response for external 3ds flow ([#4828](https://github.com/juspay/hyperswitch/pull/4828)) ([`67f017f`](https://github.com/juspay/hyperswitch/commit/67f017f6f035b102ce7a0102b157a884ce9d4109)) +- **users:** Create config for TOTP Issuer ([#4776](https://github.com/juspay/hyperswitch/pull/4776)) ([`0cbb292`](https://github.com/juspay/hyperswitch/commit/0cbb2928bd054cb8e98c3811f397a837a8887486)) + +### Bug Fixes + +- **connector:** Make few fields optional in struct NetceteraErrorDetails ([#4827](https://github.com/juspay/hyperswitch/pull/4827)) ([`69b2f76`](https://github.com/juspay/hyperswitch/commit/69b2f76be7a2c0deba2c069a87c10a33253e2216)) +- Include client_version and client_source in retried payments ([#4826](https://github.com/juspay/hyperswitch/pull/4826)) ([`fa5f5a4`](https://github.com/juspay/hyperswitch/commit/fa5f5a4eddecd072f974738d2168cd0b7c277d2e)) + +### Refactors + +- **connector:** + - [Klarna] Add shipping Address in Klarna Session and Payment Request ([#4836](https://github.com/juspay/hyperswitch/pull/4836)) ([`8650077`](https://github.com/juspay/hyperswitch/commit/865007717c5c7e617ca1b447ea5f9bb3d274cac3)) + - Airwallex convert init payment to preprocessing ([#4842](https://github.com/juspay/hyperswitch/pull/4842)) ([`e5da133`](https://github.com/juspay/hyperswitch/commit/e5da133fe00b5736dc3c55bf4ee86fa77158dbe7)) +- **users:** Changes for Home and Signout APIs for TOTP Redis flows ([#4851](https://github.com/juspay/hyperswitch/pull/4851)) ([`d242850`](https://github.com/juspay/hyperswitch/commit/d242850b63173f314fb259451139464f09e0a9e9)) + +### Miscellaneous Tasks + +- **cypress:** Remove logs that expose `globalState` ([#4844](https://github.com/juspay/hyperswitch/pull/4844)) ([`d84e624`](https://github.com/juspay/hyperswitch/commit/d84e62441f39c165af7dc1c8d893344ff85c1711)) + +**Full Changelog:** [`2024.05.31.1...2024.06.04.0`](https://github.com/juspay/hyperswitch/compare/2024.05.31.1...2024.06.04.0) + +- - - + ## 2024.05.31.1 ### Features From ba0a1e95b72c0acf5bde81d424aa8fe220c40a22 Mon Sep 17 00:00:00 2001 From: chikke srujan <121822803+srujanchikke@users.noreply.github.com> Date: Tue, 4 Jun 2024 13:02:15 +0530 Subject: [PATCH 18/25] fix(connector): [Adyen]add required fields for afterpay clearpay (#4858) --- .../connector_configs/toml/development.toml | 2 - crates/connector_configs/toml/sandbox.toml | 2 - crates/router/src/configs/defaults.rs | 94 +++++++++++++++++++ 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/crates/connector_configs/toml/development.toml b/crates/connector_configs/toml/development.toml index 138fef0cdf30..0d40e81c4adb 100644 --- a/crates/connector_configs/toml/development.toml +++ b/crates/connector_configs/toml/development.toml @@ -127,8 +127,6 @@ merchant_secret="Source verification key" payment_method_type = "eps" [[adyen.bank_redirect]] payment_method_type = "blik" -[[adyen.bank_redirect]] - payment_method_type = "przelewy24" [[adyen.bank_redirect]] payment_method_type = "trustly" [[adyen.bank_redirect]] diff --git a/crates/connector_configs/toml/sandbox.toml b/crates/connector_configs/toml/sandbox.toml index 7236863745da..a71933870a51 100644 --- a/crates/connector_configs/toml/sandbox.toml +++ b/crates/connector_configs/toml/sandbox.toml @@ -127,8 +127,6 @@ merchant_secret="Source verification key" payment_method_type = "eps" [[adyen.bank_redirect]] payment_method_type = "blik" -[[adyen.bank_redirect]] - payment_method_type = "przelewy24" [[adyen.bank_redirect]] payment_method_type = "trustly" [[adyen.bank_redirect]] diff --git a/crates/router/src/configs/defaults.rs b/crates/router/src/configs/defaults.rs index c989e4c04c0d..7177488cb3cc 100644 --- a/crates/router/src/configs/defaults.rs +++ b/crates/router/src/configs/defaults.rs @@ -8110,6 +8110,100 @@ impl Default for super::settings::RequiredFields { ]), common : HashMap::new(), } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.line2".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line2".to_string(), + display_name: "line2".to_string(), + field_type: enums::FieldType::UserAddressLine2, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "GB".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ]), + common : HashMap::new(), + } ) ]), }, From 0ac20d24df0f845acc7786e7488f584a6dd074e8 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 08:40:45 +0000 Subject: [PATCH 19/25] chore(version): 2024.06.04.1 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d523897086a..3b2946f8baae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to HyperSwitch will be documented here. - - - +## 2024.06.04.1 + +### Bug Fixes + +- **connector:** [Adyen]add required fields for afterpay clearpay ([#4858](https://github.com/juspay/hyperswitch/pull/4858)) ([`ba0a1e9`](https://github.com/juspay/hyperswitch/commit/ba0a1e95b72c0acf5bde81d424aa8fe220c40a22)) + +**Full Changelog:** [`2024.06.04.0...2024.06.04.1`](https://github.com/juspay/hyperswitch/compare/2024.06.04.0...2024.06.04.1) + +- - - + ## 2024.06.04.0 ### Features From 7f75f941c18e5c1ce113a6e59f91a47e8302838d Mon Sep 17 00:00:00 2001 From: Kashif Date: Tue, 4 Jun 2024 16:22:47 +0530 Subject: [PATCH 20/25] refactor(api_models): rename Card struct for payouts to avoid overrides in auto generated open API spec (#4861) --- crates/api_models/src/payouts.rs | 6 +- crates/openapi/src/openapi.rs | 2 +- crates/router/src/connector/utils.rs | 2 +- crates/router/src/types/api/payouts.rs | 2 +- openapi/openapi_spec.json | 90 +++++++++++++++++++++++--- 5 files changed, 87 insertions(+), 15 deletions(-) diff --git a/crates/api_models/src/payouts.rs b/crates/api_models/src/payouts.rs index 69c50da79c23..2df40bd6757b 100644 --- a/crates/api_models/src/payouts.rs +++ b/crates/api_models/src/payouts.rs @@ -153,19 +153,19 @@ pub struct PayoutCreateRequest { #[derive(Debug, Clone, Deserialize, Serialize, ToSchema)] #[serde(rename_all = "snake_case")] pub enum PayoutMethodData { - Card(Card), + Card(CardPayout), Bank(Bank), Wallet(Wallet), } impl Default for PayoutMethodData { fn default() -> Self { - Self::Card(Card::default()) + Self::Card(CardPayout::default()) } } #[derive(Default, Eq, PartialEq, Clone, Debug, Deserialize, Serialize, ToSchema)] -pub struct Card { +pub struct CardPayout { /// The card number #[schema(value_type = String, example = "4242424242424242")] pub card_number: CardNumber, diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index 237cddcf94e7..c15704afa3be 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -440,7 +440,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::GiftCardData, api_models::payments::GiftCardDetails, api_models::payments::Address, - api_models::payouts::Card, + api_models::payouts::CardPayout, api_models::payouts::Wallet, api_models::payouts::Paypal, api_models::payouts::Venmo, diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 6737bbf3af0f..873e6f18d23c 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -1202,7 +1202,7 @@ pub trait CardData { } #[cfg(feature = "payouts")] -impl CardData for payouts::Card { +impl CardData for payouts::CardPayout { fn get_card_expiry_year_2_digit(&self) -> Result, errors::ConnectorError> { let binding = self.expiry_year.clone(); let year = binding.peek(); diff --git a/crates/router/src/types/api/payouts.rs b/crates/router/src/types/api/payouts.rs index d4417c5f1ccd..dfe7e949aa18 100644 --- a/crates/router/src/types/api/payouts.rs +++ b/crates/router/src/types/api/payouts.rs @@ -1,5 +1,5 @@ pub use api_models::payouts::{ - AchBankTransfer, BacsBankTransfer, Bank as BankPayout, Card as CardPayout, PayoutActionRequest, + AchBankTransfer, BacsBankTransfer, Bank as BankPayout, CardPayout, PayoutActionRequest, PayoutCreateRequest, PayoutCreateResponse, PayoutListConstraints, PayoutListFilterConstraints, PayoutListFilters, PayoutListResponse, PayoutMethodData, PayoutRequest, PayoutRetrieveBody, PayoutRetrieveRequest, PixBankTransfer, SepaBankTransfer, Wallet as WalletPayout, diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index f42481798a49..195fb7ed00e6 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -7054,9 +7054,10 @@ "type": "object", "required": [ "card_number", - "expiry_month", - "expiry_year", - "card_holder_name" + "card_exp_month", + "card_exp_year", + "card_holder_name", + "card_cvc" ], "properties": { "card_number": { @@ -7064,18 +7065,60 @@ "description": "The card number", "example": "4242424242424242" }, - "expiry_month": { + "card_exp_month": { "type": "string", - "description": "The card's expiry month" + "description": "The card's expiry month", + "example": "24" }, - "expiry_year": { + "card_exp_year": { "type": "string", - "description": "The card's expiry year" + "description": "The card's expiry year", + "example": "24" }, "card_holder_name": { "type": "string", "description": "The card holder's name", - "example": "John Doe" + "example": "John Test" + }, + "card_cvc": { + "type": "string", + "description": "The CVC number for the card", + "example": "242" + }, + "card_issuer": { + "type": "string", + "description": "The name of the issuer of card", + "example": "chase", + "nullable": true + }, + "card_network": { + "allOf": [ + { + "$ref": "#/components/schemas/CardNetwork" + } + ], + "nullable": true + }, + "card_type": { + "type": "string", + "example": "CREDIT", + "nullable": true + }, + "card_issuing_country": { + "type": "string", + "example": "INDIA", + "nullable": true + }, + "bank_code": { + "type": "string", + "example": "JP_AMEX", + "nullable": true + }, + "nick_name": { + "type": "string", + "description": "The card holder's nick name", + "example": "John Test", + "nullable": true } } }, @@ -7256,6 +7299,35 @@ "Maestro" ] }, + "CardPayout": { + "type": "object", + "required": [ + "card_number", + "expiry_month", + "expiry_year", + "card_holder_name" + ], + "properties": { + "card_number": { + "type": "string", + "description": "The card number", + "example": "4242424242424242" + }, + "expiry_month": { + "type": "string", + "description": "The card's expiry month" + }, + "expiry_year": { + "type": "string", + "description": "The card's expiry year" + }, + "card_holder_name": { + "type": "string", + "description": "The card holder's name", + "example": "John Doe" + } + } + }, "CardRedirectData": { "oneOf": [ { @@ -16752,7 +16824,7 @@ ], "properties": { "card": { - "$ref": "#/components/schemas/Card" + "$ref": "#/components/schemas/CardPayout" } } }, From 8096d5e577d892b3cdb7854dd100c3c8bab955d6 Mon Sep 17 00:00:00 2001 From: Swangi Kumari <85639103+swangi-kumari@users.noreply.github.com> Date: Tue, 4 Jun 2024 16:23:40 +0530 Subject: [PATCH 21/25] refactor(connector): [Adyen] handle redirection error response (#4862) --- crates/router/src/connector/adyen/transformers.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index bed99a9fb663..2489afd94dee 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -394,8 +394,9 @@ pub struct AdyenWebhookResponse { #[serde(rename_all = "camelCase")] pub struct RedirectionErrorResponse { result_code: AdyenStatus, - refusal_reason: String, + refusal_reason: Option, psp_reference: Option, + merchant_reference: Option, } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -3566,8 +3567,11 @@ pub fn get_redirection_error_response( storage_enums::AttemptStatus::foreign_from((is_manual_capture, response.result_code, pmt)); let error = Some(types::ErrorResponse { code: status.to_string(), - message: response.refusal_reason.clone(), - reason: Some(response.refusal_reason), + message: response + .refusal_reason + .clone() + .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), + reason: response.refusal_reason, status_code, attempt_status: None, connector_transaction_id: response.psp_reference.clone(), @@ -3579,7 +3583,10 @@ pub fn get_redirection_error_response( mandate_reference: None, connector_metadata: None, network_txn_id: None, - connector_response_reference_id: None, + connector_response_reference_id: response + .merchant_reference + .clone() + .or(response.psp_reference), incremental_authorization_allowed: None, charge_id: None, }; From 5414485866989c205830feec8ff79baecc834950 Mon Sep 17 00:00:00 2001 From: Mani Chandra <84711804+ThisIsMani@users.noreply.github.com> Date: Tue, 4 Jun 2024 16:43:08 +0530 Subject: [PATCH 22/25] feat(auth): Create and use `SinglePurposeOrLoginTokenAuth` (#4830) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- crates/router/src/consts/user.rs | 2 +- crates/router/src/core/user.rs | 12 +- crates/router/src/routes/app.rs | 2 +- crates/router/src/routes/user.rs | 27 +--- crates/router/src/services/authentication.rs | 118 ++++++++---------- .../src/services/authentication/blacklist.rs | 13 +- 6 files changed, 76 insertions(+), 98 deletions(-) diff --git a/crates/router/src/consts/user.rs b/crates/router/src/consts/user.rs index c7615aa4be4a..331c256e8a48 100644 --- a/crates/router/src/consts/user.rs +++ b/crates/router/src/consts/user.rs @@ -18,4 +18,4 @@ pub const MIN_PASSWORD_LENGTH: usize = 8; pub const REDIS_TOTP_PREFIX: &str = "TOTP_"; pub const REDIS_RECOVERY_CODE_PREFIX: &str = "RC_"; pub const REDIS_TOTP_SECRET_PREFIX: &str = "TOTP_SEC_"; -pub const REDIS_TOTP_SECRET_TTL_IN_SECS: i64 = 5 * 60; // 5 minutes +pub const REDIS_TOTP_SECRET_TTL_IN_SECS: i64 = 15 * 60; // 15 minutes diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs index 69a4cfc8a61c..cfc01afb91b1 100644 --- a/crates/router/src/core/user.rs +++ b/crates/router/src/core/user.rs @@ -1237,11 +1237,11 @@ pub async fn create_merchant_account( pub async fn list_merchants_for_user( state: SessionState, - user_from_token: Box, + user_from_token: auth::UserIdFromAuth, ) -> UserResponse> { let user_roles = state .store - .list_user_roles_by_user_id(user_from_token.get_user_id().as_str()) + .list_user_roles_by_user_id(user_from_token.user_id.as_str()) .await .change_context(UserErrors::InternalServerError)?; @@ -1697,7 +1697,7 @@ pub async fn reset_totp( pub async fn verify_totp( state: SessionState, - user_token: auth::UserFromSinglePurposeToken, + user_token: auth::UserIdFromAuth, req: user_api::VerifyTotpRequest, ) -> UserResponse { let user_from_db: domain::UserFromStorage = state @@ -1737,7 +1737,7 @@ pub async fn verify_totp( pub async fn update_totp( state: SessionState, - user_token: auth::UserFromSinglePurposeToken, + user_token: auth::UserIdFromAuth, req: user_api::VerifyTotpRequest, ) -> UserResponse<()> { let user_from_db: domain::UserFromStorage = state @@ -1806,7 +1806,7 @@ pub async fn update_totp( pub async fn generate_recovery_codes( state: SessionState, - user_token: auth::UserFromSinglePurposeToken, + user_token: auth::UserIdFromAuth, ) -> UserResponse { if !tfa_utils::check_totp_in_redis(&state, &user_token.user_id).await? { return Err(UserErrors::TotpRequired.into()); @@ -1838,7 +1838,7 @@ pub async fn generate_recovery_codes( pub async fn verify_recovery_code( state: SessionState, - user_token: auth::UserFromSinglePurposeToken, + user_token: auth::UserIdFromAuth, req: user_api::VerifyRecoveryCodeRequest, ) -> UserResponse { let user_from_db: domain::UserFromStorage = state diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 5af3a2bef25c..457e232ebd17 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -1316,7 +1316,7 @@ impl User { // The route is utilized to select an invitation from a list of merchants in an intermediate state .service( web::resource("/merchants_select/list") - .route(web::get().to(list_merchants_for_user_with_spt)), + .route(web::get().to(list_merchants_for_user)), ) .service(web::resource("/permission_info").route(web::get().to(get_authorization_info))) .service(web::resource("/update").route(web::post().to(update_user_account_details))) diff --git a/crates/router/src/routes/user.rs b/crates/router/src/routes/user.rs index e5cc7e4e2946..5325cbe437bf 100644 --- a/crates/router/src/routes/user.rs +++ b/crates/router/src/routes/user.rs @@ -318,24 +318,7 @@ pub async fn list_merchants_for_user(state: web::Data, req: HttpReques &req, (), |state, user, _, _| user_core::list_merchants_for_user(state, user), - &auth::DashboardNoPermissionAuth, - api_locking::LockAction::NotApplicable, - )) - .await -} - -pub async fn list_merchants_for_user_with_spt( - state: web::Data, - req: HttpRequest, -) -> HttpResponse { - let flow = Flow::UserMerchantAccountList; - Box::pin(api::server_wrap( - flow, - state, - &req, - (), - |state, user, _, _| user_core::list_merchants_for_user(state, user), - &auth::SinglePurposeJWTAuth(TokenPurpose::AcceptInvite), + &auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::AcceptInvite), api_locking::LockAction::NotApplicable, )) .await @@ -674,7 +657,7 @@ pub async fn totp_verify( &req, json_payload.into_inner(), |state, user, req_body, _| user_core::verify_totp(state, user, req_body), - &auth::SinglePurposeJWTAuth(TokenPurpose::TOTP), + &auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::TOTP), api_locking::LockAction::NotApplicable, )) .await @@ -692,7 +675,7 @@ pub async fn verify_recovery_code( &req, json_payload.into_inner(), |state, user, req_body, _| user_core::verify_recovery_code(state, user, req_body), - &auth::SinglePurposeJWTAuth(TokenPurpose::TOTP), + &auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::TOTP), api_locking::LockAction::NotApplicable, )) .await @@ -710,7 +693,7 @@ pub async fn totp_update( &req, json_payload.into_inner(), |state, user, req_body, _| user_core::update_totp(state, user, req_body), - &auth::SinglePurposeJWTAuth(TokenPurpose::TOTP), + &auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::TOTP), api_locking::LockAction::NotApplicable, )) .await @@ -724,7 +707,7 @@ pub async fn generate_recovery_codes(state: web::Data, req: HttpReques &req, (), |state, user, _, _| user_core::generate_recovery_codes(state, user), - &auth::SinglePurposeJWTAuth(TokenPurpose::TOTP), + &auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::TOTP), api_locking::LockAction::NotApplicable, )) .await diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index 28f9ccd1a778..72d0860eed9c 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -64,10 +64,15 @@ pub enum AuthenticationType { UserJwt { user_id: String, }, - SinglePurposeJWT { + SinglePurposeJwt { user_id: String, purpose: TokenPurpose, }, + SinglePurposeOrLoginJwt { + user_id: String, + purpose: Option, + role_id: Option, + }, MerchantId { merchant_id: String, }, @@ -107,7 +112,8 @@ impl AuthenticationType { | Self::WebhookAuth { merchant_id } => Some(merchant_id.as_ref()), Self::AdminApiKey | Self::UserJwt { .. } - | Self::SinglePurposeJWT { .. } + | Self::SinglePurposeJwt { .. } + | Self::SinglePurposeOrLoginJwt { .. } | Self::NoAuth => None, } } @@ -189,6 +195,19 @@ pub struct UserFromToken { pub org_id: String, } +pub struct UserIdFromAuth { + pub user_id: String, +} + +#[cfg(feature = "olap")] +#[derive(serde::Serialize, serde::Deserialize)] +pub struct SinglePurposeOrLoginToken { + pub user_id: String, + pub role_id: Option, + pub purpose: Option, + pub exp: u64, +} + pub trait AuthInfo { fn get_merchant_id(&self) -> Option<&str>; } @@ -205,23 +224,6 @@ impl AuthInfo for AuthenticationData { } } -pub trait GetUserIdFromAuth { - fn get_user_id(&self) -> String; -} - -impl GetUserIdFromAuth for UserFromToken { - fn get_user_id(&self) -> String { - self.user_id.clone() - } -} - -#[cfg(feature = "olap")] -impl GetUserIdFromAuth for UserFromSinglePurposeToken { - fn get_user_id(&self) -> String { - self.user_id.clone() - } -} - #[async_trait] pub trait AuthenticateAndFetch where @@ -355,7 +357,7 @@ where user_id: payload.user_id.clone(), origin: payload.origin.clone(), }, - AuthenticationType::SinglePurposeJWT { + AuthenticationType::SinglePurposeJwt { user_id: payload.user_id, purpose: payload.purpose, }, @@ -363,9 +365,13 @@ where } } +#[cfg(feature = "olap")] +#[derive(Debug)] +pub struct SinglePurposeOrLoginTokenAuth(pub TokenPurpose); + #[cfg(feature = "olap")] #[async_trait] -impl AuthenticateAndFetch, A> for SinglePurposeJWTAuth +impl AuthenticateAndFetch for SinglePurposeOrLoginTokenAuth where A: SessionStateInfo + Sync, { @@ -373,26 +379,35 @@ where &self, request_headers: &HeaderMap, state: &A, - ) -> RouterResult<(Box, AuthenticationType)> { - let payload = parse_jwt_payload::(request_headers, state).await?; + ) -> RouterResult<(UserIdFromAuth, AuthenticationType)> { + let payload = + parse_jwt_payload::(request_headers, state).await?; if payload.check_in_blacklist(state).await? { return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); } - if self.0 != payload.purpose { - return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); - } + let is_purpose_equal = payload + .purpose + .as_ref() + .is_some_and(|purpose| purpose == &self.0); - Ok(( - Box::new(UserFromSinglePurposeToken { - user_id: payload.user_id.clone(), - origin: payload.origin.clone(), - }), - AuthenticationType::SinglePurposeJWT { - user_id: payload.user_id, - purpose: payload.purpose, - }, - )) + let purpose_exists = payload.purpose.is_some(); + let role_id_exists = payload.role_id.is_some(); + + if is_purpose_equal && !role_id_exists || role_id_exists && !purpose_exists { + Ok(( + UserIdFromAuth { + user_id: payload.user_id.clone(), + }, + AuthenticationType::SinglePurposeOrLoginJwt { + user_id: payload.user_id, + purpose: payload.purpose, + role_id: payload.role_id, + }, + )) + } else { + Err(errors::ApiErrorResponse::InvalidJwtToken.into()) + } } } @@ -864,37 +879,6 @@ where } } -#[cfg(feature = "olap")] -#[async_trait] -impl AuthenticateAndFetch, A> for DashboardNoPermissionAuth -where - A: SessionStateInfo + Sync, -{ - async fn authenticate_and_fetch( - &self, - request_headers: &HeaderMap, - state: &A, - ) -> RouterResult<(Box, AuthenticationType)> { - let payload = parse_jwt_payload::(request_headers, state).await?; - if payload.check_in_blacklist(state).await? { - return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); - } - - Ok(( - Box::new(UserFromToken { - user_id: payload.user_id.clone(), - merchant_id: payload.merchant_id.clone(), - org_id: payload.org_id, - role_id: payload.role_id, - }), - AuthenticationType::MerchantJwt { - merchant_id: payload.merchant_id, - user_id: Some(payload.user_id), - }, - )) - } -} - #[cfg(feature = "olap")] #[async_trait] impl AuthenticateAndFetch<(), A> for DashboardNoPermissionAuth diff --git a/crates/router/src/services/authentication/blacklist.rs b/crates/router/src/services/authentication/blacklist.rs index 8a3aefd8fc04..0ac8c419ef69 100644 --- a/crates/router/src/services/authentication/blacklist.rs +++ b/crates/router/src/services/authentication/blacklist.rs @@ -7,7 +7,7 @@ use redis_interface::RedisConnectionPool; use super::AuthToken; #[cfg(feature = "olap")] -use super::SinglePurposeToken; +use super::{SinglePurposeOrLoginToken, SinglePurposeToken}; #[cfg(feature = "email")] use crate::consts::{EMAIL_TOKEN_BLACKLIST_PREFIX, EMAIL_TOKEN_TIME_IN_SECS}; use crate::{ @@ -166,3 +166,14 @@ impl BlackList for SinglePurposeToken { check_user_in_blacklist(state, &self.user_id, self.exp).await } } + +#[cfg(feature = "olap")] +#[async_trait::async_trait] +impl BlackList for SinglePurposeOrLoginToken { + async fn check_in_blacklist(&self, state: &A) -> RouterResult + where + A: SessionStateInfo + Sync, + { + check_user_in_blacklist(state, &self.user_id, self.exp).await + } +} From 1d36798399c118f7cb7af93935123634e1afd6a0 Mon Sep 17 00:00:00 2001 From: Sakil Mostak <73734619+Sakilmostak@users.noreply.github.com> Date: Tue, 4 Jun 2024 17:16:23 +0530 Subject: [PATCH 23/25] feat(cypress): Add service level testing for Payouts (#4744) --- .../ConnectorTest/00001-CustomerCreate.cy.js | 22 - .../00005-NoThreeDSManualCapture.cy.js | 206 --- .../e2e/ConnectorTest/00006-VoidPayment.cy.js | 130 -- .../ConnectorTest/00008-RefundPayment.cy.js | 990 ------------- .../e2e/ConnectorTest/00009-SyncRefund.cy.js | 72 - .../00010-CreateSingleuseMandate.cy.js | 129 -- .../00011-CreateMultiuseMandate.cy.js | 138 -- .../00012-ListAndRevokeMandate.cy.js | 59 - .../ConnectorTest/00013-SaveCardFlow.cy.js | 187 --- .../ConnectorTest/00014-ZeroAuthMandate.cy.js | 68 - .../00015-ThreeDSManualCapture.cy.js | 216 --- .../e2e/ConnectorUtils/BankOfAmerica.js | 381 ----- .../cypress/e2e/ConnectorUtils/Bluesnap.js | 425 ------ .../cypress/e2e/ConnectorUtils/Cybersource.js | 381 ----- .../cypress/e2e/ConnectorUtils/Nmi.js | 427 ------ .../cypress/e2e/ConnectorUtils/Paypal.js | 440 ------ .../cypress/e2e/ConnectorUtils/Stripe.js | 384 ----- .../e2e/PaymentTest/00000-AccountCreate.cy.js | 24 + .../PaymentTest/00001-CustomerCreate.cy.js | 20 + .../00002-ConnectorCreate.cy.js | 12 +- .../00003-NoThreeDSAutoCapture.cy.js | 72 +- .../00004-ThreeDSAutoCapture.cy.js | 51 +- .../00005-NoThreeDSManualCapture.cy.js | 263 ++++ .../e2e/PaymentTest/00006-VoidPayment.cy.js | 181 +++ .../00007-SyncPayment.cy.js | 47 +- .../e2e/PaymentTest/00008-RefundPayment.cy.js | 1304 +++++++++++++++++ .../e2e/PaymentTest/00009-SyncRefund.cy.js | 89 ++ .../00010-CreateSingleuseMandate.cy.js | 199 +++ .../00011-CreateMultiuseMandate.cy.js | 222 +++ .../00012-ListAndRevokeMandate.cy.js | 77 + .../e2e/PaymentTest/00013-SaveCardFlow.cy.js | 278 ++++ .../PaymentTest/00014-ZeroAuthMandate.cy.js | 113 ++ .../00015-ThreeDSManualCapture.cy.js | 272 ++++ .../00016-BankTransfers.cy.js | 8 +- .../00017-BankRedirect.cy.js | 30 +- .../{ConnectorUtils => PaymentUtils}/Adyen.js | 0 .../cypress/e2e/PaymentUtils/BankOfAmerica.js | 369 +++++ .../cypress/e2e/PaymentUtils/Bluesnap.js | 414 ++++++ .../Commons.js | 0 .../cypress/e2e/PaymentUtils/Cybersource.js | 370 +++++ cypress-tests/cypress/e2e/PaymentUtils/Nmi.js | 417 ++++++ .../cypress/e2e/PaymentUtils/Paypal.js | 429 ++++++ .../cypress/e2e/PaymentUtils/Stripe.js | 373 +++++ .../Trustpay.js | 0 .../{ConnectorUtils => PaymentUtils}/utils.js | 0 .../00000-AccountCreate.cy.js | 13 +- .../e2e/PayoutTest/00001-CustomerCreate.cy.js | 18 + .../PayoutTest/00002-ConnectorCreate.cy.js | 21 + .../e2e/PayoutTest/00003-CardTest.cy.js | 140 ++ .../cypress/e2e/PayoutUtils/Adyen.js | 59 + .../cypress/e2e/PayoutUtils/utils.js | 33 + .../fixtures/create-payout-confirm-body.json | 36 + cypress-tests/cypress/support/commands.js | 1262 +++++++++------- cypress-tests/cypress/support/e2e.js | 4 +- .../cypress/support/redirectionhandler.js | 38 +- cypress-tests/cypress/utils/State.js | 4 +- cypress-tests/package.json | 4 +- cypress-tests/readme.md | 2 +- 58 files changed, 6654 insertions(+), 5269 deletions(-) delete mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00001-CustomerCreate.cy.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00005-NoThreeDSManualCapture.cy.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00006-VoidPayment.cy.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00008-RefundPayment.cy.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00009-SyncRefund.cy.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00010-CreateSingleuseMandate.cy.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00011-CreateMultiuseMandate.cy.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00012-ListAndRevokeMandate.cy.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00013-SaveCardFlow.cy.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00014-ZeroAuthMandate.cy.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorTest/00015-ThreeDSManualCapture.cy.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorUtils/BankOfAmerica.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorUtils/Bluesnap.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorUtils/Cybersource.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorUtils/Nmi.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorUtils/Paypal.js delete mode 100644 cypress-tests/cypress/e2e/ConnectorUtils/Stripe.js create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00000-AccountCreate.cy.js create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00001-CustomerCreate.cy.js rename cypress-tests/cypress/e2e/{ConnectorTest => PaymentTest}/00002-ConnectorCreate.cy.js (78%) rename cypress-tests/cypress/e2e/{ConnectorTest => PaymentTest}/00003-NoThreeDSAutoCapture.cy.js (60%) rename cypress-tests/cypress/e2e/{ConnectorTest => PaymentTest}/00004-ThreeDSAutoCapture.cy.js (61%) create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00005-NoThreeDSManualCapture.cy.js create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00006-VoidPayment.cy.js rename cypress-tests/cypress/e2e/{ConnectorTest => PaymentTest}/00007-SyncPayment.cy.js (62%) create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00008-RefundPayment.cy.js create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00009-SyncRefund.cy.js create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00010-CreateSingleuseMandate.cy.js create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00011-CreateMultiuseMandate.cy.js create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00012-ListAndRevokeMandate.cy.js create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00013-SaveCardFlow.cy.js create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00014-ZeroAuthMandate.cy.js create mode 100644 cypress-tests/cypress/e2e/PaymentTest/00015-ThreeDSManualCapture.cy.js rename cypress-tests/cypress/e2e/{ConnectorTest => PaymentTest}/00016-BankTransfers.cy.js (93%) rename cypress-tests/cypress/e2e/{ConnectorTest => PaymentTest}/00017-BankRedirect.cy.js (95%) rename cypress-tests/cypress/e2e/{ConnectorUtils => PaymentUtils}/Adyen.js (100%) create mode 100644 cypress-tests/cypress/e2e/PaymentUtils/BankOfAmerica.js create mode 100644 cypress-tests/cypress/e2e/PaymentUtils/Bluesnap.js rename cypress-tests/cypress/e2e/{ConnectorUtils => PaymentUtils}/Commons.js (100%) create mode 100644 cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js create mode 100644 cypress-tests/cypress/e2e/PaymentUtils/Nmi.js create mode 100644 cypress-tests/cypress/e2e/PaymentUtils/Paypal.js create mode 100644 cypress-tests/cypress/e2e/PaymentUtils/Stripe.js rename cypress-tests/cypress/e2e/{ConnectorUtils => PaymentUtils}/Trustpay.js (100%) rename cypress-tests/cypress/e2e/{ConnectorUtils => PaymentUtils}/utils.js (100%) rename cypress-tests/cypress/e2e/{ConnectorTest => PayoutTest}/00000-AccountCreate.cy.js (83%) create mode 100644 cypress-tests/cypress/e2e/PayoutTest/00001-CustomerCreate.cy.js create mode 100644 cypress-tests/cypress/e2e/PayoutTest/00002-ConnectorCreate.cy.js create mode 100644 cypress-tests/cypress/e2e/PayoutTest/00003-CardTest.cy.js create mode 100644 cypress-tests/cypress/e2e/PayoutUtils/Adyen.js create mode 100644 cypress-tests/cypress/e2e/PayoutUtils/utils.js create mode 100644 cypress-tests/cypress/fixtures/create-payout-confirm-body.json diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00001-CustomerCreate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00001-CustomerCreate.cy.js deleted file mode 100644 index 5e8bcb5aa14c..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorTest/00001-CustomerCreate.cy.js +++ /dev/null @@ -1,22 +0,0 @@ -import customerCreateBody from "../../fixtures/create-customer-body.json"; -import State from "../../utils/State"; - -let globalState; - -describe("Customer Create flow test", () => { - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - }) - after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - it("customer-create-call-test", () => { - - cy.createCustomerCallTest(customerCreateBody, globalState); - - }); -}); \ No newline at end of file diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00005-NoThreeDSManualCapture.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00005-NoThreeDSManualCapture.cy.js deleted file mode 100644 index 4ee4483c961a..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorTest/00005-NoThreeDSManualCapture.cy.js +++ /dev/null @@ -1,206 +0,0 @@ -import captureBody from "../../fixtures/capture-flow-body.json"; -import confirmBody from "../../fixtures/confirm-body.json"; -import createConfirmPaymentBody from "../../fixtures/create-confirm-body.json"; -import createPaymentBody from "../../fixtures/create-payment-body.json"; -import State from "../../utils/State"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; - -let globalState; - -describe("Card - NoThreeDS Manual payment flow test", () => { - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - }) - - after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - - context("Card - NoThreeDS Manual Full Capture payment flow test", () => { - - context("payment Create and Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - }); - - context("Payment Create+Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create+confirm-payment-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.createConfirmPaymentTest(createConfirmPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - }); - - - }); - - context("Card - NoThreeDS Manual Partial Capture payment flow test - Create and Confirm", () => { - - context("payment Create and Payment Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - }); - - context("payment + Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create+confirm-payment-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.createConfirmPaymentTest(createConfirmPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - }); - - - }); -}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00006-VoidPayment.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00006-VoidPayment.cy.js deleted file mode 100644 index ef8157775688..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorTest/00006-VoidPayment.cy.js +++ /dev/null @@ -1,130 +0,0 @@ -import confirmBody from "../../fixtures/confirm-body.json"; -import createPaymentBody from "../../fixtures/create-payment-body.json"; -import voidBody from "../../fixtures/void-payment-body.json"; -import State from "../../utils/State"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; - -let globalState; - -describe("Card - NoThreeDS Manual payment flow test", () => { - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - }) - - after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - - context("Card - void payment in Requires_capture state flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("void-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Void"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.voidCallTest(voidBody, req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - context("Card - void payment in Requires_payment_method state flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("void-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Void"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.voidCallTest(voidBody, req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); }); - }); - - context("Card - void payment in Requires_payment_method state flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, false, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("void-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Void"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.voidCallTest(voidBody, req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); }); - }); -}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00008-RefundPayment.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00008-RefundPayment.cy.js deleted file mode 100644 index 672c5cf8f4aa..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorTest/00008-RefundPayment.cy.js +++ /dev/null @@ -1,990 +0,0 @@ -import captureBody from "../../fixtures/capture-flow-body.json"; -import confirmBody from "../../fixtures/confirm-body.json"; -import createConfirmPaymentBody from "../../fixtures/create-confirm-body.json"; -import citConfirmBody from "../../fixtures/create-mandate-cit.json"; -import mitConfirmBody from "../../fixtures/create-mandate-mit.json"; -import createPaymentBody from "../../fixtures/create-payment-body.json"; -import refundBody from "../../fixtures/refund-flow-body.json"; -import listRefundCall from "../../fixtures/list-refund-call-body.json"; -import State from "../../utils/State"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; - -let globalState; - -describe("Card - Refund flow test", () => { - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - - }) - - afterEach("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - - context("Card - Full Refund flow test for No-3DS", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - context("Card - Partial Refund flow test for No-3DS", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 1200, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 1200, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - context("Fully Refund Card-NoThreeDS payment flow test Create+Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create+confirm-payment-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createConfirmPaymentTest( createConfirmPaymentBody, req_data, res_data,"no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - }); - - context("Partially Refund Card-NoThreeDS payment flow test Create+Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create+confirm-payment-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createConfirmPaymentTest( createConfirmPaymentBody, req_data, res_data,"no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("sync-refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SyncRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.syncRefundCallTest(req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - context("Card - Full Refund for fully captured No-3DS payment", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("sync-refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SyncRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.syncRefundCallTest(req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - context("Card - Partial Refund for fully captured No-3DS payment", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("sync-refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SyncRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.syncRefundCallTest(req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - it("list-refund-call-test", () => { - cy.listRefundCallTest(listRefundCall, globalState); - }); - }); - - context("Card - Full Refund for partially captured No-3DS payment", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - - }); - - it("sync-refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SyncRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.syncRefundCallTest(req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - context("Card - partial Refund for partially captured No-3DS payment", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("sync-refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SyncRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.syncRefundCallTest(req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - context("Card - Full Refund for Create + Confirm Automatic CIT and MIT payment flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("Confirm No 3DS CIT", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["MandateMultiUseNo3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + req_data.card); - cy.citForMandatesCallTest(citConfirmBody, req_data, res_data, 7000, true, "automatic", "new_mandate", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 7000, true, "automatic", globalState); - }); - - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 7000, true, "automatic", globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 7000, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("sync-refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SyncRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.syncRefundCallTest(req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - -}); - - context("Card - Full Refund flow test for 3DS", () => { - - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - - }) - - afterEach("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("Confirm 3DS", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = confirmBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - context("Card - Partial Refund flow test for 3DS", () => { - - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("Confirm 3DS", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = confirmBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 1200, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 1200, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - context("Fully Refund Card-ThreeDS payment flow test Create+Confirm", () => { - - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create+confirm-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createConfirmPaymentTest(createConfirmPaymentBody, req_data, res_data, "three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = confirmBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - }); - - context("Partially Refund Card-ThreeDS payment flow test Create+Confirm", () => { - - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create+confirm-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createConfirmPaymentTest(createConfirmPaymentBody, req_data, res_data, "three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = confirmBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("sync-refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SyncRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.syncRefundCallTest(req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - }); - - context("Card - Full Refund for fully captured 3DS payment", () => { - - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("Confirm 3DS", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = confirmBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - }); - - context("Card - Partial Refund for fully captured 3DS payment", () => { - - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("Confirm 3DS", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = confirmBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 5000, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 1500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - - }); - - context("Card - Full Refund for partially captured 3DS payment", () => { - - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("Confirm 3DS", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = confirmBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - - }); - - context("Card - partial Refund for partially captured 3DS payment", () => { - - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("Confirm 3DS", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = confirmBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 50 , globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00009-SyncRefund.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00009-SyncRefund.cy.js deleted file mode 100644 index f0cdc9a68903..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorTest/00009-SyncRefund.cy.js +++ /dev/null @@ -1,72 +0,0 @@ -import confirmBody from "../../fixtures/confirm-body.json"; -import createPaymentBody from "../../fixtures/create-payment-body.json"; -import refundBody from "../../fixtures/refund-flow-body.json"; -import State from "../../utils/State"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; - -let globalState; - -describe("Card - Sync Refund flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - }) - - after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Refund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("sync-refund-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SyncRefund"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.syncRefundCallTest(req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - -}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00010-CreateSingleuseMandate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00010-CreateSingleuseMandate.cy.js deleted file mode 100644 index ec85017f55d3..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorTest/00010-CreateSingleuseMandate.cy.js +++ /dev/null @@ -1,129 +0,0 @@ -import captureBody from "../../fixtures/capture-flow-body.json"; -import citConfirmBody from "../../fixtures/create-mandate-cit.json"; -import mitConfirmBody from "../../fixtures/create-mandate-mit.json"; -import State from "../../utils/State"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; - -let globalState; - -describe("Card - SingleUse Mandates flow test", () => { - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - }) - - after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - - context("Card - NoThreeDS Create + Confirm Automatic CIT and MIT payment flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("Confirm No 3DS CIT", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["MandateSingleUseNo3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.citForMandatesCallTest(citConfirmBody, req_data, res_data, 7000, true, "automatic", "new_mandate", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 7000, true, "automatic", globalState); - }); - }); - - context("Card - NoThreeDS Create + Confirm Manual CIT and MIT payment flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("Confirm No 3DS CIT", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["MandateSingleUseNo3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.citForMandatesCallTest(citConfirmBody, req_data, res_data, 6500, true, "manual", "new_mandate", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("cit-capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 6500, true, "manual", globalState); - }); - - it("mit-capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("list-mandate-call-test", () => { - cy.listMandateCallTest(globalState); - }); - }); - - context("Card - ThreeDS Create + Confirm Manual CIT and MIT payment flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("Create No 3DS CIT", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["MandateSingleUseNo3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.citForMandatesCallTest(citConfirmBody, req_data, res_data, 6500, true, "manual", "new_mandate", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("cit-capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 7000, true, "automatic", globalState); - }); - - it("list-mandate-call-test", () => { - cy.listMandateCallTest(globalState); - }); - }); -}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00011-CreateMultiuseMandate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00011-CreateMultiuseMandate.cy.js deleted file mode 100644 index 3e14d69db88e..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorTest/00011-CreateMultiuseMandate.cy.js +++ /dev/null @@ -1,138 +0,0 @@ -import captureBody from "../../fixtures/capture-flow-body.json"; -import citConfirmBody from "../../fixtures/create-mandate-cit.json"; -import mitConfirmBody from "../../fixtures/create-mandate-mit.json"; -import State from "../../utils/State"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; - -let globalState; - -describe("Card - MultiUse Mandates flow test", () => { - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - }) - - after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - - - context("Card - NoThreeDS Create + Confirm Automatic CIT and MIT payment flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("Confirm No 3DS CIT", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["MandateMultiUseNo3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.citForMandatesCallTest(citConfirmBody, req_data, res_data, 7000, true, "automatic", "new_mandate", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 7000, true, "automatic", globalState); - }); - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 7000, true, "automatic", globalState); - }); - }); - - context("Card - NoThreeDS Create + Confirm Manual CIT and MIT payment flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("Confirm No 3DS CIT", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["MandateMultiUseNo3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.citForMandatesCallTest(citConfirmBody, req_data, res_data, 6500, true, "manual", "new_mandate", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("cit-capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Confirm No 3DS MIT 1", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 6500, true, "manual", globalState); - }); - - it("mit-capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Confirm No 3DS MIT 2", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 6500, true, "manual", globalState); - }); - - it("mit-capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - context("Card - ThreeDS Create + Confirm Manual CIT and MIT payment flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("Confirm No 3DS CIT", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["MandateMultiUseNo3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.citForMandatesCallTest(citConfirmBody, req_data, res_data, 6500, true, "manual", "new_mandate", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("cit-capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 6500, true, "automatic", globalState); - }); - }); -}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00012-ListAndRevokeMandate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00012-ListAndRevokeMandate.cy.js deleted file mode 100644 index 1f9782f22740..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorTest/00012-ListAndRevokeMandate.cy.js +++ /dev/null @@ -1,59 +0,0 @@ -import citConfirmBody from "../../fixtures/create-mandate-cit.json"; -import mitConfirmBody from "../../fixtures/create-mandate-mit.json"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; - -import State from "../../utils/State"; - -let globalState; - -describe("Card - SingleUse Mandates flow test", () => { - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - }) - - after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - - context("Card - NoThreeDS Create + Confirm Automatic CIT and MIT payment flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("Confirm No 3DS CIT", () => { - console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["MandateSingleUseNo3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - console.log("det -> " + data.card); - cy.citForMandatesCallTest(citConfirmBody, req_data, res_data, 7000, true, "automatic", "new_mandate", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 7000, true, "automatic", globalState); - }); - - it("list-mandate-call-test", () => { - cy.listMandateCallTest(globalState); - }); - - it("revoke-mandate-call-test", () => { - cy.revokeMandateCallTest(globalState); - }); - - it("revoke-revoked-mandate-call-test", () => { - cy.revokeMandateCallTest(globalState); - }); - }); - -}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00013-SaveCardFlow.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00013-SaveCardFlow.cy.js deleted file mode 100644 index 828fb5101ac7..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorTest/00013-SaveCardFlow.cy.js +++ /dev/null @@ -1,187 +0,0 @@ -import captureBody from "../../fixtures/capture-flow-body.json"; -import confirmBody from "../../fixtures/confirm-body.json"; -import createPaymentBody from "../../fixtures/create-payment-body.json"; -import createConfirmPaymentBody from "../../fixtures/create-confirm-body.json"; -import customerCreateBody from "../../fixtures/create-customer-body.json"; -import SaveCardConfirmBody from "../../fixtures/save-card-confirm-body.json"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; -import State from "../../utils/State"; -let globalState; - -describe("Card - SaveCard payment flow test", () => { - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - }) - - - context("Save card for NoThreeDS automatic capture payment- Create+Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("customer-create-call-test", () => { - cy.createCustomerCallTest(customerCreateBody, globalState); - }); - - it("create+confirm-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SaveCardUseNo3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createConfirmPaymentTest( createConfirmPaymentBody, req_data, res_data,"no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("retrieve-customerPM-call-test", () => { - cy.listCustomerPMCallTest(globalState); - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it ("confirm-save-card-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SaveCardUseNo3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.saveCardConfirmCallTest(SaveCardConfirmBody, req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - }); - - context("Save card for NoThreeDS manual full capture payment- Create+Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("customer-create-call-test", () => { - cy.createCustomerCallTest(customerCreateBody, globalState); - }); - - it("create+confirm-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SaveCardUseNo3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createConfirmPaymentTest( createConfirmPaymentBody, req_data, res_data,"no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("retrieve-customerPM-call-test", () => { - cy.listCustomerPMCallTest(globalState); - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest( createPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - - it ("confirm-save-card-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SaveCardUseNo3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.saveCardConfirmCallTest(SaveCardConfirmBody, req_data, res_data, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - context("Save card for NoThreeDS manual partial capture payment- Create + Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("customer-create-call-test", () => { - cy.createCustomerCallTest(customerCreateBody, globalState); - }); - - it("create+confirm-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SaveCardUseNo3DSAutoCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createConfirmPaymentTest( createConfirmPaymentBody, req_data, res_data,"no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("retrieve-customerPM-call-test", () => { - cy.listCustomerPMCallTest(globalState); - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest( createPaymentBody, req_data, res_data, "no_three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - - it ("confirm-save-card-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["SaveCardUseNo3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.saveCardConfirmCallTest(SaveCardConfirmBody,req_data, res_data,globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - }); - - -}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00014-ZeroAuthMandate.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00014-ZeroAuthMandate.cy.js deleted file mode 100644 index 7a0eba4b6ad9..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorTest/00014-ZeroAuthMandate.cy.js +++ /dev/null @@ -1,68 +0,0 @@ -import citConfirmBody from "../../fixtures/create-mandate-cit.json"; -import mitConfirmBody from "../../fixtures/create-mandate-mit.json"; -import State from "../../utils/State"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; - -let globalState; - -describe("Card - SingleUse Mandates flow test", () => { - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - }) - - after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - - context("Card - NoThreeDS Create + Confirm Automatic CIT and Single use MIT payment flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("Confirm No 3DS CIT", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["ZeroAuthMandate"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.citForMandatesCallTest(citConfirmBody, req_data, res_data, 0, true, "automatic", "setup_mandate", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 7000, true, "automatic", globalState); - }); - }); - context("Card - NoThreeDS Create + Confirm Automatic CIT and Multi use MIT payment flow test", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("Confirm No 3DS CIT", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["ZeroAuthMandate"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.citForMandatesCallTest(citConfirmBody, req_data, res_data, 0, true, "automatic", "setup_mandate", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 7000, true, "automatic", globalState); - }); - it("Confirm No 3DS MIT", () => { - cy.mitForMandatesCallTest(mitConfirmBody, 7000, true, "automatic", globalState); - }); - }); - -}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00015-ThreeDSManualCapture.cy.js b/cypress-tests/cypress/e2e/ConnectorTest/00015-ThreeDSManualCapture.cy.js deleted file mode 100644 index 50d136b59600..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorTest/00015-ThreeDSManualCapture.cy.js +++ /dev/null @@ -1,216 +0,0 @@ -import createPaymentBody from "../../fixtures/create-payment-body.json"; -import createConfirmPaymentBody from "../../fixtures/create-confirm-body.json"; -import confirmBody from "../../fixtures/confirm-body.json"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import State from "../../utils/State"; -import captureBody from "../../fixtures/capture-flow-body.json"; -import * as utils from "../ConnectorUtils/utils"; - -let globalState; - -describe("Card - ThreeDS Manual payment flow test", () => { - - - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { - globalState = new State(state); - }) - - }) - - afterEach("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - - context("Card - ThreeDS Manual Full Capture payment flow test", () => { - context("payment Create and Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = confirmBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - }); - - context("Payment Create+Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create+confirm-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createConfirmPaymentTest(createConfirmPaymentBody, req_data, res_data, "three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = createConfirmPaymentBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["Capture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - }); - - - }); - - context("Card - ThreeDS Manual Partial Capture payment flow test - Create and Confirm", () => { - context("payment Create and Payment Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("payment_methods-call-test", () => { - cy.paymentMethodsCallTest(globalState); - }); - - it("confirm-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = confirmBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - }); - - context("payment + Confirm", () => { - let should_continue = true; // variable that will be used to skip tests if a previous test fails - - beforeEach(function () { - if(!should_continue) { - this.skip(); - } - }); - - it("create+confirm-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSManualCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.createConfirmPaymentTest(createConfirmPaymentBody, req_data, res_data, "three_ds", "manual", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("Handle redirection", () => { - let expected_redirection = createConfirmPaymentBody["return_url"]; - cy.handleRedirection(globalState, expected_redirection); - }) - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - it("capture-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PartialCapture"]; - let req_data = data["Request"]; - let res_data = data["Response"]; - cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); - }); - - it("retrieve-payment-call-test", () => { - cy.retrievePaymentCallTest(globalState); - }); - - }); - - - }); -}); diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/BankOfAmerica.js b/cypress-tests/cypress/e2e/ConnectorUtils/BankOfAmerica.js deleted file mode 100644 index 5b3df0efc5d8..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorUtils/BankOfAmerica.js +++ /dev/null @@ -1,381 +0,0 @@ -const successfulNo3DSCardDetails = { - "card_number": "4242424242424242", - "card_exp_month": "01", - "card_exp_year": "25", - "card_holder_name": "joseph Doe", - "card_cvc": "123" - -}; - -const successfulThreeDSTestCardDetails = { - "card_number": "4000000000001091", - "card_exp_month": "01", - "card_exp_year": "25", - "card_holder_name": "joseph Doe", - "card_cvc": "123" -}; -export const connectorDetails = { - card_pm:{ - "PaymentIntent": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_payment_method" - } - } - }, - "3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "No3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "No3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "Capture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body":{ - "status": "succeeded", - "amount": 6500, - "amount_capturable": 0, - "amount_received": 6500, - - } - } - }, - "PartialCapture": { - "Request": { - - }, - "Response": { - "status": 200, - "body": { - "status": "partially_captured", - "amount": 6500, - "amount_capturable": 0, - "amount_received": 100, - } - - } - }, - "Void":{ - "Request": { - }, - "Response": { - "status": 200, - "body":{ - status: "cancelled" - - } - } - }, - "Refund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "pending", - } - - } - }, - "PartialRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "pending", - } - - } - }, - "SyncRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "pending", - } - - } - }, - "MandateSingleUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - - }, - "MandateSingleUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "requires_customer_action" - } - } - - }, - "MandateSingleUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "MandateSingleUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "MandateMultiUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "MandateMultiUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "MandateMultiUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "MandateMultiUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "ZeroAuthMandate": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "SaveCardUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "SaveCardUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - } - }; diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/Bluesnap.js b/cypress-tests/cypress/e2e/ConnectorUtils/Bluesnap.js deleted file mode 100644 index 17e040668adc..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorUtils/Bluesnap.js +++ /dev/null @@ -1,425 +0,0 @@ -const successfulNo3DSCardDetails = { - "card_number": "4242424242424242", - "card_exp_month": "10", - "card_exp_year": "30", - "card_holder_name": "John", - "card_cvc": "737" -}; - -const successfulThreeDSTestCardDetails = { - "card_number": "4000000000001091", - "card_exp_month": "10", - "card_exp_year": "30", - "card_holder_name": "Joseph", - "card_cvc": "737" -}; - -export const connectorDetails = { - card_pm:{ - "PaymentIntent": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_payment_method" - } - } - }, - "3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "No3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "No3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "Capture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body":{ - "status": "succeeded", - "amount": 6500, - "amount_capturable": 0, - "amount_received": 6500, - - } - } - }, - "PartialCapture": { - "Request": { - - }, - "Response": { - "status": 200, - "body": { - "status": "partially_captured", - "amount": 6500, - "amount_capturable": 0, - "amount_received": 100, - } - - } - }, - "Void":{ - "Request": { - }, - "Response": { - "status": 200, - "body":{ - status: "cancelled" - - } - } - }, - "Refund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded", - } - - } - }, - "PartialRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded", - } - - } - }, - "SyncRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded", - } - - } - }, - "MandateSingleUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by bluesnap" - } - } - } - - }, - "MandateSingleUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by bluesnap" - } - } - } - - }, - "MandateSingleUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by bluesnap" - } - } - } - }, - "MandateSingleUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by bluesnap" - } - } - } - }, - "MandateMultiUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by bluesnap" - } - } - } - }, - "MandateMultiUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by bluesnap" - } - } - } - }, - "MandateMultiUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by bluesnap" - } - } - } - }, - "MandateMultiUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by bluesnap" - } - } - } - }, - "ZeroAuthMandate": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 501, - "body": { - "error": { - "type": "invalid_request", - "message": "Setup Mandate flow for Bluesnap is not implemented", - "code": "IR_00", - } - } - } - }, - "SaveCardUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "SaveCardUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - } - }; \ No newline at end of file diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/Cybersource.js b/cypress-tests/cypress/e2e/ConnectorUtils/Cybersource.js deleted file mode 100644 index 67d2875df5c8..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorUtils/Cybersource.js +++ /dev/null @@ -1,381 +0,0 @@ -const successfulNo3DSCardDetails = { - "card_number": "4242424242424242", - "card_exp_month": "01", - "card_exp_year": "25", - "card_holder_name": "joseph Doe", - "card_cvc": "123" -}; - -const successfulThreeDSTestCardDetails = { - "card_number": "4000000000001091", - "card_exp_month": "01", - "card_exp_year": "25", - "card_holder_name": "joseph Doe", - "card_cvc": "123" -}; - -export const connectorDetails = { - card_pm:{ - "PaymentIntent": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_payment_method" - } - } - }, - "3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "No3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "No3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "Capture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body":{ - "status": "succeeded", - "amount": 6500, - "amount_capturable": 0, - "amount_received": 6500, - - } - } - }, - "PartialCapture": { - "Request": { - - }, - "Response": { - "status": 200, - "body": { - "status": "partially_captured", - "amount": 6500, - "amount_capturable": 0, - "amount_received": 100, - } - - } - }, - "Void":{ - "Request": { - }, - "Response": { - "status": 200, - "body":{ - status: "cancelled" - - } - } - }, - "Refund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "pending", - } - - } - }, - "PartialRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "pending", - } - - } - }, - "SyncRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "pending", - } - - } - }, - "MandateSingleUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - - }, - "MandateSingleUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "requires_customer_action" - } - } - - }, - "MandateSingleUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "MandateSingleUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "MandateMultiUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "MandateMultiUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "MandateMultiUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "MandateMultiUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "ZeroAuthMandate": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "SaveCardUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "SaveCardUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - } - }; \ No newline at end of file diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/Nmi.js b/cypress-tests/cypress/e2e/ConnectorUtils/Nmi.js deleted file mode 100644 index 27caaa82dc83..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorUtils/Nmi.js +++ /dev/null @@ -1,427 +0,0 @@ -const successfulNo3DSCardDetails = { - "card_number": "4000000000002503", - "card_exp_month": "08", - "card_exp_year": "25", - "card_holder_name": "joseph Doe", - "card_cvc": "999" -}; - -const successfulThreeDSTestCardDetails = { - "card_number": "4000000000002503", - "card_exp_month": "10", - "card_exp_year": "25", - "card_holder_name": "morino", - "card_cvc": "999" -}; - -export const connectorDetails = { - card_pm:{ - "PaymentIntent": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_payment_method" - } - } - }, - "3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "processing" - } - } - }, - "3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "processing" - } - } - }, - "No3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "processing" - } - } - }, - "No3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "processing" - } - } - }, - "Capture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body":{ - "status": "processing", - "amount": 6500, - "amount_capturable": 6500, - - } - } - }, - "PartialCapture": { - "Request": { - - }, - "Response": { - "status": 200, - "body": { - "status": "processing", - "amount": 6500, - "amount_capturable": 6500, - } - - } - }, - "Void":{ - "Request": { - }, - "Response": { - "status": 400, - "body":{ - "error":{ - "code":"IR_16", - "message":"You cannot cancel this payment because it has status processing", - "type":"invalid_request", - } - - } - } - }, - "Refund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "pending", - } - - } - }, - "PartialRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "pending", - } - - } - }, - "SyncRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded", - } - - } - }, - "MandateSingleUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by nmi" - } - } - } - - }, - "MandateSingleUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by nmi" - } - } - } - - }, - "MandateSingleUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by nmi" - } - } - } - }, - "MandateSingleUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by nmi" - } - } - } - }, - "MandateMultiUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by nmi" - } - } - } - }, - "MandateMultiUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by nmi" - } - } - } - }, - "MandateMultiUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by nmi" - } - } - } - }, - "MandateMultiUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by nmi" - } - } - } - }, - "ZeroAuthMandate": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 501, - "body": { - "error": { - "type": "invalid_request", - "message": "Setup Mandate flow for Nmi is not implemented", - "code": "IR_00", - } - } - } - }, - "SaveCardUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "processing" - } - } - }, - "SaveCardUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "processing" - } - } - }, - } - }; \ No newline at end of file diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/Paypal.js b/cypress-tests/cypress/e2e/ConnectorUtils/Paypal.js deleted file mode 100644 index 056b4b5e8ac3..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorUtils/Paypal.js +++ /dev/null @@ -1,440 +0,0 @@ -const successfulNo3DSCardDetails = { - "card_number": "4012000033330026", - "card_exp_month": "01", - "card_exp_year": "25", - "card_holder_name": "joseph Doe", - "card_cvc": "123" - -}; - -const successfulThreeDSTestCardDetails = { - "card_number": "4868719460707704", - "card_exp_month": "01", - "card_exp_year": "25", - "card_holder_name": "joseph Doe", - "card_cvc": "123" -}; - -export const connectorDetails = { - card_pm:{ - "PaymentIntent": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_payment_method" - } - } - }, - "3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "processing" - } - } - }, - "No3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "No3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "processing" - } - } - }, - "Capture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body":{ - "status": "processing", - "amount": 6500, - "amount_capturable": 6500, - "amount_received": 0, - - } - } - }, - "PartialCapture": { - "Request": { - - }, - "Response": { - "status": 200, - "body": { - "status": "processing", - "amount": 6500, - "amount_capturable": 6500, - "amount_received": 0, - } - - } - }, - "Void":{ - "Request": { - }, - "Response": { - "status": 200, - "body":{ - status: "cancelled" - - } - } - }, - "Refund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", - "code" : "IR_14" - }, - } - - } - }, - "PartialRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", - "code" : "IR_14" - }, - } - - } - }, - "SyncRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 400, - "body": { - "error": { - "type": "invalid_request", - "message": "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", - "code" : "IR_14" - }, - } - - } - }, - "MandateSingleUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by paypal" - } - } - } - - }, - "MandateSingleUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by paypal" - } - } - } - - }, - "MandateSingleUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by paypal" - } - } - } - }, - "MandateSingleUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by paypal" - } - } - } - }, - "MandateMultiUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by paypal" - } - } - } - }, - "MandateMultiUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by paypal" - } - } - } - }, - "MandateMultiUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by paypal" - } - } - } - }, - "MandateMultiUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 400, - "body":{ - "error": { - "type": "invalid_request", - "message": "Payment method type not supported", - "code": "HE_03", - "reason": "debit mandate payment is not supported by paypal" - } - } - } - }, - "ZeroAuthMandate": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 501, - "body": { - "error": { - "type": "invalid_request", - "message": "Setup Mandate flow for Paypal is not implemented", - "code": "IR_00", - } - } - } - }, - "SaveCardUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "processing" - } - } - }, - "SaveCardUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - } - }; - - diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/Stripe.js b/cypress-tests/cypress/e2e/ConnectorUtils/Stripe.js deleted file mode 100644 index 1003946dd736..000000000000 --- a/cypress-tests/cypress/e2e/ConnectorUtils/Stripe.js +++ /dev/null @@ -1,384 +0,0 @@ -const successfulTestCard = "4242424242424242"; -const successful3DSCard = "4000002760003184"; - -const successfulNo3DSCardDetails = { - "card_number": "4242424242424242", - "card_exp_month": "10", - "card_exp_year": "25", - "card_holder_name": "morino", - "card_cvc": "737" -}; - -const successfulThreeDSTestCardDetails = { - "card_number": "4000002760003184", - "card_exp_month": "10", - "card_exp_year": "25", - "card_holder_name": "morino", - "card_cvc": "737" -}; - -export const connectorDetails = { -card_pm:{ - "PaymentIntent": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_payment_method" - } - } - }, - "3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "No3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "No3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - "setup_future_usage": "on_session" - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "Capture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body":{ - "status": "succeeded", - "amount": 6500, - "amount_capturable": 0, - "amount_received": 6500, - - } - } - }, - "PartialCapture": { - "Request": { - - }, - "Response": { - "status": 200, - "body": { - "status": "partially_captured", - "amount": 6500, - "amount_capturable": 0, - "amount_received": 100, - } - - } - }, - "Void":{ - "Request": { - }, - "Response": { - "status": 200, - "body":{ - status: "cancelled" - - } - } - }, - "Refund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded", - } - - } - }, - "PartialRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded", - } - - } - }, - "SyncRefund": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "customer_acceptance": null, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded", - } - - } - }, - "MandateSingleUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - - }, - "MandateSingleUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "requires_customer_action" - } - } - - }, - "MandateSingleUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "MandateSingleUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "MandateMultiUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "MandateMultiUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "MandateMultiUse3DSAutoCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "MandateMultiUse3DSManualCapture": { - "Request": { - "card": successfulThreeDSTestCardDetails, - "currency": "USD", - "mandate_type": { - "multi_use": { - "amount": 8000, - "currency": "USD" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, - "ZeroAuthMandate": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "mandate_type": { - "single_use": { - "amount": 8000, - "currency": "USD" - } - } - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "SaveCardUseNo3DSAutoCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "succeeded" - } - } - }, - "SaveCardUseNo3DSManualCapture": { - "Request": { - "card": successfulNo3DSCardDetails, - "currency": "USD", - "setup_future_usage": "on_session", - "customer_acceptance": { - "acceptance_type": "offline", - "accepted_at": "1963-05-03T04:07:52.723Z", - "online": { - "ip_address": "127.0.0.1", - "user_agent": "amet irure esse" - } - }, - }, - "Response": { - "status": 200, - "body": { - "status": "requires_capture" - } - } - }, -} -}; \ No newline at end of file diff --git a/cypress-tests/cypress/e2e/PaymentTest/00000-AccountCreate.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00000-AccountCreate.cy.js new file mode 100644 index 000000000000..f58eb194db71 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00000-AccountCreate.cy.js @@ -0,0 +1,24 @@ +import apiKeyCreateBody from "../../fixtures/create-api-key-body.json"; +import merchantCreateBody from "../../fixtures/merchant-create-body.json"; +import State from "../../utils/State"; + +let globalState; +describe("Account Create flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + console.log("seeding globalState -> " + JSON.stringify(globalState)); + }); + }); + after("flush global state", () => { + console.log("flushing globalState -> " + JSON.stringify(globalState)); + cy.task("setGlobalState", globalState.data); + }); + + it("merchant-create-call-test", () => { + cy.merchantCreateCallTest(merchantCreateBody, globalState); + }); + it("api-key-create-call-test", () => { + cy.apiKeyCreateTest(apiKeyCreateBody, globalState); + }); +}); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00001-CustomerCreate.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00001-CustomerCreate.cy.js new file mode 100644 index 000000000000..996ec85ee31a --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00001-CustomerCreate.cy.js @@ -0,0 +1,20 @@ +import customerCreateBody from "../../fixtures/create-customer-body.json"; +import State from "../../utils/State"; + +let globalState; + +describe("Customer Create flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + console.log("seeding globalState -> " + JSON.stringify(globalState)); + }); + }); + after("flush global state", () => { + console.log("flushing globalState -> " + JSON.stringify(globalState)); + cy.task("setGlobalState", globalState.data); + }); + it("customer-create-call-test", () => { + cy.createCustomerCallTest(customerCreateBody, globalState); + }); +}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00002-ConnectorCreate.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00002-ConnectorCreate.cy.js similarity index 78% rename from cypress-tests/cypress/e2e/ConnectorTest/00002-ConnectorCreate.cy.js rename to cypress-tests/cypress/e2e/PaymentTest/00002-ConnectorCreate.cy.js index 927f0d020110..85a908da1a86 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00002-ConnectorCreate.cy.js +++ b/cypress-tests/cypress/e2e/PaymentTest/00002-ConnectorCreate.cy.js @@ -3,17 +3,15 @@ import State from "../../utils/State"; let globalState; describe("Connector Account Create flow test", () => { - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { + cy.task("getGlobalState").then((state) => { globalState = new State(state); - }) - }) + }); + }); after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) + cy.task("setGlobalState", globalState.data); + }); it("connector-create-call-test", () => { cy.createConnectorCallTest(createConnectorBody, globalState); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00003-NoThreeDSAutoCapture.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00003-NoThreeDSAutoCapture.cy.js similarity index 60% rename from cypress-tests/cypress/e2e/ConnectorTest/00003-NoThreeDSAutoCapture.cy.js rename to cypress-tests/cypress/e2e/PaymentTest/00003-NoThreeDSAutoCapture.cy.js index ec36fa16023e..2dfedbb83d31 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00003-NoThreeDSAutoCapture.cy.js +++ b/cypress-tests/cypress/e2e/PaymentTest/00003-NoThreeDSAutoCapture.cy.js @@ -2,39 +2,47 @@ import confirmBody from "../../fixtures/confirm-body.json"; import createConfirmPaymentBody from "../../fixtures/create-confirm-body.json"; import createPaymentBody from "../../fixtures/create-payment-body.json"; import State from "../../utils/State"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; let globalState; describe("Card - NoThreeDS payment flow test", () => { - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { + cy.task("getGlobalState").then((state) => { globalState = new State(state); - }) - }) + }); + }); after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) + cy.task("setGlobalState", globalState.data); + }); context("Card-NoThreeDS payment flow test Create and confirm", () => { let should_continue = true; // variable that will be used to skip tests if a previous test fails - beforeEach(function () { - if(!should_continue) { - this.skip(); - } + beforeEach(function () { + if (!should_continue) { + this.skip(); + } }); it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; let req_data = data["Request"]; let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); }); it("payment_methods-call-test", () => { @@ -42,35 +50,47 @@ describe("Card - NoThreeDS payment flow test", () => { }); it("Confirm No 3DS", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSAutoCapture"]; + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "No3DSAutoCapture" + ]; let req_data = data["Request"]; let res_data = data["Response"]; cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); + if (should_continue) + should_continue = utils.should_continue_further(res_data); }); it("retrieve-payment-call-test", () => { cy.retrievePaymentCallTest(globalState); }); - }); context("Card-NoThreeDS payment flow test Create+Confirm", () => { let should_continue = true; // variable that will be used to skip tests if a previous test fails - beforeEach(function () { - if(!should_continue) { - this.skip(); - } + beforeEach(function () { + if (!should_continue) { + this.skip(); + } }); it("create+confirm-payment-call-test", () => { console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSAutoCapture"]; + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "No3DSAutoCapture" + ]; let req_data = data["Request"]; let res_data = data["Response"]; - cy.createConfirmPaymentTest(createConfirmPaymentBody, req_data, res_data, "no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); }); it("retrieve-payment-call-test", () => { diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00004-ThreeDSAutoCapture.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00004-ThreeDSAutoCapture.cy.js similarity index 61% rename from cypress-tests/cypress/e2e/ConnectorTest/00004-ThreeDSAutoCapture.cy.js rename to cypress-tests/cypress/e2e/PaymentTest/00004-ThreeDSAutoCapture.cy.js index 3178170021c5..7ae900c833a8 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00004-ThreeDSAutoCapture.cy.js +++ b/cypress-tests/cypress/e2e/PaymentTest/00004-ThreeDSAutoCapture.cy.js @@ -1,39 +1,46 @@ import confirmBody from "../../fixtures/confirm-body.json"; import createPaymentBody from "../../fixtures/create-payment-body.json"; import State from "../../utils/State"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; let globalState; describe("Card - ThreeDS payment flow test", () => { let should_continue = true; // variable that will be used to skip tests if a previous test fails - beforeEach(function () { - if(!should_continue) { - this.skip(); - } + beforeEach(function () { + if (!should_continue) { + this.skip(); + } }); before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { + cy.task("getGlobalState").then((state) => { globalState = new State(state); - }) - - }) + }); + }); afterEach("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) - + cy.task("setGlobalState", globalState.data); + }); it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; let req_data = data["Request"]; let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); }); it("payment_methods-call-test", () => { @@ -41,16 +48,18 @@ describe("Card - ThreeDS payment flow test", () => { }); it("Confirm 3DS", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["3DSAutoCapture"]; + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "3DSAutoCapture" + ]; let req_data = data["Request"]; let res_data = data["Response"]; cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); + if (should_continue) + should_continue = utils.should_continue_further(res_data); }); it("Handle redirection", () => { let expected_redirection = confirmBody["return_url"]; cy.handleRedirection(globalState, expected_redirection); - }) - + }); }); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00005-NoThreeDSManualCapture.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00005-NoThreeDSManualCapture.cy.js new file mode 100644 index 000000000000..8fa262fd0694 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00005-NoThreeDSManualCapture.cy.js @@ -0,0 +1,263 @@ +import captureBody from "../../fixtures/capture-flow-body.json"; +import confirmBody from "../../fixtures/confirm-body.json"; +import createConfirmPaymentBody from "../../fixtures/create-confirm-body.json"; +import createPaymentBody from "../../fixtures/create-payment-body.json"; +import State from "../../utils/State"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; + +let globalState; + +describe("Card - NoThreeDS Manual payment flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + + after("flush global state", () => { + cy.task("setGlobalState", globalState.data); + }); + + context("Card - NoThreeDS Manual Full Capture payment flow test", () => { + context("payment Create and Confirm", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["No3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + }); + + context("Payment Create+Confirm", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create+confirm-payment-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["No3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + }); + }); + + context( + "Card - NoThreeDS Manual Partial Capture payment flow test - Create and Confirm", + () => { + context("payment Create and Payment Confirm", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["No3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest( + confirmBody, + req_data, + res_data, + true, + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PartialCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + }); + + context("payment + Confirm", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create+confirm-payment-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["No3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PartialCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + }); + }, + ); +}); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00006-VoidPayment.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00006-VoidPayment.cy.js new file mode 100644 index 000000000000..dea9d9e54061 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00006-VoidPayment.cy.js @@ -0,0 +1,181 @@ +import confirmBody from "../../fixtures/confirm-body.json"; +import createPaymentBody from "../../fixtures/create-payment-body.json"; +import voidBody from "../../fixtures/void-payment-body.json"; +import State from "../../utils/State"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; + +let globalState; + +describe("Card - NoThreeDS Manual payment flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + + after("flush global state", () => { + cy.task("setGlobalState", globalState.data); + }); + + context("Card - void payment in Requires_capture state flow test", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "No3DSManualCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("void-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Void" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.voidCallTest(voidBody, req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }); + + context( + "Card - void payment in Requires_payment_method state flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("void-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Void"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.voidCallTest(voidBody, req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }, + ); + + context( + "Card - void payment in Requires_payment_method state flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["No3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, false, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("void-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Void"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.voidCallTest(voidBody, req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }, + ); +}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00007-SyncPayment.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00007-SyncPayment.cy.js similarity index 62% rename from cypress-tests/cypress/e2e/ConnectorTest/00007-SyncPayment.cy.js rename to cypress-tests/cypress/e2e/PaymentTest/00007-SyncPayment.cy.js index 1920cdd09dbc..06e8b490ede2 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00007-SyncPayment.cy.js +++ b/cypress-tests/cypress/e2e/PaymentTest/00007-SyncPayment.cy.js @@ -1,36 +1,45 @@ import confirmBody from "../../fixtures/confirm-body.json"; import createPaymentBody from "../../fixtures/create-payment-body.json"; import State from "../../utils/State"; -import getConnectorDetails from "../ConnectorUtils/utils"; -import * as utils from "../ConnectorUtils/utils"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; let globalState; describe("Card - Sync payment flow test", () => { let should_continue = true; // variable that will be used to skip tests if a previous test fails - beforeEach(function () { - if(!should_continue) { - this.skip(); - } + beforeEach(function () { + if (!should_continue) { + this.skip(); + } }); before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { + cy.task("getGlobalState").then((state) => { globalState = new State(state); - }) - }) + }); + }); after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) + cy.task("setGlobalState", globalState.data); + }); it("create-payment-call-test", () => { - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["PaymentIntent"]; + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; let req_data = data["Request"]; let res_data = data["Response"]; - cy.createPaymentIntentTest(createPaymentBody, req_data, res_data, "no_three_ds", "automatic", globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); }); it("payment_methods-call-test", () => { @@ -39,16 +48,18 @@ describe("Card - Sync payment flow test", () => { it("confirm-call-test", () => { console.log("confirm -> " + globalState.get("connectorId")); - let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"]["No3DSAutoCapture"]; + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "No3DSAutoCapture" + ]; let req_data = data["Request"]; let res_data = data["Response"]; console.log("det -> " + data.card); cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); - if(should_continue) should_continue = utils.should_continue_further(res_data); + if (should_continue) + should_continue = utils.should_continue_further(res_data); }); it("retrieve-payment-call-test", () => { cy.retrievePaymentCallTest(globalState); }); - }); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00008-RefundPayment.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00008-RefundPayment.cy.js new file mode 100644 index 000000000000..f2d921d80ffc --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00008-RefundPayment.cy.js @@ -0,0 +1,1304 @@ +import captureBody from "../../fixtures/capture-flow-body.json"; +import confirmBody from "../../fixtures/confirm-body.json"; +import createConfirmPaymentBody from "../../fixtures/create-confirm-body.json"; +import citConfirmBody from "../../fixtures/create-mandate-cit.json"; +import mitConfirmBody from "../../fixtures/create-mandate-mit.json"; +import createPaymentBody from "../../fixtures/create-payment-body.json"; +import refundBody from "../../fixtures/refund-flow-body.json"; +import listRefundCall from "../../fixtures/list-refund-call-body.json"; +import State from "../../utils/State"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; + +let globalState; + +describe("Card - Refund flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + + afterEach("flush global state", () => { + cy.task("setGlobalState", globalState.data); + }); + + context("Card - Full Refund flow test for No-3DS", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "No3DSAutoCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Refund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }); + + context("Card - Partial Refund flow test for No-3DS", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "No3DSAutoCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 1200, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 1200, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }); + + context( + "Fully Refund Card-NoThreeDS payment flow test Create+Confirm", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create+confirm-payment-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["No3DSAutoCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Refund"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }, + ); + + context( + "Partially Refund Card-NoThreeDS payment flow test Create+Confirm", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create+confirm-payment-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["No3DSAutoCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PartialRefund"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PartialRefund"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("sync-refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["SyncRefund"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.syncRefundCallTest(req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }, + ); + + context("Card - Full Refund for fully captured No-3DS payment", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "No3DSManualCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Capture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Refund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("sync-refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "SyncRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.syncRefundCallTest(req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }); + + context("Card - Partial Refund for fully captured No-3DS payment", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "No3DSManualCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Capture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("sync-refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "SyncRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.syncRefundCallTest(req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + it("list-refund-call-test", () => { + cy.listRefundCallTest(listRefundCall, globalState); + }); + }); + + context("Card - Full Refund for partially captured No-3DS payment", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "No3DSManualCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Refund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("sync-refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "SyncRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.syncRefundCallTest(req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }); + + context("Card - partial Refund for partially captured No-3DS payment", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "No3DSManualCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("sync-refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "SyncRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.syncRefundCallTest(req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }); + + context( + "Card - Full Refund for Create + Confirm Automatic CIT and MIT payment flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("Confirm No 3DS CIT", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["MandateMultiUseNo3DSAutoCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + req_data.card); + cy.citForMandatesCallTest( + citConfirmBody, + req_data, + res_data, + 7000, + true, + "automatic", + "new_mandate", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 7000, + true, + "automatic", + globalState, + ); + }); + + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 7000, + true, + "automatic", + globalState, + ); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Refund"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 7000, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("sync-refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["SyncRefund"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.syncRefundCallTest(req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }, + ); +}); + +context("Card - Full Refund flow test for 3DS", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + + afterEach("flush global state", () => { + cy.task("setGlobalState", globalState.data); + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm 3DS", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "3DSAutoCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = confirmBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Refund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); +}); + +context("Card - Partial Refund flow test for 3DS", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm 3DS", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "3DSAutoCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = confirmBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 1200, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 1200, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); +}); + +context("Fully Refund Card-ThreeDS payment flow test Create+Confirm", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create+confirm-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "3DSAutoCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = confirmBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Refund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); +}); + +context( + "Partially Refund Card-ThreeDS payment flow test Create+Confirm", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create+confirm-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "3DSAutoCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = confirmBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 3000, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("sync-refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "SyncRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.syncRefundCallTest(req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }, +); + +context("Card - Full Refund for fully captured 3DS payment", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm 3DS", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "3DSManualCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = confirmBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Capture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Refund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); +}); + +context("Card - Partial Refund for fully captured 3DS payment", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm 3DS", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "3DSManualCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = confirmBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Capture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Refund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 5000, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Refund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 1500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); +}); + +context("Card - Full Refund for partially captured 3DS payment", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm 3DS", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "3DSManualCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = confirmBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Refund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); +}); + +context("Card - partial Refund for partially captured 3DS payment", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("Confirm 3DS", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "3DSManualCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = confirmBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PartialCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Refund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 50, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); +}); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00009-SyncRefund.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00009-SyncRefund.cy.js new file mode 100644 index 000000000000..0f14dad72d66 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00009-SyncRefund.cy.js @@ -0,0 +1,89 @@ +import confirmBody from "../../fixtures/confirm-body.json"; +import createPaymentBody from "../../fixtures/create-payment-body.json"; +import refundBody from "../../fixtures/refund-flow-body.json"; +import State from "../../utils/State"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; + +let globalState; + +describe("Card - Sync Refund flow test", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + + after("flush global state", () => { + cy.task("setGlobalState", globalState.data); + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "PaymentIntent" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "No3DSAutoCapture" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "Refund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.refundCallTest(refundBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("sync-refund-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))["card_pm"][ + "SyncRefund" + ]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.syncRefundCallTest(req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); +}); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00010-CreateSingleuseMandate.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00010-CreateSingleuseMandate.cy.js new file mode 100644 index 000000000000..00faf6dfcba7 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00010-CreateSingleuseMandate.cy.js @@ -0,0 +1,199 @@ +import captureBody from "../../fixtures/capture-flow-body.json"; +import citConfirmBody from "../../fixtures/create-mandate-cit.json"; +import mitConfirmBody from "../../fixtures/create-mandate-mit.json"; +import State from "../../utils/State"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; + +let globalState; + +describe("Card - SingleUse Mandates flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + + after("flush global state", () => { + cy.task("setGlobalState", globalState.data); + }); + + context( + "Card - NoThreeDS Create + Confirm Automatic CIT and MIT payment flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("Confirm No 3DS CIT", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["MandateSingleUseNo3DSAutoCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.citForMandatesCallTest( + citConfirmBody, + req_data, + res_data, + 7000, + true, + "automatic", + "new_mandate", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 7000, + true, + "automatic", + globalState, + ); + }); + }, + ); + + context( + "Card - NoThreeDS Create + Confirm Manual CIT and MIT payment flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("Confirm No 3DS CIT", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["MandateSingleUseNo3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.citForMandatesCallTest( + citConfirmBody, + req_data, + res_data, + 6500, + true, + "manual", + "new_mandate", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("cit-capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 6500, + true, + "manual", + globalState, + ); + }); + + it("mit-capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("list-mandate-call-test", () => { + cy.listMandateCallTest(globalState); + }); + }, + ); + + context( + "Card - ThreeDS Create + Confirm Manual CIT and MIT payment flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("Create No 3DS CIT", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["MandateSingleUseNo3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.citForMandatesCallTest( + citConfirmBody, + req_data, + res_data, + 6500, + true, + "manual", + "new_mandate", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("cit-capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 7000, + true, + "automatic", + globalState, + ); + }); + + it("list-mandate-call-test", () => { + cy.listMandateCallTest(globalState); + }); + }, + ); +}); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00011-CreateMultiuseMandate.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00011-CreateMultiuseMandate.cy.js new file mode 100644 index 000000000000..1dee7ea901f0 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00011-CreateMultiuseMandate.cy.js @@ -0,0 +1,222 @@ +import captureBody from "../../fixtures/capture-flow-body.json"; +import citConfirmBody from "../../fixtures/create-mandate-cit.json"; +import mitConfirmBody from "../../fixtures/create-mandate-mit.json"; +import State from "../../utils/State"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; + +let globalState; + +describe("Card - MultiUse Mandates flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + + after("flush global state", () => { + cy.task("setGlobalState", globalState.data); + }); + + context( + "Card - NoThreeDS Create + Confirm Automatic CIT and MIT payment flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("Confirm No 3DS CIT", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["MandateMultiUseNo3DSAutoCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.citForMandatesCallTest( + citConfirmBody, + req_data, + res_data, + 7000, + true, + "automatic", + "new_mandate", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 7000, + true, + "automatic", + globalState, + ); + }); + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 7000, + true, + "automatic", + globalState, + ); + }); + }, + ); + + context( + "Card - NoThreeDS Create + Confirm Manual CIT and MIT payment flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("Confirm No 3DS CIT", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["MandateMultiUseNo3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.citForMandatesCallTest( + citConfirmBody, + req_data, + res_data, + 6500, + true, + "manual", + "new_mandate", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("cit-capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Confirm No 3DS MIT 1", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 6500, + true, + "manual", + globalState, + ); + }); + + it("mit-capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Confirm No 3DS MIT 2", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 6500, + true, + "manual", + globalState, + ); + }); + + it("mit-capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }, + ); + + context( + "Card - ThreeDS Create + Confirm Manual CIT and MIT payment flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("Confirm No 3DS CIT", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["MandateMultiUseNo3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.citForMandatesCallTest( + citConfirmBody, + req_data, + res_data, + 6500, + true, + "manual", + "new_mandate", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("cit-capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 6500, + true, + "automatic", + globalState, + ); + }); + }, + ); +}); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00012-ListAndRevokeMandate.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00012-ListAndRevokeMandate.cy.js new file mode 100644 index 000000000000..28ffacb829c8 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00012-ListAndRevokeMandate.cy.js @@ -0,0 +1,77 @@ +import citConfirmBody from "../../fixtures/create-mandate-cit.json"; +import mitConfirmBody from "../../fixtures/create-mandate-mit.json"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; + +import State from "../../utils/State"; + +let globalState; + +describe("Card - SingleUse Mandates flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + + after("flush global state", () => { + cy.task("setGlobalState", globalState.data); + }); + + context( + "Card - NoThreeDS Create + Confirm Automatic CIT and MIT payment flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("Confirm No 3DS CIT", () => { + console.log("confirm -> " + globalState.get("connectorId")); + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["MandateSingleUseNo3DSAutoCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + console.log("det -> " + data.card); + cy.citForMandatesCallTest( + citConfirmBody, + req_data, + res_data, + 7000, + true, + "automatic", + "new_mandate", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 7000, + true, + "automatic", + globalState, + ); + }); + + it("list-mandate-call-test", () => { + cy.listMandateCallTest(globalState); + }); + + it("revoke-mandate-call-test", () => { + cy.revokeMandateCallTest(globalState); + }); + + it("revoke-revoked-mandate-call-test", () => { + cy.revokeMandateCallTest(globalState); + }); + }, + ); +}); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00013-SaveCardFlow.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00013-SaveCardFlow.cy.js new file mode 100644 index 000000000000..c31a24e39318 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00013-SaveCardFlow.cy.js @@ -0,0 +1,278 @@ +import captureBody from "../../fixtures/capture-flow-body.json"; +import confirmBody from "../../fixtures/confirm-body.json"; +import createPaymentBody from "../../fixtures/create-payment-body.json"; +import createConfirmPaymentBody from "../../fixtures/create-confirm-body.json"; +import customerCreateBody from "../../fixtures/create-customer-body.json"; +import SaveCardConfirmBody from "../../fixtures/save-card-confirm-body.json"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; +import State from "../../utils/State"; +let globalState; + +describe("Card - SaveCard payment flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + + context( + "Save card for NoThreeDS automatic capture payment- Create+Confirm", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("customer-create-call-test", () => { + cy.createCustomerCallTest(customerCreateBody, globalState); + }); + + it("create+confirm-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["SaveCardUseNo3DSAutoCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("retrieve-customerPM-call-test", () => { + cy.listCustomerPMCallTest(globalState); + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("confirm-save-card-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["SaveCardUseNo3DSAutoCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.saveCardConfirmCallTest( + SaveCardConfirmBody, + req_data, + res_data, + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }, + ); + + context( + "Save card for NoThreeDS manual full capture payment- Create+Confirm", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("customer-create-call-test", () => { + cy.createCustomerCallTest(customerCreateBody, globalState); + }); + + it("create+confirm-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["SaveCardUseNo3DSAutoCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("retrieve-customerPM-call-test", () => { + cy.listCustomerPMCallTest(globalState); + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("confirm-save-card-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["SaveCardUseNo3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.saveCardConfirmCallTest( + SaveCardConfirmBody, + req_data, + res_data, + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }, + ); + + context( + "Save card for NoThreeDS manual partial capture payment- Create + Confirm", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("customer-create-call-test", () => { + cy.createCustomerCallTest(customerCreateBody, globalState); + }); + + it("create+confirm-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["SaveCardUseNo3DSAutoCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "no_three_ds", + "automatic", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("retrieve-customerPM-call-test", () => { + cy.listCustomerPMCallTest(globalState); + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "no_three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("confirm-save-card-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["SaveCardUseNo3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.saveCardConfirmCallTest( + SaveCardConfirmBody, + req_data, + res_data, + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PartialCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + }, + ); +}); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00014-ZeroAuthMandate.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00014-ZeroAuthMandate.cy.js new file mode 100644 index 000000000000..d90d86d8c412 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00014-ZeroAuthMandate.cy.js @@ -0,0 +1,113 @@ +import citConfirmBody from "../../fixtures/create-mandate-cit.json"; +import mitConfirmBody from "../../fixtures/create-mandate-mit.json"; +import State from "../../utils/State"; +import getConnectorDetails from "../PaymentUtils/utils"; +import * as utils from "../PaymentUtils/utils"; + +let globalState; + +describe("Card - SingleUse Mandates flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + + after("flush global state", () => { + cy.task("setGlobalState", globalState.data); + }); + + context( + "Card - NoThreeDS Create + Confirm Automatic CIT and Single use MIT payment flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("Confirm No 3DS CIT", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["ZeroAuthMandate"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.citForMandatesCallTest( + citConfirmBody, + req_data, + res_data, + 0, + true, + "automatic", + "setup_mandate", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 7000, + true, + "automatic", + globalState, + ); + }); + }, + ); + context( + "Card - NoThreeDS Create + Confirm Automatic CIT and Multi use MIT payment flow test", + () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("Confirm No 3DS CIT", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["ZeroAuthMandate"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.citForMandatesCallTest( + citConfirmBody, + req_data, + res_data, + 0, + true, + "automatic", + "setup_mandate", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 7000, + true, + "automatic", + globalState, + ); + }); + it("Confirm No 3DS MIT", () => { + cy.mitForMandatesCallTest( + mitConfirmBody, + 7000, + true, + "automatic", + globalState, + ); + }); + }, + ); +}); diff --git a/cypress-tests/cypress/e2e/PaymentTest/00015-ThreeDSManualCapture.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00015-ThreeDSManualCapture.cy.js new file mode 100644 index 000000000000..0aa4ad104923 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentTest/00015-ThreeDSManualCapture.cy.js @@ -0,0 +1,272 @@ +import createPaymentBody from "../../fixtures/create-payment-body.json"; +import createConfirmPaymentBody from "../../fixtures/create-confirm-body.json"; +import confirmBody from "../../fixtures/confirm-body.json"; +import getConnectorDetails from "../PaymentUtils/utils"; +import State from "../../utils/State"; +import captureBody from "../../fixtures/capture-flow-body.json"; +import * as utils from "../PaymentUtils/utils"; + +let globalState; + +describe("Card - ThreeDS Manual payment flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + + afterEach("flush global state", () => { + cy.task("setGlobalState", globalState.data); + }); + + context("Card - ThreeDS Manual Full Capture payment flow test", () => { + context("payment Create and Confirm", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.confirmCallTest(confirmBody, req_data, res_data, true, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = confirmBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + }); + + context("Payment Create+Confirm", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create+confirm-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = createConfirmPaymentBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Capture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.captureCallTest(captureBody, req_data, res_data, 6500, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + }); + }); + + context( + "Card - ThreeDS Manual Partial Capture payment flow test - Create and Confirm", + () => { + context("payment Create and Payment Confirm", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PaymentIntent"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createPaymentIntentTest( + createPaymentBody, + req_data, + res_data, + "three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("payment_methods-call-test", () => { + cy.paymentMethodsCallTest(globalState); + }); + + it("confirm-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.confirmCallTest( + confirmBody, + req_data, + res_data, + true, + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = confirmBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PartialCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + }); + + context("payment + Confirm", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + it("create+confirm-payment-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["3DSManualCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPaymentTest( + createConfirmPaymentBody, + req_data, + res_data, + "three_ds", + "manual", + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("Handle redirection", () => { + let expected_redirection = createConfirmPaymentBody["return_url"]; + cy.handleRedirection(globalState, expected_redirection); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + + it("capture-call-test", () => { + let data = getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["PartialCapture"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.captureCallTest(captureBody, req_data, res_data, 100, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payment-call-test", () => { + cy.retrievePaymentCallTest(globalState); + }); + }); + }, + ); +}); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00016-BankTransfers.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00016-BankTransfers.cy.js similarity index 93% rename from cypress-tests/cypress/e2e/ConnectorTest/00016-BankTransfers.cy.js rename to cypress-tests/cypress/e2e/PaymentTest/00016-BankTransfers.cy.js index da4fab34b8e5..6e132f5a1b6b 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00016-BankTransfers.cy.js +++ b/cypress-tests/cypress/e2e/PaymentTest/00016-BankTransfers.cy.js @@ -1,7 +1,7 @@ import confirmBody from "../../fixtures/confirm-body.json"; import createPaymentBody from "../../fixtures/create-payment-body.json"; import State from "../../utils/State"; -import getConnectorDetails, * as utils from "../ConnectorUtils/utils"; +import getConnectorDetails, * as utils from "../PaymentUtils/utils"; let globalState; @@ -37,7 +37,7 @@ describe("Bank Transfers", () => { res_data, "three_ds", "automatic", - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -58,7 +58,7 @@ describe("Bank Transfers", () => { req_data, res_data, true, - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -70,7 +70,7 @@ describe("Bank Transfers", () => { cy.handleBankTransferRedirection( globalState, payment_method_type, - expected_redirection + expected_redirection, ); }); }); diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00017-BankRedirect.cy.js b/cypress-tests/cypress/e2e/PaymentTest/00017-BankRedirect.cy.js similarity index 95% rename from cypress-tests/cypress/e2e/ConnectorTest/00017-BankRedirect.cy.js rename to cypress-tests/cypress/e2e/PaymentTest/00017-BankRedirect.cy.js index 3a636b2020a0..0706cf15b13f 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00017-BankRedirect.cy.js +++ b/cypress-tests/cypress/e2e/PaymentTest/00017-BankRedirect.cy.js @@ -1,7 +1,7 @@ import confirmBody from "../../fixtures/confirm-body.json"; import createPaymentBody from "../../fixtures/create-payment-body.json"; import State from "../../utils/State"; -import getConnectorDetails, * as utils from "../ConnectorUtils/utils"; +import getConnectorDetails, * as utils from "../PaymentUtils/utils"; let globalState; @@ -41,7 +41,7 @@ describe("Bank Redirect tests", () => { res_data, "three_ds", "automatic", - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -62,7 +62,7 @@ describe("Bank Redirect tests", () => { req_data, res_data, true, - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -89,7 +89,7 @@ describe("Bank Redirect tests", () => { res_data, "three_ds", "automatic", - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -110,7 +110,7 @@ describe("Bank Redirect tests", () => { req_data, res_data, true, - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -123,7 +123,7 @@ describe("Bank Redirect tests", () => { cy.handleBankRedirectRedirection( globalState, payment_method_type, - expected_redirection + expected_redirection, ); }); }); @@ -149,7 +149,7 @@ describe("Bank Redirect tests", () => { res_data, "three_ds", "automatic", - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -170,7 +170,7 @@ describe("Bank Redirect tests", () => { req_data, res_data, true, - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -183,7 +183,7 @@ describe("Bank Redirect tests", () => { cy.handleBankRedirectRedirection( globalState, payment_method_type, - expected_redirection + expected_redirection, ); }); }); @@ -208,7 +208,7 @@ describe("Bank Redirect tests", () => { res_data, "three_ds", "automatic", - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -229,7 +229,7 @@ describe("Bank Redirect tests", () => { req_data, res_data, true, - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -242,7 +242,7 @@ describe("Bank Redirect tests", () => { cy.handleBankRedirectRedirection( globalState, payment_method_type, - expected_redirection + expected_redirection, ); }); }); @@ -267,7 +267,7 @@ describe("Bank Redirect tests", () => { res_data, "three_ds", "automatic", - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -288,7 +288,7 @@ describe("Bank Redirect tests", () => { req_data, res_data, true, - globalState + globalState, ); if (should_continue) should_continue = utils.should_continue_further(res_data); @@ -301,7 +301,7 @@ describe("Bank Redirect tests", () => { cy.handleBankRedirectRedirection( globalState, payment_method_type, - expected_redirection + expected_redirection, ); }); }); diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/Adyen.js b/cypress-tests/cypress/e2e/PaymentUtils/Adyen.js similarity index 100% rename from cypress-tests/cypress/e2e/ConnectorUtils/Adyen.js rename to cypress-tests/cypress/e2e/PaymentUtils/Adyen.js diff --git a/cypress-tests/cypress/e2e/PaymentUtils/BankOfAmerica.js b/cypress-tests/cypress/e2e/PaymentUtils/BankOfAmerica.js new file mode 100644 index 000000000000..a34190c20924 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentUtils/BankOfAmerica.js @@ -0,0 +1,369 @@ +const successfulNo3DSCardDetails = { + card_number: "4242424242424242", + card_exp_month: "01", + card_exp_year: "25", + card_holder_name: "joseph Doe", + card_cvc: "123", +}; + +const successfulThreeDSTestCardDetails = { + card_number: "4000000000001091", + card_exp_month: "01", + card_exp_year: "25", + card_holder_name: "joseph Doe", + card_cvc: "123", +}; +export const connectorDetails = { + card_pm: { + PaymentIntent: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }, + "3DSManualCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + "3DSAutoCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + No3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + No3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + Capture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + amount: 6500, + amount_capturable: 0, + amount_received: 6500, + }, + }, + }, + PartialCapture: { + Request: {}, + Response: { + status: 200, + body: { + status: "partially_captured", + amount: 6500, + amount_capturable: 0, + amount_received: 100, + }, + }, + }, + Void: { + Request: {}, + Response: { + status: 200, + body: { + status: "cancelled", + }, + }, + }, + Refund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, + }, + PartialRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, + }, + SyncRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, + }, + MandateSingleUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateSingleUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, + }, + MandateSingleUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateSingleUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateMultiUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + ZeroAuthMandate: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + }, +}; diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Bluesnap.js b/cypress-tests/cypress/e2e/PaymentUtils/Bluesnap.js new file mode 100644 index 000000000000..0969e4088dda --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentUtils/Bluesnap.js @@ -0,0 +1,414 @@ +const successfulNo3DSCardDetails = { + card_number: "4242424242424242", + card_exp_month: "10", + card_exp_year: "30", + card_holder_name: "John", + card_cvc: "737", +}; + +const successfulThreeDSTestCardDetails = { + card_number: "4000000000001091", + card_exp_month: "10", + card_exp_year: "30", + card_holder_name: "Joseph", + card_cvc: "737", +}; + +export const connectorDetails = { + card_pm: { + PaymentIntent: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }, + "3DSManualCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + "3DSAutoCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + No3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + No3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + Capture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + amount: 6500, + amount_capturable: 0, + amount_received: 6500, + }, + }, + }, + PartialCapture: { + Request: {}, + Response: { + status: 200, + body: { + status: "partially_captured", + amount: 6500, + amount_capturable: 0, + amount_received: 100, + }, + }, + }, + Void: { + Request: {}, + Response: { + status: 200, + body: { + status: "cancelled", + }, + }, + }, + Refund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + PartialRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SyncRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateSingleUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by bluesnap", + }, + }, + }, + }, + MandateSingleUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by bluesnap", + }, + }, + }, + }, + MandateSingleUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by bluesnap", + }, + }, + }, + }, + MandateSingleUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by bluesnap", + }, + }, + }, + }, + MandateMultiUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by bluesnap", + }, + }, + }, + }, + MandateMultiUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by bluesnap", + }, + }, + }, + }, + MandateMultiUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by bluesnap", + }, + }, + }, + }, + MandateMultiUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by bluesnap", + }, + }, + }, + }, + ZeroAuthMandate: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 501, + body: { + error: { + type: "invalid_request", + message: "Setup Mandate flow for Bluesnap is not implemented", + code: "IR_00", + }, + }, + }, + }, + SaveCardUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + }, +}; diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/Commons.js b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js similarity index 100% rename from cypress-tests/cypress/e2e/ConnectorUtils/Commons.js rename to cypress-tests/cypress/e2e/PaymentUtils/Commons.js diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js b/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js new file mode 100644 index 000000000000..d4818ce29417 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentUtils/Cybersource.js @@ -0,0 +1,370 @@ +const successfulNo3DSCardDetails = { + card_number: "4242424242424242", + card_exp_month: "01", + card_exp_year: "25", + card_holder_name: "joseph Doe", + card_cvc: "123", +}; + +const successfulThreeDSTestCardDetails = { + card_number: "4000000000001091", + card_exp_month: "01", + card_exp_year: "25", + card_holder_name: "joseph Doe", + card_cvc: "123", +}; + +export const connectorDetails = { + card_pm: { + PaymentIntent: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }, + "3DSManualCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + "3DSAutoCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + No3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + No3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + Capture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + amount: 6500, + amount_capturable: 0, + amount_received: 6500, + }, + }, + }, + PartialCapture: { + Request: {}, + Response: { + status: 200, + body: { + status: "partially_captured", + amount: 6500, + amount_capturable: 0, + amount_received: 100, + }, + }, + }, + Void: { + Request: {}, + Response: { + status: 200, + body: { + status: "cancelled", + }, + }, + }, + Refund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, + }, + PartialRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, + }, + SyncRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, + }, + MandateSingleUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateSingleUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, + }, + MandateSingleUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateSingleUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateMultiUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + ZeroAuthMandate: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + }, +}; diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Nmi.js b/cypress-tests/cypress/e2e/PaymentUtils/Nmi.js new file mode 100644 index 000000000000..c420bb884455 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentUtils/Nmi.js @@ -0,0 +1,417 @@ +const successfulNo3DSCardDetails = { + card_number: "4000000000002503", + card_exp_month: "08", + card_exp_year: "25", + card_holder_name: "joseph Doe", + card_cvc: "999", +}; + +const successfulThreeDSTestCardDetails = { + card_number: "4000000000002503", + card_exp_month: "10", + card_exp_year: "25", + card_holder_name: "morino", + card_cvc: "999", +}; + +export const connectorDetails = { + card_pm: { + PaymentIntent: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }, + "3DSManualCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + "3DSAutoCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + No3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + No3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + Capture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + }, + }, + }, + PartialCapture: { + Request: {}, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + }, + }, + }, + Void: { + Request: {}, + Response: { + status: 400, + body: { + error: { + code: "IR_16", + message: + "You cannot cancel this payment because it has status processing", + type: "invalid_request", + }, + }, + }, + }, + Refund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, + }, + PartialRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "pending", + }, + }, + }, + SyncRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateSingleUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by nmi", + }, + }, + }, + }, + MandateSingleUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by nmi", + }, + }, + }, + }, + MandateSingleUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by nmi", + }, + }, + }, + }, + MandateSingleUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by nmi", + }, + }, + }, + }, + MandateMultiUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by nmi", + }, + }, + }, + }, + MandateMultiUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by nmi", + }, + }, + }, + }, + MandateMultiUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by nmi", + }, + }, + }, + }, + MandateMultiUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by nmi", + }, + }, + }, + }, + ZeroAuthMandate: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 501, + body: { + error: { + type: "invalid_request", + message: "Setup Mandate flow for Nmi is not implemented", + code: "IR_00", + }, + }, + }, + }, + SaveCardUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + SaveCardUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + }, +}; diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Paypal.js b/cypress-tests/cypress/e2e/PaymentUtils/Paypal.js new file mode 100644 index 000000000000..69c39f0dc8b7 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentUtils/Paypal.js @@ -0,0 +1,429 @@ +const successfulNo3DSCardDetails = { + card_number: "4012000033330026", + card_exp_month: "01", + card_exp_year: "25", + card_holder_name: "joseph Doe", + card_cvc: "123", +}; + +const successfulThreeDSTestCardDetails = { + card_number: "4868719460707704", + card_exp_month: "01", + card_exp_year: "25", + card_holder_name: "joseph Doe", + card_cvc: "123", +}; + +export const connectorDetails = { + card_pm: { + PaymentIntent: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }, + "3DSManualCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + "3DSAutoCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + No3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + No3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + Capture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + amount_received: 0, + }, + }, + }, + PartialCapture: { + Request: {}, + Response: { + status: 200, + body: { + status: "processing", + amount: 6500, + amount_capturable: 6500, + amount_received: 0, + }, + }, + }, + Void: { + Request: {}, + Response: { + status: 200, + body: { + status: "cancelled", + }, + }, + }, + Refund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: + "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", + code: "IR_14", + }, + }, + }, + }, + PartialRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: + "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", + code: "IR_14", + }, + }, + }, + }, + SyncRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: + "This Payment could not be refund because it has a status of processing. The expected state is succeeded, partially_captured", + code: "IR_14", + }, + }, + }, + }, + MandateSingleUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by paypal", + }, + }, + }, + }, + MandateSingleUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by paypal", + }, + }, + }, + }, + MandateSingleUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by paypal", + }, + }, + }, + }, + MandateSingleUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by paypal", + }, + }, + }, + }, + MandateMultiUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by paypal", + }, + }, + }, + }, + MandateMultiUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by paypal", + }, + }, + }, + }, + MandateMultiUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by paypal", + }, + }, + }, + }, + MandateMultiUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 400, + body: { + error: { + type: "invalid_request", + message: "Payment method type not supported", + code: "HE_03", + reason: "debit mandate payment is not supported by paypal", + }, + }, + }, + }, + ZeroAuthMandate: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 501, + body: { + error: { + type: "invalid_request", + message: "Setup Mandate flow for Paypal is not implemented", + code: "IR_00", + }, + }, + }, + }, + SaveCardUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "processing", + }, + }, + }, + SaveCardUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + }, +}; diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js b/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js new file mode 100644 index 000000000000..841c40b87361 --- /dev/null +++ b/cypress-tests/cypress/e2e/PaymentUtils/Stripe.js @@ -0,0 +1,373 @@ +const successfulTestCard = "4242424242424242"; +const successful3DSCard = "4000002760003184"; + +const successfulNo3DSCardDetails = { + card_number: "4242424242424242", + card_exp_month: "10", + card_exp_year: "25", + card_holder_name: "morino", + card_cvc: "737", +}; + +const successfulThreeDSTestCardDetails = { + card_number: "4000002760003184", + card_exp_month: "10", + card_exp_year: "25", + card_holder_name: "morino", + card_cvc: "737", +}; + +export const connectorDetails = { + card_pm: { + PaymentIntent: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_payment_method", + }, + }, + }, + "3DSManualCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + "3DSAutoCapture": { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + No3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + No3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + setup_future_usage: "on_session", + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + Capture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + amount: 6500, + amount_capturable: 0, + amount_received: 6500, + }, + }, + }, + PartialCapture: { + Request: {}, + Response: { + status: 200, + body: { + status: "partially_captured", + amount: 6500, + amount_capturable: 0, + amount_received: 100, + }, + }, + }, + Void: { + Request: {}, + Response: { + status: 200, + body: { + status: "cancelled", + }, + }, + }, + Refund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + PartialRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SyncRefund: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + customer_acceptance: null, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateSingleUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateSingleUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_customer_action", + }, + }, + }, + MandateSingleUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateSingleUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + MandateMultiUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUse3DSAutoCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + MandateMultiUse3DSManualCapture: { + Request: { + card: successfulThreeDSTestCardDetails, + currency: "USD", + mandate_type: { + multi_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + ZeroAuthMandate: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + mandate_type: { + single_use: { + amount: 8000, + currency: "USD", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSAutoCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "succeeded", + }, + }, + }, + SaveCardUseNo3DSManualCapture: { + Request: { + card: successfulNo3DSCardDetails, + currency: "USD", + setup_future_usage: "on_session", + customer_acceptance: { + acceptance_type: "offline", + accepted_at: "1963-05-03T04:07:52.723Z", + online: { + ip_address: "127.0.0.1", + user_agent: "amet irure esse", + }, + }, + }, + Response: { + status: 200, + body: { + status: "requires_capture", + }, + }, + }, + }, +}; diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/Trustpay.js b/cypress-tests/cypress/e2e/PaymentUtils/Trustpay.js similarity index 100% rename from cypress-tests/cypress/e2e/ConnectorUtils/Trustpay.js rename to cypress-tests/cypress/e2e/PaymentUtils/Trustpay.js diff --git a/cypress-tests/cypress/e2e/ConnectorUtils/utils.js b/cypress-tests/cypress/e2e/PaymentUtils/utils.js similarity index 100% rename from cypress-tests/cypress/e2e/ConnectorUtils/utils.js rename to cypress-tests/cypress/e2e/PaymentUtils/utils.js diff --git a/cypress-tests/cypress/e2e/ConnectorTest/00000-AccountCreate.cy.js b/cypress-tests/cypress/e2e/PayoutTest/00000-AccountCreate.cy.js similarity index 83% rename from cypress-tests/cypress/e2e/ConnectorTest/00000-AccountCreate.cy.js rename to cypress-tests/cypress/e2e/PayoutTest/00000-AccountCreate.cy.js index aed901c29972..c1b62c883fa0 100644 --- a/cypress-tests/cypress/e2e/ConnectorTest/00000-AccountCreate.cy.js +++ b/cypress-tests/cypress/e2e/PayoutTest/00000-AccountCreate.cy.js @@ -4,16 +4,14 @@ import State from "../../utils/State"; let globalState; describe("Account Create flow test", () => { - before("seed global state", () => { - - cy.task('getGlobalState').then((state) => { + cy.task("getGlobalState").then((state) => { globalState = new State(state); - }) - }) + }); + }); after("flush global state", () => { - cy.task('setGlobalState', globalState.data); - }) + cy.task("setGlobalState", globalState.data); + }); it("merchant-create-call-test", () => { cy.merchantCreateCallTest(merchantCreateBody, globalState); @@ -21,5 +19,4 @@ describe("Account Create flow test", () => { it("api-key-create-call-test", () => { cy.apiKeyCreateTest(apiKeyCreateBody, globalState); }); - }); diff --git a/cypress-tests/cypress/e2e/PayoutTest/00001-CustomerCreate.cy.js b/cypress-tests/cypress/e2e/PayoutTest/00001-CustomerCreate.cy.js new file mode 100644 index 000000000000..584296bdaee7 --- /dev/null +++ b/cypress-tests/cypress/e2e/PayoutTest/00001-CustomerCreate.cy.js @@ -0,0 +1,18 @@ +import customerCreateBody from "../../fixtures/create-customer-body.json"; +import State from "../../utils/State"; + +let globalState; + +describe("Customer Create flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + }); + }); + after("flush global state", () => { + cy.task("setGlobalState", globalState.data); + }); + it("customer-create-call-test", () => { + cy.createCustomerCallTest(customerCreateBody, globalState); + }); +}); diff --git a/cypress-tests/cypress/e2e/PayoutTest/00002-ConnectorCreate.cy.js b/cypress-tests/cypress/e2e/PayoutTest/00002-ConnectorCreate.cy.js new file mode 100644 index 000000000000..16292914aa24 --- /dev/null +++ b/cypress-tests/cypress/e2e/PayoutTest/00002-ConnectorCreate.cy.js @@ -0,0 +1,21 @@ +import createConnectorBody from "../../fixtures/create-connector-body.json"; +import State from "../../utils/State"; + +let globalState; +describe("Connector Account Create flow test", () => { + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + console.log("seeding globalState -> " + JSON.stringify(globalState)); + }); + }); + + after("flush global state", () => { + console.log("flushing globalState -> " + JSON.stringify(globalState)); + cy.task("setGlobalState", globalState.data); + }); + + it("connector-create-call-test", () => { + cy.createPayoutConnectorCallTest(createConnectorBody, globalState); + }); +}); diff --git a/cypress-tests/cypress/e2e/PayoutTest/00003-CardTest.cy.js b/cypress-tests/cypress/e2e/PayoutTest/00003-CardTest.cy.js new file mode 100644 index 000000000000..4f563a689cea --- /dev/null +++ b/cypress-tests/cypress/e2e/PayoutTest/00003-CardTest.cy.js @@ -0,0 +1,140 @@ +import createPayoutBody from "../../fixtures/create-payout-confirm-body.json"; +import State from "../../utils/State"; +import * as utils from "../PayoutUtils/utils"; + +let globalState; + +describe("Card - Auto Fulfill", () => { + let should_continue = true; // variable that will be used to skip tests if a previous test fails + + beforeEach(function () { + if (!should_continue) { + this.skip(); + } + }); + + before("seed global state", () => { + cy.task("getGlobalState").then((state) => { + globalState = new State(state); + console.log("seeding globalState -> " + JSON.stringify(globalState)); + cy.task( + "cli_log", + "SEEDING GLOBAL STATE -> " + JSON.stringify(globalState), + ); + }); + }); + + afterEach("flush global state", () => { + console.log("flushing globalState -> " + JSON.stringify(globalState)); + cy.task("setGlobalState", globalState.data); + cy.task( + "cli_log", + " FLUSHING GLOBAL STATE -> " + JSON.stringify(globalState), + ); + }); + + context("Payout Card with Auto Fulfill", () => { + it("confirm-payout-call-with-auto-fulfill-test", () => { + let data = utils.getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Fulfill"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPayoutTest( + createPayoutBody, + req_data, + res_data, + true, + true, + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payout-call-test", () => { + cy.retrievePayoutCallTest(globalState); + }); + }); + + context("Payout Card with Manual Fulfill - Create Confirm", () => { + it("confirm-payout-call-with-manual-fulfill-test", () => { + let data = utils.getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Confirm"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPayoutTest( + createPayoutBody, + req_data, + res_data, + true, + false, + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("fulfill-payout-call-test", () => { + let data = utils.getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Fulfill"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.fulfillPayoutCallTest({}, req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payout-call-test", () => { + cy.retrievePayoutCallTest(globalState); + }); + }); + + context("Payout Card with Manual Fulfill - Create Intent + Confirm", () => { + it("create-payout-call", () => { + let data = utils.getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Create"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.createConfirmPayoutTest( + createPayoutBody, + req_data, + res_data, + false, + false, + globalState, + ); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("confirm-payout-call", () => { + let data = utils.getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Confirm"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.updatePayoutCallTest({}, req_data, res_data, false, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("fulfill-payout-call-test", () => { + let data = utils.getConnectorDetails(globalState.get("connectorId"))[ + "card_pm" + ]["Fulfill"]; + let req_data = data["Request"]; + let res_data = data["Response"]; + cy.fulfillPayoutCallTest({}, req_data, res_data, globalState); + if (should_continue) + should_continue = utils.should_continue_further(res_data); + }); + + it("retrieve-payout-call-test", () => { + cy.retrievePayoutCallTest(globalState); + }); + }); +}); diff --git a/cypress-tests/cypress/e2e/PayoutUtils/Adyen.js b/cypress-tests/cypress/e2e/PayoutUtils/Adyen.js new file mode 100644 index 000000000000..eaa25e7fa292 --- /dev/null +++ b/cypress-tests/cypress/e2e/PayoutUtils/Adyen.js @@ -0,0 +1,59 @@ +const card_data = { + card_number: "4111111111111111", + expiry_month: "3", + expiry_year: "2030", + card_holder_name: "John Smith", +}; + +export const connectorDetails = { + card_pm: { + Create: { + Request: { + payout_method_data: { + card: card_data, + }, + currency: "EUR", + payout_type: "card", + }, + Response: { + status: 200, + body: { + status: "requires_creation", + payout_type: "card", + }, + }, + }, + Confirm: { + Request: { + payout_method_data: { + card: card_data, + }, + currency: "EUR", + payout_type: "card", + }, + Response: { + status: 200, + body: { + status: "requires_fulfillment", + payout_type: "card", + }, + }, + }, + Fulfill: { + Request: { + payout_method_data: { + card: card_data, + }, + currency: "EUR", + payout_type: "card", + }, + Response: { + status: 200, + body: { + status: "success", + payout_type: "card", + }, + }, + }, + }, +}; diff --git a/cypress-tests/cypress/e2e/PayoutUtils/utils.js b/cypress-tests/cypress/e2e/PayoutUtils/utils.js new file mode 100644 index 000000000000..619fd313f202 --- /dev/null +++ b/cypress-tests/cypress/e2e/PayoutUtils/utils.js @@ -0,0 +1,33 @@ +import { connectorDetails as adyenConnectorDetails } from "./Adyen.js"; + +const connectorDetails = { + adyen: adyenConnectorDetails, +}; + +export const getConnectorDetails = (connectorId) => { + let x = getValueByKey(connectorDetails, connectorId); + return x; +}; + +function getValueByKey(jsonObject, key) { + const data = + typeof jsonObject === "string" ? JSON.parse(jsonObject) : jsonObject; + + if (data && typeof data === "object" && key in data) { + return data[key]; + } else { + return null; + } +} + +export const should_continue_further = (res_data) => { + if ( + res_data.body.error !== undefined || + res_data.body.error_code !== undefined || + res_data.body.error_message !== undefined + ) { + return false; + } else { + return true; + } +}; diff --git a/cypress-tests/cypress/fixtures/create-payout-confirm-body.json b/cypress-tests/cypress/fixtures/create-payout-confirm-body.json new file mode 100644 index 000000000000..2eb32bf26dab --- /dev/null +++ b/cypress-tests/cypress/fixtures/create-payout-confirm-body.json @@ -0,0 +1,36 @@ +{ + "amount": 1, + "currency": "EUR", + "customer_id": "payout_customer", + "email": "payout_customer@example.com", + "name": "John Doe", + "phone": "999999999", + "phone_country_code": "+65", + "description": "Its my first payout request", + "payout_type": "card", + "payout_method_data": {}, + "billing": { + "address": { + "line1": "1467", + "line2": "Harrison Street", + "line3": "Harrison Street", + "city": "San Fransico", + "state": "NY", + "zip": "94122", + "country": "US", + "first_name": "John", + "last_name": "Doe" + }, + "phone": { + "number": "8056594427", + "country_code": "+91" + } + }, + "entity_type": "Individual", + "recurring": false, + "metadata": { + "ref": "123" + }, + "auto_fulfill": true, + "confirm": true +} diff --git a/cypress-tests/cypress/support/commands.js b/cypress-tests/cypress/support/commands.js index 4842ed017344..59a201668682 100644 --- a/cypress-tests/cypress/support/commands.js +++ b/cypress-tests/cypress/support/commands.js @@ -30,9 +30,9 @@ import { handleRedirection } from "./redirectionHandler"; function logRequestId(xRequestId) { if (xRequestId) { - cy.task('cli_log', "x-request-id -> " + xRequestId); + cy.task("cli_log", "x-request-id -> " + xRequestId); } else { - cy.task('cli_log', "x-request-id is not available in the response headers"); + cy.task("cli_log", "x-request-id is not available in the response headers"); } } @@ -43,27 +43,30 @@ function defaultErrorHandler(response, response_data) { } } -Cypress.Commands.add("merchantCreateCallTest", (merchantCreateBody, globalState) => { - const randomMerchantId = RequestBodyUtils.generateRandomString(); - RequestBodyUtils.setMerchantId(merchantCreateBody, randomMerchantId); - globalState.set("merchantId", randomMerchantId); +Cypress.Commands.add( + "merchantCreateCallTest", + (merchantCreateBody, globalState) => { + const randomMerchantId = RequestBodyUtils.generateRandomString(); + RequestBodyUtils.setMerchantId(merchantCreateBody, randomMerchantId); + globalState.set("merchantId", randomMerchantId); - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/accounts`, - headers: { - "Content-Type": "application/json", - Accept: "application/json", - "api-key": globalState.get("adminApiKey"), - }, - body: merchantCreateBody, - }).then((response) => { - logRequestId(response.headers['x-request-id']); + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/accounts`, + headers: { + "Content-Type": "application/json", + Accept: "application/json", + "api-key": globalState.get("adminApiKey"), + }, + body: merchantCreateBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); - // Handle the response as needed - globalState.set("publishableKey", response.body.publishable_key); - }); -}); + // Handle the response as needed + globalState.set("publishableKey", response.body.publishable_key); + }); + }, +); Cypress.Commands.add("apiKeyCreateTest", (apiKeyCreateBody, globalState) => { cy.request({ @@ -76,113 +79,191 @@ Cypress.Commands.add("apiKeyCreateTest", (apiKeyCreateBody, globalState) => { }, body: apiKeyCreateBody, }).then((response) => { - logRequestId(response.headers['x-request-id']); + logRequestId(response.headers["x-request-id"]); // Handle the response as needed globalState.set("apiKey", response.body.api_key); }); }); -Cypress.Commands.add("createConnectorCallTest", (createConnectorBody, globalState) => { - const merchantId = globalState.get("merchantId"); - createConnectorBody.connector_name = globalState.get("connectorId"); - // readFile is used to read the contents of the file and it always returns a promise ([Object Object]) due to its asynchronous nature - // it is best to use then() to handle the response within the same block of code - cy.readFile(globalState.get("connectorAuthFilePath")).then((jsonContent) => { - const authDetails = getValueByKey(JSON.stringify(jsonContent), globalState.get("connectorId")); - createConnectorBody.connector_account_details = authDetails; - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/account/${merchantId}/connectors`, - headers: { - "Content-Type": "application/json", - Accept: "application/json", - "api-key": globalState.get("adminApiKey"), +Cypress.Commands.add( + "createConnectorCallTest", + (createConnectorBody, globalState) => { + const merchantId = globalState.get("merchantId"); + createConnectorBody.connector_name = globalState.get("connectorId"); + // readFile is used to read the contents of the file and it always returns a promise ([Object Object]) due to its asynchronous nature + // it is best to use then() to handle the response within the same block of code + cy.readFile(globalState.get("connectorAuthFilePath")).then( + (jsonContent) => { + const authDetails = getValueByKey( + JSON.stringify(jsonContent), + globalState.get("connectorId"), + ); + createConnectorBody.connector_account_details = authDetails; + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/account/${merchantId}/connectors`, + headers: { + "Content-Type": "application/json", + Accept: "application/json", + "api-key": globalState.get("adminApiKey"), + }, + body: createConnectorBody, + failOnStatusCode: false, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + + if (response.status === 200) { + expect(globalState.get("connectorId")).to.equal( + response.body.connector_name, + ); + } else { + cy.task( + "cli_log", + "response status -> " + JSON.stringify(response.status), + ); + } + }); }, - body: createConnectorBody, - failOnStatusCode: false - }).then((response) => { - logRequestId(response.headers['x-request-id']); + ); + }, +); - if (response.status === 200) { - expect(globalState.get("connectorId")).to.equal(response.body.connector_name); - } else { - cy.task('cli_log', "response status -> " + JSON.stringify(response.status)); - } - }); - }); -}); +Cypress.Commands.add( + "createPayoutConnectorCallTest", + (createConnectorBody, globalState) => { + const merchantId = globalState.get("merchantId"); + let connectorName = globalState.get("connectorId"); + createConnectorBody.connector_name = connectorName; + createConnectorBody.connector_type = "payout_processor"; + // readFile is used to read the contents of the file and it always returns a promise ([Object Object]) due to its asynchronous nature + // it is best to use then() to handle the response within the same block of code + cy.readFile(globalState.get("connectorAuthFilePath")).then( + (jsonContent) => { + const authDetails = getValueByKey( + JSON.stringify(jsonContent), + `${connectorName}_payout`, + ); + createConnectorBody.connector_account_details = authDetails; + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/account/${merchantId}/connectors`, + headers: { + "Content-Type": "application/json", + Accept: "application/json", + "api-key": globalState.get("adminApiKey"), + }, + body: createConnectorBody, + failOnStatusCode: false, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + + if (response.status === 200) { + expect(globalState.get("connectorId")).to.equal( + response.body.connector_name, + ); + } else { + cy.task( + "cli_log", + "response status -> " + JSON.stringify(response.status), + ); + } + }); + }, + ); + }, +); function getValueByKey(jsonObject, key) { - const data = typeof jsonObject === 'string' ? JSON.parse(jsonObject) : jsonObject; - if (data && typeof data === 'object' && key in data) { + const data = + typeof jsonObject === "string" ? JSON.parse(jsonObject) : jsonObject; + if (data && typeof data === "object" && key in data) { return data[key]; } else { return null; } } -Cypress.Commands.add("createCustomerCallTest", (customerCreateBody, globalState) => { - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/customers`, - headers: { - "Content-Type": "application/json", - "api-key": globalState.get("apiKey"), - }, - body: customerCreateBody, - }).then((response) => { - logRequestId(response.headers['x-request-id']); +Cypress.Commands.add( + "createCustomerCallTest", + (customerCreateBody, globalState) => { + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/customers`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + body: customerCreateBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); - globalState.set("customerId", response.body.customer_id); - }); -}); + globalState.set("customerId", response.body.customer_id); + }); + }, +); -Cypress.Commands.add("createPaymentIntentTest", (request, req_data, res_data, authentication_type, capture_method, globalState) => { - if (!request || typeof request !== "object" || !req_data.currency || !authentication_type) { - throw new Error("Invalid parameters provided to createPaymentIntentTest command"); - } - request.currency = req_data.currency; - request.authentication_type = authentication_type; - request.capture_method = capture_method; - request.setup_future_usage = req_data.setup_future_usage; - request.customer_acceptance = req_data.customer_acceptance; - request.customer_id = globalState.get("customerId"); - globalState.set("paymentAmount", request.amount); - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/payments`, - headers: { - "Content-Type": "application/json", - Accept: "application/json", - "api-key": globalState.get("apiKey"), - }, - failOnStatusCode: false, - body: request, - }).then((response) => { - logRequestId(response.headers['x-request-id']); +Cypress.Commands.add( + "createPaymentIntentTest", + ( + request, + req_data, + res_data, + authentication_type, + capture_method, + globalState, + ) => { + if ( + !request || + typeof request !== "object" || + !req_data.currency || + !authentication_type + ) { + throw new Error( + "Invalid parameters provided to createPaymentIntentTest command", + ); + } + request.currency = req_data.currency; + request.authentication_type = authentication_type; + request.capture_method = capture_method; + request.setup_future_usage = req_data.setup_future_usage; + request.customer_acceptance = req_data.customer_acceptance; + request.customer_id = globalState.get("customerId"); + globalState.set("paymentAmount", request.amount); + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payments`, + headers: { + "Content-Type": "application/json", + Accept: "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + body: request, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); - expect(res_data.status).to.equal(response.status); - expect(response.headers["content-type"]).to.include("application/json"); - - if(response.status === 200){ - expect(response.body).to.have.property("client_secret"); - const clientSecret = response.body.client_secret; - globalState.set("clientSecret", clientSecret); - globalState.set("paymentID", response.body.payment_id); - cy.log(clientSecret); - for(const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + + if (response.status === 200) { + expect(response.body).to.have.property("client_secret"); + const clientSecret = response.body.client_secret; + globalState.set("clientSecret", clientSecret); + globalState.set("paymentID", response.body.payment_id); + cy.log(clientSecret); + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + expect(request.amount).to.equal(response.body.amount); + expect(null).to.equal(response.body.amount_received); + expect(request.amount).to.equal(response.body.amount_capturable); + } else { + defaultErrorHandler(response, res_data); } - expect(request.amount).to.equal(response.body.amount); - expect(null).to.equal(response.body.amount_received); - expect(request.amount).to.equal(response.body.amount_capturable); - } - else { - defaultErrorHandler(response, res_data); - } - }); -}); + }); + }, +); Cypress.Commands.add("paymentMethodsCallTest", (globalState) => { const clientSecret = globalState.get("clientSecret"); @@ -196,7 +277,7 @@ Cypress.Commands.add("paymentMethodsCallTest", (globalState) => { "api-key": globalState.get("publishableKey"), }, }).then((response) => { - logRequestId(response.headers['x-request-id']); + logRequestId(response.headers["x-request-id"]); expect(response.headers["content-type"]).to.include("application/json"); expect(response.body).to.have.property("redirect_url"); @@ -206,60 +287,69 @@ Cypress.Commands.add("paymentMethodsCallTest", (globalState) => { }); }); -Cypress.Commands.add("confirmCallTest", (confirmBody, req_data, res_data, confirm, globalState) => { - const paymentIntentID = globalState.get("paymentID"); - confirmBody.payment_method_data.card = req_data.card; - confirmBody.confirm = confirm; - confirmBody.client_secret = globalState.get("clientSecret"); - confirmBody.customer_acceptance = req_data.customer_acceptance; +Cypress.Commands.add( + "confirmCallTest", + (confirmBody, req_data, res_data, confirm, globalState) => { + const paymentIntentID = globalState.get("paymentID"); + confirmBody.payment_method_data.card = req_data.card; + confirmBody.confirm = confirm; + confirmBody.client_secret = globalState.get("clientSecret"); + confirmBody.customer_acceptance = req_data.customer_acceptance; - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/payments/${paymentIntentID}/confirm`, - headers: { - "Content-Type": "application/json", - "api-key": globalState.get("publishableKey"), - }, - failOnStatusCode: false, - body: confirmBody, - }).then((response) => { - logRequestId(response.headers['x-request-id']); - expect(res_data.status).to.equal(response.status); - expect(response.headers["content-type"]).to.include("application/json"); - if(response.status === 200){ - globalState.set("paymentID", paymentIntentID); - if (response.body.capture_method === "automatic") { - if (response.body.authentication_type === "three_ds") { - expect(response.body).to.have.property("next_action") - .to.have.property("redirect_to_url"); - globalState.set("nextActionUrl", response.body.next_action.redirect_to_url); - } else if (response.body.authentication_type === "no_three_ds") { - for(const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payments/${paymentIntentID}/confirm`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("publishableKey"), + }, + failOnStatusCode: false, + body: confirmBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + if (response.status === 200) { + globalState.set("paymentID", paymentIntentID); + if (response.body.capture_method === "automatic") { + if (response.body.authentication_type === "three_ds") { + expect(response.body) + .to.have.property("next_action") + .to.have.property("redirect_to_url"); + globalState.set( + "nextActionUrl", + response.body.next_action.redirect_to_url, + ); + } else if (response.body.authentication_type === "no_three_ds") { + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + } else { + defaultErrorHandler(response, res_data); } - } else { - defaultErrorHandler(response, res_data); - } - } else if (response.body.capture_method === "manual") { - if (response.body.authentication_type === "three_ds") { - expect(response.body).to.have.property("next_action") - .to.have.property("redirect_to_url") - globalState.set("nextActionUrl", response.body.next_action.redirect_to_url); - } - else if (response.body.authentication_type === "no_three_ds") { - for (const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); + } else if (response.body.capture_method === "manual") { + if (response.body.authentication_type === "three_ds") { + expect(response.body) + .to.have.property("next_action") + .to.have.property("redirect_to_url"); + globalState.set( + "nextActionUrl", + response.body.next_action.redirect_to_url, + ); + } else if (response.body.authentication_type === "no_three_ds") { + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + } else { + defaultErrorHandler(response, res_data); } - } else { - defaultErrorHandler(response, res_data); } + } else { + defaultErrorHandler(response, res_data); } - } - else { - defaultErrorHandler(response, res_data); - } - }); -}); + }); + }, +); Cypress.Commands.add( "confirmBankRedirectCallTest", @@ -294,8 +384,12 @@ Cypress.Commands.add( response.body.capture_method === "automatic" || response.body.capture_method === "manual" ) { - if (response.body.status !== "failed") { // we get many statuses here, hence this verification - if (connectorId === "adyen" && response.body.payment_method_type === "blik") { + if (response.body.status !== "failed") { + // we get many statuses here, hence this verification + if ( + connectorId === "adyen" && + response.body.payment_method_type === "blik" + ) { expect(response.body) .to.have.property("next_action") .to.have.property("type") @@ -306,11 +400,13 @@ Cypress.Commands.add( .to.have.property("redirect_to_url"); globalState.set( "nextActionUrl", - response.body.next_action.redirect_to_url + response.body.next_action.redirect_to_url, ); } } else if (response.body.status === "failed") { - expect(response.body.error_code).to.equal(res_data.body.error_code); + expect(response.body.error_code).to.equal( + res_data.body.error_code, + ); } } else { defaultErrorHandler(response, res_data); @@ -326,7 +422,7 @@ Cypress.Commands.add( .to.have.property("redirect_to_url"); globalState.set( "nextActionUrl", - response.body.next_action.redirect_to_url + response.body.next_action.redirect_to_url, ); } else { defaultErrorHandler(response, res_data); @@ -336,7 +432,7 @@ Cypress.Commands.add( defaultErrorHandler(response, res_data); } }); - } + }, ); Cypress.Commands.add( @@ -349,7 +445,7 @@ Cypress.Commands.add( confirmBody.confirm = confirm; confirmBody.client_secret = globalState.get("clientSecret"); globalState.set("paymentMethodType", confirmBody.payment_method_type); - + cy.request({ method: "POST", url: `${globalState.get("baseUrl")}/payments/${paymentIntentID}/confirm`, @@ -376,7 +472,7 @@ Cypress.Commands.add( .to.have.property("qr_code_url"); globalState.set( "nextActionUrl", // This is intentionally kept as nextActionUrl to avoid issues during handleRedirection call, - response.body.next_action.qr_code_url + response.body.next_action.qr_code_url, ); break; default: @@ -385,7 +481,7 @@ Cypress.Commands.add( .to.have.property("redirect_to_url"); globalState.set( "nextActionUrl", - response.body.next_action.redirect_to_url + response.body.next_action.redirect_to_url, ); break; } @@ -396,190 +492,214 @@ Cypress.Commands.add( defaultErrorHandler(response, res_data); } }); - } + }, ); -Cypress.Commands.add("createConfirmPaymentTest", (createConfirmPaymentBody, req_data, res_data, authentication_type, capture_method, globalState) => { - createConfirmPaymentBody.payment_method_data.card = req_data.card; - createConfirmPaymentBody.authentication_type = authentication_type; - createConfirmPaymentBody.currency = req_data.currency; - createConfirmPaymentBody.capture_method = capture_method; - createConfirmPaymentBody.customer_acceptance = req_data.customer_acceptance; - createConfirmPaymentBody.setup_future_usage = req_data.setup_future_usage; - createConfirmPaymentBody.customer_id = globalState.get("customerId"); - - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/payments`, - headers: { - "Content-Type": "application/json", - "api-key": globalState.get("apiKey"), - }, - failOnStatusCode: false, - body: createConfirmPaymentBody, - }).then((response) => { - logRequestId(response.headers['x-request-id']); - - expect(res_data.status).to.equal(response.status); - expect(response.headers["content-type"]).to.include("application/json"); - - if(response.status === 200){ - if (response.body.capture_method === "automatic") { - expect(response.body).to.have.property("status"); - globalState.set("paymentAmount", createConfirmPaymentBody.amount); - globalState.set("paymentID", response.body.payment_id); - if (response.body.authentication_type === "three_ds") { - expect(response.body).to.have.property("next_action") - .to.have.property("redirect_to_url") - globalState.set("nextActionUrl", response.body.next_action.redirect_to_url); - } - else if (response.body.authentication_type === "no_three_ds") { - for(const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); - } - } else { - defaultErrorHandler(response, res_data); - } - } - else if (response.body.capture_method === "manual") { - expect(response.body).to.have.property("status"); - globalState.set("paymentAmount", createConfirmPaymentBody.amount); - globalState.set("paymentID", response.body.payment_id); - if (response.body.authentication_type === "three_ds") { - expect(response.body).to.have.property("next_action") - .to.have.property("redirect_to_url") - globalState.set("nextActionUrl", response.body.next_action.redirect_to_url); - } - else if (response.body.authentication_type === "no_three_ds") { - for(const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); - } - } else { - defaultErrorHandler(response, res_data); - } - } - } - else{ - defaultErrorHandler(response, res_data); - } - }); -}); +Cypress.Commands.add( + "createConfirmPaymentTest", + ( + createConfirmPaymentBody, + req_data, + res_data, + authentication_type, + capture_method, + globalState, + ) => { + createConfirmPaymentBody.payment_method_data.card = req_data.card; + createConfirmPaymentBody.authentication_type = authentication_type; + createConfirmPaymentBody.currency = req_data.currency; + createConfirmPaymentBody.capture_method = capture_method; + createConfirmPaymentBody.customer_acceptance = req_data.customer_acceptance; + createConfirmPaymentBody.setup_future_usage = req_data.setup_future_usage; + createConfirmPaymentBody.customer_id = globalState.get("customerId"); -// This is consequent saved card payment confirm call test(Using payment token) -Cypress.Commands.add("saveCardConfirmCallTest", (saveCardConfirmBody, req_data, res_data,globalState) => { - const paymentIntentID = globalState.get("paymentID"); - saveCardConfirmBody.card_cvc = req_data.card.card_cvc; - saveCardConfirmBody.payment_token = globalState.get("paymentToken"); - saveCardConfirmBody.client_secret = globalState.get("clientSecret"); - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/payments/${paymentIntentID}/confirm`, - headers: { - "Content-Type": "application/json", - "api-key": globalState.get("publishableKey"), - }, - failOnStatusCode: false, - body: saveCardConfirmBody, - }) - .then((response) => { - logRequestId(response.headers['x-request-id']); + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payments`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + body: createConfirmPaymentBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); expect(res_data.status).to.equal(response.status); expect(response.headers["content-type"]).to.include("application/json"); - globalState.set("paymentID", paymentIntentID); - if(response.status === 200){ + + if (response.status === 200) { if (response.body.capture_method === "automatic") { + expect(response.body).to.have.property("status"); + globalState.set("paymentAmount", createConfirmPaymentBody.amount); + globalState.set("paymentID", response.body.payment_id); if (response.body.authentication_type === "three_ds") { - expect(response.body).to.have.property("next_action") + expect(response.body) + .to.have.property("next_action") .to.have.property("redirect_to_url"); - const nextActionUrl = response.body.next_action.redirect_to_url; - } else if (response.body.authentication_type === "no_three_ds") { - for(const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); + globalState.set( + "nextActionUrl", + response.body.next_action.redirect_to_url, + ); + } else if (response.body.authentication_type === "no_three_ds") { + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); } - expect(response.body.customer_id).to.equal(globalState.get("customerId")); } else { - // Handle other authentication types as needed defaultErrorHandler(response, res_data); } } else if (response.body.capture_method === "manual") { + expect(response.body).to.have.property("status"); + globalState.set("paymentAmount", createConfirmPaymentBody.amount); + globalState.set("paymentID", response.body.payment_id); if (response.body.authentication_type === "three_ds") { - expect(response.body).to.have.property("next_action") - .to.have.property("redirect_to_url") + expect(response.body) + .to.have.property("next_action") + .to.have.property("redirect_to_url"); + globalState.set( + "nextActionUrl", + response.body.next_action.redirect_to_url, + ); + } else if (response.body.authentication_type === "no_three_ds") { + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + } else { + defaultErrorHandler(response, res_data); } - else if (response.body.authentication_type === "no_three_ds") { - for(const key in res_data.body) { + } + } else { + defaultErrorHandler(response, res_data); + } + }); + }, +); + +// This is consequent saved card payment confirm call test(Using payment token) +Cypress.Commands.add( + "saveCardConfirmCallTest", + (saveCardConfirmBody, req_data, res_data, globalState) => { + const paymentIntentID = globalState.get("paymentID"); + saveCardConfirmBody.card_cvc = req_data.card.card_cvc; + saveCardConfirmBody.payment_token = globalState.get("paymentToken"); + saveCardConfirmBody.client_secret = globalState.get("clientSecret"); + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payments/${paymentIntentID}/confirm`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("publishableKey"), + }, + failOnStatusCode: false, + body: saveCardConfirmBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + globalState.set("paymentID", paymentIntentID); + if (response.status === 200) { + if (response.body.capture_method === "automatic") { + if (response.body.authentication_type === "three_ds") { + expect(response.body) + .to.have.property("next_action") + .to.have.property("redirect_to_url"); + const nextActionUrl = response.body.next_action.redirect_to_url; + } else if (response.body.authentication_type === "no_three_ds") { + for (const key in res_data.body) { expect(res_data.body[key]).to.equal(response.body[key]); } - expect(response.body.customer_id).to.equal(globalState.get("customerId")); + expect(response.body.customer_id).to.equal( + globalState.get("customerId"), + ); + } else { + // Handle other authentication types as needed + defaultErrorHandler(response, res_data); + } + } else if (response.body.capture_method === "manual") { + if (response.body.authentication_type === "three_ds") { + expect(response.body) + .to.have.property("next_action") + .to.have.property("redirect_to_url"); + } else if (response.body.authentication_type === "no_three_ds") { + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + expect(response.body.customer_id).to.equal( + globalState.get("customerId"), + ); } else { // Handle other authentication types as needed defaultErrorHandler(response, res_data); } } - } - else { + } else { defaultErrorHandler(response, res_data); } }); -}); + }, +); -Cypress.Commands.add("captureCallTest", (requestBody, req_data, res_data, amount_to_capture, globalState) => { - const payment_id = globalState.get("paymentID"); - requestBody.amount_to_capture = amount_to_capture; - let amount = globalState.get("paymentAmount"); - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/payments/${payment_id}/capture`, - headers: { - "Content-Type": "application/json", - "api-key": globalState.get("apiKey"), - }, - failOnStatusCode: false, - body: requestBody, - }).then((response) => { - logRequestId(response.headers['x-request-id']); +Cypress.Commands.add( + "captureCallTest", + (requestBody, req_data, res_data, amount_to_capture, globalState) => { + const payment_id = globalState.get("paymentID"); + requestBody.amount_to_capture = amount_to_capture; + let amount = globalState.get("paymentAmount"); + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payments/${payment_id}/capture`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + body: requestBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); - expect(res_data.status).to.equal(response.status); - expect(response.headers["content-type"]).to.include("application/json"); - if(response.body.capture_method !== undefined) { - expect(response.body.payment_id).to.equal(payment_id); - for(const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + if (response.body.capture_method !== undefined) { + expect(response.body.payment_id).to.equal(payment_id); + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + } else { + defaultErrorHandler(response, res_data); } - } - else{ - defaultErrorHandler(response, res_data); - } - }); -}); + }); + }, +); -Cypress.Commands.add("voidCallTest", (requestBody, req_data, res_data, globalState) => { - const payment_id = globalState.get("paymentID"); - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/payments/${payment_id}/cancel`, - headers: { - "Content-Type": "application/json", - "api-key": globalState.get("apiKey"), - }, - failOnStatusCode: false, - body: requestBody, - }).then((response) => { - logRequestId(response.headers['x-request-id']); +Cypress.Commands.add( + "voidCallTest", + (requestBody, req_data, res_data, globalState) => { + const payment_id = globalState.get("paymentID"); + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payments/${payment_id}/cancel`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + body: requestBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); - expect(res_data.status).to.equal(response.status); - expect(response.headers["content-type"]).to.include("application/json"); - if(response.status === 200) { - for(const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + if (response.status === 200) { + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + } else { + defaultErrorHandler(response, res_data); } - } - else{ - defaultErrorHandler(response, res_data); - } - }); -}); + }); + }, +); Cypress.Commands.add("retrievePaymentCallTest", (globalState) => { const payment_id = globalState.get("paymentID"); @@ -592,7 +712,7 @@ Cypress.Commands.add("retrievePaymentCallTest", (globalState) => { }, failOnStatusCode: false, }).then((response) => { - logRequestId(response.headers['x-request-id']); + logRequestId(response.headers["x-request-id"]); expect(response.headers["content-type"]).to.include("application/json"); expect(response.body.payment_id).to.equal(payment_id); @@ -601,168 +721,189 @@ Cypress.Commands.add("retrievePaymentCallTest", (globalState) => { }); }); -Cypress.Commands.add("refundCallTest", (requestBody, req_data, res_data, refund_amount, globalState) => { - const payment_id = globalState.get("paymentID"); - requestBody.payment_id = payment_id; - requestBody.amount = refund_amount; - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/refunds`, - headers: { - "Content-Type": "application/json", - "api-key": globalState.get("apiKey"), - }, - failOnStatusCode: false, - body: requestBody - }).then((response) => { - logRequestId(response.headers['x-request-id']); - expect(res_data.status).to.equal(response.status); - expect(response.headers["content-type"]).to.include("application/json"); - - if(response.status === 200) { - globalState.set("refundId", response.body.refund_id); - for(const key in res_data.body) { +Cypress.Commands.add( + "refundCallTest", + (requestBody, req_data, res_data, refund_amount, globalState) => { + const payment_id = globalState.get("paymentID"); + requestBody.payment_id = payment_id; + requestBody.amount = refund_amount; + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/refunds`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + body: requestBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + + if (response.status === 200) { + globalState.set("refundId", response.body.refund_id); + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + expect(response.body.payment_id).to.equal(payment_id); + } else { + defaultErrorHandler(response, res_data); + } + }); + }, +); + +Cypress.Commands.add( + "syncRefundCallTest", + (req_data, res_data, globalState) => { + const refundId = globalState.get("refundId"); + cy.request({ + method: "GET", + url: `${globalState.get("baseUrl")}/refunds/${refundId}`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + for (const key in res_data.body) { expect(res_data.body[key]).to.equal(response.body[key]); } - expect(response.body.payment_id).to.equal(payment_id); - } - else{ - defaultErrorHandler(response, res_data); - } - - }); -}); + }); + }, +); -Cypress.Commands.add("syncRefundCallTest", (req_data, res_data, globalState) => { - const refundId = globalState.get("refundId"); - cy.request({ - method: "GET", - url: `${globalState.get("baseUrl")}/refunds/${refundId}`, - headers: { - "Content-Type": "application/json", - "api-key": globalState.get("apiKey"), - }, - failOnStatusCode: false, - }).then((response) => { - logRequestId(response.headers['x-request-id']); - expect(res_data.status).to.equal(response.status); - expect(response.headers["content-type"]).to.include("application/json"); - for(const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); - } - }); -}); +Cypress.Commands.add( + "citForMandatesCallTest", + ( + requestBody, + req_data, + res_data, + amount, + confirm, + capture_method, + payment_type, + globalState, + ) => { + requestBody.payment_method_data.card = req_data.card; + requestBody.payment_type = payment_type; + requestBody.confirm = confirm; + requestBody.amount = amount; + requestBody.currency = req_data.currency; + requestBody.capture_method = capture_method; + requestBody.mandate_data.mandate_type = req_data.mandate_type; + requestBody.customer_id = globalState.get("customerId"); + globalState.set("paymentAmount", requestBody.amount); + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payments`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + body: requestBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + globalState.set("mandateId", response.body.mandate_id); + globalState.set("paymentID", response.body.payment_id); -Cypress.Commands.add("citForMandatesCallTest", (requestBody, req_data, res_data, amount, confirm, capture_method, payment_type, globalState) => { - requestBody.payment_method_data.card = req_data.card; - requestBody.payment_type = payment_type; - requestBody.confirm = confirm; - requestBody.amount = amount; - requestBody.currency = req_data.currency; - requestBody.capture_method = capture_method; - requestBody.mandate_data.mandate_type = req_data.mandate_type; - requestBody.customer_id = globalState.get("customerId"); - globalState.set("paymentAmount", requestBody.amount); - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/payments`, - headers: { - "Content-Type": "application/json", - "api-key": globalState.get("apiKey"), - }, - failOnStatusCode: false, - body: requestBody, - }).then((response) => { - logRequestId(response.headers['x-request-id']); - expect(res_data.status).to.equal(response.status); - expect(response.headers["content-type"]).to.include("application/json"); - globalState.set("mandateId", response.body.mandate_id); - globalState.set("paymentID", response.body.payment_id); + if (response.status === 200) { + if (response.body.capture_method === "automatic") { + expect(response.body).to.have.property("mandate_id"); + if (response.body.authentication_type === "three_ds") { + expect(response.body) + .to.have.property("next_action") + .to.have.property("redirect_to_url"); + const nextActionUrl = response.body.next_action.redirect_to_url; + globalState.set( + "nextActionUrl", + response.body.next_action.redirect_to_url, + ); + cy.log(response.body); + cy.log(nextActionUrl); + } else if (response.body.authentication_type === "no_three_ds") { + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + } + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + } else if (response.body.capture_method === "manual") { + expect(response.body).to.have.property("mandate_id"); + if (response.body.authentication_type === "three_ds") { + expect(response.body).to.have.property("next_action"); + } + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + } + } else { + defaultErrorHandler(response, res_data); + } + }); + }, +); - if(response.status === 200) { +Cypress.Commands.add( + "mitForMandatesCallTest", + (requestBody, amount, confirm, capture_method, globalState) => { + requestBody.amount = amount; + requestBody.confirm = confirm; + requestBody.capture_method = capture_method; + requestBody.mandate_id = globalState.get("mandateId"); + requestBody.customer_id = globalState.get("customerId"); + globalState.set("paymentAmount", requestBody.amount); + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payments`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + body: requestBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + expect(response.headers["content-type"]).to.include("application/json"); + globalState.set("paymentID", response.body.payment_id); if (response.body.capture_method === "automatic") { - expect(response.body).to.have.property("mandate_id"); if (response.body.authentication_type === "three_ds") { - expect(response.body).to.have.property("next_action") + expect(response.body) + .to.have.property("next_action") .to.have.property("redirect_to_url"); const nextActionUrl = response.body.next_action.redirect_to_url; - globalState.set("nextActionUrl", response.body.next_action.redirect_to_url); cy.log(response.body); cy.log(nextActionUrl); } else if (response.body.authentication_type === "no_three_ds") { - for(const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); - } - } - for(const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); + expect(response.body.status).to.equal("succeeded"); + } else { + defaultErrorHandler(response, res_data); } - } - else if (response.body.capture_method === "manual") { - expect(response.body).to.have.property("mandate_id"); + } else if (response.body.capture_method === "manual") { if (response.body.authentication_type === "three_ds") { - expect(response.body).to.have.property("next_action") - } - for(const key in res_data.body) { - expect(res_data.body[key]).to.equal(response.body[key]); + expect(response.body) + .to.have.property("next_action") + .to.have.property("redirect_to_url"); + const nextActionUrl = response.body.next_action.redirect_to_url; + cy.log(response.body); + cy.log(nextActionUrl); + } else if (response.body.authentication_type === "no_three_ds") { + expect(response.body.status).to.equal("requires_capture"); + } else { + defaultErrorHandler(response, res_data); } } - } - else{ - defaultErrorHandler(response, res_data); - } - }); -}); - -Cypress.Commands.add("mitForMandatesCallTest", (requestBody, amount, confirm, capture_method, globalState) => { - requestBody.amount = amount; - requestBody.confirm = confirm; - requestBody.capture_method = capture_method; - requestBody.mandate_id = globalState.get("mandateId"); - requestBody.customer_id = globalState.get("customerId"); - globalState.set("paymentAmount", requestBody.amount); - cy.request({ - method: "POST", - url: `${globalState.get("baseUrl")}/payments`, - headers: { - "Content-Type": "application/json", - "api-key": globalState.get("apiKey"), - }, - failOnStatusCode: false, - body: requestBody, - }).then((response) => { - logRequestId(response.headers['x-request-id']); - expect(response.headers["content-type"]).to.include("application/json"); - globalState.set("paymentID", response.body.payment_id); - if (response.body.capture_method === "automatic") { - if (response.body.authentication_type === "three_ds") { - expect(response.body).to.have.property("next_action") - .to.have.property("redirect_to_url"); - const nextActionUrl = response.body.next_action.redirect_to_url; - cy.log(response.body); - cy.log(nextActionUrl); - } else if (response.body.authentication_type === "no_three_ds") { - expect(response.body.status).to.equal("succeeded"); - } else { - defaultErrorHandler(response, res_data); - } - } - else if (response.body.capture_method === "manual") { - if (response.body.authentication_type === "three_ds") { - expect(response.body).to.have.property("next_action") - .to.have.property("redirect_to_url"); - const nextActionUrl = response.body.next_action.redirect_to_url; - cy.log(response.body); - cy.log(nextActionUrl); - } else if (response.body.authentication_type === "no_three_ds") { - expect(response.body.status).to.equal("requires_capture"); - } else { - defaultErrorHandler(response, res_data); - } - } - }); -}); - + }); + }, +); Cypress.Commands.add("listMandateCallTest", (globalState) => { const customerId = globalState.get("customerId"); @@ -774,7 +915,7 @@ Cypress.Commands.add("listMandateCallTest", (globalState) => { "api-key": globalState.get("apiKey"), }, }).then((response) => { - logRequestId(response.headers['x-request-id']); + logRequestId(response.headers["x-request-id"]); expect(response.headers["content-type"]).to.include("application/json"); @@ -783,7 +924,7 @@ Cypress.Commands.add("listMandateCallTest", (globalState) => { if (response.body[i].mandate_id === globalState.get("mandateId")) { expect(response.body[i].status).to.equal("active"); } - }; + } }); }); @@ -796,9 +937,9 @@ Cypress.Commands.add("revokeMandateCallTest", (globalState) => { "Content-Type": "application/json", "api-key": globalState.get("apiKey"), }, - failOnStatusCode: false + failOnStatusCode: false, }).then((response) => { - logRequestId(response.headers['x-request-id']); + logRequestId(response.headers["x-request-id"]); expect(response.headers["content-type"]).to.include("application/json"); if (response.body.status === 200) { @@ -809,17 +950,20 @@ Cypress.Commands.add("revokeMandateCallTest", (globalState) => { }); }); -Cypress.Commands.add("handleRedirection", (globalState, expected_redirection) => { - let connectorId = globalState.get("connectorId"); - let expected_url = new URL(expected_redirection); - let redirection_url = new URL(globalState.get("nextActionUrl")); - handleRedirection( - "three_ds", - { redirection_url, expected_url }, - connectorId, - null - ); -}); +Cypress.Commands.add( + "handleRedirection", + (globalState, expected_redirection) => { + let connectorId = globalState.get("connectorId"); + let expected_url = new URL(expected_redirection); + let redirection_url = new URL(globalState.get("nextActionUrl")); + handleRedirection( + "three_ds", + { redirection_url, expected_url }, + connectorId, + null, + ); + }, +); Cypress.Commands.add( "handleBankRedirectRedirection", @@ -834,10 +978,10 @@ Cypress.Commands.add( "bank_redirect", { redirection_url, expected_url }, connectorId, - payment_method_type + payment_method_type, ); } - } + }, ); Cypress.Commands.add( @@ -850,9 +994,9 @@ Cypress.Commands.add( "bank_transfer", { redirection_url, expected_redirection }, connectorId, - payment_method_type + payment_method_type, ); - } + }, ); Cypress.Commands.add("listCustomerPMCallTest", (globalState) => { @@ -865,15 +1009,15 @@ Cypress.Commands.add("listCustomerPMCallTest", (globalState) => { "api-key": globalState.get("apiKey"), }, }).then((response) => { - logRequestId(response.headers['x-request-id']); + logRequestId(response.headers["x-request-id"]); expect(response.headers["content-type"]).to.include("application/json"); if (response.body.customer_payment_methods[0]?.payment_token) { - const paymentToken = response.body.customer_payment_methods[0].payment_token; + const paymentToken = + response.body.customer_payment_methods[0].payment_token; globalState.set("paymentToken", paymentToken); // Set paymentToken in globalState expect(paymentToken).to.equal(globalState.get("paymentToken")); // Verify paymentToken - } - else { + } else { defaultErrorHandler(response, res_data); } }); @@ -889,8 +1033,144 @@ Cypress.Commands.add("listRefundCallTest", (requestBody, globalState) => { }, body: requestBody, }).then((response) => { - logRequestId(response.headers['x-request-id']); + logRequestId(response.headers["x-request-id"]); expect(response.headers["content-type"]).to.include("application/json"); - expect(response.body.data).to.be.an('array').and.not.empty; + expect(response.body.data).to.be.an("array").and.not.empty; + }); +}); + +Cypress.Commands.add( + "createConfirmPayoutTest", + ( + createConfirmPayoutBody, + req_data, + res_data, + confirm, + auto_fulfill, + globalState, + ) => { + for (const key in req_data) { + createConfirmPayoutBody[key] = req_data[key]; + } + createConfirmPayoutBody.auto_fulfill = auto_fulfill; + createConfirmPayoutBody.confirm = confirm; + createConfirmPayoutBody.customer_id = globalState.get("customerId"); + + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payouts/create`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + body: createConfirmPayoutBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + + if (response.status === 200) { + globalState.set("payoutAmount", createConfirmPayoutBody.amount); + globalState.set("payoutID", response.body.payout_id); + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + } else { + expect(response.body).to.have.property("error"); + for (const key in res_data.body.error) { + expect(res_data.body.error[key]).to.equal(response.body.error[key]); + } + } + }); + }, +); + +Cypress.Commands.add( + "fulfillPayoutCallTest", + (payoutFulfillBody, req_data, res_data, globalState) => { + payoutFulfillBody.payout_id = globalState.get("payoutID"); + + cy.request({ + method: "POST", + url: `${globalState.get("baseUrl")}/payouts/${globalState.get("payoutID")}/fulfill`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + body: payoutFulfillBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + + if (response.status === 200) { + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + } else { + expect(response.body).to.have.property("error"); + for (const key in res_data.body.error) { + expect(res_data.body.error[key]).to.equal(response.body.error[key]); + } + } + }); + }, +); + +Cypress.Commands.add( + "updatePayoutCallTest", + (payoutConfirmBody, req_data, res_data, auto_fulfill, globalState) => { + payoutConfirmBody.confirm = true; + payoutConfirmBody.auto_fulfill = auto_fulfill; + + cy.request({ + method: "PUT", + url: `${globalState.get("baseUrl")}/payouts/${globalState.get("payoutID")}`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + body: payoutConfirmBody, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + + expect(res_data.status).to.equal(response.status); + expect(response.headers["content-type"]).to.include("application/json"); + + if (response.status === 200) { + for (const key in res_data.body) { + expect(res_data.body[key]).to.equal(response.body[key]); + } + } else { + expect(response.body).to.have.property("error"); + for (const key in res_data.body.error) { + expect(res_data.body.error[key]).to.equal(response.body.error[key]); + } + } }); + }, +); + +Cypress.Commands.add("retrievePayoutCallTest", (globalState) => { + const payout_id = globalState.get("payoutID"); + cy.request({ + method: "GET", + url: `${globalState.get("baseUrl")}/payouts/${payout_id}`, + headers: { + "Content-Type": "application/json", + "api-key": globalState.get("apiKey"), + }, + failOnStatusCode: false, + }).then((response) => { + logRequestId(response.headers["x-request-id"]); + + expect(response.headers["content-type"]).to.include("application/json"); + expect(response.body.payout_id).to.equal(payout_id); + expect(response.body.amount).to.equal(globalState.get("payoutAmount")); }); +}); diff --git a/cypress-tests/cypress/support/e2e.js b/cypress-tests/cypress/support/e2e.js index 9b1ef71ce0f5..3a252243880a 100644 --- a/cypress-tests/cypress/support/e2e.js +++ b/cypress-tests/cypress/support/e2e.js @@ -14,7 +14,7 @@ // *********************************************************** // Import commands.js using ES2015 syntax: -import './commands'; +import "./commands"; // Alternatively you can use CommonJS syntax: -// require('./commands') \ No newline at end of file +// require('./commands') diff --git a/cypress-tests/cypress/support/redirectionhandler.js b/cypress-tests/cypress/support/redirectionhandler.js index 6e4818581531..f6b65d825142 100644 --- a/cypress-tests/cypress/support/redirectionhandler.js +++ b/cypress-tests/cypress/support/redirectionhandler.js @@ -4,7 +4,7 @@ export function handleRedirection( redirection_type, urls, connectorId, - payment_method_type + payment_method_type, ) { switch (redirection_type) { case "three_ds": @@ -15,7 +15,7 @@ export function handleRedirection( urls.redirection_url, urls.expected_url, connectorId, - payment_method_type + payment_method_type, ); break; case "bank_transfer": @@ -23,7 +23,7 @@ export function handleRedirection( urls.redirection_url, urls.expected_url, connectorId, - payment_method_type + payment_method_type, ); break; default: @@ -35,7 +35,7 @@ function bankTransferRedirection( redirection_url, expected_url, connectorId, - payment_method_type + payment_method_type, ) { cy.request(redirection_url.href).then((response) => { switch (connectorId) { @@ -119,7 +119,7 @@ function bankRedirectRedirection( redirection_url, expected_url, connectorId, - payment_method_type + payment_method_type, ) { let verifyUrl = false; cy.visit(redirection_url.href); @@ -136,7 +136,7 @@ function bankRedirectRedirection( case "ideal": cy.get(":nth-child(4) > td > p").should( "contain.text", - "Your Payment was Authorised/Refused/Cancelled (It may take up to five minutes to show on the Payment List)" + "Your Payment was Authorised/Refused/Cancelled (It may take up to five minutes to show on the Payment List)", ); cy.get(".btnLink").click(); cy.url().should("include", "status=succeeded"); @@ -144,12 +144,12 @@ function bankRedirectRedirection( break; case "giropay": cy.get( - ".rds-cookies-overlay__allow-all-cookies-btn > .rds-button" + ".rds-cookies-overlay__allow-all-cookies-btn > .rds-button", ).click(); cy.wait(5000); cy.get(".normal-3").should( "contain.text", - "Bank suchen ‑ mit giropay zahlen." + "Bank suchen ‑ mit giropay zahlen.", ); cy.get("#bankSearch").type("giropay TestBank{enter}"); cy.get(".normal-2 > div").click(); @@ -186,14 +186,14 @@ function bankRedirectRedirection( .should("contain", "Continue") .click(); } - } + }, ); break; case "trustly": break; default: throw new Error( - `Unsupported payment method type: ${payment_method_type}` + `Unsupported payment method type: ${payment_method_type}`, ); } verifyUrl = true; @@ -203,16 +203,16 @@ function bankRedirectRedirection( case "eps": cy.get("._transactionId__header__iXVd_").should( "contain.text", - "Bank suchen ‑ mit eps zahlen." + "Bank suchen ‑ mit eps zahlen.", ); cy.get(".BankSearch_searchInput__uX_9l").type( - "Allgemeine Sparkasse Oberösterreich Bank AG{enter}" + "Allgemeine Sparkasse Oberösterreich Bank AG{enter}", ); cy.get(".BankSearch_searchResultItem__lbcKm").click(); cy.get("._transactionId__primaryButton__nCa0r").click(); cy.get("#loginTitle").should( "contain.text", - "eps Online-Überweisung Login" + "eps Online-Überweisung Login", ); cy.get("#user") .should("be.visible") @@ -224,7 +224,7 @@ function bankRedirectRedirection( case "ideal": cy.get("p").should( "contain.text", - "Choose your iDeal Issuer Bank please" + "Choose your iDeal Issuer Bank please", ); cy.get("#issuerSearchInput").click(); cy.get("#issuerSearchInput").type("ING{enter}"); @@ -233,10 +233,10 @@ function bankRedirectRedirection( case "giropay": cy.get("._transactionId__header__iXVd_").should( "contain.text", - "Bank suchen ‑ mit giropay zahlen." + "Bank suchen ‑ mit giropay zahlen.", ); cy.get(".BankSearch_searchInput__uX_9l").type( - "Volksbank Hildesheim{enter}" + "Volksbank Hildesheim{enter}", ); cy.get(".BankSearch_searchIcon__EcVO7").click(); cy.get(".BankSearch_bankWrapper__R5fUK").click(); @@ -249,7 +249,7 @@ function bankRedirectRedirection( break; default: throw new Error( - `Unsupported payment method type: ${payment_method_type}` + `Unsupported payment method type: ${payment_method_type}`, ); } verifyUrl = false; @@ -273,7 +273,7 @@ function verifyReturnUrl(redirection_url, expected_url, forward_flow) { { args: { expected_url: expected_url.origin } }, ({ expected_url }) => { cy.window().its("location.origin").should("eq", expected_url); - } + }, ); } } @@ -303,7 +303,7 @@ async function fetchAndParseQRCode(url) { const qrCodeData = jsQR( imageData.data, imageData.width, - imageData.height + imageData.height, ); if (qrCodeData) { diff --git a/cypress-tests/cypress/utils/State.js b/cypress-tests/cypress/utils/State.js index dae4963000f0..b7b96dae5ee8 100644 --- a/cypress-tests/cypress/utils/State.js +++ b/cypress-tests/cypress/utils/State.js @@ -5,7 +5,9 @@ class State { this.data["connectorId"] = Cypress.env("CONNECTOR"); this.data["baseUrl"] = Cypress.env("BASEURL"); this.data["adminApiKey"] = Cypress.env("ADMINAPIKEY"); - this.data["connectorAuthFilePath"] = Cypress.env("CONNECTOR_AUTH_FILE_PATH"); + this.data["connectorAuthFilePath"] = Cypress.env( + "CONNECTOR_AUTH_FILE_PATH", + ); } set(key, val) { diff --git a/cypress-tests/package.json b/cypress-tests/package.json index af4b0244fbd5..b6602ece459e 100644 --- a/cypress-tests/package.json +++ b/cypress-tests/package.json @@ -6,7 +6,9 @@ "scripts": { "cypress": "npx cypress open", "cypress-e2e": "npx cypress run --e2e", - "cypress:ci": "npx cypress run --headless" + "cypress:ci": "npx cypress run --headless", + "cypress:payments": "cypress run --spec 'cypress/e2e/PaymentTest/**/*'", + "cypress:payouts": "cypress run --spec 'cypress/e2e/PayoutTest/**/*'" }, "author": "", "license": "ISC", diff --git a/cypress-tests/readme.md b/cypress-tests/readme.md index 511625cdbfb9..78251ef9c810 100644 --- a/cypress-tests/readme.md +++ b/cypress-tests/readme.md @@ -141,7 +141,7 @@ Cypress.Commands.add("listMandateCallTest", (globalState) => { } else { cy.task( "cli_log", - "x-request-id is not available in the response headers" + "x-request-id is not available in the response headers", ); } expect(response.headers["content-type"]).to.include("application/json"); From 901b88ab8065459cf9f9d8b2ac27f378449afc4a Mon Sep 17 00:00:00 2001 From: Pa1NarK <69745008+pixincreate@users.noreply.github.com> Date: Tue, 4 Jun 2024 18:13:56 +0530 Subject: [PATCH 24/25] fix(cypress): fix `redirectionHandler` from failing to compile (#4846) --- .../cypress/e2e/PaymentUtils/Commons.js | 19 +- ...ectionhandler.js => redirectionHandler.js} | 0 cypress-tests/package-lock.json | 342 +++++++++++++----- cypress-tests/package.json | 3 +- 4 files changed, 270 insertions(+), 94 deletions(-) rename cypress-tests/cypress/support/{redirectionhandler.js => redirectionHandler.js} (100%) diff --git a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js index 9436f334068b..d3228396fc7f 100644 --- a/cypress-tests/cypress/e2e/PaymentUtils/Commons.js +++ b/cypress-tests/cypress/e2e/PaymentUtils/Commons.js @@ -8,7 +8,22 @@ const globalState = new State({ connectorAuthFilePath: Cypress.env("CONNECTOR_AUTH_FILE_PATH"), }); -const connectorId = globalState.get("connectorId"); +const connectorName = normalise(globalState.get("connectorId")); + +function normalise(input) { + const exceptions = { + bankofamerica: "Bank of America", + cybersource: "Cybersource", + paypal: "Paypal", + // Add more known exceptions here + }; + + if (exceptions[input.toLowerCase()]) { + return exceptions[input.toLowerCase()]; + } else { + return input; + } +} const successfulNo3DSCardDetails = { card_number: "4111111111111111", @@ -42,7 +57,7 @@ const getDefaultExchange = () => ({ body: { error: { type: "invalid_request", - message: `Selected payment method through ${connectorId} is not implemented`, + message: `Selected payment method through ${connectorName} is not implemented`, code: "IR_00", }, }, diff --git a/cypress-tests/cypress/support/redirectionhandler.js b/cypress-tests/cypress/support/redirectionHandler.js similarity index 100% rename from cypress-tests/cypress/support/redirectionhandler.js rename to cypress-tests/cypress/support/redirectionHandler.js diff --git a/cypress-tests/package-lock.json b/cypress-tests/package-lock.json index 91a7cc32f35c..10bda21a9bb2 100644 --- a/cypress-tests/package-lock.json +++ b/cypress-tests/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { - "cypress": "^13.7.3" + "cypress": "^13.10.0", + "jsqr": "^1.4.0" } }, "node_modules/@colors/colors": { @@ -17,6 +18,7 @@ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=0.1.90" @@ -27,6 +29,7 @@ "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -56,6 +59,7 @@ "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.1.0", "lodash.once": "^4.1.1" @@ -66,15 +70,17 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/@types/node": { - "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", + "version": "20.14.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.1.tgz", + "integrity": "sha512-T2MzSGEu+ysB/FkWfqmhV3PLyQlowdptmmgD20C6QxsS8Fmv5SjpZ1ayXaEC0S21/h5UJ9iA6W/5vSNU5l00OA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "undici-types": "~5.26.4" @@ -84,19 +90,22 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/sizzle": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz", "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "@types/node": "*" @@ -107,6 +116,7 @@ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, + "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -120,6 +130,7 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -129,6 +140,7 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -144,6 +156,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -153,6 +166,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -181,13 +195,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": "~2.1.0" } @@ -197,6 +213,7 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -206,6 +223,7 @@ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -214,19 +232,22 @@ "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, + "license": "ISC", "engines": { "node": ">= 4.0.0" } @@ -236,15 +257,17 @@ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.0.tgz", + "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==", + "dev": true, + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -264,13 +287,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tweetnacl": "^0.14.3" } @@ -279,13 +304,15 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/buffer": { "version": "5.7.1", @@ -306,6 +333,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -316,6 +344,7 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -325,6 +354,7 @@ "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -334,6 +364,7 @@ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -352,13 +383,15 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -375,6 +408,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -387,6 +421,7 @@ "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -402,6 +437,7 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } @@ -411,6 +447,7 @@ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -420,6 +457,7 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, + "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" }, @@ -428,10 +466,11 @@ } }, "node_modules/cli-table3": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.4.tgz", - "integrity": "sha512-Lm3L0p+/npIQWNIiyF/nAn7T5dnOwR3xNTHXYEBFBFVPXzCVNZ5lqEC/1eo/EVfpDsQ1I+TX4ORPQgp+UI0CRw==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", "dev": true, + "license": "MIT", "dependencies": { "string-width": "^4.2.0" }, @@ -447,6 +486,7 @@ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", "dev": true, + "license": "MIT", "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" @@ -463,6 +503,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -474,19 +515,22 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -499,6 +543,7 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -508,6 +553,7 @@ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -516,13 +562,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -533,11 +581,12 @@ } }, "node_modules/cypress": { - "version": "13.7.3", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.7.3.tgz", - "integrity": "sha512-uoecY6FTCAuIEqLUYkTrxamDBjMHTYak/1O7jtgwboHiTnS1NaMOoR08KcTrbRZFCBvYOiS4tEkQRmsV+xcrag==", + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.10.0.tgz", + "integrity": "sha512-tOhwRlurVOQbMduX+KonoMeQILs2cwR3yHGGENoFvvSoLUBHmJ8b9/n21gFSDqjlOJ+SRVcwuh+fG/JDsHsT6Q==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@cypress/request": "^3.0.0", "@cypress/xvfb": "^1.2.4", @@ -594,6 +643,7 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" }, @@ -602,16 +652,18 @@ } }, "node_modules/dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==", - "dev": true + "version": "1.11.11", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", + "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==", + "dev": true, + "license": "MIT" }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -629,6 +681,7 @@ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -646,6 +699,7 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -655,6 +709,7 @@ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, + "license": "MIT", "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -664,13 +719,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, + "license": "MIT", "dependencies": { "once": "^1.4.0" } @@ -680,6 +737,7 @@ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -693,6 +751,7 @@ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -705,6 +764,7 @@ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -714,6 +774,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } @@ -722,13 +783,15 @@ "version": "6.4.7", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/execa": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.0", "get-stream": "^5.0.0", @@ -752,6 +815,7 @@ "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^2.2.0" }, @@ -763,13 +827,15 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", @@ -792,13 +858,15 @@ "dev": true, "engines": [ "node >=0.6.0" - ] + ], + "license": "MIT" }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, + "license": "MIT", "dependencies": { "pend": "~1.2.0" } @@ -808,6 +876,7 @@ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -823,6 +892,7 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } @@ -832,6 +902,7 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -846,6 +917,7 @@ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, + "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -861,6 +933,7 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -870,6 +943,7 @@ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -889,6 +963,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, + "license": "MIT", "dependencies": { "pump": "^3.0.0" }, @@ -904,6 +979,7 @@ "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", "dev": true, + "license": "MIT", "dependencies": { "async": "^3.2.0" } @@ -913,6 +989,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" } @@ -922,6 +999,7 @@ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", "dev": true, + "license": "MIT", "dependencies": { "ini": "2.0.0" }, @@ -937,6 +1015,7 @@ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -948,13 +1027,15 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -964,6 +1045,7 @@ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -976,6 +1058,7 @@ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -988,6 +1071,7 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -1000,6 +1084,7 @@ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -1012,6 +1097,7 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^2.0.2", @@ -1026,6 +1112,7 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=8.12.0" } @@ -1048,13 +1135,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1064,6 +1153,7 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -1073,6 +1163,7 @@ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", "dev": true, + "license": "MIT", "dependencies": { "ci-info": "^3.2.0" }, @@ -1085,6 +1176,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1094,6 +1186,7 @@ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "dev": true, + "license": "MIT", "dependencies": { "global-dirs": "^3.0.0", "is-path-inside": "^3.0.2" @@ -1110,6 +1203,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1119,6 +1213,7 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -1130,13 +1225,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -1148,37 +1245,43 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -1194,6 +1297,7 @@ "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -1201,11 +1305,19 @@ "verror": "1.10.0" } }, + "node_modules/jsqr": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsqr/-/jsqr-1.4.0.tgz", + "integrity": "sha512-dxLob7q65Xg2DvstYkRpkYtmKm2sPJ9oFhrhmudT1dZvNFFTlroai3AWSpLey/w5vMcLBXRgOJsbXpdN9HzU/A==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/lazy-ass": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", "dev": true, + "license": "MIT", "engines": { "node": "> 0.8" } @@ -1215,6 +1327,7 @@ "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", "dev": true, + "license": "MIT", "dependencies": { "cli-truncate": "^2.1.0", "colorette": "^2.0.16", @@ -1241,19 +1354,22 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -1270,6 +1386,7 @@ "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-escapes": "^4.3.0", "cli-cursor": "^3.1.0", @@ -1288,6 +1405,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -1305,6 +1423,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -1314,29 +1433,19 @@ "node": ">=8" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1346,6 +1455,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -1358,6 +1468,7 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1367,6 +1478,7 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1375,13 +1487,15 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -1394,6 +1508,7 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1403,6 +1518,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -1412,6 +1528,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -1426,13 +1543,15 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/p-map": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, + "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -1448,6 +1567,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1456,19 +1576,22 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1478,6 +1601,7 @@ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -1490,6 +1614,7 @@ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6.0" } @@ -1498,19 +1623,22 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -1521,6 +1649,7 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1530,6 +1659,7 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -1544,13 +1674,15 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/request-progress": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", "dev": true, + "license": "MIT", "dependencies": { "throttleit": "^1.0.0" } @@ -1559,13 +1691,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -1578,13 +1712,15 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -1607,22 +1743,22 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -1635,6 +1771,7 @@ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -1652,6 +1789,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -1664,6 +1802,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1673,6 +1812,7 @@ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -1690,13 +1830,15 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/slice-ansi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -1711,6 +1853,7 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, + "license": "MIT", "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -1736,6 +1879,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -1750,6 +1894,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -1762,6 +1907,7 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1771,6 +1917,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -1786,6 +1933,7 @@ "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", "integrity": "sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -1794,22 +1942,25 @@ "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.14" } }, "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -1825,6 +1976,7 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4.0.0" } @@ -1833,13 +1985,15 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -1851,13 +2005,15 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true + "dev": true, + "license": "Unlicense" }, "node_modules/type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -1870,6 +2026,7 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/universalify": { @@ -1877,6 +2034,7 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.0.0" } @@ -1886,6 +2044,7 @@ "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1895,6 +2054,7 @@ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dev": true, + "license": "MIT", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -1905,6 +2065,7 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -1917,6 +2078,7 @@ "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -1928,6 +2090,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -1943,6 +2106,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -1959,19 +2123,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, + "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" diff --git a/cypress-tests/package.json b/cypress-tests/package.json index b6602ece459e..4bb7e4153430 100644 --- a/cypress-tests/package.json +++ b/cypress-tests/package.json @@ -12,7 +12,8 @@ }, "author": "", "license": "ISC", - "dependencies": { + "devDependencies": { + "cypress": "^13.10.0", "jsqr": "^1.4.0" } } From d413e1a8a5105a51f1909e160cda1c3648713926 Mon Sep 17 00:00:00 2001 From: Jeeva Ramachandran <120017870+JeevaRamu0104@users.noreply.github.com> Date: Tue, 4 Jun 2024 18:18:27 +0530 Subject: [PATCH 25/25] chore(euclid_wasm): paypal metadata (#4868) --- crates/connector_configs/src/transformer.rs | 33 +++++++++++---------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/crates/connector_configs/src/transformer.rs b/crates/connector_configs/src/transformer.rs index 87d1e3e810b6..976068c98b65 100644 --- a/crates/connector_configs/src/transformer.rs +++ b/crates/connector_configs/src/transformer.rs @@ -71,24 +71,27 @@ impl DashboardRequestPayload { api_models::enums::PaymentExperience::RedirectToUrl, api_models::enums::PaymentExperience::InvokeSdkClient, ]; - + let default_provider = Provider { + payment_method_type: Paypal, + accepted_currencies: None, + accepted_countries: None, + }; + let provider = providers.first().unwrap_or(&default_provider); let mut payment_method_types = Vec::new(); for experience in payment_experiences { - for provider in &providers { - let data = payment_methods::RequestPaymentMethodTypes { - payment_method_type: provider.payment_method_type, - card_networks: None, - minimum_amount: Some(0), - maximum_amount: Some(68607706), - recurring_enabled: true, - installment_payment_enabled: false, - accepted_currencies: provider.accepted_currencies.clone(), - accepted_countries: provider.accepted_countries.clone(), - payment_experience: Some(experience), - }; - payment_method_types.push(data); - } + let data = payment_methods::RequestPaymentMethodTypes { + payment_method_type: provider.payment_method_type, + card_networks: None, + minimum_amount: Some(0), + maximum_amount: Some(68607706), + recurring_enabled: true, + installment_payment_enabled: false, + accepted_currencies: provider.accepted_currencies.clone(), + accepted_countries: provider.accepted_countries.clone(), + payment_experience: Some(experience), + }; + payment_method_types.push(data); } payment_method_types