Bug: [FEATURE]:Payments of statuses like requires_payment_method, requires_capture, requires_confirmation, requires_action can be cancelled 



### Feature Description

When trying the below curl, getting the following error
```
curl --location 'https://sandbox.hyperswitch.io/payments/pay_GqU4LxURmOgj4W9iZXeG/cancel' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: snd_RoTeY3DJkA2JOPS855zpgZ1WolpAarTvkAOZOnJTxqmsCb8PuCNilyTozw8mO97S' \
--data '{
  "cancellation_reason": "requested_by_customer"
}'
```
```
Error:
{
    "error": {
        "type": "invalid_request",
        "message": "You cannot cancel the payment that has not been authorized",
        "code": "IR_06"
    }
}
```
**We should be able to cancel payments when they are in any of the following statuses:
requires_payment_method, requires_capture, requires_confirmation, requires_action**


### Possible Implementation

As for the above following statuses we can't send the cancel request to connector as those flows are not going to the connector hence we need to handle the stuffs in update method itself so we need to check the condition whether it is in those above statuses we need to void the fields in DB.

### Have you spent some time to check if this feature request has been raised before?

- [X] I checked and didn't find similar issue

### Have you read the Contributing Guidelines?

- [X] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Sample SubIssues
- [x] #1083


### Are you willing to submit a PR?

Yes I am willing to submit a PR!
diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs
index f589b61745d..9c613cf782a 100644
--- a/crates/router/src/core/payments/operations/payment_cancel.rs
+++ b/crates/router/src/core/payments/operations/payment_cancel.rs
@@ -53,6 +53,18 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCancelRequest>
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        helpers::validate_payment_status_against_not_allowed_statuses(
+            &payment_intent.status,
+            &[
+                enums::IntentStatus::Failed,
+                enums::IntentStatus::Succeeded,
+                enums::IntentStatus::Cancelled,
+                enums::IntentStatus::Processing,
+                enums::IntentStatus::RequiresMerchantAction,
+            ],
+            "cancelled",
+        )?;
+
         let mut payment_attempt = db
             .find_payment_attempt_by_payment_id_merchant_id_attempt_id(
                 payment_intent.payment_id.as_str(),
@@ -112,44 +124,35 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCancelRequest>
             .await
             .transpose()?;
 
-        match payment_intent.status {
-            status if status != enums::IntentStatus::RequiresCapture => {
-                Err(errors::ApiErrorResponse::InvalidRequestData {
-                    message: "You cannot cancel the payment that has not been authorized"
-                        .to_string(),
-                }
-                .into())
-            }
-            _ => Ok((
-                Box::new(self),
-                PaymentData {
-                    flow: PhantomData,
-                    payment_intent,
-                    payment_attempt,
-                    currency,
-                    amount,
-                    email: None,
-                    mandate_id: None,
-                    setup_mandate: None,
-                    token: None,
-                    address: PaymentAddress {
-                        shipping: shipping_address.as_ref().map(|a| a.foreign_into()),
-                        billing: billing_address.as_ref().map(|a| a.foreign_into()),
-                    },
-                    confirm: None,
-                    payment_method_data: None,
-                    force_sync: None,
-                    refunds: vec![],
-                    connector_response,
-                    sessions_token: vec![],
-                    card_cvc: None,
-                    creds_identifier,
-                    pm_token: None,
-                    connector_customer_id: None,
+        Ok((
+            Box::new(self),
+            PaymentData {
+                flow: PhantomData,
+                payment_intent,
+                payment_attempt,
+                currency,
+                amount,
+                email: None,
+                mandate_id: None,
+                setup_mandate: None,
+                token: None,
+                address: PaymentAddress {
+                    shipping: shipping_address.as_ref().map(|a| a.foreign_into()),
+                    billing: billing_address.as_ref().map(|a| a.foreign_into()),
                 },
-                None,
-            )),
-        }
+                confirm: None,
+                payment_method_data: None,
+                force_sync: None,
+                refunds: vec![],
+                connector_response,
+                sessions_token: vec![],
+                card_cvc: None,
+                creds_identifier,
+                pm_token: None,
+                connector_customer_id: None,
+            },
+            None,
+        ))
     }
 }
 
@@ -172,18 +175,37 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsCancelRequest> for
         F: 'b + Send,
     {
         let cancellation_reason = payment_data.payment_attempt.cancellation_reason.clone();
-        payment_data.payment_attempt = db
-            .update_payment_attempt_with_attempt_id(
-                payment_data.payment_attempt,
-                storage::PaymentAttemptUpdate::VoidUpdate {
-                    status: enums::AttemptStatus::VoidInitiated,
-                    cancellation_reason,
-                },
-                storage_scheme,
-            )
-            .await
-            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
+        let (intent_status_update, attempt_status_update) =
+            if payment_data.payment_intent.status != enums::IntentStatus::RequiresCapture {
+                let payment_intent_update = storage::PaymentIntentUpdate::PGStatusUpdate {
+                    status: enums::IntentStatus::Cancelled,
+                };
+                (Some(payment_intent_update), enums::AttemptStatus::Voided)
+            } else {
+                (None, enums::AttemptStatus::VoidInitiated)
+            };
 
+        if let Some(payment_intent_update) = intent_status_update {
+            payment_data.payment_intent = db
+                .update_payment_intent(
+                    payment_data.payment_intent,
+                    payment_intent_update,
+                    storage_scheme,
+                )
+                .await
+                .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
+        }
+
+        db.update_payment_attempt_with_attempt_id(
+            payment_data.payment_attempt.clone(),
+            storage::PaymentAttemptUpdate::VoidUpdate {
+                status: attempt_status_update,
+                cancellation_reason,
+            },
+            storage_scheme,
+        )
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
         Ok((Box::new(self), payment_data))
     }
 }
diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs
index 4d985c095a2..92030dcaea9 100644
--- a/crates/router/src/routes/payments.rs
+++ b/crates/router/src/routes/payments.rs
@@ -623,7 +623,6 @@ pub async fn payments_cancel(
     let mut payload = json_payload.into_inner();
     let payment_id = path.into_inner();
     payload.payment_id = payment_id;
-
     api::server_wrap(
         flow,
         state.get_ref(),

requires_payment_method, requires_capture, requires_confirmation, requires_action

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

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

## Description
Previously while cancelling payment from some of the the payment intent statuses like requires_payment_method, requires_capture, requires_confirmation, requires_action there was an error thrown that these can't be cancelled as they haven't been authorized. Hence now we can cancel these payments too.
 
### Additional Changes

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


## Motivation and Context
As for the above statuses we aren't involving the connector and handling the requests ourselves in update method hence having a check and voding the payment attempt and cancelling the payment_intent status in DB.


## How did you test it?
Tested it by using postman as now we are able to cancel the payment in all those cases.


## 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
