From d6a3e508e28af74146ee38178f33f162274324f1 Mon Sep 17 00:00:00 2001 From: ItsMeShashank Date: Mon, 19 Dec 2022 18:43:04 +0530 Subject: [PATCH] feat(router): add straight-through routing connector selection in payments (#153) --- add_connector.md | 2 +- crates/api_models/src/enums.rs | 28 +++++++ crates/api_models/src/payments.rs | 1 + .../router/src/compatibility/stripe/errors.rs | 1 + .../compatibility/stripe/payment_intents.rs | 9 +++ .../stripe/payment_intents/types.rs | 2 + .../src/compatibility/stripe/setup_intents.rs | 7 ++ .../src/core/errors/api_error_response.rs | 3 + crates/router/src/core/payments.rs | 73 ++++++++++--------- crates/router/src/core/payments/helpers.rs | 73 +++++++++++-------- crates/router/src/core/payments/operations.rs | 13 +++- .../payments/operations/payment_confirm.rs | 5 +- .../payments/operations/payment_create.rs | 5 +- .../operations/payment_method_validate.rs | 3 +- .../payments/operations/payment_session.rs | 3 +- .../core/payments/operations/payment_start.rs | 5 +- .../payments/operations/payment_status.rs | 5 +- .../payments/operations/payment_update.rs | 5 +- crates/router/src/core/webhooks.rs | 1 + crates/router/src/routes/payments.rs | 13 ++++ .../src/scheduler/workflows/payment_sync.rs | 1 + crates/router/src/types.rs | 2 +- crates/router/src/types/api.rs | 10 ++- crates/router/src/types/connector.rs | 15 +--- crates/router/tests/payments.rs | 4 + crates/router/tests/payments2.rs | 3 + 26 files changed, 192 insertions(+), 100 deletions(-) diff --git a/add_connector.md b/add_connector.md index 7ef93e82ce..14868530fb 100644 --- a/add_connector.md +++ b/add_connector.md @@ -293,7 +293,7 @@ Feel free to connect with us in case of queries and also if you want to confirm Add connector name in : -- `crates/router/src/types/connector.rs` in Connector enum +- `crates/api_models/src/enums.rs` in Connector enum (in alphabetical order) - `crates/router/src/types/api/mod.rs` convert_connector function Configure the Connectors API credentials using the PaymentConnectors API. diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 01b79e688e..9da929e51c 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -468,6 +468,34 @@ pub enum MandateStatus { Revoked, } +#[derive( + Clone, + Copy, + Debug, + Default, + Eq, + PartialEq, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumString, + frunk::LabelledGeneric, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum Connector { + Aci, + Adyen, + Applepay, + Authorizedotnet, + Braintree, + Checkout, + #[default] + Dummy, + Klarna, + Stripe, +} + impl From for IntentStatus { fn from(s: AttemptStatus) -> Self { match s { diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 5b2ff66c60..f4d2131a80 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -22,6 +22,7 @@ pub struct PaymentsRequest { pub merchant_id: Option, #[serde(default, deserialize_with = "amount::deserialize_option")] pub amount: Option, + pub connector: Option, pub currency: Option, pub capture_method: Option, pub amount_to_capture: Option, diff --git a/crates/router/src/compatibility/stripe/errors.rs b/crates/router/src/compatibility/stripe/errors.rs index 65b411be7a..3790e6d95d 100644 --- a/crates/router/src/compatibility/stripe/errors.rs +++ b/crates/router/src/compatibility/stripe/errors.rs @@ -349,6 +349,7 @@ impl From for ErrorCode { ApiErrorResponse::RefundFailed { data } => ErrorCode::RefundFailed, // Nothing at stripe to map ApiErrorResponse::InternalServerError => ErrorCode::InternalServerError, // not a stripe code + ApiErrorResponse::IncorrectConnectorNameGiven => ErrorCode::InternalServerError, ApiErrorResponse::MandateActive => ErrorCode::MandateActive, //not a stripe code ApiErrorResponse::CustomerRedacted => ErrorCode::CustomerRedacted, //not a stripe code ApiErrorResponse::DuplicateRefundRequest => ErrorCode::DuplicateRefundRequest, diff --git a/crates/router/src/compatibility/stripe/payment_intents.rs b/crates/router/src/compatibility/stripe/payment_intents.rs index 60bb699a00..3cead5fd8c 100644 --- a/crates/router/src/compatibility/stripe/payment_intents.rs +++ b/crates/router/src/compatibility/stripe/payment_intents.rs @@ -47,12 +47,14 @@ pub async fn payment_intents_create( &req, create_payment_req, |state, merchant_account, req| { + let connector = req.connector; payments::payments_core::( state, merchant_account, payments::PaymentCreate, req, api::AuthFlow::Merchant, + connector, payments::CallConnectorAction::Trigger, ) }, @@ -101,6 +103,7 @@ pub async fn payment_intents_retrieve( payments::PaymentStatus, payload, auth_flow, + None, payments::CallConnectorAction::Trigger, ) }, @@ -149,12 +152,14 @@ pub async fn payment_intents_update( &req, payload, |state, merchant_account, req| { + let connector = req.connector; payments::payments_core::( state, merchant_account, payments::PaymentUpdate, req, auth_flow, + connector, payments::CallConnectorAction::Trigger, ) }, @@ -204,12 +209,14 @@ pub async fn payment_intents_confirm( &req, payload, |state, merchant_account, req| { + let connector = req.connector; payments::payments_core::( state, merchant_account, payments::PaymentConfirm, req, auth_flow, + connector, payments::CallConnectorAction::Trigger, ) }, @@ -257,6 +264,7 @@ pub async fn payment_intents_capture( payments::PaymentCapture, payload, api::AuthFlow::Merchant, + None, payments::CallConnectorAction::Trigger, ) }, @@ -310,6 +318,7 @@ pub async fn payment_intents_cancel( payments::PaymentCancel, req, auth_flow, + None, payments::CallConnectorAction::Trigger, ) }, diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs index f4cf0933d7..8738d66d71 100644 --- a/crates/router/src/compatibility/stripe/payment_intents/types.rs +++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs @@ -114,6 +114,7 @@ impl From for Address { #[derive(Default, PartialEq, Eq, Deserialize, Clone)] pub(crate) struct StripePaymentIntentRequest { pub(crate) amount: Option, //amount in cents, hence passed as integer + pub(crate) connector: Option, pub(crate) currency: Option, #[serde(rename = "amount_to_capture")] pub(crate) amount_capturable: Option, @@ -137,6 +138,7 @@ impl From for PaymentsRequest { fn from(item: StripePaymentIntentRequest) -> Self { PaymentsRequest { amount: item.amount.map(|amount| amount.into()), + connector: item.connector, currency: item.currency.as_ref().map(|c| c.to_uppercase()), capture_method: item.capture_method, amount_to_capture: item.amount_capturable, diff --git a/crates/router/src/compatibility/stripe/setup_intents.rs b/crates/router/src/compatibility/stripe/setup_intents.rs index bf410e1930..6a0cec28be 100644 --- a/crates/router/src/compatibility/stripe/setup_intents.rs +++ b/crates/router/src/compatibility/stripe/setup_intents.rs @@ -43,12 +43,14 @@ pub async fn setup_intents_create( &req, create_payment_req, |state, merchant_account, req| { + let connector = req.connector; payments::payments_core::( state, merchant_account, payments::PaymentCreate, req, api::AuthFlow::Merchant, + connector, payments::CallConnectorAction::Trigger, ) }, @@ -97,6 +99,7 @@ pub async fn setup_intents_retrieve( payments::PaymentStatus, payload, auth_flow, + None, payments::CallConnectorAction::Trigger, ) }, @@ -145,12 +148,14 @@ pub async fn setup_intents_update( &req, payload, |state, merchant_account, req| { + let connector = req.connector; payments::payments_core::( state, merchant_account, payments::PaymentUpdate, req, auth_flow, + connector, payments::CallConnectorAction::Trigger, ) }, @@ -200,12 +205,14 @@ pub async fn setup_intents_confirm( &req, payload, |state, merchant_account, req| { + let connector = req.connector; payments::payments_core::( state, merchant_account, payments::PaymentConfirm, req, auth_flow, + connector, payments::CallConnectorAction::Trigger, ) }, diff --git a/crates/router/src/core/errors/api_error_response.rs b/crates/router/src/core/errors/api_error_response.rs index bfeabd7b1d..95f631953e 100644 --- a/crates/router/src/core/errors/api_error_response.rs +++ b/crates/router/src/core/errors/api_error_response.rs @@ -123,6 +123,8 @@ pub enum ApiErrorResponse { PaymentNotSucceeded, #[error(error_type= ErrorType::ObjectNotFound, code = "RE_05", message = "Successful payment not found for the given payment id")] SuccessfulPaymentNotFound, + #[error(error_type = ErrorType::ObjectNotFound, code = "RE_05", message = "The connector provided in the request is incorrect or not available")] + IncorrectConnectorNameGiven, #[error(error_type = ErrorType::ObjectNotFound, code = "RE_05", message = "Address does not exist in our records.")] AddressNotFound, #[error(error_type = ErrorType::ValidationError, code = "RE_03", message = "Mandate Validation Failed" )] @@ -183,6 +185,7 @@ impl actix_web::ResponseError for ApiErrorResponse { | ApiErrorResponse::ClientSecretNotGiven | ApiErrorResponse::ClientSecretInvalid | ApiErrorResponse::SuccessfulPaymentNotFound + | ApiErrorResponse::IncorrectConnectorNameGiven | ApiErrorResponse::ResourceIdNotFound | ApiErrorResponse::AddressNotFound => StatusCode::BAD_REQUEST, // 400 ApiErrorResponse::DuplicateMerchantAccount diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 3b7a9e75ee..337a0c8400 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -25,15 +25,14 @@ use crate::{ payments, }, db::StorageInterface, - logger, - pii::{Email, Secret}, + logger, pii, routes::AppState, scheduler::utils as pt_utils, services, types::{ self, - api::{self, PaymentIdTypeExt, PaymentsResponse, PaymentsRetrieveRequest}, - storage::{self, enums, ProcessTrackerExt}, + api::{self, enums as api_enums}, + storage::{self, enums as storage_enums}, transformers::ForeignInto, }, utils::{self, OptionExt}, @@ -45,6 +44,7 @@ pub async fn payments_operation_core( merchant_account: storage::MerchantAccount, operation: Op, req: Req, + use_connector: Option, call_connector_action: CallConnectorAction, ) -> RouterResult<(PaymentData, Req, Option)> where @@ -106,6 +106,7 @@ where validate_result.storage_scheme, ) .await?; + payment_data.payment_method_data = payment_method_data; if let Some(token) = payment_token { payment_data.token = Some(token) @@ -113,7 +114,7 @@ where let connector_details = operation .to_domain()? - .get_connector(&merchant_account, state) + .get_connector(&merchant_account, state, use_connector) .await?; if let api::ConnectorCallType::Single(ref connector) = connector_details { @@ -175,6 +176,7 @@ pub async fn payments_core( operation: Op, req: Req, auth_flow: services::AuthFlow, + use_connector: Option, call_connector_action: CallConnectorAction, ) -> RouterResponse where @@ -199,9 +201,11 @@ where merchant_account, operation.clone(), req, + use_connector, call_connector_action, ) .await?; + Res::generate_response( Some(req), payment_data, @@ -220,7 +224,7 @@ fn is_start_pay(operation: &Op) -> bool { pub async fn handle_payments_redirect_response<'a, F>( state: &AppState, merchant_account: storage::MerchantAccount, - req: PaymentsRetrieveRequest, + req: api::PaymentsRetrieveRequest, ) -> RouterResponse where F: Send + Clone + 'a, @@ -229,11 +233,10 @@ where let query_params = req.param.clone().get_required_value("param")?; - let resource_id = req.resource_id.get_payment_intent_id().change_context( - errors::ApiErrorResponse::MissingRequiredField { + let resource_id = api::PaymentIdTypeExt::get_payment_intent_id(&req.resource_id) + .change_context(errors::ApiErrorResponse::MissingRequiredField { field_name: "payment_id".to_string(), - }, - )?; + })?; let connector_data = api::ConnectorData::get_connector_by_name( &state.conf.connectors, @@ -277,15 +280,16 @@ where pub async fn payments_response_for_redirection_flows<'a>( state: &AppState, merchant_account: storage::MerchantAccount, - req: PaymentsRetrieveRequest, + req: api::PaymentsRetrieveRequest, flow_type: CallConnectorAction, -) -> RouterResponse { +) -> RouterResponse { payments_core::( state, merchant_account, payments::PaymentStatus, req, services::api::AuthFlow::Merchant, + None, flow_type, ) .await @@ -433,7 +437,7 @@ where pub enum CallConnectorAction { Trigger, Avoid, - StatusUpdate(enums::AttemptStatus), + StatusUpdate(storage_enums::AttemptStatus), HandleResponse(Vec), } @@ -453,7 +457,7 @@ where pub payment_attempt: storage::PaymentAttempt, pub connector_response: storage::ConnectorResponse, pub amount: api::Amount, - pub currency: enums::Currency, + pub currency: storage_enums::Currency, pub mandate_id: Option, pub setup_mandate: Option, pub address: PaymentAddress, @@ -463,21 +467,21 @@ where pub payment_method_data: Option, pub refunds: Vec, pub sessions_token: Vec, - pub card_cvc: Option>, + pub card_cvc: Option>, } #[derive(Debug)] pub struct CustomerDetails { pub customer_id: Option, pub name: Option>, - pub email: Option>, + pub email: Option>, pub phone: Option>, pub phone_country_code: Option, } pub fn if_not_create_change_operation<'a, Op, F>( is_update: bool, - status: enums::IntentStatus, + status: storage_enums::IntentStatus, current: &'a Op, ) -> BoxedOperation where @@ -486,9 +490,9 @@ where &'a Op: Operation, { match status { - enums::IntentStatus::RequiresConfirmation - | enums::IntentStatus::RequiresCustomerAction - | enums::IntentStatus::RequiresPaymentMethod => { + storage_enums::IntentStatus::RequiresConfirmation + | storage_enums::IntentStatus::RequiresCustomerAction + | storage_enums::IntentStatus::RequiresPaymentMethod => { if is_update { Box::new(&PaymentUpdate) } else { @@ -525,7 +529,7 @@ pub fn should_call_connector( "PaymentStart" => { !matches!( payment_data.payment_intent.status, - enums::IntentStatus::Failed | enums::IntentStatus::Succeeded + storage_enums::IntentStatus::Failed | storage_enums::IntentStatus::Succeeded ) && payment_data .connector_response .authentication_data @@ -534,20 +538,20 @@ pub fn should_call_connector( "PaymentStatus" => { matches!( payment_data.payment_intent.status, - enums::IntentStatus::Failed - | enums::IntentStatus::Processing - | enums::IntentStatus::Succeeded - | enums::IntentStatus::RequiresCustomerAction + storage_enums::IntentStatus::Failed + | storage_enums::IntentStatus::Processing + | storage_enums::IntentStatus::Succeeded + | storage_enums::IntentStatus::RequiresCustomerAction ) && payment_data.force_sync.unwrap_or(false) } "PaymentCancel" => matches!( payment_data.payment_intent.status, - enums::IntentStatus::RequiresCapture + storage_enums::IntentStatus::RequiresCapture ), "PaymentCapture" => { matches!( payment_data.payment_intent.status, - enums::IntentStatus::RequiresCapture + storage_enums::IntentStatus::RequiresCapture ) } "PaymentSession" => true, @@ -602,13 +606,14 @@ pub async fn add_process_sync_task( &payment_attempt.txn_id, &payment_attempt.merchant_id, ); - let process_tracker_entry = storage::ProcessTracker::make_process_tracker_new( - process_tracker_id, - task, - runner, - tracking_data, - schedule_time, - )?; + let process_tracker_entry = + ::make_process_tracker_new( + process_tracker_id, + task, + runner, + tracking_data, + schedule_time, + )?; db.insert_process(process_tracker_entry).await?; Ok(()) diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index c363dbd8a2..8ce4becbca 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -620,43 +620,52 @@ pub async fn get_customer_from_details( pub async fn get_connector_default( merchant_account: &storage::MerchantAccount, state: &AppState, + request_connector: Option, ) -> CustomResult { let connectors = &state.conf.connectors; - let vec_val: Vec = merchant_account - .custom_routing_rules - .clone() - .parse_value("CustomRoutingRulesVec") - .change_context(errors::ConnectorError::RoutingRulesParsingError) - .change_context(errors::ApiErrorResponse::InternalServerError)?; - let custom_routing_rules: api::CustomRoutingRules = vec_val[0] - .clone() - .parse_value("CustomRoutingRules") - .change_context(errors::ConnectorError::RoutingRulesParsingError) - .change_context(errors::ApiErrorResponse::InternalServerError)?; - let connector_names = custom_routing_rules - .connectors_pecking_order - .unwrap_or_else(|| vec!["stripe".to_string()]); + if let Some(connector) = request_connector { + let connector_data = api::ConnectorData::get_connector_by_name( + connectors, + &connector.to_string(), + api::GetToken::Connector, + )?; + Ok(api::ConnectorCallType::Single(connector_data)) + } else { + let vec_val: Vec = merchant_account + .custom_routing_rules + .clone() + .parse_value("CustomRoutingRulesVec") + .change_context(errors::ConnectorError::RoutingRulesParsingError) + .change_context(errors::ApiErrorResponse::InternalServerError)?; + let custom_routing_rules: api::CustomRoutingRules = vec_val[0] + .clone() + .parse_value("CustomRoutingRules") + .change_context(errors::ConnectorError::RoutingRulesParsingError) + .change_context(errors::ApiErrorResponse::InternalServerError)?; + let connector_names = custom_routing_rules + .connectors_pecking_order + .unwrap_or_else(|| vec!["stripe".to_string()]); - //use routing rules if configured by merchant else query MCA as per PM - let connector_list: types::ConnectorsList = types::ConnectorsList { - connectors: connector_names, - }; + //use routing rules if configured by merchant else query MCA as per PM + let connector_list: types::ConnectorsList = types::ConnectorsList { + connectors: connector_names, + }; - let connector_name = connector_list - .connectors - .first() - .get_required_value("connectors") - .change_context(errors::ConnectorError::FailedToObtainPreferredConnector) - .change_context(errors::ApiErrorResponse::InternalServerError)? - .as_str(); + let connector_name = connector_list + .connectors + .first() + .get_required_value("connectors") + .change_context(errors::ConnectorError::FailedToObtainPreferredConnector) + .change_context(errors::ApiErrorResponse::InternalServerError)? + .as_str(); - let connector_data = api::ConnectorData::get_connector_by_name( - connectors, - connector_name, - api::GetToken::Connector, - )?; - - Ok(api::ConnectorCallType::Single(connector_data)) + let connector_data = api::ConnectorData::get_connector_by_name( + connectors, + connector_name, + api::GetToken::Connector, + )?; + Ok(api::ConnectorCallType::Single(connector_data)) + } } #[instrument(skip_all)] diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index 602191a6a7..cf7a20a41b 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -30,7 +30,8 @@ use crate::{ pii::Secret, routes::AppState, types::{ - self, api, + self, + api::{self, enums as api_enums}, storage::{self, enums}, PaymentsResponseData, }, @@ -138,6 +139,7 @@ pub trait Domain: Send + Sync { &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, + request_connector: Option, ) -> CustomResult; } @@ -204,8 +206,9 @@ where &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, + request_connector: Option, ) -> CustomResult { - helpers::get_connector_default(merchant_account, state).await + helpers::get_connector_default(merchant_account, state, request_connector).await } #[instrument(skip_all)] @@ -291,8 +294,9 @@ where &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, + request_connector: Option, ) -> CustomResult { - helpers::get_connector_default(merchant_account, state).await + helpers::get_connector_default(merchant_account, state, request_connector).await } } @@ -350,7 +354,8 @@ where &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, + request_connector: Option, ) -> CustomResult { - helpers::get_connector_default(merchant_account, state).await + helpers::get_connector_default(merchant_account, state, request_connector).await } } diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index cc4ca66605..55550948c0 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -17,7 +17,7 @@ use crate::{ routes::AppState, types::{ self, - api::{self, PaymentIdTypeExt}, + api::{self, enums as api_enums, PaymentIdTypeExt}, storage::{self, enums}, transformers::ForeignInto, }, @@ -243,8 +243,9 @@ impl Domain for PaymentConfirm { &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, + request_connector: Option, ) -> CustomResult { - helpers::get_connector_default(merchant_account, state).await + helpers::get_connector_default(merchant_account, state, request_connector).await } } diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index c8cd30ea22..91eae8f7cd 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -19,7 +19,7 @@ use crate::{ routes::AppState, types::{ self, - api::{self, PaymentIdTypeExt}, + api::{self, enums as api_enums, PaymentIdTypeExt}, storage::{ self, enums::{self, IntentStatus}, @@ -290,8 +290,9 @@ impl Domain for PaymentCreate { &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, + request_connector: Option, ) -> CustomResult { - helpers::get_connector_default(merchant_account, state).await + helpers::get_connector_default(merchant_account, state, request_connector).await } } diff --git a/crates/router/src/core/payments/operations/payment_method_validate.rs b/crates/router/src/core/payments/operations/payment_method_validate.rs index cf3974c7d1..56291719c1 100644 --- a/crates/router/src/core/payments/operations/payment_method_validate.rs +++ b/crates/router/src/core/payments/operations/payment_method_validate.rs @@ -265,8 +265,9 @@ where &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, + request_connector: Option, ) -> CustomResult { - helpers::get_connector_default(merchant_account, state).await + helpers::get_connector_default(merchant_account, state, request_connector).await } } diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index b94929e47e..1f68feeb16 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -16,7 +16,7 @@ use crate::{ pii::Secret, routes::AppState, types::{ - api::{self, PaymentIdTypeExt}, + api::{self, enums as api_enums, PaymentIdTypeExt}, storage::{self, enums}, transformers::ForeignInto, }, @@ -257,6 +257,7 @@ where &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, + _request_connector: Option, ) -> RouterResult { let connectors = &state.conf.connectors; let db = &state.store; diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index 701b0ef27a..4afc084372 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -15,7 +15,7 @@ use crate::{ pii::Secret, routes::AppState, types::{ - api::{self, PaymentIdTypeExt}, + api::{self, enums as api_enums, PaymentIdTypeExt}, storage::{self, enums, Customer}, transformers::ForeignInto, }, @@ -265,7 +265,8 @@ where &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, + request_connector: Option, ) -> CustomResult { - helpers::get_connector_default(merchant_account, state).await + helpers::get_connector_default(merchant_account, state, request_connector).await } } diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index c3845182f3..68b5c03db1 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -15,7 +15,7 @@ use crate::{ db::StorageInterface, routes::AppState, types::{ - api, + api::{self, enums as api_enums}, storage::{self, enums}, transformers::ForeignInto, }, @@ -117,8 +117,9 @@ impl Domain for PaymentStatus { &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, + request_connector: Option, ) -> CustomResult { - helpers::get_connector_default(merchant_account, state).await + helpers::get_connector_default(merchant_account, state, request_connector).await } } diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 2bbea28782..4340dee17c 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -16,7 +16,7 @@ use crate::{ db::StorageInterface, routes::AppState, types::{ - api::{self, PaymentIdTypeExt}, + api::{self, enums as api_enums, PaymentIdTypeExt}, storage::{self, enums}, transformers::ForeignInto, }, @@ -237,8 +237,9 @@ impl Domain for PaymentUpdate { &'a self, merchant_account: &storage::MerchantAccount, state: &AppState, + request_connector: Option, ) -> CustomResult { - helpers::get_connector_default(merchant_account, state).await + helpers::get_connector_default(merchant_account, state, request_connector).await } } diff --git a/crates/router/src/core/webhooks.rs b/crates/router/src/core/webhooks.rs index 386e62dc62..3f8ebd8c38 100644 --- a/crates/router/src/core/webhooks.rs +++ b/crates/router/src/core/webhooks.rs @@ -52,6 +52,7 @@ async fn payments_incoming_webhook_flow( param: None, }, services::AuthFlow::Merchant, + None, consume_or_trigger_flow, ) .await diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index adbde39af0..dc91999128 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -46,6 +46,7 @@ pub async fn payments_create( |state, merchant_account, req| { // TODO: Change for making it possible for the flow to be inferred internally or through validation layer async { + let connector = req.connector; match req.amount.as_ref() { Some(api_types::Amount::Value(_)) | None => { payments::payments_core::( @@ -54,10 +55,12 @@ pub async fn payments_create( payments::PaymentCreate, req, api::AuthFlow::Merchant, + connector, payments::CallConnectorAction::Trigger, ) .await } + Some(api_types::Amount::Zero) => { payments::payments_core::( state, @@ -65,6 +68,7 @@ pub async fn payments_create( payments::PaymentCreate, req, api::AuthFlow::Merchant, + connector, payments::CallConnectorAction::Trigger, ) .await @@ -100,6 +104,7 @@ pub async fn payments_start( payments::operations::PaymentStart, req, api::AuthFlow::Client, + None, payments::CallConnectorAction::Trigger, ) }, @@ -140,6 +145,7 @@ pub async fn payments_retrieve( payments::PaymentStatus, req, api::AuthFlow::Merchant, + None, payments::CallConnectorAction::Trigger, ) }, @@ -179,12 +185,14 @@ pub async fn payments_update( &req, payload, |state, merchant_account, req| { + let connector = req.connector; payments::payments_core::( state, merchant_account, payments::PaymentUpdate, req, auth_flow, + connector, payments::CallConnectorAction::Trigger, ) }, @@ -223,12 +231,14 @@ pub async fn payments_confirm( &req, payload, |state, merchant_account, req| { + let connector = req.connector; payments::payments_core::( state, merchant_account, payments::PaymentConfirm, req, auth_flow, + connector, payments::CallConnectorAction::Trigger, ) }, @@ -261,6 +271,7 @@ pub(crate) async fn payments_capture( payments::PaymentCapture, payload, api::AuthFlow::Merchant, + None, payments::CallConnectorAction::Trigger, ) }, @@ -288,6 +299,7 @@ pub(crate) async fn payments_connector_session( payments::PaymentSession, payload, api::AuthFlow::Merchant, + None, payments::CallConnectorAction::Trigger, ) }, @@ -347,6 +359,7 @@ pub async fn payments_cancel( payments::PaymentCancel, req, api::AuthFlow::Merchant, + None, payments::CallConnectorAction::Trigger, ) }, diff --git a/crates/router/src/scheduler/workflows/payment_sync.rs b/crates/router/src/scheduler/workflows/payment_sync.rs index df8597797e..48824d6d36 100644 --- a/crates/router/src/scheduler/workflows/payment_sync.rs +++ b/crates/router/src/scheduler/workflows/payment_sync.rs @@ -41,6 +41,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow { merchant_account.clone(), operations::PaymentStatus, tracking_data.clone(), + None, payment_flows::CallConnectorAction::Trigger, ) .await?; diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 391c4333e5..f991c4415c 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -13,9 +13,9 @@ pub mod transformers; use std::marker::PhantomData; +pub use api_models::enums::Connector; use error_stack::{IntoReport, ResultExt}; -pub use self::connector::Connector; use self::{api::payments, storage::enums as storage_enums}; pub use crate::core::payments::PaymentAddress; use crate::{core::errors, services}; diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index d97c252f36..5aeddbac5a 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -17,7 +17,7 @@ use crate::{ connector, core::errors::{self, CustomResult}, services::ConnectorRedirectResponse, - types, + types::{self, api::enums as api_enums}, }; pub trait ConnectorCommon { @@ -82,6 +82,12 @@ pub enum ConnectorCallType { Multiple(Vec), } +impl ConnectorCallType { + pub fn is_single(&self) -> bool { + matches!(self, Self::Single(_)) + } +} + impl ConnectorData { pub fn get_connector_by_name( connectors: &Connectors, @@ -89,7 +95,7 @@ impl ConnectorData { connector_type: GetToken, ) -> CustomResult { let connector = Self::convert_connector(connectors, name)?; - let connector_name = types::Connector::from_str(name) + let connector_name = api_enums::Connector::from_str(name) .into_report() .change_context(errors::ConnectorError::InvalidConnectorName) .attach_printable_lazy(|| format!("unable to parse connector name {connector:?}")) diff --git a/crates/router/src/types/connector.rs b/crates/router/src/types/connector.rs index d8ff63d5d1..8b13789179 100644 --- a/crates/router/src/types/connector.rs +++ b/crates/router/src/types/connector.rs @@ -1,14 +1 @@ -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, strum::Display, strum::EnumString)] -#[strum(serialize_all = "snake_case")] -pub enum Connector { - Adyen, - Stripe, - Checkout, - Aci, - Authorizedotnet, - Braintree, - Klarna, - Applepay, - #[default] - Dummy, -} + diff --git a/crates/router/tests/payments.rs b/crates/router/tests/payments.rs index 22a784165b..0ccfd74d18 100644 --- a/crates/router/tests/payments.rs +++ b/crates/router/tests/payments.rs @@ -289,6 +289,7 @@ async fn payments_create_core() { )), merchant_id: Some("jarnura".to_string()), amount: Some(6540.into()), + connector: None, currency: Some("USD".to_string()), capture_method: Some(api_enums::CaptureMethod::Automatic), amount_to_capture: Some(6540), @@ -354,6 +355,7 @@ async fn payments_create_core() { payments::PaymentCreate, req, services::AuthFlow::Merchant, + None, payments::CallConnectorAction::Trigger, ) .await @@ -446,6 +448,7 @@ async fn payments_create_core_adyen_no_redirect() { payment_id: Some(api::PaymentIdType::PaymentIntentId(payment_id.clone())), merchant_id: Some(merchant_id.clone()), amount: Some(6540.into()), + connector: None, currency: Some("USD".to_string()), capture_method: Some(api_enums::CaptureMethod::Automatic), amount_to_capture: Some(6540), @@ -510,6 +513,7 @@ async fn payments_create_core_adyen_no_redirect() { payments::PaymentCreate, req, services::AuthFlow::Merchant, + None, payments::CallConnectorAction::Trigger, ) .await diff --git a/crates/router/tests/payments2.rs b/crates/router/tests/payments2.rs index 02b914d3c2..7a3041efcf 100644 --- a/crates/router/tests/payments2.rs +++ b/crates/router/tests/payments2.rs @@ -106,6 +106,7 @@ async fn payments_create_core() { payments::PaymentCreate, req, services::AuthFlow::Merchant, + None, payments::CallConnectorAction::Trigger, ) .await @@ -201,6 +202,7 @@ async fn payments_create_core_adyen_no_redirect() { payment_id: Some(api::PaymentIdType::PaymentIntentId(payment_id.clone())), merchant_id: Some(merchant_id.clone()), amount: Some(6540.into()), + connector: None, currency: Some("USD".to_string()), capture_method: Some(api_enums::CaptureMethod::Automatic), amount_to_capture: Some(6540), @@ -265,6 +267,7 @@ async fn payments_create_core_adyen_no_redirect() { payments::PaymentCreate, req, services::AuthFlow::Merchant, + None, payments::CallConnectorAction::Trigger, ) .await