use common_utils::errors::ErrorSwitch; use hyperswitch_domain_models::errors::api_error_response as errors; use crate::core::errors::CustomersErrorResponse; #[derive(Debug, router_derive::ApiError, Clone)] #[error(error_type_enum = StripeErrorType)] pub enum StripeErrorCode { /* "error": { "message": "Invalid API Key provided: sk_jkjgs****nlgs", "type": "invalid_request_error" } */ #[error( error_type = StripeErrorType::InvalidRequestError, code = "IR_01", message = "Invalid API Key provided" )] Unauthorized, #[error(error_type = StripeErrorType::InvalidRequestError, code = "IR_02", message = "Unrecognized request URL.")] InvalidRequestUrl, #[error(error_type = StripeErrorType::InvalidRequestError, code = "parameter_missing", message = "Missing required param: {field_name}.")] ParameterMissing { field_name: String, param: String }, #[error( error_type = StripeErrorType::InvalidRequestError, code = "parameter_unknown", message = "{field_name} contains invalid data. Expected format is {expected_format}." )] ParameterUnknown { field_name: String, expected_format: String, }, #[error(error_type = StripeErrorType::InvalidRequestError, code = "IR_06", message = "The refund amount exceeds the amount captured.")] RefundAmountExceedsPaymentAmount { param: String }, #[error(error_type = StripeErrorType::ApiError, code = "payment_intent_authentication_failure", message = "Payment failed while processing with connector. Retry payment.")] PaymentIntentAuthenticationFailure { data: Option }, #[error(error_type = StripeErrorType::ApiError, code = "payment_intent_payment_attempt_failed", message = "Capture attempt failed while processing with connector.")] PaymentIntentPaymentAttemptFailed { data: Option }, #[error(error_type = StripeErrorType::ApiError, code = "dispute_failure", message = "Dispute failed while processing with connector. Retry operation.")] DisputeFailed { data: Option }, #[error(error_type = StripeErrorType::CardError, code = "expired_card", message = "Card Expired. Please use another card")] ExpiredCard, #[error(error_type = StripeErrorType::CardError, code = "invalid_card_type", message = "Card data is invalid")] InvalidCardType, #[error( error_type = StripeErrorType::ConnectorError, code = "invalid_wallet_token", message = "Invalid {wallet_name} wallet token" )] InvalidWalletToken { wallet_name: String }, #[error(error_type = StripeErrorType::ApiError, code = "refund_failed", message = "refund has failed")] RefundFailed, // stripe error code #[error(error_type = StripeErrorType::ApiError, code = "payout_failed", message = "payout has failed")] PayoutFailed, #[error(error_type = StripeErrorType::ApiError, code = "external_vault_failed", message = "external vault has failed")] ExternalVaultFailed, #[error(error_type = StripeErrorType::ApiError, code = "internal_server_error", message = "Server is down")] InternalServerError, #[error(error_type = StripeErrorType::ApiError, code = "internal_server_error", message = "Server is down")] DuplicateRefundRequest, #[error(error_type = StripeErrorType::InvalidRequestError, code = "active_mandate", message = "Customer has active mandate")] MandateActive, #[error(error_type = StripeErrorType::InvalidRequestError, code = "customer_redacted", message = "Customer has redacted")] CustomerRedacted, #[error(error_type = StripeErrorType::InvalidRequestError, code = "customer_already_exists", message = "Customer with the given customer_id already exists")] DuplicateCustomer, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such refund")] RefundNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "client_secret_invalid", message = "Expected client secret to be included in the request")] ClientSecretNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such customer")] CustomerNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such config")] ConfigNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "duplicate_resource", message = "Duplicate config")] DuplicateConfig, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such payment")] PaymentNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such payment method")] PaymentMethodNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "{message}")] GenericNotFoundError { message: String }, #[error(error_type = StripeErrorType::InvalidRequestError, code = "duplicate_resource", message = "{message}")] GenericDuplicateError { message: String }, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such merchant account")] MerchantAccountNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such resource ID")] ResourceIdNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "Merchant connector account does not exist in our records")] MerchantConnectorAccountNotFound { id: String }, #[error(error_type = StripeErrorType::InvalidRequestError, code = "invalid_request", message = "The merchant connector account is disabled")] MerchantConnectorAccountDisabled, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such mandate")] MandateNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such API key")] ApiKeyNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such payout")] PayoutNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "resource_missing", message = "No such event")] EventNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "token_already_used", message = "Duplicate payout request")] DuplicatePayout { payout_id: String }, #[error(error_type = StripeErrorType::InvalidRequestError, code = "parameter_missing", message = "Return url is not available")] ReturnUrlUnavailable, #[error(error_type = StripeErrorType::InvalidRequestError, code = "token_already_used", message = "duplicate merchant account")] DuplicateMerchantAccount, #[error(error_type = StripeErrorType::InvalidRequestError, code = "token_already_used", message = "The merchant connector account with the specified profile_id '{profile_id}' and connector_label '{connector_label}' already exists in our records")] DuplicateMerchantConnectorAccount { profile_id: String, connector_label: String, }, #[error(error_type = StripeErrorType::InvalidRequestError, code = "token_already_used", message = "duplicate payment method")] DuplicatePaymentMethod, #[error(error_type = StripeErrorType::InvalidRequestError, code = "" , message = "deserialization failed: {error_message}")] SerdeQsError { error_message: String, param: Option, }, #[error(error_type = StripeErrorType::InvalidRequestError, code = "payment_intent_invalid_parameter" , message = "The client_secret provided does not match the client_secret associated with the PaymentIntent.")] PaymentIntentInvalidParameter { param: String }, #[error( error_type = StripeErrorType::InvalidRequestError, code = "IR_05", message = "{message}" )] InvalidRequestData { message: String }, #[error( error_type = StripeErrorType::InvalidRequestError, code = "IR_10", message = "{message}" )] PreconditionFailed { message: String }, #[error( error_type = StripeErrorType::InvalidRequestError, code = "", message = "The payment has not succeeded yet" )] PaymentFailed, #[error( error_type = StripeErrorType::InvalidRequestError, code = "", message = "The verification did not succeeded" )] VerificationFailed { data: Option }, #[error( error_type = StripeErrorType::InvalidRequestError, code = "", message = "Reached maximum refund attempts" )] MaximumRefundCount, #[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "Duplicate mandate request. Mandate already attempted with the Mandate ID.")] DuplicateMandate, #[error(error_type= StripeErrorType::InvalidRequestError, code = "", message = "Successful payment not found for the given payment id")] SuccessfulPaymentNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "Address does not exist in our records.")] AddressNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "This PaymentIntent could not be {current_flow} because it has a {field_name} of {current_value}. The expected state is {states}.")] PaymentIntentUnexpectedState { current_flow: String, field_name: String, current_value: String, states: String, }, #[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "The mandate information is invalid. {message}")] PaymentIntentMandateInvalid { message: String }, #[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "The payment with the specified payment_id already exists in our records.")] DuplicatePayment { payment_id: common_utils::id_type::PaymentId, }, #[error(error_type = StripeErrorType::ConnectorError, code = "", message = "{code}: {message}")] ExternalConnectorError { code: String, message: String, connector: String, status_code: u16, }, #[error(error_type = StripeErrorType::CardError, code = "", message = "{code}: {message}")] PaymentBlockedError { code: u16, message: String, status: String, reason: String, }, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "The connector provided in the request is incorrect or not available")] IncorrectConnectorNameGiven, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "No such {object}: '{id}'")] ResourceMissing { object: String, id: String }, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File validation failed")] FileValidationFailed, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File not found in the request")] MissingFile, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File puropse not found in the request")] MissingFilePurpose, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File content type not found")] MissingFileContentType, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "Dispute id not found in the request")] MissingDisputeId, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File does not exists in our records")] FileNotFound, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "File not available")] FileNotAvailable, #[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "Not Supported because provider is not Router")] FileProviderNotSupported, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "There was an issue with processing webhooks")] WebhookProcessingError, #[error(error_type = StripeErrorType::InvalidRequestError, code = "payment_method_unactivated", message = "The operation cannot be performed as the payment method used has not been activated. Activate the payment method in the Dashboard, then try again.")] PaymentMethodUnactivated, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "{message}")] HyperswitchUnprocessableEntity { message: String }, #[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "{message}")] CurrencyNotSupported { message: String }, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "Payment Link does not exist in our records")] PaymentLinkNotFound, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "Resource Busy. Please try again later")] LockTimeout, #[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "Merchant connector account is configured with invalid {config}")] 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, #[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "Extended card info does not exist")] ExtendedCardInfoNotFound, #[error(error_type = StripeErrorType::InvalidRequestError, code = "not_configured", message = "{message}")] LinkConfigurationError { message: String }, #[error(error_type = StripeErrorType::ConnectorError, code = "CE", message = "{reason} as data mismatched for {field_names}")] IntegrityCheckFailed { reason: String, field_names: String, connector_transaction_id: Option, }, #[error(error_type = StripeErrorType::InvalidRequestError, code = "IR_28", message = "Invalid tenant")] InvalidTenant, #[error(error_type = StripeErrorType::HyperswitchError, code = "HE_01", message = "Failed to convert amount to {amount_type} type")] AmountConversionFailed { amount_type: &'static str }, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "Platform Bad Request")] PlatformBadRequest, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "Platform Unauthorized Request")] PlatformUnauthorizedRequest, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "Profile Acquirer not found")] ProfileAcquirerNotFound, // [#216]: https://github.com/juspay/hyperswitch/issues/216 // Implement the remaining stripe error codes /* AccountCountryInvalidAddress, AccountErrorCountryChangeRequiresAdditionalSteps, AccountInformationMismatch, AccountInvalid, AccountNumberInvalid, AcssDebitSessionIncomplete, AlipayUpgradeRequired, AmountTooLarge, AmountTooSmall, ApiKeyExpired, AuthenticationRequired, BalanceInsufficient, BankAccountBadRoutingNumbers, BankAccountDeclined, BankAccountExists, BankAccountUnusable, BankAccountUnverified, BankAccountVerificationFailed, BillingInvalidMandate, BitcoinUpgradeRequired, CardDeclineRateLimitExceeded, CardDeclined, CardholderPhoneNumberRequired, ChargeAlreadyCaptured, ChargeAlreadyRefunded, ChargeDisputed, ChargeExceedsSourceLimit, ChargeExpiredForCapture, ChargeInvalidParameter, ClearingCodeUnsupported, CountryCodeInvalid, CountryUnsupported, CouponExpired, CustomerMaxPaymentMethods, CustomerMaxSubscriptions, DebitNotAuthorized, EmailInvalid, ExpiredCard, IdempotencyKeyInUse, IncorrectAddress, IncorrectCvc, IncorrectNumber, IncorrectZip, InstantPayoutsConfigDisabled, InstantPayoutsCurrencyDisabled, InstantPayoutsLimitExceeded, InstantPayoutsUnsupported, InsufficientFunds, IntentInvalidState, IntentVerificationMethodMissing, InvalidCardType, InvalidCharacters, InvalidChargeAmount, InvalidCvc, InvalidExpiryMonth, InvalidExpiryYear, InvalidNumber, InvalidSourceUsage, InvoiceNoCustomerLineItems, InvoiceNoPaymentMethodTypes, InvoiceNoSubscriptionLineItems, InvoiceNotEditable, InvoiceOnBehalfOfNotEditable, InvoicePaymentIntentRequiresAction, InvoiceUpcomingNone, LivemodeMismatch, LockTimeout, Missing, NoAccount, NotAllowedOnStandardAccount, OutOfInventory, ParameterInvalidEmpty, ParameterInvalidInteger, ParameterInvalidStringBlank, ParameterInvalidStringEmpty, ParametersExclusive, PaymentIntentActionRequired, PaymentIntentIncompatiblePaymentMethod, PaymentIntentInvalidParameter, PaymentIntentKonbiniRejectedConfirmationNumber, PaymentIntentPaymentAttemptExpired, PaymentIntentUnexpectedState, PaymentMethodBankAccountAlreadyVerified, PaymentMethodBankAccountBlocked, PaymentMethodBillingDetailsAddressMissing, PaymentMethodCurrencyMismatch, PaymentMethodInvalidParameter, PaymentMethodInvalidParameterTestmode, PaymentMethodMicrodepositFailed, PaymentMethodMicrodepositVerificationAmountsInvalid, PaymentMethodMicrodepositVerificationAmountsMismatch, PaymentMethodMicrodepositVerificationAttemptsExceeded, PaymentMethodMicrodepositVerificationDescriptorCodeMismatch, PaymentMethodMicrodepositVerificationTimeout, PaymentMethodProviderDecline, PaymentMethodProviderTimeout, PaymentMethodUnexpectedState, PaymentMethodUnsupportedType, PayoutsNotAllowed, PlatformAccountRequired, PlatformApiKeyExpired, PostalCodeInvalid, ProcessingError, ProductInactive, RateLimit, ReferToCustomer, RefundDisputedPayment, ResourceAlreadyExists, ResourceMissing, ReturnIntentAlreadyProcessed, RoutingNumberInvalid, SecretKeyRequired, SepaUnsupportedAccount, SetupAttemptFailed, SetupIntentAuthenticationFailure, SetupIntentInvalidParameter, SetupIntentSetupAttemptExpired, SetupIntentUnexpectedState, ShippingCalculationFailed, SkuInactive, StateUnsupported, StatusTransitionInvalid, TaxIdInvalid, TaxesCalculationFailed, TerminalLocationCountryUnsupported, TestmodeChargesOnly, TlsVersionUnsupported, TokenInUse, TransferSourceBalanceParametersMismatch, TransfersNotAllowed, */ } impl ::core::fmt::Display for StripeErrorCode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{{\"error\": {}}}", serde_json::to_string(self).unwrap_or_else(|_| "API error response".to_string()) ) } } #[derive(Clone, Debug, serde::Serialize)] #[serde(rename_all = "snake_case")] #[allow(clippy::enum_variant_names)] pub enum StripeErrorType { ApiError, CardError, InvalidRequestError, ConnectorError, HyperswitchError, } impl From for StripeErrorCode { fn from(value: errors::ApiErrorResponse) -> Self { match value { errors::ApiErrorResponse::Unauthorized | errors::ApiErrorResponse::InvalidJwtToken | errors::ApiErrorResponse::GenericUnauthorized { .. } | errors::ApiErrorResponse::AccessForbidden { .. } | errors::ApiErrorResponse::InvalidCookie | errors::ApiErrorResponse::InvalidEphemeralKey | errors::ApiErrorResponse::CookieNotFound => Self::Unauthorized, errors::ApiErrorResponse::InvalidRequestUrl | errors::ApiErrorResponse::InvalidHttpMethod | errors::ApiErrorResponse::InvalidCardIin | errors::ApiErrorResponse::InvalidCardIinLength => Self::InvalidRequestUrl, errors::ApiErrorResponse::MissingRequiredField { field_name } => { Self::ParameterMissing { field_name: field_name.to_string(), param: field_name.to_string(), } } errors::ApiErrorResponse::UnprocessableEntity { message } => { Self::HyperswitchUnprocessableEntity { message } } errors::ApiErrorResponse::MissingRequiredFields { field_names } => { // Instead of creating a new error variant in StripeErrorCode for MissingRequiredFields, converted vec<&str> to String Self::ParameterMissing { field_name: field_names.clone().join(", "), param: field_names.clone().join(", "), } } errors::ApiErrorResponse::GenericNotFoundError { message } => { Self::GenericNotFoundError { message } } errors::ApiErrorResponse::GenericDuplicateError { message } => { Self::GenericDuplicateError { message } } // parameter unknown, invalid request error // actually if we type wrong values in address we get this error. Stripe throws parameter unknown. I don't know if stripe is validating email and stuff errors::ApiErrorResponse::InvalidDataFormat { field_name, expected_format, } => Self::ParameterUnknown { field_name, expected_format, }, errors::ApiErrorResponse::RefundAmountExceedsPaymentAmount => { Self::RefundAmountExceedsPaymentAmount { param: "amount".to_owned(), } } errors::ApiErrorResponse::PaymentAuthorizationFailed { data } | errors::ApiErrorResponse::PaymentAuthenticationFailed { data } => { Self::PaymentIntentAuthenticationFailure { data } } errors::ApiErrorResponse::VerificationFailed { data } => { Self::VerificationFailed { data } } errors::ApiErrorResponse::PaymentCaptureFailed { data } => { Self::PaymentIntentPaymentAttemptFailed { data } } errors::ApiErrorResponse::DisputeFailed { data } => Self::DisputeFailed { data }, errors::ApiErrorResponse::InvalidCardData { data: _ } => Self::InvalidCardType, // Maybe it is better to de generalize this router error errors::ApiErrorResponse::CardExpired { data: _ } => Self::ExpiredCard, errors::ApiErrorResponse::RefundNotPossible { connector: _ } => Self::RefundFailed, errors::ApiErrorResponse::RefundFailed { data: _ } => Self::RefundFailed, // Nothing at stripe to map errors::ApiErrorResponse::PayoutFailed { data: _ } => Self::PayoutFailed, errors::ApiErrorResponse::ExternalVaultFailed => Self::ExternalVaultFailed, errors::ApiErrorResponse::MandateUpdateFailed | errors::ApiErrorResponse::MandateSerializationFailed | errors::ApiErrorResponse::MandateDeserializationFailed | errors::ApiErrorResponse::InternalServerError | errors::ApiErrorResponse::HealthCheckError { .. } => Self::InternalServerError, // not a stripe code errors::ApiErrorResponse::ExternalConnectorError { code, message, connector, status_code, .. } => Self::ExternalConnectorError { code, message, connector, status_code, }, errors::ApiErrorResponse::IncorrectConnectorNameGiven => { Self::IncorrectConnectorNameGiven } errors::ApiErrorResponse::MandateActive => Self::MandateActive, //not a stripe code errors::ApiErrorResponse::CustomerRedacted => Self::CustomerRedacted, //not a stripe code errors::ApiErrorResponse::ConfigNotFound => Self::ConfigNotFound, // not a stripe code errors::ApiErrorResponse::DuplicateConfig => Self::DuplicateConfig, // not a stripe code errors::ApiErrorResponse::DuplicateRefundRequest => Self::DuplicateRefundRequest, errors::ApiErrorResponse::DuplicatePayout { payout_id } => { Self::DuplicatePayout { payout_id } } errors::ApiErrorResponse::RefundNotFound => Self::RefundNotFound, errors::ApiErrorResponse::CustomerNotFound => Self::CustomerNotFound, errors::ApiErrorResponse::PaymentNotFound => Self::PaymentNotFound, errors::ApiErrorResponse::PaymentMethodNotFound => Self::PaymentMethodNotFound, errors::ApiErrorResponse::ClientSecretNotGiven | errors::ApiErrorResponse::ClientSecretExpired => Self::ClientSecretNotFound, errors::ApiErrorResponse::MerchantAccountNotFound => Self::MerchantAccountNotFound, errors::ApiErrorResponse::PaymentLinkNotFound => Self::PaymentLinkNotFound, errors::ApiErrorResponse::ResourceIdNotFound => Self::ResourceIdNotFound, errors::ApiErrorResponse::MerchantConnectorAccountNotFound { id } => { Self::MerchantConnectorAccountNotFound { id } } errors::ApiErrorResponse::MandateNotFound => Self::MandateNotFound, errors::ApiErrorResponse::ApiKeyNotFound => Self::ApiKeyNotFound, errors::ApiErrorResponse::PayoutNotFound => Self::PayoutNotFound, errors::ApiErrorResponse::EventNotFound => Self::EventNotFound, errors::ApiErrorResponse::MandateValidationFailed { reason } => { Self::PaymentIntentMandateInvalid { message: reason } } errors::ApiErrorResponse::ReturnUrlUnavailable => Self::ReturnUrlUnavailable, errors::ApiErrorResponse::DuplicateMerchantAccount => Self::DuplicateMerchantAccount, errors::ApiErrorResponse::DuplicateMerchantConnectorAccount { profile_id, connector_label, } => Self::DuplicateMerchantConnectorAccount { profile_id, connector_label, }, errors::ApiErrorResponse::DuplicatePaymentMethod => Self::DuplicatePaymentMethod, errors::ApiErrorResponse::PaymentBlockedError { code, message, status, reason, } => Self::PaymentBlockedError { code, message, status, reason, }, errors::ApiErrorResponse::ClientSecretInvalid => Self::PaymentIntentInvalidParameter { param: "client_secret".to_owned(), }, errors::ApiErrorResponse::InvalidRequestData { message } => { Self::InvalidRequestData { message } } errors::ApiErrorResponse::PreconditionFailed { message } => { Self::PreconditionFailed { message } } errors::ApiErrorResponse::InvalidDataValue { field_name } => Self::ParameterMissing { field_name: field_name.to_string(), param: field_name.to_string(), }, errors::ApiErrorResponse::MaximumRefundCount => Self::MaximumRefundCount, errors::ApiErrorResponse::PaymentNotSucceeded => Self::PaymentFailed, errors::ApiErrorResponse::DuplicateMandate => Self::DuplicateMandate, errors::ApiErrorResponse::SuccessfulPaymentNotFound => Self::SuccessfulPaymentNotFound, errors::ApiErrorResponse::AddressNotFound => Self::AddressNotFound, errors::ApiErrorResponse::NotImplemented { .. } => Self::Unauthorized, errors::ApiErrorResponse::FlowNotSupported { .. } => Self::InternalServerError, errors::ApiErrorResponse::MandatePaymentDataMismatch { .. } => Self::PlatformBadRequest, errors::ApiErrorResponse::MaxFieldLengthViolated { .. } => Self::PlatformBadRequest, errors::ApiErrorResponse::PaymentUnexpectedState { current_flow, field_name, current_value, states, } => Self::PaymentIntentUnexpectedState { current_flow, field_name, current_value, states, }, errors::ApiErrorResponse::DuplicatePayment { payment_id } => { Self::DuplicatePayment { payment_id } } errors::ApiErrorResponse::DisputeNotFound { dispute_id } => Self::ResourceMissing { object: "dispute".to_owned(), id: dispute_id, }, errors::ApiErrorResponse::AuthenticationNotFound { id } => Self::ResourceMissing { object: "authentication".to_owned(), id, }, errors::ApiErrorResponse::ProfileNotFound { id } => Self::ResourceMissing { object: "business_profile".to_owned(), id, }, errors::ApiErrorResponse::PollNotFound { id } => Self::ResourceMissing { object: "poll".to_owned(), id, }, errors::ApiErrorResponse::DisputeStatusValidationFailed { reason: _ } => { Self::InternalServerError } errors::ApiErrorResponse::FileValidationFailed { .. } => Self::FileValidationFailed, errors::ApiErrorResponse::MissingFile => Self::MissingFile, errors::ApiErrorResponse::MissingFilePurpose => Self::MissingFilePurpose, errors::ApiErrorResponse::MissingFileContentType => Self::MissingFileContentType, errors::ApiErrorResponse::MissingDisputeId => Self::MissingDisputeId, errors::ApiErrorResponse::FileNotFound => Self::FileNotFound, errors::ApiErrorResponse::FileNotAvailable => Self::FileNotAvailable, errors::ApiErrorResponse::MerchantConnectorAccountDisabled => { Self::MerchantConnectorAccountDisabled } errors::ApiErrorResponse::NotSupported { .. } => Self::InternalServerError, errors::ApiErrorResponse::CurrencyNotSupported { message } => { Self::CurrencyNotSupported { message } } errors::ApiErrorResponse::FileProviderNotSupported { .. } => { Self::FileProviderNotSupported } errors::ApiErrorResponse::WebhookBadRequest | errors::ApiErrorResponse::WebhookResourceNotFound | errors::ApiErrorResponse::WebhookProcessingFailure | errors::ApiErrorResponse::WebhookAuthenticationFailed | errors::ApiErrorResponse::WebhookUnprocessableEntity | errors::ApiErrorResponse::WebhookInvalidMerchantSecret => { Self::WebhookProcessingError } errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration => { Self::PaymentMethodUnactivated } errors::ApiErrorResponse::ResourceBusy => Self::PaymentMethodUnactivated, errors::ApiErrorResponse::InvalidConnectorConfiguration { config } => { Self::InvalidConnectorConfiguration { config } } errors::ApiErrorResponse::CurrencyConversionFailed => Self::CurrencyConversionFailed, errors::ApiErrorResponse::PaymentMethodDeleteFailed => Self::PaymentMethodDeleteFailed, errors::ApiErrorResponse::InvalidWalletToken { wallet_name } => { Self::InvalidWalletToken { wallet_name } } errors::ApiErrorResponse::ExtendedCardInfoNotFound => Self::ExtendedCardInfoNotFound, errors::ApiErrorResponse::LinkConfigurationError { message } => { Self::LinkConfigurationError { message } } errors::ApiErrorResponse::IntegrityCheckFailed { reason, field_names, connector_transaction_id, } => Self::IntegrityCheckFailed { reason, field_names, connector_transaction_id, }, errors::ApiErrorResponse::InvalidTenant { tenant_id: _ } | errors::ApiErrorResponse::MissingTenantId => Self::InvalidTenant, errors::ApiErrorResponse::AmountConversionFailed { amount_type } => { Self::AmountConversionFailed { amount_type } } errors::ApiErrorResponse::PlatformAccountAuthNotSupported => Self::PlatformBadRequest, errors::ApiErrorResponse::InvalidPlatformOperation => Self::PlatformUnauthorizedRequest, errors::ApiErrorResponse::ProfileAcquirerNotFound { .. } => { Self::ProfileAcquirerNotFound } } } } impl actix_web::ResponseError for StripeErrorCode { fn status_code(&self) -> reqwest::StatusCode { use reqwest::StatusCode; match self { Self::Unauthorized | Self::PlatformUnauthorizedRequest => StatusCode::UNAUTHORIZED, Self::InvalidRequestUrl | Self::GenericNotFoundError { .. } => StatusCode::NOT_FOUND, Self::ParameterUnknown { .. } | Self::HyperswitchUnprocessableEntity { .. } => { StatusCode::UNPROCESSABLE_ENTITY } Self::ParameterMissing { .. } | Self::RefundAmountExceedsPaymentAmount { .. } | Self::PaymentIntentAuthenticationFailure { .. } | Self::PaymentIntentPaymentAttemptFailed { .. } | Self::ExpiredCard | Self::InvalidCardType | Self::DuplicateRefundRequest | Self::DuplicatePayout { .. } | Self::RefundNotFound | Self::CustomerNotFound | Self::ConfigNotFound | Self::DuplicateConfig | Self::ClientSecretNotFound | Self::PaymentNotFound | Self::PaymentMethodNotFound | Self::MerchantAccountNotFound | Self::MerchantConnectorAccountNotFound { .. } | Self::MerchantConnectorAccountDisabled | Self::MandateNotFound | Self::ApiKeyNotFound | Self::PayoutNotFound | Self::EventNotFound | Self::DuplicateMerchantAccount | Self::DuplicateMerchantConnectorAccount { .. } | Self::DuplicatePaymentMethod | Self::PaymentFailed | Self::VerificationFailed { .. } | Self::DisputeFailed { .. } | Self::MaximumRefundCount | Self::PaymentIntentInvalidParameter { .. } | Self::SerdeQsError { .. } | Self::InvalidRequestData { .. } | Self::InvalidWalletToken { .. } | Self::PreconditionFailed { .. } | Self::DuplicateMandate | Self::SuccessfulPaymentNotFound | Self::AddressNotFound | Self::ResourceIdNotFound | Self::PaymentIntentMandateInvalid { .. } | Self::PaymentIntentUnexpectedState { .. } | Self::DuplicatePayment { .. } | Self::GenericDuplicateError { .. } | Self::IncorrectConnectorNameGiven | Self::ResourceMissing { .. } | Self::FileValidationFailed | Self::MissingFile | Self::MissingFileContentType | Self::MissingFilePurpose | Self::MissingDisputeId | Self::FileNotFound | Self::FileNotAvailable | Self::FileProviderNotSupported | Self::CurrencyNotSupported { .. } | Self::DuplicateCustomer | Self::PaymentMethodUnactivated | Self::InvalidConnectorConfiguration { .. } | Self::CurrencyConversionFailed | Self::PaymentMethodDeleteFailed | Self::ExtendedCardInfoNotFound | Self::PlatformBadRequest | Self::LinkConfigurationError { .. } => StatusCode::BAD_REQUEST, Self::RefundFailed | Self::PayoutFailed | Self::PaymentLinkNotFound | Self::InternalServerError | Self::MandateActive | Self::CustomerRedacted | Self::WebhookProcessingError | Self::InvalidTenant | Self::ExternalVaultFailed | Self::AmountConversionFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR, Self::ReturnUrlUnavailable => StatusCode::SERVICE_UNAVAILABLE, Self::ExternalConnectorError { status_code, .. } => { StatusCode::from_u16(*status_code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR) } Self::IntegrityCheckFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR, Self::PaymentBlockedError { code, .. } => { StatusCode::from_u16(*code).unwrap_or(StatusCode::OK) } Self::LockTimeout => StatusCode::LOCKED, Self::ProfileAcquirerNotFound => StatusCode::NOT_FOUND, } } fn error_response(&self) -> actix_web::HttpResponse { use actix_web::http::header; actix_web::HttpResponseBuilder::new(self.status_code()) .insert_header((header::CONTENT_TYPE, mime::APPLICATION_JSON)) .body(self.to_string()) } } impl From for StripeErrorCode { fn from(item: serde_qs::Error) -> Self { match item { serde_qs::Error::Custom(s) => Self::SerdeQsError { error_message: s, param: None, }, serde_qs::Error::Parse(param, position) => Self::SerdeQsError { error_message: format!( "parsing failed with error: '{param}' at position: {position}" ), param: Some(param), }, serde_qs::Error::Unsupported => Self::SerdeQsError { error_message: "Given request format is not supported".to_owned(), param: None, }, serde_qs::Error::FromUtf8(_) => Self::SerdeQsError { error_message: "Failed to parse request to from utf-8".to_owned(), param: None, }, serde_qs::Error::Io(_) => Self::SerdeQsError { error_message: "Failed to parse request".to_owned(), param: None, }, serde_qs::Error::ParseInt(_) => Self::SerdeQsError { error_message: "Failed to parse integer in request".to_owned(), param: None, }, serde_qs::Error::Utf8(_) => Self::SerdeQsError { error_message: "Failed to convert utf8 to string".to_owned(), param: None, }, } } } impl ErrorSwitch for errors::ApiErrorResponse { fn switch(&self) -> StripeErrorCode { self.clone().into() } } impl crate::services::EmbedError for error_stack::Report {} impl ErrorSwitch for CustomersErrorResponse { fn switch(&self) -> StripeErrorCode { use StripeErrorCode as SC; match self { Self::CustomerRedacted => SC::CustomerRedacted, Self::InternalServerError => SC::InternalServerError, Self::MandateActive => SC::MandateActive, Self::CustomerNotFound => SC::CustomerNotFound, Self::CustomerAlreadyExists => SC::DuplicateCustomer, } } }