diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index 86211770e0d..c3e49a49bb1 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -363,6 +363,16 @@ pub async fn trigger_refund_to_gateway( refund.refund_id ) })?; + utils::trigger_refund_outgoing_webhook( + state, + merchant_account, + &response, + payment_attempt.profile_id.clone(), + key_store, + ) + .await + .map_err(|error| logger::warn!(refunds_outgoing_webhook_error=?error)) + .ok(); Ok(response) } @@ -467,7 +477,7 @@ pub async fn refund_retrieve_core( .transpose()?; let response = if should_call_refund(&refund, request.force_sync.unwrap_or(false)) { - sync_refund_with_gateway( + Box::pin(sync_refund_with_gateway( &state, &merchant_account, &key_store, @@ -476,7 +486,7 @@ pub async fn refund_retrieve_core( &refund, creds_identifier, charges_req, - ) + )) .await } else { Ok(refund) @@ -669,6 +679,16 @@ pub async fn sync_refund_with_gateway( refund.refund_id ) })?; + utils::trigger_refund_outgoing_webhook( + state, + merchant_account, + &response, + payment_attempt.profile_id.clone(), + key_store, + ) + .await + .map_err(|error| logger::warn!(refunds_outgoing_webhook_error=?error)) + .ok(); Ok(response) } diff --git a/crates/router/src/utils.rs b/crates/router/src/utils.rs index ca61543ec57..9dca6cf3477 100644 --- a/crates/router/src/utils.rs +++ b/crates/router/src/utils.rs @@ -59,7 +59,10 @@ use crate::{ logger, routes::{metrics, SessionState}, services, - types::{self, domain, transformers::ForeignFrom}, + types::{ + self, domain, + transformers::{ForeignFrom, ForeignInto}, + }, }; pub mod error_parser { @@ -1274,3 +1277,70 @@ pub async fn flatten_join_error(handle: Handle) -> RouterResult { .attach_printable("Join Error"), } } + +#[cfg(feature = "v1")] +pub async fn trigger_refund_outgoing_webhook( + state: &SessionState, + merchant_account: &domain::MerchantAccount, + refund: &diesel_models::Refund, + profile_id: id_type::ProfileId, + key_store: &domain::MerchantKeyStore, +) -> RouterResult<()> { + let refund_status = refund.refund_status; + if matches!( + refund_status, + enums::RefundStatus::Success + | enums::RefundStatus::Failure + | enums::RefundStatus::TransactionFailure + ) { + let event_type = ForeignFrom::foreign_from(refund_status); + let refund_response: api_models::refunds::RefundResponse = refund.clone().foreign_into(); + let key_manager_state = &(state).into(); + let refund_id = refund_response.refund_id.clone(); + let business_profile = state + .store + .find_business_profile_by_profile_id(key_manager_state, key_store, &profile_id) + .await + .to_not_found_response(errors::ApiErrorResponse::ProfileNotFound { + id: profile_id.get_string_repr().to_owned(), + })?; + let cloned_state = state.clone(); + let cloned_key_store = key_store.clone(); + let cloned_merchant_account = merchant_account.clone(); + let primary_object_created_at = refund_response.created_at; + if let Some(outgoing_event_type) = event_type { + tokio::spawn( + async move { + Box::pin(webhooks_core::create_event_and_trigger_outgoing_webhook( + cloned_state, + cloned_merchant_account, + business_profile, + &cloned_key_store, + outgoing_event_type, + diesel_models::enums::EventClass::Refunds, + refund_id.to_string(), + diesel_models::enums::EventObjectType::RefundDetails, + webhooks::OutgoingWebhookContent::RefundDetails(Box::new(refund_response)), + primary_object_created_at, + )) + .await + } + .in_current_span(), + ); + } else { + logger::warn!("Outgoing webhook not sent because of missing event type status mapping"); + }; + } + Ok(()) +} + +#[cfg(feature = "v2")] +pub async fn trigger_refund_outgoing_webhook( + state: &SessionState, + merchant_account: &domain::MerchantAccount, + refund: &diesel_models::Refund, + profile_id: id_type::ProfileId, + key_store: &domain::MerchantKeyStore, +) -> RouterResult<()> { + todo!() +}