Issue:
Bug: [BUG] [JPMORGAN] 5xx during Payments Authorize and Void



- Card expiry should be be `i32` and not `String`
- Void has a set of enum values to be passed and not random String values


Pull request description:
## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [x] Bugfix
- [ ] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->

This PR fixes 5xx thrown by JPMorgan connector during payments authorize and void call.

Connector expects the expiry month and year to be `i32` and not a `String` which is why it used to a 5xx due to deserialization failure.

And for Void, the connector expects a limited set of values as cancellation reason. Passing values outside of those limited values results in a 5xx being thrown.

### 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).
-->

This bug fix is done as a part of connector auditing for JPMorgan connector. Closes https://github.com/juspay/hyperswitch/issues/8281

## 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)?
-->

Fixed and ran Cypress tests against the connector. 

![image](https://github.com/user-attachments/assets/036fb788-9d6d-4575-adf7-9e724556ae60)


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `just clippy && just clippy_v2`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible


Testing:


Fixed and ran Cypress tests against the connector. 

![image](https://github.com/user-attachments/assets/036fb788-9d6d-4575-adf7-9e724556ae60)

Patch:
diff --git a/crates/hyperswitch_connectors/src/connectors/jpmorgan.rs b/crates/hyperswitch_connectors/src/connectors/jpmorgan.rs
index 00e9fb35e8e..9783324c042 100644
--- a/crates/hyperswitch_connectors/src/connectors/jpmorgan.rs
+++ b/crates/hyperswitch_connectors/src/connectors/jpmorgan.rs
@@ -306,6 +306,16 @@ impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken>
 impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
     for Jpmorgan
 {
+    fn build_request(
+        &self,
+        _req: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
+        _connectors: &Connectors,
+    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
+        Err(
+            errors::ConnectorError::NotImplemented("Setup Mandate flow for JPMorgan".to_string())
+                .into(),
+        )
+    }
 }
 
 impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Jpmorgan {
diff --git a/crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs b/crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs
index 8497443fbb8..9f253c0ffb7 100644
--- a/crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs
@@ -1,5 +1,8 @@
+use std::str::FromStr;
+
 use common_enums::enums::CaptureMethod;
 use common_utils::types::MinorUnit;
+use error_stack::{report, ResultExt};
 use hyperswitch_domain_models::{
     payment_method_data::PaymentMethodData,
     router_data::{AccessToken, ConnectorAuthType, RouterData},
@@ -12,7 +15,7 @@ use hyperswitch_domain_models::{
     },
 };
 use hyperswitch_interfaces::errors;
-use masking::Secret;
+use masking::{PeekInterface, Secret};
 use serde::{Deserialize, Serialize};
 
 use crate::{
@@ -102,8 +105,8 @@ pub struct JpmorganPaymentMethodType {
 #[derive(Default, Debug, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 pub struct Expiry {
-    month: Secret<String>,
-    year: Secret<String>,
+    month: Secret<i32>,
+    year: Secret<i32>,
 }
 
 #[derive(Serialize, Debug, Default, Deserialize)]
@@ -159,8 +162,15 @@ impl TryFrom<&JpmorganRouterData<&PaymentsAuthorizeRouterData>> for JpmorganPaym
                 let merchant = JpmorganMerchant { merchant_software };
 
                 let expiry: Expiry = Expiry {
-                    month: req_card.card_exp_month.clone(),
-                    year: req_card.get_expiry_year_4_digit(),
+                    month: Secret::new(
+                        req_card
+                            .card_exp_month
+                            .peek()
+                            .clone()
+                            .parse::<i32>()
+                            .change_context(errors::ConnectorError::RequestEncodingFailed)?,
+                    ),
+                    year: req_card.get_expiry_year_as_4_digit_i32()?,
                 };
 
                 let account_number = Secret::new(req_card.card_number.to_string());
@@ -637,12 +647,47 @@ impl TryFrom<RefundsResponseRouterData<RSync, JpmorganRefundSyncResponse>>
     }
 }
 
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+pub enum ReversalReason {
+    NoResponse,
+    LateResponse,
+    UnableToDeliver,
+    CardDeclined,
+    MacNotVerified,
+    MacSyncError,
+    ZekSyncError,
+    SystemMalfunction,
+    SuspectedFraud,
+}
+
+impl FromStr for ReversalReason {
+    type Err = error_stack::Report<errors::ConnectorError>;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s.to_uppercase().as_str() {
+            "NO_RESPONSE" => Ok(Self::NoResponse),
+            "LATE_RESPONSE" => Ok(Self::LateResponse),
+            "UNABLE_TO_DELIVER" => Ok(Self::UnableToDeliver),
+            "CARD_DECLINED" => Ok(Self::CardDeclined),
+            "MAC_NOT_VERIFIED" => Ok(Self::MacNotVerified),
+            "MAC_SYNC_ERROR" => Ok(Self::MacSyncError),
+            "ZEK_SYNC_ERROR" => Ok(Self::ZekSyncError),
+            "SYSTEM_MALFUNCTION" => Ok(Self::SystemMalfunction),
+            "SUSPECTED_FRAUD" => Ok(Self::SuspectedFraud),
+            _ => Err(report!(errors::ConnectorError::InvalidDataFormat {
+                field_name: "cancellation_reason",
+            })),
+        }
+    }
+}
+
 #[derive(Debug, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 pub struct JpmorganCancelRequest {
     pub amount: Option<i64>,
     pub is_void: Option<bool>,
-    pub reversal_reason: Option<String>,
+    pub reversal_reason: Option<ReversalReason>,
 }
 
 impl TryFrom<JpmorganRouterData<&PaymentsCancelRouterData>> for JpmorganCancelRequest {
@@ -651,7 +696,13 @@ impl TryFrom<JpmorganRouterData<&PaymentsCancelRouterData>> for JpmorganCancelRe
         Ok(Self {
             amount: item.router_data.request.amount,
             is_void: Some(true),
-            reversal_reason: item.router_data.request.cancellation_reason.clone(),
+            reversal_reason: item
+                .router_data
+                .request
+                .cancellation_reason
+                .as_ref()
+                .map(|reason| ReversalReason::from_str(reason))
+                .transpose()?,
         })
     }
 }