付款后 Stripe 订阅未更新为 ACTIVE

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

我有java+react应用程序。想要实施固定价格订阅。我确实遵循了这个示例 github 但看起来我错过了一些东西。

客户输入卡后,我可以在 Stripe 仪表板中看到付款已处理,但订阅仍处于“未完成”状态。这个问题与这个问题类似,但即使添加 ON_SUBSCRIPTION 后我仍然遇到问题。

Java部分:

@GetMapping("/stripe/prices")
public Response<PricesResponse> prices() {

    RequestOptions options = RequestOptions.builder()
            .setApiKey(apiKey)
            .build();

    // search customer

    try {
        CustomerSearchParams params =
                CustomerSearchParams.builder()
                        .setQuery("name:'aaa bbb'")
                        .build();

        CustomerSearchResult customers = Customer.search(params, options);

        List<String> names = customers.getData()
                .stream()
                .map(Customer::getName)
                .toList();

        logger.info(String.valueOf(names));


    } catch (StripeException e) {
        throw new RuntimeException(e);
    }

    // create customer

    Customer customer;

    try {
        String customerName = "Jenny Rosen " + System.currentTimeMillis();

        System.out.println(customerName);

        CustomerCreateParams params =
                CustomerCreateParams.builder()
                        .setName(customerName)
                        .setEmail("[email protected]")
                        .build();
        customer = Customer.create(params, options);
    } catch (StripeException e) {
        throw new RuntimeException(e);
    }

    // get prices

    PriceCollection prices = new PriceCollection();
    try {
        PriceListParams params = PriceListParams
                .builder()
                .build();


        prices = Price.list(params, options);

    } catch (StripeException e) {
        throw new RuntimeException(e);
    }

    // create subscriptions

    Subscription subscription;

    try {
        SubscriptionCreateParams.PaymentSettings paymentSettings =
                SubscriptionCreateParams.PaymentSettings
                        .builder()
                        .setSaveDefaultPaymentMethod(SubscriptionCreateParams.PaymentSettings.SaveDefaultPaymentMethod.ON_SUBSCRIPTION)
                        .build();

        SubscriptionCreateParams subCreateParams = SubscriptionCreateParams
                .builder()
                .setCustomer(customer.getId())
                .addItem(
                        SubscriptionCreateParams
                                .Item.builder()
                                .setPrice(prices.getData().get(0).getId())
                                .build()
                )
                .setPaymentSettings(paymentSettings)
                .setPaymentBehavior(SubscriptionCreateParams.PaymentBehavior.DEFAULT_INCOMPLETE)
                .addAllExpand(Arrays.asList("latest_invoice.payment_intent"))
                .build();

        subscription = Subscription.create(subCreateParams, options);
    } catch (StripeException e) {
        throw new RuntimeException(e);
    }

    // create payment intent

    PaymentIntent paymentIntent;

    try {
        PaymentIntentCreateParams params =
                PaymentIntentCreateParams.builder()
                        .setCustomer(customer.getId())
                        .setAmount(prices.getData().get(0).getUnitAmount())
                        .setCurrency("usd")
                        .build();

        paymentIntent = PaymentIntent.create(params, options);

    } catch (StripeException e) {
        throw new RuntimeException(e);
    }
    
    return new Response<>(new PricesResponse(publishableKey,  paymentIntent.getClientSecret(), prices.getData()
            .stream()
            .map(price -> new PriceResponse(price.getId(), price.getNickname(), price.getUnitAmount()))
            .toList()));
}

反应部分:

价格页面

const Prices = () => {
const navigate = useNavigate();
const [prices, setPrices] = useState([]);
const [clientSecret, setClientSecret] = useState("");

useEffect(() => {
    doRestCall('/stripe/prices', 'get', null, null,
        (response) => {
            setPrices(response.body.prices)
            setClientSecret(response.body.clientSecret)
        })
}, [])

function toCheckout() {
    navigate('/checkout', {
        state: {
            clientSecret
        }
    })
}

return (
    <div>
        <h1>Select a plan</h1>

        <div className="price-list">
            {prices.map((price) => {
                return (
                    <div key={price.id}>
                        <h3>{price.name}</h3>

                        <p>
                            ${price.amount / 100} / month
                        </p>

                        <button onClick={() => toCheckout()}>
                            Select
                        </button>

                    </div>
                )
            })}
        </div>
    </div>
)}

结账页面

const Checkout = () => {

const {
    state: {
        clientSecret,
    }
} = useLocation();

const stripe = useStripe();
const elements = useElements();

const [name, setName] = useState('Jenny Rosen');
const [messages, setMessages] = useState('');

const navigate = useNavigate();

const handleSubmit = async (e) => {
    e.preventDefault();

    const cardElement = elements.getElement(CardElement);

    const { error } = await stripe.confirmCardPayment(clientSecret, {
        payment_method: {
            card: cardElement,
            billing_details: {
                name: name,
            }
        }
    });

    if(error) {
        // show error and collect new card details.
        setMessages(error.message);
        return;
    }

    navigate('/complete', {
        state: {
            clientSecret
        }
    });

};

return (<>
    <h1>Subscribe</h1>

    <p>
        Try the successful test card: <span>4242424242424242</span>.
    </p>

    <p>
        Try the test card that requires SCA: <span>4000002500003155</span>.
    </p>

    <p>
        Use any <i>future</i> expiry date, CVC,5 digit postal code
    </p>

    <hr/>
    <form onSubmit={handleSubmit}>
        <label>
            Full name
            <input type="text" id="name" value={name} onChange={(e) => setName(e.target.value)}/>
        </label>

        <CardElement/>

        <button>
            Subscribe
        </button>

        <div>{messages}</div>
    </form>

</>);

还有关于订阅如何工作页面中的订阅流程的问题。其中提到了“发票”。我应该手动处理吗?我确实在 GitHub 示例中的 java 端看到了 /invoice-preview,但找不到从 React 部分调用它的位置。

java reactjs stripe-payments
1个回答
0
投票

您应该只返回与订阅的

latest_invoice
关联的 PaymentIntent 的 clientSecret,而不是创建新的 PaymentIntent 并返回其 clientSecret。

您可以在集成中找到示例代码指南

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