From 1d23e28a17de29aadaf7a5e10062f2e863656e86 Mon Sep 17 00:00:00 2001 From: AdityaWNL <113281443+AdityaKumaar21@users.noreply.github.com> Date: Thu, 18 Sep 2025 20:18:01 +0530 Subject: [PATCH] feat(revenue_recovery): Implement redis API to update the lock status for connector customer id (#9403) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- .../src/revenue_recovery_data_backfill.rs | 11 +++++++ .../core/revenue_recovery_data_backfill.rs | 29 ++++++++++++++++++- crates/router/src/routes/app.rs | 5 ++++ .../routes/revenue_recovery_data_backfill.rs | 25 +++++++++++++++- 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/crates/api_models/src/revenue_recovery_data_backfill.rs b/crates/api_models/src/revenue_recovery_data_backfill.rs index d73ae8a33c..34c64b7554 100644 --- a/crates/api_models/src/revenue_recovery_data_backfill.rs +++ b/crates/api_models/src/revenue_recovery_data_backfill.rs @@ -23,6 +23,11 @@ pub struct RevenueRecoveryBackfillRequest { pub daily_retry_history: Option, } +#[derive(Debug, Serialize)] +pub struct UnlockStatusResponse { + pub unlocked: bool, +} + #[derive(Debug, Serialize)] pub struct RevenueRecoveryDataBackfillResponse { pub processed_records: usize, @@ -59,6 +64,12 @@ impl ApiEventMetric for RevenueRecoveryDataBackfillResponse { } } +impl ApiEventMetric for UnlockStatusResponse { + fn get_api_event_type(&self) -> Option { + Some(common_utils::events::ApiEventsType::Miscellaneous) + } +} + impl ApiEventMetric for CsvParsingResult { fn get_api_event_type(&self) -> Option { Some(common_utils::events::ApiEventsType::Miscellaneous) diff --git a/crates/router/src/core/revenue_recovery_data_backfill.rs b/crates/router/src/core/revenue_recovery_data_backfill.rs index 4f32a91484..629b9e6a58 100644 --- a/crates/router/src/core/revenue_recovery_data_backfill.rs +++ b/crates/router/src/core/revenue_recovery_data_backfill.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use api_models::revenue_recovery_data_backfill::{ BackfillError, ComprehensiveCardData, RevenueRecoveryBackfillRequest, - RevenueRecoveryDataBackfillResponse, + RevenueRecoveryDataBackfillResponse, UnlockStatusResponse, }; use common_enums::{CardNetwork, PaymentMethodType}; use hyperswitch_domain_models::api::ApplicationResponse; @@ -60,6 +60,33 @@ pub async fn revenue_recovery_data_backfill( Ok(ApplicationResponse::Json(response)) } +pub async fn unlock_connector_customer_status( + state: SessionState, + connector_customer_id: String, +) -> RouterResult> { + let unlocked = storage::revenue_recovery_redis_operation:: + RedisTokenManager::unlock_connector_customer_status(&state, &connector_customer_id) + .await + .map_err(|e| { + logger::error!( + "Failed to unlock connector customer status for {}: {}", + connector_customer_id, + e + ); + errors::ApiErrorResponse::InternalServerError + })?; + + let response = UnlockStatusResponse { unlocked }; + + logger::info!( + "Unlock operation completed for connector customer {}: {}", + connector_customer_id, + unlocked + ); + + Ok(ApplicationResponse::Json(response)) +} + async fn process_payment_method_record( state: &SessionState, record: &RevenueRecoveryBackfillRequest, diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 11d90e66f1..8572f3cfa3 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -3002,5 +3002,10 @@ impl RecoveryDataBackfill { .to(super::revenue_recovery_data_backfill::revenue_recovery_data_backfill), ), ) + .service(web::resource("/status/{token_id}").route( + web::post().to( + super::revenue_recovery_data_backfill::revenue_recovery_data_backfill_status, + ), + )) } } diff --git a/crates/router/src/routes/revenue_recovery_data_backfill.rs b/crates/router/src/routes/revenue_recovery_data_backfill.rs index 340d9a084b..4203f52dff 100644 --- a/crates/router/src/routes/revenue_recovery_data_backfill.rs +++ b/crates/router/src/routes/revenue_recovery_data_backfill.rs @@ -7,7 +7,7 @@ use crate::{ core::{api_locking, revenue_recovery_data_backfill}, routes::AppState, services::{api, authentication as auth}, - types::domain, + types::{domain, storage}, }; #[instrument(skip_all, fields(flow = ?Flow::RecoveryDataBackfill))] @@ -65,3 +65,26 @@ pub async fn revenue_recovery_data_backfill( )) .await } + +#[instrument(skip_all, fields(flow = ?Flow::RecoveryDataBackfill))] +pub async fn revenue_recovery_data_backfill_status( + state: web::Data, + req: HttpRequest, + path: web::Path, +) -> HttpResponse { + let flow = Flow::RecoveryDataBackfill; + let connector_customer_id = path.into_inner(); + + Box::pin(api::server_wrap( + flow, + state, + &req, + connector_customer_id, + |state, _: (), id, _| { + revenue_recovery_data_backfill::unlock_connector_customer_status(state, id) + }, + &auth::V2AdminApiAuth, + api_locking::LockAction::NotApplicable, + )) + .await +}