Skip to content

Instantly share code, notes, and snippets.

@takumade
Created December 14, 2021 09:40
Show Gist options
  • Save takumade/b159f2b18e887357dd3f41c027f2e37e to your computer and use it in GitHub Desktop.
Save takumade/b159f2b18e887357dd3f41c027f2e37e to your computer and use it in GitHub Desktop.
Flutter Stripe checkout
import 'package:flutter_stripe/flutter_stripe.dart';
// Initialize Stripe: Either in main or another file
Stripe.publishableKey = "YOUR KEY HERE";
Stripe.merchantIdentifier = "MERCHANT ID HERE";
// Stripe file, for payments
class StripePayments {
String itemDesc = "";
int amount = 0;
double totalCost = 0;
int finalAmount = 0;
double tip = 1.0;
double tax = 0.0;
double taxPercent = 0.15;
final paymentType;
String gateway = "stripe";
PaymentResponse? paymentResponse;
PaymentMethod? paymentMethod;
StripeSettings? stripeSettings;
final paymentsRepo = PaymentsRepo();
final dynamic productId;
final purchaseType;
final settingsBox = Hive.box("settings");
final auth = Get.find<AuthController>();
String invoiceId =
"Invoice " + DateTime.now().millisecondsSinceEpoch.toString();
String customerId =
"customer-" + DateTime.now().millisecondsSinceEpoch.toString();
List<BuyItem>? _items;
StripePayments({this.paymentType, this.productId, this.purchaseType});
Future<PaymentResponse> payWithCurrentCard(
CardFieldInputDetails? _card) async {
if (_card == null) {
print("Stop 1");
return PaymentResponse(
status: false,
message: "Please add card!",
errorCode: "payment_failed");
}
try {
print("Stop 2");
// 1. Gather customer billing information (ex. email)
final billingDetails =
await this.getBillingAddress(); // mocked data for tests
// 2. Create payment method
final paymentMethod =
await Stripe.instance.createPaymentMethod(PaymentMethodParams.card(
billingDetails: billingDetails,
));
print("Stop 3");
// 3. call API to create PaymentIntent
final paymentIntentResult = await remoteCreatePaymentIntent(
useStripeSdk: true,
paymentMethodId: paymentMethod.id,
currency: 'usd', // mocked data
items: [
{
'amount': this.finalAmount,
'name': 'A movie',
'desc': 'A description'
}
],
);
print("Stop 4");
if (paymentIntentResult['error'] != null) {
// Error during creating or confirming Intent
return PaymentResponse(
errorCode: "payment_failed",
message: 'Error: ${paymentIntentResult['error']}',
status: false);
}
print("Stop 5");
if (paymentIntentResult['clientSecret'] != null &&
paymentIntentResult['requiresAction'] == null) {
// Payment succedeed
await this.saveTranscaction();
return PaymentResponse(
errorCode: "payment_success",
message: 'The payment was confirmed successfully!',
status: true);
}
if (paymentIntentResult['clientSecret'] != null &&
paymentIntentResult['requiresAction'] == true) {
// 4. if payment requires action calling handleCardAction
final paymentIntent = await Stripe.instance
.handleCardAction(paymentIntentResult['clientSecret']);
// todo handle error
/*if (cardActionError) {
Alert.alert(
`Error code: ${cardActionError.code}`,
cardActionError.message
);
} else*/
if (paymentIntent.status == PaymentIntentsStatus.RequiresConfirmation) {
// 5. Call API to confirm intent
return await confirmIntent(paymentIntent.id);
} else {
// Payment succedeed
return PaymentResponse(
errorCode: "payment_failed",
message: 'Error: ${paymentIntentResult['error']}',
status: false);
}
}
} catch (e) {
print(e);
String? errorMessage = "";
if (e is StripeException) {
errorMessage = e.error.message;
}
if (e is PlatformException) {
errorMessage = e.message;
}
return PaymentResponse(
errorCode: "payment_failed", message: errorMessage, status: false);
}
return PaymentResponse(
status: false,
message: "Payment Failed, Unknown Error!",
errorCode: "payment_failed");
}
Future<PaymentResponse> confirmIntent(String paymentIntentId) async {
final result =
await remoteConfirmPaymentIntent(paymentIntentId: paymentIntentId);
if (result['error'] != null) {
return PaymentResponse(
status: false,
message: 'Error: ${result['error']}',
errorCode: 'payment_failed');
} else {
await this.saveTranscaction();
return PaymentResponse(
status: true,
message: 'Success!: The payment was confirmed successfully!',
errorCode: 'payment_success');
}
}
Future<Map<String, dynamic>> remoteConfirmPaymentIntent({
String? paymentIntentId,
}) async {
final result = await this.paymentsRepo.stripeChargeCard(paymentIntentId);
return result;
}
Future<Map<String, dynamic>> remoteCreatePaymentIntent({
bool? useStripeSdk,
String? paymentMethodId,
String? currency,
List<Map<String, dynamic>>? items,
}) async {
final result = await paymentsRepo.stripeCreatePaymentIntent(
useStripeSdk, paymentMethodId, currency, items);
return result!;
}
Future<void> saveTranscaction() async {
final transactionBox = Hive.box('transactions');
final paymentRepo = PaymentsRepo();
final transcation = Transcation(
auth.currentUser!.userId,
this.productId,
this.purchaseType,
this.gateway,
this.invoiceId,
this.customerId,
this.totalCost);
await transactionBox.add(transcation.toMap());
await paymentRepo.setUserPayment(transcation);
}
Future<BillingDetails> getBillingAddress() async {
AppBillingDetails billingDetails;
var results = settingsBox.get("billing_details");
if (results == null) {
billingDetails = new AppBillingDetails(
auth.currentUser!.userName,
"35 Coronation Avenue",
"Greendale, Harare",
"Harare",
"Mashonaland East",
"000000",
auth.currentUser!.userEmail,
"077777777", // TODO: Put real user number here
"Zimbabwe");
} else {
billingDetails = AppBillingDetails.fromJson(results);
}
return BillingDetails(
email: billingDetails.email,
phone: billingDetails.phone,
address: Address(
city: billingDetails.city,
country: billingDetails.country,
line1: billingDetails.address1,
line2: billingDetails.address2,
state: billingDetails.state,
postalCode: billingDetails.zip,
),
);
}
Future<void> createPayment(List<BuyItem>? items) async {
this._items = items;
for (BuyItem i in _items!) {
itemDesc += i.name!;
totalCost += i.price;
}
// Calculate final amount
final stripeCharge = (2.9 / 100) * this.totalCost + 0.30;
this.totalCost = (this.totalCost + stripeCharge) * 100;
this.finalAmount = int.parse(this.totalCost.toStringAsFixed(0));
}
}
//
Future<Map<String, dynamic>> remoteConfirmPaymentIntent({
String? paymentIntentId,
}) async {
final result = await this.paymentsRepo.stripeChargeCard(paymentIntentId);
return result;
}
///////////////////////////////////////////////////////////
//
//. PAYMENTS REPO
//
///////////////////////////////////////////////////////////
Future<Map<String, dynamic>> remoteCreatePaymentIntent({
bool? useStripeSdk,
String? paymentMethodId,
String? currency,
List<Map<String, dynamic>>? items,
}) async {
final result = await paymentsRepo.stripeCreatePaymentIntent(
useStripeSdk, paymentMethodId, currency, items);
return result!;
}
Future<Map<String, dynamic>> stripeChargeCard(String? paymentIntentId) async {
final url = '$kApiUrl/charge-card-off-session';
final response = await Dio().post(
url,
queryParameters: {
'paymentIntentId': paymentIntentId,
},
);
Future<Map<String, dynamic>?> stripeCreatePaymentIntent(
bool? useStripeSdk,
String? paymentMethodId,
String? currency,
List<Map<String, dynamic>>? items) async {
final url = '$kApiUrl/pay-without-webhooks';
try {
final response = await Dio().post(
url,
options: Options(headers: {
'Content-Type': 'application/json',
}),
data: jsonEncode({
'useStripeSdk': useStripeSdk,
'paymentMethodId': paymentMethodId,
'currency': currency,
'items': items
}),
);
final result = Map<String, dynamic>.from(response.data);
return result;
} catch (err) {
if (err is DioError) {
print(err.response!.data);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment