mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-11-26 13:34:55 +00:00
subspace model also has product model and item
This commit is contained in:
@ -1,10 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { ProductService } from './services';
|
||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||
import { ProductController } from './controllers';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
controllers: [ProductController],
|
||||
providers: [ProductService, ProductRepository],
|
||||
exports: [ProductService],
|
||||
})
|
||||
export class ProductModule {}
|
||||
|
||||
@ -21,4 +21,23 @@ export class ProductService {
|
||||
message: 'List of products retrieved successfully',
|
||||
});
|
||||
}
|
||||
|
||||
async findOne(productUuid: string): Promise<BaseResponseDto> {
|
||||
const product = await this.productRepository.findOne({
|
||||
where: {
|
||||
uuid: productUuid,
|
||||
},
|
||||
});
|
||||
if (!product) {
|
||||
throw new HttpException(
|
||||
`No product with ${productUuid} found in the system`,
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return new SuccessResponseDto({
|
||||
data: product,
|
||||
message: 'Succefully retrieved product',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
1
src/space-model/common/index.ts
Normal file
1
src/space-model/common/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './services';
|
||||
@ -0,0 +1,60 @@
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { QueryRunner } from 'typeorm';
|
||||
import { SpaceModelEntity } from '@app/common/modules/space-model';
|
||||
import { CreateProductItemModelDto } from 'src/space-model/dtos';
|
||||
|
||||
export abstract class BaseProductItemService {
|
||||
async validateTags(
|
||||
itemModelDtos: CreateProductItemModelDto[],
|
||||
queryRunner: QueryRunner,
|
||||
spaceModel: SpaceModelEntity,
|
||||
): Promise<void> {
|
||||
const incomingTags = new Set(
|
||||
itemModelDtos.map((item) => item.tag).filter(Boolean),
|
||||
);
|
||||
|
||||
const duplicateTags = itemModelDtos
|
||||
.map((item) => item.tag)
|
||||
.filter((tag, index, array) => array.indexOf(tag) !== index);
|
||||
|
||||
if (duplicateTags.length > 0) {
|
||||
throw new HttpException(
|
||||
`Duplicate tags found in the request: ${[...new Set(duplicateTags)].join(', ')}`,
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
|
||||
const existingTagsQuery = `
|
||||
SELECT DISTINCT tag
|
||||
FROM (
|
||||
SELECT spi.tag
|
||||
FROM "subspace-product-item-model" spi
|
||||
INNER JOIN "subspace-product-model" spm ON spi.subspace_product_model_uuid = spm.uuid
|
||||
INNER JOIN "subspace-model" sm ON spm.subspace_model_uuid = sm.uuid
|
||||
WHERE sm.space_model_uuid = $1
|
||||
UNION
|
||||
SELECT spi.tag
|
||||
FROM "space-product-item-model" spi
|
||||
INNER JOIN "space-product-model" spm ON spi.space_product_model_uuid = spm.uuid
|
||||
WHERE spm.space_model_uuid = $1
|
||||
) AS combined_tags;
|
||||
`;
|
||||
|
||||
const existingTags = await queryRunner.manager.query(existingTagsQuery, [
|
||||
spaceModel.uuid,
|
||||
]);
|
||||
const existingTagsSet = new Set(
|
||||
existingTags.map((row: { tag: string }) => row.tag),
|
||||
);
|
||||
|
||||
const conflictingTags = [...incomingTags].filter((tag) =>
|
||||
existingTagsSet.has(tag),
|
||||
);
|
||||
if (conflictingTags.length > 0) {
|
||||
throw new HttpException(
|
||||
`Tags already exist in the model: ${conflictingTags.join(', ')}`,
|
||||
HttpStatus.CONFLICT,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { CreateSpaceProductModelDto } from 'src/space-model/dtos';
|
||||
import { ProductService } from '../../../product/services';
|
||||
|
||||
export abstract class BaseProductModelService {
|
||||
constructor(private readonly productService: ProductService) {}
|
||||
|
||||
protected async validateProductCount(
|
||||
dto: CreateSpaceProductModelDto,
|
||||
): Promise<void> {
|
||||
const productItemCount = dto.items.length;
|
||||
if (dto.productCount !== productItemCount) {
|
||||
throw new HttpException(
|
||||
`Product count (${dto.productCount}) does not match the number of items (${productItemCount}) for product ID ${dto.productUuid}.`,
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected async getProduct(productId: string) {
|
||||
const product = await this.productService.findOne(productId);
|
||||
return product.data;
|
||||
}
|
||||
}
|
||||
2
src/space-model/common/services/index.ts
Normal file
2
src/space-model/common/services/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './base-product-item-model.service';
|
||||
export * from './base-product-model.service';
|
||||
@ -1,5 +1,13 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
import {
|
||||
IsArray,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import { CreateSpaceProductModelDto } from './create-space-product-model.dto';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
export class CreateSubspaceModelDto {
|
||||
@ApiProperty({
|
||||
@ -9,4 +17,14 @@ export class CreateSubspaceModelDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
subspaceName: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'List of products included in the model',
|
||||
type: [CreateSpaceProductModelDto],
|
||||
})
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateSpaceProductModelDto)
|
||||
spaceProductModels?: CreateSpaceProductModelDto[];
|
||||
}
|
||||
|
||||
@ -2,3 +2,5 @@ export * from './space-model.service';
|
||||
export * from './space-product-item-model.service';
|
||||
export * from './space-product-model.service';
|
||||
export * from './subspace-model.service';
|
||||
export * from './subspace-product-item-model.service';
|
||||
export * from './space-product-model.service';
|
||||
|
||||
@ -6,12 +6,15 @@ import {
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { CreateProductItemModelDto } from '../dtos';
|
||||
import { QueryRunner } from 'typeorm';
|
||||
import { BaseProductItemService } from '../common';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceProductItemModelService {
|
||||
export class SpaceProductItemModelService extends BaseProductItemService {
|
||||
constructor(
|
||||
private readonly spaceProductItemRepository: SpaceProductItemModelRepository,
|
||||
) {}
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async createProdutItemModel(
|
||||
itemModelDtos: CreateProductItemModelDto[],
|
||||
@ -41,41 +44,4 @@ export class SpaceProductItemModelService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async validateTags(
|
||||
itemModelDtos: CreateProductItemModelDto[],
|
||||
queryRunner: QueryRunner,
|
||||
spaceModel: SpaceModelEntity,
|
||||
) {
|
||||
const incomingTags = itemModelDtos.map((item) => item.tag);
|
||||
|
||||
const duplicateTags = incomingTags.filter(
|
||||
(tag, index) => incomingTags.indexOf(tag) !== index,
|
||||
);
|
||||
if (duplicateTags.length > 0) {
|
||||
throw new HttpException(
|
||||
`Duplicate tags found in the request: ${[...new Set(duplicateTags)].join(', ')}`,
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
|
||||
const existingTags = await queryRunner.manager.find(
|
||||
this.spaceProductItemRepository.target,
|
||||
{
|
||||
where: { spaceProductModel: { spaceModel } },
|
||||
select: ['tag'],
|
||||
},
|
||||
);
|
||||
const existingTagSet = new Set(existingTags.map((item) => item.tag));
|
||||
|
||||
const conflictingTags = incomingTags.filter((tag) =>
|
||||
existingTagSet.has(tag),
|
||||
);
|
||||
if (conflictingTags.length > 0) {
|
||||
throw new HttpException(
|
||||
`Tags already exist in the model: ${conflictingTags.join(', ')}`,
|
||||
HttpStatus.CONFLICT,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,17 +4,20 @@ import {
|
||||
} from '@app/common/modules/space-model';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { CreateSpaceProductModelDto } from '../dtos';
|
||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||
import { SpaceProductItemModelService } from './space-product-item-model.service';
|
||||
import { QueryRunner } from 'typeorm';
|
||||
import { BaseProductModelService } from '../common';
|
||||
import { ProductService } from 'src/product/services';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceProductModelService {
|
||||
export class SpaceProductModelService extends BaseProductModelService {
|
||||
constructor(
|
||||
private readonly spaceProductModelRepository: SpaceProductModelRepository,
|
||||
private readonly productRepository: ProductRepository,
|
||||
private readonly spaceProductItemModelService: SpaceProductItemModelService,
|
||||
) {}
|
||||
productService: ProductService,
|
||||
) {
|
||||
super(productService);
|
||||
}
|
||||
|
||||
async createSpaceProductModels(
|
||||
spaceProductModelDtos: CreateSpaceProductModelDto[],
|
||||
@ -61,25 +64,4 @@ export class SpaceProductModelService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private validateProductCount(dto: CreateSpaceProductModelDto) {
|
||||
const productItemCount = dto.items.length;
|
||||
if (dto.productCount !== productItemCount) {
|
||||
throw new HttpException(
|
||||
`Product count (${dto.productCount}) does not match the number of items (${productItemCount}) for product ID ${dto.productUuid}.`,
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async getProduct(productId: string) {
|
||||
const product = await this.productRepository.findOneBy({ uuid: productId });
|
||||
if (!product) {
|
||||
throw new HttpException(
|
||||
`Product with ID ${productId} not found.`,
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
return product;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,11 +5,13 @@ import {
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { CreateSubspaceModelDto } from '../dtos';
|
||||
import { QueryRunner } from 'typeorm';
|
||||
import { SubspaceProductModelService } from './subspace-product-model.service';
|
||||
|
||||
@Injectable()
|
||||
export class SubSpaceModelService {
|
||||
constructor(
|
||||
private readonly subspaceModelRepository: SubspaceModelRepository,
|
||||
private readonly subSpaceProducetModelService: SubspaceProductModelService,
|
||||
) {}
|
||||
|
||||
async createSubSpaceModels(
|
||||
@ -28,6 +30,18 @@ export class SubSpaceModelService {
|
||||
);
|
||||
|
||||
await queryRunner.manager.save(subspaces);
|
||||
|
||||
await Promise.all(
|
||||
subSpaceModelDtos.map((dto, index) => {
|
||||
const subspaceModel = subspaces[index];
|
||||
return this.subSpaceProducetModelService.createSubspaceProductModels(
|
||||
dto.spaceProductModels,
|
||||
spaceModel,
|
||||
subspaceModel,
|
||||
queryRunner,
|
||||
);
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof HttpException) {
|
||||
throw error;
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { CreateProductItemModelDto } from '../dtos';
|
||||
import { QueryRunner } from 'typeorm';
|
||||
import {
|
||||
SpaceModelEntity,
|
||||
SubspaceProductItemModelRepository,
|
||||
SubspaceProductModelEntity,
|
||||
} from '@app/common/modules/space-model';
|
||||
import { BaseProductItemService } from '../common';
|
||||
|
||||
@Injectable()
|
||||
export class SubspaceProductItemModelService extends BaseProductItemService {
|
||||
constructor(
|
||||
private readonly subspaceProductItemRepository: SubspaceProductItemModelRepository,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async createProdutItemModel(
|
||||
itemModelDtos: CreateProductItemModelDto[],
|
||||
subspaceProductModel: SubspaceProductModelEntity,
|
||||
spaceModel: SpaceModelEntity,
|
||||
queryRunner: QueryRunner,
|
||||
) {
|
||||
if (!subspaceProductModel) {
|
||||
throw new HttpException(
|
||||
'The spaceProductModel parameter is required but was not provided.',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
await this.validateTags(itemModelDtos, queryRunner, spaceModel);
|
||||
try {
|
||||
const productItems = itemModelDtos.map((dto) =>
|
||||
queryRunner.manager.create(this.subspaceProductItemRepository.target, {
|
||||
tag: dto.tag,
|
||||
subspaceProductModel,
|
||||
}),
|
||||
);
|
||||
|
||||
await queryRunner.manager.save(productItems);
|
||||
} catch (error) {
|
||||
if (error instanceof HttpException) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw new HttpException(
|
||||
error.message ||
|
||||
'An unexpected error occurred while creating product items.',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
src/space-model/services/subspace-product-model.service.ts
Normal file
69
src/space-model/services/subspace-product-model.service.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import {
|
||||
SpaceModelEntity,
|
||||
SubspaceModelEntity,
|
||||
SubspaceProductModelRepository,
|
||||
} from '@app/common/modules/space-model';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { SubspaceProductItemModelService } from './subspace-product-item-model.service';
|
||||
import { CreateSpaceProductModelDto } from '../dtos';
|
||||
import { QueryRunner } from 'typeorm';
|
||||
import { BaseProductModelService } from '../common';
|
||||
import { ProductService } from 'src/product/services';
|
||||
|
||||
@Injectable()
|
||||
export class SubspaceProductModelService extends BaseProductModelService {
|
||||
constructor(
|
||||
private readonly subpaceProductModelRepository: SubspaceProductModelRepository,
|
||||
productService: ProductService,
|
||||
private readonly subspaceProductItemModelService: SubspaceProductItemModelService,
|
||||
) {
|
||||
super(productService);
|
||||
}
|
||||
|
||||
async createSubspaceProductModels(
|
||||
spaceProductModelDtos: CreateSpaceProductModelDto[],
|
||||
spaceModel: SpaceModelEntity,
|
||||
subspaceModel: SubspaceModelEntity,
|
||||
queryRunner: QueryRunner,
|
||||
) {
|
||||
try {
|
||||
const productModels = await Promise.all(
|
||||
spaceProductModelDtos.map(async (dto) => {
|
||||
this.validateProductCount(dto);
|
||||
const product = await this.getProduct(dto.productUuid);
|
||||
return queryRunner.manager.create(
|
||||
this.subpaceProductModelRepository.target,
|
||||
{
|
||||
product,
|
||||
productCount: dto.productCount,
|
||||
subspaceModel,
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
const savedProductModels = await queryRunner.manager.save(productModels);
|
||||
|
||||
await Promise.all(
|
||||
spaceProductModelDtos.map((dto, index) => {
|
||||
const savedModel = savedProductModels[index];
|
||||
return this.subspaceProductItemModelService.createProdutItemModel(
|
||||
dto.items,
|
||||
savedModel, // Pass the saved model
|
||||
spaceModel,
|
||||
queryRunner,
|
||||
);
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof HttpException) {
|
||||
throw error;
|
||||
}
|
||||
throw new HttpException(
|
||||
error.message ||
|
||||
'An unexpected error occurred while creating product models.',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,15 +7,19 @@ import {
|
||||
SpaceProductItemModelService,
|
||||
SpaceProductModelService,
|
||||
SubSpaceModelService,
|
||||
SubspaceProductItemModelService,
|
||||
} from './services';
|
||||
import {
|
||||
SpaceModelRepository,
|
||||
SpaceProductItemModelRepository,
|
||||
SpaceProductModelRepository,
|
||||
SubspaceModelRepository,
|
||||
SubspaceProductItemModelRepository,
|
||||
SubspaceProductModelRepository,
|
||||
} from '@app/common/modules/space-model';
|
||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||
import { SubspaceProductModelService } from './services/subspace-product-model.service';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule, SpaceRepositoryModule],
|
||||
@ -31,6 +35,10 @@ import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||
ProductRepository,
|
||||
SpaceProductItemModelService,
|
||||
SpaceProductItemModelRepository,
|
||||
SubspaceProductItemModelService,
|
||||
SubspaceProductItemModelRepository,
|
||||
SubspaceProductModelService,
|
||||
SubspaceProductModelRepository,
|
||||
],
|
||||
exports: [],
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user