Skip to content

Commit

Permalink
feat: add possibility to create deffered payment for payment sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
Remon committed Aug 12, 2023
1 parent 80449d9 commit 9906a5c
Show file tree
Hide file tree
Showing 17 changed files with 1,114 additions and 25 deletions.
178 changes: 178 additions & 0 deletions example/lib/screens/payment_sheet/payment_sheet_deffered_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import 'dart:convert';

Check warning on line 1 in example/lib/screens/payment_sheet/payment_sheet_deffered_screen.dart

View workflow job for this annotation

GitHub Actions / Typo CI

Filename: example/lib/screens/payment_sheet/payment_sheet_deffered_screen.dart

"deffered" in the filename is a typo. Did you mean "differed"?

import 'package:flutter/material.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:http/http.dart' as http;
import 'package:stripe_example/config.dart';
import 'package:stripe_example/screens/payment_sheet/payment_sheet_screen_custom_flow.dart';
import 'package:stripe_example/widgets/example_scaffold.dart';
import 'package:stripe_example/widgets/loading_button.dart';

class PaymentSheetDefferedScreen extends StatefulWidget {

Check warning on line 11 in example/lib/screens/payment_sheet/payment_sheet_deffered_screen.dart

View workflow job for this annotation

GitHub Actions / Typo CI

PaymentSheetDefferedScreen

"PaymentSheetDefferedScreen" is a typo. Did you mean "PaymentSheetDifferedScreen"?
@override
_PaymentSheetScreenState createState() => _PaymentSheetScreenState();
}

class _PaymentSheetScreenState extends State<PaymentSheetDefferedScreen> {

Check warning on line 16 in example/lib/screens/payment_sheet/payment_sheet_deffered_screen.dart

View workflow job for this annotation

GitHub Actions / Typo CI

PaymentSheetDefferedScreen

"PaymentSheetDefferedScreen" is a typo. Did you mean "PaymentSheetDifferedScreen"?
int step = 0;

@override
Widget build(BuildContext context) {
return ExampleScaffold(
title: 'Payment Sheet',
tags: ['Single Step'],
children: [
Stepper(
controlsBuilder: emptyControlBuilder,
currentStep: step,
steps: [
Step(
title: Text('Init payment'),
content: LoadingButton(
onPressed: initPaymentSheet,
text: 'Init payment sheet',
),
),
Step(
title: Text('Confirm payment'),
content: LoadingButton(
onPressed: confirmPayment,
text: 'Pay now',
),
),
],
),
],
);
}

Future<void> _createIntentAndConfirmToUser() async {
final url = Uri.parse('$kApiUrl/payment-sheet');
final response = await http.post(
url,
headers: {
'Content-Type': 'application/json',
},
body: json.encode({
'a': 'a',
}),
);
final body = json.decode(response.body);
if (body['error'] != null) {
throw Exception(body['error']);
}

await Stripe.instance.intentCreationCallback(
IntentCreationCallbackParams(clientSecret: body['paymentIntent']));
}

Future<void> initPaymentSheet() async {
try {
// // 1. create payment intent on the server
// final data = await _createTestPaymentSheet();

// create some billingdetails
final billingDetails = BillingDetails(
name: 'Flutter Stripe',
email: '[email protected]',
phone: '+48888000888',
address: Address(
city: 'Houston',
country: 'US',
line1: '1459 Circle Drive',
line2: '',
state: 'Texas',
postalCode: '77063',
),
); // mocked data for tests

// 2. initialize the payment sheet
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
// Main params
merchantDisplayName: 'Flutter Stripe Store Demo',
intentConfiguration: IntentConfiguration(
mode: IntentMode(
currencyCode: 'EUR',
amount: 1500,
),
intentCreationCallback: (method, saveFuture) {
_createIntentAndConfirmToUser();
}),

// Extra params
primaryButtonLabel: 'Pay now',
applePay: PaymentSheetApplePay(
merchantCountryCode: 'DE',
),
googlePay: PaymentSheetGooglePay(
merchantCountryCode: 'DE',
testEnv: true,
),
style: ThemeMode.dark,
appearance: PaymentSheetAppearance(
colors: PaymentSheetAppearanceColors(
background: Colors.lightBlue,
primary: Colors.blue,
componentBorder: Colors.red,
),
shapes: PaymentSheetShape(
borderWidth: 4,
shadow: PaymentSheetShadowParams(color: Colors.red),
),
primaryButton: PaymentSheetPrimaryButtonAppearance(
shapes: PaymentSheetPrimaryButtonShape(blurRadius: 8),
colors: PaymentSheetPrimaryButtonTheme(
light: PaymentSheetPrimaryButtonThemeColors(
background: Color.fromARGB(255, 231, 235, 30),
text: Color.fromARGB(255, 235, 92, 30),
border: Color.fromARGB(255, 235, 92, 30),
),
),
),
),
billingDetails: billingDetails,
),
);
setState(() {
step = 1;
});
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
);
rethrow;
}
}

Future<void> confirmPayment() async {
try {
// 3. display the payment sheet.
await Stripe.instance.presentPaymentSheet();

setState(() {
step = 0;
});

ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Payment succesfully completed'),

Check warning on line 159 in example/lib/screens/payment_sheet/payment_sheet_deffered_screen.dart

View workflow job for this annotation

GitHub Actions / Typo CI

succesfully

"succesfully" is a typo. Did you mean "successfully"?
),
);
} on Exception catch (e) {
if (e is StripeException) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error from Stripe: ${e.error.localizedMessage}'),
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Unforeseen error: ${e}'),
),
);
}
}
}
}
6 changes: 6 additions & 0 deletions example/lib/screens/screens.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:stripe_example/screens/checkout/checkout_screen.dart';
import 'package:stripe_example/screens/payment_sheet/payment_element/payment_element.dart';
import 'package:stripe_example/screens/payment_sheet/payment_sheet_deffered_screen.dart';
import 'package:stripe_example/screens/payment_sheet/payment_sheet_screen.dart';
import 'package:stripe_example/screens/payment_sheet/payment_sheet_screen_custom_flow.dart';
import 'package:stripe_example/screens/regional_payment_methods/ali_pay_screen.dart';
Expand Down Expand Up @@ -101,6 +102,11 @@ class Example extends StatelessWidget {
builder: (context) => PaymentSheetScreen(),
platformsSupported: [DevicePlatform.android, DevicePlatform.ios],
),
Example(
title: 'Single Step (deffered payment)',

Check warning on line 106 in example/lib/screens/screens.dart

View workflow job for this annotation

GitHub Actions / Typo CI

deffered

"deffered" is a typo. Did you mean "differed"?
builder: (context) => PaymentSheetDefferedScreen(),

Check warning on line 107 in example/lib/screens/screens.dart

View workflow job for this annotation

GitHub Actions / Typo CI

PaymentSheetDefferedScreen

"PaymentSheetDefferedScreen" is a typo. Did you mean "PaymentSheetDifferedScreen"?
platformsSupported: [DevicePlatform.android, DevicePlatform.ios],
),
Example(
title: 'Custom Flow',
builder: (context) => PaymentSheetScreenWithCustomFlow(),
Expand Down
7 changes: 7 additions & 0 deletions packages/stripe/lib/src/stripe.dart
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,13 @@ class Stripe {
return await _platform.presentPaymentSheet(options: options);
}

/// Method used to confirm to the user that the intent is created successfull
/// or not successfull when using a defferred payment method.

Check warning on line 448 in packages/stripe/lib/src/stripe.dart

View workflow job for this annotation

GitHub Actions / Typo CI

defferred

"defferred" is a typo. Did you mean "deferred"?
Future<void> intentCreationCallback(IntentCreationCallbackParams params) async {
await _awaitForSettings();
return await _platform.intentCreationCallback(params);
}

/// Call this method when the user logs out from your app.
///
/// This will ensure that any persisted authentication state in the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:stripe_platform_interface/src/models/ach_params.dart';
import 'package:stripe_platform_interface/src/models/create_token_data.dart';
import 'package:stripe_platform_interface/src/models/financial_connections.dart';
import 'package:stripe_platform_interface/src/models/google_pay.dart';
import 'package:stripe_platform_interface/src/models/intent_creation_callback_params.dart';
import 'package:stripe_platform_interface/src/models/platform_pay.dart';
import 'package:stripe_platform_interface/src/models/wallet.dart';
import 'package:stripe_platform_interface/src/result_parser.dart';
Expand Down Expand Up @@ -32,9 +33,7 @@ class MethodChannelStripe extends StripePlatform {
required bool platformIsAndroid,
}) : _methodChannel = methodChannel,
_platformIsAndroid = platformIsAndroid,
_platformIsIos = platformIsIos {
_init();
}
_platformIsIos = platformIsIos;

final MethodChannel _methodChannel;
final bool _platformIsIos;
Expand All @@ -58,9 +57,11 @@ class MethodChannelStripe extends StripePlatform {
'urlScheme': urlScheme,
'setReturnUrlSchemeOnAndroid': setReturnUrlSchemeOnAndroid,
});
}

void _init() {}
_methodChannel.setMethodCallHandler((call) async {
print('foo ${call.method}');
});
}

@override
Future<PaymentMethod> createPaymentMethod(
Expand Down Expand Up @@ -509,6 +510,15 @@ class MethodChannelStripe extends StripePlatform {
orderDetails.toJson(),
);
}

@override
Future<void> intentCreationCallback(
IntentCreationCallbackParams params) async {
await _methodChannel.invokeMethod(
'intentCreationCallback',
{'params': params.toJson()},
);
}
}

class MethodChannelStripeFactory {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/// Defines how the money will be captured from the customer's account.
// ignore_for_file: constant_identifier_names

enum CaptureMethod {
/// Reserve the funds but the customer has to authorize the payment.
Manual,

/// Funds are automatically captured by stripe
Automatic,

/// The payment was collected outside of Stripe.
AutomaticAsync,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:stripe_platform_interface/src/models/errors.dart';

part 'intent_creation_callback_params.freezed.dart';

Check warning on line 4 in packages/stripe_platform_interface/lib/src/models/intent_creation_callback_params.dart

View workflow job for this annotation

GitHub Actions / Typo CI

freezed

"freezed" is a typo. Did you mean "freezes"?
part 'intent_creation_callback_params.g.dart';

@freezed

Check warning on line 7 in packages/stripe_platform_interface/lib/src/models/intent_creation_callback_params.dart

View workflow job for this annotation

GitHub Actions / Typo CI

freezed

"freezed" is a typo. Did you mean "freezes"?
class IntentCreationCallbackParams with _$IntentCreationCallbackParams {
@JsonSerializable(explicitToJson: true)
const factory IntentCreationCallbackParams({
/// Client secret of the payment intent or setup intent.
String? clientSecret,

/// Error that occurred during the creation of the payment intent or setup intent.
StripeException? error,
}) = _IntentCreationCallbackParams;

factory IntentCreationCallbackParams.fromJson(Map<String, dynamic> json) =>
_$IntentCreationCallbackParamsFromJson(json);
}
Loading

0 comments on commit 9906a5c

Please sign in to comment.