Flutter Stripe Web 使用 PaymentElement 而不是 PaymentSheet

问题描述 投票:0回答:2

在探索其他选项后,我了解到解决在 Flutter Web 应用程序中接受卡付款的用例问题的唯一方法是通过 Flutter_stripe 和 flutter_stripe_web 包。

我实现了这两个功能,以发现 Web 不支持 Stripe.PaymentSheet。 :( 从 Stripe 支持中,我了解到我应该使用 Stripe.PaymentElement 而不是 PaymentSheet,而其余代码保持不变,即 PaymentIntent 和后端函数等

我尝试过以下文档(尽管在 Flutter/dart 的上下文中有点不清楚),但我只是无法填充缺失的块。

你们能看一下并让我知道我做错了什么或者什么是实现 PaymentElement 而不是 Sheets 的正确方法吗

提前致谢。

我的付款文件

import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:http/http.dart' as http;

    class StripePayments {
      Future<void> initPaymentSheet(context,
          {required String email, required int amount}) async {
        try {
          // 1. create payment intent on the server
          final response = await http.post(
              Uri.parse(
                  'https://mycloudFunctionUrl/stripePaymentIntentRequest'),
              body: {
                'email': email,
                'amount': amount.toString(),
              });
    
          if (response.statusCode != 200) {
            throw Exception('Failed to create payment intent: ${response.body}');
          }
    
          final jsonResponse = jsonDecode(response.body);
          log('Payment intent response: $jsonResponse');
    
          // 2. Verify the keys and data
          if (jsonResponse['paymentIntent'] == null ||
              jsonResponse['customer'] == null ||
              jsonResponse['ephemeralKey'] == null) {
            throw Exception('Invalid response from server: $jsonResponse');
          }
    
          // 3. initialize the payment sheet
    
          await Stripe.instance.initPaymentSheet(
            paymentSheetParameters: SetupPaymentSheetParameters(
              paymentIntentClientSecret: jsonResponse['paymentIntent'],
              merchantDisplayName: 'Cruise-App',
              customerId: jsonResponse['customer'],
              customerEphemeralKeySecret: jsonResponse['ephemeralKey'],
              style: ThemeMode.light,
            ),
          );
    
          // 4. Present the payment sheet
          await Stripe.instance.presentPaymentSheet();
    
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Payment completed!')),
          );
        } catch (e) {
          if (e is StripeException) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text('Error from Stripe: ${e.error.localizedMessage}'),
              ),
            );
          } else if (e is StripeConfigException) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text('Stripe configuration error: ${e.message}'),
              ),
            );
          } else {
            print(e.toString());
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Error: $e')),
            );
          }
        }
      }
    }

这就是我的后端/云功能的样子

const functions = require("firebase-functions");
const cors = require("cors")({ origin: true });
const stripe = require("stripe")("sk_test_my_secret_key");

exports.stripePaymentIntentRequest = functions.region("europe-west3").https.onRequest((req, res) => {
  cors(req, res, async () => {
    try {
      let customerId;

      // Gets the customer whose email id matches the one sent by the client
      const customerList = await stripe.customers.list({
        email: req.body.email,
        limit: 1
      });

      // Checks if the customer exists, if not creates a new customer
      if (customerList.data.length !== 0) {
        customerId = customerList.data[0].id;
      } else {
        const customer = await stripe.customers.create({
          email: req.body.email
        });
        customerId = customer.id; // Changed customer.data.id to customer.id
      }

      // Creates a temporary secret key linked with the customer
      const ephemeralKey = await stripe.ephemeralKeys.create(
        { customer: customerId },
        { apiVersion: '2020-08-27' }
      );

      // Creates a new payment intent with amount passed in from the client
      const paymentIntent = await stripe.paymentIntents.create({
        amount: parseInt(req.body.amount),
        currency: 'nok',
        customer: customerId,
      });

      res.status(200).send({
        paymentIntent: paymentIntent.client_secret,
        ephemeralKey: ephemeralKey.secret,
        customer: customerId,
        success: true,
      });

    } catch (error) {
      res.status(404).send({ success: false, error: error.message });
    }
  });
});

这是 Stripe 团队向我推荐的文档,但他们的支持人员在 Discord 上表示,“我们不知道 dart 或 flutter。不确定已经做过的人是如何做到这一点的”

请推荐!再次感谢您

flutter stripe-payments
2个回答
1
投票

您可以直接使用PaymentElement小部件。我对此了解不多,但这可能会帮助您入门。

var paymentIntentResult = await createPaymentIntent('100','JYP');
var paymentIntentSecret = paymentIntentResult['client_secret'];

PaymentElement(
        autofocus: true,
        enablePostalCode: true,
        onCardChanged: (_) {},
        clientSecret: paymentIntentSecret ?? '',
)

createPaymentIntent(String amount, String currency) async {
try {
  //Request body
  Map<String, dynamic> body = {
    'amount': calculateAmount(amount),
    'currency': currency,
  };

  //Make post request to Stripe
  var response = await http.post(
    Uri.parse('https://api.stripe.com/v1/payment_intents'),
    headers: {
      'Authorization':
          'Bearer [your_key]',
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: body,
  );
  return json.decode(response.body);
} catch (err) {
  throw Exception(err.toString());
}

并用它来拨打电话

 OutlinedButton(
          onPressed: () async {
            try {
              await WebStripe.instance
                  .confirmPaymentElement(ConfirmPaymentElementOptions(
                redirect: PaymentConfirmationRedirect.ifRequired,
                confirmParams: ConfirmPaymentParams(return_url: ''),
              ));
            } on Exception catch (e) {
              print(e.toString());
            }
          },
          child: Text('Go'));

0
投票

完整情况的简要说明

class StripeTestScreen extends StatefulWidget {
  const StripeTestScreen({super.key});

  @override
  State<StripeTestScreen> createState() => _StripeTestScreenState();
}

class _StripeTestScreenState extends State<StripeTestScreen> {
  final controller = CardFormEditController();

  String? paymentIntentSecret;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          if (paymentIntentSecret != null)
            PaymentElement(
              autofocus: true,
              enablePostalCode: true,
              onCardChanged: (_) {},
              clientSecret: paymentIntentSecret ?? '',
            ),
          ElevatedButton(
            onPressed: makePayment,
            child: const Text('Get Product'),
          ),
          OutlinedButton(
              onPressed: () async {
                try {
                  var paymentIntent = await WebStripe.instance.confirmPaymentElement(const ConfirmPaymentElementOptions(
                    redirect: PaymentConfirmationRedirect.ifRequired,
                    confirmParams: ConfirmPaymentParams(return_url: ''),
                  ));
                  log(paymentIntent.toString());
                } on Exception catch (e) {
                  print(e.toString());
                }
              },
              child: Text('Go')),
        ],
      ),
    );
  }

  Future<void> makePayment() async {
    try {
      paymentIntentSecret = await createPaymentIntent('499', 'USD');
      setState(() {});
    } catch (err) {
      throw Exception(err);
    }
  }

  createPaymentIntent(String amount, String currency) async {
    try {
      Map<String, dynamic> body = {
        'amount': amount,
        'currency': currency,
      };

      var response = await http.post(
        Uri.parse('https://api.stripe.com/v1/payment_intents'),
        headers: {
          'Authorization':
              'Bearer <your secret key>',
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: body,
      );

      log('LOG: ${response.body}');
      return json.decode(response.body)?['client_secret'];
    } catch (err) {
      log("LOG ERR createPaymentIntent: ${err.toString()}");
      throw Exception(err.toString());
    }
  }
}

© www.soinside.com 2019 - 2024. All rights reserved.