Muhammad Amir
Muhammad Amir

Reputation: 672

Payment not being charged, because of some error in the firebase cloud function

I'm making a react-redux app with firetore as database. Now, I wanted to use firebase cloud functions for handling stripe payments.

Here is the setup:

Below is the action method for checkout, after receiving token and amount from react side.

export const checkoutFunc = (token, amount) => {
  return (dispatch, getState, { getFirebase, getFirestore }) => {
    const uid = getState().firebase.auth.uid;
    const ref = database.ref();
    ref.child(`payments/${uid}`).push({
      token: token,
      amount: amount
    });
  };
};

This function creates a payment and saves token and amount.

Now, here is the cloud function which should "charge" the payment, after the above payment is created.

exports.stripeCharge = functions.database
  .ref("/payments/{userId}/{paymentId}")
  .onWrite((change, context) => {
    const payment = change.after.val();

    const userId = context.params.userId;
    const paymentId = context.params.paymentId;

    if (!payment || payment.charge) return;

    return admin
      .database()
      .ref(`/teachers/${userId}`)
      .once("value")
      .then(snap => {
        return snap.val();
      })
      .then(customer => {
        const amount = payment.amount;
        const idempotency_key = paymentId;
        const source = payment.token.id;
        const currency = "usd";
        const charge = { amount, currency, source };

        return stripe.charges.create(charge, { idempotency_key });
      })

      .then(charge => {
        admin
          .database()
          .ref(`/payments/${userId}/${paymentId}/charge`)
          .set(charge)
          .then(charge => {
            return true;
          });
      });
  });

The creation of payment works and the token and amount is saved in payments table. But, the cloud function is not doing its job of charging the token.

Expected Result:

https://i.ibb.co/Fq9Zfhq/image.png

Actual result:

https://i.ibb.co/Krk7cGL/image.png

Upvotes: 1

Views: 377

Answers (2)

Muhammad Amir
Muhammad Amir

Reputation: 672

Though the answer provided by @Doug Stevenson is helpful, it was not the main problem. So, I am writing the solution here for other people struggling with it. I was using the wrong public key and secret key pair in my app, that when I used correctly, it worked.

Upvotes: 1

Doug Stevenson
Doug Stevenson

Reputation: 317372

You're not returning the promise returned from set() using the Admin SDK. The function is terminating and cleaning up before that async work is complete.

  .then(charge => {
    return admin    // add a return here
      .database()
      .ref(`/payments/${userId}/${paymentId}/charge`)
      .set(charge)
      .then(charge => {
        return true;
      });
  });

FYI these promise chains are easier to visualize if you use async/await syntax instead of then/catch.

Upvotes: 0

Related Questions