mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-31 01:57:45 +08:00
refactor(payout): move payout quote call to payout core from execute_pretasks (#4900)
This commit is contained in:
@ -913,7 +913,6 @@ Utility functions for tests are also available at `tests/connector/utils`. These
|
||||
Box::new(services::MockApiClient),
|
||||
)
|
||||
.await;
|
||||
integration.execute_pretasks(&mut request, &state).await?;
|
||||
Box::pin(call_connector(request, integration)).await
|
||||
}
|
||||
```
|
||||
|
||||
@ -155,6 +155,10 @@ impl Connector {
|
||||
matches!((self, payout_method), (_, PayoutType::Card))
|
||||
}
|
||||
#[cfg(feature = "payouts")]
|
||||
pub fn is_payout_quote_call_required(&self) -> bool {
|
||||
matches!(self, Self::Wise)
|
||||
}
|
||||
#[cfg(feature = "payouts")]
|
||||
pub fn supports_access_token_for_payout(&self, payout_method: PayoutType) -> bool {
|
||||
matches!((self, payout_method), (Self::Paypal, _))
|
||||
}
|
||||
|
||||
@ -26,8 +26,6 @@ use crate::{
|
||||
},
|
||||
utils::BytesExt,
|
||||
};
|
||||
#[cfg(feature = "payouts")]
|
||||
use crate::{core::payments, routes, types::transformers::ForeignFrom};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Wise;
|
||||
@ -503,44 +501,6 @@ impl
|
||||
impl services::ConnectorIntegration<api::PoCreate, types::PayoutsData, types::PayoutsResponseData>
|
||||
for Wise
|
||||
{
|
||||
async fn execute_pretasks(
|
||||
&self,
|
||||
router_data: &mut types::PayoutsRouterData<api::PoCreate>,
|
||||
app_state: &routes::SessionState,
|
||||
) -> CustomResult<(), errors::ConnectorError> {
|
||||
// Create a quote
|
||||
let quote_router_data =
|
||||
&types::PayoutsRouterData::foreign_from((&router_data, router_data.request.clone()));
|
||||
let quote_connector_integration: Box<
|
||||
&(dyn services::ConnectorIntegration<
|
||||
api::PoQuote,
|
||||
types::PayoutsData,
|
||||
types::PayoutsResponseData,
|
||||
> + Send
|
||||
+ Sync
|
||||
+ 'static),
|
||||
> = Box::new(self);
|
||||
let quote_router_resp = services::execute_connector_processing_step(
|
||||
app_state,
|
||||
quote_connector_integration,
|
||||
quote_router_data,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
match quote_router_resp.response.to_owned() {
|
||||
Ok(resp) => {
|
||||
router_data.quote_id = resp.connector_payout_id;
|
||||
Ok(())
|
||||
}
|
||||
Err(_err) => {
|
||||
router_data.response = quote_router_resp.response;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
_req: &types::PayoutsRouterData<api::PoCreate>,
|
||||
|
||||
@ -205,10 +205,6 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
|
||||
types::PaymentsAuthorizeData,
|
||||
types::PaymentsResponseData,
|
||||
> = connector.connector.get_connector_integration();
|
||||
connector_integration
|
||||
.execute_pretasks(self, state)
|
||||
.await
|
||||
.to_payment_failed_response()?;
|
||||
|
||||
metrics::EXECUTE_PRETASK_COUNT.add(
|
||||
&metrics::CONTEXT,
|
||||
|
||||
@ -738,18 +738,13 @@ pub async fn add_payment_method_token<F: Clone, T: types::Tokenizable + Clone>(
|
||||
let pm_token_response_data: Result<types::PaymentsResponseData, types::ErrorResponse> =
|
||||
Err(types::ErrorResponse::default());
|
||||
|
||||
let mut pm_token_router_data =
|
||||
let pm_token_router_data =
|
||||
helpers::router_data_type_conversion::<_, api::PaymentMethodToken, _, _, _, _>(
|
||||
router_data.clone(),
|
||||
pm_token_request_data,
|
||||
pm_token_response_data,
|
||||
);
|
||||
|
||||
connector_integration
|
||||
.execute_pretasks(&mut pm_token_router_data, state)
|
||||
.await
|
||||
.to_payment_failed_response()?;
|
||||
|
||||
router_data
|
||||
.request
|
||||
.set_session_token(pm_token_router_data.session_token.clone());
|
||||
|
||||
@ -26,7 +26,7 @@ use super::{
|
||||
payments::customers,
|
||||
};
|
||||
#[cfg(feature = "olap")]
|
||||
use crate::types::{domain::behaviour::Conversion, transformers::ForeignFrom};
|
||||
use crate::types::domain::behaviour::Conversion;
|
||||
use crate::{
|
||||
core::{
|
||||
errors::{self, CustomResult, RouterResponse, RouterResult},
|
||||
@ -41,6 +41,7 @@ use crate::{
|
||||
api::{self, payouts},
|
||||
domain,
|
||||
storage::{self, PaymentRoutingInfo},
|
||||
transformers::ForeignFrom,
|
||||
},
|
||||
utils::{self, OptionExt},
|
||||
};
|
||||
@ -160,13 +161,13 @@ pub async fn make_connector_decision(
|
||||
) -> RouterResult<()> {
|
||||
match connector_call_type {
|
||||
api::ConnectorCallType::PreDetermined(connector_data) => {
|
||||
call_connector_payout(
|
||||
Box::pin(call_connector_payout(
|
||||
state,
|
||||
merchant_account,
|
||||
key_store,
|
||||
&connector_data,
|
||||
payout_data,
|
||||
)
|
||||
))
|
||||
.await?;
|
||||
|
||||
#[cfg(feature = "payout_retry")]
|
||||
@ -197,13 +198,13 @@ pub async fn make_connector_decision(
|
||||
|
||||
let connector_data = get_next_connector(&mut connectors)?;
|
||||
|
||||
call_connector_payout(
|
||||
Box::pin(call_connector_payout(
|
||||
state,
|
||||
merchant_account,
|
||||
key_store,
|
||||
&connector_data,
|
||||
payout_data,
|
||||
)
|
||||
))
|
||||
.await?;
|
||||
|
||||
#[cfg(feature = "payout_retry")]
|
||||
@ -933,13 +934,13 @@ pub async fn call_connector_payout(
|
||||
.await?;
|
||||
|
||||
// Payout creation flow
|
||||
complete_create_payout(
|
||||
Box::pin(complete_create_payout(
|
||||
state,
|
||||
merchant_account,
|
||||
key_store,
|
||||
connector_data,
|
||||
payout_data,
|
||||
)
|
||||
))
|
||||
.await?;
|
||||
};
|
||||
|
||||
@ -1380,10 +1381,7 @@ pub async fn create_payout(
|
||||
> = connector_data.connector.get_connector_integration();
|
||||
|
||||
// 4. Execute pretasks
|
||||
connector_integration
|
||||
.execute_pretasks(&mut router_data, state)
|
||||
.await
|
||||
.to_payout_failed_response()?;
|
||||
complete_payout_quote_steps_if_required(state, connector_data, &mut router_data).await?;
|
||||
|
||||
// 5. Call connector service
|
||||
let router_data_resp = services::execute_connector_processing_step(
|
||||
@ -1474,6 +1472,45 @@ pub async fn create_payout(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn complete_payout_quote_steps_if_required<F>(
|
||||
state: &SessionState,
|
||||
connector_data: &api::ConnectorData,
|
||||
router_data: &mut types::RouterData<F, types::PayoutsData, types::PayoutsResponseData>,
|
||||
) -> RouterResult<()> {
|
||||
if connector_data
|
||||
.connector_name
|
||||
.is_payout_quote_call_required()
|
||||
{
|
||||
let quote_router_data =
|
||||
types::PayoutsRouterData::foreign_from((router_data, router_data.request.clone()));
|
||||
let connector_integration: services::BoxedConnectorIntegration<
|
||||
'_,
|
||||
api::PoQuote,
|
||||
types::PayoutsData,
|
||||
types::PayoutsResponseData,
|
||||
> = connector_data.connector.get_connector_integration();
|
||||
let router_data_resp = services::execute_connector_processing_step(
|
||||
state,
|
||||
connector_integration,
|
||||
"e_router_data,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.to_payout_failed_response()?;
|
||||
|
||||
match router_data_resp.response.to_owned() {
|
||||
Ok(resp) => {
|
||||
router_data.quote_id = resp.connector_payout_id;
|
||||
}
|
||||
Err(_err) => {
|
||||
router_data.response = router_data_resp.response;
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn complete_create_recipient_disburse_account(
|
||||
state: &SessionState,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
|
||||
@ -246,7 +246,14 @@ pub async fn do_retry(
|
||||
|
||||
modify_trackers(state, &connector, merchant_account, payout_data).await?;
|
||||
|
||||
call_connector_payout(state, merchant_account, key_store, &connector, payout_data).await
|
||||
Box::pin(call_connector_payout(
|
||||
state,
|
||||
merchant_account,
|
||||
key_store,
|
||||
&connector,
|
||||
payout_data,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
|
||||
@ -171,26 +171,6 @@ pub trait ConnectorIntegration<T, Req, Resp>: ConnectorIntegrationAny<T, Req, Re
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// This module can be called before executing a payment flow where a pre-task is needed
|
||||
/// Eg: Some connectors requires one-time session token before making a payment, we can add the session token creation logic in this block
|
||||
async fn execute_pretasks(
|
||||
&self,
|
||||
_router_data: &mut types::RouterData<T, Req, Resp>,
|
||||
_app_state: &SessionState,
|
||||
) -> CustomResult<(), errors::ConnectorError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This module can be called after executing a payment flow where a post-task needed
|
||||
/// Eg: Some connectors require payment sync to happen immediately after the authorize call to complete the transaction, we can add that logic in this block
|
||||
async fn execute_posttasks(
|
||||
&self,
|
||||
_router_data: &mut types::RouterData<T, Req, Resp>,
|
||||
_app_state: &SessionState,
|
||||
) -> CustomResult<(), errors::ConnectorError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_request(
|
||||
&self,
|
||||
req: &types::RouterData<T, Req, Resp>,
|
||||
|
||||
@ -842,13 +842,13 @@ impl<F1, F2, T1, T2> ForeignFrom<(&RouterData<F1, T1, PaymentsResponseData>, T2)
|
||||
#[cfg(feature = "payouts")]
|
||||
impl<F1, F2>
|
||||
ForeignFrom<(
|
||||
&&mut RouterData<F1, PayoutsData, PayoutsResponseData>,
|
||||
&RouterData<F1, PayoutsData, PayoutsResponseData>,
|
||||
PayoutsData,
|
||||
)> for RouterData<F2, PayoutsData, PayoutsResponseData>
|
||||
{
|
||||
fn foreign_from(
|
||||
item: (
|
||||
&&mut RouterData<F1, PayoutsData, PayoutsResponseData>,
|
||||
&RouterData<F1, PayoutsData, PayoutsResponseData>,
|
||||
PayoutsData,
|
||||
),
|
||||
) -> Self {
|
||||
|
||||
@ -86,7 +86,7 @@ pub trait ConnectorActions: Connector {
|
||||
payment_info: Option<PaymentInfo>,
|
||||
) -> Result<types::PaymentsAuthorizeRouterData, Report<ConnectorError>> {
|
||||
let integration = self.get_data().connector.get_connector_integration();
|
||||
let mut request = self.generate_data(
|
||||
let request = self.generate_data(
|
||||
types::PaymentsAuthorizeData {
|
||||
confirm: true,
|
||||
capture_method: Some(diesel_models::enums::CaptureMethod::Manual),
|
||||
@ -94,18 +94,6 @@ pub trait ConnectorActions: Connector {
|
||||
},
|
||||
payment_info,
|
||||
);
|
||||
let tx: oneshot::Sender<()> = oneshot::channel().0;
|
||||
let app_state = Box::pin(routes::AppState::with_storage(
|
||||
Settings::new().unwrap(),
|
||||
StorageImpl::PostgresqlTest,
|
||||
tx,
|
||||
Box::new(services::MockApiClient),
|
||||
))
|
||||
.await;
|
||||
let state = Arc::new(app_state)
|
||||
.get_session_state("public", || {})
|
||||
.unwrap();
|
||||
integration.execute_pretasks(&mut request, &state).await?;
|
||||
Box::pin(call_connector(request, integration)).await
|
||||
}
|
||||
|
||||
@ -115,25 +103,12 @@ pub trait ConnectorActions: Connector {
|
||||
payment_info: Option<PaymentInfo>,
|
||||
) -> Result<types::ConnectorCustomerRouterData, Report<ConnectorError>> {
|
||||
let integration = self.get_data().connector.get_connector_integration();
|
||||
let mut request = self.generate_data(
|
||||
let request = self.generate_data(
|
||||
types::ConnectorCustomerData {
|
||||
..(payment_data.unwrap_or(CustomerType::default().0))
|
||||
},
|
||||
payment_info,
|
||||
);
|
||||
let tx: oneshot::Sender<()> = oneshot::channel().0;
|
||||
|
||||
let app_state = Box::pin(routes::AppState::with_storage(
|
||||
Settings::new().unwrap(),
|
||||
StorageImpl::PostgresqlTest,
|
||||
tx,
|
||||
Box::new(services::MockApiClient),
|
||||
))
|
||||
.await;
|
||||
let state = Arc::new(app_state)
|
||||
.get_session_state("public", || {})
|
||||
.unwrap();
|
||||
integration.execute_pretasks(&mut request, &state).await?;
|
||||
Box::pin(call_connector(request, integration)).await
|
||||
}
|
||||
|
||||
@ -143,25 +118,12 @@ pub trait ConnectorActions: Connector {
|
||||
payment_info: Option<PaymentInfo>,
|
||||
) -> Result<types::TokenizationRouterData, Report<ConnectorError>> {
|
||||
let integration = self.get_data().connector.get_connector_integration();
|
||||
let mut request = self.generate_data(
|
||||
let request = self.generate_data(
|
||||
types::PaymentMethodTokenizationData {
|
||||
..(payment_data.unwrap_or(TokenType::default().0))
|
||||
},
|
||||
payment_info,
|
||||
);
|
||||
let tx: oneshot::Sender<()> = oneshot::channel().0;
|
||||
|
||||
let app_state = Box::pin(routes::AppState::with_storage(
|
||||
Settings::new().unwrap(),
|
||||
StorageImpl::PostgresqlTest,
|
||||
tx,
|
||||
Box::new(services::MockApiClient),
|
||||
))
|
||||
.await;
|
||||
let state = Arc::new(app_state)
|
||||
.get_session_state("public", || {})
|
||||
.unwrap();
|
||||
integration.execute_pretasks(&mut request, &state).await?;
|
||||
Box::pin(call_connector(request, integration)).await
|
||||
}
|
||||
|
||||
@ -173,7 +135,7 @@ pub trait ConnectorActions: Connector {
|
||||
payment_info: Option<PaymentInfo>,
|
||||
) -> Result<types::PaymentsAuthorizeRouterData, Report<ConnectorError>> {
|
||||
let integration = self.get_data().connector.get_connector_integration();
|
||||
let mut request = self.generate_data(
|
||||
let request = self.generate_data(
|
||||
types::PaymentsAuthorizeData {
|
||||
confirm: true,
|
||||
capture_method: Some(diesel_models::enums::CaptureMethod::Automatic),
|
||||
@ -181,19 +143,6 @@ pub trait ConnectorActions: Connector {
|
||||
},
|
||||
payment_info,
|
||||
);
|
||||
let tx: oneshot::Sender<()> = oneshot::channel().0;
|
||||
|
||||
let app_state = Box::pin(routes::AppState::with_storage(
|
||||
Settings::new().unwrap(),
|
||||
StorageImpl::PostgresqlTest,
|
||||
tx,
|
||||
Box::new(services::MockApiClient),
|
||||
))
|
||||
.await;
|
||||
let state = Arc::new(app_state)
|
||||
.get_session_state("public", || {})
|
||||
.unwrap();
|
||||
integration.execute_pretasks(&mut request, &state).await?;
|
||||
Box::pin(call_connector(request, integration)).await
|
||||
}
|
||||
|
||||
@ -609,7 +558,7 @@ pub trait ConnectorActions: Connector {
|
||||
.ok_or(ConnectorError::FailedToObtainPreferredConnector)?
|
||||
.connector
|
||||
.get_connector_integration();
|
||||
let mut request = self.get_payout_request(None, payout_type, payment_info);
|
||||
let request = self.get_payout_request(None, payout_type, payment_info);
|
||||
let tx: oneshot::Sender<()> = oneshot::channel().0;
|
||||
|
||||
let app_state = Box::pin(routes::AppState::with_storage(
|
||||
@ -622,9 +571,6 @@ pub trait ConnectorActions: Connector {
|
||||
let state = Arc::new(app_state)
|
||||
.get_session_state("public", || {})
|
||||
.unwrap();
|
||||
connector_integration
|
||||
.execute_pretasks(&mut request, &state)
|
||||
.await?;
|
||||
let res = services::api::execute_connector_processing_step(
|
||||
&state,
|
||||
connector_integration,
|
||||
@ -653,7 +599,7 @@ pub trait ConnectorActions: Connector {
|
||||
.ok_or(ConnectorError::FailedToObtainPreferredConnector)?
|
||||
.connector
|
||||
.get_connector_integration();
|
||||
let mut request = self.get_payout_request(connector_payout_id, payout_type, payment_info);
|
||||
let request = self.get_payout_request(connector_payout_id, payout_type, payment_info);
|
||||
let tx: oneshot::Sender<()> = oneshot::channel().0;
|
||||
|
||||
let app_state = Box::pin(routes::AppState::with_storage(
|
||||
@ -666,9 +612,6 @@ pub trait ConnectorActions: Connector {
|
||||
let state = Arc::new(app_state)
|
||||
.get_session_state("public", || {})
|
||||
.unwrap();
|
||||
connector_integration
|
||||
.execute_pretasks(&mut request, &state)
|
||||
.await?;
|
||||
let res = services::api::execute_connector_processing_step(
|
||||
&state,
|
||||
connector_integration,
|
||||
@ -711,9 +654,6 @@ pub trait ConnectorActions: Connector {
|
||||
let state = Arc::new(app_state)
|
||||
.get_session_state("public", || {})
|
||||
.unwrap();
|
||||
connector_integration
|
||||
.execute_pretasks(&mut request, &state)
|
||||
.await?;
|
||||
let res = services::api::execute_connector_processing_step(
|
||||
&state,
|
||||
connector_integration,
|
||||
@ -742,8 +682,7 @@ pub trait ConnectorActions: Connector {
|
||||
.ok_or(ConnectorError::FailedToObtainPreferredConnector)?
|
||||
.connector
|
||||
.get_connector_integration();
|
||||
let mut request =
|
||||
self.get_payout_request(Some(connector_payout_id), payout_type, payment_info);
|
||||
let request = self.get_payout_request(Some(connector_payout_id), payout_type, payment_info);
|
||||
let tx: oneshot::Sender<()> = oneshot::channel().0;
|
||||
|
||||
let app_state = Box::pin(routes::AppState::with_storage(
|
||||
@ -756,9 +695,6 @@ pub trait ConnectorActions: Connector {
|
||||
let state = Arc::new(app_state)
|
||||
.get_session_state("public", || {})
|
||||
.unwrap();
|
||||
connector_integration
|
||||
.execute_pretasks(&mut request, &state)
|
||||
.await?;
|
||||
let res = services::api::execute_connector_processing_step(
|
||||
&state,
|
||||
connector_integration,
|
||||
@ -838,7 +774,7 @@ pub trait ConnectorActions: Connector {
|
||||
.ok_or(ConnectorError::FailedToObtainPreferredConnector)?
|
||||
.connector
|
||||
.get_connector_integration();
|
||||
let mut request = self.get_payout_request(None, payout_type, payment_info);
|
||||
let request = self.get_payout_request(None, payout_type, payment_info);
|
||||
let tx = oneshot::channel().0;
|
||||
|
||||
let app_state = Box::pin(routes::AppState::with_storage(
|
||||
@ -851,9 +787,6 @@ pub trait ConnectorActions: Connector {
|
||||
let state = Arc::new(app_state)
|
||||
.get_session_state("public", || {})
|
||||
.unwrap();
|
||||
connector_integration
|
||||
.execute_pretasks(&mut request, &state)
|
||||
.await?;
|
||||
let res = services::api::execute_connector_processing_step(
|
||||
&state,
|
||||
connector_integration,
|
||||
|
||||
Reference in New Issue
Block a user