Bug: feat(opensearch): refactor global search querybuilder and add case insensitivity opensearch filters



- Currently the global search query builder logic is entirely present in a single function.
- With more and more features getting added on, it is better to separate out the logic to build the query into separate modules.
- Also, with the enhancement of global search, it is better to give out some fields as case sensitive and others as case insensitive.

Case Sensitive filters:
- customer_email
- payment_id
- card_last_4
- search_tags

Case Insensitive filters:
- payment_method
- payment_method_type
- card_network
- currency
- connector
- status


The new structure would be divided into separate functions for the respective modules as follows:
- Free Search Query + Time Range + Filters (case sensitive)
- Filters (case insensitive)
- Authentication and Search Params
diff --git a/crates/analytics/src/opensearch.rs b/crates/analytics/src/opensearch.rs
index a6e6c486ebe..84a2b9db3d4 100644
--- a/crates/analytics/src/opensearch.rs
+++ b/crates/analytics/src/opensearch.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::{
     analytics::search::SearchIndex,
     errors::types::{ApiError, ApiErrorResponse},
@@ -456,7 +458,8 @@ pub struct OpenSearchQueryBuilder {
     pub count: Option<i64>,
     pub filters: Vec<(String, Vec<String>)>,
     pub time_range: Option<OpensearchTimeRange>,
-    pub search_params: Vec<AuthInfo>,
+    search_params: Vec<AuthInfo>,
+    case_sensitive_fields: HashSet<&'static str>,
 }
 
 impl OpenSearchQueryBuilder {
@@ -469,6 +472,12 @@ impl OpenSearchQueryBuilder {
             count: Default::default(),
             filters: Default::default(),
             time_range: Default::default(),
+            case_sensitive_fields: HashSet::from([
+                "customer_email.keyword",
+                "search_tags.keyword",
+                "card_last_4.keyword",
+                "payment_id.keyword",
+            ]),
         }
     }
 
@@ -490,48 +499,16 @@ impl OpenSearchQueryBuilder {
 
     pub fn get_status_field(&self, index: &SearchIndex) -> &str {
         match index {
-            SearchIndex::Refunds => "refund_status.keyword",
-            SearchIndex::Disputes => "dispute_status.keyword",
+            SearchIndex::Refunds | SearchIndex::SessionizerRefunds => "refund_status.keyword",
+            SearchIndex::Disputes | SearchIndex::SessionizerDisputes => "dispute_status.keyword",
             _ => "status.keyword",
         }
     }
 
-    pub fn replace_status_field(&self, filters: &[Value], index: &SearchIndex) -> Vec<Value> {
-        filters
-            .iter()
-            .map(|filter| {
-                if let Some(terms) = filter.get("terms").and_then(|v| v.as_object()) {
-                    let mut new_filter = filter.clone();
-                    if let Some(new_terms) =
-                        new_filter.get_mut("terms").and_then(|v| v.as_object_mut())
-                    {
-                        let key = "status.keyword";
-                        if let Some(status_terms) = terms.get(key) {
-                            new_terms.remove(key);
-                            new_terms.insert(
-                                self.get_status_field(index).to_string(),
-                                status_terms.clone(),
-                            );
-                        }
-                    }
-                    new_filter
-                } else {
-                    filter.clone()
-                }
-            })
-            .collect()
-    }
-
-    /// # Panics
-    ///
-    /// This function will panic if:
-    ///
-    /// * The structure of the JSON query is not as expected (e.g., missing keys or incorrect types).
-    ///
-    /// Ensure that the input data and the structure of the query are valid and correctly handled.
-    pub fn construct_payload(&self, indexes: &[SearchIndex]) -> QueryResult<Vec<Value>> {
-        let mut query_obj = Map::new();
-        let mut bool_obj = Map::new();
+    pub fn build_filter_array(
+        &self,
+        case_sensitive_filters: Vec<&(String, Vec<String>)>,
+    ) -> Vec<Value> {
         let mut filter_array = Vec::new();
 
         filter_array.push(json!({
@@ -542,13 +519,12 @@ impl OpenSearchQueryBuilder {
             }
         }));
 
-        let mut filters = self
-            .filters
-            .iter()
+        let case_sensitive_json_filters = case_sensitive_filters
+            .into_iter()
             .map(|(k, v)| json!({"terms": {k: v}}))
             .collect::<Vec<Value>>();
 
-        filter_array.append(&mut filters);
+        filter_array.extend(case_sensitive_json_filters);
 
         if let Some(ref time_range) = self.time_range {
             let range = json!(time_range);
@@ -559,8 +535,72 @@ impl OpenSearchQueryBuilder {
             }));
         }
 
-        let should_array = self
-            .search_params
+        filter_array
+    }
+
+    pub fn build_case_insensitive_filters(
+        &self,
+        mut payload: Value,
+        case_insensitive_filters: &[&(String, Vec<String>)],
+        auth_array: Vec<Value>,
+        index: &SearchIndex,
+    ) -> Value {
+        let mut must_array = case_insensitive_filters
+            .iter()
+            .map(|(k, v)| {
+                let key = if *k == "status.keyword" {
+                    self.get_status_field(index).to_string()
+                } else {
+                    k.clone()
+                };
+                json!({
+                    "bool": {
+                        "must": [
+                            {
+                                "bool": {
+                                    "should": v.iter().map(|value| {
+                                        json!({
+                                            "term": {
+                                                format!("{}", key): {
+                                                    "value": value,
+                                                    "case_insensitive": true
+                                                }
+                                            }
+                                        })
+                                    }).collect::<Vec<Value>>(),
+                                    "minimum_should_match": 1
+                                }
+                            }
+                        ]
+                    }
+                })
+            })
+            .collect::<Vec<Value>>();
+
+        must_array.push(json!({ "bool": {
+            "must": [
+                {
+                    "bool": {
+                        "should": auth_array,
+                        "minimum_should_match": 1
+                    }
+                }
+            ]
+        }}));
+
+        if let Some(query) = payload.get_mut("query") {
+            if let Some(bool_obj) = query.get_mut("bool") {
+                if let Some(bool_map) = bool_obj.as_object_mut() {
+                    bool_map.insert("must".to_string(), Value::Array(must_array));
+                }
+            }
+        }
+
+        payload
+    }
+
+    pub fn build_auth_array(&self) -> Vec<Value> {
+        self.search_params
             .iter()
             .map(|user_level| match user_level {
                 AuthInfo::OrgLevel { org_id } => {
@@ -579,11 +619,17 @@ impl OpenSearchQueryBuilder {
                     })
                 }
                 AuthInfo::MerchantLevel {
-                    org_id: _,
+                    org_id,
                     merchant_ids,
                 } => {
                     let must_clauses = vec![
-                        // TODO: Add org_id field to the filters
+                        json!({
+                            "term": {
+                                "organization_id.keyword": {
+                                    "value": org_id
+                                }
+                            }
+                        }),
                         json!({
                             "terms": {
                                 "merchant_id.keyword": merchant_ids
@@ -598,12 +644,18 @@ impl OpenSearchQueryBuilder {
                     })
                 }
                 AuthInfo::ProfileLevel {
-                    org_id: _,
+                    org_id,
                     merchant_id,
                     profile_ids,
                 } => {
                     let must_clauses = vec![
-                        // TODO: Add org_id field to the filters
+                        json!({
+                            "term": {
+                                "organization_id.keyword": {
+                                    "value": org_id
+                                }
+                            }
+                        }),
                         json!({
                             "term": {
                                 "merchant_id.keyword": {
@@ -625,55 +677,60 @@ impl OpenSearchQueryBuilder {
                     })
                 }
             })
-            .collect::<Vec<Value>>();
+            .collect::<Vec<Value>>()
+    }
+
+    /// # Panics
+    ///
+    /// This function will panic if:
+    ///
+    /// * The structure of the JSON query is not as expected (e.g., missing keys or incorrect types).
+    ///
+    /// Ensure that the input data and the structure of the query are valid and correctly handled.
+    pub fn construct_payload(&self, indexes: &[SearchIndex]) -> QueryResult<Vec<Value>> {
+        let mut query_obj = Map::new();
+        let mut bool_obj = Map::new();
+
+        let (case_sensitive_filters, case_insensitive_filters): (Vec<_>, Vec<_>) = self
+            .filters
+            .iter()
+            .partition(|(k, _)| self.case_sensitive_fields.contains(k.as_str()));
+
+        let filter_array = self.build_filter_array(case_sensitive_filters);
 
         if !filter_array.is_empty() {
             bool_obj.insert("filter".to_string(), Value::Array(filter_array));
         }
+
+        let should_array = self.build_auth_array();
+
         if !bool_obj.is_empty() {
             query_obj.insert("bool".to_string(), Value::Object(bool_obj));
         }
 
-        let mut query = Map::new();
-        query.insert("query".to_string(), Value::Object(query_obj));
+        let mut sort_obj = Map::new();
+        sort_obj.insert(
+            "@timestamp".to_string(),
+            json!({
+                "order": "desc"
+            }),
+        );
 
         Ok(indexes
             .iter()
             .map(|index| {
-                let updated_query = query
-                    .get("query")
-                    .and_then(|q| q.get("bool"))
-                    .and_then(|b| b.get("filter"))
-                    .and_then(|f| f.as_array())
-                    .map(|filters| self.replace_status_field(filters, index))
-                    .unwrap_or_default();
-                let mut final_bool_obj = Map::new();
-                if !updated_query.is_empty() {
-                    final_bool_obj.insert("filter".to_string(), Value::Array(updated_query));
-                }
-                if !should_array.is_empty() {
-                    final_bool_obj.insert("should".to_string(), Value::Array(should_array.clone()));
-                    final_bool_obj
-                        .insert("minimum_should_match".to_string(), Value::Number(1.into()));
-                }
-                let mut final_query = Map::new();
-                if !final_bool_obj.is_empty() {
-                    final_query.insert("bool".to_string(), Value::Object(final_bool_obj));
-                }
-
-                let mut sort_obj = Map::new();
-                sort_obj.insert(
-                    "@timestamp".to_string(),
-                    json!({
-                        "order": "desc"
-                    }),
-                );
-                let payload = json!({
-                    "query": Value::Object(final_query),
+                let mut payload = json!({
+                    "query": query_obj.clone(),
                     "sort": [
-                        Value::Object(sort_obj)
+                        Value::Object(sort_obj.clone())
                     ]
                 });
+                payload = self.build_case_insensitive_filters(
+                    payload,
+                    &case_insensitive_filters,
+                    should_array.clone(),
+                    index,
+                );
                 payload
             })
             .collect::<Vec<Value>>())
diff --git a/crates/analytics/src/search.rs b/crates/analytics/src/search.rs
index f53b07b1232..9be0200030d 100644
--- a/crates/analytics/src/search.rs
+++ b/crates/analytics/src/search.rs
@@ -190,7 +190,17 @@ pub async fn search_results(
     search_params: Vec<AuthInfo>,
 ) -> CustomResult<GetSearchResponse, OpenSearchError> {
     let search_req = req.search_req;
-
+    if search_req.query.trim().is_empty()
+        && search_req
+            .filters
+            .as_ref()
+            .map_or(true, |filters| filters.is_all_none())
+    {
+        return Err(OpenSearchError::BadRequestError(
+            "Both query and filters are empty".to_string(),
+        )
+        .into());
+    }
     let mut query_builder = OpenSearchQueryBuilder::new(
         OpenSearchQuery::Search(req.index),
         search_req.query,

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

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

## Description
<!-- Describe your changes in detail -->
- Currently the global search query builder logic is entirely present in a single function.
- With more and more features getting added on, it is better to separate out the logic to build the query into separate modules.
- Also, with the enhancement of global search, it is better to give out some fields as case sensitive and others as case insensitive.

Case Sensitive filters:
- customer_email
- payment_id
- card_last_4
- search_tags

Case Insensitive filters:
- payment_method
- payment_method_type
- card_network
- currency
- connector
- status


The new structure would be divided into separate functions for the respective modules as follows:
- Free Search Query + Time Range + Filters (case sensitive)
- Filters (case insensitive)
- Authentication and Search Params

The query generated to hit opensearch will now look like the following:
```json
{
  "query": {
    "bool": {
      "filter": [
        {
          "multi_match": {
            "type": "phrase",
            "query": "merchant_1726046328",
            "lenient": true
          }
        },
        {
          "terms": {
            "customer_email.keyword": [
              "f6cd0753a831880835a0e0d23136ef66318d8303605bd37fa80b4ecf248bd303"
            ]
          }
        },
        {
          "terms": {
            "card_last_4.keyword": [
              "4242"
            ]
          }
        },
        {
          "terms": {
            "payment_id.keyword": [
              "pay_QdstJpRVAcRKHzRIRK4d"
            ]
          }
        },
        {
          "range": {
            "@timestamp": {
              "gte": "2024-09-13T00:30:00.000Z",
              "lte": "2024-10-30T21:45:00.000Z"
            }
          }
        }
      ],
      "must": [
        {
          "bool": {
            "must": [
              {
                "bool": {
                  "should": [
                    {
                      "term": {
                        "currency.keyword": {
                          "value": "UsD",
                          "case_insensitive": true
                        }
                      }
                    }
                  ],
                  "minimum_should_match": 1
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must": [
              {
                "bool": {
                  "should": [
                    {
                      "term": {
                        "status.keyword": {
                          "value": "CharGed",
                          "case_insensitive": true
                        }
                      }
                    },
                    {
                      "term": {
                        "status.keyword": {
                          "value": "succeeded",
                          "case_insensitive": true
                        }
                      }
                    }
                  ],
                  "minimum_should_match": 1
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must": [
              {
                "bool": {
                  "should": [
                    {
                      "term": {
                        "payment_method.keyword": {
                          "value": "cArd",
                          "case_insensitive": true
                        }
                      }
                    },
                    {
                      "term": {
                        "payment_method.keyword": {
                          "value": "iwubefi",
                          "case_insensitive": true
                        }
                      }
                    }
                  ],
                  "minimum_should_match": 1
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must": [
              {
                "bool": {
                  "should": [
                    {
                      "term": {
                        "connector.keyword": {
                          "value": "striPe_Test",
                          "case_insensitive": true
                        }
                      }
                    }
                  ],
                  "minimum_should_match": 1
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must": [
              {
                "bool": {
                  "should": [
                    {
                      "term": {
                        "payment_method_type.keyword": {
                          "value": "credit",
                          "case_insensitive": true
                        }
                      }
                    }
                  ],
                  "minimum_should_match": 1
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must": [
              {
                "bool": {
                  "should": [
                    {
                      "bool": {
                        "must": [
                          {
                            "term": {
                              "organization_id.keyword": {
                                "value": "org_VpSHOjsYfDvabVYJgCAJ"
                              }
                            }
                          }
                        ]
                      }
                    }
                  ],
                  "minimum_should_match": 1
                }
              }
            ]
          }
        }
      ]
    }
  },
  "sort": [
    {
      "@timestamp": {
        "order": "desc"
      }
    }
  ]
}
```
### 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 it is an obvious bug or documentation fix
that will have little conversation).
-->

- Enhanced search experience based on free search and specific filters using global search.
- Can now search via filters in a case-insensitive manner for some common filters.
## 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)?
-->

Can send the following filters in any case:
- payment_method
- payment_method_type
- card_network
- currency
- connector
- status

Must send the following filters in the exact case:
- customer_email
- payment_id
- card_last_4
- search_tags


#### Hit the curl:
```bash
curl --location 'http://localhost:8080/analytics/v1/search' \
--header 'sec-ch-ua-platform: "macOS"' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNTQ5ZTNkMmItMTY5Yi00NzUzLWJmNTQtZDcxMTM2YjRiN2JkIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzI2MDQ2MzI4Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTczMDg3MDI4Niwib3JnX2lkIjoib3JnX1ZwU0hPanNZZkR2YWJWWUpnQ0FKIiwicHJvZmlsZV9pZCI6InByb192NXNGb0hlODBPZWlVbElvbm9jTSJ9.luU7VDVnDVz7xuHLKEY5UWfxU78sGvzysZ99R8-1Bxo' \
--header 'Referer: http://localhost:9000/' \
--header 'sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'api-key: dev_LZcIA7XeMpnK5satp4CDvjcnHCaeKTBcosyuBBJaknZu1odhFo96cwS0nSdfzuJF' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query": "merchant_1726046328",
    "filters": {
        "currency": [
            "UsD"
        ],
        "connector": [
            "striPe_Test"
        ],
        "customer_email": [
            "test@test14.com"
        ],
        "payment_method_type": [
            "credit"
        ],
        "payment_method": [
            "cArd", "iwubefi"
        ],
        "payment_id": [
            "pay_QdstJpRVAcRKHzRIRK4d"
        ],
        "card_last_4": [
            "4242"
        ],
        "status": [
            "CharGed", "succeeded"
        ]
    },
    "timeRange": {
        "startTime": "2024-09-13T00:30:00Z",
        "endTime": "2024-10-30T21:45:00Z"
    }
}'
```

Expected response:
```json
[
    {
        "count": 0,
        "index": "payment_attempts",
        "hits": [],
        "status": "Success"
    },
    {
        "count": 0,
        "index": "payment_intents",
        "hits": [],
        "status": "Success"
    },
    {
        "count": 0,
        "index": "refunds",
        "hits": [],
        "status": "Success"
    },
    {
        "count": 0,
        "index": "disputes",
        "hits": [],
        "status": "Failure"
    },
    {
        "count": 1,
        "index": "sessionizer_payment_attempts",
        "hits": [
            {
                "@timestamp": "2024-10-24T07:59:12.887Z",
                "amount": 6540,
                "amount_capturable": 0,
                "amount_to_capture": 6540,
                "attempt_id": "pay_QdstJpRVAcRKHzRIRK4d_1",
                "authentication_type": "no_three_ds",
                "capture_method": "automatic",
                "capture_on": 1662804672000,
                "card_last_4": "4242",
                "confirm": true,
                "connector": "stripe_test",
                "connector_transaction_id": "pay_BV1cUypv6paxZvJl2SiQ",
                "created_at": 1729756752887,
                "currency": "USD",
                "customer_email": "f6cd0753a831880835a0e0d23136ef66318d8303605bd37fa80b4ecf248bd303",
                "customer_id": "StripeCustomer",
                "first_attempt": true,
                "headers": {},
                "log_count": 9,
                "merchant_connector_id": "mca_NNsdIEb1AjEOkyALerP6",
                "merchant_id": "merchant_1726046328",
                "modified_at": 1729756754123,
                "net_amount": 6540,
                "organization_id": "org_VpSHOjsYfDvabVYJgCAJ",
                "payment_id": "pay_QdstJpRVAcRKHzRIRK4d",
                "payment_method": "card",
                "payment_method_data": "{\"card\":{\"last4\":\"4242\",\"bank_code\":null,\"card_isin\":\"424242\",\"card_type\":null,\"card_issuer\":null,\"card_network\":null,\"card_exp_year\":\"25\",\"card_exp_month\":\"10\",\"payment_checks\":null,\"card_holder_name\":null,\"card_extended_bin\":null,\"authentication_data\":null,\"card_issuing_country\":null}}",
                "payment_method_type": "credit",
                "profile_id": "pro_v5sFoHe80OeiUlIonocM",
                "source_type": "kafka",
                "status": "charged",
                "tenant_id": "public",
                "timestamp": "2024-10-24T07:59:12.887Z"
            }
        ],
        "status": "Success"
    },
    {
        "count": 1,
        "index": "sessionizer_payment_intents",
        "hits": [
            {
                "@timestamp": "2024-10-24T07:59:12.886Z",
                "active_attempt_id": "pay_QdstJpRVAcRKHzRIRK4d_1",
                "amount": 6540,
                "amount_captured": 6540,
                "attempt_count": 1,
                "attempts_list": [
                    {
                        "amount": 6540,
                        "amount_capturable": 0,
                        "amount_to_capture": 6540,
                        "attempt_id": "pay_QdstJpRVAcRKHzRIRK4d_1",
                        "authentication_type": "no_three_ds",
                        "capture_method": "automatic",
                        "capture_on": 1662804672000,
                        "confirm": true,
                        "connector": "stripe_test",
                        "connector_transaction_id": "pay_BV1cUypv6paxZvJl2SiQ",
                        "created_at": 1729756752887,
                        "currency": "USD",
                        "last_synced": 1729756752887,
                        "merchant_connector_id": "mca_NNsdIEb1AjEOkyALerP6",
                        "merchant_id": "merchant_1726046328",
                        "modified_at": 1729756754123,
                        "net_amount": 6540,
                        "organization_id": "org_VpSHOjsYfDvabVYJgCAJ",
                        "payment_id": "pay_QdstJpRVAcRKHzRIRK4d",
                        "payment_method": "card",
                        "payment_method_data": "{\"card\":{\"last4\":\"4242\",\"bank_code\":null,\"card_isin\":\"424242\",\"card_type\":null,\"card_issuer\":null,\"card_network\":null,\"card_exp_year\":\"25\",\"card_exp_month\":\"10\",\"payment_checks\":null,\"card_holder_name\":null,\"card_extended_bin\":null,\"authentication_data\":null,\"card_issuing_country\":null}}",
                        "payment_method_type": "credit",
                        "profile_id": "pro_v5sFoHe80OeiUlIonocM",
                        "status": "charged",
                        "tenant_id": "public"
                    }
                ],
                "authentication_type": "no_three_ds",
                "business_label": "default",
                "card_last_4": "4242",
                "client_secret": "pay_QdstJpRVAcRKHzRIRK4d_secret_u2WJTHVO3BmpJfkzdXaY",
                "connector": "stripe_test",
                "created_at": 1729756752886,
                "currency": "USD",
                "customer_email": "f6cd0753a831880835a0e0d23136ef66318d8303605bd37fa80b4ecf248bd303",
                "customer_id": "StripeCustomer",
                "description": "Its my first payment request",
                "dispute_list": [],
                "headers": {},
                "log_count": 9,
                "merchant_connector_id": "mca_NNsdIEb1AjEOkyALerP6",
                "merchant_id": "merchant_1726046328",
                "metadata": "{\"data2\":\"camel\",\"login_date\":\"2019-09-10T10:11:12Z\",\"new_customer\":\"true\"}",
                "modified_at": 1729756754123,
                "organization_id": "org_VpSHOjsYfDvabVYJgCAJ",
                "payment_id": "pay_QdstJpRVAcRKHzRIRK4d",
                "payment_method": "card",
                "payment_method_data": "{\"card\":{\"last4\":\"4242\",\"bank_code\":null,\"card_isin\":\"424242\",\"card_type\":null,\"card_issuer\":null,\"card_network\":null,\"card_exp_year\":\"25\",\"card_exp_month\":\"10\",\"payment_checks\":null,\"card_holder_name\":null,\"card_extended_bin\":null,\"authentication_data\":null,\"card_issuing_country\":null}}",
                "payment_method_type": "credit",
                "profile_id": "pro_v5sFoHe80OeiUlIonocM",
                "refund_list": [
                    {
                        "attempt_id": "pay_QdstJpRVAcRKHzRIRK4d_1",
                        "connector": "stripe_test",
                        "connector_refund_id": "dummy_ref_6HyIEJcmDyE75QiFnv76",
                        "connector_transaction_id": "pay_BV1cUypv6paxZvJl2SiQ",
                        "created_at": 1729756766669,
                        "currency": "USD",
                        "description": "Customer returned product",
                        "external_reference_id": "ref_Tc3KfBVm5HEuzECytr9g",
                        "internal_reference_id": "refid_vDztMj3wI0ETCFXEoWUG",
                        "merchant_id": "merchant_1726046328",
                        "modified_at": 1729756767668,
                        "organization_id": "org_VpSHOjsYfDvabVYJgCAJ",
                        "payment_id": "pay_QdstJpRVAcRKHzRIRK4d",
                        "profile_id": "pro_v5sFoHe80OeiUlIonocM",
                        "refund_amount": 600,
                        "refund_arn": "",
                        "refund_id": "ref_Tc3KfBVm5HEuzECytr9g",
                        "refund_reason": "Customer returned product",
                        "refund_status": "success",
                        "refund_type": "instant_refund",
                        "sent_to_gateway": true,
                        "tenant_id": "public",
                        "total_amount": 6540
                    }
                ],
                "refunds_status": "partial_refunded",
                "return_url": "https://google.com/",
                "source_type": "kafka",
                "statement_descriptor_name": "joseph",
                "statement_descriptor_suffix": "JS",
                "status": "succeeded",
                "tenant_id": "public",
                "timestamp": "2024-10-24T07:59:12.886Z"
            }
        ],
        "status": "Success"
    },
    {
        "count": 0,
        "index": "sessionizer_refunds",
        "hits": [],
        "status": "Success"
    },
    {
        "count": 0,
        "index": "sessionizer_disputes",
        "hits": [],
        "status": "Failure"
    }
]
```
## 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 the submitted code
- [ ] I added unit tests for my changes where possible
