diff --git a/packages/common/src/schemas/documents/workflow/config-schema.ts b/packages/common/src/schemas/documents/workflow/config-schema.ts index e3f6464bed..eb253cdd93 100644 --- a/packages/common/src/schemas/documents/workflow/config-schema.ts +++ b/packages/common/src/schemas/documents/workflow/config-schema.ts @@ -72,7 +72,6 @@ export const WorkflowConfigSchema = Type.Object({ availableDocuments: Type.Optional(Type.Array(AvailableDocumentSchema)), callbackResult: Type.Optional(CallbackResultSchema), childCallbackResults: Type.Optional(Type.Array(ChildCallbackResultSchema)), - createCollectionFlowToken: Type.Optional(Type.Boolean()), mainRepresentative: Type.Optional(MainRepresentativeSchema), customerName: Type.Optional(Type.String()), enableManualCreation: Type.Optional(Type.Boolean()), diff --git a/packages/common/src/utils/collection-flow/build-collection-flow-state.ts b/packages/common/src/utils/collection-flow/build-collection-flow-state.ts index f5ef3a140d..c894ed686b 100644 --- a/packages/common/src/utils/collection-flow/build-collection-flow-state.ts +++ b/packages/common/src/utils/collection-flow/build-collection-flow-state.ts @@ -36,11 +36,9 @@ export const buildCollectionFlowState = (inputConfig: TCollectionFlowConfig): TC const config: TCollectionFlow['config'] = initializeConfig(inputConfig); const state: TCollectionFlow['state'] = initializeState(inputConfig); - const collectionFlow: TCollectionFlow = { + return { config, state, additionalInformation: inputConfig.additionalInformation || {}, }; - - return collectionFlow; }; diff --git a/services/workflows-service/scripts/workflows/dynamic-ui-workflow.ts b/services/workflows-service/scripts/workflows/dynamic-ui-workflow.ts index fb07c03de1..d8c56199e5 100644 --- a/services/workflows-service/scripts/workflows/dynamic-ui-workflow.ts +++ b/services/workflows-service/scripts/workflows/dynamic-ui-workflow.ts @@ -229,7 +229,6 @@ export const dynamicUiWorkflowDefinition = { language: 'en', supportedLanguages: ['en', 'cn'], initialEvent: 'START', - createCollectionFlowToken: true, childCallbackResults: [ { definitionId: kycEmailSessionDefinition.name, diff --git a/services/workflows-service/scripts/workflows/kyb-kyc-workflow-definition.ts b/services/workflows-service/scripts/workflows/kyb-kyc-workflow-definition.ts index eaa4d9d6e2..b149104b96 100644 --- a/services/workflows-service/scripts/workflows/kyb-kyc-workflow-definition.ts +++ b/services/workflows-service/scripts/workflows/kyb-kyc-workflow-definition.ts @@ -229,7 +229,6 @@ export const kybKycWorkflowDefinition = { deliverEvent: 'KYC_RESPONDED', }, ], - createCollectionFlowToken: true, }, contextSchema: { type: 'json-schema', diff --git a/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-child-associated-company-definition.ts b/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-child-associated-company-definition.ts index 5505de7a57..d87b9dbb9d 100644 --- a/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-child-associated-company-definition.ts +++ b/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-child-associated-company-definition.ts @@ -57,7 +57,6 @@ export const composeChildAssociatedCompanyDefinition = ({ apiPlugins: [], }, config: { - createCollectionFlowToken: true, workflowLevelResolution: true, }, projectId: projectId, diff --git a/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-kyb-with-associated-companies-definition.ts b/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-kyb-with-associated-companies-definition.ts index 824031ae18..e6af502529 100644 --- a/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-kyb-with-associated-companies-definition.ts +++ b/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-kyb-with-associated-companies-definition.ts @@ -188,7 +188,6 @@ export const composeKybWithAssociatedCompaniesDefinition = ({ }, config: { isExample: true, - createCollectionFlowToken: true, workflowLevelResolution: true, childCallbackResults: [ { diff --git a/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-kyc-child-workflow-definition.ts b/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-kyc-child-workflow-definition.ts index 3f0c5652a2..8eb8d962c7 100644 --- a/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-kyc-child-workflow-definition.ts +++ b/services/workflows-service/scripts/workflows/ui-definition/kyb-with-associated-companies/definition/compose-kyc-child-workflow-definition.ts @@ -57,7 +57,6 @@ export const composeKycChildWorkflowDefinition = ({ apiPlugins: [], }, config: { - createCollectionFlowToken: true, workflowLevelResolution: true, isCaseOverviewEnabled: true, }, diff --git a/services/workflows-service/src/auth/auth.module.ts b/services/workflows-service/src/auth/auth.module.ts index 9e32eef26a..00683203e9 100644 --- a/services/workflows-service/src/auth/auth.module.ts +++ b/services/workflows-service/src/auth/auth.module.ts @@ -4,7 +4,7 @@ import { AuthService } from './auth.service'; import { BasicStrategy } from './basic/basic.strategy'; import { PasswordService } from './password/password.service'; // eslint-disable-next-line import/no-cycle -import { UserModule } from '../user/user.module'; +import { UserModule } from '@/user/user.module'; import { LocalStrategy } from '@/auth/local/local.strategy'; import { SessionSerializer } from '@/auth/session-serializer'; import { UserService } from '@/user/user.service'; diff --git a/services/workflows-service/src/auth/workflow-token/workflow-token.repository.ts b/services/workflows-service/src/auth/workflow-token/workflow-token.repository.ts index 07a708a6ac..9c5c220dcf 100644 --- a/services/workflows-service/src/auth/workflow-token/workflow-token.repository.ts +++ b/services/workflows-service/src/auth/workflow-token/workflow-token.repository.ts @@ -1,7 +1,8 @@ -import { Prisma, PrismaClient } from '@prisma/client'; import { Injectable } from '@nestjs/common'; -import type { PrismaTransaction, TProjectId } from '@/types'; +import { Prisma, PrismaClient } from '@prisma/client'; + import { PrismaService } from '@/prisma/prisma.service'; +import type { PrismaTransaction, TProjectId } from '@/types'; @Injectable() export class WorkflowTokenRepository { @@ -23,6 +24,13 @@ export class WorkflowTokenRepository { }); } + async count(args: Prisma.WorkflowRuntimeDataTokenCountArgs, projectId: TProjectId) { + return await this.prismaService.workflowRuntimeDataToken.count({ + ...args, + where: { ...args.where, projectId }, + }); + } + async findFirstByWorkflowruntimeDataIdUnscoped(workflowRuntimeDataId: string) { return await this.prismaService.workflowRuntimeDataToken.findFirst({ select: { diff --git a/services/workflows-service/src/auth/workflow-token/workflow-token.service.ts b/services/workflows-service/src/auth/workflow-token/workflow-token.service.ts index 4c07dd4ef9..6146063c99 100644 --- a/services/workflows-service/src/auth/workflow-token/workflow-token.service.ts +++ b/services/workflows-service/src/auth/workflow-token/workflow-token.service.ts @@ -1,16 +1,94 @@ import { Injectable } from '@nestjs/common'; import { WorkflowTokenRepository } from '@/auth/workflow-token/workflow-token.repository'; -import type { PrismaTransaction, TProjectId } from '@/types'; +import type { InputJsonValue, PrismaTransaction, TProjectId } from '@/types'; +import { Prisma, UiDefinitionContext } from '@prisma/client'; +import { buildCollectionFlowState, getOrderedSteps } from '@ballerine/common'; +import { env } from '@/env'; +import { WORKFLOW_FINAL_STATES } from '@/workflow/consts'; +import { UiDefinitionService } from '@/ui-definition/ui-definition.service'; +import { WorkflowRuntimeDataRepository } from '@/workflow/workflow-runtime-data.repository'; +import { CustomerService } from '@/customer/customer.service'; @Injectable() export class WorkflowTokenService { - constructor(private readonly workflowTokenRepository: WorkflowTokenRepository) {} + constructor( + private readonly customerService: CustomerService, + private readonly uiDefinitionService: UiDefinitionService, + private readonly workflowTokenRepository: WorkflowTokenRepository, + private readonly workflowRuntimeDataRepository: WorkflowRuntimeDataRepository, + ) {} async create( projectId: TProjectId, data: Parameters[1], transaction?: PrismaTransaction, ) { + const { workflowRuntimeDataId } = data; + + const existingTokensForWorkflowRuntime = await this.count( + { where: { workflowRuntimeDataId } }, + projectId, + ); + + if (existingTokensForWorkflowRuntime === 0) { + const { workflowDefinitionId, context } = await this.workflowRuntimeDataRepository.findById( + workflowRuntimeDataId, + { select: { workflowDefinitionId: true, context: true } }, + [projectId], + ); + + const [uiDefinition, customer] = await Promise.all([ + this.uiDefinitionService.getByWorkflowDefinitionId( + workflowDefinitionId, + UiDefinitionContext.collection_flow, + [projectId], + ), + this.customerService.getByProjectId(projectId), + ]); + + const collectionFlow = buildCollectionFlowState({ + apiUrl: env.APP_API_URL, + steps: uiDefinition?.definition + ? getOrderedSteps( + (uiDefinition?.definition as Prisma.JsonObject)?.definition as Record< + string, + Record + >, + { finalStates: [...WORKFLOW_FINAL_STATES] }, + ).map(stepName => ({ + stateName: stepName, + })) + : [], + additionalInformation: { + customerCompany: customer.displayName, + }, + }); + + const workflowToken = await this.workflowTokenRepository.create(projectId, data, transaction); + + await this.workflowRuntimeDataRepository.updateStateById( + workflowRuntimeDataId, + { + data: { + context: { + ...context, + collectionFlow, + metadata: { + ...(context.metadata ?? {}), + token: workflowToken.token, + collectionFlowUrl: env.COLLECTION_FLOW_URL, + webUiSDKUrl: env.WEB_UI_SDK_URL, + }, + } as InputJsonValue, + projectId, + }, + }, + transaction, + ); + + return workflowToken; + } + return await this.workflowTokenRepository.create(projectId, data, transaction); } @@ -26,6 +104,13 @@ export class WorkflowTokenService { return await this.workflowTokenRepository.findByTokenWithExpiredUnscoped(token); } + async count( + args: Parameters[0], + projectId: TProjectId, + ) { + return await this.workflowTokenRepository.count(args, projectId); + } + async deleteByToken(token: string) { return await this.workflowTokenRepository.deleteByTokenUnscoped(token); } diff --git a/services/workflows-service/src/collection-flow/collection-flow.service.intg.test.ts b/services/workflows-service/src/collection-flow/collection-flow.service.intg.test.ts index d29e1e5148..9e66afda41 100644 --- a/services/workflows-service/src/collection-flow/collection-flow.service.intg.test.ts +++ b/services/workflows-service/src/collection-flow/collection-flow.service.intg.test.ts @@ -37,6 +37,7 @@ import { Customer, EndUser, PrismaClient, Project } from '@prisma/client'; import { noop } from 'lodash'; import { CollectionFlowService } from './collection-flow.service'; import { MerchantMonitoringClient } from '@/business-report/merchant-monitoring-client'; +import { env } from '@/env'; const deps: Provider[] = [ { @@ -121,6 +122,7 @@ describe('CollectionFlowService', () => { let workflowRuntimeDataRepository: WorkflowRuntimeDataRepository; let customerRepository: CustomerRepository; let endUserRepository: EndUserRepository; + let uiDefinitionRepository: UiDefinitionRepository; let customer: Customer; let project: Project; @@ -159,6 +161,7 @@ describe('CollectionFlowService', () => { ); customerRepository = module.get(CustomerRepository); endUserRepository = module.get(EndUserRepository); + uiDefinitionRepository = module.get(UiDefinitionRepository); }); beforeEach(async () => { @@ -202,6 +205,16 @@ describe('CollectionFlowService', () => { }, }); + await uiDefinitionRepository.create({ + data: { + uiSchema: {}, + projectId: project.id, + name: 'test-ui-definition', + uiContext: 'collection_flow', + workflowDefinitionId: workflowDefinition.id, + }, + }); + const workflowRuntimeData = await workflowRuntimeDataRepository.create({ data: { workflowDefinitionId: workflowDefinition.id, @@ -220,7 +233,28 @@ describe('CollectionFlowService', () => { const context = await collectionFlowService.getCollectionFlowContext(token); - expect(context.context).toEqual(workflowContext); + const expectedContext = { + metadata: { + token: token.token, + webUiSDKUrl: env.WEB_UI_SDK_URL, + collectionFlowUrl: env.COLLECTION_FLOW_URL, + }, + collectionFlow: { + state: { + steps: [], + status: 'pending', + currentStep: '', + }, + config: { + apiUrl: env.APP_API_URL, + }, + additionalInformation: { + customerCompany: customer.displayName, + }, + }, + }; + + expect(context.context).toEqual(expectedContext); expect(context.config).toEqual(workflowConfig); }); }); diff --git a/services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.intg.test.ts b/services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.intg.test.ts index 04e627d114..8ddf1c26a9 100644 --- a/services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.intg.test.ts +++ b/services/workflows-service/src/collection-flow/controllers/collection-flow.no-user.controller.intg.test.ts @@ -37,12 +37,16 @@ import { WorkflowEventEmitterService } from '@/workflow/workflow-event-emitter.s import { WorkflowRuntimeDataRepository } from '@/workflow/workflow-runtime-data.repository'; import { WorkflowService } from '@/workflow/workflow.service'; import { CollectionFlowNoUserController } from './collection-flow.no-user.controller'; +import { UiDefinitionRepository } from '@/ui-definition/ui-definition.repository'; +import { ApiKeyService } from '@/customer/api-key/api-key.service'; +import { ApiKeyRepository } from '@/customer/api-key/api-key.repository'; describe('CollectionFlowSignupController', () => { let app: INestApplication; let prismaClient: PrismaService; let workflowTokenService: WorkflowTokenService; let workflowDefinitionRepository: WorkflowDefinitionRepository; + let uiDefinitionRepository: UiDefinitionRepository; let workflowRuntimeDataRepository: WorkflowRuntimeDataRepository; let customerRepository: CustomerRepository; let endUserRepository: EndUserRepository; @@ -55,8 +59,6 @@ describe('CollectionFlowSignupController', () => { controllers: [CollectionFlowNoUserController], providers: [ { provide: BusinessService, useValue: noop }, - { provide: UiDefinitionService, useValue: noop }, - { provide: CustomerService, useValue: noop }, { provide: FileService, useValue: noop }, { provide: SalesforceService, useValue: noop }, { provide: RiskRuleService, useValue: noop }, @@ -72,6 +74,11 @@ describe('CollectionFlowSignupController', () => { { provide: WorkflowEventEmitterService, useValue: { emit: noop } }, WorkflowService, EndUserService, + UiDefinitionService, + UiDefinitionRepository, + CustomerService, + ApiKeyService, + ApiKeyRepository, BusinessReportService, BusinessRepository, EntityRepository, @@ -95,6 +102,7 @@ describe('CollectionFlowSignupController', () => { workflowDefinitionRepository = module.get( WorkflowDefinitionRepository, ); + uiDefinitionRepository = module.get(UiDefinitionRepository); workflowRuntimeDataRepository = module.get( WorkflowRuntimeDataRepository, ); @@ -124,6 +132,16 @@ describe('CollectionFlowSignupController', () => { }, }); + await uiDefinitionRepository.create({ + data: { + uiSchema: {}, + projectId: project.id, + uiContext: 'collection_flow', + name: 'signup-test-ui-definition', + workflowDefinitionId: workflowDefinition.id, + }, + }); + const { id: workflowRuntimeDataId } = await workflowRuntimeDataRepository.create({ data: { workflowDefinitionId: workflowDefinition.id, diff --git a/services/workflows-service/src/common/guards/token-guard/token-auth.module.ts b/services/workflows-service/src/common/guards/token-guard/token-auth.module.ts index 3cbe3caa13..0816dc5207 100644 --- a/services/workflows-service/src/common/guards/token-guard/token-auth.module.ts +++ b/services/workflows-service/src/common/guards/token-guard/token-auth.module.ts @@ -1,10 +1,31 @@ -import { WorkflowTokenRepository } from '@/auth/workflow-token/workflow-token.repository'; -import { WorkflowTokenService } from '@/auth/workflow-token/workflow-token.service'; -import { TokenAuthGuard } from '@/common/guards/token-guard/token-auth.guard'; import { Module } from '@nestjs/common'; +import { CustomerService } from '@/customer/customer.service'; +import { ApiKeyService } from '@/customer/api-key/api-key.service'; +import { CustomerRepository } from '@/customer/customer.repository'; +import { ProjectScopeService } from '@/project/project-scope.service'; +import { ApiKeyRepository } from '@/customer/api-key/api-key.repository'; +import { UiDefinitionService } from '@/ui-definition/ui-definition.service'; +import { TokenAuthGuard } from '@/common/guards/token-guard/token-auth.guard'; +import { UiDefinitionRepository } from '@/ui-definition/ui-definition.repository'; +import { WorkflowTokenService } from '@/auth/workflow-token/workflow-token.service'; +import { WorkflowTokenRepository } from '@/auth/workflow-token/workflow-token.repository'; +import { WorkflowRuntimeDataRepository } from '@/workflow/workflow-runtime-data.repository'; + @Module({ - providers: [WorkflowTokenRepository, WorkflowTokenService, TokenAuthGuard], + providers: [ + WorkflowTokenRepository, + WorkflowTokenService, + TokenAuthGuard, + CustomerService, + CustomerRepository, + UiDefinitionService, + ProjectScopeService, + UiDefinitionRepository, + WorkflowRuntimeDataRepository, + ApiKeyService, + ApiKeyRepository, + ], exports: [WorkflowTokenRepository, WorkflowTokenService, TokenAuthGuard], }) export class TokenAuthModule {} diff --git a/services/workflows-service/src/workflow/schemas/zod-schemas.ts b/services/workflows-service/src/workflow/schemas/zod-schemas.ts index c47d641554..0fc2fdbc79 100644 --- a/services/workflows-service/src/workflow/schemas/zod-schemas.ts +++ b/services/workflows-service/src/workflow/schemas/zod-schemas.ts @@ -40,10 +40,6 @@ export const ConfigSchema = z .optional(), ) .optional(), - createCollectionFlowToken: z - .boolean() - .optional() - .describe('Whether to create a collection flow token as part of the workflow'), mainRepresentative: z .object({ fullName: z.string(), diff --git a/services/workflows-service/src/workflow/workflow-runtime-data.repository.ts b/services/workflows-service/src/workflow/workflow-runtime-data.repository.ts index 2c6915a4b0..e4b3d83ee1 100644 --- a/services/workflows-service/src/workflow/workflow-runtime-data.repository.ts +++ b/services/workflows-service/src/workflow/workflow-runtime-data.repository.ts @@ -23,14 +23,13 @@ type StateRelatedColumns = 'state' | 'status' | 'context' | 'tags'; @Injectable() export class WorkflowRuntimeDataRepository { constructor( - protected readonly prisma: PrismaService, - protected readonly projectScopeService: ProjectScopeService, + protected readonly prismaService: PrismaService, protected readonly scopeService: ProjectScopeService, ) {} async create( args: Prisma.SelectSubset, - transaction: PrismaTransaction | PrismaClient = this.prisma, + transaction: PrismaTransaction | PrismaClient = this.prismaService, ): Promise { return await transaction.workflowRuntimeData.create({ ...args, @@ -48,7 +47,7 @@ export class WorkflowRuntimeDataRepository { args: Prisma.SelectSubset, projectIds: TProjectIds, ) { - return await this.prisma.workflowRuntimeData.findMany( + return await this.prismaService.workflowRuntimeData.findMany( this.scopeService.scopeFindMany(args, projectIds), ); } @@ -56,13 +55,13 @@ export class WorkflowRuntimeDataRepository { async findManyUnscoped( args: Prisma.SelectSubset, ) { - return await this.prisma.workflowRuntimeData.findMany(args); + return await this.prismaService.workflowRuntimeData.findMany(args); } async findOne( args: Prisma.SelectSubset, projectIds: TProjectIds, - transaction: PrismaTransaction | PrismaClient = this.prisma, + transaction: PrismaTransaction | PrismaClient = this.prismaService, ): Promise { return await transaction.workflowRuntimeData.findFirst( this.scopeService.scopeFindOne(args, projectIds), @@ -86,7 +85,7 @@ export class WorkflowRuntimeDataRepository { id: string, args: Prisma.SelectSubset>, projectIds: TProjectIds, - transaction: PrismaTransaction | PrismaClient = this.prisma, + transaction: PrismaTransaction | PrismaClient = this.prismaService, ): Promise { return await transaction.workflowRuntimeData.findFirstOrThrow( this.scopeService.scopeFindOne(merge(args, { where: { id } }), projectIds), @@ -134,7 +133,7 @@ export class WorkflowRuntimeDataRepository { async findByIdAndLockUnscoped({ id, - transaction = this.prisma, + transaction = this.prismaService, }: { id: string; transaction: PrismaTransaction | PrismaClient; @@ -149,7 +148,7 @@ export class WorkflowRuntimeDataRepository { args: { data: Omit; }, - transaction: PrismaTransaction | PrismaService = this.prisma, + transaction: PrismaTransaction | PrismaService = this.prismaService, ): Promise { return await transaction.workflowRuntimeData.update({ where: { id }, @@ -166,7 +165,7 @@ export class WorkflowRuntimeDataRepository { data: Prisma.WorkflowRuntimeDataUncheckedUpdateInput; include?: Prisma.WorkflowRuntimeDataInclude; }, - transaction: PrismaTransaction, + transaction: PrismaTransaction = this.prismaService, ) { return await transaction.workflowRuntimeData.update({ where: { id }, @@ -182,7 +181,7 @@ export class WorkflowRuntimeDataRepository { projectIds: TProjectIds, ): Promise { const stringifiedConfig = JSON.stringify(newConfig); - const affectedRows = await this.prisma + const affectedRows = await this.prismaService .$executeRaw`UPDATE "WorkflowRuntimeData" SET "config" = jsonb_deep_merge_with_options("config", ${stringifiedConfig}::jsonb, ${arrayMergeOption}) WHERE "id" = ${id} AND "projectId" in (${projectIds?.join( ',', )})`; @@ -200,7 +199,7 @@ export class WorkflowRuntimeDataRepository { args: Prisma.SelectSubset>, projectIds: TProjectIds, ): Promise { - return await this.prisma.workflowRuntimeData.delete( + return await this.prismaService.workflowRuntimeData.delete( this.scopeService.scopeDelete( { where: { id }, @@ -259,7 +258,7 @@ export class WorkflowRuntimeDataRepository { async findContext(id: string, projectIds: TProjectIds) { return ( - await this.prisma.workflowRuntimeData.findFirstOrThrow( + await this.prismaService.workflowRuntimeData.findFirstOrThrow( this.scopeService.scopeFindOne( { where: { id }, @@ -277,7 +276,7 @@ export class WorkflowRuntimeDataRepository { args: Prisma.SelectSubset, projectIds: TProjectIds, ): Promise { - return await this.prisma.workflowRuntimeData.count( + return await this.prismaService.workflowRuntimeData.count( this.scopeService.scopeFindMany(args, projectIds) as any, ); } @@ -286,7 +285,7 @@ export class WorkflowRuntimeDataRepository { args: Prisma.SubsetIntersection, projectIds: TProjectIds, ) { - return await this.prisma.workflowRuntimeData.groupBy( + return await this.prismaService.workflowRuntimeData.groupBy( this.scopeService.scopeGroupBy(args, projectIds), ); } @@ -396,6 +395,6 @@ export class WorkflowRuntimeDataRepository { LIMIT ${take} OFFSET ${skip} `; - return (await this.prisma.$queryRaw(sql)) as WorkflowRuntimeData[]; + return (await this.prismaService.$queryRaw(sql)) as WorkflowRuntimeData[]; } } diff --git a/services/workflows-service/src/workflow/workflow.controller.external.ts b/services/workflows-service/src/workflow/workflow.controller.external.ts index 313e3ba4ec..91a0221221 100644 --- a/services/workflows-service/src/workflow/workflow.controller.external.ts +++ b/services/workflows-service/src/workflow/workflow.controller.external.ts @@ -52,7 +52,7 @@ export const WORKFLOW_TAG = 'Workflows'; @common.Controller('external/workflows') export class WorkflowControllerExternal { constructor( - protected readonly service: WorkflowService, + protected readonly workflowService: WorkflowService, protected readonly normalizeService: HookCallbackHandlerService, private readonly workflowTokenService: WorkflowTokenService, private readonly workflowDefinitionService: WorkflowDefinitionService, @@ -68,7 +68,7 @@ export class WorkflowControllerExternal { @Query() query: GetWorkflowsRuntimeInputDto, @ProjectIds() projectIds: TProjectIds, ): Promise { - const results = await this.service.listRuntimeData( + const results = await this.workflowService.listRuntimeData( { page: query.page, size: query.limit, @@ -89,7 +89,7 @@ export class WorkflowControllerExternal { @common.Param() params: WorkflowDefinitionWhereUniqueInput, @ProjectIds() projectIds: TProjectIds, ) { - return await this.service.getWorkflowDefinitionById( + return await this.workflowService.getWorkflowDefinitionById( params.id, { include: { @@ -186,7 +186,7 @@ export class WorkflowControllerExternal { @common.Param() params: WorkflowDefinitionWhereUniqueInput, @ProjectIds() projectIds: TProjectIds, ): Promise { - const workflowRuntimeData = await this.service.getWorkflowRuntimeDataById( + const workflowRuntimeData = await this.workflowService.getWorkflowRuntimeDataById( params.id, {}, projectIds, @@ -210,7 +210,11 @@ export class WorkflowControllerExternal { @CurrentProject() currentProjectId: TProjectId, ): Promise { try { - return await this.service.updateWorkflowRuntimeData(params.id, data, currentProjectId); + return await this.workflowService.updateWorkflowRuntimeData( + params.id, + data, + currentProjectId, + ); } catch (error) { if (isRecordNotFoundError(error)) { throw new errors.NotFoundException(`No resource was found for ${JSON.stringify(params)}`); @@ -352,7 +356,7 @@ export class WorkflowControllerExternal { projectIds, ); - const actionResult = await this.service.createOrUpdateWorkflowRuntime({ + const actionResult = await this.workflowService.createOrUpdateWorkflowRuntime({ workflowDefinitionId: latestDefinitionVersion.id, context, config, @@ -368,7 +372,6 @@ export class WorkflowControllerExternal { workflowDefinitionId: actionResult[0]?.workflowDefinition.id, workflowRuntimeId: actionResult[0]?.workflowRuntimeData.id, ballerineEntityId: actionResult[0]?.ballerineEntityId, - entities: actionResult[0]?.entities, }); } @@ -378,21 +381,18 @@ export class WorkflowControllerExternal { @common.HttpCode(200) @swagger.ApiForbiddenResponse({ type: errors.ForbiddenException }) async createCollectionFlowUrl( - @common.Body() - { workflowRuntimeDataId }: CreateCollectionFlowUrlDto, + @common.Body() { workflowRuntimeDataId }: CreateCollectionFlowUrlDto, ) { - const result = await this.workflowTokenService.findFirstByWorkflowruntimeDataIdUnscoped( + const token = await this.workflowTokenService.findFirstByWorkflowruntimeDataIdUnscoped( workflowRuntimeDataId, ); - if (!result) { - throw new NotFoundException( - `No WorkflowRuntimeDataId was found for ${JSON.stringify(workflowRuntimeDataId)}`, - ); + if (!token) { + throw new NotFoundException(`No token was found for ${workflowRuntimeDataId}`); } return { - collectionFlowUrl: `${env.COLLECTION_FLOW_URL}?token=${result.token}`, + collectionFlowUrl: `${env.COLLECTION_FLOW_URL}?token=${token.token}`, }; } @@ -405,6 +405,16 @@ export class WorkflowControllerExternal { @common.Body() { expiry, workflowRuntimeDataId, endUserId }: CreateTokenDto, @CurrentProject() currentProjectId: TProjectId, ) { + try { + await this.workflowService.getWorkflowRuntimeDataById(workflowRuntimeDataId, {}, [ + currentProjectId, + ]); + } catch (e) { + throw new common.BadRequestException( + `No WorkflowRuntimeData was found for ${workflowRuntimeDataId}`, + ); + } + const expiresAt = new Date(Date.now() + (expiry || 30) * 24 * 60 * 60 * 1000); const { token } = await this.workflowTokenService.create(currentProjectId, { @@ -429,7 +439,7 @@ export class WorkflowControllerExternal { @ProjectIds() projectIds: TProjectIds, @CurrentProject() currentProjectId: TProjectId, ): Promise { - return await this.service.event( + return await this.workflowService.event( { ...data, id, @@ -451,7 +461,7 @@ export class WorkflowControllerExternal { @ProjectIds() projectIds: TProjectIds, @CurrentProject() currentProjectId: TProjectId, ) { - return await this.service.event( + return await this.workflowService.event( { ...data, id, @@ -479,7 +489,7 @@ export class WorkflowControllerExternal { @ProjectIds() projectIds: TProjectIds, ) { try { - const context = await this.service.getWorkflowRuntimeDataContext(id, projectIds); + const context = await this.workflowService.getWorkflowRuntimeDataContext(id, projectIds); return { context }; } catch (err) { @@ -504,10 +514,11 @@ export class WorkflowControllerExternal { ): Promise { try { await this.prismaService.$transaction(async transaction => { - const workflowRuntime = await this.service.getWorkflowRuntimeDataByIdAndLockUnscoped({ - id: params.id, - transaction, - }); + const workflowRuntime = + await this.workflowService.getWorkflowRuntimeDataByIdAndLockUnscoped({ + id: params.id, + transaction, + }); const context = await this.normalizeService.handleHookResponse({ workflowRuntime, @@ -518,7 +529,7 @@ export class WorkflowControllerExternal { currentProjectId: workflowRuntime.projectId, }); - await this.service.event( + await this.workflowService.event( { id: params.id, name: BUILT_IN_EVENT.DEEP_MERGE_CONTEXT, @@ -532,7 +543,7 @@ export class WorkflowControllerExternal { transaction, ); - await this.service.event( + await this.workflowService.event( { id: params.id, name: params.event, diff --git a/services/workflows-service/src/workflow/workflow.service.ts b/services/workflows-service/src/workflow/workflow.service.ts index 10b0ec69ca..d5b1b686f2 100644 --- a/services/workflows-service/src/workflow/workflow.service.ts +++ b/services/workflows-service/src/workflow/workflow.service.ts @@ -1,5 +1,4 @@ import { WorkflowTokenService } from '@/auth/workflow-token/workflow-token.service'; -import { BusinessReportService } from '@/business-report/business-report.service'; import { BusinessRepository } from '@/business/business.repository'; import { BusinessService } from '@/business/business.service'; import { ajv } from '@/common/ajv/ajv.validator'; @@ -52,11 +51,9 @@ import { } from '@/workflow/workflow-runtime-list-item.model'; import { AnyRecord, - buildCollectionFlowState, CollectionFlowStatusesEnum, DefaultContextSchema, getDocumentId, - getOrderedSteps, isErrorWithMessage, isObject, ProcessStatus, @@ -89,7 +86,6 @@ import { EndUser, Prisma, PrismaClient, - UiDefinitionContext, User, WorkflowDefinition, WorkflowRuntimeData, @@ -100,7 +96,6 @@ import { plainToClass } from 'class-transformer'; import dayjs from 'dayjs'; import { isEqual, merge } from 'lodash'; import mime from 'mime'; -import { WORKFLOW_FINAL_STATES } from './consts'; import { WorkflowDefinitionCreateDto } from './dtos/workflow-definition-create'; import { WorkflowDefinitionFindManyArgs } from './dtos/workflow-definition-find-many-args'; import { WorkflowDefinitionUpdateInput } from './dtos/workflow-definition-update-input'; @@ -140,7 +135,6 @@ export class WorkflowService { protected readonly workflowRuntimeDataRepository: WorkflowRuntimeDataRepository, protected readonly endUserRepository: EndUserRepository, protected readonly endUserService: EndUserService, - protected readonly businessReportService: BusinessReportService, protected readonly businessRepository: BusinessRepository, protected readonly businessService: BusinessService, protected readonly entityRepository: EntityRepository, @@ -1444,12 +1438,6 @@ export class WorkflowService { validatedConfig || {}, ) as InputJsonValue; - const entities: Array<{ - id: string; - type: 'individual' | 'business'; - tags?: Array<'mainRepresentative' | 'UBO'>; - }> = []; - // Creating new workflow if ( !existingWorkflowRuntimeData || @@ -1466,19 +1454,6 @@ export class WorkflowService { currentProjectId, customer.name, ); - let uiDefinition; - - try { - uiDefinition = await this.uiDefinitionService.getByWorkflowDefinitionId( - workflowDefinitionId, - UiDefinitionContext.collection_flow, - projectIds, - ); - } catch (err) { - if (isErrorWithMessage(err)) { - this.logger.warn(err.message); - } - } workflowRuntimeData = await this.workflowRuntimeDataRepository.create( { @@ -1519,87 +1494,6 @@ export class WorkflowService { workflowRuntimeData, }); - let endUserId: string | null = null; - const entityData = - workflowRuntimeData.context.entity?.data?.additionalInfo?.mainRepresentative; - - if (mergedConfig.createCollectionFlowToken) { - if (entityType === 'endUser') { - endUserId = entityId; - entities.push({ type: 'individual', id: entityId }); - } else if (entityData) { - endUserId = await this.__generateEndUserWithBusiness({ - entityType, - workflowRuntimeData, - entityData: entityData, - currentProjectId, - entityId, - position: BusinessPosition.representative, - }); - - entities.push({ - type: 'individual', - id: endUserId, - }); - - entities.push({ type: 'business', id: entityId }); - - if (entityData) { - workflowRuntimeData.context.entity.data.additionalInfo.mainRepresentative.ballerineEntityId = - endUserId; - } - } - - const nowPlus30Days = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000); - const workflowToken = await this.workflowTokenService.create( - currentProjectId, - { - workflowRuntimeDataId: workflowRuntimeData.id, - endUserId: endUserId ?? null, - expiresAt: nowPlus30Days, - }, - transaction, - ); - - const collectionFlow = buildCollectionFlowState({ - apiUrl: env.APP_API_URL, - steps: uiDefinition?.definition - ? getOrderedSteps( - (uiDefinition?.definition as Prisma.JsonObject)?.definition as Record< - string, - Record - >, - { finalStates: [...WORKFLOW_FINAL_STATES] }, - ).map(stepName => ({ - stateName: stepName, - })) - : [], - additionalInformation: { - customerCompany: customer.displayName, - }, - }); - - workflowRuntimeData = await this.workflowRuntimeDataRepository.updateStateById( - workflowRuntimeData.id, - { - data: { - context: { - ...workflowRuntimeData.context, - collectionFlow, - metadata: { - ...(workflowRuntimeData.context.metadata ?? {}), - token: workflowToken.token, - collectionFlowUrl: env.COLLECTION_FLOW_URL, - webUiSDKUrl: env.WEB_UI_SDK_URL, - }, - } as InputJsonValue, - projectId: currentProjectId, - }, - }, - transaction, - ); - } - if (mergedConfig?.initialEvent) { workflowRuntimeData = await this.event( { @@ -1680,7 +1574,6 @@ export class WorkflowService { workflowDefinition, workflowRuntimeData, ballerineEntityId: entityId, - entities, }, ] as const; }); diff --git a/services/workflows-service/src/workflow/workflow.service.unit.test.ts b/services/workflows-service/src/workflow/workflow.service.unit.test.ts index 17b19e3914..ac70009bb4 100644 --- a/services/workflows-service/src/workflow/workflow.service.unit.test.ts +++ b/services/workflows-service/src/workflow/workflow.service.unit.test.ts @@ -102,7 +102,6 @@ describe('WorkflowService', () => { let projectScopeService; let businessRepo; let businessService; - let businessReportService; let customerService; let endUserRepo; let entityRepo; @@ -135,7 +134,6 @@ describe('WorkflowService', () => { workflowRuntimeDataRepo = new FakeWorkflowRuntimeDataRepo(); businessRepo = new FakeBusinessRepo(); businessService = new FakeBusinessRepo(); - businessReportService = new FakeBusinessRepo(); endUserRepo = new FakeEndUserRepo(); entityRepo = new FakeEntityRepo(); customerService = new FakeCustomerRepo(); @@ -188,7 +186,6 @@ describe('WorkflowService', () => { workflowDefinitionRepo as any, workflowRuntimeDataRepo, endUserRepo, - businessReportService, {} as any, businessRepo, businessService,