diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 56247bfad64c..09190afe5e5b 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -3471,15 +3471,10 @@ pub enum ErrorCategory { } impl ErrorCategory { - pub fn should_perform_elimination_routing( - self, - ) -> bool { + pub fn should_perform_elimination_routing(self) -> bool { match self { - Self::FrmDecline | - Self::ProcessorDowntime | - Self::ProcessorDeclineUnauthorized => true, - Self::IssueWithPaymentMethod | - Self::ProcessorDeclineIncorrectData => false, + Self::FrmDecline | Self::ProcessorDowntime | Self::ProcessorDeclineUnauthorized => true, + Self::IssueWithPaymentMethod | Self::ProcessorDeclineIncorrectData => false, } } } diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 90f8fb86fedc..a62db3cae6ff 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1311,7 +1311,10 @@ async fn payment_response_update_tracker( .as_mut() .map(|info| info.status = status) }); - let (capture_update, mut payment_attempt_update, gsm_error_category) = match router_data.response.clone() { + let (capture_update, mut payment_attempt_update, gsm_error_category) = match router_data + .response + .clone() + { Err(err) => { let auth_update = if Some(router_data.auth_type) != payment_data.payment_attempt.authentication_type @@ -1320,122 +1323,124 @@ async fn payment_response_update_tracker( } else { None }; - let (capture_update, attempt_update, gsm_error_category) = match payment_data.multiple_capture_data { - Some(multiple_capture_data) => { - let capture_update = storage::CaptureUpdate::ErrorUpdate { - status: match err.status_code { - 500..=511 => enums::CaptureStatus::Pending, - _ => enums::CaptureStatus::Failed, - }, - error_code: Some(err.code), - error_message: Some(err.message), - error_reason: err.reason, - }; - let capture_update_list = vec![( - multiple_capture_data.get_latest_capture().clone(), - capture_update, - )]; - ( - Some((multiple_capture_data, capture_update_list)), - auth_update.map(|auth_type| { - storage::PaymentAttemptUpdate::AuthenticationTypeUpdate { - authentication_type: auth_type, - updated_by: storage_scheme.to_string(), - } - }), - None, - ) - } - None => { - let connector_name = router_data.connector.to_string(); - let flow_name = core_utils::get_flow_name::()?; - let option_gsm = payments_helpers::get_gsm_record( - state, - Some(err.code.clone()), - Some(err.message.clone()), - connector_name, - flow_name.clone(), - ) - .await; - - let gsm_unified_code = - option_gsm.as_ref().and_then(|gsm| gsm.unified_code.clone()); - let gsm_unified_message = option_gsm.clone().and_then(|gsm| gsm.unified_message); - - let (unified_code, unified_message) = if let Some((code, message)) = - gsm_unified_code.as_ref().zip(gsm_unified_message.as_ref()) - { - (code.to_owned(), message.to_owned()) - } else { + let (capture_update, attempt_update, gsm_error_category) = + match payment_data.multiple_capture_data { + Some(multiple_capture_data) => { + let capture_update = storage::CaptureUpdate::ErrorUpdate { + status: match err.status_code { + 500..=511 => enums::CaptureStatus::Pending, + _ => enums::CaptureStatus::Failed, + }, + error_code: Some(err.code), + error_message: Some(err.message), + error_reason: err.reason, + }; + let capture_update_list = vec![( + multiple_capture_data.get_latest_capture().clone(), + capture_update, + )]; ( - consts::DEFAULT_UNIFIED_ERROR_CODE.to_owned(), - consts::DEFAULT_UNIFIED_ERROR_MESSAGE.to_owned(), + Some((multiple_capture_data, capture_update_list)), + auth_update.map(|auth_type| { + storage::PaymentAttemptUpdate::AuthenticationTypeUpdate { + authentication_type: auth_type, + updated_by: storage_scheme.to_string(), + } + }), + None, ) - }; - let unified_translated_message = locale - .as_ref() - .async_and_then(|locale_str| async { - payments_helpers::get_unified_translation( - state, - unified_code.to_owned(), - unified_message.to_owned(), - locale_str.to_owned(), + } + None => { + let connector_name = router_data.connector.to_string(); + let flow_name = core_utils::get_flow_name::()?; + let option_gsm = payments_helpers::get_gsm_record( + state, + Some(err.code.clone()), + Some(err.message.clone()), + connector_name, + flow_name.clone(), + ) + .await; + + let gsm_unified_code = + option_gsm.as_ref().and_then(|gsm| gsm.unified_code.clone()); + let gsm_unified_message = + option_gsm.clone().and_then(|gsm| gsm.unified_message); + + let (unified_code, unified_message) = if let Some((code, message)) = + gsm_unified_code.as_ref().zip(gsm_unified_message.as_ref()) + { + (code.to_owned(), message.to_owned()) + } else { + ( + consts::DEFAULT_UNIFIED_ERROR_CODE.to_owned(), + consts::DEFAULT_UNIFIED_ERROR_MESSAGE.to_owned(), ) + }; + let unified_translated_message = locale + .as_ref() + .async_and_then(|locale_str| async { + payments_helpers::get_unified_translation( + state, + unified_code.to_owned(), + unified_message.to_owned(), + locale_str.to_owned(), + ) + .await + }) .await - }) - .await - .or(Some(unified_message)); + .or(Some(unified_message)); - let status = match err.attempt_status { - // Use the status sent by connector in error_response if it's present - Some(status) => status, - None => - // mark previous attempt status for technical failures in PSync flow - { - if flow_name == "PSync" { - match err.status_code { - // marking failure for 2xx because this is genuine payment failure - 200..=299 => enums::AttemptStatus::Failure, - _ => router_data.status, - } - } else if flow_name == "Capture" { - match err.status_code { - 500..=511 => enums::AttemptStatus::Pending, - // don't update the status for 429 error status - 429 => router_data.status, - _ => enums::AttemptStatus::Failure, - } - } else { - match err.status_code { - 500..=511 => enums::AttemptStatus::Pending, - _ => enums::AttemptStatus::Failure, + let status = match err.attempt_status { + // Use the status sent by connector in error_response if it's present + Some(status) => status, + None => + // mark previous attempt status for technical failures in PSync flow + { + if flow_name == "PSync" { + match err.status_code { + // marking failure for 2xx because this is genuine payment failure + 200..=299 => enums::AttemptStatus::Failure, + _ => router_data.status, + } + } else if flow_name == "Capture" { + match err.status_code { + 500..=511 => enums::AttemptStatus::Pending, + // don't update the status for 429 error status + 429 => router_data.status, + _ => enums::AttemptStatus::Failure, + } + } else { + match err.status_code { + 500..=511 => enums::AttemptStatus::Pending, + _ => enums::AttemptStatus::Failure, + } } } - } - }; - ( - None, - Some(storage::PaymentAttemptUpdate::ErrorUpdate { - connector: None, - status, - error_message: Some(Some(err.message)), - error_code: Some(Some(err.code)), - error_reason: Some(err.reason), - amount_capturable: router_data - .request - .get_amount_capturable(&payment_data, status) - .map(MinorUnit::new), - updated_by: storage_scheme.to_string(), - unified_code: Some(Some(unified_code)), - unified_message: Some(unified_translated_message), - connector_transaction_id: err.connector_transaction_id, - payment_method_data: additional_payment_method_data, - authentication_type: auth_update, - }), - option_gsm.and_then(|option_gsm| option_gsm.error_category) - ) - } - }; + }; + ( + None, + Some(storage::PaymentAttemptUpdate::ErrorUpdate { + connector: None, + status, + error_message: Some(Some(err.message)), + error_code: Some(Some(err.code)), + error_reason: Some(err.reason), + amount_capturable: router_data + .request + .get_amount_capturable(&payment_data, status) + .map(MinorUnit::new), + updated_by: storage_scheme.to_string(), + unified_code: Some(Some(unified_code)), + unified_message: Some(unified_translated_message), + connector_transaction_id: err.connector_transaction_id, + payment_method_data: additional_payment_method_data, + authentication_type: auth_update, + }), + option_gsm.and_then(|option_gsm| option_gsm.error_category), + ) + } + }; (capture_update, attempt_update, gsm_error_category) } @@ -1768,23 +1773,31 @@ async fn payment_response_update_tracker( connector_response_reference_id, updated_by: storage_scheme.to_string(), }), - None + None, ) } types::PaymentsResponseData::SessionResponse { .. } => (None, None, None), - types::PaymentsResponseData::SessionTokenResponse { .. } => (None, None, None), - types::PaymentsResponseData::TokenizationResponse { .. } => (None, None, None), + types::PaymentsResponseData::SessionTokenResponse { .. } => { + (None, None, None) + } + types::PaymentsResponseData::TokenizationResponse { .. } => { + (None, None, None) + } types::PaymentsResponseData::ConnectorCustomerResponse { .. } => { (None, None, None) } types::PaymentsResponseData::ThreeDSEnrollmentResponse { .. } => { (None, None, None) } - types::PaymentsResponseData::PostProcessingResponse { .. } => (None, None, None), + types::PaymentsResponseData::PostProcessingResponse { .. } => { + (None, None, None) + } types::PaymentsResponseData::IncrementalAuthorizationResponse { .. } => (None, None, None), - types::PaymentsResponseData::SessionUpdateResponse { .. } => (None, None, None), + types::PaymentsResponseData::SessionUpdateResponse { .. } => { + (None, None, None) + } types::PaymentsResponseData::MultipleCaptureResponse { capture_sync_response_list, } => match payment_data.multiple_capture_data { @@ -1793,7 +1806,11 @@ async fn payment_response_update_tracker( &multiple_capture_data, capture_sync_response_list, )?; - (Some((multiple_capture_data, capture_update_list)), None, None) + ( + Some((multiple_capture_data, capture_update_list)), + None, + None, + ) } None => (None, None, None), }, @@ -2040,7 +2057,8 @@ async fn payment_response_update_tracker( .algorithm_id_with_timestamp .algorithm_id .is_some() - }) && gsm_error_category.should_perform_elimination_routing() + }) + && gsm_error_category.should_perform_elimination_routing() { routing_helpers::update_window_for_elimination_routing( &state, diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 17d4e6203e64..7c3532d4ad30 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -768,7 +768,8 @@ pub async fn update_window_for_elimination_routing( business_profile, elimination_algo_ref .algorithm_id_with_timestamp - .algorithm_id.clone() + .algorithm_id + .clone() .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable( "success_based_routing_algorithm_id not found in business_profile", @@ -814,28 +815,28 @@ pub async fn update_window_for_elimination_routing( ); client - .update_elimination_bucket_config( - tenant_business_profile_id, - elimination_routing_config_params, - vec![routing_types::RoutableConnectorChoiceWithBucketName::new( - routing_types::RoutableConnectorChoice { - choice_kind: api_models::routing::RoutableChoiceKind::FullStruct, - connector: common_enums::RoutableConnectors::from_str( - payment_connector.as_str(), - ) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to infer routable_connector from connector")?, - merchant_connector_id: payment_attempt.merchant_connector_id.clone(), - }, - gsm_error_category.to_string(), - )], - elimination_routing_config.elimination_analyser_config, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable( - "unable to update success based routing window in dynamic routing service", - )?; + .update_elimination_bucket_config( + tenant_business_profile_id, + elimination_routing_config_params, + vec![routing_types::RoutableConnectorChoiceWithBucketName::new( + routing_types::RoutableConnectorChoice { + choice_kind: api_models::routing::RoutableChoiceKind::FullStruct, + connector: common_enums::RoutableConnectors::from_str( + payment_connector.as_str(), + ) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unable to infer routable_connector from connector")?, + merchant_connector_id: payment_attempt.merchant_connector_id.clone(), + }, + gsm_error_category.to_string(), + )], + elimination_routing_config.elimination_analyser_config, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "unable to update success based routing window in dynamic routing service", + )?; Ok(()) } else { Ok(())