mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 09:07:09 +08:00
initial commit
This commit is contained in:
350
crates/router/src/core/payments/operations.rs
Normal file
350
crates/router/src/core/payments/operations.rs
Normal file
@ -0,0 +1,350 @@
|
||||
mod payment_cancel;
|
||||
mod payment_capture;
|
||||
mod payment_confirm;
|
||||
mod payment_create;
|
||||
mod payment_response;
|
||||
mod payment_start;
|
||||
mod payment_status;
|
||||
mod payment_update;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use error_stack::{report, ResultExt};
|
||||
pub use payment_cancel::PaymentCancel;
|
||||
pub use payment_capture::PaymentCapture;
|
||||
pub use payment_confirm::PaymentConfirm;
|
||||
pub use payment_create::PaymentCreate;
|
||||
pub use payment_response::PaymentResponse;
|
||||
pub use payment_start::PaymentStart;
|
||||
pub use payment_status::PaymentStatus;
|
||||
pub use payment_update::PaymentUpdate;
|
||||
use router_env::{instrument, tracing};
|
||||
use storage::Customer;
|
||||
|
||||
use super::{helpers, CustomerDetails, PaymentData};
|
||||
use crate::{
|
||||
core::errors::{self, CustomResult, RouterResult},
|
||||
db::Db,
|
||||
routes::AppState,
|
||||
types::{
|
||||
self, api,
|
||||
storage::{self, enums},
|
||||
PaymentsResponseData,
|
||||
},
|
||||
};
|
||||
|
||||
pub type BoxedOperation<'a, F, T> = Box<dyn Operation<F, T> + Send + Sync + 'a>;
|
||||
|
||||
pub trait Operation<F: Clone, T>: Send + std::fmt::Debug {
|
||||
fn to_validate_request(&self) -> RouterResult<&(dyn ValidateRequest<F, T> + Send + Sync)> {
|
||||
Err(report!(errors::ApiErrorResponse::InternalServerError))
|
||||
.attach_printable_lazy(|| format!("validate request interface not found for {self:?}"))
|
||||
}
|
||||
fn to_get_tracker(
|
||||
&self,
|
||||
) -> RouterResult<&(dyn GetTracker<F, PaymentData<F>, T> + Send + Sync)> {
|
||||
Err(report!(errors::ApiErrorResponse::InternalServerError))
|
||||
.attach_printable_lazy(|| format!("get tracker interface not found for {self:?}"))
|
||||
}
|
||||
fn to_domain(&self) -> RouterResult<&dyn Domain<F, T>> {
|
||||
Err(report!(errors::ApiErrorResponse::InternalServerError))
|
||||
.attach_printable_lazy(|| format!("domain interface not found for {self:?}"))
|
||||
}
|
||||
fn to_update_tracker(
|
||||
&self,
|
||||
) -> RouterResult<&(dyn UpdateTracker<F, PaymentData<F>, T> + Send + Sync)> {
|
||||
Err(report!(errors::ApiErrorResponse::InternalServerError))
|
||||
.attach_printable_lazy(|| format!("update tracker interface not found for {self:?}"))
|
||||
}
|
||||
fn to_post_update_tracker(
|
||||
&self,
|
||||
) -> RouterResult<&(dyn PostUpdateTracker<F, PaymentData<F>, T> + Send + Sync)> {
|
||||
Err(report!(errors::ApiErrorResponse::InternalServerError)).attach_printable_lazy(|| {
|
||||
format!("post connector update tracker not found for {self:?}")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub trait ValidateRequest<F, R> {
|
||||
fn validate_request<'a, 'b>(
|
||||
&'b self,
|
||||
request: &R,
|
||||
merchant_account: &'a storage::MerchantAccount,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'b, F, R>,
|
||||
&'a str,
|
||||
api::PaymentIdType,
|
||||
Option<api::MandateTxnType>,
|
||||
)>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait GetTracker<F, D, R>: Send {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn get_trackers<'a>(
|
||||
&'a self,
|
||||
state: &'a AppState,
|
||||
payment_id: &api::PaymentIdType,
|
||||
merchant_id: &str,
|
||||
connector: types::Connector,
|
||||
request: &R,
|
||||
mandate_type: Option<api::MandateTxnType>,
|
||||
) -> RouterResult<(BoxedOperation<'a, F, R>, D, Option<CustomerDetails>)>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Domain<F: Clone, R>: Send + Sync {
|
||||
/// This will fetch customer details, (this operation is flow specific)
|
||||
async fn get_or_create_customer_details<'a>(
|
||||
&'a self,
|
||||
db: &dyn Db,
|
||||
payment_data: &mut PaymentData<F>,
|
||||
request: Option<CustomerDetails>,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<(BoxedOperation<'a, F, R>, Option<api::CustomerResponse>), errors::StorageError>;
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn make_pm_data<'a>(
|
||||
&'a self,
|
||||
state: &'a AppState,
|
||||
_payment_method: Option<enums::PaymentMethodType>,
|
||||
txn_id: &str,
|
||||
payment_attempt: &storage::PaymentAttempt,
|
||||
request: &Option<api::PaymentMethod>,
|
||||
token: Option<i32>,
|
||||
) -> RouterResult<(BoxedOperation<'a, F, R>, Option<api::PaymentMethod>)>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait UpdateTracker<F, D, R>: Send {
|
||||
async fn update_trackers<'b>(
|
||||
&'b self,
|
||||
db: &dyn Db,
|
||||
payment_id: &api::PaymentIdType,
|
||||
payment_data: D,
|
||||
customer: Option<Customer>,
|
||||
) -> RouterResult<(BoxedOperation<'b, F, R>, D)>
|
||||
where
|
||||
F: 'b + Send;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait PostUpdateTracker<F, D, R>: Send {
|
||||
async fn update_tracker<'b>(
|
||||
&'b self,
|
||||
db: &dyn Db,
|
||||
payment_id: &api::PaymentIdType,
|
||||
payment_data: D,
|
||||
response: Option<types::RouterData<F, R, PaymentsResponseData>>,
|
||||
) -> RouterResult<D>
|
||||
where
|
||||
F: 'b + Send;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<F: Clone + Send, Op: Send + Sync + Operation<F, api::PaymentsRequest>>
|
||||
Domain<F, api::PaymentsRequest> for Op
|
||||
where
|
||||
for<'a> &'a Op: Operation<F, api::PaymentsRequest>,
|
||||
{
|
||||
#[instrument(skip_all)]
|
||||
async fn get_or_create_customer_details<'a>(
|
||||
&'a self,
|
||||
db: &dyn Db,
|
||||
payment_data: &mut PaymentData<F>,
|
||||
request: Option<CustomerDetails>,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<
|
||||
(
|
||||
BoxedOperation<'a, F, api::PaymentsRequest>,
|
||||
Option<api::CustomerResponse>,
|
||||
),
|
||||
errors::StorageError,
|
||||
> {
|
||||
helpers::create_customer_if_not_exist(
|
||||
Box::new(self),
|
||||
db,
|
||||
payment_data,
|
||||
request,
|
||||
merchant_id,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn make_pm_data<'a>(
|
||||
&'a self,
|
||||
state: &'a AppState,
|
||||
payment_method: Option<enums::PaymentMethodType>,
|
||||
txn_id: &str,
|
||||
payment_attempt: &storage::PaymentAttempt,
|
||||
request: &Option<api::PaymentMethod>,
|
||||
token: Option<i32>,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsRequest>,
|
||||
Option<api::PaymentMethod>,
|
||||
)> {
|
||||
helpers::make_pm_data(
|
||||
Box::new(self),
|
||||
state,
|
||||
payment_method,
|
||||
txn_id,
|
||||
payment_attempt,
|
||||
request,
|
||||
token,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<F: Clone + Send, Op: Send + Sync + Operation<F, api::PaymentsRetrieveRequest>>
|
||||
Domain<F, api::PaymentsRetrieveRequest> for Op
|
||||
where
|
||||
for<'a> &'a Op: Operation<F, api::PaymentsRetrieveRequest>,
|
||||
{
|
||||
#[instrument(skip_all)]
|
||||
async fn get_or_create_customer_details<'a>(
|
||||
&'a self,
|
||||
db: &dyn Db,
|
||||
payment_data: &mut PaymentData<F>,
|
||||
_request: Option<CustomerDetails>,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<
|
||||
(
|
||||
BoxedOperation<'a, F, api::PaymentsRetrieveRequest>,
|
||||
Option<api::CustomerResponse>,
|
||||
),
|
||||
errors::StorageError,
|
||||
> {
|
||||
Ok((
|
||||
Box::new(self),
|
||||
helpers::get_customer_from_details(
|
||||
db,
|
||||
payment_data.payment_intent.customer_id.clone(),
|
||||
merchant_id,
|
||||
)
|
||||
.await?,
|
||||
))
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn make_pm_data<'a>(
|
||||
&'a self,
|
||||
state: &'a AppState,
|
||||
payment_method: Option<enums::PaymentMethodType>,
|
||||
txn_id: &str,
|
||||
payment_attempt: &storage::PaymentAttempt,
|
||||
request: &Option<api::PaymentMethod>,
|
||||
token: Option<i32>,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsRetrieveRequest>,
|
||||
Option<api::PaymentMethod>,
|
||||
)> {
|
||||
helpers::make_pm_data(
|
||||
Box::new(self),
|
||||
state,
|
||||
payment_method,
|
||||
txn_id,
|
||||
payment_attempt,
|
||||
request,
|
||||
token,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<F: Clone + Send, Op: Send + Sync + Operation<F, api::PaymentsCaptureRequest>>
|
||||
Domain<F, api::PaymentsCaptureRequest> for Op
|
||||
where
|
||||
for<'a> &'a Op: Operation<F, api::PaymentsCaptureRequest>,
|
||||
{
|
||||
#[instrument(skip_all)]
|
||||
async fn get_or_create_customer_details<'a>(
|
||||
&'a self,
|
||||
db: &dyn Db,
|
||||
payment_data: &mut PaymentData<F>,
|
||||
_request: Option<CustomerDetails>,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<
|
||||
(
|
||||
BoxedOperation<'a, F, api::PaymentsCaptureRequest>,
|
||||
Option<api::CustomerResponse>,
|
||||
),
|
||||
errors::StorageError,
|
||||
> {
|
||||
Ok((
|
||||
Box::new(self),
|
||||
helpers::get_customer_from_details(
|
||||
db,
|
||||
payment_data.payment_intent.customer_id.clone(),
|
||||
merchant_id,
|
||||
)
|
||||
.await?,
|
||||
))
|
||||
}
|
||||
#[instrument(skip_all)]
|
||||
async fn make_pm_data<'a>(
|
||||
&'a self,
|
||||
_state: &'a AppState,
|
||||
_payment_method: Option<enums::PaymentMethodType>,
|
||||
_txn_id: &str,
|
||||
_payment_attempt: &storage::PaymentAttempt,
|
||||
_request: &Option<api::PaymentMethod>,
|
||||
_token: Option<i32>,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsCaptureRequest>,
|
||||
Option<api::PaymentMethod>,
|
||||
)> {
|
||||
Ok((Box::new(self), None))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<F: Clone + Send, Op: Send + Sync + Operation<F, api::PaymentsCancelRequest>>
|
||||
Domain<F, api::PaymentsCancelRequest> for Op
|
||||
where
|
||||
for<'a> &'a Op: Operation<F, api::PaymentsCancelRequest>,
|
||||
{
|
||||
#[instrument(skip_all)]
|
||||
async fn get_or_create_customer_details<'a>(
|
||||
&'a self,
|
||||
db: &dyn Db,
|
||||
payment_data: &mut PaymentData<F>,
|
||||
_request: Option<CustomerDetails>,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<
|
||||
(
|
||||
BoxedOperation<'a, F, api::PaymentsCancelRequest>,
|
||||
Option<api::CustomerResponse>,
|
||||
),
|
||||
errors::StorageError,
|
||||
> {
|
||||
Ok((
|
||||
Box::new(self),
|
||||
helpers::get_customer_from_details(
|
||||
db,
|
||||
payment_data.payment_intent.customer_id.clone(),
|
||||
merchant_id,
|
||||
)
|
||||
.await?,
|
||||
))
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn make_pm_data<'a>(
|
||||
&'a self,
|
||||
_state: &'a AppState,
|
||||
_payment_method: Option<enums::PaymentMethodType>,
|
||||
_txn_id: &str,
|
||||
_payment_attempt: &storage::PaymentAttempt,
|
||||
_request: &Option<api::PaymentMethod>,
|
||||
_token: Option<i32>,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsCancelRequest>,
|
||||
Option<api::PaymentMethod>,
|
||||
)> {
|
||||
Ok((Box::new(self), None))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user