Bug: feat(connector): [Shift4] Refund webhooks 



Refund webhook support for connector shift4
diff --git a/crates/router/src/connector/shift4.rs b/crates/router/src/connector/shift4.rs
index 8f8d6cee56b..d75a0896583 100644
--- a/crates/router/src/connector/shift4.rs
+++ b/crates/router/src/connector/shift4.rs
@@ -3,7 +3,7 @@ mod transformers;
 use std::fmt::Debug;
 
 use common_utils::ext_traits::ByteSliceExt;
-use error_stack::ResultExt;
+use error_stack::{IntoReport, ResultExt};
 use transformers as shift4;
 
 use super::utils::RefundsRequestData;
@@ -737,9 +737,25 @@ impl api::IncomingWebhook for Shift4 {
             .parse_struct("Shift4WebhookObjectId")
             .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
 
-        Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
-            api_models::payments::PaymentIdType::ConnectorTransactionId(details.data.id),
-        ))
+        if shift4::is_transaction_event(&details.event_type) {
+            Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
+                api_models::payments::PaymentIdType::ConnectorTransactionId(details.data.id),
+            ))
+        } else if shift4::is_refund_event(&details.event_type) {
+            Ok(api_models::webhooks::ObjectReferenceId::RefundId(
+                api_models::webhooks::RefundIdType::ConnectorRefundId(
+                    details
+                        .data
+                        .refunds
+                        .and_then(|refund| {
+                            refund.first().map(|refund_object| refund_object.id.clone())
+                        })
+                        .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?,
+                ),
+            ))
+        } else {
+            Err(errors::ConnectorError::WebhookReferenceIdNotFound).into_report()
+        }
     }
 
     fn get_webhook_event_type(
@@ -750,12 +766,7 @@ impl api::IncomingWebhook for Shift4 {
             .body
             .parse_struct("Shift4WebhookObjectEventType")
             .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
-        Ok(match details.event_type {
-            shift4::Shift4WebhookEvent::ChargeSucceeded => {
-                api::IncomingWebhookEvent::PaymentIntentSuccess
-            }
-            shift4::Shift4WebhookEvent::Unknown => api::IncomingWebhookEvent::EventNotSupported,
-        })
+        Ok(api::IncomingWebhookEvent::from(details.event_type))
     }
 
     fn get_webhook_resource_object(
diff --git a/crates/router/src/connector/shift4/transformers.rs b/crates/router/src/connector/shift4/transformers.rs
index dc5f4efbeb5..22a3ae58a77 100644
--- a/crates/router/src/connector/shift4/transformers.rs
+++ b/crates/router/src/connector/shift4/transformers.rs
@@ -323,8 +323,13 @@ pub struct Shift4WebhookObjectEventType {
 }
 
 #[derive(Debug, Deserialize)]
+#[allow(clippy::enum_variant_names)]
 pub enum Shift4WebhookEvent {
     ChargeSucceeded,
+    ChargeFailed,
+    ChargeUpdated,
+    ChargeCaptured,
+    ChargeRefunded,
     #[serde(other)]
     Unknown,
 }
@@ -332,10 +337,18 @@ pub enum Shift4WebhookEvent {
 #[derive(Debug, Deserialize)]
 pub struct Shift4WebhookObjectData {
     pub id: String,
+    pub refunds: Option<Vec<RefundIdObject>>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct RefundIdObject {
+    pub id: String,
 }
 
 #[derive(Debug, Deserialize)]
 pub struct Shift4WebhookObjectId {
+    #[serde(rename = "type")]
+    pub event_type: Shift4WebhookEvent,
     pub data: Shift4WebhookObjectData,
 }
 
@@ -604,3 +617,32 @@ pub struct ApiErrorResponse {
     pub code: Option<String>,
     pub message: String,
 }
+
+pub fn is_transaction_event(event: &Shift4WebhookEvent) -> bool {
+    matches!(
+        event,
+        Shift4WebhookEvent::ChargeCaptured
+            | Shift4WebhookEvent::ChargeFailed
+            | Shift4WebhookEvent::ChargeSucceeded
+            | Shift4WebhookEvent::ChargeUpdated
+    )
+}
+
+pub fn is_refund_event(event: &Shift4WebhookEvent) -> bool {
+    matches!(event, Shift4WebhookEvent::ChargeRefunded)
+}
+
+impl From<Shift4WebhookEvent> for api::IncomingWebhookEvent {
+    fn from(event: Shift4WebhookEvent) -> Self {
+        match event {
+            Shift4WebhookEvent::ChargeSucceeded | Shift4WebhookEvent::ChargeUpdated => {
+                //reference : https://dev.shift4.com/docs/api#event-types
+                Self::PaymentIntentProcessing
+            }
+            Shift4WebhookEvent::ChargeCaptured => Self::PaymentIntentSuccess,
+            Shift4WebhookEvent::ChargeFailed => Self::PaymentIntentFailure,
+            Shift4WebhookEvent::ChargeRefunded => Self::RefundSuccess,
+            Shift4WebhookEvent::Unknown => Self::EventNotSupported,
+        }
+    }
+}

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [x] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
Refund webhook support for shift4 ([status mapping ref](https://dev.shift4.com/docs/api#event-types)) . We always update the status by psync as we don't have source verification for shift4 .

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!-- 
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless its an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
**payment webhook**
<img width="1181" alt="Screenshot 2023-05-29 at 6 51 42 PM" src="https://github.com/juspay/hyperswitch/assets/121822803/f077b49d-eb93-4612-a187-dfc7ea8e06e0">
**Refund webhook**
<img width="1184" alt="Screenshot 2023-05-29 at 6 51 05 PM" src="https://github.com/juspay/hyperswitch/assets/121822803/b5b1e489-a3bb-4e77-b073-11d5ff8e5edc">


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed submitted code
- [ ] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
