Stripe payment intent working but not checkout session

18 Views Asked by At

So I am using Firebase and Stripe extension for handling subscribers in my SaaS.

The user registers, successfully adding a customerID and stripeID with their customerURL in Firestore, but later when the user purchases a subscription, only the payment intent gets updated in Stripe, nothing else, the Firestore does not get updated either.

Whats wrong with the code here?

// External Imports.
import { getStripePayments } from "@stripe/firestore-stripe-payments";
import { createCheckoutSession } from "@stripe/firestore-stripe-payments";
import { getApp } from "@firebase/app";
import { getFirestore, addDoc, onSnapshot } from "firebase/firestore";
import { getAuth } from "firebase/auth";

const express = require("express");
const bodyParser = require("body-parser");
const stripe = require("stripe")(process.env.STRIPE_SDK_KEY);
const firebaseAdmin = require("firebase-admin");

const firebaseServiceAcc = require("../../firebase.serviceAcc.json");
const db = getFirestore();
const auth = getAuth();
const currentUser = auth.currentUser;

// Configuring Firebasebase Admin and Firestore
firebaseAdmin.initializeApp({
  credential: firebaseAdmin.credential.cert(firebaseServiceAcc),
});
const firestore = firebaseAdmin.firestore();
// Configuring the router for this file.
const router = express.Router();

const session = await createCheckoutSession(payments, {
  price: myPriceId,
});

const createCheckoutSession = async () => {
  try {
    const docRef = await addDoc(
      collection(db, 'subscriptions', currentUser.uid, 'checkout_sessions'),
      {
        price: 'placeholder',
        success_url: window.location.origin,
        cancel_url: window.location.origin,
      }
    );

    // Wait for the CheckoutSession to get attached by the extension
    onSnapshot(docRef, (snap) => {
      const { error, url } = snap.data();
      if (error) {
        // Show an error to your customer and
        // inspect your Cloud Function logs in the Firebase console.
        alert(`An error occurred: ${error.message}`);
      }
      if (url) {
        // We have a Stripe Checkout URL, let's redirect.
        window.location.assign(url);
      }
    });
  } catch (error) {
    console.error("Error creating checkout session:", error);
    // Handle error as needed
  }
};

// Call the function to create the checkout session
createCheckoutSession();

onCurrentUserSubscriptionUpdate(
  payments,
  (snapshot) => {
    for (const change in snapshot.changes) {
      if (change.type === "added") {
        console.log(`New subscription added with ID: ${change.subscription.id}`);
      }
    }
  }
);

window.location.assign(session.url);

// This function handles all of stripe webhook calls.
const handleWebhook = async function (req, res) {
  // Getting request headers and body.
  const sig = req.headers["stripe-signature"];
  const payload = req.body;

  if (payload.type === "checkout.session.completed") {
    const event = stripe.webhooks.constructEvent(
      payload,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET
    );
    const session = event.data.object;
    const userId = session.customer;
    console.log(userId)
  }

  res.json({ received: true });
};

// This function handles /webhook/payment-intent-succeeded endpoint
const handlePaymentIntentSucceed = async function (req, res) {
  // Getting request headers and body.
  const sig = req.headers["stripe-signature"];
  const payload = req.body;
  const { id } = payload;

  const findUserBySubscriptionId = async (subscriptionId) => {
    try {
      const userSnapshot = await firestore
        .collection("users")
        .where("stripeSubscriptionID", "==", subscriptionId)
        .get();

      // User not found
      if (userSnapshot.empty) {
        return null;
      }

      // Return the user data
      return userSnapshot.docs[0].data();
    } catch (error) {
      console.error("Error finding user by subscription:", error);
      throw error;
    }
  };

  try {
    const event = stripe.webhooks.constructEvent(
      payload,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET
    );
    const user = await findUserBySubscriptionId(id);

    if (!user) {
      console.error(`User not found for payment_intent ${id}`);

      return res.json({
        success: true,
        message: "User not found, but event acknowledged.",
      });
    }

    switch (event.type) {
      case "payment_intent.succeeded":
        const paymentIntentSucceeded = event.data.object;

        break;
      default:
        console.log(`Unhandled event type ${event.type}`);
    }

    response.send();

    res.json({ success: true });
  } catch (error) {
    console.error("Error handling payment_intent.succeeded:", error);
    res.status(500).json({ error: "Internal Server Error" });
  }
};

// This function creates a checkout session for a button click event.
const handleBuyButtonClick = async function (req, res) {
  try {
    const { priceId } = req.body;
    const checkoutSession = await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      line_items: [
        {
          // price: priceId,
          price: priceId,
          quantity: 1,
        },
      ],
      mode: "payment",
      success_url: `${process.env.CLIENT_URL}/pages/verify-success.html`,
      cancel_url: `${process.env.CLIENT_URL}/pages/verify-cancel.html`,
    });

    res.json({ sessionId: checkoutSession.id });
  } catch (error) {
    console.error("Error handling Buy Button click:", error);
    res.status(500).json({ error: "Internal Server Error" });
  }
};

// Endpoints.

// Stripe webhook endpoint.
router.post(
  "/webhook",
  bodyParser.raw({ type: "application/json" }),
  handleWebhook
);

// Endpoint to specifically handle, payment success.
router.post("/webhook/payment-intent-succeeded", handlePaymentIntentSucceed);

// Buy Button Click Endpoint.
router.post("/create-checkout-session", handleBuyButtonClick);

// Exporting the router.
module.exports = router;
0

There are 0 best solutions below