简体   繁体   中英

On payment success remove all cart items

I have integrated stripe api into my ecommerce website. When you checkout you are sent to the stripe api payment link where you type in your information. Of course two things could happen here, either the payment goes through and succeed or the order gets canceled. Everything works except I am trying to remove all cart items only if the payment succeeds and goes through.

Here is my code:

app.post('/api/createCheckoutSession', async (req, res) => {


    try {
        const session = await stripe.checkout.sessions.create({
            payment_method_types: ['card'],
            mode: 'payment',
            line_items: req.body.items.map(item => {
                const storeItem = storeItems.get(item.id)
                return {
                    price_data: {
                        currency: 'usd',
                        product_data: {
                            name: storeItem.name
                        },
                        unit_amount: storeItem.priceInCents
                    },
                    quantity: item.quantity
                }

            }),
            success_url: `${process.env.SERVER_URL}`,
            cancel_url: `${process.env.SERVER_URL}cart`,
        })

        res.json({ url: session.url })
    } catch (e) {
        console.log(e)
        res.status(500).json({ error: e.message })
    }

});

So if I do the following code I can remove all cartItems from the user, however this happens regardless of if the payment was successful or not:

app.post('/api/createCheckoutSession', async (req, res) => {


    try {
        const session = await stripe.checkout.sessions.create({
            payment_method_types: ['card'],
            mode: 'payment',
            line_items: req.body.items.map(item => {
                const storeItem = storeItems.get(item.id)
                return {
                    price_data: {
                        currency: 'usd',
                        product_data: {
                            name: storeItem.name
                        },
                        unit_amount: storeItem.priceInCents
                    },
                    quantity: item.quantity
                }

            }),
            success_url: `${process.env.SERVER_URL}`,
            cancel_url: `${process.env.SERVER_URL}cart`,

        })


        cartItem.remove({ user: req.body.user }, function (err) {
            if (err) {
                console.log(err)
            }
        })

        res.json({ url: session.url })
    } catch (e) {
        console.log(e)
        res.status(500).json({ error: e.message })
    }
    });

So looking through Stripe api documentation and googling the only thing that consistently comes up is success_url, which wasn't what I am looking for (at least I do not think it will fix what I am trying to do). So for the original code I tried to console.log(session) and found a payment_status: 'unpaid' and figured I could use this to do what I am trying to by the following:

app.post('/api/createCheckoutSession', async (req, res) => {


    try {
        const session = await stripe.checkout.sessions.create({
            payment_method_types: ['card'],
            mode: 'payment',
            line_items: req.body.items.map(item => {
                const storeItem = storeItems.get(item.id)
                return {
                    price_data: {
                        currency: 'usd',
                        product_data: {
                            name: storeItem.name
                        },
                        unit_amount: storeItem.priceInCents
                    },
                    quantity: item.quantity
                }

            }),
            success_url: `${process.env.SERVER_URL}`,
            cancel_url: `${process.env.SERVER_URL}cart`,

        })


        console.log(session)
        if (session.payment_status == 'paid') {
        cartItem.remove({ user: req.body.user }, function (err) {
            if (err) {
                console.log(err)
            }
        })
        }


        res.json({ url: session.url })
    } catch (e) {
        console.log(e)
        res.status(500).json({ error: e.message })
    }



});

With the above code, the if statement does not work as the only time something gets logged to the console is when the session first gets created, so the if statement does not execute after the payment succeeds or gets canceled.

Another solution is for me to create a different success_url where it pops up and I have a react useEffect call the remove cart items function. And then it redirects again somewhere else, but as I alluded to earlier this just seems like a terrible solution when it feels like I am just missing something very simple to get this to work the way I have attempted to.

I'm going to restate what I think your goal is here so I am clear on what the answer is.

After user is sent to checkout you have 2 potential outcomes you want your app to handle:

  • Successful payment: Get money, get user their goods
  • Payment canceled: Empty user cart

The problem you are running into is that your code can only await the creation of the user session. At that point you should just redirect to the Checkout URL. At this point your code does not know whether the payment will go through or not because the user is just being redirected to the Checkout UI where they can make their payment.

The state of the user's payment is reported back to your app in 2 different ways.

  • Customized Success/Cancel URLS - While this doc focuses on capturing the Session ID in the Success URL, you can do the same thing with the Cancel URL. In this case which URL the user is sent to tells your system a Checkout was either successful or was canceled. The Session ID injected into the URL identifies which Checkout session it was.

  • Checkout Webhook events - This approach provides confirmation of success but requires waiting until the session is expired to confirm cancelation. Still, it is recommended that most integrations make use of Webhooks to monitor account activities.

So to circle back to your code, I would move the code that clears the cart to a function that responds to either the user being redirected to the cancel_url in your app or responds to the checkout.session.expired webhook event

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM