Кнопка запроса оплаты Stripe с подписками

Я действительно устал искать нужную информацию и надеюсь на вашу помощь. Также я написал в поддержку Stripe, но пока общение с ними очень затруднено.

Начнем с самого начала.

Я использую подписки Stripe с Laravel Cashier.

Я уже завершил оплату кредитной / дебетовой картой. У него такой рабочий процесс: - пользователь заполняет форму; - Stripe.js отправляет заполненные данные на сервер Stripe и возвращает paymentMethod; - затем я отправляю paymentMethod на свой сервер и оформляю подписку для пользователя с / без пробных дней.

Мне нужно добавить кнопки Google Pay и Apple Pay. Согласно документам Stripe о Google Pay и Apple Pay, мне нужно создать кнопку запроса платежа. Насколько я понимаю, документы о кнопке запроса платежа работают следующим образом: - на стороне сервера создается paymentIntent и отправляется его клиентской стороне;- пользователь нажимает кнопку "Запрос платежа";- браузер открывает всплывающее окно с сохраненными карточками пользователя;- пользователь выбирает карту, и stripe.js моментально снимает с него деньги.

Я не могу понять, на какой шаговой полосе известен идентификатор плана для создания подписки для пользователя.

Мне не нужно заряжать пользователя мгновенно, мне нужно просто получить paymentMethod, чтобы отправить его на сервер. Есть ли у кого-нибудь опыт создания подписок Stripe с кнопкой запроса платежа?

Буду очень признателен за помощь.

3 ответа

Вот как я это сделал. Я использовал JS на клиенте и сервере, но по большей части шаги такие же, даже если синтаксис отличается. На это так мало документации - я подумал, смогу ли я помочь. Даже если это совсем другое, большая часть логики должна быть такой же. Конкретно:

Frontend returns paymentRequest -> Server-takes-paymentRequest -> customer -> subscription -> Done

Во-первых, вам не нужно ничего делать с платежным намерением на веб-интерфейсе. Некоторое время я был на этом зациклен.

Далее, начиная все, используя stripe.paymentRequest() который принимает некоторые платежные реквизиты и возвращает объект PaymentRequest..

Здесь вы обрабатываете рендеринг кнопки на основе PaymentRequest.canMakePayment()

Следующее, как я поступаю, когда они нажимают кнопку "Платить".

В paymentRequest есть метод "on", который по сути является подписчиком. Я думаю, это называется веб-крючком. Он принимает 2 аргумента, строку "paymentmethod", указывающую, чего вы ждете, и функцию, которой в качестве аргумента передается результат события, например

    stripePaymentRequest.on('paymentmethod', (event) => {
      const paymentMethod = event.paymentMethod

      if (paymentMethod) {
        // call your server and pass it the payment method 
        // for Server side Stripe-API handling of payment
      }

      event.complete('success'); // Completes the transaction and closes Google/Apple pay
    });

Когда вы звоните на сервер, вы можете обрабатывать его аналогично карточному платежу, поскольку у вас есть способ оплаты.

1: вы создаете объект "Клиент" из полосы, используя способ оплаты. Я использовал что-то вроде

        const customer = await stripe.customers.create({
            payment_method: paymentMethod.id,
            email: paymentMethod.billing_details.email,
            invoice_settings: {
                default_payment_method: paymentMethod.id,
            },
        });

2: вы создаете объект "Подписка" из полосы с помощью клиента, я сделал это так

        const subscription = await stripe.subscriptions.create({
            customer: customer.id,
            items: [{ plan: "plan_HereIsYourPlanID" }], // <--
            trial_period_days: 7,
            expand: ["latest_invoice.payment_intent"],
        });

3: Предыдущий шаг должен выполнить все, что вам нужно для Stripe. На данный момент у меня есть часть моего собственного кода управления пользователями, чтобы отслеживать, подписался ли мой пользователь или нет. Затем вы возвращаете успех или нет - той функции, которую вы вызывали во внешнем интерфейсе, и теперь, когда все готово, вы вызываете event.complete('success')

Надеюсь, это поможет. Извините, это не PHP, но, надеюсь, это начало.

SeanMC, большое спасибо за этот ответ - документации по использованию PaymentRequestButton с подписками очень мало. Руководство Stripe по PaymentRequestButton включает в себя paymentIntents, которые я ошибочно думал, что это требование для использования RequestPaymentButton.

У меня были небольшие проблемы с вашим кодом, поэтому я хотел поделиться своей реализацией для всех, кто может с этим бороться.

Я использую Stripe Elements (StripeJS) на стороне клиента для типичной платежной страницы с полями для платежной информации, а также для ввода информации CC. Я хочу, чтобы клиенты могли использовать Apple Pay или Google Pay, чтобы ускорить процесс оформления заказа. Вот мой компонент ниже, который выполняет это (я удалил некоторые определения импорта /TypeScript для ясности).

import React, { useEffect, useState } from 'react';
import {
  PaymentRequestButtonElement,
  useStripe,
} from '@stripe/react-stripe-js';
import * as stripeJs from '@stripe/stripe-js';

const AlternativePaymentOption: React.FC = ({
  price, //the price for the subscription being purchased
  priceId, //the priceId for the subscription (I found it easiest to create one 
           //product with multiple priceId for the different subscription tiers
  checkout,
}) => {
  const stripe = useStripe();
  const [paymentRequest, setPaymentRequest] = useState<
    stripeJs.PaymentRequest
  >();

  useEffect(() => {
    //return early if missing dependancies
    if (!stripe || !price) return;
    //create the paymentRequest which is passed down to
    //to the <PaymentRequestButtonElement /> as a prop
    const pr = stripe.paymentRequest({
      country: 'US',
      currency: 'usd',
      total: {
        label: 'Website Subscription',
        amount: price * 100,
      },
      requestPayerName: true,
      requestPayerEmail: true,
      requestPayerPhone: true,
    });
    //check if the browser has a saved card that can be used
    pr.canMakePayment()
      .then((result) => {
        //user has a saved card that can be used - display button
        if (result) {
          //the render method below is conditional based on this state
          setPaymentRequest(pr);
          pr.on('paymentmethod', (ev) => {
            //this event is triggered at the completion of the saved payment 
            //interface
            //we don't care about the actual payment request anymore
            //now that we have a paymentMethod, we can check out as normal
            //the checkout function I am not including here, but is very similar 
            //to the 'create a subscription' stripe guide
            //however it is important to note that I am passing in the event as an 
            //argument.  Once checkout receives a response from my server as to 
            //wether the transaction was successful or not, use 
            //ev.complete('success') and ev.complete('fail') accordingly to close
            //the modal or display an error message (browser specific behavior)
            checkout(ev.paymentMethod.id, ev);
          });
        }
      })
      .catch((err) => {
        //log errors, retry, or abort here depending on your use case
      });
     //stripe, priceId, and price are listed as dependancies so that if they 
     //change, useEffect re-runs.
  }, [stripe, priceId, price]);
  return (
    <>
      {paymentRequest && (
        <PaymentRequestButtonElement
          options={{ paymentRequest }}
          //hacky fix to make force this component to re-render
          //a la https://github.com/stripe/react-stripe-elements/issues/284
          key={Math.random()}
        />
      )}
    </>
  );
};

export default AlternativePaymentOption;

Надеюсь, это поможет любому в подобной ситуации. Я заблудился в траве, работая над этим в течение двух дней, прежде чем я открыл для себя этот подход благодаря SeanMC.

Неперехваченное (в обещании) исключение DOMException: не удалось выполнить 'complete' в 'PaymentResponse': время ожидания истекло через 60 секунд, метод complete() вызван слишком поздно на https://js.stripe.com/v3/fingerprinted/js/payment-request -внутренний браузер-4b0f08c05410918c9c08f2c24bf68698.js: 1: 11808

Другие вопросы по тегам