mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +08:00
feat(session): ability to request session token for specific wallets (#280)
Co-authored-by: Arun Raj M <jarnura47@gmail.com>
This commit is contained in:
@ -509,6 +509,15 @@ pub enum Connector {
|
||||
Worldpay,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum SupportedWallets {
|
||||
Paypal,
|
||||
ApplePay,
|
||||
Klarna,
|
||||
Gpay,
|
||||
}
|
||||
|
||||
impl From<AttemptStatus> for IntentStatus {
|
||||
fn from(s: AttemptStatus) -> Self {
|
||||
match s {
|
||||
|
||||
@ -751,15 +751,6 @@ pub struct PaymentsRetrieveRequest {
|
||||
pub connector: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum SupportedWallets {
|
||||
Paypal,
|
||||
ApplePay,
|
||||
Klarna,
|
||||
Gpay,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct OrderDetails {
|
||||
pub product_name: String,
|
||||
@ -777,6 +768,7 @@ pub struct Metadata {
|
||||
pub struct PaymentsSessionRequest {
|
||||
pub payment_id: String,
|
||||
pub client_secret: String,
|
||||
pub wallets: Vec<api_enums::SupportedWallets>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
|
||||
@ -47,14 +47,12 @@ pub async fn payment_intents_create(
|
||||
&req,
|
||||
create_payment_req,
|
||||
|state, merchant_account, req| {
|
||||
let connector = req.connector;
|
||||
payments::payments_core::<api_types::Authorize, api_types::PaymentsResponse, _, _, _>(
|
||||
state,
|
||||
merchant_account,
|
||||
payments::PaymentCreate,
|
||||
req,
|
||||
api::AuthFlow::Merchant,
|
||||
connector,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -102,7 +100,6 @@ pub async fn payment_intents_retrieve(
|
||||
payments::PaymentStatus,
|
||||
payload,
|
||||
auth_flow,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -155,14 +152,12 @@ pub async fn payment_intents_update(
|
||||
&req,
|
||||
payload,
|
||||
|state, merchant_account, req| {
|
||||
let connector = req.connector;
|
||||
payments::payments_core::<api_types::Authorize, api_types::PaymentsResponse, _, _, _>(
|
||||
state,
|
||||
merchant_account,
|
||||
payments::PaymentUpdate,
|
||||
req,
|
||||
auth_flow,
|
||||
connector,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -217,14 +212,12 @@ pub async fn payment_intents_confirm(
|
||||
&req,
|
||||
payload,
|
||||
|state, merchant_account, req| {
|
||||
let connector = req.connector;
|
||||
payments::payments_core::<api_types::Authorize, api_types::PaymentsResponse, _, _, _>(
|
||||
state,
|
||||
merchant_account,
|
||||
payments::PaymentConfirm,
|
||||
req,
|
||||
auth_flow,
|
||||
connector,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -274,7 +267,6 @@ pub async fn payment_intents_capture(
|
||||
payments::PaymentCapture,
|
||||
payload,
|
||||
api::AuthFlow::Merchant,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -329,7 +321,6 @@ pub async fn payment_intents_cancel(
|
||||
payments::PaymentCancel,
|
||||
req,
|
||||
auth_flow,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
|
||||
@ -44,14 +44,12 @@ pub async fn setup_intents_create(
|
||||
&req,
|
||||
create_payment_req,
|
||||
|state, merchant_account, req| {
|
||||
let connector = req.connector;
|
||||
payments::payments_core::<api_types::Verify, api_types::PaymentsResponse, _, _, _>(
|
||||
state,
|
||||
merchant_account,
|
||||
payments::PaymentCreate,
|
||||
req,
|
||||
api::AuthFlow::Merchant,
|
||||
connector,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -99,7 +97,6 @@ pub async fn setup_intents_retrieve(
|
||||
payments::PaymentStatus,
|
||||
payload,
|
||||
auth_flow,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -149,14 +146,12 @@ pub async fn setup_intents_update(
|
||||
&req,
|
||||
payload,
|
||||
|state, merchant_account, req| {
|
||||
let connector = req.connector;
|
||||
payments::payments_core::<api_types::Verify, api_types::PaymentsResponse, _, _, _>(
|
||||
state,
|
||||
merchant_account,
|
||||
payments::PaymentUpdate,
|
||||
req,
|
||||
auth_flow,
|
||||
connector,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -207,14 +202,12 @@ pub async fn setup_intents_confirm(
|
||||
&req,
|
||||
payload,
|
||||
|state, merchant_account, req| {
|
||||
let connector = req.connector;
|
||||
payments::payments_core::<api_types::Verify, api_types::PaymentsResponse, _, _, _>(
|
||||
state,
|
||||
merchant_account,
|
||||
payments::PaymentConfirm,
|
||||
req,
|
||||
auth_flow,
|
||||
connector,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
|
||||
@ -28,8 +28,7 @@ use crate::{
|
||||
scheduler::utils as pt_utils,
|
||||
services,
|
||||
types::{
|
||||
self,
|
||||
api::{self, enums as api_enums},
|
||||
self, api,
|
||||
storage::{self, enums as storage_enums},
|
||||
transformers::ForeignInto,
|
||||
},
|
||||
@ -42,7 +41,6 @@ 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
|
||||
@ -100,7 +98,7 @@ where
|
||||
|
||||
let connector_details = operation
|
||||
.to_domain()?
|
||||
.get_connector(&merchant_account, state, use_connector)
|
||||
.get_connector(&merchant_account, state, &req)
|
||||
.await?;
|
||||
|
||||
if let api::ConnectorCallType::Single(ref connector) = connector_details {
|
||||
@ -163,7 +161,6 @@ 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
|
||||
@ -188,7 +185,6 @@ where
|
||||
merchant_account,
|
||||
operation.clone(),
|
||||
req,
|
||||
use_connector,
|
||||
call_connector_action,
|
||||
)
|
||||
.await?;
|
||||
@ -276,7 +272,6 @@ pub async fn payments_response_for_redirection_flows<'a>(
|
||||
PaymentStatus,
|
||||
req,
|
||||
services::api::AuthFlow::Merchant,
|
||||
None,
|
||||
flow_type,
|
||||
)
|
||||
.await
|
||||
|
||||
@ -26,8 +26,7 @@ use crate::{
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
types::{
|
||||
self,
|
||||
api::{self, enums as api_enums},
|
||||
self, api,
|
||||
storage::{self, enums},
|
||||
PaymentsResponseData,
|
||||
},
|
||||
@ -125,7 +124,7 @@ pub trait Domain<F: Clone, R>: Send + Sync {
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
request: &R,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse>;
|
||||
}
|
||||
|
||||
@ -192,9 +191,9 @@ where
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
_request: &api::PaymentsRetrieveRequest,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
helpers::get_connector_default(merchant_account, state, None).await
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
@ -258,9 +257,9 @@ where
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
_request: &api::PaymentsCaptureRequest,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
helpers::get_connector_default(merchant_account, state, None).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,8 +311,8 @@ where
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
_request: &api::PaymentsCancelRequest,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
helpers::get_connector_default(merchant_account, state, None).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ use crate::{
|
||||
routes::AppState,
|
||||
types::{
|
||||
self,
|
||||
api::{self, enums as api_enums, PaymentIdTypeExt},
|
||||
api::{self, PaymentIdTypeExt},
|
||||
storage::{self, enums},
|
||||
transformers::ForeignInto,
|
||||
},
|
||||
@ -254,9 +254,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>,
|
||||
request: &api::PaymentsRequest,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
helpers::get_connector_default(merchant_account, state, request.connector).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ use crate::{
|
||||
routes::AppState,
|
||||
types::{
|
||||
self,
|
||||
api::{self, enums as api_enums, PaymentIdTypeExt},
|
||||
api::{self, PaymentIdTypeExt},
|
||||
storage::{
|
||||
self,
|
||||
enums::{self, IntentStatus},
|
||||
@ -256,9 +256,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>,
|
||||
request: &api::PaymentsRequest,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
helpers::get_connector_default(merchant_account, state, request.connector).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -252,9 +252,9 @@ where
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
_request: &api::VerifyRequest,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
helpers::get_connector_default(merchant_account, state, None).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::{collections::HashSet, marker::PhantomData};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use common_utils::ext_traits::ValueExt;
|
||||
@ -268,7 +268,7 @@ where
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
_request_connector: Option<api_enums::Connector>,
|
||||
request: &api::PaymentsSessionRequest,
|
||||
) -> RouterResult<api::ConnectorCallType> {
|
||||
let connectors = &state.conf.connectors;
|
||||
let db = &state.store;
|
||||
@ -287,10 +287,10 @@ where
|
||||
supported_connectors.contains(&connector_account.connector_name)
|
||||
})
|
||||
.map(|filtered_connector| filtered_connector.connector_name.clone())
|
||||
.collect::<Vec<String>>();
|
||||
.collect::<HashSet<String>>();
|
||||
|
||||
// Parse the payment methods enabled to check if the merchant has enabled gpay ( wallet )
|
||||
// through that connector this parsing from Value to payment method is costly and has to be done for every connector
|
||||
// through that connector. This parsing from serde_json::Value to payment method is costly and has to be done for every connector
|
||||
// for sure looks like an area of optimization
|
||||
let session_token_from_metadata_connectors = connector_accounts
|
||||
.iter()
|
||||
@ -310,8 +310,35 @@ where
|
||||
})
|
||||
})
|
||||
.map(|filtered_connector| filtered_connector.connector_name.clone())
|
||||
.collect::<Vec<String>>();
|
||||
.collect::<HashSet<String>>();
|
||||
|
||||
let given_wallets = request.wallets.clone();
|
||||
|
||||
let connectors_data = if !given_wallets.is_empty() {
|
||||
// Create connectors for provided wallets
|
||||
let mut connectors_data = Vec::with_capacity(supported_connectors.len());
|
||||
for wallet in given_wallets {
|
||||
let (connector_name, connector_type) = match wallet {
|
||||
api_enums::SupportedWallets::Gpay => ("adyen", api::GetToken::Metadata),
|
||||
api_enums::SupportedWallets::ApplePay => ("applepay", api::GetToken::Connector),
|
||||
api_enums::SupportedWallets::Paypal => ("braintree", api::GetToken::Connector),
|
||||
api_enums::SupportedWallets::Klarna => ("klarna", api::GetToken::Connector),
|
||||
};
|
||||
|
||||
// Check if merchant has enabled the required merchant connector account
|
||||
if session_token_from_metadata_connectors.contains(connector_name)
|
||||
|| normal_connector_names.contains(connector_name)
|
||||
{
|
||||
connectors_data.push(api::ConnectorData::get_connector_by_name(
|
||||
connectors,
|
||||
connector_name,
|
||||
connector_type,
|
||||
)?);
|
||||
}
|
||||
}
|
||||
connectors_data
|
||||
} else {
|
||||
// Create connectors for all enabled wallets
|
||||
let mut connectors_data = Vec::with_capacity(
|
||||
normal_connector_names.len() + session_token_from_metadata_connectors.len(),
|
||||
);
|
||||
@ -333,6 +360,8 @@ where
|
||||
)?;
|
||||
connectors_data.push(connector_data);
|
||||
}
|
||||
connectors_data
|
||||
};
|
||||
|
||||
Ok(api::ConnectorCallType::Multiple(connectors_data))
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ use crate::{
|
||||
pii::Secret,
|
||||
routes::AppState,
|
||||
types::{
|
||||
api::{self, enums as api_enums, PaymentIdTypeExt},
|
||||
api::{self, PaymentIdTypeExt},
|
||||
storage::{self, enums},
|
||||
transformers::ForeignInto,
|
||||
},
|
||||
@ -252,8 +252,8 @@ where
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
request_connector: Option<api_enums::Connector>,
|
||||
_request: &api::PaymentsStartRequest,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
helpers::get_connector_default(merchant_account, state, None).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ use crate::{
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
types::{
|
||||
api::{self, enums as api_enums},
|
||||
api,
|
||||
storage::{self, enums},
|
||||
transformers::ForeignInto,
|
||||
},
|
||||
@ -100,9 +100,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>,
|
||||
_request: &api::PaymentsRequest,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
helpers::get_connector_default(merchant_account, state, None).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ use crate::{
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
types::{
|
||||
api::{self, enums as api_enums, PaymentIdTypeExt},
|
||||
api::{self, PaymentIdTypeExt},
|
||||
storage::{self, enums},
|
||||
transformers::ForeignInto,
|
||||
},
|
||||
@ -271,9 +271,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>,
|
||||
_request: &api::PaymentsRequest,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state, request_connector).await
|
||||
helpers::get_connector_default(merchant_account, state, None).await
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -52,7 +52,6 @@ async fn payments_incoming_webhook_flow(
|
||||
param: None,
|
||||
},
|
||||
services::AuthFlow::Merchant,
|
||||
None,
|
||||
consume_or_trigger_flow,
|
||||
)
|
||||
.await
|
||||
|
||||
@ -63,7 +63,6 @@ pub async fn payments_start(
|
||||
payments::operations::PaymentStart,
|
||||
req,
|
||||
api::AuthFlow::Client,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -103,7 +102,6 @@ pub async fn payments_retrieve(
|
||||
payments::PaymentStatus,
|
||||
req,
|
||||
api::AuthFlow::Merchant,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -219,7 +217,6 @@ pub async fn payments_capture(
|
||||
payments::PaymentCapture,
|
||||
payload,
|
||||
api::AuthFlow::Merchant,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -253,7 +250,6 @@ pub async fn payments_connector_session(
|
||||
payments::PaymentSession,
|
||||
payload,
|
||||
api::AuthFlow::Client,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -317,7 +313,6 @@ pub async fn payments_cancel(
|
||||
payments::PaymentCancel,
|
||||
req,
|
||||
api::AuthFlow::Merchant,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
@ -366,7 +361,6 @@ where
|
||||
// the operation are flow agnostic, and the flow is only required in the post_update_tracker
|
||||
// Thus the flow can be generated just before calling the connector instead of explicitly passing it here.
|
||||
|
||||
let connector = req.connector;
|
||||
match req.amount.as_ref() {
|
||||
Some(api_types::Amount::Value(_)) | None => payments::payments_core::<
|
||||
api_types::Authorize,
|
||||
@ -380,7 +374,6 @@ where
|
||||
operation,
|
||||
req,
|
||||
auth_flow,
|
||||
connector,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
.await,
|
||||
@ -392,7 +385,6 @@ where
|
||||
operation,
|
||||
req,
|
||||
auth_flow,
|
||||
connector,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
.await
|
||||
|
||||
@ -41,7 +41,6 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow {
|
||||
merchant_account.clone(),
|
||||
operations::PaymentStatus,
|
||||
tracking_data.clone(),
|
||||
None,
|
||||
payment_flows::CallConnectorAction::Trigger,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@ -355,7 +355,6 @@ async fn payments_create_core() {
|
||||
payments::PaymentCreate,
|
||||
req,
|
||||
services::AuthFlow::Merchant,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
.await
|
||||
@ -513,7 +512,6 @@ async fn payments_create_core_adyen_no_redirect() {
|
||||
payments::PaymentCreate,
|
||||
req,
|
||||
services::AuthFlow::Merchant,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
.await
|
||||
|
||||
@ -106,7 +106,6 @@ async fn payments_create_core() {
|
||||
payments::PaymentCreate,
|
||||
req,
|
||||
services::AuthFlow::Merchant,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
.await
|
||||
@ -267,7 +266,6 @@ async fn payments_create_core_adyen_no_redirect() {
|
||||
payments::PaymentCreate,
|
||||
req,
|
||||
services::AuthFlow::Merchant,
|
||||
None,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user