mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
131 lines
3.2 KiB
TypeScript
131 lines
3.2 KiB
TypeScript
import { WEBSITE_URL, getStripeItems } from "@/server/utils/stripe";
|
|
import {
|
|
IS_CLOUD,
|
|
findAdminById,
|
|
findServersByAdminId,
|
|
updateAdmin,
|
|
} from "@dokploy/server";
|
|
import { TRPCError } from "@trpc/server";
|
|
import Stripe from "stripe";
|
|
import { z } from "zod";
|
|
import { adminProcedure, createTRPCRouter } from "../trpc";
|
|
|
|
export const stripeRouter = createTRPCRouter({
|
|
getProducts: adminProcedure.query(async ({ ctx }) => {
|
|
const admin = await findAdminById(ctx.user.adminId);
|
|
const stripeCustomerId = admin.stripeCustomerId;
|
|
|
|
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
|
|
apiVersion: "2024-09-30.acacia",
|
|
});
|
|
|
|
const products = await stripe.products.list({
|
|
expand: ["data.default_price"],
|
|
active: true,
|
|
});
|
|
|
|
if (!stripeCustomerId) {
|
|
return {
|
|
products: products.data,
|
|
subscriptions: [],
|
|
};
|
|
}
|
|
|
|
const subscriptions = await stripe.subscriptions.list({
|
|
customer: stripeCustomerId,
|
|
status: "active",
|
|
expand: ["data.items.data.price"],
|
|
});
|
|
|
|
return {
|
|
products: products.data,
|
|
subscriptions: subscriptions.data,
|
|
};
|
|
}),
|
|
createCheckoutSession: adminProcedure
|
|
.input(
|
|
z.object({
|
|
productId: z.string(),
|
|
serverQuantity: z.number().min(1),
|
|
isAnnual: z.boolean(),
|
|
}),
|
|
)
|
|
.mutation(async ({ ctx, input }) => {
|
|
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
|
|
apiVersion: "2024-09-30.acacia",
|
|
});
|
|
|
|
const items = getStripeItems(input.serverQuantity, input.isAnnual);
|
|
const admin = await findAdminById(ctx.user.adminId);
|
|
|
|
let stripeCustomerId = admin.stripeCustomerId;
|
|
|
|
if (stripeCustomerId) {
|
|
const customer = await stripe.customers.retrieve(stripeCustomerId);
|
|
|
|
if (customer.deleted) {
|
|
await updateAdmin(admin.authId, {
|
|
stripeCustomerId: null,
|
|
});
|
|
stripeCustomerId = null;
|
|
}
|
|
}
|
|
|
|
const session = await stripe.checkout.sessions.create({
|
|
mode: "subscription",
|
|
line_items: items,
|
|
...(stripeCustomerId && {
|
|
customer: stripeCustomerId,
|
|
}),
|
|
metadata: {
|
|
adminId: admin.adminId,
|
|
},
|
|
success_url: `${WEBSITE_URL}/dashboard/settings/billing`,
|
|
cancel_url: `${WEBSITE_URL}/dashboard/settings/billing`,
|
|
});
|
|
|
|
return { sessionId: session.id };
|
|
}),
|
|
createCustomerPortalSession: adminProcedure.mutation(
|
|
async ({ ctx, input }) => {
|
|
const admin = await findAdminById(ctx.user.adminId);
|
|
|
|
if (!admin.stripeCustomerId) {
|
|
throw new TRPCError({
|
|
code: "BAD_REQUEST",
|
|
message: "Stripe Customer ID not found",
|
|
});
|
|
}
|
|
const stripeCustomerId = admin.stripeCustomerId;
|
|
|
|
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || "", {
|
|
apiVersion: "2024-09-30.acacia",
|
|
});
|
|
|
|
try {
|
|
const session = await stripe.billingPortal.sessions.create({
|
|
customer: stripeCustomerId,
|
|
return_url: `${WEBSITE_URL}/dashboard/settings/billing`,
|
|
});
|
|
|
|
return { url: session.url };
|
|
} catch (error) {
|
|
return {
|
|
url: "",
|
|
};
|
|
}
|
|
},
|
|
),
|
|
|
|
canCreateMoreServers: adminProcedure.query(async ({ ctx }) => {
|
|
const admin = await findAdminById(ctx.user.adminId);
|
|
const servers = await findServersByAdminId(admin.adminId);
|
|
|
|
if (!IS_CLOUD) {
|
|
return true;
|
|
}
|
|
|
|
return servers.length < admin.serversQuantity;
|
|
}),
|
|
});
|