diff --git a/src/space-model/dtos/subspaces-model-dtos/update-subspace-model.dto.ts b/src/space-model/dtos/subspaces-model-dtos/update-subspace-model.dto.ts index eb5305c..93ca12b 100644 --- a/src/space-model/dtos/subspaces-model-dtos/update-subspace-model.dto.ts +++ b/src/space-model/dtos/subspaces-model-dtos/update-subspace-model.dto.ts @@ -7,7 +7,7 @@ import { IsOptional, ValidateNested, } from 'class-validator'; -import { CreateProductModelDto } from '../product-model-dtos'; +import { ProductModelModificationDto } from '../product-model-dtos'; export class UpdateSubspaceModelDto { @ApiProperty({ @@ -23,12 +23,11 @@ export class UpdateSubspaceModelDto { subspaceUuid: string; @ApiProperty({ - description: 'List of products included in the model', - type: [CreateProductModelDto], + description: 'Products models modified in the model', + type: ProductModelModificationDto, }) - @IsArray() @IsOptional() @ValidateNested({ each: true }) - @Type(() => CreateProductModelDto) - spaceProductModels?: CreateProductModelDto[]; + @Type(() => ProductModelModificationDto) + updatedProductModels?: ProductModelModificationDto; } diff --git a/src/space-model/interfaces/update-subspace.interface.ts b/src/space-model/interfaces/update-subspace.interface.ts index 7433c2d..5898d34 100644 --- a/src/space-model/interfaces/update-subspace.interface.ts +++ b/src/space-model/interfaces/update-subspace.interface.ts @@ -30,12 +30,20 @@ export interface IModifiedProductItemsModelsInterface { export interface IUpdateSubspaceModelInterface { subspaceName?: string; uuid: string; + productModels?: IModifiedProductItemsModelsInterface[]; } export interface IDeletedSubsaceModelInterface { uuid: string; } +export interface IUpdatedProductModelInterface { + productModelUuid: string; + productModifiedItemModel: IModifiedProductItemsModelsInterface; +} + export interface IModifiedProductModelsInterface { add?: ProductModelInterface[]; + update?: IUpdatedProductModelInterface[]; + delete?: string[]; } diff --git a/src/space-model/services/subspace/subspace-model.service.ts b/src/space-model/services/subspace/subspace-model.service.ts index 305323d..caefce2 100644 --- a/src/space-model/services/subspace/subspace-model.service.ts +++ b/src/space-model/services/subspace/subspace-model.service.ts @@ -72,62 +72,126 @@ export class SubSpaceModelService { async updateSubspaceModels( updateDtos: UpdateSubspaceModelDto[], + spaceModel: SpaceModelEntity, queryRunner: QueryRunner, - ) { - const updateResults: IUpdateSubspaceModelInterface[] = []; + ): Promise { try { - for (const dto of updateDtos) { - const subspaceModel = await this.findOne(dto.subspaceUuid); - const updateResult: IUpdateSubspaceModelInterface = { - uuid: dto.subspaceUuid, - }; + const updateResults: IUpdateSubspaceModelInterface[] = []; - if (dto.subspaceName) { - subspaceModel.subspaceName = dto.subspaceName; - await queryRunner.manager.update( - this.subspaceModelRepository.target, - { uuid: dto.subspaceUuid }, - { subspaceName: dto.subspaceName }, + const updatePromises = updateDtos.map(async (dto) => { + try { + const subspaceModel = await this.findOne(dto.subspaceUuid); + + if (!subspaceModel) { + throw new HttpException( + `Subspace model with UUID ${dto.subspaceUuid} not found.`, + HttpStatus.NOT_FOUND, + ); + } + + const updateResult: IUpdateSubspaceModelInterface = { + uuid: dto.subspaceUuid, + }; + + if (dto.subspaceName) { + await this.updateSubspaceName( + dto.subspaceUuid, + dto.subspaceName, + queryRunner, + ); + subspaceModel.subspaceName = dto.subspaceName; + updateResult.subspaceName = dto.subspaceName; + } + + if (dto.updatedProductModels) { + await this.subSpaceProducetModelService.modifySubspaceProductModels( + dto.updatedProductModels, + spaceModel, + subspaceModel, + queryRunner, + ); + } + + updateResults.push(updateResult); + } catch (error) { + throw new HttpException( + `Failed to update subspace model with UUID ${dto.subspaceUuid}: ${error.message}`, + HttpStatus.INTERNAL_SERVER_ERROR, ); - updateResult.subspaceName = dto.subspaceName; } + }); - updateResults.push(updateResult); - } + await Promise.all(updatePromises); return updateResults; } catch (error) { - if (error instanceof HttpException) { - throw error; - } throw new HttpException( - error.message || 'Failed to update SpaceModels', + error.message || 'Failed to update subspace models.', HttpStatus.INTERNAL_SERVER_ERROR, ); } } - async deleteSubspaceModels( - dtos: DeleteSubspaceModelDto[], + private async updateSubspaceName( + uuid: string, + subspaceName: string, queryRunner: QueryRunner, - ) { - const deleteResults: IDeletedSubsaceModelInterface[] = []; + ): Promise { + await queryRunner.manager.update( + this.subspaceModelRepository.target, + { uuid }, + { subspaceName }, + ); + } + + async deleteSubspaceModels( + deleteDtos: DeleteSubspaceModelDto[], + queryRunner: QueryRunner, + ): Promise { try { - for (const dto of dtos) { - await this.findOne(dto.subspaceUuid); + const deleteResults: IDeletedSubsaceModelInterface[] = []; - await queryRunner.manager.update( - this.subspaceModelRepository.target, - { uuid: dto.subspaceUuid }, - { disabled: true }, - ); + const deletePromises = deleteDtos.map(async (dto) => { + try { + const subspaceModel = await this.findOne(dto.subspaceUuid); + + if (!subspaceModel) { + throw new HttpException( + `Subspace model with UUID ${dto.subspaceUuid} not found.`, + HttpStatus.NOT_FOUND, + ); + } + + await queryRunner.manager.update( + this.subspaceModelRepository.target, + { uuid: dto.subspaceUuid }, + { disabled: true }, + ); + + if (subspaceModel.productModels.length > 0) { + await this.subSpaceProducetModelService.disableProductModels( + subspaceModel.productModels, + queryRunner, + ); + } + + deleteResults.push({ uuid: dto.subspaceUuid }); + } catch (error) { + throw new HttpException( + `Failed to delete subspace model with UUID ${dto.subspaceUuid}: ${error.message}`, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + }); + + await Promise.all(deletePromises); - deleteResults.push({ uuid: dto.subspaceUuid }); - } return deleteResults; } catch (error) { - console.error(`Bulk delete operation failed: ${error.message}`); - throw new Error('Bulk delete operation failed.'); + throw new HttpException( + 'Bulk delete operation failed. Please try again.', + HttpStatus.INTERNAL_SERVER_ERROR, + ); } } @@ -136,6 +200,7 @@ export class SubSpaceModelService { where: { uuid: subspaceUuid, }, + relations: ['productModels', 'productModels.itemModels'], }); if (!subspace) { throw new HttpException( @@ -181,36 +246,48 @@ export class SubSpaceModelService { dto: ModifySubspacesModelDto, spaceModel: SpaceModelEntity, queryRunner: QueryRunner, - ) { + ): Promise { const subspaces: IModifySubspaceModelInterface = { spaceModelUuid: spaceModel.uuid, }; + try { + const actions = []; + if (dto.add) { - const addedSubspaces = await this.createSubSpaceModels( - dto.add, - spaceModel, - queryRunner, + actions.push( + this.createSubSpaceModels(dto.add, spaceModel, queryRunner).then( + (addedSubspaces) => { + subspaces.new = addedSubspaces; + }, + ), ); - subspaces.new = addedSubspaces; - } else if (dto.update) { - const updatedSubspaces = await this.updateSubspaceModels( - dto.update, - queryRunner, - ); - subspaces.update = updatedSubspaces; - } else if (dto.delete) { - const deletedSubspaces = await this.deleteSubspaceModels( - dto.delete, - queryRunner, - ); - subspaces.delete = deletedSubspaces; } + + if (dto.update) { + actions.push( + this.updateSubspaceModels(dto.update, spaceModel, queryRunner).then( + (updatedSubspaces) => { + subspaces.update = updatedSubspaces; + }, + ), + ); + } + + if (dto.delete) { + actions.push( + this.deleteSubspaceModels(dto.delete, queryRunner).then( + (deletedSubspaces) => { + subspaces.delete = deletedSubspaces; + }, + ), + ); + } + + await Promise.all(actions); + return subspaces; } catch (error) { - if (error instanceof HttpException) { - throw error; - } throw new HttpException( error.message || 'Failed to modify SpaceModels', HttpStatus.INTERNAL_SERVER_ERROR, diff --git a/src/space-model/services/subspace/subspace-product-item-model.service.ts b/src/space-model/services/subspace/subspace-product-item-model.service.ts index 27fc2b9..592e45c 100644 --- a/src/space-model/services/subspace/subspace-product-item-model.service.ts +++ b/src/space-model/services/subspace/subspace-product-item-model.service.ts @@ -92,6 +92,7 @@ export class SubspaceProductItemModelService extends BaseProductItemService { queryRunner: QueryRunner, ): Promise { try { + if (dtos.length === 0) return; const productItemModels = await Promise.all( dtos.map(async (dto) => { const productItemModel = await this.findOne(dto.productModelUuid); @@ -100,18 +101,29 @@ export class SubspaceProductItemModelService extends BaseProductItemService { }), ); - const response = (await this.saveProductItems( + const disabledItemModels = await this.disableProductItemModels( productItemModels, - this.subspaceProductItemRepository, queryRunner, - )) as SubspaceProductItemModelEntity[]; + ); - return response.map((item) => item.uuid); + return disabledItemModels.map((item) => item.uuid); } catch (error) { - this.handleException(error, 'Failed to modify SpaceModels.'); + this.handleException(error, 'Failed to delete SpaceModels.'); } } + async disableProductItemModels( + productItemModels: SubspaceProductItemModelEntity[], + queryRunner: QueryRunner, + ): Promise { + productItemModels.forEach((model) => (model.disabled = true)); + return (await this.saveProductItems( + productItemModels, + this.subspaceProductItemRepository, + queryRunner, + )) as SubspaceProductItemModelEntity[]; + } + async findOne(uuid: string): Promise { const productItemModel = await this.subspaceProductItemRepository.findOne({ where: { uuid }, diff --git a/src/space-model/services/subspace/subspace-product-model.service.ts b/src/space-model/services/subspace/subspace-product-model.service.ts index 8b9d05f..724234d 100644 --- a/src/space-model/services/subspace/subspace-product-model.service.ts +++ b/src/space-model/services/subspace/subspace-product-model.service.ts @@ -4,12 +4,13 @@ import { SubspaceProductModelEntity, SubspaceProductModelRepository, } from '@app/common/modules/space-model'; -import { QueryRunner } from 'typeorm'; +import { In, QueryRunner } from 'typeorm'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { SubspaceProductItemModelService } from './subspace-product-item-model.service'; import { CreateProductModelDto, + DeleteProductModelDto, ProductModelModificationDto, UpdateProductModelDto, } from '../../dtos'; @@ -17,6 +18,7 @@ import { BaseProductModelService } from '../../common'; import { ProductService } from 'src/product/services'; import { IModifiedProductModelsInterface, + IUpdatedProductModelInterface, ProductModelInterface, } from '../../interfaces'; @@ -83,34 +85,138 @@ export class SubspaceProductModelService extends BaseProductModelService { } } - async updateSubspaceProductModels(dtos: UpdateProductModelDto[]) { - try { - for (const dto of dtos) { - await this.findOne(dto.productModelUuid); - } - } catch (error) {} - } - - async modifySubspaceProductModels( - dto: ProductModelModificationDto, + async updateSubspaceProductModels( + dtos: UpdateProductModelDto[], spaceModel: SpaceModelEntity, - subspaceModel: SubspaceModelEntity, queryRunner: QueryRunner, - ) { - const productItemModels: IModifiedProductModelsInterface = {}; + ): Promise { try { - productItemModels.add = await this.createSubspaceProductModels( - dto.add, - spaceModel, - subspaceModel, - queryRunner, + const updatedProductModels = await Promise.all( + dtos.map(async (dto) => { + const productModel = await this.findOne(dto.productModelUuid); + const productModifiedItemModel = + await this.subspaceProductItemModelService.modifyProductItemModel( + dto.items, + productModel, + spaceModel, + queryRunner, + ); + return { + productModelUuid: productModel.uuid, + productModifiedItemModel, + }; + }), ); + + return updatedProductModels; } catch (error) { if (error instanceof HttpException) { throw error; } throw new HttpException( - 'Failed to modify Subspace product model', + 'Failed to update Subspace product model', + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + + async removeSubspaceProductModels( + deleteDtos: DeleteProductModelDto[], + transactionRunner: QueryRunner, + ): Promise { + try { + const productModels = await Promise.all( + deleteDtos.map((dto) => this.findOne(dto.productModelUuid)), + ); + + return await this.disableProductModels(productModels, transactionRunner); + } catch (error) { + throw new HttpException( + 'Failed to remove subspace product models', + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + + async disableProductModels( + productModels: SubspaceProductModelEntity[], + transactionRunner: QueryRunner, + ): Promise { + try { + const productModelUuids = productModels.map((model) => model.uuid); + + await transactionRunner.manager.update( + this.subpaceProductModelRepository.target, + { uuid: In(productModelUuids) }, + { disabled: true }, + ); + + const itemModelDisables = productModels.map((model) => + model.itemModels.length > 0 + ? this.subspaceProductItemModelService.disableProductItemModels( + model.itemModels, + transactionRunner, + ) + : Promise.resolve(), + ); + + await Promise.all(itemModelDisables); + + return productModelUuids; + } catch (error) { + throw new HttpException( + 'Failed to disable product models', + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + + async modifySubspaceProductModels( + modificationDto: ProductModelModificationDto, + spaceEntity: SpaceModelEntity, + subspaceEntity: SubspaceModelEntity, + transactionRunner: QueryRunner, + ): Promise { + const modifiedProductModels: IModifiedProductModelsInterface = {}; + + try { + await Promise.all([ + modificationDto.add + ? this.createSubspaceProductModels( + modificationDto.add, + spaceEntity, + subspaceEntity, + transactionRunner, + ).then((addedModels) => { + modifiedProductModels.add = addedModels; + }) + : Promise.resolve(), + modificationDto.update + ? this.updateSubspaceProductModels( + modificationDto.update, + spaceEntity, + transactionRunner, + ).then((updatedModels) => { + modifiedProductModels.update = updatedModels; + }) + : Promise.resolve(), + modificationDto.delete + ? this.removeSubspaceProductModels( + modificationDto.delete, + transactionRunner, + ).then((deletedModels) => { + modifiedProductModels.delete = deletedModels; + }) + : Promise.resolve(), + ]); + + return modifiedProductModels; + } catch (error) { + if (error instanceof HttpException) { + throw error; + } + throw new HttpException( + 'Failed to modify subspace product models', HttpStatus.INTERNAL_SERVER_ERROR, ); } @@ -121,6 +227,7 @@ export class SubspaceProductModelService extends BaseProductModelService { where: { uuid, }, + relations: ['itemModels'], }); if (!productModel) throw new HttpException(