mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-04 14:07:18 +08:00 
			
		
		
		
	feat(router): use payment confirm for confirmed payments in payments create and update (#165)
Co-authored-by: Arun Raj M <jarnura47@gmail.com>
This commit is contained in:
		@ -482,6 +482,7 @@ pub struct CustomerDetails {
 | 
			
		||||
pub fn if_not_create_change_operation<'a, Op, F>(
 | 
			
		||||
    is_update: bool,
 | 
			
		||||
    status: storage_enums::IntentStatus,
 | 
			
		||||
    confirm: Option<bool>,
 | 
			
		||||
    current: &'a Op,
 | 
			
		||||
) -> BoxedOperation<F, api::PaymentsRequest>
 | 
			
		||||
where
 | 
			
		||||
@ -489,17 +490,21 @@ where
 | 
			
		||||
    Op: Operation<F, api::PaymentsRequest> + Send + Sync,
 | 
			
		||||
    &'a Op: Operation<F, api::PaymentsRequest>,
 | 
			
		||||
{
 | 
			
		||||
    match status {
 | 
			
		||||
        storage_enums::IntentStatus::RequiresConfirmation
 | 
			
		||||
        | storage_enums::IntentStatus::RequiresCustomerAction
 | 
			
		||||
        | storage_enums::IntentStatus::RequiresPaymentMethod => {
 | 
			
		||||
            if is_update {
 | 
			
		||||
                Box::new(&PaymentUpdate)
 | 
			
		||||
            } else {
 | 
			
		||||
                Box::new(current)
 | 
			
		||||
    if confirm.unwrap_or(false) {
 | 
			
		||||
        Box::new(PaymentConfirm)
 | 
			
		||||
    } else {
 | 
			
		||||
        match status {
 | 
			
		||||
            storage_enums::IntentStatus::RequiresConfirmation
 | 
			
		||||
            | storage_enums::IntentStatus::RequiresCustomerAction
 | 
			
		||||
            | storage_enums::IntentStatus::RequiresPaymentMethod => {
 | 
			
		||||
                if is_update {
 | 
			
		||||
                    Box::new(&PaymentUpdate)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Box::new(current)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            _ => Box::new(&PaymentStatus),
 | 
			
		||||
        }
 | 
			
		||||
        _ => Box::new(&PaymentStatus),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -257,7 +257,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
 | 
			
		||||
        db: &dyn StorageInterface,
 | 
			
		||||
        _payment_id: &api::PaymentIdType,
 | 
			
		||||
        mut payment_data: PaymentData<F>,
 | 
			
		||||
        _customer: Option<storage::Customer>,
 | 
			
		||||
        customer: Option<storage::Customer>,
 | 
			
		||||
        storage_scheme: enums::MerchantStorageScheme,
 | 
			
		||||
    ) -> RouterResult<(BoxedOperation<'b, F, api::PaymentsRequest>, PaymentData<F>)>
 | 
			
		||||
    where
 | 
			
		||||
@ -285,8 +285,11 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
 | 
			
		||||
            .update_payment_attempt(
 | 
			
		||||
                payment_data.payment_attempt,
 | 
			
		||||
                storage::PaymentAttemptUpdate::ConfirmUpdate {
 | 
			
		||||
                    amount: payment_data.amount.into(),
 | 
			
		||||
                    currency: payment_data.currency,
 | 
			
		||||
                    status: attempt_status,
 | 
			
		||||
                    payment_method,
 | 
			
		||||
                    authentication_type: None,
 | 
			
		||||
                    browser_info,
 | 
			
		||||
                    connector,
 | 
			
		||||
                    payment_token,
 | 
			
		||||
@ -303,11 +306,16 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
 | 
			
		||||
            payment_data.payment_intent.billing_address_id.clone(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let customer_id = customer.map(|c| c.customer_id);
 | 
			
		||||
 | 
			
		||||
        payment_data.payment_intent = db
 | 
			
		||||
            .update_payment_intent(
 | 
			
		||||
                payment_data.payment_intent,
 | 
			
		||||
                storage::PaymentIntentUpdate::MerchantStatusUpdate {
 | 
			
		||||
                storage::PaymentIntentUpdate::Update {
 | 
			
		||||
                    amount: payment_data.amount.into(),
 | 
			
		||||
                    currency: payment_data.currency,
 | 
			
		||||
                    status: intent_status,
 | 
			
		||||
                    customer_id,
 | 
			
		||||
                    shipping_address_id: shipping_address,
 | 
			
		||||
                    billing_address_id: billing_address,
 | 
			
		||||
                },
 | 
			
		||||
 | 
			
		||||
@ -185,6 +185,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
 | 
			
		||||
        let operation = payments::if_not_create_change_operation::<_, F>(
 | 
			
		||||
            is_update,
 | 
			
		||||
            payment_intent.status,
 | 
			
		||||
            request.confirm,
 | 
			
		||||
            self,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
@ -280,10 +281,10 @@ impl<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentCreate {
 | 
			
		||||
    #[instrument(skip_all)]
 | 
			
		||||
    async fn add_task_to_process_tracker<'a>(
 | 
			
		||||
        &'a self,
 | 
			
		||||
        state: &'a AppState,
 | 
			
		||||
        payment_attempt: &storage::PaymentAttempt,
 | 
			
		||||
        _state: &'a AppState,
 | 
			
		||||
        _payment_attempt: &storage::PaymentAttempt,
 | 
			
		||||
    ) -> CustomResult<(), errors::ApiErrorResponse> {
 | 
			
		||||
        helpers::add_domain_task_to_pt(self, state, payment_attempt).await
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn get_connector<'a>(
 | 
			
		||||
@ -388,6 +389,13 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentCreate
 | 
			
		||||
            None => None,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if let Some(true) = request.confirm {
 | 
			
		||||
            helpers::validate_pm_or_token_given(
 | 
			
		||||
                &request.payment_token,
 | 
			
		||||
                &request.payment_method_data,
 | 
			
		||||
            )?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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)?;
 | 
			
		||||
 | 
			
		||||
@ -126,6 +126,13 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
 | 
			
		||||
                    .attach_printable("Database error when finding connector response")
 | 
			
		||||
            })?;
 | 
			
		||||
 | 
			
		||||
        let next_operation: BoxedOperation<'a, F, api::PaymentsRequest> =
 | 
			
		||||
            if request.confirm.unwrap_or(false) {
 | 
			
		||||
                Box::new(operations::PaymentConfirm)
 | 
			
		||||
            } else {
 | 
			
		||||
                Box::new(self)
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        match payment_intent.status {
 | 
			
		||||
            enums::IntentStatus::Succeeded | enums::IntentStatus::Failed => {
 | 
			
		||||
                Err(report!(errors::ApiErrorResponse::PreconditionFailed {
 | 
			
		||||
@ -135,7 +142,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
 | 
			
		||||
                }))
 | 
			
		||||
            }
 | 
			
		||||
            _ => Ok((
 | 
			
		||||
                Box::new(self),
 | 
			
		||||
                next_operation,
 | 
			
		||||
                PaymentData {
 | 
			
		||||
                    flow: PhantomData,
 | 
			
		||||
                    payment_intent,
 | 
			
		||||
@ -227,10 +234,10 @@ impl<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentUpdate {
 | 
			
		||||
    #[instrument(skip_all)]
 | 
			
		||||
    async fn add_task_to_process_tracker<'a>(
 | 
			
		||||
        &'a self,
 | 
			
		||||
        state: &'a AppState,
 | 
			
		||||
        payment_attempt: &storage::PaymentAttempt,
 | 
			
		||||
        _state: &'a AppState,
 | 
			
		||||
        _payment_attempt: &storage::PaymentAttempt,
 | 
			
		||||
    ) -> CustomResult<(), errors::ApiErrorResponse> {
 | 
			
		||||
        helpers::add_domain_task_to_pt(self, state, payment_attempt).await
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn get_connector<'a>(
 | 
			
		||||
@ -352,6 +359,13 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentUpdate
 | 
			
		||||
            None => None,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if let Some(true) = request.confirm {
 | 
			
		||||
            helpers::validate_pm_or_token_given(
 | 
			
		||||
                &request.payment_token,
 | 
			
		||||
                &request.payment_method_data,
 | 
			
		||||
            )?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let request_merchant_id = request.merchant_id.as_deref();
 | 
			
		||||
        helpers::validate_merchant_id(&merchant_account.merchant_id, request_merchant_id)
 | 
			
		||||
            .change_context(errors::ApiErrorResponse::InvalidDataFormat {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user