在我的 Stripe 应用程序中,我想将一封电子邮件链接到一位客户,因此任何定期付款都不会重复客户,但 Stripe 会不断重复

问题描述 投票:0回答:1

所以我的产品是一项订阅服务,它允许用户访问我网站上的服务。我已经在 stripe 上创建了该产品,并将付款链接添加到我的网站:

<a
   className="bg-red-600 text-white py-2 px-4 rounded inline-block"
  target="_blank"
  href={`https://buy.stripe.com/test_bIY15h1Jp5eg6409AA?prefilled_email=${session.user.email}`}
 > Pay Now

我已经在我的 api 中编写了 webhook.ts 代码,在成功付款后授予用户访问权限,在未付款订阅时撤销访问权限。它在一定程度上起作用;在测试期间,我取消订阅并尝试使用同一电子邮件再次订阅(我将 customerId 添加到用户数据库),stripe 创建另一个客户而不是使用同一客户及其导致的问题

我的 webhookk.ts:

import { NextApiResponse, NextApiRequest } from "next";
import Stripe from "stripe";
import mongooseConnect from "@/lib/mongooseConnect";
import User from "@/models/User";
import Order from "@/models/Order";
import { buffer } from "micro";

const stripe = new Stripe(process.env.STRIPE_SK as string);

const webhookSecret = process.env.STRIPE_ENDPOINT_SECRET as string;

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  
  await mongooseConnect();

  const sig = req.headers['stripe-signature'];

  let event: Stripe.Event;

  try {
    event = stripe.webhooks.constructEvent(await buffer(req), sig!, webhookSecret);
  } catch (err: any) {
    console.error(`Webhook signature verification failed. ${err.message}`);
    return res.status(400).json({ error: err.message });
  }

  const eventType = event.type;

  try {
    switch (eventType) {
     
      case 'checkout.session.completed': {
        const session = event.data.object as Stripe.Checkout.Session;
        const email = session.customer_details?.email;
      
        if (email) {
          let user = await User.findOne({ email });
      
          let subscription;
          if (typeof session.subscription === 'string') {
            subscription = await stripe.subscriptions.retrieve(session.subscription);
          } else {
            subscription = session.subscription as Stripe.Subscription;
          }
      
          const priceId = subscription?.items.data[0]?.price?.id || null;
      
          if (!user) {
            // Create a new user if none exists
            user = await User.create({
              email,
              name: session.customer_details?.name || 'Unknown',
              stripeCustomerId: session.customer as string,
              priceId,
              hasAccess: true,
            });
          } else {
            // Update existing user with Stripe Customer ID if it doesn't exist
            if (!user.stripeCustomerId) {
              user.stripeCustomerId = session.customer as string;
            }
            // Ensure user has access
            user.hasAccess = true;
            user.priceId = priceId;
            await user.save();
          }
      
          // Create an order record
          await Order.create({
            user: user._id,
            name: user.name,
            email: user.email,
            stripeCustomerId: user.stripeCustomerId,
            paid: true,
          });
        }
        break;
      }
      

      case 'customer.subscription.deleted': {
        const subscription = event.data.object as Stripe.Subscription;

        const user = await User.findOne({
          stripeCustomerId: subscription.customer as string,
        });

        if (user) {
          // Revoke access
          user.hasAccess = false;
          await user.save();
        }

        break;
      }

      default:
        console.log(`Unhandled event type ${event.type}`);
    }
  } catch (e: any) {
    console.error(`Stripe error: ${e.message} | EVENT TYPE: ${eventType}`);
  }

  return res.status(200).json({ received: true });
}

export const config = {
  api: {
    bodyParser: false,
  },
};

我的模型/用户.ts:

import mongoose, { Schema, model, models } from "mongoose";

const userSchema = new Schema({
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: false, default: null },
  image: { type: String, required: false },
  stripeCustomerId: { type: String, required: false, default: null },
  hasAccess: {type: Boolean, required: true, default: false},
  priceId: { type: String, required: false, default: null },
  emailVerified: { type: Boolean, default: false },
}, {timestamps: true});

const User = models.User || model("User", userSchema);

export default User;

它可以工作,但是在取消订阅并尝试再次付款后,它会在stripe仪表板中创建一个新客户,并且它会弄乱代码,有什么解决方案来解决客户重复吗?

typescript mongodb next.js stripe-payments stripe-customers
1个回答
0
投票

您应该首先创建(或检索,如果有现有客户)一个客户,然后将

customer
传递给结帐会话创建 API,以便 Stripe 将新创建的订阅与该客户关联,而不是创建新客户。请参阅 API
© www.soinside.com 2019 - 2024. All rights reserved.