Path: blob/main/Signal/src/ViewControllers/Donations/DonationViewsUtil+LocalizedStripeError.swift
1 views
//
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public import SignalServiceKit
extension DonationViewsUtil {
typealias ErrorSheetDetails = (message: String, actions: ErrorSheetActions)
enum ErrorSheetActions {
/// Show a simple "OK" to dismiss the error.
case dismiss
/// Show a "learn more" button with the given URL along with an "OK" to dismiss the error.
case learnMore(link: URL)
}
static func localizedDonationFailure(
chargeErrorCode: String?,
paymentMethod: DonationPaymentMethod?,
) -> ErrorSheetDetails {
switch paymentMethod {
case .applePay:
let errorMessage = localizedDonationFailureForApplePay(chargeErrorCode: chargeErrorCode)
return (errorMessage, .dismiss)
case .creditOrDebitCard:
let errorMessage = localizedDonationFailureForCreditOrDebitCard(chargeErrorCode: chargeErrorCode)
return (errorMessage, .dismiss)
case .paypal, nil:
// TODO: [PayPal] Use the charge error code to put together a non-generic error.
let errorMessage = OWSLocalizedString(
"SUSTAINER_VIEW_CANT_ADD_BADGE_MESSAGE",
comment: "Action sheet message for Couldn't Add Badge sheet",
)
return (errorMessage, .dismiss)
case .sepa, .ideal:
return localizedDonationFailureForSEPA(chargeErrorCode: chargeErrorCode)
}
}
private static func localizedDonationFailureForApplePay(chargeErrorCode: String?) -> String {
switch chargeErrorCode {
case "authentication_required":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_AUTHENTICATION_REQUIRED",
comment: "Apple Pay donation error for decline failures where authentication is required.",
)
case "approve_with_id":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_PAYMENT_CANNOT_BE_AUTHORIZED",
comment: "Apple Pay donation error for decline failures where the payment cannot be authorized.",
)
case "call_issuer":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_CALL_ISSUER",
comment: "Apple Pay donation error for decline failures where the user may need to contact their card or bank.",
)
case "card_not_supported":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_CARD_NOT_SUPPORTED",
comment: "Apple Pay donation error for decline failures where the card is not supported.",
)
case "expired_card":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_EXPIRED_CARD",
comment: "Apple Pay donation error for decline failures where the card has expired.",
)
case "incorrect_number":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_INCORRECT_CARD_NUMBER",
comment: "Apple Pay donation error for decline failures where the card number is incorrect.",
)
case "incorrect_cvc", "invalid_cvc":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_INCORRECT_CARD_VERIFICATION_CODE",
comment: "Apple Pay donation error for decline failures where the card verification code (often called CVV or CVC) is incorrect.",
)
case "insufficient_funds":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_INSUFFICIENT_FUNDS",
comment: "Apple Pay donation error for decline failures where the card has insufficient funds.",
)
case "invalid_expiry_month":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_INVALID_EXPIRY_MONTH",
comment: "Apple Pay donation error for decline failures where the expiration month on the payment method is incorrect.",
)
case "invalid_expiry_year":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_INVALID_EXPIRY_YEAR",
comment: "Apple Pay donation error for decline failures where the expiration year on the payment method is incorrect.",
)
case "invalid_number":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_INVALID_NUMBER",
comment: "Apple Pay donation error for decline failures where the card number is incorrect.",
)
case "issuer_not_available", "processing_error", "reenter_transaction":
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_ISSUER_NOT_AVAILABLE",
comment: "Apple Pay donation error for \"issuer not available\" decline failures. The user should try again or contact their card/bank.",
)
default:
return OWSLocalizedString(
"APPLE_PAY_DONATION_ERROR_OTHER",
comment: "Apple Pay donation error for unspecified decline failures.",
)
}
}
private static func localizedDonationFailureForCreditOrDebitCard(chargeErrorCode: String?) -> String {
switch chargeErrorCode {
case "approve_with_id":
return OWSLocalizedString(
"CREDIT_OR_DEBIT_CARD_DONATION_ERROR_PAYMENT_CANNOT_BE_AUTHORIZED",
comment: "Credit/debit card donation error for decline failures where the payment cannot be authorized.",
)
case "expired_card":
return OWSLocalizedString(
"CREDIT_OR_DEBIT_CARD_DONATION_ERROR_EXPIRED_CARD",
comment: "Credit/debit card donation error for decline failures where the card has expired.",
)
case "incorrect_number", "invalid_number":
return OWSLocalizedString(
"CREDIT_OR_DEBIT_CARD_DONATION_ERROR_INCORRECT_CARD_NUMBER",
comment: "Credit/debit card donation error for decline failures where the card number is incorrect.",
)
case "incorrect_cvc", "invalid_cvc":
return OWSLocalizedString(
"CREDIT_OR_DEBIT_CARD_DONATION_ERROR_INCORRECT_CARD_VERIFICATION_CODE",
comment: "Credit/debit card donation error for decline failures where the card verification code (often called CVV or CVC) is incorrect.",
)
case "invalid_expiry_month":
return OWSLocalizedString(
"CREDIT_OR_DEBIT_CARD_DONATION_ERROR_INVALID_EXPIRY_MONTH",
comment: "Credit/debit card donation error for decline failures where the expiration month on the payment method is incorrect.",
)
case "invalid_expiry_year":
return OWSLocalizedString(
"CREDIT_OR_DEBIT_CARD_DONATION_ERROR_INVALID_EXPIRY_YEAR",
comment: "Credit/debit card donation error for decline failures where the expiration year on the payment method is incorrect.",
)
default:
return OWSLocalizedString(
"CREDIT_OR_DEBIT_CARD_DONATION_ERROR_OTHER",
comment: "Credit/debit card donation error for unspecified decline failures.",
)
}
}
private static func localizedDonationFailureForSEPA(chargeErrorCode: String?) -> ErrorSheetDetails {
let message: String
let actions: ErrorSheetActions
switch chargeErrorCode {
case "insufficient_funds":
message = OWSLocalizedString(
"SEPA_DONATION_ERROR_INSUFFICIENT_FUNDS",
comment: "SEPA bank account donation error for insufficient funds.",
)
actions = .learnMore(link: URL.Support.Donations.badgeExpiration)
case "debit_not_authorized":
message = OWSLocalizedString(
"SEPA_DONATION_ERROR_PAYMENT_NOT_AUTHORIZED",
comment: "SEPA bank account donation error for the payment not being authorizing by the account holder.",
)
actions = .learnMore(link: URL.Support.Donations.badgeExpiration)
case "account_closed", "bank_account_restricted", "recipient_deceased":
message = OWSLocalizedString(
"SEPA_DONATION_ERROR_NOT_PROCESSED",
comment: "SEPA bank account donation error for the account details not being able to be processed.",
)
actions = .learnMore(link: URL.Support.Donations.badgeExpiration)
case "debit_authorization_not_match":
message = OWSLocalizedString(
"SEPA_DONATION_ERROR_NOT_AUTHORIZED",
comment: "SEPA bank account donation error for missing or incorrect mandate information.",
)
actions = .learnMore(link: URL.Support.Donations.badgeExpiration)
case "debit_disputed":
fallthrough
case "branch_does_not_exist", "incorrect_account_holder_name", "invalid_account_number", "generic_could_not_process", "refer_to_customer":
fallthrough
default:
message = OWSLocalizedString(
"SEPA_DONATION_ERROR_OTHER",
comment: "SEPA bank account donation error for unspecified decline failures.",
)
actions = .dismiss
}
return (message, actions)
}
public static func localizedDonationFailureForPaymentAuthorizationRedirect(error: Stripe.RedirectAuthorizationError) -> String? {
switch error {
case .cancelled:
return OWSLocalizedString(
"DONATION_REDIRECT_ERROR_CANCELLED_MESSAGE",
comment: "Error message displayed if something goes wrong with 3DSecure/iDEAL payment authorization. This will be encountered if the user cancels the webview before authrizing the payment.",
)
case .denied:
return OWSLocalizedString(
"DONATION_REDIRECT_ERROR_PAYMENT_DENIED_MESSAGE",
comment: "Error message displayed if something goes wrong with 3DSecure/iDEAL payment authorization. This will be encountered if the user denies the payment.",
)
case .invalidCallback:
return OWSLocalizedString(
"DONATION_REDIRECT_ERROR_INVALID_RESPONSE_MESSAGE",
comment: "Error message displayed if something goes wrong with 3DSecure/iDEAL payment authorization. This will be encountered if the callback is in an unexpected format.",
)
}
}
}