Flutter & Stripe - Подписка - PaymentSheet не может настроить PaymentIntent в статусе "успешно"Android

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Flutter & Stripe - Подписка - PaymentSheet не может настроить PaymentIntent в статусе "успешно"

Сообщение Anonymous »

У меня есть приложение, написанное на Flutter, и я реализовал в нем единовременную оплату (например, игровые очки) с помощью Stripe SDK 11.0.0. Моя серверная часть и приложение идеально подходят для сценария единовременного платежа. Я вижу успех на экране своего мобильного телефона, а оплату — на панели управления Stripe.
Теперь мне захотелось реализовать оплату подписок.
Вы можете видеть, что я делаю. до сих пор я делал во всем классе модели представления только для этого сценария:

Код: Выделить всё

import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:get/get.dart';
import 'package:my_app/data/response/Status.dart';
import 'package:my_app/repository/marketing/MarketingRepository.dart';
import 'package:my_app/view_models/user_preference/UserPreference.dart';

class SubscriptionViewModel extends GetxController {
final _api = MarketingRepository();
UserPreference userPreference = UserPreference();

final rxRequestStatus = Status.LOADING.obs;
RxString clientSecret = ''.obs;
RxString ephemeralKey = ''.obs;
RxString customerId = ''.obs;

/// Handles subscription for all three cases
Future handleSubscription(String plan) async {
try {
var user = await userPreference.getUser();

// Step 1: Make request to the backend to check for payment method and retrieve necessary information
Map data = {
MY_REQUEST_BODY_HERE
};

// API call to backend to initiate subscription
var response = await _api.paymentApi(
data,
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer ${user.accessToken}"
},
);

// Handle the response based on the status
if (response["status"] == "requires_payment_method") {
// Case 1: No payment method available, collect payment details
print('No payment method available, need to collect payment details');

await collectPaymentMethod(
response["setupIntentClientSecret"],
response["customerId"],
response["ephemeralKey"],
plan
);

} else if (response["status"] == "success" && response["payload"]["clientSecret"] != null) {
if (response["payload"]["ephemeralKey"] != null) {
// Case 2: User has a payment method but it's not the default, retrieve and use it
print('User has a payment method, but not default.');
await confirmSubscription(response["payload"]["clientSecret"], response["payload"]["ephemeralKey"], response["payload"]["customerId"]);
} else {
// Case 3: User has a default payment method, directly pop up payment sheet
print('User has a default payment method.  Confirming subscription.');
await confirmSubscription(response["payload"]["clientSecret"], "", response["payload"]["customerId"]);
}
}
} catch (e) {
print('Error during subscription: $e');
if (e is StripeException) {
print('Stripe error: ${e.error.localizedMessage}');
} else {
print('Unexpected error: $e');
}
}
}

/// Collect payment method when none is available (Case 1)
Future collectPaymentMethod(String setupIntentClientSecret, String customerId, String ephemeralKey, String plan) async {
try {
// Initialize payment sheet for collecting new payment method
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
customFlow: false,
merchantDisplayName: 'My Store',
setupIntentClientSecret: setupIntentClientSecret,
customerEphemeralKeySecret: ephemeralKey,
customerId: customerId,
),
);

// Present the payment sheet for the user to enter payment details
await Stripe.instance.presentPaymentSheet();

print('Payment method successfully added!');

// Retrieve the payment method from the SetupIntent after the payment sheet is completed
final paymentMethodId = await retrievePaymentMethodIdFromSetupIntent(setupIntentClientSecret);

if (paymentMethodId != null) {
print('PaymentMethodId: $paymentMethodId');

// Send the paymentMethodId to the backend to set it as default and complete the subscription
var user2 = await userPreference.getUser();

// Step 1: Make request to the backend to check for payment method and retrieve necessary information
Map data2 = {
MY_REQUEST_BODY_HERE
'paymentMethodId': paymentMethodId,
};

// API call to backend to initiate subscription
await _api.paymentApi(
data2,
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer ${user2.accessToken}"
},
);

// Show successful subscription
Get.snackbar('Success', 'Subscription completed successfully!');
}

} catch (e) {
print('Error collecting payment method: $e');
if (e is StripeException) {
print('Stripe error: ${e.error.localizedMessage}');
} else {
print('Unexpected error: $e');
}
}
}

/// Helper method to retrieve the paymentMethodId from a SetupIntent
Future retrievePaymentMethodIdFromSetupIntent(String setupIntentClientSecret) async {
try {
// Fetch the SetupIntent to retrieve the attached payment method
final setupIntent = await Stripe.instance.retrieveSetupIntent(setupIntentClientSecret);
if (setupIntent.paymentMethodId != null) {
return setupIntent.paymentMethodId; // Retrieve the payment method ID
} else {
print('No payment method was found in the SetupIntent.');
return null;
}
} catch (e) {
print('Error retrieving payment method from SetupIntent: $e');
return null;
}
}

/// Confirm subscription for users with a payment method (Case 2 & Case 3)
Future  confirmSubscription(String clientSecret, String ephemeralKey, String customerId) async {
try {
// Initialize payment sheet for confirmation
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
customFlow: false,
merchantDisplayName: 'My Store',
paymentIntentClientSecret: clientSecret,
customerEphemeralKeySecret: ephemeralKey,  // This will be empty for default payment methods
customerId: customerId,
),
);

// Present the payment sheet to confirm the subscription
await Stripe.instance.presentPaymentSheet().then((e) {
Stripe.instance.confirmPaymentSheetPayment();
});

print('Subscription confirmed successfully!');

// Show successful subscription
Get.snackbar('Success', 'Subscription completed successfully!');

} catch (e) {
print('Error confirming subscription: $e');
if (e is StripeException) {
print('Stripe error: ${e.error.localizedMessage}');
} else {
print('Unexpected error: $e');
}
}
}
}
Когда я нажимаю кнопку, она вызывает метод handleSubscription. Проще говоря, он отправляет запрос на мой бэкэнд с телом, включающим некоторые параметры.
Если я нажму первый раз, мой бэкэнд вернет ответ. мне это нравится;

Код: Выделить всё

{
"customerId": "cus_Qy9...",
"ephemeralKey": "ek_test_YWN...",
"message": "Customer has no default payment method. Please provide a payment method.",
"setupIntentClientSecret": "seti_1Q6...",
"status": "requires_payment_method"
}
В моем коде он присоединяется к Case1 (что означает CollectPaymentMethod). И я вижу свой экран следующим образом:
Изображение

Думаю, я поступаю правильно, потому что если я введу номер тестовой карты и нажму кнопку «Настроить», я увижу кнопку зеленой с зеленой галочкой, а затем увижу свою подписку на панели управления Stripe. .
Затем, если я отменю подписку с помощью Stripe Dashboard и если я попытаюсь второй раз использовать другую подписку из своего приложения, мой сервер вернет мне такой ответ: >

Код: Выделить всё

{
"payload": {
"clientSecret": "pi_3Q6...",
"customerId": "cus_Qy9...",
"ephemeralKey": "ek_test_YWN...",
"id": "sub_1Q6...",
"status": "active"
},
"status": "success",
"transaction_type": "subscription"
}
Но на экране я вижу индикатор загрузки, а затем он исчезает. Я вижу это так:
Изображение
Я вижу это в своих журналах;

Код: Выделить всё

I/flutter (21575): User has a payment method, but not default.
I/ContentCaptureHelper(21575): Setting logging level to OFF
I/flutter (21575): Error confirming subscription: StripeException(error: LocalizedErrorMessage(code: FailureCode.Failed, localizedMessage: PaymentSheet cannot set up a PaymentIntent in status 'succeeded'.
I/flutter (21575): See https://stripe.com/docs/api/payment_intents/object#payment_intent_object-status., message: PaymentSheet cannot set up a PaymentIntent in status 'succeeded'.
I/flutter (21575): See https://stripe.com/docs/api/payment_intents/object#payment_intent_object-status., stripeErrorCode: null, declineCode: null, type: null))
I/flutter (21575): Stripe error: PaymentSheet cannot set up a PaymentIntent in status 'succeeded'.
I/flutter (21575): See https://stripe.com/docs/api/payment_intents/object#payment_intent_object-status.
W/WindowOnBackDispatcher(21575): sendCancelIfRunning: isInProgress=falsecallback=androidx.activity.OnBackPressedDispatcher$Api34Impl$createOnBackAnimationCallback$1@a9a0ae4
Странно; Я вижу свою новую подписку на панели управления Stripe.
1-й вопрос;
В случае 1 я вижу кнопку как " Настраивать". Это правильно и все правильно?
2-й вопрос;
Поскольку я вижу журналы ошибок и просто счетчик и исчезает на моем мобильном телефоне, но успешная подписка на панели инструментов Stripe. Можете ли вы сказать мне, чего мне не хватает? Что я делаю не так?
Если вы считаете, что на моем мобильном флаттере все правильно, я могу отредактировать вопрос и добавить сюда свои серверные коды.

Подробнее здесь: https://stackoverflow.com/questions/790 ... tintent-in
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Flutter & Stripe - Подписка - PaymentSheet не может настроить PaymentIntent в статусе "успешно"
    Anonymous » » в форуме Android
    0 Ответы
    24 Просмотры
    Последнее сообщение Anonymous
  • Как получить информацию о контроллере домена, статусе и статусе репликации с помощью LDAP и C#?
    Anonymous » » в форуме C#
    0 Ответы
    34 Просмотры
    Последнее сообщение Anonymous
  • Проблема оплаты Stripe в отношении PaymentIntent требует способа оплаты
    Anonymous » » в форуме C#
    0 Ответы
    132 Просмотры
    Последнее сообщение Anonymous
  • Проблема оплаты Stripe в отношении PaymentIntent требует способа оплаты
    Anonymous » » в форуме C#
    0 Ответы
    96 Просмотры
    Последнее сообщение Anonymous
  • Создание секрета клиента PaymentIntent в Stripe
    Anonymous » » в форуме Php
    0 Ответы
    26 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Android»