feat(refunds_v2): Add refund update core flow in v2 apis (#7724)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Amey Wale
2025-05-13 14:36:22 +05:30
committed by GitHub
parent 9c8cf93662
commit 04dc14a930
8 changed files with 239 additions and 22 deletions

View File

@ -465,6 +465,42 @@ where
request.check_integrity(request, connector_refund_id.to_owned())
}
// ********************************************** REFUND UPDATE **********************************************
pub async fn refund_metadata_update_core(
state: SessionState,
merchant_account: domain::MerchantAccount,
req: refunds::RefundMetadataUpdateRequest,
global_refund_id: id_type::GlobalRefundId,
) -> errors::RouterResponse<refunds::RefundResponse> {
let db = state.store.as_ref();
let refund = db
.find_refund_by_id(&global_refund_id, merchant_account.storage_scheme)
.await
.to_not_found_response(errors::ApiErrorResponse::RefundNotFound)?;
let response = db
.update_refund(
refund,
storage::RefundUpdate::MetadataAndReasonUpdate {
metadata: req.metadata,
reason: req.reason,
updated_by: merchant_account.storage_scheme.to_string(),
},
merchant_account.storage_scheme,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable_lazy(|| {
format!(
"Unable to update refund with refund_id: {}",
global_refund_id.get_string_repr()
)
})?;
refunds::RefundResponse::foreign_try_from(response).map(services::ApplicationResponse::Json)
}
// ********************************************** REFUND SYNC **********************************************
#[instrument(skip_all)]

View File

@ -1187,7 +1187,11 @@ impl Refunds {
{
route = route
.service(web::resource("").route(web::post().to(refunds::refunds_create)))
.service(web::resource("/{id}").route(web::get().to(refunds::refunds_retrieve)));
.service(web::resource("/{id}").route(web::get().to(refunds::refunds_retrieve)))
.service(
web::resource("/{id}/update_metadata")
.route(web::put().to(refunds::refunds_metadata_update)),
);
}
route

View File

@ -12,6 +12,39 @@ use crate::{
services::{api, authentication as auth, authorization::permissions::Permission},
types::{api::refunds, domain},
};
#[cfg(feature = "v2")]
/// A private module to hold internal types to be used in route handlers.
/// This is because we will need to implement certain traits on these types which will have the resource id
/// But the api payload will not contain the resource id
/// So these types can hold the resource id along with actual api payload, on which api event and locking action traits can be implemented
mod internal_payload_types {
use super::*;
// Serialize is implemented because of api events
#[derive(Debug, serde::Serialize)]
pub struct RefundsGenericRequestWithResourceId<T: serde::Serialize> {
pub global_refund_id: common_utils::id_type::GlobalRefundId,
pub payment_id: Option<common_utils::id_type::GlobalPaymentId>,
#[serde(flatten)]
pub payload: T,
}
impl<T: serde::Serialize> common_utils::events::ApiEventMetric
for RefundsGenericRequestWithResourceId<T>
{
fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
let refund_id = self.global_refund_id.clone();
self.payment_id
.clone()
.map(|payment_id| common_utils::events::ApiEventsType::Refund {
payment_id,
refund_id,
})
}
}
}
/// Refunds - Create
///
/// To create a refund against an already processed payment
@ -323,6 +356,45 @@ pub async fn refunds_update(
.await
}
#[cfg(all(feature = "v2", feature = "refunds_v2"))]
#[instrument(skip_all, fields(flow = ?Flow::RefundsUpdate))]
pub async fn refunds_metadata_update(
state: web::Data<AppState>,
req: HttpRequest,
json_payload: web::Json<refunds::RefundMetadataUpdateRequest>,
path: web::Path<common_utils::id_type::GlobalRefundId>,
) -> HttpResponse {
let flow = Flow::RefundsUpdate;
let global_refund_id = path.into_inner();
let internal_payload = internal_payload_types::RefundsGenericRequestWithResourceId {
global_refund_id: global_refund_id.clone(),
payment_id: None,
payload: json_payload.into_inner(),
};
Box::pin(api::server_wrap(
flow,
state,
&req,
internal_payload,
|state, auth: auth::AuthenticationData, req, _| {
refund_metadata_update_core(
state,
auth.merchant_account,
req.payload,
global_refund_id.clone(),
)
},
&auth::V2ApiKeyAuth {
is_connected_allowed: false,
is_platform_allowed: false,
},
api_locking::LockAction::NotApplicable,
))
.await
}
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "refunds_v2"),

View File

@ -1,11 +1,11 @@
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "refunds_v2")))]
pub use api_models::refunds::RefundRequest;
#[cfg(all(feature = "v2", feature = "refunds_v2"))]
pub use api_models::refunds::RefundsCreateRequest;
pub use api_models::refunds::{
RefundListRequest, RefundListResponse, RefundResponse, RefundStatus, RefundType,
RefundUpdateRequest, RefundsRetrieveBody, RefundsRetrieveRequest,
};
#[cfg(all(feature = "v2", feature = "refunds_v2"))]
pub use api_models::refunds::{RefundMetadataUpdateRequest, RefundsCreateRequest};
pub use hyperswitch_domain_models::router_flow_types::refunds::{Execute, RSync};
pub use hyperswitch_interfaces::api::refunds::{Refund, RefundExecute, RefundSync};