mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-03 05:17:02 +08:00
feat(routes): add the validation API in payments route (#61)
This commit is contained in:
@ -10,8 +10,8 @@ use router_env::{tracing, tracing::instrument};
|
||||
use time;
|
||||
|
||||
pub use self::operations::{
|
||||
PaymentCancel, PaymentCapture, PaymentConfirm, PaymentCreate, PaymentResponse, PaymentSession,
|
||||
PaymentStatus, PaymentUpdate,
|
||||
PaymentCancel, PaymentCapture, PaymentConfirm, PaymentCreate, PaymentMethodValidate,
|
||||
PaymentResponse, PaymentStatus, PaymentUpdate,
|
||||
};
|
||||
use self::{
|
||||
flows::{ConstructFlowSpecificData, Feature},
|
||||
@ -23,7 +23,6 @@ use crate::{
|
||||
core::{
|
||||
errors::{self, RouterResponse, RouterResult},
|
||||
payments,
|
||||
payments::transformers as payments_transformers,
|
||||
},
|
||||
db::StorageInterface,
|
||||
pii::Email,
|
||||
@ -136,18 +135,19 @@ where
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[instrument(skip_all)]
|
||||
pub async fn payments_core<F, Req, Op, FData>(
|
||||
pub async fn payments_core<F, Res, Req, Op, FData>(
|
||||
state: &AppState,
|
||||
merchant_account: storage::MerchantAccount,
|
||||
operation: Op,
|
||||
req: Req,
|
||||
auth_flow: services::AuthFlow,
|
||||
call_connector_action: CallConnectorAction,
|
||||
) -> RouterResponse<api::PaymentsResponse>
|
||||
) -> RouterResponse<Res>
|
||||
where
|
||||
F: Send + Clone,
|
||||
Op: Operation<F, Req> + Send + Sync + Clone,
|
||||
Req: Debug,
|
||||
Res: transformers::ToResponse<Req, PaymentData<F>, Op> + From<Req>,
|
||||
|
||||
// To create connector flow specific interface data
|
||||
PaymentData<F>: ConstructFlowSpecificData<F, FData, types::PaymentsResponseData>,
|
||||
@ -159,9 +159,7 @@ where
|
||||
|
||||
// To perform router related operation for PaymentResponse
|
||||
PaymentResponse: Operation<F, FData>,
|
||||
|
||||
// To create merchant response
|
||||
api::PaymentsResponse: From<Req>,
|
||||
{
|
||||
let (payment_data, req, customer) = payments_operation_core(
|
||||
state,
|
||||
@ -171,19 +169,12 @@ where
|
||||
call_connector_action,
|
||||
)
|
||||
.await?;
|
||||
|
||||
payments_transformers::payments_to_payments_response(
|
||||
Res::generate_response(
|
||||
Some(req),
|
||||
payment_data.payment_attempt,
|
||||
payment_data.payment_intent,
|
||||
payment_data.refunds,
|
||||
payment_data.mandate_id,
|
||||
payment_data.payment_method_data,
|
||||
payment_data,
|
||||
customer,
|
||||
auth_flow,
|
||||
payment_data.address,
|
||||
&state.conf.server,
|
||||
payment_data.connector_response.authentication_data,
|
||||
operation,
|
||||
)
|
||||
}
|
||||
@ -253,7 +244,7 @@ pub async fn payments_response_for_redirection_flows<'a>(
|
||||
req: PaymentsRetrieveRequest,
|
||||
flow_type: CallConnectorAction,
|
||||
) -> RouterResponse<PaymentsResponse> {
|
||||
payments_core::<api::PSync, _, _, _>(
|
||||
payments_core::<api::PSync, api::PaymentsResponse, _, _, _>(
|
||||
state,
|
||||
merchant_account,
|
||||
payments::PaymentStatus,
|
||||
|
||||
@ -14,6 +14,7 @@ pub use payment_cancel::PaymentCancel;
|
||||
pub use payment_capture::PaymentCapture;
|
||||
pub use payment_confirm::PaymentConfirm;
|
||||
pub use payment_create::PaymentCreate;
|
||||
pub use payment_method_validate::PaymentMethodValidate;
|
||||
pub use payment_response::PaymentResponse;
|
||||
pub use payment_session::PaymentSession;
|
||||
pub use payment_start::PaymentStart;
|
||||
|
||||
@ -40,7 +40,7 @@ impl<F: Send + Clone> ValidateRequest<F, api::VerifyRequest> for PaymentMethodVa
|
||||
api::PaymentIdType,
|
||||
Option<api::MandateTxnType>,
|
||||
)> {
|
||||
let request_merchant_id = Some(&request.merchant_id[..]);
|
||||
let request_merchant_id = request.merchant_id.as_deref();
|
||||
helpers::validate_merchant_id(&merchant_account.merchant_id, request_merchant_id)
|
||||
.change_context(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ use crate::{
|
||||
#[derive(Debug, Clone, Copy, router_derive::PaymentOperation)]
|
||||
#[operation(
|
||||
ops = "post_tracker",
|
||||
flow = "syncdata,authorizedata,canceldata,capturedata"
|
||||
flow = "syncdata,authorizedata,canceldata,capturedata,verifydata"
|
||||
)]
|
||||
pub struct PaymentResponse;
|
||||
|
||||
@ -104,6 +104,24 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsCancelData> f
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::VerifyRequestData> for PaymentResponse {
|
||||
async fn update_tracker<'b>(
|
||||
&'b self,
|
||||
db: &dyn StorageInterface,
|
||||
payment_id: &api::PaymentIdType,
|
||||
payment_data: PaymentData<F>,
|
||||
response: Option<
|
||||
types::RouterData<F, types::VerifyRequestData, types::PaymentsResponseData>,
|
||||
>,
|
||||
) -> RouterResult<PaymentData<F>>
|
||||
where
|
||||
F: 'b + Send,
|
||||
{
|
||||
Ok(payment_response_ut(db, payment_id, payment_data, response).await?)
|
||||
}
|
||||
}
|
||||
|
||||
async fn payment_response_ut<F: Clone, T>(
|
||||
db: &dyn StorageInterface,
|
||||
_payment_id: &api::PaymentIdType,
|
||||
|
||||
@ -103,6 +103,92 @@ where
|
||||
Ok((payment_data, router_data))
|
||||
}
|
||||
|
||||
pub trait ToResponse<Req, D, Op>
|
||||
where
|
||||
Self: From<Req>,
|
||||
Op: Debug,
|
||||
{
|
||||
fn generate_response(
|
||||
req: Option<Req>,
|
||||
data: D,
|
||||
customer: Option<storage::Customer>,
|
||||
auth_flow: services::AuthFlow,
|
||||
server: &Server,
|
||||
operation: Op,
|
||||
) -> RouterResponse<Self>;
|
||||
}
|
||||
|
||||
impl<F, Req, Op> ToResponse<Req, PaymentData<F>, Op> for api::PaymentsResponse
|
||||
where
|
||||
Self: From<Req>,
|
||||
F: Clone,
|
||||
Op: Debug,
|
||||
{
|
||||
fn generate_response(
|
||||
req: Option<Req>,
|
||||
payment_data: PaymentData<F>,
|
||||
customer: Option<storage::Customer>,
|
||||
auth_flow: services::AuthFlow,
|
||||
server: &Server,
|
||||
operation: Op,
|
||||
) -> RouterResponse<Self> {
|
||||
payments_to_payments_response(
|
||||
req,
|
||||
payment_data.payment_attempt,
|
||||
payment_data.payment_intent,
|
||||
payment_data.refunds,
|
||||
payment_data.mandate_id,
|
||||
payment_data.payment_method_data,
|
||||
customer,
|
||||
auth_flow,
|
||||
payment_data.address,
|
||||
server,
|
||||
payment_data.connector_response.authentication_data,
|
||||
operation,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req, Op> ToResponse<Req, PaymentData<F>, Op> for api::VerifyResponse
|
||||
where
|
||||
Self: From<Req>,
|
||||
F: Clone,
|
||||
Op: Debug,
|
||||
{
|
||||
fn generate_response(
|
||||
_req: Option<Req>,
|
||||
data: PaymentData<F>,
|
||||
customer: Option<storage::Customer>,
|
||||
_auth_flow: services::AuthFlow,
|
||||
_server: &Server,
|
||||
_operation: Op,
|
||||
) -> RouterResponse<Self> {
|
||||
Ok(services::BachResponse::Json(Self {
|
||||
verify_id: Some(data.payment_intent.payment_id),
|
||||
merchant_id: Some(data.payment_intent.merchant_id),
|
||||
client_secret: data.payment_intent.client_secret.map(masking::Secret::new),
|
||||
customer_id: customer.as_ref().map(|x| x.customer_id.clone()),
|
||||
email: customer
|
||||
.as_ref()
|
||||
.and_then(|cus| cus.email.as_ref().map(|s| s.to_owned())),
|
||||
name: customer
|
||||
.as_ref()
|
||||
.and_then(|cus| cus.name.as_ref().map(|s| s.to_owned().into())),
|
||||
phone: customer
|
||||
.as_ref()
|
||||
.and_then(|cus| cus.phone.as_ref().map(|s| s.to_owned())),
|
||||
mandate_id: data.mandate_id,
|
||||
payment_method: data.payment_attempt.payment_method,
|
||||
payment_method_data: data
|
||||
.payment_method_data
|
||||
.map(api::PaymentMethodDataResponse::from),
|
||||
payment_token: data.token,
|
||||
error_code: None,
|
||||
error_message: data.payment_attempt.error_message,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
// try to use router data here so that already validated things , we don't want to repeat the validations.
|
||||
// Add internal value not found and external value not found so that we can give 500 / Internal server error for internal value not found
|
||||
@ -130,7 +216,6 @@ where
|
||||
.as_ref()
|
||||
.get_required_value("currency")?
|
||||
.to_string();
|
||||
|
||||
let refunds_response = if refunds.is_empty() {
|
||||
None
|
||||
} else {
|
||||
|
||||
@ -37,7 +37,7 @@ async fn payments_incoming_webhook_flow(
|
||||
payments::CallConnectorAction::Trigger
|
||||
};
|
||||
|
||||
let payments_response = payments::payments_core::<api::PSync, _, _, _>(
|
||||
let payments_response = payments::payments_core::<api::PSync, api::PaymentsResponse, _, _, _>(
|
||||
&state,
|
||||
merchant_account.clone(),
|
||||
payments::operations::PaymentStatus,
|
||||
|
||||
Reference in New Issue
Block a user