mirror of
https://github.com/lukevella/rallly.git
synced 2025-04-29 02:06:34 +02:00
♻️ Make user required in subscription model (#1585)
This commit is contained in:
parent
01758f81ae
commit
aebea5a41c
5 changed files with 87 additions and 92 deletions
|
@ -24,26 +24,60 @@ export async function onCustomerSubscriptionCreated(event: Stripe.Event) {
|
||||||
throw new Error("Missing user ID");
|
throw new Error("Missing user ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and update user
|
const userId = res.data.userId;
|
||||||
await prisma.user.update({
|
|
||||||
where: {
|
// Check if user already has a subscription
|
||||||
id: res.data.userId,
|
const existingUser = await prisma.user.findUnique({
|
||||||
},
|
where: { id: userId },
|
||||||
data: {
|
include: { subscription: true },
|
||||||
subscription: {
|
});
|
||||||
create: {
|
|
||||||
id: subscription.id,
|
if (!existingUser) {
|
||||||
active: isActive,
|
throw new Error(`User with ID ${userId} not found`);
|
||||||
priceId,
|
}
|
||||||
currency,
|
|
||||||
interval,
|
// If user already has a subscription, update it or replace it
|
||||||
amount,
|
if (existingUser.subscription) {
|
||||||
status: subscription.status,
|
// Update the existing subscription with new data
|
||||||
createdAt: toDate(subscription.created),
|
await prisma.subscription.update({
|
||||||
periodStart: toDate(subscription.current_period_start),
|
where: { id: existingUser.subscription.id },
|
||||||
periodEnd: toDate(subscription.current_period_end),
|
data: {
|
||||||
|
id: subscription.id,
|
||||||
|
active: isActive,
|
||||||
|
priceId,
|
||||||
|
currency,
|
||||||
|
interval,
|
||||||
|
amount,
|
||||||
|
status: subscription.status,
|
||||||
|
createdAt: toDate(subscription.created),
|
||||||
|
periodStart: toDate(subscription.current_period_start),
|
||||||
|
periodEnd: toDate(subscription.current_period_end),
|
||||||
|
cancelAtPeriodEnd: subscription.cancel_at_period_end,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Create a new subscription for the user
|
||||||
|
await prisma.user.update({
|
||||||
|
where: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
subscription: {
|
||||||
|
create: {
|
||||||
|
id: subscription.id,
|
||||||
|
active: isActive,
|
||||||
|
priceId,
|
||||||
|
currency,
|
||||||
|
interval,
|
||||||
|
amount,
|
||||||
|
status: subscription.status,
|
||||||
|
createdAt: toDate(subscription.created),
|
||||||
|
periodStart: toDate(subscription.current_period_start),
|
||||||
|
periodEnd: toDate(subscription.current_period_end),
|
||||||
|
cancelAtPeriodEnd: subscription.cancel_at_period_end,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
"./*": "./src/*.ts"
|
"./*": "./src/*.ts"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"normalize-subscription-metadata": "dotenv -e ../../.env -- tsx ./src/scripts/normalize-metadata.ts",
|
|
||||||
"checkout-expiry": "dotenv -e ../../.env -- tsx ./src/scripts/checkout-expiry.ts",
|
"checkout-expiry": "dotenv -e ../../.env -- tsx ./src/scripts/checkout-expiry.ts",
|
||||||
"subscription-data-sync": "dotenv -e ../../.env -- tsx ./src/scripts/subscription-data-sync.ts",
|
"subscription-data-sync": "dotenv -e ../../.env -- tsx ./src/scripts/subscription-data-sync.ts",
|
||||||
"sync-payment-methods": "dotenv -e ../../.env -- tsx ./src/scripts/sync-payment-methods.ts",
|
"sync-payment-methods": "dotenv -e ../../.env -- tsx ./src/scripts/sync-payment-methods.ts",
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
/* eslint-disable no-console */
|
|
||||||
/**
|
|
||||||
* This script will go through all subscriptions and add the userId to the metadata.
|
|
||||||
*/
|
|
||||||
import { prisma } from "@rallly/database";
|
|
||||||
|
|
||||||
import { stripe } from "../lib/stripe";
|
|
||||||
|
|
||||||
async function getSubscriptionsWithMissingMetadata(
|
|
||||||
starting_after?: string,
|
|
||||||
): Promise<string[]> {
|
|
||||||
const res: string[] = [];
|
|
||||||
|
|
||||||
const subscriptions = await stripe.subscriptions.list({
|
|
||||||
limit: 100,
|
|
||||||
starting_after,
|
|
||||||
});
|
|
||||||
subscriptions.data.forEach((subscription) => {
|
|
||||||
if (!subscription.metadata.userId) {
|
|
||||||
res.push(subscription.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (subscriptions.has_more) {
|
|
||||||
return [
|
|
||||||
...res,
|
|
||||||
...(await getSubscriptionsWithMissingMetadata(
|
|
||||||
subscriptions.data[subscriptions.data.length - 1].id,
|
|
||||||
)),
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function normalizeSubscriptionMetadata() {
|
|
||||||
const subscriptions = await getSubscriptionsWithMissingMetadata();
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`Found ${subscriptions.length} subscriptions with missing metadata`,
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const subscriptionId of subscriptions) {
|
|
||||||
const user = await prisma.user.findFirst({
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
},
|
|
||||||
where: {
|
|
||||||
subscriptionId: subscriptionId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
console.log("User not found for subscription", subscriptionId);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
await stripe.subscriptions.update(subscriptionId, {
|
|
||||||
metadata: {
|
|
||||||
userId: user.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("Updated subscription", subscriptionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
normalizeSubscriptionMetadata();
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "users" DROP CONSTRAINT "users_subscription_id_fkey";
|
||||||
|
|
||||||
|
-- DropIndex
|
||||||
|
DROP INDEX "users_subscription_id_key";
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "subscriptions" ADD COLUMN "user_id" TEXT;
|
||||||
|
|
||||||
|
-- Populate user_id in subscriptions table using data from users table
|
||||||
|
UPDATE "subscriptions" s
|
||||||
|
SET "user_id" = u.id
|
||||||
|
FROM "users" u
|
||||||
|
WHERE u."subscription_id" = s.id;
|
||||||
|
|
||||||
|
-- Delete orphaned subscriptions (subscriptions without a corresponding user)
|
||||||
|
DELETE FROM "subscriptions"
|
||||||
|
WHERE "user_id" IS NULL;
|
||||||
|
|
||||||
|
-- Make user_id NOT NULL after populating data
|
||||||
|
ALTER TABLE "subscriptions" ALTER COLUMN "user_id" SET NOT NULL;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "users" DROP COLUMN "subscription_id";
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "subscriptions_user_id_key" ON "subscriptions"("user_id");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "subscriptions" ADD CONSTRAINT "subscriptions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -49,7 +49,6 @@ model User {
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime? @updatedAt @map("updated_at")
|
updatedAt DateTime? @updatedAt @map("updated_at")
|
||||||
customerId String? @map("customer_id")
|
customerId String? @map("customer_id")
|
||||||
subscriptionId String? @unique @map("subscription_id")
|
|
||||||
|
|
||||||
comments Comment[]
|
comments Comment[]
|
||||||
polls Poll[]
|
polls Poll[]
|
||||||
|
@ -58,8 +57,7 @@ model User {
|
||||||
accounts Account[]
|
accounts Account[]
|
||||||
participants Participant[]
|
participants Participant[]
|
||||||
paymentMethods PaymentMethod[]
|
paymentMethods PaymentMethod[]
|
||||||
|
subscription Subscription? @relation("UserToSubscription")
|
||||||
subscription Subscription? @relation(fields: [subscriptionId], references: [id], onDelete: SetNull)
|
|
||||||
|
|
||||||
@@map("users")
|
@@map("users")
|
||||||
}
|
}
|
||||||
|
@ -111,8 +109,9 @@ model Subscription {
|
||||||
periodStart DateTime @map("period_start")
|
periodStart DateTime @map("period_start")
|
||||||
periodEnd DateTime @map("period_end")
|
periodEnd DateTime @map("period_end")
|
||||||
cancelAtPeriodEnd Boolean @default(false) @map("cancel_at_period_end")
|
cancelAtPeriodEnd Boolean @default(false) @map("cancel_at_period_end")
|
||||||
|
userId String @unique @map("user_id")
|
||||||
|
|
||||||
user User?
|
user User @relation("UserToSubscription", fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
@@map("subscriptions")
|
@@map("subscriptions")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue