feat(router): add straight-through routing connector selection in payments (#153)

This commit is contained in:
ItsMeShashank
2022-12-19 18:43:04 +05:30
committed by GitHub
parent a5f0c98eb7
commit d6a3e508e2
26 changed files with 192 additions and 100 deletions

View File

@ -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.

View File

@ -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<AttemptStatus> for IntentStatus {
fn from(s: AttemptStatus) -> Self {
match s {

View File

@ -22,6 +22,7 @@ pub struct PaymentsRequest {
pub merchant_id: Option<String>,
#[serde(default, deserialize_with = "amount::deserialize_option")]
pub amount: Option<Amount>,
pub connector: Option<api_enums::Connector>,
pub currency: Option<String>,
pub capture_method: Option<api_enums::CaptureMethod>,
pub amount_to_capture: Option<i64>,

View File

@ -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,

View File

@ -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,
)
},

View File

@ -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,

View File

@ -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,
)
},

View File

@ -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

View File

@ -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(())

View File

@ -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)]

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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;

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -52,6 +52,7 @@ async fn payments_incoming_webhook_flow(
param: None,
},
services::AuthFlow::Merchant,
None,
consume_or_trigger_flow,
)
.await

View File

@ -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,
)
},

View File

@ -41,6 +41,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow {
merchant_account.clone(),
operations::PaymentStatus,
tracking_data.clone(),
None,
payment_flows::CallConnectorAction::Trigger,
)
.await?;

View File

@ -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};

View File

@ -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:?}"))

View File

@ -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,
}

View File

@ -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

View File

@ -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