diff --git a/src/space-model/commands/index.ts b/src/space-model/commands/index.ts new file mode 100644 index 0000000..716d458 --- /dev/null +++ b/src/space-model/commands/index.ts @@ -0,0 +1 @@ +export * from './propogate-subspace-update-command'; diff --git a/src/space-model/commands/propogate-subspace-update-command.ts b/src/space-model/commands/propogate-subspace-update-command.ts new file mode 100644 index 0000000..286b9bd --- /dev/null +++ b/src/space-model/commands/propogate-subspace-update-command.ts @@ -0,0 +1,6 @@ +import { ICommand } from '@nestjs/cqrs'; +import { UpdatedSubspaceModelInterface } from '../interfaces'; + +export class PropogateSubspaceCommand implements ICommand { + constructor(public readonly param: UpdatedSubspaceModelInterface) {} +} diff --git a/src/space-model/dtos/index.ts b/src/space-model/dtos/index.ts index cc4e0df..e7b2373 100644 --- a/src/space-model/dtos/index.ts +++ b/src/space-model/dtos/index.ts @@ -5,3 +5,4 @@ export * from './create-subspace-model.dto'; export * from './project-param.dto'; export * from './update-space-model.dto'; export * from './space-model-param'; +export * from './update-subspace-model.dto'; diff --git a/src/space-model/dtos/update-space-model.dto.ts b/src/space-model/dtos/update-space-model.dto.ts index 09b196d..daaa62b 100644 --- a/src/space-model/dtos/update-space-model.dto.ts +++ b/src/space-model/dtos/update-space-model.dto.ts @@ -2,8 +2,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsArray, IsOptional, IsString, ValidateNested } from 'class-validator'; import { CreateSubspaceModelDto } from './create-subspace-model.dto'; import { Type } from 'class-transformer'; +import { UpdateSubspaceModelDto } from './update-subspace-model.dto'; -export class UpdateSubspaceModelDto { +export class UpdateSubspacesModelDto { @ApiProperty({ description: 'List of subspaces to add', type: [CreateSubspaceModelDto], @@ -14,7 +15,19 @@ export class UpdateSubspaceModelDto { @ValidateNested({ each: true }) @Type(() => CreateSubspaceModelDto) add?: CreateSubspaceModelDto[]; + + @ApiProperty({ + description: 'List of subspaces to add', + type: [CreateSubspaceModelDto], + required: false, + }) + @IsOptional() + @IsArray() + @ValidateNested({ each: true }) + @Type(() => UpdateSubspaceModelDto) + update?: UpdateSubspaceModelDto[]; } + export class UpdateSpaceModelDto { @ApiProperty({ description: 'Updated name of the space model', @@ -25,5 +38,5 @@ export class UpdateSpaceModelDto { modelName?: string; @IsOptional() - subspaceModels?: UpdateSubspaceModelDto; + subspaceModels?: UpdateSubspacesModelDto; } diff --git a/src/space-model/dtos/update-subspace-model.dto.ts b/src/space-model/dtos/update-subspace-model.dto.ts new file mode 100644 index 0000000..da71afc --- /dev/null +++ b/src/space-model/dtos/update-subspace-model.dto.ts @@ -0,0 +1,30 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { + IsNotEmpty, + IsString, + IsArray, + IsOptional, + ValidateNested, +} from 'class-validator'; +import { CreateSpaceProductModelDto } from './create-space-product-model.dto'; + +export class UpdateSubspaceModelDto { + @ApiProperty({ + description: 'Name of the subspace', + example: 'Living Room', + }) + @IsNotEmpty() + @IsString() + subspaceName?: string; + + @ApiProperty({ + description: 'List of products included in the model', + type: [CreateSpaceProductModelDto], + }) + @IsArray() + @IsOptional() + @ValidateNested({ each: true }) + @Type(() => CreateSpaceProductModelDto) + spaceProductModels?: CreateSpaceProductModelDto[]; +} diff --git a/src/space-model/handlers/index.ts b/src/space-model/handlers/index.ts new file mode 100644 index 0000000..7dfa7f5 --- /dev/null +++ b/src/space-model/handlers/index.ts @@ -0,0 +1 @@ +export * from './propate-subspace-handler'; diff --git a/src/space-model/handlers/propate-subspace-handler.ts b/src/space-model/handlers/propate-subspace-handler.ts new file mode 100644 index 0000000..e7a4db7 --- /dev/null +++ b/src/space-model/handlers/propate-subspace-handler.ts @@ -0,0 +1,177 @@ +import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; +import { PropogateSubspaceCommand } from '../commands'; +import { Logger } from '@nestjs/common'; +import { SpaceEntity, SpaceRepository } from '@app/common/modules/space'; +import { + SubspaceProductItemRepository, + SubspaceProductRepository, + SubspaceRepository, +} from '@app/common/modules/space/repositories/subspace.repository'; + +@CommandHandler(PropogateSubspaceCommand) +export class PropogateSubspaceHandler + implements ICommandHandler +{ + private readonly logger = new Logger(PropogateSubspaceHandler.name); + + constructor( + private readonly spaceRepository: SpaceRepository, + private readonly subspaceRepository: SubspaceRepository, + private readonly productRepository: SubspaceProductRepository, + private readonly productItemRepository: SubspaceProductItemRepository, + ) {} + + async execute(command: PropogateSubspaceCommand): Promise { + try { + const newSubspaceModels = command.param?.new; + + if (!newSubspaceModels || newSubspaceModels.length === 0) { + this.logger.warn('No new subspace models provided.'); + return; + } + + const spaceModelUuid = + newSubspaceModels[0]?.subspaceModel?.spaceModel?.uuid; + + if (!spaceModelUuid) { + this.logger.error( + 'Space model UUID is missing in the command parameters.', + ); + return; + } + + const spaces = await this.getSpacesByModel(spaceModelUuid); + + if (spaces.length === 0) { + this.logger.warn(`No spaces found for model UUID: ${spaceModelUuid}`); + return; + } + + await this.processSubspaces(newSubspaceModels, spaces); + } catch (error) { + this.logger.error( + 'Error in PropogateSubspaceHandler execution', + error.stack, + ); + } + } + + private async processSubspaces( + newSubspaceModels: any[], + spaces: SpaceEntity[], + ) { + for (const newSubspaceModel of newSubspaceModels) { + for (const space of spaces) { + try { + const subspace = await this.createSubspace(newSubspaceModel, space); + + if (newSubspaceModel.productModels?.length > 0) { + await this.processProducts( + newSubspaceModel.productModels, + subspace, + ); + } + } catch (error) { + this.logger.error( + `Failed to create subspace for space ID: ${space.uuid}`, + error.stack, + ); + } + } + } + } + + private async createSubspace(newSubspaceModel: any, space: SpaceEntity) { + const subspace = this.subspaceRepository.create({ + subspaceName: newSubspaceModel.subspaceModel.subspaceName, + space, + subSpaceModel: newSubspaceModel.subspaceModel, + }); + + const createdSubspace = await this.subspaceRepository.save(subspace); + this.logger.log( + `Subspace created for space ${space.uuid} with name ${createdSubspace.subspaceName}`, + ); + return createdSubspace; + } + + private async processProducts(productModels: any[], subspace: any) { + for (const productModel of productModels) { + try { + const subspaceProduct = await this.createSubspaceProduct( + productModel, + subspace, + ); + + if (productModel.productItemModels?.length > 0) { + await this.processProductItems( + productModel.productItemModels, + subspaceProduct, + ); + } + } catch (error) { + this.logger.error( + `Failed to create product for subspace ID: ${subspace.id}`, + error.stack, + ); + } + } + } + + private async createSubspaceProduct(productModel: any, subspace: any) { + const subspaceProduct = this.productRepository.create({ + product: productModel.productModel.product, + subspace, + productCount: productModel.productModel.productCount, + model: productModel.productModel, + }); + + const createdSubspaceProduct = + await this.productRepository.save(subspaceProduct); + this.logger.log( + `Product added to subspace ${subspace.id} with count ${createdSubspaceProduct.productCount}`, + ); + return createdSubspaceProduct; + } + + private async processProductItems( + productItemModels: any[], + subspaceProduct: any, + ) { + for (const productItemModel of productItemModels) { + try { + const subspaceProductItem = this.productItemRepository.create({ + tag: productItemModel.tag, + subspaceProduct, + model: productItemModel, + }); + + await this.productItemRepository.save(subspaceProductItem); + this.logger.log( + `Product item added to subspace product ${subspaceProduct.id} with tag ${subspaceProductItem.tag}`, + ); + } catch (error) { + this.logger.error( + `Failed to create product item for subspace product ID: ${subspaceProduct.id}`, + error.stack, + ); + } + } + } + + private async getSpacesByModel(uuid: string): Promise { + try { + return await this.spaceRepository.find({ + where: { + spaceModel: { uuid }, + }, + }); + } catch (error) { + this.logger.error( + `Failed to fetch spaces for model UUID: ${uuid}`, + error.stack, + ); + throw error; + } + } +} diff --git a/src/space-model/interfaces/index.ts b/src/space-model/interfaces/index.ts new file mode 100644 index 0000000..606eb46 --- /dev/null +++ b/src/space-model/interfaces/index.ts @@ -0,0 +1 @@ +export * from './update-subspace.interface' \ No newline at end of file diff --git a/src/space-model/interfaces/update-subspace.interface.ts b/src/space-model/interfaces/update-subspace.interface.ts new file mode 100644 index 0000000..4ccc588 --- /dev/null +++ b/src/space-model/interfaces/update-subspace.interface.ts @@ -0,0 +1,19 @@ +import { + SubspaceModelEntity, + SubspaceProductItemModelEntity, + SubspaceProductModelEntity, +} from '@app/common/modules/space-model'; + +export interface AddSubspaceModelInterface { + subspaceModel: SubspaceModelEntity; + productModels: ProductModelInterface[]; +} + +export interface ProductModelInterface { + productModel: SubspaceProductModelEntity; + productItemModels: SubspaceProductItemModelEntity[]; +} + +export interface UpdatedSubspaceModelInterface { + new?: AddSubspaceModelInterface[]; +} diff --git a/src/space-model/services/space-model.service.ts b/src/space-model/services/space-model.service.ts index 805ffa0..6b0c5db 100644 --- a/src/space-model/services/space-model.service.ts +++ b/src/space-model/services/space-model.service.ts @@ -18,6 +18,9 @@ import { SpaceModelDto } from '@app/common/modules/space-model/dtos'; import { SpaceModelParam } from '../dtos/space-model-param'; import { ProjectService } from 'src/project/services'; import { ProjectEntity } from '@app/common/modules/project/entities'; +import { UpdatedSubspaceModelInterface } from '../interfaces'; +import { CommandBus } from '@nestjs/cqrs'; +import { PropogateSubspaceCommand } from '../commands'; @Injectable() export class SpaceModelService { @@ -27,6 +30,7 @@ export class SpaceModelService { private readonly projectService: ProjectService, private readonly subSpaceModelService: SubSpaceModelService, private readonly spaceProductModelService: SpaceProductModelService, + private commandBus: CommandBus, ) {} async createSpaceModel( @@ -142,21 +146,27 @@ export class SpaceModelService { await queryRunner.startTransaction(); try { const { modelName } = dto; + let updatedSubspaces: UpdatedSubspaceModelInterface; if (modelName) spaceModel.modelName = modelName; await queryRunner.manager.save(spaceModel); if (dto.subspaceModels) { - const updatedSubspaces = - await this.subSpaceModelService.updateSubSpaceModels( - dto.subspaceModels, - spaceModel, - queryRunner, - ); + updatedSubspaces = await this.subSpaceModelService.modifySubSpaceModels( + dto.subspaceModels, + spaceModel, + queryRunner, + ); } await queryRunner.commitTransaction(); + if (updatedSubspaces) { + await this.commandBus.execute( + new PropogateSubspaceCommand(updatedSubspaces), + ); + } + return new SuccessResponseDto({ message: 'SpaceModel updated successfully', data: spaceModel, diff --git a/src/space-model/services/subspace/subspace-model.service.ts b/src/space-model/services/subspace/subspace-model.service.ts index 6814362..d49ff83 100644 --- a/src/space-model/services/subspace/subspace-model.service.ts +++ b/src/space-model/services/subspace/subspace-model.service.ts @@ -3,9 +3,10 @@ import { SubspaceModelRepository, } from '@app/common/modules/space-model'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { CreateSubspaceModelDto, UpdateSubspaceModelDto } from '../../dtos'; +import { CreateSubspaceModelDto, UpdateSubspacesModelDto } from '../../dtos'; import { QueryRunner } from 'typeorm'; import { SubspaceProductModelService } from './subspace-product-model.service'; +import { UpdatedSubspaceModelInterface } from 'src/space-model/interfaces'; @Injectable() export class SubSpaceModelService { @@ -91,12 +92,12 @@ export class SubSpaceModelService { } } - async updateSubSpaceModels( - dto: UpdateSubspaceModelDto, + async modifySubSpaceModels( + dto: UpdateSubspacesModelDto, spaceModel: SpaceModelEntity, queryRunner: QueryRunner, ) { - const subspaces: { new?: any } = {}; + const subspaces: UpdatedSubspaceModelInterface = {}; try { if (dto.add) { const addedSubspaces = await this.createSubSpaceModels( @@ -105,6 +106,8 @@ export class SubSpaceModelService { queryRunner, ); subspaces.new = addedSubspaces; + } else if (dto.update) { + } return subspaces; } catch (error) { diff --git a/src/space-model/space-model.module.ts b/src/space-model/space-model.module.ts index ae275e2..e1e4b56 100644 --- a/src/space-model/space-model.module.ts +++ b/src/space-model/space-model.module.ts @@ -20,13 +20,25 @@ import { import { ProjectRepository } from '@app/common/modules/project/repositiories'; import { ProductRepository } from '@app/common/modules/product/repositories'; import { SubspaceProductModelService } from './services/subspace/subspace-product-model.service'; +import { PropogateSubspaceHandler } from './handlers'; +import { CqrsModule } from '@nestjs/cqrs'; +import { SpaceRepository } from '@app/common/modules/space'; +import { + SubspaceProductItemRepository, + SubspaceProductRepository, + SubspaceRepository, +} from '@app/common/modules/space/repositories/subspace.repository'; + +const CommandHandlers = [PropogateSubspaceHandler]; @Module({ - imports: [ConfigModule, SpaceRepositoryModule], + imports: [ConfigModule, SpaceRepositoryModule, CqrsModule], controllers: [SpaceModelController], providers: [ + ...CommandHandlers, SpaceModelService, SpaceModelRepository, + SpaceRepository, ProjectRepository, SubSpaceModelService, SpaceProductModelService, @@ -39,7 +51,10 @@ import { SubspaceProductModelService } from './services/subspace/subspace-produc SubspaceProductItemModelRepository, SubspaceProductModelService, SubspaceProductModelRepository, + SubspaceRepository, + SubspaceProductRepository, + SubspaceProductItemRepository, ], - exports: [], + exports: [CqrsModule], }) export class SpaceModelModule {}