Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PaymentSheet IntentMode doesn't support SetupIntents #1853

Closed
ztaylor54 opened this issue Jul 12, 2024 · 0 comments
Closed

PaymentSheet IntentMode doesn't support SetupIntents #1853

ztaylor54 opened this issue Jul 12, 2024 · 0 comments
Assignees
Labels
bug Something isn't working

Comments

@ztaylor54
Copy link

The Stripe docs describe how to collect payment details before creating an Intent, but the flutter platform interface doesn't properly implement the IntentMode enum:

@freezed
class IntentMode with _$IntentMode {
@JsonSerializable(explicitToJson: true)
const factory IntentMode({
required String currencyCode,
required int amount,
/// Data related to the future payment intent
IntentFutureUsage? setupFutureUsage,
/// Capture method for the future payment intent
CaptureMethod? captureMethod,
}) = _IntentMode;
factory IntentMode.fromJson(Map<String, dynamic> json) =>
_$IntentModeFromJson(json);
}

Note how the IntentMode class requires currencyCode and amount, but the platform implementations expect amount and currencyCode to be nullable when reading them, and use that information to determine whether to configure the payment sheet for a PaymentIntent or SetupIntent:

private func buildIntentConfiguration(
modeParams: NSDictionary,
paymentMethodTypes: [String]?,
captureMethod: PaymentSheet.IntentConfiguration.CaptureMethod
) -> PaymentSheet.IntentConfiguration {
var mode: PaymentSheet.IntentConfiguration.Mode
if let amount = modeParams["amount"] as? Int {
mode = PaymentSheet.IntentConfiguration.Mode.payment(
amount: amount,
currency: modeParams["currencyCode"] as? String ?? "",
setupFutureUsage: modeParams["setupFutureUsage"] != nil
? (modeParams["setupFutureUsage"] as? String == "OffSession" ? .offSession : .onSession)
: nil,
captureMethod: captureMethod
)
} else {
mode = PaymentSheet.IntentConfiguration.Mode.setup(
currency: modeParams["currencyCode"] as? String,
setupFutureUsage: modeParams["setupFutureUsage"] as? String == "OffSession" ? .offSession : .onSession
)
}
return PaymentSheet.IntentConfiguration.init(
mode: mode,
paymentMethodTypes: paymentMethodTypes,
confirmHandler: { paymentMethod, shouldSavePaymentMethod, intentCreationCallback in
if (self.hasEventListeners) {
self.paymentSheetIntentCreationCallback = intentCreationCallback
self.sendEvent(withName: "onConfirmHandlerCallback", body: [
"paymentMethod": Mappers.mapFromPaymentMethod(paymentMethod) ?? NSNull(),
"shouldSavePaymentMethod": shouldSavePaymentMethod
])
} else {
RCTMakeAndLogError("Tried to call confirmHandler, but no callback was found. Please file an issue: https://github.com/stripe/stripe-react-native/issues", nil, nil)
}
})
}

private fun buildIntentConfigurationMode(modeParams: Bundle): PaymentSheet.IntentConfiguration.Mode {
val currencyCode = modeParams.getString("currencyCode")
?: throw PaymentSheetException("You must provide a value to intentConfiguration.mode.currencyCode")
return if (modeParams.containsKey("amount")) {
PaymentSheet.IntentConfiguration.Mode.Payment(
amount = modeParams.getInt("amount").toLong(),
currency = currencyCode,
setupFutureUse = mapToSetupFutureUse(modeParams.getString("setupFutureUsage")),
captureMethod = mapToCaptureMethod(modeParams.getString("captureMethod")),
)
} else {
val setupFutureUsage = mapToSetupFutureUse(modeParams.getString("setupFutureUsage"))
?: throw PaymentSheetException("You must provide a value to intentConfiguration.mode.setupFutureUsage")
PaymentSheet.IntentConfiguration.Mode.Setup(
currency = currencyCode,
setupFutureUse = setupFutureUsage
)
}
}

Both iOS and Android configure the payment sheet for a SetupIntent when amount is null. It is interesting (and perhaps a separate bug?) to note that while iOS allows currencyCode to be null on a PaymentIntent, Android does not.

Resolution

I think the easiest fix here would be to make IntentMode.amount a nullable field. Freezed does support union types, but that would get messy and would require updates to the individual platform implementations.

Hopefully this can get resolved quicky, because as of now there is no way to use a SetupIntent for a deferred payment in the manner described in the Stripe documentation. If you attempt to just specify a bogus amount, the payment sheet returns an error because it tries to fetch a PaymentIntent that doesn't exist:

Screenshot 2024-07-12 at 5 10 29 PM
@remonh87 remonh87 self-assigned this Jul 13, 2024
@remonh87 remonh87 added the bug Something isn't working label Jul 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants