Home > Mobile >  Firebase function failing to execute every step
Firebase function failing to execute every step

Time:07-30

I've been trying to make this function execute every step in the process, but it seems to only be executing everything and returning a 200 response but doesn't run any of the set functions.

This code is triggered by a Stripe Webhook (customer.subscription.created) which calls my endpoint and activates this function.

I can't seem to figure out if the Stripe objects (customer, plan, price, product) are not yet set before my function is called or if my code doesn't work.

const functions = require("firebase-functions");
const axios = require("axios");

class stripeWebhookSubscription {
  static createSubscription(database, subscription, res) {
      let barcode;
      let plan;

      database.collection("subscriptions").add({
            id: subscription.id,
            customer: subscription.customer,
            status: subscription.status,
            price: {
                amount: (subscription.items.data[0].price.unit_amount / 100).toFixed(2),
                interval: subscription.items.data[0].price.recurring.interval,
                interval_count: subscription.items.data[0].price.recurring.interval_count,
            },
            product: subscription.items.data[0].price.product,
            created: subscription.created,
            current_period_start: subscription.current_period_start,
            current_period_end: subscription.current_period_end,
            cancel_at: subscription.cancel_at,
            cancel_at_period_end: subscription.cancel_at_period_end,
            payment_gateway: "stripe",
            current_usage: 1,
        })
        .then((doc) => {
            barcode = doc.id;

            console.log(subscription.items.data[0].price.product);

            return database.collection("plans").where("stripe.product", "==", subscription.items.data[0].price.product).limit(1).get()
                .then((docs) => {
                    docs.forEach((doc) => {
                        console.log(doc.data());
                        return plan = doc.data();
                    });
                });
        })
        .then(() => {
            database.collection("customers").doc(subscription.customer).set({
                merchant: plan.merchant,
                subscriptions: [barcode],
            }, {merge: true})
                .then((doc) => {
                    return console.log("Customer updated with: merchant ("   plan.merchant   ") and subscription ("   [barcode]   ")");
                });
        })
        .then(() => {
            database.collection("subscriptions").doc(barcode).set({
                merchant: plan.merchant,
            }, {merge: true})
                .then((doc) => {
                    return console.log("Subscription updated with merchant: "   plan.merchant);
                });
        })
        .then(() => {
            // Sends the email confirmation to the customer
             database.collection("customers").doc(subscription.customer).get()
                .then((doc) => {
                    const customer = doc.data();

                    return axios.request({
                        url: "https://api.sendinblue.com/v3/smtp/email",
                        method: "post",
                        headers: {
                            "api-key": functions.config().sendinblue.key,
                            "Content-Type": "application/json",
                        },
                        data: {
                            "to": [
                                {
                                    "email": customer.email,
                                    "name": customer.name,
                                },
                            ],
                            "replyTo": {
                                "email": "[email protected]",
                                "name": "Scanable",
                            },
                            "templateId": 2,
                            "params": {
                                "NAME": customer.name,
                                "SUBSCRIPTION": barcode,
                            },
                        },
                    });

                    // return console.log("Customer ("   customer.email   ") email sent!");
                });
        })
        .then(() => {
            return res.status(200).send("✅ Subscription "   subscription.id   " created!");
        })
        .catch((err) => {
          return res.status(400).send("⚠️ Error creating subscription ("  subscription.id   "): "   err);
        });
  }
}

CodePudding user response:

This is because you are not correctly chaining the different Promises returned by the asynchronous Firestore and Axios asynchronous methods.

The below code adaptations should do the trick.

  • In each then() block we return the promise returned by the asynchronous method;
  • We don't create a pyramid of doom of then() blocks. If you want to log the fact that an asynchronous method call was successfully executed, do the console.log() in the next then() block.
  • Finally we don't need to return the call to the Express send() method. See the following official video.

let plan;

database.collection("subscriptions").add({
    id: subscription.id,
    customer: subscription.customer,
    status: subscription.status,
    price: {
        amount: (subscription.items.data[0].price.unit_amount / 100).toFixed(2),
        interval: subscription.items.data[0].price.recurring.interval,
        interval_count: subscription.items.data[0].price.recurring.interval_count,
    },
    product: subscription.items.data[0].price.product,
    created: subscription.created,
    current_period_start: subscription.current_period_start,
    current_period_end: subscription.current_period_end,
    cancel_at: subscription.cancel_at,
    cancel_at_period_end: subscription.cancel_at_period_end,
    payment_gateway: "stripe",
    current_usage: 1,
})
    .then((doc) => {
        barcode = doc.id;

        console.log(subscription.items.data[0].price.product);

        return database.collection("plans").where("stripe.product", "==", subscription.items.data[0].price.product).limit(1).get();
    })
    .then((docs) => {
        // docs is a QuerySnapshot with one element
        plan = docs[0].data();

        return database.collection("customers").doc(subscription.customer).set({
            merchant: plan.merchant,
            subscriptions: [barcode],
        }, { merge: true })
    })
    .then(() => {
        console.log("Confirmation of previous update")
        return database.collection("subscriptions").doc(barcode).set({
            merchant: plan.merchant,
        }, { merge: true })
    })
    .then(() => {
        // Sends the email confirmation to the customer
        return database.collection("customers").doc(subscription.customer).get();
    })
    .then((doc) => {
        const customer = doc.data();

        return axios.request({
            url: "https://api.sendinblue.com/v3/smtp/email",
            method: "post",
            headers: {
                "api-key": functions.config().sendinblue.key,
                "Content-Type": "application/json",
            },
            data: {
                "to": [
                    {
                        "email": customer.email,
                        "name": customer.name,
                    },
                ],
                "replyTo": {
                    "email": "[email protected]",
                    "name": "Scanable",
                },
                "templateId": 2,
                "params": {
                    "NAME": customer.name,
                    "SUBSCRIPTION": barcode,
                },
            },
        });
    })
    .then(() => {
        res.status(200).send("✅ Subscription "   subscription.id   " created!");
    })
    .catch((err) => {
        res.status(400).send("⚠️ Error creating subscription ("   subscription.id   "): "   err);
    });
  • Related