diff --git a/apps/dokploy/pages/dashboard/settings/invoices.tsx b/apps/dokploy/pages/dashboard/settings/invoices.tsx
new file mode 100644
index 000000000..a37c3607c
--- /dev/null
+++ b/apps/dokploy/pages/dashboard/settings/invoices.tsx
@@ -0,0 +1,63 @@
+import { IS_CLOUD } from "@dokploy/server/constants";
+import { validateRequest } from "@dokploy/server/lib/auth";
+import { createServerSideHelpers } from "@trpc/react-query/server";
+import type { GetServerSidePropsContext } from "next";
+import type { ReactElement } from "react";
+import superjson from "superjson";
+import { ShowBillingInvoices } from "@/components/dashboard/settings/billing/show-billing-invoices";
+import { DashboardLayout } from "@/components/layouts/dashboard-layout";
+import { appRouter } from "@/server/api/root";
+
+const Page = () => {
+ return ;
+};
+
+export default Page;
+
+Page.getLayout = (page: ReactElement) => {
+ return {page};
+};
+export async function getServerSideProps(
+ ctx: GetServerSidePropsContext<{ serviceId: string }>,
+) {
+ if (!IS_CLOUD) {
+ return {
+ redirect: {
+ permanent: true,
+ destination: "/dashboard/projects",
+ },
+ };
+ }
+ const { req, res } = ctx;
+ const { user, session } = await validateRequest(req);
+ if (!user || user.role !== "owner") {
+ return {
+ redirect: {
+ permanent: true,
+ destination: "/",
+ },
+ };
+ }
+
+ const helpers = createServerSideHelpers({
+ router: appRouter,
+ ctx: {
+ req: req as any,
+ res: res as any,
+ db: null as any,
+ session: session as any,
+ user: user as any,
+ },
+ transformer: superjson,
+ });
+
+ await helpers.user.get.prefetch();
+
+ await helpers.settings.isCloud.prefetch();
+
+ return {
+ props: {
+ trpcState: helpers.dehydrate(),
+ },
+ };
+}
diff --git a/apps/dokploy/server/api/routers/stripe.ts b/apps/dokploy/server/api/routers/stripe.ts
index d2a000324..3354c3311 100644
--- a/apps/dokploy/server/api/routers/stripe.ts
+++ b/apps/dokploy/server/api/routers/stripe.ts
@@ -81,6 +81,7 @@ export const stripeRouter = createTRPCRouter({
metadata: {
adminId: owner.id,
},
+ customer_email: owner.email,
allow_promotion_codes: true,
success_url: `${WEBSITE_URL}/dashboard/settings/servers?success=true`,
cancel_url: `${WEBSITE_URL}/dashboard/settings/billing`,
@@ -128,4 +129,39 @@ export const stripeRouter = createTRPCRouter({
return servers.length < user.serversQuantity;
}),
+
+ getInvoices: adminProcedure.query(async ({ ctx }) => {
+ const user = await findUserById(ctx.user.ownerId);
+ const stripeCustomerId = user.stripeCustomerId;
+
+ if (!stripeCustomerId) {
+ return [];
+ }
+
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
+ apiVersion: "2024-09-30.acacia",
+ });
+
+ try {
+ const invoices = await stripe.invoices.list({
+ customer: stripeCustomerId,
+ limit: 100,
+ });
+
+ return invoices.data.map((invoice) => ({
+ id: invoice.id,
+ number: invoice.number,
+ status: invoice.status,
+ amountDue: invoice.amount_due,
+ amountPaid: invoice.amount_paid,
+ currency: invoice.currency,
+ created: invoice.created,
+ dueDate: invoice.due_date,
+ hostedInvoiceUrl: invoice.hosted_invoice_url,
+ invoicePdf: invoice.invoice_pdf,
+ }));
+ } catch (_) {
+ return [];
+ }
+ }),
});
diff --git a/apps/monitoring/database/containers.go b/apps/monitoring/database/containers.go
index 568ad12e5..4e41f5fae 100644
--- a/apps/monitoring/database/containers.go
+++ b/apps/monitoring/database/containers.go
@@ -58,7 +58,7 @@ func (db *DB) GetLastNContainerMetrics(containerName string, limit int) ([]Conta
WITH recent_metrics AS (
SELECT metrics_json
FROM container_metrics
- WHERE container_name LIKE ? || '%'
+ WHERE container_name = ?
ORDER BY timestamp DESC
LIMIT ?
)
@@ -98,7 +98,7 @@ func (db *DB) GetAllMetricsContainer(containerName string) ([]ContainerMetric, e
WITH recent_metrics AS (
SELECT metrics_json
FROM container_metrics
- WHERE container_name LIKE ? || '%'
+ WHERE container_name = ?
ORDER BY timestamp DESC
)
SELECT metrics_json FROM recent_metrics ORDER BY json_extract(metrics_json, '$.timestamp') ASC