mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +08:00
feat(router): add straight-through routing connector selection in payments (#153)
This commit is contained in:
@ -349,6 +349,7 @@ impl From<ApiErrorResponse> 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,
|
||||
|
||||
@ -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::<Authorize, api_types::PaymentsResponse, _, _, _>(
|
||||
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::<Authorize, api_types::PaymentsResponse, _, _, _>(
|
||||
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::<Authorize, api_types::PaymentsResponse, _, _, _>(
|
||||
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,
|
||||
)
|
||||
},
|
||||
|
||||
@ -114,6 +114,7 @@ impl From<Shipping> for Address {
|
||||
#[derive(Default, PartialEq, Eq, Deserialize, Clone)]
|
||||
pub(crate) struct StripePaymentIntentRequest {
|
||||
pub(crate) amount: Option<i64>, //amount in cents, hence passed as integer
|
||||
pub(crate) connector: Option<api_enums::Connector>,
|
||||
pub(crate) currency: Option<String>,
|
||||
#[serde(rename = "amount_to_capture")]
|
||||
pub(crate) amount_capturable: Option<i64>,
|
||||
@ -137,6 +138,7 @@ impl From<StripePaymentIntentRequest> 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,
|
||||
|
||||
@ -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::<Verify, api_types::PaymentsResponse, _, _, _>(
|
||||
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::<Verify, api_types::PaymentsResponse, _, _, _>(
|
||||
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::<Verify, api_types::PaymentsResponse, _, _, _>(
|
||||
state,
|
||||
merchant_account,
|
||||
payments::PaymentConfirm,
|
||||
req,
|
||||
auth_flow,
|
||||
connector,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<F, Req, Op, FData>(
|
||||
merchant_account: storage::MerchantAccount,
|
||||
operation: Op,
|
||||
req: Req,
|
||||
use_connector: Option<api_enums::Connector>,
|
||||
call_connector_action: CallConnectorAction,
|
||||
) -> RouterResult<(PaymentData<F>, Req, Option<storage::Customer>)>
|
||||
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<F, Res, Req, Op, FData>(
|
||||
operation: Op,
|
||||
req: Req,
|
||||
auth_flow: services::AuthFlow,
|
||||
use_connector: Option<api_enums::Connector>,
|
||||
call_connector_action: CallConnectorAction,
|
||||
) -> RouterResponse<Res>
|
||||
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<Op: Debug>(operation: &Op) -> bool {
|
||||
pub async fn handle_payments_redirect_response<'a, F>(
|
||||
state: &AppState,
|
||||
merchant_account: storage::MerchantAccount,
|
||||
req: PaymentsRetrieveRequest,
|
||||
req: api::PaymentsRetrieveRequest,
|
||||
) -> RouterResponse<api::RedirectionResponse>
|
||||
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<PaymentsResponse> {
|
||||
) -> RouterResponse<api::PaymentsResponse> {
|
||||
payments_core::<api::PSync, api::PaymentsResponse, _, _, _>(
|
||||
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<u8>),
|
||||
}
|
||||
|
||||
@ -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<String>,
|
||||
pub setup_mandate: Option<api::MandateData>,
|
||||
pub address: PaymentAddress,
|
||||
@ -463,21 +467,21 @@ where
|
||||
pub payment_method_data: Option<api::PaymentMethod>,
|
||||
pub refunds: Vec<storage::Refund>,
|
||||
pub sessions_token: Vec<api::SessionToken>,
|
||||
pub card_cvc: Option<Secret<String>>,
|
||||
pub card_cvc: Option<pii::Secret<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CustomerDetails {
|
||||
pub customer_id: Option<String>,
|
||||
pub name: Option<masking::Secret<String, masking::WithType>>,
|
||||
pub email: Option<masking::Secret<String, Email>>,
|
||||
pub email: Option<masking::Secret<String, pii::Email>>,
|
||||
pub phone: Option<masking::Secret<String, masking::WithType>>,
|
||||
pub phone_country_code: Option<String>,
|
||||
}
|
||||
|
||||
pub fn if_not_create_change_operation<'a, Op, F>(
|
||||
is_update: bool,
|
||||
status: enums::IntentStatus,
|
||||
status: storage_enums::IntentStatus,
|
||||
current: &'a Op,
|
||||
) -> BoxedOperation<F, api::PaymentsRequest>
|
||||
where
|
||||
@ -486,9 +490,9 @@ where
|
||||
&'a Op: Operation<F, api::PaymentsRequest>,
|
||||
{
|
||||
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<Op: Debug, F: Clone>(
|
||||
"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<Op: Debug, F: Clone>(
|
||||
"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 =
|
||||
<storage::ProcessTracker as storage::ProcessTrackerExt>::make_process_tracker_new(
|
||||
process_tracker_id,
|
||||
task,
|
||||
runner,
|
||||
tracking_data,
|
||||
schedule_time,
|
||||
)?;
|
||||
|
||||
db.insert_process(process_tracker_entry).await?;
|
||||
Ok(())
|
||||
|
||||
@ -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<api_enums::Connector>,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
let connectors = &state.conf.connectors;
|
||||
let vec_val: Vec<serde_json::Value> = 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<serde_json::Value> = 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)]
|
||||
|
||||
@ -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<F: Clone, R>: Send + Sync {
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse>;
|
||||
}
|
||||
|
||||
@ -204,8 +206,9 @@ where
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
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<api_enums::Connector>,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
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<api_enums::Connector>,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentConfirm {
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentCreate {
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -265,8 +265,9 @@ where
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<api_enums::Connector>,
|
||||
) -> RouterResult<api::ConnectorCallType> {
|
||||
let connectors = &state.conf.connectors;
|
||||
let db = &state.store;
|
||||
|
||||
@ -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<api_enums::Connector>,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentStatus {
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentUpdate {
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -52,6 +52,7 @@ async fn payments_incoming_webhook_flow(
|
||||
param: None,
|
||||
},
|
||||
services::AuthFlow::Merchant,
|
||||
None,
|
||||
consume_or_trigger_flow,
|
||||
)
|
||||
.await
|
||||
|
||||
@ -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::<Authorize, PaymentsResponse, _, _, _>(
|
||||
@ -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::<Verify, PaymentsResponse, _, _, _>(
|
||||
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::<Authorize, PaymentsResponse, _, _, _>(
|
||||
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::<Authorize, PaymentsResponse, _, _, _>(
|
||||
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,
|
||||
)
|
||||
},
|
||||
|
||||
@ -41,6 +41,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow {
|
||||
merchant_account.clone(),
|
||||
operations::PaymentStatus,
|
||||
tracking_data.clone(),
|
||||
None,
|
||||
payment_flows::CallConnectorAction::Trigger,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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<ConnectorData>),
|
||||
}
|
||||
|
||||
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<ConnectorData, errors::ApiErrorResponse> {
|
||||
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:?}"))
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user