Implement proper error handling for charge failure on initial subscription attempt.

This commit is contained in:
Alex Hart 2022-06-23 12:33:06 -03:00 committed by Cody Henthorne
parent 8efd07b3e2
commit 6ddb5b983f
2 changed files with 31 additions and 4 deletions

View file

@ -166,6 +166,12 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
ActiveSubscription.ChargeFailure chargeFailure = activeSubscription.getChargeFailure();
if (chargeFailure != null) {
Log.w(TAG, "Subscription payment charge failure code: " + chargeFailure.getCode() + ", message: " + chargeFailure.getMessage(), true);
if (!isForKeepAlive) {
Log.w(TAG, "Initial subscription payment failed, treating as a permanent failure.");
onPaymentFailure(subscription.getStatus(), chargeFailure, subscription.getEndOfCurrentPeriod(), false);
throw new Exception("New subscription has hit a payment failure.");
}
}
Log.w(TAG, "Subscription is not yet active. Status: " + subscription.getStatus(), true);
@ -294,12 +300,31 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
SignalStore.donationsValues().setUnexpectedSubscriptionCancelationReason(status);
SignalStore.donationsValues().setUnexpectedSubscriptionCancelationTimestamp(timestamp);
MultiDeviceSubscriptionSyncRequestJob.enqueue();
} else if (chargeFailure != null) {
StripeDeclineCode declineCode = StripeDeclineCode.Companion.getFromCode(chargeFailure.getOutcomeNetworkReason());
DonationError.PaymentSetupError paymentSetupError;
if (declineCode.isKnown()) {
paymentSetupError = new DonationError.PaymentSetupError.DeclinedError(
getErrorSource(),
new Exception(chargeFailure.getMessage()),
declineCode
);
} else {
paymentSetupError = new DonationError.PaymentSetupError.CodedError(
getErrorSource(),
new Exception("Card was declined. " + chargeFailure.getCode()),
chargeFailure.getCode()
);
}
Log.w(TAG, "Not for a keep-alive and we have a charge failure. Routing a payment setup error...", true);
DonationError.routeDonationError(context, paymentSetupError);
} else {
Log.d(TAG, "Not for a keep-alive and we have a status. Routing a payment setup error...", true);
DonationError.routeDonationError(context, new DonationError.PaymentSetupError.DeclinedError(
Log.d(TAG, "Not for a keep-alive and we have a failure status. Routing a payment setup error...", true);
DonationError.routeDonationError(context, new DonationError.PaymentSetupError.GenericError(
getErrorSource(),
new Exception("Got a failure status from the subscription object."),
StripeDeclineCode.Companion.getFromCode(status)
new Exception("Got a failure status from the subscription object.")
));
}
}

View file

@ -8,6 +8,8 @@ sealed class StripeDeclineCode {
data class Known(val code: Code) : StripeDeclineCode()
data class Unknown(val code: String) : StripeDeclineCode()
fun isKnown(): Boolean = this.isKnown()
enum class Code(val code: String) {
AUTHENTICATION_REQUIRED("authentication_required"),
APPROVE_WITH_ID("approve_with_id"),