/// All available error codes from 01/08/2023
/// 
/// [Official Stripe error code list](https://stripe.com/docs/error-codes)
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum Codes {
  None,
  AccountCountryInvalidAddress,
  AccountErrorCountryChangeRequiresAdditionalSteps,
  AccountInformationMismatch,
  AccountInvalid,
  AccountNumberInvalid,
  AcssDebitSessionIncomplete,
  AlipayUpgradeRequired,
  AmountTooLarge,
  AmountTooSmall,
  ApiKeyExpired,
  AuthenticationRequired,
  BalanceInsufficient,
  BankAccountBadRoutingNumbers,
  BankAccountDeclined,
  BankAccountExists,
  BankAccountRestricted,
  BankAccountUnusable,
  BankAccountUnverified,
  BankAccountVerificationFailed,
  BillingInvalidMandate,
  BitcoinUpgradeRequired,
  CardDeclineRateLimitExceeded,
  CardDeclined,
  CardholderPhoneNumberRequired,
  ChargeAlreadyCaptured,
  ChargeAlreadyRefunded,
  ChargeDisputed,
  ChargeExceedsSourceLimit,
  ChargeExpiredForCapture,
  ChargeInvalidParamter,
  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,
  OwnershipDeclarationNotAllowed,
  ParameterInvalidEmpty,
  ParameterInvalidInteger,
  ParameterInvalidStringBlank,
  ParameterInvalidStringEmpty,
  ParameterMissing,
  ParameterUnknown,
  ParametersExclusive,
  PaymentIntentActionRequired,
  PaymentIntentAuthenticationFailure,
  PaymentIntentIncompatiblePaymentMethod,
  PaymentIntentInvalidParameter,
  PaymentIntentKonbiniRejectedConfirmationNumber,
  PaymentIntentMandateInvalid,
  PaymentIntentPaymentAttemptExpired,
  PaymentIntentPaymentAttemptFailed,
  PaymentIntentUnexpectedState,
  PaymentMethodBankAccountAlreadyVerified,
  PaymentMethodBankAccountBlocked,
  PaymentMethodBillingDetailsAddressMissing,
  PaymentMethodCurrencyMismatch,
  PaymentMethodCustomerDecline,
  PaymentMethodInvalidParameter,
  PaymentMethodInvalidParameterTestmode,
  PaymentMethodMicrodepositFailed,
  PaymentMethodMicrodepositVerificationAmountsInvalid,
  PaymentMethodMicrodepositVerificationAmountsMismatch,
  PaymentMethodMicrodepositVerificationAttemptsExceeded,
  PaymentMethodMicrodepositVerificationDescriptorCodeMismatch,
  PaymentMethodMicrodepositVerificationTimeout,
  PaymentMethodProviderDecline,
  PaymentMethodProviderTimeout,
  PaymentMethodUnactivated,
  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,
  TokenAlreadyUsed,
  TokenInUse,
  TransferSourceBalanceParametersMismatch,
  TransfersNotAllowed,
  UrlInvalid
}

impl std::fmt::Display for Codes {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    let mut result = String::new();

    let self_to_string = format!("{:?}", self);
    for (i, c) in self_to_string.chars().enumerate() {
      if i > 0 && c.is_uppercase() {
        result.push('_');
      }
      result.push(c);
    }

    write!(f, "{}", result.to_lowercase())
  }
}