Bug: [BUG] Payout in stages



### Bug Description

- Default status (based on different conditions) does not update in payouts table
- Payout status updation during confirmation happens prior to validating the request
- Helper functions for deciding whether or not to execute different payout flows does not have the updated status list

Payout in stages is broken.

### Expected Behavior

Let me create a payout, be able to update it, confirm it and finally fulfill it.

### Actual Behavior

It's letting me create a payout, while updating, it does not let me even access the API as the status conditions do not match (since default status was not updated in payouts table). It also does not respect the `confirm` field which is responsible for deciding and triggering core payout flows.

### Steps To Reproduce

- Create a payout with `confirm: false`
- Try to update this payout (you shall see an error)

### Context For The Bug

Not needed.

### Environment

Not needed.

### Have you spent some time checking if this bug has been raised before?

- [X] I checked and didn't find a 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)

### Are you willing to submit a PR?

Yes, I am willing to submit a PR!
diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs
index f6f78094943..7d5dd908fdb 100644
--- a/crates/router/src/core/payouts.rs
+++ b/crates/router/src/core/payouts.rs
@@ -368,8 +368,6 @@ pub async fn payouts_confirm_core(
     let payout_attempt = payout_data.payout_attempt.to_owned();
     let status = payout_attempt.status;
 
-    helpers::update_payouts_and_payout_attempt(&mut payout_data, &merchant_account, &req, &state)
-        .await?;
     helpers::validate_payout_status_against_not_allowed_statuses(
         &status,
         &[
@@ -384,10 +382,11 @@ pub async fn payouts_confirm_core(
         "confirm",
     )?;
 
-    // Update payout link's status
+    helpers::update_payouts_and_payout_attempt(&mut payout_data, &merchant_account, &req, &state)
+        .await?;
+
     let db = &*state.store;
 
-    // payout_data.payout_link
     payout_data.payout_link = payout_data
         .payout_link
         .clone()
@@ -467,15 +466,17 @@ pub async fn payouts_update_core(
     )
     .await?;
 
-    payouts_core(
-        &state,
-        &merchant_account,
-        &key_store,
-        &mut payout_data,
-        req.routing.clone(),
-        req.connector.clone(),
-    )
-    .await?;
+    if let Some(true) = payout_data.payouts.confirm {
+        payouts_core(
+            &state,
+            &merchant_account,
+            &key_store,
+            &mut payout_data,
+            req.routing.clone(),
+            req.connector.clone(),
+        )
+        .await?;
+    }
 
     response_handler(&merchant_account, &payout_data).await
 }
@@ -2052,6 +2053,18 @@ pub async fn payout_create_db_entries(
         format!("payout_{payout_id}_secret").as_str(),
     );
     let amount = MinorUnit::from(req.amount.unwrap_or(api::Amount::Zero));
+    let status = if req.payout_method_data.is_some()
+        || req.payout_token.is_some()
+        || stored_payout_method_data.is_some()
+    {
+        match req.confirm {
+            Some(true) => storage_enums::PayoutStatus::RequiresCreation,
+            _ => storage_enums::PayoutStatus::RequiresConfirmation,
+        }
+    } else {
+        storage_enums::PayoutStatus::RequiresPayoutMethodData
+    };
+
     let payouts_req = storage::PayoutsNew {
         payout_id: payout_id.to_string(),
         merchant_id: merchant_id.to_string(),
@@ -2076,6 +2089,7 @@ pub async fn payout_create_db_entries(
             .map(|link_data| link_data.link_id.clone()),
         client_secret: Some(client_secret),
         priority: req.priority,
+        status,
         ..Default::default()
     };
     let payouts = db
@@ -2086,17 +2100,6 @@ pub async fn payout_create_db_entries(
         })
         .attach_printable("Error inserting payouts in db")?;
     // Make payout_attempt entry
-    let status = if req.payout_method_data.is_some()
-        || req.payout_token.is_some()
-        || stored_payout_method_data.is_some()
-    {
-        match req.confirm {
-            Some(true) => storage_enums::PayoutStatus::RequiresCreation,
-            _ => storage_enums::PayoutStatus::RequiresConfirmation,
-        }
-    } else {
-        storage_enums::PayoutStatus::RequiresPayoutMethodData
-    };
     let payout_attempt_id = utils::get_payment_attempt_id(payout_id, 1);
 
     let payout_attempt_req = storage::PayoutAttemptNew {
diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs
index ba00370e881..423e92fafc3 100644
--- a/crates/router/src/core/payouts/helpers.rs
+++ b/crates/router/src/core/payouts/helpers.rs
@@ -880,9 +880,12 @@ pub async fn get_gsm_record(
 }
 
 pub fn is_payout_initiated(status: api_enums::PayoutStatus) -> bool {
-    matches!(
+    !matches!(
         status,
-        api_enums::PayoutStatus::Pending | api_enums::PayoutStatus::RequiresFulfillment
+        api_enums::PayoutStatus::RequiresCreation
+            | api_enums::PayoutStatus::RequiresConfirmation
+            | api_enums::PayoutStatus::RequiresPayoutMethodData
+            | api_enums::PayoutStatus::RequiresVendorAccountCreation
     )
 }
 
@@ -903,10 +906,13 @@ pub(crate) fn validate_payout_status_against_not_allowed_statuses(
 pub fn is_payout_terminal_state(status: api_enums::PayoutStatus) -> bool {
     !matches!(
         status,
-        api_enums::PayoutStatus::Pending
-            | api_enums::PayoutStatus::RequiresCreation
-            | api_enums::PayoutStatus::RequiresFulfillment
+        api_enums::PayoutStatus::RequiresCreation
+            | api_enums::PayoutStatus::RequiresConfirmation
             | api_enums::PayoutStatus::RequiresPayoutMethodData
+            | api_enums::PayoutStatus::RequiresVendorAccountCreation
+            // Initiated by the underlying connector
+            | api_enums::PayoutStatus::Pending
+            | api_enums::PayoutStatus::RequiresFulfillment
     )
 }
 
@@ -923,7 +929,9 @@ pub fn is_eligible_for_local_payout_cancellation(status: api_enums::PayoutStatus
     matches!(
         status,
         api_enums::PayoutStatus::RequiresCreation
-            | api_enums::PayoutStatus::RequiresPayoutMethodData,
+            | api_enums::PayoutStatus::RequiresConfirmation
+            | api_enums::PayoutStatus::RequiresPayoutMethodData
+            | api_enums::PayoutStatus::RequiresVendorAccountCreation
     )
 }
 

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

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

## Description
This PR fixes below bugs

- default status (based on different conditions) does not update in `payouts` table
- payout status updation during confirmation happens prior to validating the request
- helper functions for deciding whether or not to execute different payout flows does not have the updated status list 


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

Tested locally using payout's test suite.


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

1. Create a payout using confirm: false, auto_fulfill: false
```
curl --location 'https://heard-directly-trademarks-diana.trycloudflare.com/payouts/create' \
--header 'x-feature: integ-custom' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_N4b6S09H8f5CHy1vvGEEyvyJcUqcs64R84eVkCtdBr3iTYFOGhCHieJlkoJUSs7w' \
--data-raw '{
    "amount": 1,
    "currency": "EUR",
    "customer_id": "cus_ZcGmeCSo9O0YMHx8S9KT",
    "email": "payout_customer@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payout request",
    "payout_type": "wallet",
    "payout_method_data": {
        "wallet": {
            "paypal": {
                "email": "example@example.com"
            }
        }
    },
    "connector": [
        "adyen"
    ],
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "CA",
            "zip": "94122",
            "country": "US",
            "first_name": "John",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "entity_type": "NaturalPerson",
    "recurring": true,
    "metadata": {
        "ref": "123"
    },
    "confirm": false,
    "auto_fulfill": false
}'
```

2. Confirm payout
```
curl --location 'https://heard-directly-trademarks-diana.trycloudflare.com/payouts/46e549bf-8f7c-491f-96c7-f79087074b3d/confirm' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_N4b6S09H8f5CHy1vvGEEyvyJcUqcs64R84eVkCtdBr3iTYFOGhCHieJlkoJUSs7w' \
--data '{
}'
```

3. Fulfill payout
```
curl --location 'https://heard-directly-trademarks-diana.trycloudflare.com/payouts/46e549bf-8f7c-491f-96c7-f79087074b3d/fulfill' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_N4b6S09H8f5CHy1vvGEEyvyJcUqcs64R84eVkCtdBr3iTYFOGhCHieJlkoJUSs7w' \
--data '{
}'
```

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