#morey-stripe-js

1 messages ยท Page 1 of 1 (latest)

plucky oyster
#

Sure, do you have more to the question?

#

createPaymentMethod will only tokenize the payment details and return a pm_1234 payment method

brittle otter
#

Hey yes.
What's the right way to attach a payment method using stripe.createPaymentMethod to a customer?

Using stripe.confirmCardSetup was causing my account to continually create the same card/billing info even though the info i submitted was different

plucky oyster
#

confirmCardSetup is used with a Setup Intent to authenticate card ownership with your customer and authorize it for future payments

#

Using stripe.confirmCardSetup was causing my account to continually create the same card/billing info even though the info i submitted was different

#

can you explain mroe about that or some some example object IDs or code?

brittle otter
#

Hey yes, give a moment

#

In testing:

FE: "setup_intent_unexpected_state"
"seti_1JcEb2LXSN9kljfY94yu5dW4_secret_KGm9GxDpHJWQttqCkETqPbN9Y7KVlxZ"

BE: When trying to create a new intent with stripe.setupIntents.create
Error while Add Payment Method Details: ReferenceError: intent is not defined

BE Code that is triggered on add.

exports.addPaymentMethodDetails = functions.firestore
  .document("/stripe_customers/{userId}/payment_methods/{pushId}")
  .onCreate(async (snap, context) => {
    try {
      const paymentMethodId = snap.data().id;
      const userId = context.params.userId;

      // grab customer data.
      const customer = await admin
        .firestore()
        .collection("stripe_customers")
        .doc(userId)
        .get();

      const paymentMethod = await stripe.paymentMethods.retrieve(
        paymentMethodId
      );

      console.log("PaymentMethod! : ", JSON.stringify(paymentMethod));

      // 1. sets to the current location: "/stripe_customers/{userId}/payment_methods/{pushId}"
      let setPaymentMethod = snap.ref.set(paymentMethod);

      // 2. Create a new SetupIntent so the customer can add a new method next time.
      let getSetupIntent = stripe.setupIntents.create({
        customer: customer.customer_id,
      });
      
      console.log("getScustomeretupIntent: ", JSON.stringify(customer));
      console.log("getSetupIntent: ", JSON.stringify(getSetupIntent));

      // 3. Stores data to `/stripe_customers/{userId}`
      const setSetupSecret = snap.ref.parent.parent.set(
        {
          setup_secret: intent.client_secret,
        },
        { merge: true }
      );

      await Promise.all([setPaymentMethod, getSetupIntent, setSetupSecret]);
    } catch (error) {
      console.log("Error while Add Payment Method Details: ", error);
      await snap.ref.set({ error: userFacingMessage(error) }, { merge: true });
    }
  });```
#

FE Code:

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

    if (!stripe || !elements) {
      return;
    }
    if (errorCard) {
      elements.getElement("card").focus();
      return;
    }

    const customerData = (await fs.collection("stripe_customers").doc(user.id).get()).data();
    const cardElement = await elements.getElement(CardElement);
    const result = await stripe.confirmCardSetup(customerData.setup_secret, {
      payment_method: {
        card: cardElement,
        billing_details: {
          name: name,
          address: {
            line1: address1,
            line2: address2,
            country: country,
            city: city,
            postal_code: postal,
            state: state,
          },
        },
      },
    });
    let { error, setupIntent } = result;
     // Errors always
    if (error) {
      if (
        error.code === "setup_intent_unexpected_state" &&
        error.setup_intent?.status === "succeeded"
      ) {
        const errSetupIntent = error.setup_intent;
        const paymentMethodRef = fs
          .collection("stripe_customers")
          .doc(user.id)
          .collection("payment_methods")
          .doc();
        await paymentMethodRef.set({ id: errSetupIntent.payment_method });
        const paymentMethodId = paymentMethodRef.id;

        // Triggers backen d
        await fs.collection("stripe_customers").doc(user.id).update({
          primaryPaymentMethod: paymentMethodId,
        });
         handleClose();
      } 
    } else {
      const paymentMethodRef = fs
        .collection("stripe_customers")
        .doc(user.id)
        .collection("payment_methods")
        .doc();
      await paymentMethodRef.set({ id: setupIntent.payment_method });
      const paymentMethodId = paymentMethodRef.id;

      await fs.collection("stripe_customers").doc(user.id).update({
        primaryPaymentMethod: paymentMethodId,
      });
      handleClose();
    }
  };
plucky oyster
#

ReferenceError: intent is not defined

#

What is that referring to?

brittle otter
#

I believe it broke here in the backend

    // 3. Stores data to `/stripe_customers/{userId}`
      const setSetupSecret = snap.ref.parent.parent.set(
        {
          setup_secret: intent.client_secret,
        },
        { merge: true }
      );```
#

oh wait

#

if this was a variable error, I'd be embarrased ๐Ÿ˜„

plucky oyster
#

๐Ÿ˜ฌ

#

ah looks like it's getSetupIntent a few lines up?

brittle otter
#

ya... xD

#

is my flow ok though? using the right stripe functions?

#

*first time seriously using stripe here

plucky oyster
#

hard to say, there's a lot going on and it depends on your exact business needs. I suggest retesting now and if any particular step isnt doing what you need / expect we (in particular @dusky crater ) can give you another hand

#

Welcome to the Stripe developer community ๐Ÿ™‚

brittle otter
#

haha thank you.

#

Do you know what would cause the setup_intent_unexpected_state?

Everytime I add a card, FE throws this... but also status = success.

the pm_1234 seem to always be the same PM when i try add another card,

dusky crater
brittle otter
#

sure, one moment

#

3 requests happen when I try adding a card
1st: req_0EskdHvq0BGSQq
2nd: req_bqAfmqK0lNpqzr
3rd: req_9ACHkpZl88Aizb

I'm not sure why 2nd keeps getting that same pm.

dusky crater
#

so here's the problem: https://dashboard.stripe.com/test/logs/req_0EskdHvq0BGSQq

message: "You cannot update this SetupIntent because it has already succeeded.",

that is the message in the API response

Your code already confirmed this SetupIntent before

but your code is again using this already succeeded SetupIntent's client_secret to confirm it again, which obviously won't work as the SetupIntent is already confirmed successfully

#

so it is a bug in your code somewhere, I would recommend you add lots of logs in your code on why your server-side is returning the old SetupIntent client_secret and not a fresh new one

brittle otter
#

Ah, so server used old setupintents.

#

Currently I try to save setupintents on my database for usage. Would it make more sense to generate the intents on the fly rather than save it in my bd? (was thinking about speed / less calls)

dusky crater
#

so while I understand your question and can answer it, the issue happening here is separate

#

if you're fetching a SetupIntent (that is in status: requires_payment_method) and is not status: succeeded , then that can be returned to your client-side to confirm

the problem here is that your backend is returning a succeeded SetupIntent to the webpage to confirm, that would be an incorrect integration

brittle otter
#

if you're fetching a SetupIntent (that is in status: requires_payment_method) and is not status: succeeded , then that can be returned to your client-side to confirm

Ah, right. succeeded means already confirm not ... call was successful. My misunderstanding

#

I see the problem. the seti_1234 was not changing at all. Ok I know what to do, thank you for your help @dusky crater

dusky crater
#

great! glad you found it!

brittle otter
#

I think it's fixed now :D.
req_NtaLmrxIssITUC

#

1 more question.

Shouldn't stripe.confirmCardSetup Auto attach the card to the customer? However, I am not seeing any cards attached after successful req

rose sluice
#

๐Ÿ‘‹ Just hopping in for @dusky crater - stripe.confirmCardSetup will automatically attach only if the SetupIntent has customer set (either during creation or in a subsequent update). It looks like the setup intent used with req_NtaLmrxIssITUC doesn't have any customer specified

brittle otter
#

Ah @rose sluice thanks. And also for jumping on real quick. I'll try that

#

Alot of stuff with stripe. it's kinda cool!

brittle otter
#

hey karbi, I have created the intents like this

        customer: customer.customer_id,
        payment_method_types: ["card"],
        usage: "on_session",
      });```

I did double check that customer_id was the customer id.... which in this example is: `cus_KGm9PTZCuem3uH`

But when using that intent it did not link to the customer
rose sluice
#

What's the setup intent ID?

ocean nimbus
#

yeah my guess is that customer.customer_id is null and so it just doesn't pass the parameter. You should print that variable, or look at the log in your Dashboard @brittle otter

brittle otter
#

oh my god. ya, I made the assumption that this picked up the customer data.... was another typo on my end.

#

It's all good now... Thank you so much for the help

ocean nimbus
#

yay!

#

Glad you got unblocked in the end and it just works ๐Ÿ™‚