refactor(payment_methods): prevent deletion of default payment method for a customer (#3964)

This commit is contained in:
Chethan Rao
2024-03-06 19:05:28 +05:30
committed by GitHub
parent 3806cd35c7
commit db39bb0a3c
5 changed files with 29 additions and 2 deletions

View File

@ -251,6 +251,8 @@ pub enum StripeErrorCode {
InvalidConnectorConfiguration { config: String },
#[error(error_type = StripeErrorType::HyperswitchError, code = "HE_01", message = "Failed to convert currency to minor unit")]
CurrencyConversionFailed,
#[error(error_type = StripeErrorType::InvalidRequestError, code = "IR_25", message = "Cannot delete the default payment method")]
PaymentMethodDeleteFailed,
// [#216]: https://github.com/juspay/hyperswitch/issues/216
// Implement the remaining stripe error codes
@ -618,6 +620,7 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
Self::InvalidConnectorConfiguration { config }
}
errors::ApiErrorResponse::CurrencyConversionFailed => Self::CurrencyConversionFailed,
errors::ApiErrorResponse::PaymentMethodDeleteFailed => Self::PaymentMethodDeleteFailed,
}
}
}
@ -686,7 +689,8 @@ impl actix_web::ResponseError for StripeErrorCode {
| Self::DuplicateCustomer
| Self::PaymentMethodUnactivated
| Self::InvalidConnectorConfiguration { .. }
| Self::CurrencyConversionFailed => StatusCode::BAD_REQUEST,
| Self::CurrencyConversionFailed
| Self::PaymentMethodDeleteFailed => StatusCode::BAD_REQUEST,
Self::RefundFailed
| Self::PayoutFailed
| Self::PaymentLinkNotFound

View File

@ -252,6 +252,8 @@ pub enum ApiErrorResponse {
InvalidConnectorConfiguration { config: String },
#[error(error_type = ErrorType::ValidationError, code = "HE_01", message = "Failed to convert currency to minor unit")]
CurrencyConversionFailed,
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_25", message = "Cannot delete the default payment method")]
PaymentMethodDeleteFailed,
}
impl PTError for ApiErrorResponse {

View File

@ -281,6 +281,9 @@ impl ErrorSwitch<api_models::errors::types::ApiErrorResponse> for ApiErrorRespon
Self::CurrencyConversionFailed => {
AER::Unprocessable(ApiError::new("HE", 2, "Failed to convert currency to minor unit", None))
}
Self::PaymentMethodDeleteFailed => {
AER::BadRequest(ApiError::new("IR", 25, "Cannot delete the default payment method", None))
}
}
}
}

View File

@ -3428,6 +3428,7 @@ pub async fn delete_payment_method(
state: routes::AppState,
merchant_account: domain::MerchantAccount,
pm_id: api::PaymentMethodId,
key_store: domain::MerchantKeyStore,
) -> errors::RouterResponse<api::PaymentMethodDeleteResponse> {
let db = state.store.as_ref();
let key = db
@ -3435,6 +3436,21 @@ pub async fn delete_payment_method(
.await
.to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
let customer = db
.find_customer_by_customer_id_merchant_id(
&key.customer_id,
&merchant_account.merchant_id,
&key_store,
)
.await
.to_not_found_response(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Customer not found for the payment method")?;
utils::when(
customer.default_payment_method_id.as_ref() == Some(&pm_id.payment_method_id),
|| Err(errors::ApiErrorResponse::PaymentMethodDeleteFailed),
)?;
if key.payment_method == enums::PaymentMethod::Card {
let response = delete_card_from_locker(
&state,

View File

@ -253,7 +253,9 @@ pub async fn payment_method_delete_api(
state,
&req,
pm,
|state, auth, req| cards::delete_payment_method(state, auth.merchant_account, req),
|state, auth, req| {
cards::delete_payment_method(state, auth.merchant_account, req, auth.key_store)
},
&auth::ApiKeyAuth,
api_locking::LockAction::NotApplicable,
))