Skip to content

Commit da389bf

Browse files
committed
fix: return sealed CollectBankAccountResult for bank account collection
Native SDKs return either a payment intent or a setup intent depending on the client secret passed to collectBankAccount / verifyPaymentIntentWithMicrodeposits, but the platform interface only typed the result as PaymentIntent. The setup intent branch therefore failed to parse against PaymentIntent.fromJson, which requires fields (amount, currency, captureMethod, confirmationMethod) that are not present on a setup intent payload. Introduce a sealed CollectBankAccountResult union so both variants can be parsed by their own freezed + json_serializable generated factories without any hand-written field extraction or status mapping.
1 parent 3d908f0 commit da389bf

8 files changed

Lines changed: 392 additions & 18 deletions

File tree

example/lib/screens/regional_payment_methods/us_bank_account_direct_debit_screen.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,15 @@ class _UsBankAccountDirectDebitScreenState
134134
),
135135
);
136136

137-
if (result.status == PaymentIntentsStatus.RequiresConfirmation) {
137+
final paymentIntent = switch (result) {
138+
CollectBankAccountPaymentIntentResult(:final paymentIntent) =>
139+
paymentIntent,
140+
CollectBankAccountSetupIntentResult() => null,
141+
};
142+
if (paymentIntent?.status == PaymentIntentsStatus.RequiresConfirmation) {
138143
setState(() {
139144
canConfirm = true;
140-
clientSecretForConfirm = result.clientSecret;
145+
clientSecretForConfirm = paymentIntent!.clientSecret;
141146
});
142147
if (context.mounted) {
143148
scaffoldMessenger.showSnackBar(

packages/stripe/lib/src/stripe.dart

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -632,8 +632,10 @@ class Stripe {
632632

633633
/// Collect the bankaccount details for the payment intent.
634634
///
635-
/// Only US bank accounts are supported.
636-
Future<PaymentIntent> collectBankAccount({
635+
/// Only US bank accounts are supported. The returned
636+
/// [CollectBankAccountResult] is a sealed union containing either a
637+
/// [PaymentIntent] or a [SetupIntent] depending on [isPaymentIntent].
638+
Future<CollectBankAccountResult> collectBankAccount({
637639
/// Whether the clientsecret is associated with setup or paymentintent
638640
required bool isPaymentIntent,
639641

@@ -655,8 +657,10 @@ class Stripe {
655657
/// Verify the bank account with microtransactions
656658
///
657659
/// Only US bank accounts are supported.This method is only implemented for
658-
/// iOS at the moment.
659-
Future<PaymentIntent> verifyPaymentIntentWithMicrodeposits({
660+
/// iOS at the moment. The returned [CollectBankAccountResult] is a sealed
661+
/// union containing either a [PaymentIntent] or a [SetupIntent] depending on
662+
/// [isPaymentIntent].
663+
Future<CollectBankAccountResult> verifyPaymentIntentWithMicrodeposits({
660664
/// Whether the clientsecret is associated with setup or paymentintent
661665
required bool isPaymentIntent,
662666

packages/stripe_platform_interface/lib/src/method_channel_stripe.dart

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'package:stripe_platform_interface/src/result_parser.dart';
1515

1616
import 'models/app_info.dart';
1717
import 'models/card_details.dart';
18+
import 'models/collect_bank_account_result.dart';
1819
import 'models/errors.dart';
1920
import 'models/payment_intents.dart';
2021
import 'models/payment_methods.dart';
@@ -569,7 +570,7 @@ class MethodChannelStripe extends StripePlatform {
569570
}
570571

571572
@override
572-
Future<PaymentIntent> collectBankAccount({
573+
Future<CollectBankAccountResult> collectBankAccount({
573574
required bool isPaymentIntent,
574575
required String clientSecret,
575576
required CollectBankAccountParams params,
@@ -583,13 +584,14 @@ class MethodChannelStripe extends StripePlatform {
583584

584585
_financialConnectionsEventHandler = params.onEvent;
585586

586-
return ResultParser<PaymentIntent>(
587-
parseJson: (json) => PaymentIntent.fromJson(json),
588-
).parse(result: result!, successResultKey: 'paymentIntent');
587+
return _parseCollectBankAccountResult(
588+
result!,
589+
isPaymentIntent: isPaymentIntent,
590+
);
589591
}
590592

591593
@override
592-
Future<PaymentIntent> verifyPaymentIntentWithMicrodeposits({
594+
Future<CollectBankAccountResult> verifyPaymentIntentWithMicrodeposits({
593595
required bool isPaymentIntent,
594596
required String clientSecret,
595597
required VerifyMicroDepositsParams params,
@@ -601,9 +603,26 @@ class MethodChannelStripe extends StripePlatform {
601603
'clientSecret': clientSecret,
602604
});
603605

604-
return ResultParser<PaymentIntent>(
605-
parseJson: (json) => PaymentIntent.fromJson(json),
606-
).parse(result: result!, successResultKey: 'paymentIntent');
606+
return _parseCollectBankAccountResult(
607+
result!,
608+
isPaymentIntent: isPaymentIntent,
609+
);
610+
}
611+
612+
CollectBankAccountResult _parseCollectBankAccountResult(
613+
Map<String, dynamic> result, {
614+
required bool isPaymentIntent,
615+
}) {
616+
if (isPaymentIntent) {
617+
final paymentIntent = ResultParser<PaymentIntent>(
618+
parseJson: (json) => PaymentIntent.fromJson(json),
619+
).parse(result: result, successResultKey: 'paymentIntent');
620+
return CollectBankAccountResult.paymentIntent(paymentIntent);
621+
}
622+
final setupIntent = ResultParser<SetupIntent>(
623+
parseJson: (json) => SetupIntent.fromJson(json),
624+
).parse(result: result, successResultKey: 'setupIntent');
625+
return CollectBankAccountResult.setupIntent(setupIntent);
607626
}
608627

609628
@override
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import 'package:freezed_annotation/freezed_annotation.dart';
2+
3+
import 'payment_intents.dart';
4+
import 'setup_intent.dart';
5+
6+
part 'collect_bank_account_result.freezed.dart';
7+
8+
/// Result of `collectBankAccount` / `verifyPaymentIntentWithMicrodeposits`.
9+
///
10+
/// Native SDKs return either a payment intent or a setup intent depending on
11+
/// the client secret that was supplied, so the result is modelled as a sealed
12+
/// union to keep both flows strongly typed.
13+
@freezed
14+
sealed class CollectBankAccountResult with _$CollectBankAccountResult {
15+
const factory CollectBankAccountResult.paymentIntent(
16+
PaymentIntent paymentIntent,
17+
) = CollectBankAccountPaymentIntentResult;
18+
19+
const factory CollectBankAccountResult.setupIntent(SetupIntent setupIntent) =
20+
CollectBankAccountSetupIntentResult;
21+
}

0 commit comments

Comments
 (0)