mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 21:07:58 +08:00
feat(router): Add payments get-intent API for v2 (#6396)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -1021,7 +1021,7 @@ pub async fn payments_intent_operation_core<F, Req, Op, D>(
|
||||
) -> RouterResult<(D, Req, Option<domain::Customer>)>
|
||||
where
|
||||
F: Send + Clone + Sync,
|
||||
Req: Authenticate + Clone,
|
||||
Req: Clone,
|
||||
Op: Operation<F, Req, Data = D> + Send + Sync,
|
||||
D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
|
||||
{
|
||||
@ -1454,7 +1454,7 @@ pub async fn payments_intent_core<F, Res, Req, Op, D>(
|
||||
where
|
||||
F: Send + Clone + Sync,
|
||||
Op: Operation<F, Req, Data = D> + Send + Sync + Clone,
|
||||
Req: Debug + Authenticate + Clone,
|
||||
Req: Debug + Clone,
|
||||
D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
|
||||
Res: transformers::ToResponse<F, D, Op>,
|
||||
{
|
||||
|
||||
@ -28,11 +28,12 @@ pub mod payments_incremental_authorization;
|
||||
#[cfg(feature = "v1")]
|
||||
pub mod tax_calculation;
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
pub mod payment_create_intent;
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
pub mod payment_confirm_intent;
|
||||
#[cfg(feature = "v2")]
|
||||
pub mod payment_create_intent;
|
||||
#[cfg(feature = "v2")]
|
||||
pub mod payment_get_intent;
|
||||
|
||||
use api_models::enums::FrmSuggestion;
|
||||
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
|
||||
@ -45,6 +46,8 @@ use router_env::{instrument, tracing};
|
||||
pub use self::payment_confirm_intent::PaymentIntentConfirm;
|
||||
#[cfg(feature = "v2")]
|
||||
pub use self::payment_create_intent::PaymentIntentCreate;
|
||||
#[cfg(feature = "v2")]
|
||||
pub use self::payment_get_intent::PaymentGetIntent;
|
||||
pub use self::payment_response::PaymentResponse;
|
||||
#[cfg(feature = "v1")]
|
||||
pub use self::{
|
||||
|
||||
231
crates/router/src/core/payments/operations/payment_get_intent.rs
Normal file
231
crates/router/src/core/payments/operations/payment_get_intent.rs
Normal file
@ -0,0 +1,231 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use api_models::{enums::FrmSuggestion, payments::PaymentsGetIntentRequest};
|
||||
use async_trait::async_trait;
|
||||
use common_utils::errors::CustomResult;
|
||||
use router_env::{instrument, tracing};
|
||||
|
||||
use super::{BoxedOperation, Domain, GetTracker, Operation, UpdateTracker, ValidateRequest};
|
||||
use crate::{
|
||||
core::{
|
||||
errors::{self, RouterResult},
|
||||
payments::{self, helpers, operations},
|
||||
},
|
||||
db::errors::StorageErrorExt,
|
||||
routes::{app::ReqState, SessionState},
|
||||
types::{
|
||||
api, domain,
|
||||
storage::{self, enums},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PaymentGetIntent;
|
||||
|
||||
impl<F: Send + Clone> Operation<F, PaymentsGetIntentRequest> for &PaymentGetIntent {
|
||||
type Data = payments::PaymentIntentData<F>;
|
||||
fn to_validate_request(
|
||||
&self,
|
||||
) -> RouterResult<&(dyn ValidateRequest<F, PaymentsGetIntentRequest, Self::Data> + Send + Sync)>
|
||||
{
|
||||
Ok(*self)
|
||||
}
|
||||
fn to_get_tracker(
|
||||
&self,
|
||||
) -> RouterResult<&(dyn GetTracker<F, Self::Data, PaymentsGetIntentRequest> + Send + Sync)>
|
||||
{
|
||||
Ok(*self)
|
||||
}
|
||||
fn to_domain(&self) -> RouterResult<&(dyn Domain<F, PaymentsGetIntentRequest, Self::Data>)> {
|
||||
Ok(*self)
|
||||
}
|
||||
fn to_update_tracker(
|
||||
&self,
|
||||
) -> RouterResult<&(dyn UpdateTracker<F, Self::Data, PaymentsGetIntentRequest> + Send + Sync)>
|
||||
{
|
||||
Ok(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Send + Clone> Operation<F, PaymentsGetIntentRequest> for PaymentGetIntent {
|
||||
type Data = payments::PaymentIntentData<F>;
|
||||
fn to_validate_request(
|
||||
&self,
|
||||
) -> RouterResult<&(dyn ValidateRequest<F, PaymentsGetIntentRequest, Self::Data> + Send + Sync)>
|
||||
{
|
||||
Ok(self)
|
||||
}
|
||||
fn to_get_tracker(
|
||||
&self,
|
||||
) -> RouterResult<&(dyn GetTracker<F, Self::Data, PaymentsGetIntentRequest> + Send + Sync)>
|
||||
{
|
||||
Ok(self)
|
||||
}
|
||||
fn to_domain(&self) -> RouterResult<&dyn Domain<F, PaymentsGetIntentRequest, Self::Data>> {
|
||||
Ok(self)
|
||||
}
|
||||
fn to_update_tracker(
|
||||
&self,
|
||||
) -> RouterResult<&(dyn UpdateTracker<F, Self::Data, PaymentsGetIntentRequest> + Send + Sync)>
|
||||
{
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
type PaymentsGetIntentOperation<'b, F> =
|
||||
BoxedOperation<'b, F, PaymentsGetIntentRequest, payments::PaymentIntentData<F>>;
|
||||
|
||||
#[async_trait]
|
||||
impl<F: Send + Clone> GetTracker<F, payments::PaymentIntentData<F>, PaymentsGetIntentRequest>
|
||||
for PaymentGetIntent
|
||||
{
|
||||
#[instrument(skip_all)]
|
||||
async fn get_trackers<'a>(
|
||||
&'a self,
|
||||
state: &'a SessionState,
|
||||
_payment_id: &common_utils::id_type::GlobalPaymentId,
|
||||
request: &PaymentsGetIntentRequest,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
_profile: &domain::Profile,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
_header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
|
||||
) -> RouterResult<
|
||||
operations::GetTrackerResponse<
|
||||
'a,
|
||||
F,
|
||||
PaymentsGetIntentRequest,
|
||||
payments::PaymentIntentData<F>,
|
||||
>,
|
||||
> {
|
||||
let db = &*state.store;
|
||||
let key_manager_state = &state.into();
|
||||
let storage_scheme = merchant_account.storage_scheme;
|
||||
let payment_intent = db
|
||||
.find_payment_intent_by_id(key_manager_state, &request.id, key_store, storage_scheme)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
|
||||
|
||||
let payment_data = payments::PaymentIntentData {
|
||||
flow: PhantomData,
|
||||
payment_intent,
|
||||
};
|
||||
|
||||
let get_trackers_response = operations::GetTrackerResponse {
|
||||
operation: Box::new(self),
|
||||
payment_data,
|
||||
};
|
||||
|
||||
Ok(get_trackers_response)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<F: Clone> UpdateTracker<F, payments::PaymentIntentData<F>, PaymentsGetIntentRequest>
|
||||
for PaymentGetIntent
|
||||
{
|
||||
#[instrument(skip_all)]
|
||||
async fn update_trackers<'b>(
|
||||
&'b self,
|
||||
_state: &'b SessionState,
|
||||
_req_state: ReqState,
|
||||
payment_data: payments::PaymentIntentData<F>,
|
||||
_customer: Option<domain::Customer>,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
_updated_customer: Option<storage::CustomerUpdate>,
|
||||
_key_store: &domain::MerchantKeyStore,
|
||||
_frm_suggestion: Option<FrmSuggestion>,
|
||||
_header_payload: hyperswitch_domain_models::payments::HeaderPayload,
|
||||
) -> RouterResult<(
|
||||
PaymentsGetIntentOperation<'b, F>,
|
||||
payments::PaymentIntentData<F>,
|
||||
)>
|
||||
where
|
||||
F: 'b + Send,
|
||||
{
|
||||
Ok((Box::new(self), payment_data))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Send + Clone> ValidateRequest<F, PaymentsGetIntentRequest, payments::PaymentIntentData<F>>
|
||||
for PaymentGetIntent
|
||||
{
|
||||
#[instrument(skip_all)]
|
||||
fn validate_request<'a, 'b>(
|
||||
&'b self,
|
||||
_request: &PaymentsGetIntentRequest,
|
||||
merchant_account: &'a domain::MerchantAccount,
|
||||
) -> RouterResult<(
|
||||
PaymentsGetIntentOperation<'b, F>,
|
||||
operations::ValidateResult,
|
||||
)> {
|
||||
Ok((
|
||||
Box::new(self),
|
||||
operations::ValidateResult {
|
||||
merchant_id: merchant_account.get_id().to_owned(),
|
||||
storage_scheme: merchant_account.storage_scheme,
|
||||
requeue: false,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<F: Clone + Send> Domain<F, PaymentsGetIntentRequest, payments::PaymentIntentData<F>>
|
||||
for PaymentGetIntent
|
||||
{
|
||||
#[instrument(skip_all)]
|
||||
async fn get_customer_details<'a>(
|
||||
&'a self,
|
||||
state: &SessionState,
|
||||
payment_data: &mut payments::PaymentIntentData<F>,
|
||||
merchant_key_store: &domain::MerchantKeyStore,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
) -> CustomResult<
|
||||
(
|
||||
BoxedOperation<'a, F, PaymentsGetIntentRequest, payments::PaymentIntentData<F>>,
|
||||
Option<domain::Customer>,
|
||||
),
|
||||
errors::StorageError,
|
||||
> {
|
||||
Ok((Box::new(self), None))
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn make_pm_data<'a>(
|
||||
&'a self,
|
||||
_state: &'a SessionState,
|
||||
_payment_data: &mut payments::PaymentIntentData<F>,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
_merchant_key_store: &domain::MerchantKeyStore,
|
||||
_customer: &Option<domain::Customer>,
|
||||
_business_profile: &domain::Profile,
|
||||
) -> RouterResult<(
|
||||
PaymentsGetIntentOperation<'a, F>,
|
||||
Option<domain::PaymentMethodData>,
|
||||
Option<String>,
|
||||
)> {
|
||||
Ok((Box::new(self), None, None))
|
||||
}
|
||||
|
||||
async fn get_connector<'a>(
|
||||
&'a self,
|
||||
_merchant_account: &domain::MerchantAccount,
|
||||
state: &SessionState,
|
||||
_request: &PaymentsGetIntentRequest,
|
||||
_payment_intent: &storage::PaymentIntent,
|
||||
_merchant_key_store: &domain::MerchantKeyStore,
|
||||
) -> CustomResult<api::ConnectorChoice, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(state, None).await
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn guard_payment_against_blocklist<'a>(
|
||||
&'a self,
|
||||
_state: &SessionState,
|
||||
_merchant_account: &domain::MerchantAccount,
|
||||
_key_store: &domain::MerchantKeyStore,
|
||||
_payment_data: &mut payments::PaymentIntentData<F>,
|
||||
) -> CustomResult<bool, errors::ApiErrorResponse> {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
@ -755,7 +755,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
impl<F, Op, D> ToResponse<F, D, Op> for api::PaymentsCreateIntentResponse
|
||||
impl<F, Op, D> ToResponse<F, D, Op> for api::PaymentsIntentResponse
|
||||
where
|
||||
F: Clone,
|
||||
Op: Debug,
|
||||
|
||||
@ -527,6 +527,10 @@ impl Payments {
|
||||
web::resource("/confirm-intent")
|
||||
.route(web::post().to(payments::payment_confirm_intent)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/get-intent")
|
||||
.route(web::get().to(payments::payments_get_intent)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/create-external-sdk-tokens")
|
||||
.route(web::post().to(payments::payments_connector_session)),
|
||||
|
||||
@ -139,6 +139,7 @@ impl From<Flow> for ApiIdentifier {
|
||||
| Flow::SessionUpdateTaxCalculation
|
||||
| Flow::PaymentsConfirmIntent
|
||||
| Flow::PaymentsCreateIntent
|
||||
| Flow::PaymentsGetIntent
|
||||
| Flow::PaymentsPostSessionTokens => Self::Payments,
|
||||
|
||||
Flow::PayoutsCreate
|
||||
|
||||
@ -125,11 +125,11 @@ pub async fn payments_create_intent(
|
||||
json_payload.into_inner(),
|
||||
|state, auth: auth::AuthenticationDataV2, req, req_state| {
|
||||
payments::payments_intent_core::<
|
||||
api_types::CreateIntent,
|
||||
payment_types::PaymentsCreateIntentResponse,
|
||||
api_types::PaymentCreateIntent,
|
||||
payment_types::PaymentsIntentResponse,
|
||||
_,
|
||||
_,
|
||||
PaymentIntentData<api_types::CreateIntent>,
|
||||
PaymentIntentData<api_types::PaymentCreateIntent>,
|
||||
>(
|
||||
state,
|
||||
req_state,
|
||||
@ -156,6 +156,57 @@ pub async fn payments_create_intent(
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(feature = "v2")]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::PaymentsGetIntent, payment_id))]
|
||||
pub async fn payments_get_intent(
|
||||
state: web::Data<app::AppState>,
|
||||
req: actix_web::HttpRequest,
|
||||
path: web::Path<common_utils::id_type::GlobalPaymentId>,
|
||||
) -> impl Responder {
|
||||
use api_models::payments::PaymentsGetIntentRequest;
|
||||
use hyperswitch_domain_models::payments::PaymentIntentData;
|
||||
|
||||
let flow = Flow::PaymentsGetIntent;
|
||||
let header_payload = match HeaderPayload::foreign_try_from(req.headers()) {
|
||||
Ok(headers) => headers,
|
||||
Err(err) => {
|
||||
return api::log_and_return_error_response(err);
|
||||
}
|
||||
};
|
||||
|
||||
let payload = PaymentsGetIntentRequest {
|
||||
id: path.into_inner(),
|
||||
};
|
||||
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
payload,
|
||||
|state, auth: auth::AuthenticationDataV2, req, req_state| {
|
||||
payments::payments_intent_core::<
|
||||
api_types::PaymentGetIntent,
|
||||
payment_types::PaymentsIntentResponse,
|
||||
_,
|
||||
_,
|
||||
PaymentIntentData<api_types::PaymentGetIntent>,
|
||||
>(
|
||||
state,
|
||||
req_state,
|
||||
auth.merchant_account,
|
||||
auth.profile,
|
||||
auth.key_store,
|
||||
payments::operations::PaymentGetIntent,
|
||||
req,
|
||||
header_payload.clone(),
|
||||
)
|
||||
},
|
||||
&auth::HeaderAuth(auth::ApiKeyAuth),
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(feature = "v1")]
|
||||
#[instrument(skip(state, req), fields(flow = ?Flow::PaymentsStart, payment_id))]
|
||||
pub async fn payments_start(
|
||||
|
||||
@ -1259,10 +1259,8 @@ impl Authenticate for api_models::payments::PaymentsIncrementalAuthorizationRequ
|
||||
impl Authenticate for api_models::payments::PaymentsStartRequest {}
|
||||
// impl Authenticate for api_models::payments::PaymentsApproveRequest {}
|
||||
impl Authenticate for api_models::payments::PaymentsRejectRequest {}
|
||||
#[cfg(feature = "v2")]
|
||||
impl Authenticate for api_models::payments::PaymentsCreateIntentRequest {}
|
||||
// #[cfg(feature = "v2")]
|
||||
// impl Authenticate for api_models::payments::PaymentsCreateIntentResponse {}
|
||||
// impl Authenticate for api_models::payments::PaymentsIntentResponse {}
|
||||
|
||||
pub fn build_redirection_form(
|
||||
form: &RedirectForm,
|
||||
|
||||
@ -19,13 +19,13 @@ pub use api_models::payments::{
|
||||
VerifyResponse, WalletData,
|
||||
};
|
||||
#[cfg(feature = "v2")]
|
||||
pub use api_models::payments::{PaymentsCreateIntentRequest, PaymentsCreateIntentResponse};
|
||||
pub use api_models::payments::{PaymentsCreateIntentRequest, PaymentsIntentResponse};
|
||||
use error_stack::ResultExt;
|
||||
pub use hyperswitch_domain_models::router_flow_types::payments::{
|
||||
Approve, Authorize, AuthorizeSessionToken, Balance, CalculateTax, Capture, CompleteAuthorize,
|
||||
CreateConnectorCustomer, CreateIntent, IncrementalAuthorization, InitPayment, PSync,
|
||||
PaymentMethodToken, PostProcessing, PostSessionTokens, PreProcessing, Reject, SdkSessionUpdate,
|
||||
Session, SetupMandate, Void,
|
||||
CreateConnectorCustomer, IncrementalAuthorization, InitPayment, PSync, PaymentCreateIntent,
|
||||
PaymentGetIntent, PaymentMethodToken, PostProcessing, PostSessionTokens, PreProcessing, Reject,
|
||||
SdkSessionUpdate, Session, SetupMandate, Void,
|
||||
};
|
||||
pub use hyperswitch_interfaces::api::payments::{
|
||||
ConnectorCustomer, MandateSetup, Payment, PaymentApprove, PaymentAuthorize,
|
||||
|
||||
Reference in New Issue
Block a user