feat(billing): refacto billing (#14243)

… prices for metered billing

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
Antoine Moreaux
2025-09-19 11:25:53 +02:00
committed by GitHub
parent 163890f6c8
commit 43e0cd5d05
351 changed files with 16091 additions and 6101 deletions
@@ -1,16 +1,18 @@
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { type WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import {
WorkflowVersionStatus,
type WorkflowVersionWorkspaceEntity,
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
import { type WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
@WorkspaceQueryHook({
key: `workflow.createMany`,
@@ -31,7 +33,7 @@ export class WorkflowCreateManyPostQueryHook
): Promise<void> {
const workspace = authContext.workspace;
workspaceValidator.assertIsDefinedOrThrow(workspace);
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
const workflowVersionRepository =
await this.twentyORMManager.getRepository<WorkflowVersionWorkspaceEntity>(
@@ -1,16 +1,18 @@
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { type WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import {
WorkflowVersionStatus,
type WorkflowVersionWorkspaceEntity,
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
import { type WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
@WorkspaceQueryHook({
key: `workflow.createOne`,
@@ -31,7 +33,7 @@ export class WorkflowCreateOnePostQueryHook
): Promise<void> {
const workspace = authContext.workspace;
workspaceValidator.assertIsDefinedOrThrow(workspace);
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
const workflow = payload[0];
@@ -1,3 +1,5 @@
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { type WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
@@ -5,7 +7,7 @@ import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-r
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { type WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
@WorkspaceQueryHook({
key: `workflow.deleteMany`,
@@ -25,7 +27,7 @@ export class WorkflowDeleteManyPostQueryHook
): Promise<void> {
const workspace = authContext.workspace;
workspaceValidator.assertIsDefinedOrThrow(workspace);
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
await this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
workflowIds: payload.map((workflow) => workflow.id),
@@ -1,3 +1,5 @@
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { type WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
@@ -5,7 +7,7 @@ import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-r
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { type WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
@WorkspaceQueryHook({
key: `workflow.deleteOne`,
@@ -25,7 +27,7 @@ export class WorkflowDeleteOnePostQueryHook
): Promise<void> {
const workspace = authContext.workspace;
workspaceValidator.assertIsDefinedOrThrow(workspace);
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
await this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
workflowIds: payload.map((workflow) => workflow.id),
@@ -1,10 +1,12 @@
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { type WorkspacePreQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { type DestroyManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
@WorkspaceQueryHook('workflow.destroyMany')
export class WorkflowDestroyManyPreQueryHook
@@ -21,7 +23,7 @@ export class WorkflowDestroyManyPreQueryHook
): Promise<DestroyManyResolverArgs<{ id: { in: string[] } }>> {
const workspace = authContext.workspace;
workspaceValidator.assertIsDefinedOrThrow(workspace);
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
await this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
workflowIds: payload.filter.id.in,
@@ -1,10 +1,12 @@
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { type WorkspacePreQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { type DestroyOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
@WorkspaceQueryHook('workflow.destroyOne')
export class WorkflowDestroyOnePreQueryHook
@@ -21,7 +23,7 @@ export class WorkflowDestroyOnePreQueryHook
): Promise<DestroyOneResolverArgs> {
const workspace = authContext.workspace;
workspaceValidator.assertIsDefinedOrThrow(workspace);
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
await this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
workflowIds: [payload.id],
@@ -1,3 +1,5 @@
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { type WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
@@ -5,7 +7,7 @@ import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-r
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { type WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
@WorkspaceQueryHook({
key: 'workflow.restoreMany',
@@ -25,7 +27,7 @@ export class WorkflowRestoreManyPostQueryHook
): Promise<void> {
const workspace = authContext.workspace;
workspaceValidator.assertIsDefinedOrThrow(workspace);
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
await this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
workflowIds: payload.map((workflow) => workflow.id),
@@ -1,3 +1,5 @@
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { type WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
@@ -5,7 +7,7 @@ import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-r
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { type WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
@WorkspaceQueryHook({
key: 'workflow.restoreOne',
@@ -25,7 +27,7 @@ export class WorkflowRestoreOnePostQueryHook
): Promise<void> {
const workspace = authContext.workspace;
workspaceValidator.assertIsDefinedOrThrow(workspace);
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
await this.workflowCommonWorkspaceService.handleWorkflowSubEntities({
workflowIds: payload.map((workflow) => workflow.id),
@@ -1,10 +1,12 @@
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { type WorkspacePreQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { type DeleteOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-version-validation.workspace-service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
@WorkspaceQueryHook(`workflowVersion.deleteOne`)
export class WorkflowVersionDeleteOnePreQueryHook
@@ -21,7 +23,7 @@ export class WorkflowVersionDeleteOnePreQueryHook
): Promise<DeleteOneResolverArgs> {
const { workspace } = authContext;
workspaceValidator.assertIsDefinedOrThrow(workspace);
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForDeleteOne(
workspace.id,
@@ -1,3 +1,5 @@
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
import { type WorkspacePreQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
import { type UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
@@ -5,7 +7,7 @@ import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runne
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { type WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-version-validation.workspace-service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
@WorkspaceQueryHook(`workflowVersion.updateOne`)
export class WorkflowVersionUpdateOnePreQueryHook
@@ -22,7 +24,7 @@ export class WorkflowVersionUpdateOnePreQueryHook
): Promise<UpdateOneResolverArgs<WorkflowVersionWorkspaceEntity>> {
const { workspace } = authContext;
workspaceValidator.assertIsDefinedOrThrow(workspace);
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
await this.workflowVersionValidationWorkspaceService.validateWorkflowVersionForUpdateOne(
{