feat: v2 managed organizations (#19341)

* refactor: allow non unique PlatformBilling customerId

* feat: add PlatformBilling managed organizations fields

* feat: ManagedOrganization table

* refactor: bill overdue based on teamId

* refactor: restructure organizations module

* wip: organizations endpoints

* Revert "wip: organizations endpoints"

This reverts commit 0e9e66fc74f31da436f12930c1b6597c650ed621.

* refactor: unique index for managed organizations

* wip: organizations endpoints

* wip: create managed organization

* remove unecessary membership check because we have guard

* feat: create managed org

* feat: get managed org and orgs

* feat: update and delete managed orgs

* wip: api key logic

* feat: allow variable api key length

* feat: refresh managed org api key

* feat: create managed org OAuth clients using api key

* finish merge main

* chore: bump platform libraries

* tests: fix and add more tests to api-auth.strategy.e2e

* refactor: dont request managed org slug and handle metadata as object

* revert: billing service and repository update overdue based on sub and customer ids

* refactor: v2 OAuth client permissions (#19501)

* refactor: v2 permissions as string array

* refactor: frontend work with permissions as string

* tests: test '*' permissions

* fix:managed org creator have profile & test can fetch oauth client

* fix: tests

* fix: OAuthClientCard on frontend

* fix: tests
This commit is contained in:
Lauris Skraucis
2025-02-25 18:10:46 -07:00
committed by GitHub
parent e4ab8d87c4
commit a44bcafcf2
192 changed files with 9103 additions and 619 deletions
@@ -3,6 +3,7 @@ import { BillingRepository } from "@/modules/billing/billing.repository";
import { BillingController } from "@/modules/billing/controllers/billing.controller";
import { BillingConfigService } from "@/modules/billing/services/billing.config.service";
import { BillingService } from "@/modules/billing/services/billing.service";
import { ManagedOrganizationsBillingService } from "@/modules/billing/services/managed-organizations.billing.service";
import { MembershipsModule } from "@/modules/memberships/memberships.module";
import { OrganizationsModule } from "@/modules/organizations/organizations.module";
import { PrismaModule } from "@/modules/prisma/prisma.module";
@@ -26,8 +27,14 @@ import { Module } from "@nestjs/common";
}),
UsersModule,
],
providers: [BillingConfigService, BillingService, BillingRepository, BillingProcessor],
exports: [BillingService, BillingRepository],
providers: [
BillingConfigService,
BillingService,
BillingRepository,
BillingProcessor,
ManagedOrganizationsBillingService,
],
exports: [BillingService, BillingRepository, ManagedOrganizationsBillingService],
controllers: [BillingController],
})
export class BillingModule {}
@@ -1,5 +1,5 @@
import { BillingRepository } from "@/modules/billing/billing.repository";
import { OrganizationsRepository } from "@/modules/organizations/organizations.repository";
import { OrganizationsRepository } from "@/modules/organizations/index/organizations.repository";
import { StripeService } from "@/modules/stripe/stripe.service";
import { Process, Processor } from "@nestjs/bull";
import { Logger } from "@nestjs/common";
@@ -38,7 +38,7 @@ export class BillingRepository {
async updateBillingOverdue(subId: string, cusId: string, overdue: boolean) {
try {
return this.dbWrite.prisma.platformBilling.update({
return this.dbWrite.prisma.platformBilling.updateMany({
where: {
subscriptionId: subId,
customerId: cusId,
@@ -141,7 +141,6 @@ describe("Platform Billing Controller (e2e)", () => {
},
} as unknown as Stripe)
);
return request(app.getHttpServer())
.post("/v2/billing/webhook")
.expect(200)
@@ -3,7 +3,7 @@ import { BILLING_QUEUE, INCREMENT_JOB, IncrementJobDataType } from "@/modules/bi
import { BillingRepository } from "@/modules/billing/billing.repository";
import { BillingConfigService } from "@/modules/billing/services/billing.config.service";
import { PlatformPlan } from "@/modules/billing/types";
import { OrganizationsRepository } from "@/modules/organizations/organizations.repository";
import { OrganizationsRepository } from "@/modules/organizations/index/organizations.repository";
import { StripeService } from "@/modules/stripe/stripe.service";
import { InjectQueue } from "@nestjs/bull";
import {
@@ -0,0 +1,34 @@
import { PlatformPlan } from "@/modules/billing/types";
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { Injectable, NotFoundException } from "@nestjs/common";
@Injectable()
export class ManagedOrganizationsBillingService {
constructor(private readonly dbRead: PrismaReadService, private readonly dbWrite: PrismaWriteService) {}
async createManagedOrganizationBilling(managerOrgId: number, managedOrgId: number) {
const managerOrgBilling = await this.dbRead.prisma.platformBilling.findUnique({
where: { id: managerOrgId },
});
if (!managerOrgBilling) {
throw new NotFoundException("Manager organization billing not found.");
}
if (managerOrgBilling.plan !== PlatformPlan.SCALE) {
throw new NotFoundException("Manager organization billing plan is not SCALE.");
}
return this.dbWrite.prisma.platformBilling.create({
data: {
id: managedOrgId,
customerId: managerOrgBilling.customerId,
subscriptionId: managerOrgBilling.subscriptionId,
plan: managerOrgBilling.plan,
billingCycleStart: managerOrgBilling.billingCycleStart,
billingCycleEnd: managerOrgBilling.billingCycleEnd,
overdue: managerOrgBilling.overdue,
managerBillingId: managerOrgBilling.id,
},
});
}
}