From d372eef4ddc08f1feb1453f95dbd06bd469603e4 Mon Sep 17 00:00:00 2001 From: sai-harsha-vardhan Date: Mon, 24 Jun 2024 14:05:30 +0530 Subject: [PATCH] add refunds manual update api --- crates/api_models/src/events/refund.rs | 14 ++++++- crates/api_models/src/refunds.rs | 26 +++++++++++++ crates/diesel_models/src/refund.rs | 18 +++++++++ crates/router/src/core/refunds.rs | 54 ++++++++++++++++++++++++++ crates/router/src/routes/app.rs | 6 ++- crates/router/src/routes/lock_utils.rs | 3 +- crates/router/src/routes/refunds.rs | 23 +++++++++++ crates/router_env/src/logger/types.rs | 2 + 8 files changed, 142 insertions(+), 4 deletions(-) diff --git a/crates/api_models/src/events/refund.rs b/crates/api_models/src/events/refund.rs index 7ab10a23b71..0717b66c6bf 100644 --- a/crates/api_models/src/events/refund.rs +++ b/crates/api_models/src/events/refund.rs @@ -1,8 +1,9 @@ use common_utils::events::{ApiEventMetric, ApiEventsType}; use crate::refunds::{ - RefundListFilters, RefundListMetaData, RefundListRequest, RefundListResponse, RefundRequest, - RefundResponse, RefundUpdateRequest, RefundsRetrieveRequest, + RefundListFilters, RefundListMetaData, RefundListRequest, RefundListResponse, + RefundManualUpdateRequest, RefundRequest, RefundResponse, RefundUpdateRequest, + RefundsRetrieveRequest, }; impl ApiEventMetric for RefundRequest { @@ -44,6 +45,15 @@ impl ApiEventMetric for RefundUpdateRequest { } } +impl ApiEventMetric for RefundManualUpdateRequest { + fn get_api_event_type(&self) -> Option { + Some(ApiEventsType::Refund { + payment_id: None, + refund_id: self.refund_id.clone(), + }) + } +} + impl ApiEventMetric for RefundListRequest { fn get_api_event_type(&self) -> Option { Some(ApiEventsType::ResourceListAPI) diff --git a/crates/api_models/src/refunds.rs b/crates/api_models/src/refunds.rs index c97344ff48b..b7fd212057c 100644 --- a/crates/api_models/src/refunds.rs +++ b/crates/api_models/src/refunds.rs @@ -97,6 +97,21 @@ pub struct RefundUpdateRequest { pub metadata: Option, } +#[derive(Default, Debug, ToSchema, Clone, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct RefundManualUpdateRequest { + #[serde(skip)] + pub refund_id: String, + /// Merchant ID + pub merchant_id: String, + /// The status for refund + pub status: Option, + /// The code for the error + pub error_code: Option, + /// The error message + pub error_message: Option, +} + /// To indicate whether to refund needs to be instant or scheduled #[derive( Default, Debug, Clone, Copy, ToSchema, Deserialize, Serialize, Eq, PartialEq, strum::Display, @@ -244,3 +259,14 @@ impl From for RefundStatus { } } } + +impl From for enums::RefundStatus { + fn from(status: RefundStatus) -> Self { + match status { + RefundStatus::Failed => Self::Failure, + RefundStatus::Review => Self::ManualReview, + RefundStatus::Pending => Self::Pending, + RefundStatus::Succeeded => Self::Success, + } + } +} diff --git a/crates/diesel_models/src/refund.rs b/crates/diesel_models/src/refund.rs index 7d5b20c3d0c..9f66d90e01d 100644 --- a/crates/diesel_models/src/refund.rs +++ b/crates/diesel_models/src/refund.rs @@ -115,6 +115,12 @@ pub enum RefundUpdate { refund_error_code: Option, updated_by: String, }, + ManualUpdate { + refund_status: Option, + refund_error_message: Option, + refund_error_code: Option, + updated_by: String, + }, } #[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)] @@ -201,6 +207,18 @@ impl From for RefundUpdateInternal { updated_by, ..Default::default() }, + RefundUpdate::ManualUpdate { + refund_status, + refund_error_message, + refund_error_code, + updated_by, + } => Self { + refund_status, + refund_error_message, + refund_error_code, + updated_by, + ..Default::default() + }, } } } diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index 9fac4e595a0..a7a23f760fa 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -838,6 +838,60 @@ pub async fn refund_filter_list( Ok(services::ApplicationResponse::Json(filter_list)) } +#[instrument(skip_all)] +#[cfg(feature = "olap")] +pub async fn refund_manual_update( + state: SessionState, + req: api_models::refunds::RefundManualUpdateRequest, +) -> RouterResponse { + let key_store = state + .store + .get_merchant_key_store_by_merchant_id( + &req.merchant_id, + &state.store.get_master_key().to_vec().into(), + ) + .await + .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound) + .attach_printable("Error while fetching the key store by merchant_id")?; + let merchant_account = state + .store + .find_merchant_account_by_merchant_id(&req.merchant_id, &key_store) + .await + .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound) + .attach_printable("Error while fetching the merchant_account by merchant_id")?; + let refund = state + .store + .find_refund_by_merchant_id_refund_id( + &merchant_account.merchant_id, + &req.refund_id, + merchant_account.storage_scheme, + ) + .await + .to_not_found_response(errors::ApiErrorResponse::RefundNotFound)?; + let refund_update = storage::RefundUpdate::ManualUpdate { + refund_status: req.status.map(common_enums::RefundStatus::from), + refund_error_message: req.error_message, + refund_error_code: req.error_code, + updated_by: merchant_account.storage_scheme.to_string(), + }; + state + .store + .update_refund( + refund.to_owned(), + refund_update, + merchant_account.storage_scheme, + ) + .await + .to_not_found_response(errors::ApiErrorResponse::InternalServerError) + .attach_printable_lazy(|| { + format!( + "Failed while updating refund: refund_id: {}", + refund.refund_id + ) + })?; + Ok(services::ApplicationResponse::StatusOk) +} + #[instrument(skip_all)] #[cfg(feature = "olap")] pub async fn get_filters_for_refunds( diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 2e7a6c4f61e..5bd6c507691 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -845,7 +845,11 @@ impl Refunds { route = route .service(web::resource("/list").route(web::post().to(refunds_list))) .service(web::resource("/filter").route(web::post().to(refunds_filter_list))) - .service(web::resource("/v2/filter").route(web::get().to(get_refunds_filters))); + .service(web::resource("/v2/filter").route(web::get().to(get_refunds_filters))) + .service( + web::resource("/{id}/manual-update") + .route(web::put().to(refunds_manual_update)), + ); } #[cfg(feature = "oltp")] { diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs index a64343757b5..a0c5f387db5 100644 --- a/crates/router/src/routes/lock_utils.rs +++ b/crates/router/src/routes/lock_utils.rs @@ -139,7 +139,8 @@ impl From for ApiIdentifier { | Flow::RefundsRetrieveForceSync | Flow::RefundsUpdate | Flow::RefundsList - | Flow::RefundsFilters => Self::Refunds, + | Flow::RefundsFilters + | Flow::RefundsManualUpdate => Self::Refunds, Flow::FrmFulfillment | Flow::IncomingWebhookReceive diff --git a/crates/router/src/routes/refunds.rs b/crates/router/src/routes/refunds.rs index 50e0c0c917f..6c7af7496ed 100644 --- a/crates/router/src/routes/refunds.rs +++ b/crates/router/src/routes/refunds.rs @@ -301,3 +301,26 @@ pub async fn get_refunds_filters(state: web::Data, req: HttpRequest) - )) .await } + +#[instrument(skip_all, fields(flow = ?Flow::RefundsManualUpdate))] +#[cfg(feature = "olap")] +pub async fn refunds_manual_update( + state: web::Data, + req: HttpRequest, + payload: web::Json, + path: web::Path, +) -> HttpResponse { + let flow = Flow::RefundsManualUpdate; + let mut refund_manual_update_req = payload.into_inner(); + refund_manual_update_req.refund_id = path.into_inner(); + Box::pin(api::server_wrap( + flow, + state, + &req, + refund_manual_update_req, + |state, _auth, req, _| refund_manual_update(state, req), + &auth::AdminApiAuth, + api_locking::LockAction::NotApplicable, + )) + .await +} diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs index 51f762e3713..2ea50d6389b 100644 --- a/crates/router_env/src/logger/types.rs +++ b/crates/router_env/src/logger/types.rs @@ -434,6 +434,8 @@ pub enum Flow { ToggleConnectorAgnosticMit, /// Get the extended card info associated to a payment_id GetExtendedCardInfo, + /// Manually update the refund details like status, error code, error message etc. + RefundsManualUpdate, } ///