From 652fae4fe9d1a9aeaacd87c6c3d2607cc7b71efc Mon Sep 17 00:00:00 2001 From: Anurag Thakur Date: Thu, 27 Mar 2025 16:49:36 +0530 Subject: [PATCH] feat(router): Add payment_methods_session_delete_payment_method endpoint [V2] (#7409) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- ...session--delete-a-saved-payment-method.mdx | 3 + api-reference-v2/mint.json | 3 +- api-reference-v2/openapi_spec.json | 79 ++++++++++++++++++- crates/api_models/src/payment_methods.rs | 10 ++- crates/openapi/src/openapi_v2.rs | 3 + crates/openapi/src/routes/payment_method.rs | 29 +++++++ crates/router/src/core/payment_methods.rs | 46 ++++++++++- crates/router/src/routes/app.rs | 5 +- crates/router/src/routes/lock_utils.rs | 1 + crates/router/src/routes/payment_methods.rs | 43 ++++++++++ crates/router_env/src/logger/types.rs | 2 + 11 files changed, 214 insertions(+), 10 deletions(-) create mode 100644 api-reference-v2/api-reference/payment-method-session/payment-method-session--delete-a-saved-payment-method.mdx diff --git a/api-reference-v2/api-reference/payment-method-session/payment-method-session--delete-a-saved-payment-method.mdx b/api-reference-v2/api-reference/payment-method-session/payment-method-session--delete-a-saved-payment-method.mdx new file mode 100644 index 0000000000..2f9e800ebe --- /dev/null +++ b/api-reference-v2/api-reference/payment-method-session/payment-method-session--delete-a-saved-payment-method.mdx @@ -0,0 +1,3 @@ +--- +openapi: delete /v2/payment-method-session/:id +--- diff --git a/api-reference-v2/mint.json b/api-reference-v2/mint.json index 2b0997326d..d0ad2e8799 100644 --- a/api-reference-v2/mint.json +++ b/api-reference-v2/mint.json @@ -67,7 +67,8 @@ "api-reference/payment-method-session/payment-method-session--retrieve", "api-reference/payment-method-session/payment-method-session--list-payment-methods", "api-reference/payment-method-session/payment-method-session--update-a-saved-payment-method", - "api-reference/payment-method-session/payment-method-session--confirm-a-payment-method-session" + "api-reference/payment-method-session/payment-method-session--confirm-a-payment-method-session", + "api-reference/payment-method-session/payment-method-session--delete-a-saved-payment-method" ] }, { diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index a9de9611e5..3604a1d910 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -2960,6 +2960,62 @@ "ephemeral_key": [] } ] + }, + "delete": { + "tags": [ + "Payment Method Session" + ], + "summary": "Payment Method Session - Delete a saved payment method", + "description": "Delete a saved payment method from the given payment method session.", + "operationId": "Delete a saved payment method", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The unique identifier for the Payment Method Session", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentMethodSessionDeleteSavedPaymentMethod" + }, + "examples": { + "Update the card holder name": { + "value": { + "payment_method_id": "12345_pm_0194b1ecabc172e28aeb71f70a4daba3" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "The payment method has been updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentMethodDeleteResponse" + } + } + } + }, + "404": { + "description": "The request is invalid" + } + }, + "security": [ + { + "ephemeral_key": [] + } + ] } }, "/v2/payment-method-session/:id/list-payment-methods": { @@ -4462,15 +4518,19 @@ "AuthenticationDetails": { "type": "object", "required": [ - "status", - "error" + "status" ], "properties": { "status": { "$ref": "#/components/schemas/IntentStatus" }, "error": { - "$ref": "#/components/schemas/ErrorDetails" + "allOf": [ + { + "$ref": "#/components/schemas/ErrorDetails" + } + ], + "nullable": true } } }, @@ -15633,6 +15693,19 @@ } } }, + "PaymentMethodSessionDeleteSavedPaymentMethod": { + "type": "object", + "required": [ + "payment_method_id" + ], + "properties": { + "payment_method_id": { + "type": "string", + "description": "The payment method id of the payment method to be updated", + "example": "12345_pm_01926c58bc6e77c09e809964e72af8c8" + } + } + }, "PaymentMethodSessionRequest": { "type": "object", "required": [ diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 56bffc0264..0a2d7dedd5 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -2781,6 +2781,14 @@ pub struct PaymentMethodSessionUpdateSavedPaymentMethod { pub payment_method_update_request: PaymentMethodUpdate, } +#[cfg(feature = "v2")] +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct PaymentMethodSessionDeleteSavedPaymentMethod { + /// The payment method id of the payment method to be updated + #[schema(value_type = String, example = "12345_pm_01926c58bc6e77c09e809964e72af8c8")] + pub payment_method_id: id_type::GlobalPaymentMethodId, +} + #[cfg(feature = "v2")] #[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)] pub struct PaymentMethodSessionConfirmRequest { @@ -2858,6 +2866,6 @@ pub struct AuthenticationDetails { pub status: common_enums::IntentStatus, /// Error details of the authentication - #[schema(value_type = ErrorDetails)] + #[schema(value_type = Option)] pub error: Option, } diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index 5b01911881..6e5eb0038f 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -143,6 +143,7 @@ Never share your secret api keys. Keep them guarded and secure. routes::payment_method::payment_method_session_retrieve, routes::payment_method::payment_method_session_list_payment_methods, routes::payment_method::payment_method_session_update_saved_payment_method, + routes::payment_method::payment_method_session_delete_saved_payment_method, routes::payment_method::payment_method_session_confirm, //Routes for refunds @@ -212,6 +213,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payment_methods::PaymentMethodCreate, api_models::payment_methods::PaymentMethodIntentCreate, api_models::payment_methods::PaymentMethodIntentConfirm, + api_models::payment_methods::AuthenticationDetails, api_models::payment_methods::PaymentMethodResponse, api_models::payment_methods::PaymentMethodResponseData, api_models::payment_methods::CustomerPaymentMethod, @@ -698,6 +700,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::feature_matrix::CardSpecificFeatures, api_models::feature_matrix::SupportedPaymentMethod, api_models::payment_methods::PaymentMethodSessionUpdateSavedPaymentMethod, + api_models::payment_methods::PaymentMethodSessionDeleteSavedPaymentMethod, common_utils::types::BrowserInformation, api_models::enums::TokenizationType, api_models::enums::NetworkTokenizationToggle, diff --git a/crates/openapi/src/routes/payment_method.rs b/crates/openapi/src/routes/payment_method.rs index cf1cd15346..6dcf3b6775 100644 --- a/crates/openapi/src/routes/payment_method.rs +++ b/crates/openapi/src/routes/payment_method.rs @@ -444,6 +444,35 @@ pub fn payment_method_session_list_payment_methods() {} )] pub fn payment_method_session_update_saved_payment_method() {} +/// Payment Method Session - Delete a saved payment method +/// +/// Delete a saved payment method from the given payment method session. +#[cfg(feature = "v2")] +#[utoipa::path( + delete, + path = "/v2/payment-method-session/:id", + params ( + ("id" = String, Path, description = "The unique identifier for the Payment Method Session"), + ), + request_body( + content = PaymentMethodSessionDeleteSavedPaymentMethod, + examples(( "Update the card holder name" = ( + value =json!( { + "payment_method_id": "12345_pm_0194b1ecabc172e28aeb71f70a4daba3", + } + ) + ))) + ), + responses( + (status = 200, description = "The payment method has been updated successfully", body = PaymentMethodDeleteResponse), + (status = 404, description = "The request is invalid") + ), + tag = "Payment Method Session", + operation_id = "Delete a saved payment method", + security(("ephemeral_key" = [])) +)] +pub fn payment_method_session_delete_saved_payment_method() {} + /// Card network tokenization - Create using raw card data /// /// Create a card network token for a customer and store it as a payment method. diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 27fb3959bf..f4ff34a296 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -2021,12 +2021,24 @@ pub async fn delete_payment_method( key_store: domain::MerchantKeyStore, merchant_account: domain::MerchantAccount, ) -> RouterResponse { - let db = state.store.as_ref(); - let key_manager_state = &(&state).into(); - let pm_id = id_type::GlobalPaymentMethodId::generate_from_string(pm_id.payment_method_id) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Unable to generate GlobalPaymentMethodId")?; + let response = delete_payment_method_core(state, pm_id, key_store, merchant_account).await?; + + Ok(services::ApplicationResponse::Json(response)) +} + +#[cfg(all(feature = "v2", feature = "payment_methods_v2"))] +#[instrument(skip_all)] +pub async fn delete_payment_method_core( + state: SessionState, + pm_id: id_type::GlobalPaymentMethodId, + key_store: domain::MerchantKeyStore, + merchant_account: domain::MerchantAccount, +) -> RouterResult { + let db = state.store.as_ref(); + let key_manager_state = &(&state).into(); let payment_method = db .find_payment_method( @@ -2084,7 +2096,7 @@ pub async fn delete_payment_method( let response = api::PaymentMethodDeleteResponse { id: pm_id }; - Ok(services::ApplicationResponse::Json(response)) + Ok(response) } #[cfg(feature = "v2")] @@ -2415,6 +2427,32 @@ pub async fn payment_methods_session_update_payment_method( Ok(services::ApplicationResponse::Json(updated_payment_method)) } +#[cfg(feature = "v2")] +pub async fn payment_methods_session_delete_payment_method( + state: SessionState, + key_store: domain::MerchantKeyStore, + merchant_account: domain::MerchantAccount, + pm_id: id_type::GlobalPaymentMethodId, + payment_method_session_id: id_type::GlobalPaymentMethodSessionId, +) -> RouterResponse { + let db = state.store.as_ref(); + let key_manager_state = &(&state).into(); + + // Validate if the session still exists + db.get_payment_methods_session(key_manager_state, &key_store, &payment_method_session_id) + .await + .to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError { + message: "payment methods session does not exist or has expired".to_string(), + }) + .attach_printable("Failed to retrieve payment methods session from db")?; + + let response = delete_payment_method_core(state, pm_id, key_store, merchant_account) + .await + .attach_printable("Failed to delete saved payment method")?; + + Ok(services::ApplicationResponse::Json(response)) +} + #[cfg(feature = "v2")] fn construct_zero_auth_payments_request( confirm_request: &payment_methods::PaymentMethodSessionConfirmRequest, diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 58acfa47d3..574b30f300 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -1332,7 +1332,10 @@ impl PaymentMethodSession { .service( web::resource("") .route(web::get().to(payment_methods::payment_methods_session_retrieve)) - .route(web::put().to(payment_methods::payment_methods_session_update)), + .route(web::put().to(payment_methods::payment_methods_session_update)) + .route(web::delete().to( + payment_methods::payment_method_session_delete_saved_payment_method, + )), ) .service(web::resource("/list-payment-methods").route( web::get().to(payment_methods::payment_method_session_list_payment_methods), diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs index 1cc3442b74..1c3e23c2b0 100644 --- a/crates/router/src/routes/lock_utils.rs +++ b/crates/router/src/routes/lock_utils.rs @@ -331,6 +331,7 @@ impl From for ApiIdentifier { | Flow::PaymentMethodSessionRetrieve | Flow::PaymentMethodSessionConfirm | Flow::PaymentMethodSessionUpdateSavedPaymentMethod + | Flow::PaymentMethodSessionDeleteSavedPaymentMethod | Flow::PaymentMethodSessionUpdate => Self::PaymentMethodSession, } } diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs index ec5e1dacf0..6b60a05c6c 100644 --- a/crates/router/src/routes/payment_methods.rs +++ b/crates/router/src/routes/payment_methods.rs @@ -1327,3 +1327,46 @@ pub async fn payment_method_session_update_saved_payment_method( )) .await } + +#[cfg(all(feature = "v2", feature = "payment_methods_v2"))] +#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodSessionUpdateSavedPaymentMethod))] +pub async fn payment_method_session_delete_saved_payment_method( + state: web::Data, + req: HttpRequest, + path: web::Path, + json_payload: web::Json< + api_models::payment_methods::PaymentMethodSessionDeleteSavedPaymentMethod, + >, +) -> HttpResponse { + let flow = Flow::PaymentMethodSessionDeleteSavedPaymentMethod; + let payload = json_payload.into_inner(); + let payment_method_session_id = path.into_inner(); + + let request = PaymentMethodsSessionGenericRequest { + payment_method_session_id: payment_method_session_id.clone(), + request: payload, + }; + + Box::pin(api::server_wrap( + flow, + state, + &req, + request, + |state, auth: auth::AuthenticationData, request, _| { + payment_methods_routes::payment_methods_session_delete_payment_method( + state, + auth.key_store, + auth.merchant_account, + request.request.payment_method_id, + request.payment_method_session_id, + ) + }, + &auth::V2ClientAuth( + common_utils::types::authentication::ResourceId::PaymentMethodSession( + payment_method_session_id, + ), + ), + api_locking::LockAction::NotApplicable, + )) + .await +} diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs index 26f88217e4..890dcae12c 100644 --- a/crates/router_env/src/logger/types.rs +++ b/crates/router_env/src/logger/types.rs @@ -566,6 +566,8 @@ pub enum Flow { PaymentMethodSessionUpdate, /// Update a saved payment method using the payment methods session PaymentMethodSessionUpdateSavedPaymentMethod, + /// Delete a saved payment method using the payment methods session + PaymentMethodSessionDeleteSavedPaymentMethod, /// Confirm a payment method session with payment method data PaymentMethodSessionConfirm, /// Create Cards Info flow