feat: new billing and restrict access when trial has ended

* fix: simply billing

* fix usage graph

* imporve billing more + supporter prompt on self-hosting

* revert service change

* revert query builder

* fix: comments
This commit is contained in:
Carl-Gerhard Lindesvärd
2025-11-11 11:09:11 +01:00
committed by GitHub
parent bbd30ca6e0
commit 9cafd61b25
57 changed files with 1642 additions and 1269 deletions

View File

@@ -117,6 +117,22 @@ const getPrismaClient = () => {
return new Date(Date.now() + 1000 * 60 * 60 * 24);
},
},
isActive: {
needs: {
subscriptionStatus: true,
subscriptionEndsAt: true,
subscriptionCanceledAt: true,
},
compute(org) {
return (
org.subscriptionStatus === 'active' &&
org.subscriptionEndsAt &&
org.subscriptionEndsAt > new Date() &&
!isCanceled(org) &&
!isWillBeCanceled(org)
);
},
},
isTrial: {
needs: { subscriptionStatus: true, subscriptionEndsAt: true },
compute(org) {

View File

@@ -1,3 +1,5 @@
export type { ProductPrice } from '@polar-sh/sdk/models/components/productprice.js';
export type IPrice = {
price: number;
events: number;

View File

@@ -5,7 +5,11 @@ import { importQueue } from '@openpanel/queue';
import { zCreateImport } from '@openpanel/validation';
import { getProjectAccess } from '../access';
import { TRPCAccessError } from '../errors';
import {
TRPCAccessError,
TRPCBadRequestError,
TRPCNotFoundError,
} from '../errors';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const importRouter = createTRPCRouter({
@@ -69,6 +73,28 @@ export const importRouter = createTRPCRouter({
);
}
const organization = await db.organization.findFirst({
where: {
projects: {
some: {
id: input.projectId,
},
},
},
});
if (!organization) {
throw TRPCNotFoundError(
'Could not start import, organization not found',
);
}
if (!organization.isActive) {
throw TRPCBadRequestError(
'You cannot start an import without an active subscription!',
);
}
// Create import record
const importRecord = await db.import.create({
data: {