feat(router): add refunds manual-update api (#5094)

This commit is contained in:
Sai Harsha Vardhan
2024-07-02 18:40:23 +05:30
committed by GitHub
parent 618ec41aff
commit 9bc780151c
8 changed files with 142 additions and 4 deletions

View File

@ -1,8 +1,9 @@
use common_utils::events::{ApiEventMetric, ApiEventsType}; use common_utils::events::{ApiEventMetric, ApiEventsType};
use crate::refunds::{ use crate::refunds::{
RefundListFilters, RefundListMetaData, RefundListRequest, RefundListResponse, RefundRequest, RefundListFilters, RefundListMetaData, RefundListRequest, RefundListResponse,
RefundResponse, RefundUpdateRequest, RefundsRetrieveRequest, RefundManualUpdateRequest, RefundRequest, RefundResponse, RefundUpdateRequest,
RefundsRetrieveRequest,
}; };
impl ApiEventMetric for RefundRequest { impl ApiEventMetric for RefundRequest {
@ -44,6 +45,15 @@ impl ApiEventMetric for RefundUpdateRequest {
} }
} }
impl ApiEventMetric for RefundManualUpdateRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Refund {
payment_id: None,
refund_id: self.refund_id.clone(),
})
}
}
impl ApiEventMetric for RefundListRequest { impl ApiEventMetric for RefundListRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> { fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI) Some(ApiEventsType::ResourceListAPI)

View File

@ -97,6 +97,21 @@ pub struct RefundUpdateRequest {
pub metadata: Option<pii::SecretSerdeValue>, pub metadata: Option<pii::SecretSerdeValue>,
} }
#[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<RefundStatus>,
/// The code for the error
pub error_code: Option<String>,
/// The error message
pub error_message: Option<String>,
}
/// To indicate whether to refund needs to be instant or scheduled /// To indicate whether to refund needs to be instant or scheduled
#[derive( #[derive(
Default, Debug, Clone, Copy, ToSchema, Deserialize, Serialize, Eq, PartialEq, strum::Display, Default, Debug, Clone, Copy, ToSchema, Deserialize, Serialize, Eq, PartialEq, strum::Display,
@ -244,3 +259,14 @@ impl From<enums::RefundStatus> for RefundStatus {
} }
} }
} }
impl From<RefundStatus> 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,
}
}
}

View File

@ -115,6 +115,12 @@ pub enum RefundUpdate {
refund_error_code: Option<String>, refund_error_code: Option<String>,
updated_by: String, updated_by: String,
}, },
ManualUpdate {
refund_status: Option<storage_enums::RefundStatus>,
refund_error_message: Option<String>,
refund_error_code: Option<String>,
updated_by: String,
},
} }
#[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)] #[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)]
@ -201,6 +207,18 @@ impl From<RefundUpdate> for RefundUpdateInternal {
updated_by, updated_by,
..Default::default() ..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()
},
} }
} }
} }

View File

@ -836,6 +836,60 @@ pub async fn refund_filter_list(
Ok(services::ApplicationResponse::Json(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<serde_json::Value> {
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)] #[instrument(skip_all)]
#[cfg(feature = "olap")] #[cfg(feature = "olap")]
pub async fn get_filters_for_refunds( pub async fn get_filters_for_refunds(

View File

@ -855,7 +855,11 @@ impl Refunds {
route = route route = route
.service(web::resource("/list").route(web::post().to(refunds_list))) .service(web::resource("/list").route(web::post().to(refunds_list)))
.service(web::resource("/filter").route(web::post().to(refunds_filter_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")] #[cfg(feature = "oltp")]
{ {

View File

@ -143,7 +143,8 @@ impl From<Flow> for ApiIdentifier {
| Flow::RefundsRetrieveForceSync | Flow::RefundsRetrieveForceSync
| Flow::RefundsUpdate | Flow::RefundsUpdate
| Flow::RefundsList | Flow::RefundsList
| Flow::RefundsFilters => Self::Refunds, | Flow::RefundsFilters
| Flow::RefundsManualUpdate => Self::Refunds,
Flow::FrmFulfillment Flow::FrmFulfillment
| Flow::IncomingWebhookReceive | Flow::IncomingWebhookReceive

View File

@ -301,3 +301,26 @@ pub async fn get_refunds_filters(state: web::Data<AppState>, req: HttpRequest) -
)) ))
.await .await
} }
#[instrument(skip_all, fields(flow = ?Flow::RefundsManualUpdate))]
#[cfg(feature = "olap")]
pub async fn refunds_manual_update(
state: web::Data<AppState>,
req: HttpRequest,
payload: web::Json<api_models::refunds::RefundManualUpdateRequest>,
path: web::Path<String>,
) -> 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
}

View File

@ -452,6 +452,8 @@ pub enum Flow {
ToggleConnectorAgnosticMit, ToggleConnectorAgnosticMit,
/// Get the extended card info associated to a payment_id /// Get the extended card info associated to a payment_id
GetExtendedCardInfo, GetExtendedCardInfo,
/// Manually update the refund details like status, error code, error message etc.
RefundsManualUpdate,
/// Manually update the payment details like status, error code, error message etc. /// Manually update the payment details like status, error code, error message etc.
PaymentsManualUpdate, PaymentsManualUpdate,
} }