Bug: [REFACTOR] update api contract for payment methods update endpoint



Remove unused fields from update payment method request and update the open api spec
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index b7a58b3b5b6..e045cf2c42d 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -88,24 +88,6 @@ pub struct PaymentMethodUpdate {
     "card_holder_name": "John Doe"}))]
     pub card: Option<CardDetailUpdate>,
 
-    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
-    #[schema(value_type = Option<CardNetwork>,example = "Visa")]
-    pub card_network: Option<api_enums::CardNetwork>,
-
-    /// Payment method details from locker
-    #[cfg(feature = "payouts")]
-    #[schema(value_type = Option<Bank>)]
-    pub bank_transfer: Option<payouts::Bank>,
-
-    /// Payment method details from locker
-    #[cfg(feature = "payouts")]
-    #[schema(value_type = Option<Wallet>)]
-    pub wallet: Option<payouts::Wallet>,
-
-    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
-    #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
-    pub metadata: Option<pii::SecretSerdeValue>,
-
     /// This is a 15 minute expiry token which shall be used from the client to authenticate and perform sessions from the SDK
     #[schema(max_length = 30, min_length = 30, example = "secret_k2uj3he2893eiu2d")]
     pub client_secret: Option<String>,
diff --git a/crates/openapi/src/routes/payment_method.rs b/crates/openapi/src/routes/payment_method.rs
index 07e6cc35903..3bc593aa5b2 100644
--- a/crates/openapi/src/routes/payment_method.rs
+++ b/crates/openapi/src/routes/payment_method.rs
@@ -138,7 +138,7 @@ pub async fn payment_method_retrieve_api() {}
 /// This API is useful for use cases such as updating the card number for expired cards to prevent discontinuity in recurring payments.
 #[utoipa::path(
     post,
-    path = "/payment_methods/{method_id}",
+    path = "/payment_methods/{method_id}/update",
     params (
         ("method_id" = String, Path, description = "The unique identifier for the Payment Method"),
     ),
@@ -149,7 +149,7 @@ pub async fn payment_method_retrieve_api() {}
     ),
     tag = "Payment Methods",
     operation_id = "Update a Payment method",
-    security(("api_key" = []))
+    security(("api_key" = []), ("publishable_key" = []))
 )]
 pub async fn payment_method_update_api() {}
 
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index 8c946630c8a..307f2dcd085 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -775,6 +775,14 @@ pub async fn update_customer_payment_method(
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
 
+        if let Some(cs) = &req.client_secret {
+            let is_client_secret_expired = authenticate_pm_client_secret_and_check_expiry(cs, &pm)?;
+
+            if is_client_secret_expired {
+                return Err((errors::ApiErrorResponse::ClientSecretExpired).into());
+            };
+        };
+
         if pm.status == enums::PaymentMethodStatus::AwaitingData {
             return Err(report!(errors::ApiErrorResponse::NotSupported {
                 message: "Payment method is awaiting data so it cannot be updated".into()
@@ -849,18 +857,15 @@ pub async fn update_customer_payment_method(
                 payment_method_issuer: pm.payment_method_issuer.clone(),
                 payment_method_issuer_code: pm.payment_method_issuer_code,
                 #[cfg(feature = "payouts")]
-                bank_transfer: req.bank_transfer,
+                bank_transfer: None,
                 card: Some(updated_card_details.clone()),
                 #[cfg(feature = "payouts")]
-                wallet: req.wallet,
-                metadata: req.metadata,
+                wallet: None,
+                metadata: None,
                 customer_id: Some(pm.customer_id.clone()),
                 client_secret: pm.client_secret.clone(),
                 payment_method_data: None,
-                card_network: req
-                    .card_network
-                    .as_ref()
-                    .map(|card_network| card_network.to_string()),
+                card_network: None,
             };
             new_pm.validate()?;
 
diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json
index d9061baebb3..0c3893c4635 100644
--- a/openapi/openapi_spec.json
+++ b/openapi/openapi_spec.json
@@ -2612,13 +2612,13 @@
           }
         ]
       },
-      "post": {
+      "delete": {
         "tags": [
           "Payment Methods"
         ],
-        "summary": "Payment Method - Update",
-        "description": "Payment Method - Update\n\nUpdate an existing payment method of a customer.\nThis API is useful for use cases such as updating the card number for expired cards to prevent discontinuity in recurring payments.",
-        "operationId": "Update a Payment method",
+        "summary": "Payment Method - Delete",
+        "description": "Payment Method - Delete\n\nDeletes a payment method of a customer.",
+        "operationId": "Delete a Payment method",
         "parameters": [
           {
             "name": "method_id",
@@ -2630,23 +2630,13 @@
             }
           }
         ],
-        "requestBody": {
-          "content": {
-            "application/json": {
-              "schema": {
-                "$ref": "#/components/schemas/PaymentMethodUpdate"
-              }
-            }
-          },
-          "required": true
-        },
         "responses": {
           "200": {
-            "description": "Payment Method updated",
+            "description": "Payment Method deleted",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/PaymentMethodResponse"
+                  "$ref": "#/components/schemas/PaymentMethodDeleteResponse"
                 }
               }
             }
@@ -2660,14 +2650,16 @@
             "api_key": []
           }
         ]
-      },
-      "delete": {
+      }
+    },
+    "/payment_methods/{method_id}/update": {
+      "post": {
         "tags": [
           "Payment Methods"
         ],
-        "summary": "Payment Method - Delete",
-        "description": "Payment Method - Delete\n\nDeletes a payment method of a customer.",
-        "operationId": "Delete a Payment method",
+        "summary": "Payment Method - Update",
+        "description": "Payment Method - Update\n\nUpdate an existing payment method of a customer.\nThis API is useful for use cases such as updating the card number for expired cards to prevent discontinuity in recurring payments.",
+        "operationId": "Update a Payment method",
         "parameters": [
           {
             "name": "method_id",
@@ -2679,13 +2671,23 @@
             }
           }
         ],
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/PaymentMethodUpdate"
+              }
+            }
+          },
+          "required": true
+        },
         "responses": {
           "200": {
-            "description": "Payment Method deleted",
+            "description": "Payment Method updated",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/PaymentMethodDeleteResponse"
+                  "$ref": "#/components/schemas/PaymentMethodResponse"
                 }
               }
             }
@@ -2697,6 +2699,9 @@
         "security": [
           {
             "api_key": []
+          },
+          {
+            "publishable_key": []
           }
         ]
       }
@@ -13258,35 +13263,6 @@
             ],
             "nullable": true
           },
-          "card_network": {
-            "allOf": [
-              {
-                "$ref": "#/components/schemas/CardNetwork"
-              }
-            ],
-            "nullable": true
-          },
-          "bank_transfer": {
-            "allOf": [
-              {
-                "$ref": "#/components/schemas/Bank"
-              }
-            ],
-            "nullable": true
-          },
-          "wallet": {
-            "allOf": [
-              {
-                "$ref": "#/components/schemas/Wallet"
-              }
-            ],
-            "nullable": true
-          },
-          "metadata": {
-            "type": "object",
-            "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.",
-            "nullable": true
-          },
           "client_secret": {
             "type": "string",
             "description": "This is a 15 minute expiry token which shall be used from the client to authenticate and perform sessions from the SDK",

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

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

## Description
<!-- Describe your changes in detail -->
This PR updates the api contract for payment methods update endpoint and removes few unused fields. This PR adds the missing client secret validation for update endpoint

### Additional Changes

- [x] 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).
-->


## 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_methods/:id/update` endpoint have to be tested 
1. Create a customer

```
curl --location 'http://localhost:8080/customers' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_kxFm2YwE2I8srj4W96v9C5XkZl8VputfqADhqdumTgJFLpuXpgU5I2NlTHOM3ply' \
--data-raw '{
    "email": "guest@example.com",
    "name": "new_cus",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "First customer",
    "address": {
        "line1": "1467",
        "line2": "Harrison Street",
        "line3": "Harrison Street",
        "city": "San Fransico",
        "state": "California",
        "zip": "94122",
        "country": "US",
        "first_name": "John",
        "last_name": "Doe"
    },
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    }
}'
```

2. Create a payment method (use `/payment_methods` endpoint)

```
curl --location 'http://localhost:8080/payment_methods' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_kxFm2YwE2I8srj4W96v9C5XkZl8VputfqADhqdumTgJFLpuXpgU5I2NlTHOM3ply' \
--data '{
    "payment_method": "card",
    "payment_method_type": "credit",
    "payment_method_issuer": "Visa",
    "card": {
        "card_number": "4111111111111111",
        "card_exp_month": "10",
        "card_exp_year": "40",
        "card_holder_name": "John"
    },
    "customer_id": "cus_a05bSJXwCoO01KZmWOdX",
    "metadata": {
        "city": "NY",
        "unit": "245"
    }
}'
```

![image](https://github.com/juspay/hyperswitch/assets/70657455/01a8e9c6-7a07-43e6-b95e-7491099ec385)


3. Update the metadata (say `expiry_year` or `nick_name`) using `/payment_methods/:id/update`

```
curl --location 'http://localhost:8080/payment_methods/pm_BuRzGWSAgkNVLRgzyfuu/update' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_kxFm2YwE2I8srj4W96v9C5XkZl8VputfqADhqdumTgJFLpuXpgU5I2NlTHOM3ply' \
--data '{
    "card": {
        "nick_name": "Rock"
    }
}'
```

![image](https://github.com/juspay/hyperswitch/assets/70657455/f538ea8d-3f51-4a5a-9d4d-4b4dd8d55696)

4. Do `list_payment_methods_for_customers` and verify whether updation of metadata is successful.

5. Also test the above flow with client secret auth in SDK

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