#Stripe payment, missing payment method type in `data`

45 messages ยท Page 1 of 1 (latest)

topaz solstice
#

After a successful order placement, paid with Stripe, the order.payments.data maps which contains all the stripe data is missing ANY info on the payment method that can be directly displayed to the user.
I should probably use the "payment_method": "pm_1NdaNIHom7EScpqgc48SfMNn" to get the readable name but that feels like uneccesary extra work on the server. Am I missing something?

eternal mural
#

What do you want to show to the customer?

topaz solstice
eternal mural
#

So you get what Stripe gives you in the intent.

topaz solstice
#

If I could add it here that would be great

#

This is a snippet of the GET order response.

eternal mural
topaz solstice
#

Would that work? Then where to best excecute this

eternal mural
#

Before you do any storing of the payment method, be sure it's PCI compliant

topaz solstice
eternal mural
#

I think if you use PaymentElement from Stripe then it's kinda hidden for medusa. All happens on the Stripe side and medusa doesn't know much about which method is chosen

#

All that is recieved from Stripe is in the intent in data property

topaz solstice
#

Yeah that makes sense. But if I told a way to set the metadata in the screenshot above, I can make a one time call to a stripe API to get the readable string and save it.

#

But I dont know how to edit that metadata field

eternal mural
#

You would need to update the payment intent I think: https://stripe.com/docs/api/payment_intents/update
But that can be only made from the backend (it needs the secret stripe key from backend).
And for that you would need to create your own endpoint I guess.

#
const stripe = require('stripe')('your stripe test key');

const paymentIntent = await stripe.paymentIntents.update(
  'pi_3L5Yh3LJMdQkx7dY14aYXXLM',
  {metadata: {paymentMethodName: 'Sofort'}}
);
#

But how will you get what method is chosen?

topaz solstice
#

Ah thats smart, and that would be automatically available in Medusa?

#

Hmm, there is payment_method in the intent which represents the method I suppose

eternal mural
#

Yes but then we get to your first original question where you never wanted to make extra work on the server ๐Ÿ™‚

topaz solstice
#

Hmm I will play a bit with this in the near future

eternal mural
topaz solstice
#

And get back

eternal mural
#

Unless you'll transform the "type"

#

or something

topaz solstice
#

Do you happen to have time to look at my Project organisation & import and export ts files post as well? That would be awesome

#

I will ask Stripe support for a solution, maybe they have a neat one.

eternal mural
#

Stripe devs are active on Stripe Discord

eternal mural
topaz solstice
#

Or this one, this is a payment_session on a draft order from the {{medusa-host}}/admin/draft-orders/dorder_01H8MDB0856HMBVXP2EFS4GYV5 response.

eternal mural
#

But you still need to get the used payment method from Stripe.

#

Honestly I would just go with Paid with Stripe on the invoice ๐Ÿ˜„

#

Or just retrieve the PaymentMethod from Stripe when creating invoice and use the "type"

topaz solstice
#

Got it!

I created a custom endpoint:

// Payment sessions
  router.put("/store/carts/:id/payment-sessions/update-data", authenticate(), (req, res) => {
    const paymentProviderService = req.scope.resolve("paymentProviderService")

    paymentProviderService.updateSessionData(req.body.payment_session, {
      data: req.body.data,
    })
      .then((paymentSession) => {
        res.json({
          payment_session: paymentSession,
        })
      })
      .catch((e) => {
        if (e) {
          res.status(400).send({
            error: e?.message,
          })
        }
      })
  })

And when I call it with the following body like so:

{
    "payment_session": {
        "id": "ps_01H8MJK22XA9KPFF31DHJTARNN",
        "provider_id": "manual"
    },
    "data": {
        "payment_term": "afterpay_30"
    }
}

I get back the follwoing response:

{
    "payment_session": {
        "id": "ps_01H8MJK22XA9KPFF31DHJTARNN",
        "created_at": "2023-08-24T20:08:22.347Z",
        "updated_at": "2023-08-24T20:18:56.488Z",
        "cart_id": "cart_01H8MJJT16V3F9ZE7JCW6N1N6M",
        "provider_id": "manual",
        "is_selected": true,
        "is_initiated": true,
        "data": {
            "status": "pending",
            "payment_term": "afterpay_30"
        },
        "idempotency_key": null,
        "amount": 48600,
        "payment_authorized_at": null
    }
}

As you can see the payment_term is now there (which I need as well). I can do the same with the readable stripe payment method. I can call this in the frontend when I finalise the cart.

topaz solstice
#

Okay this is not a solution either as the data in the payment_session is emptied somehow when you go from a draft order to an order.....

#

So still no solution here.

eternal mural
#

Yeah I feel you'll need to fetch the payment method from Stripe for the invoice generation. Or just just dump a "Paid with Stripe" if that suits you.
Have you asked on Stripe Discord? I think there's nothing in the intent about the method, so you'll need the payment method.

topaz solstice
#

I did it the following way. In my order.completed notifier I did the following:

orderCreated = async (data) => {
    const config = {
      relations: ['payments'],
    }
    this.orderService.retrieve(data.id, config)
      .then((order) => {
        // Copy the cart's context to the order's metadata for convenience reasons
        this.cartService.retrieve(order.cart_id)
          .then(async (cart) => {
            // Get the payment method and save it to the order's context
            let paymentMethod = null
            if (order.payments?.[0]?.data?.payment_method) {
              const paymentMethodResponse = await axios.get('https://api.stripe.com/v1/payment_methods/' + order.payments?.[0]?.data?.payment_method, {
                headers: {
                  Authorization: `bearer ${process.env.STRIPE_API_KEY}`,
                }
              })

              paymentMethod = paymentMethodResponse.data
            }

            this.orderService.update(data.id, {
              metadata: {
                ...cart.context,
                stripe_payment_method: paymentMethod,
              }
            })
...........

So it one-time fetches the stripe API and sets the stripe_payment_method in my order.metadata.

I can then easily acces it anytime.