mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-16 02:36:19 +00:00
Merge pull request #173 from SyncrowIOT/feat/link-space-to-space-model
Feat/link-space-to-space-model
This commit is contained in:
@ -9,6 +9,15 @@ import { EmailService } from './util/email.service';
|
||||
import { ErrorMessageService } from 'src/error-message/error-message.service';
|
||||
import { TuyaService } from './integrations/tuya/services/tuya.service';
|
||||
import { SceneDeviceRepository } from './modules/scene-device/repositories';
|
||||
import { SpaceProductItemRepository, SpaceRepository } from './modules/space';
|
||||
import {
|
||||
SpaceModelRepository,
|
||||
SpaceProductModelRepository,
|
||||
SubspaceModelRepository,
|
||||
SubspaceProductItemModelRepository,
|
||||
SubspaceProductModelRepository,
|
||||
} from './modules/space-model';
|
||||
import { SubspaceRepository } from './modules/space/repositories/subspace.repository';
|
||||
@Module({
|
||||
providers: [
|
||||
CommonService,
|
||||
@ -16,6 +25,14 @@ import { SceneDeviceRepository } from './modules/scene-device/repositories';
|
||||
ErrorMessageService,
|
||||
TuyaService,
|
||||
SceneDeviceRepository,
|
||||
SpaceRepository,
|
||||
SubspaceRepository,
|
||||
SubspaceModelRepository,
|
||||
SubspaceProductModelRepository,
|
||||
SubspaceProductItemModelRepository,
|
||||
SpaceModelRepository,
|
||||
SpaceProductModelRepository,
|
||||
SpaceProductItemRepository,
|
||||
],
|
||||
exports: [
|
||||
CommonService,
|
||||
@ -25,6 +42,13 @@ import { SceneDeviceRepository } from './modules/scene-device/repositories';
|
||||
EmailService,
|
||||
ErrorMessageService,
|
||||
SceneDeviceRepository,
|
||||
SpaceRepository,
|
||||
SubspaceRepository,
|
||||
SubspaceModelRepository,
|
||||
SubspaceProductModelRepository,
|
||||
SubspaceProductItemModelRepository,
|
||||
SpaceModelRepository,
|
||||
SpaceProductModelRepository,
|
||||
],
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
|
@ -11,7 +11,10 @@ import { PermissionTypeEntity } from '../modules/permission/entities';
|
||||
import {
|
||||
SpaceEntity,
|
||||
SpaceLinkEntity,
|
||||
SpaceProductItemEntity,
|
||||
SubspaceEntity,
|
||||
SubspaceProductEntity,
|
||||
SubspaceProductItemEntity,
|
||||
} from '../modules/space/entities';
|
||||
import { UserSpaceEntity } from '../modules/user/entities';
|
||||
import { DeviceUserPermissionEntity } from '../modules/device/entities';
|
||||
@ -32,6 +35,8 @@ import {
|
||||
SpaceProductItemModelEntity,
|
||||
SpaceProductModelEntity,
|
||||
SubspaceModelEntity,
|
||||
SubspaceProductItemModelEntity,
|
||||
SubspaceProductModelEntity,
|
||||
} from '../modules/space-model/entities';
|
||||
import {
|
||||
InviteUserEntity,
|
||||
@ -80,6 +85,12 @@ import {
|
||||
SpaceProductModelEntity,
|
||||
SpaceProductItemModelEntity,
|
||||
SubspaceModelEntity,
|
||||
SpaceProductEntity,
|
||||
SpaceProductItemEntity,
|
||||
SubspaceProductModelEntity,
|
||||
SubspaceProductItemModelEntity,
|
||||
SubspaceProductEntity,
|
||||
SubspaceProductItemEntity,
|
||||
InviteUserEntity,
|
||||
InviteUserSpaceEntity,
|
||||
],
|
||||
|
@ -4,6 +4,7 @@ import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { DeviceEntity } from '../../device/entities';
|
||||
import { SpaceProductEntity } from '../../space/entities/space-product.entity';
|
||||
import { SpaceProductModelEntity } from '../../space-model/entities';
|
||||
import { SubspaceProductModelEntity } from '../../space-model/entities/subspace-model/subspace-product-model.entity';
|
||||
|
||||
@Entity({ name: 'product' })
|
||||
export class ProductEntity extends AbstractEntity<ProductDto> {
|
||||
@ -37,6 +38,12 @@ export class ProductEntity extends AbstractEntity<ProductDto> {
|
||||
)
|
||||
spaceProductModels: SpaceProductModelEntity[];
|
||||
|
||||
@OneToMany(
|
||||
() => SubspaceProductModelEntity,
|
||||
(subspaceProductModel) => subspaceProductModel.product,
|
||||
)
|
||||
subpaceProductModels: SubspaceProductModelEntity[];
|
||||
|
||||
@OneToMany(
|
||||
() => DeviceEntity,
|
||||
(devicesProductEntity) => devicesProductEntity.productDevice,
|
||||
|
@ -1,4 +1,4 @@
|
||||
export * from './subspace-model.dto';
|
||||
export * from './subspace-model';
|
||||
export * from './space-model.dto';
|
||||
export * from './space-product-item.dto';
|
||||
export * from './space-product-item-model.dto';
|
||||
export * from './space-product-model.dto';
|
||||
|
@ -0,0 +1,15 @@
|
||||
import { IsString, IsNotEmpty } from 'class-validator';
|
||||
|
||||
export class SpaceProductItemModelDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
tag: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
spaceProductModelUuid: string;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
||||
import { SpaceProductItemDto } from './space-product-item.dto';
|
||||
import { SpaceProductItemModelDto } from './space-product-item-model.dto';
|
||||
|
||||
export class SpaceProductModelDto {
|
||||
@IsString()
|
||||
@ -17,7 +17,7 @@ export class SpaceProductModelDto {
|
||||
|
||||
@ApiProperty({
|
||||
description: 'List of individual items with specific names for the product',
|
||||
type: [SpaceProductItemDto],
|
||||
type: [SpaceProductItemModelDto],
|
||||
})
|
||||
items: SpaceProductItemDto[];
|
||||
items: SpaceProductItemModelDto[];
|
||||
}
|
||||
|
@ -0,0 +1,3 @@
|
||||
export * from './subspace-model.dto';
|
||||
export * from './subspace-product-item-model.dto';
|
||||
export * from './subspace-product-model.dto';
|
@ -0,0 +1,15 @@
|
||||
import { IsString, IsNotEmpty } from 'class-validator';
|
||||
|
||||
export class SubspaceProductItemModelDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
tag: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
subspaceProductModelUuid: string;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
|
||||
import { SubspaceProductItemModelDto } from './subspace-product-item-model.dto';
|
||||
|
||||
export class SubpaceProductModelDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
uuid: string;
|
||||
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
productCount: number;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
productUuid: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'List of individual items with specific names for the product',
|
||||
type: [SubspaceProductItemModelDto],
|
||||
})
|
||||
items: SubspaceProductItemModelDto[];
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
export * from './space-model.entity';
|
||||
export * from './space-product-item.entity';
|
||||
export * from './space-product-item-model.entity';
|
||||
export * from './space-product-model.entity';
|
||||
export * from './subspace-model.entity';
|
||||
export * from './subspace-model';
|
||||
|
@ -8,9 +8,10 @@ import {
|
||||
} from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { SpaceModelDto } from '../dtos';
|
||||
import { SubspaceModelEntity } from './subspace-model.entity';
|
||||
import { SubspaceModelEntity } from './subspace-model';
|
||||
import { SpaceProductModelEntity } from './space-product-model.entity';
|
||||
import { ProjectEntity } from '../../project/entities';
|
||||
import { SpaceEntity } from '../../space/entities';
|
||||
|
||||
@Entity({ name: 'space-model' })
|
||||
@Unique(['modelName', 'project'])
|
||||
@ -48,9 +49,13 @@ export class SpaceModelEntity extends AbstractEntity<SpaceModelDto> {
|
||||
() => SpaceProductModelEntity,
|
||||
(productModel) => productModel.spaceModel,
|
||||
{
|
||||
cascade: true,
|
||||
nullable: true,
|
||||
},
|
||||
)
|
||||
public spaceProductModels: SpaceProductModelEntity[];
|
||||
|
||||
@OneToMany(() => SpaceEntity, (space) => space.spaceModel, {
|
||||
cascade: true,
|
||||
})
|
||||
public spaces: SpaceEntity[];
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
import { Entity, Column, ManyToOne, Unique } from 'typeorm';
|
||||
import { Entity, Column, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { SpaceProductItemDto } from '../dtos';
|
||||
import { SpaceProductItemModelDto } from '../dtos';
|
||||
import { SpaceProductModelEntity } from './space-product-model.entity';
|
||||
import { SpaceModelEntity } from './space-model.entity';
|
||||
import { SpaceProductItemEntity } from '../../space/entities';
|
||||
|
||||
@Entity({ name: 'space-product-item-model' })
|
||||
@Unique(['tag', 'spaceProductModel', 'spaceModel'])
|
||||
export class SpaceProductItemModelEntity extends AbstractEntity<SpaceProductItemDto> {
|
||||
export class SpaceProductItemModelEntity extends AbstractEntity<SpaceProductItemModelDto> {
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
@ -21,12 +20,10 @@ export class SpaceProductItemModelEntity extends AbstractEntity<SpaceProductItem
|
||||
)
|
||||
public spaceProductModel: SpaceProductModelEntity;
|
||||
|
||||
@ManyToOne(
|
||||
() => SpaceModelEntity,
|
||||
(spaceModel) => spaceModel.spaceProductModels,
|
||||
{
|
||||
nullable: false,
|
||||
},
|
||||
@OneToMany(
|
||||
() => SpaceProductItemEntity,
|
||||
(spaceProductItem) => spaceProductItem.spaceProductItemModel,
|
||||
{ cascade: true },
|
||||
)
|
||||
public spaceModel: SpaceModelEntity;
|
||||
public items: SpaceProductItemEntity[];
|
||||
}
|
@ -2,8 +2,9 @@ import { Entity, Column, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { ProductEntity } from '../../product/entities';
|
||||
import { SpaceModelEntity } from './space-model.entity';
|
||||
import { SpaceProductItemModelEntity } from './space-product-item.entity';
|
||||
import { SpaceProductItemModelEntity } from './space-product-item-model.entity';
|
||||
import { SpaceProductModelDto } from '../dtos';
|
||||
import { SpaceProductEntity } from '../../space/entities';
|
||||
|
||||
@Entity({ name: 'space-product-model' })
|
||||
export class SpaceProductModelEntity extends AbstractEntity<SpaceProductModelDto> {
|
||||
@ -37,4 +38,13 @@ export class SpaceProductModelEntity extends AbstractEntity<SpaceProductModelDto
|
||||
},
|
||||
)
|
||||
public items: SpaceProductItemModelEntity[];
|
||||
|
||||
@OneToMany(
|
||||
() => SpaceProductEntity,
|
||||
(spaceProduct) => spaceProduct.spaceProductModel,
|
||||
{
|
||||
cascade: true,
|
||||
},
|
||||
)
|
||||
public spaceProducts: SpaceProductEntity[];
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { SpaceModelEntity } from './space-model.entity';
|
||||
import { SubSpaceModelDto } from '../dtos';
|
||||
|
||||
@Entity({ name: 'subspace-model' })
|
||||
@Unique(['subspaceName', 'spaceModel'])
|
||||
export class SubspaceModelEntity extends AbstractEntity<SubSpaceModelDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public subspaceName: string;
|
||||
|
||||
@ManyToOne(
|
||||
() => SpaceModelEntity,
|
||||
(spaceModel) => spaceModel.subspaceModels,
|
||||
{
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
},
|
||||
)
|
||||
public spaceModel: SpaceModelEntity;
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
export * from './subspace-model.entity';
|
||||
export * from './subspace-product-item-model.entity';
|
||||
export * from './subspace-product-model.entity';
|
@ -0,0 +1,46 @@
|
||||
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
||||
import { Column, Entity, ManyToOne, OneToMany, Unique } from 'typeorm';
|
||||
import { SubSpaceModelDto } from '../../dtos';
|
||||
import { SpaceModelEntity } from '../space-model.entity';
|
||||
import { SubspaceEntity } from '@app/common/modules/space/entities';
|
||||
import { SubspaceProductModelEntity } from './subspace-product-model.entity';
|
||||
|
||||
@Entity({ name: 'subspace-model' })
|
||||
@Unique(['subspaceName', 'spaceModel'])
|
||||
export class SubspaceModelEntity extends AbstractEntity<SubSpaceModelDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public subspaceName: string;
|
||||
|
||||
@ManyToOne(
|
||||
() => SpaceModelEntity,
|
||||
(spaceModel) => spaceModel.subspaceModels,
|
||||
{
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
},
|
||||
)
|
||||
public spaceModel: SpaceModelEntity;
|
||||
|
||||
@OneToMany(() => SubspaceEntity, (space) => space.subSpaceModel, {
|
||||
cascade: true,
|
||||
})
|
||||
public spaces: SubspaceEntity[];
|
||||
|
||||
@OneToMany(
|
||||
() => SubspaceProductModelEntity,
|
||||
(productModel) => productModel.subspaceModel,
|
||||
{
|
||||
nullable: true,
|
||||
},
|
||||
)
|
||||
public productModels: SubspaceProductModelEntity[];
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
||||
import { Entity, Column, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { SubspaceProductItemModelDto } from '../../dtos';
|
||||
import { SubspaceProductModelEntity } from './subspace-product-model.entity';
|
||||
import { SubspaceProductItemEntity } from '@app/common/modules/space/entities';
|
||||
|
||||
@Entity({ name: 'subspace-product-item-model' })
|
||||
export class SubspaceProductItemModelEntity extends AbstractEntity<SubspaceProductItemModelDto> {
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public tag: string;
|
||||
|
||||
@ManyToOne(
|
||||
() => SubspaceProductModelEntity,
|
||||
(productModel) => productModel.itemModels,
|
||||
{
|
||||
nullable: false,
|
||||
},
|
||||
)
|
||||
public subspaceProductModel: SubspaceProductModelEntity;
|
||||
|
||||
@OneToMany(() => SubspaceProductItemEntity, (item) => item.subspaceProduct, {
|
||||
nullable: true,
|
||||
})
|
||||
items: SubspaceProductItemEntity[];
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
import { Entity, Column, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { SubpaceProductModelDto } from '../../dtos';
|
||||
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
||||
import { SubspaceModelEntity } from './subspace-model.entity';
|
||||
import { ProductEntity } from '@app/common/modules/product/entities';
|
||||
import { SubspaceProductEntity } from '@app/common/modules/space/entities';
|
||||
import { SubspaceProductItemModelEntity } from './subspace-product-item-model.entity';
|
||||
|
||||
@Entity({ name: 'subspace-product-model' })
|
||||
export class SubspaceProductModelEntity extends AbstractEntity<SubpaceProductModelDto> {
|
||||
@Column({
|
||||
nullable: false,
|
||||
type: 'int',
|
||||
})
|
||||
productCount: number;
|
||||
|
||||
@ManyToOne(
|
||||
() => SubspaceModelEntity,
|
||||
(spaceModel) => spaceModel.productModels,
|
||||
{
|
||||
nullable: false,
|
||||
},
|
||||
)
|
||||
public subspaceModel: SubspaceModelEntity;
|
||||
|
||||
@ManyToOne(() => ProductEntity, (product) => product.subpaceProductModels, {
|
||||
nullable: false,
|
||||
})
|
||||
public product: ProductEntity;
|
||||
|
||||
@OneToMany(() => SubspaceProductEntity, (product) => product.model, {
|
||||
nullable: true,
|
||||
})
|
||||
public subspaceProducts: SubspaceProductEntity[];
|
||||
|
||||
@OneToMany(
|
||||
() => SubspaceProductItemModelEntity,
|
||||
(product) => product.subspaceProductModel,
|
||||
{
|
||||
nullable: true,
|
||||
},
|
||||
)
|
||||
public itemModels: SubspaceProductItemModelEntity[];
|
||||
}
|
@ -5,6 +5,8 @@ import {
|
||||
SpaceProductItemModelEntity,
|
||||
SpaceProductModelEntity,
|
||||
SubspaceModelEntity,
|
||||
SubspaceProductItemModelEntity,
|
||||
SubspaceProductModelEntity,
|
||||
} from '../entities';
|
||||
|
||||
@Injectable()
|
||||
@ -20,6 +22,20 @@ export class SubspaceModelRepository extends Repository<SubspaceModelEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SubspaceProductModelRepository extends Repository<SubspaceProductModelEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SubspaceProductModelEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SubspaceProductItemModelRepository extends Repository<SubspaceProductItemModelEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SubspaceProductItemModelEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SpaceProductModelRepository extends Repository<SpaceProductModelEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
|
@ -1,2 +1,4 @@
|
||||
export * from './space.dto';
|
||||
export * from './subspace.dto';
|
||||
export * from './space-product-item.dto';
|
||||
export * from './space-product.dto';
|
||||
|
@ -11,5 +11,5 @@ export class SpaceProductItemDto {
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
spaceProductModelUuid: string;
|
||||
spaceProductUuid: string;
|
||||
}
|
23
libs/common/src/modules/space/dtos/space-product.dto.ts
Normal file
23
libs/common/src/modules/space/dtos/space-product.dto.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsNotEmpty, IsNumber } from 'class-validator';
|
||||
import { SpaceProductItemDto } from './space-product-item.dto';
|
||||
|
||||
export class SpaceProductModelDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
uuid: string;
|
||||
|
||||
@IsNumber()
|
||||
@IsNotEmpty()
|
||||
productCount: number;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
productUuid: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'List of individual items with specific names for the product',
|
||||
type: [SpaceProductItemDto],
|
||||
})
|
||||
items: SpaceProductItemDto[];
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
export * from './space.entity';
|
||||
export * from './subspace.entity';
|
||||
export * from './subspace';
|
||||
export * from './space-product.entity';
|
||||
export * from './space-product-item.entity';
|
||||
export * from './space-link.entity';
|
||||
|
@ -0,0 +1,27 @@
|
||||
import { Column, Entity, ManyToOne } from 'typeorm';
|
||||
import { SpaceProductEntity } from './space-product.entity';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { SpaceProductItemDto } from '../dtos';
|
||||
import { SpaceProductItemModelEntity } from '../../space-model';
|
||||
|
||||
@Entity({ name: 'space-product-item' })
|
||||
export class SpaceProductItemEntity extends AbstractEntity<SpaceProductItemDto> {
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public tag: string;
|
||||
|
||||
@ManyToOne(() => SpaceProductEntity, (spaceProduct) => spaceProduct.items, {
|
||||
nullable: false,
|
||||
})
|
||||
public spaceProduct: SpaceProductEntity;
|
||||
|
||||
@ManyToOne(
|
||||
() => SpaceProductItemModelEntity,
|
||||
(spaceProductItemModel) => spaceProductItemModel.items,
|
||||
{
|
||||
nullable: true,
|
||||
},
|
||||
)
|
||||
public spaceProductItemModel?: SpaceProductItemModelEntity;
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
import { Column, Entity, ManyToOne, JoinColumn } from 'typeorm';
|
||||
import { Column, Entity, ManyToOne, JoinColumn, OneToMany } from 'typeorm';
|
||||
import { SpaceEntity } from './space.entity';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { ProductEntity } from '../../product/entities';
|
||||
import { SpaceProductItemEntity } from './space-product-item.entity';
|
||||
import { SpaceProductModelEntity } from '../../space-model';
|
||||
|
||||
@Entity({ name: 'space-product' })
|
||||
export class SpaceProductEntity extends AbstractEntity<SpaceProductEntity> {
|
||||
@ -25,6 +27,21 @@ export class SpaceProductEntity extends AbstractEntity<SpaceProductEntity> {
|
||||
})
|
||||
productCount: number;
|
||||
|
||||
@OneToMany(() => SpaceProductItemEntity, (item) => item.spaceProduct, {
|
||||
cascade: true,
|
||||
})
|
||||
public items: SpaceProductItemEntity[];
|
||||
|
||||
@ManyToOne(
|
||||
() => SpaceProductModelEntity,
|
||||
(spaceProductModel) => spaceProductModel.spaceProducts,
|
||||
{
|
||||
nullable: true,
|
||||
},
|
||||
)
|
||||
@JoinColumn({ name: 'space_product_model_uuid' })
|
||||
public spaceProductModel?: SpaceProductModelEntity;
|
||||
|
||||
constructor(partial: Partial<SpaceProductEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
|
@ -11,10 +11,11 @@ import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { UserSpaceEntity } from '../../user/entities';
|
||||
import { DeviceEntity } from '../../device/entities';
|
||||
import { CommunityEntity } from '../../community/entities';
|
||||
import { SubspaceEntity } from './subspace.entity';
|
||||
import { SubspaceEntity } from './subspace';
|
||||
import { SpaceLinkEntity } from './space-link.entity';
|
||||
import { SpaceProductEntity } from './space-product.entity';
|
||||
import { SceneEntity } from '../../scene/entities';
|
||||
import { SpaceModelEntity } from '../../space-model';
|
||||
import { InviteUserSpaceEntity } from '../../Invite-user/entities';
|
||||
|
||||
@Entity({ name: 'space' })
|
||||
@ -98,6 +99,11 @@ export class SpaceEntity extends AbstractEntity<SpaceDto> {
|
||||
|
||||
@OneToMany(() => SceneEntity, (scene) => scene.space)
|
||||
scenes: SceneEntity[];
|
||||
|
||||
@ManyToOne(() => SpaceModelEntity, { nullable: true })
|
||||
@JoinColumn({ name: 'space_model_uuid' })
|
||||
spaceModel?: SpaceModelEntity;
|
||||
|
||||
@OneToMany(
|
||||
() => InviteUserSpaceEntity,
|
||||
(inviteUserSpace) => inviteUserSpace.space,
|
||||
|
@ -1,37 +0,0 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { DeviceEntity } from '../../device/entities';
|
||||
import { SpaceEntity } from './space.entity';
|
||||
import { SubspaceDto } from '../dtos';
|
||||
|
||||
@Entity({ name: 'subspace' })
|
||||
export class SubspaceEntity extends AbstractEntity<SubspaceDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public subspaceName: string;
|
||||
|
||||
@ManyToOne(() => SpaceEntity, (space) => space.subspaces, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'space_id' })
|
||||
space: SpaceEntity;
|
||||
|
||||
@OneToMany(() => DeviceEntity, (device) => device.subspace, {
|
||||
nullable: true,
|
||||
})
|
||||
devices: DeviceEntity[];
|
||||
|
||||
constructor(partial: Partial<SubspaceEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
3
libs/common/src/modules/space/entities/subspace/index.ts
Normal file
3
libs/common/src/modules/space/entities/subspace/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './subspace.entity';
|
||||
export * from './subspace-product.entity';
|
||||
export * from './subspace-product-item.entity';
|
@ -0,0 +1,32 @@
|
||||
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
||||
import { SpaceProductItemDto } from '../../dtos';
|
||||
import { Column, Entity, ManyToOne } from 'typeorm';
|
||||
import { SubspaceProductEntity } from './subspace-product.entity';
|
||||
import { SubspaceProductItemModelEntity } from '@app/common/modules/space-model';
|
||||
|
||||
@Entity({ name: 'subspace-product-item' })
|
||||
export class SubspaceProductItemEntity extends AbstractEntity<SpaceProductItemDto> {
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public tag: string;
|
||||
|
||||
@ManyToOne(
|
||||
() => SubspaceProductEntity,
|
||||
(subspaceProduct) => subspaceProduct.items,
|
||||
{
|
||||
nullable: false,
|
||||
},
|
||||
)
|
||||
public subspaceProduct: SubspaceProductEntity;
|
||||
|
||||
@ManyToOne(() => SubspaceProductItemModelEntity, (model) => model.items, {
|
||||
nullable: true,
|
||||
})
|
||||
model: SubspaceProductItemModelEntity;
|
||||
|
||||
constructor(partial: Partial<SubspaceProductItemEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
import { ProductEntity } from '@app/common/modules/product/entities';
|
||||
import { Column, Entity, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { SubspaceEntity } from './subspace.entity';
|
||||
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
||||
import { SubspaceProductItemEntity } from './subspace-product-item.entity';
|
||||
import {
|
||||
SubspaceProductItemModelEntity,
|
||||
SubspaceProductModelEntity,
|
||||
} from '@app/common/modules/space-model';
|
||||
import { SpaceProductModelDto } from '../../dtos';
|
||||
|
||||
@Entity({ name: 'subspace-product' })
|
||||
export class SubspaceProductEntity extends AbstractEntity<SpaceProductModelDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
type: 'int',
|
||||
})
|
||||
productCount: number;
|
||||
|
||||
@ManyToOne(() => SubspaceEntity, (subspace) => subspace.subspaceProducts, {
|
||||
nullable: false,
|
||||
})
|
||||
public subspace: SubspaceEntity;
|
||||
|
||||
@ManyToOne(() => ProductEntity, (product) => product.subpaceProductModels, {
|
||||
nullable: false,
|
||||
})
|
||||
public product: ProductEntity;
|
||||
|
||||
@OneToMany(() => SubspaceProductItemEntity, (item) => item.subspaceProduct, {
|
||||
nullable: true,
|
||||
})
|
||||
public items: SubspaceProductItemEntity[];
|
||||
|
||||
@ManyToOne(
|
||||
() => SubspaceProductModelEntity,
|
||||
(model) => model.subspaceProducts,
|
||||
{
|
||||
nullable: true,
|
||||
},
|
||||
)
|
||||
model: SubspaceProductModelEntity;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
|
||||
import { DeviceEntity } from '@app/common/modules/device/entities';
|
||||
import { SubspaceModelEntity } from '@app/common/modules/space-model';
|
||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { SubspaceDto } from '../../dtos';
|
||||
import { SpaceEntity } from '../space.entity';
|
||||
import { SubspaceProductEntity } from './subspace-product.entity';
|
||||
|
||||
@Entity({ name: 'subspace' })
|
||||
export class SubspaceEntity extends AbstractEntity<SubspaceDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
nullable: false,
|
||||
})
|
||||
public subspaceName: string;
|
||||
|
||||
@ManyToOne(() => SpaceEntity, (space) => space.subspaces, {
|
||||
nullable: false,
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'space_uuid' })
|
||||
space: SpaceEntity;
|
||||
|
||||
@OneToMany(() => DeviceEntity, (device) => device.subspace, {
|
||||
nullable: true,
|
||||
})
|
||||
devices: DeviceEntity[];
|
||||
|
||||
@ManyToOne(() => SubspaceModelEntity, { nullable: true })
|
||||
@JoinColumn({ name: 'subspace_model_uuid' })
|
||||
subSpaceModel?: SubspaceModelEntity;
|
||||
|
||||
@OneToMany(
|
||||
() => SubspaceProductEntity,
|
||||
(subspaceProduct) => subspaceProduct.subspace,
|
||||
{
|
||||
nullable: true,
|
||||
},
|
||||
)
|
||||
public subspaceProducts: SubspaceProductEntity[];
|
||||
|
||||
constructor(partial: Partial<SubspaceEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
}
|
||||
}
|
4
libs/common/src/modules/space/index.ts
Normal file
4
libs/common/src/modules/space/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './dtos';
|
||||
export * from './entities';
|
||||
export * from './repositories';
|
||||
export * from './space.repository.module';
|
@ -1,7 +1,11 @@
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { SpaceProductEntity } from '../entities/space-product.entity';
|
||||
import { SpaceEntity, SpaceLinkEntity, SubspaceEntity } from '../entities';
|
||||
import {
|
||||
SpaceEntity,
|
||||
SpaceLinkEntity,
|
||||
SpaceProductItemEntity,
|
||||
} from '../entities';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceRepository extends Repository<SpaceEntity> {
|
||||
@ -9,12 +13,6 @@ export class SpaceRepository extends Repository<SpaceEntity> {
|
||||
super(SpaceEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
@Injectable()
|
||||
export class SubspaceRepository extends Repository<SubspaceEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SubspaceEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SpaceLinkRepository extends Repository<SpaceLinkEntity> {
|
||||
@ -28,3 +26,10 @@ export class SpaceProductRepository extends Repository<SpaceProductEntity> {
|
||||
super(SpaceProductEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SpaceProductItemRepository extends Repository<SpaceProductItemEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SpaceProductItemEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import {
|
||||
SubspaceEntity,
|
||||
SubspaceProductEntity,
|
||||
SubspaceProductItemEntity,
|
||||
} from '../entities';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class SubspaceRepository extends Repository<SubspaceEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SubspaceEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SubspaceProductRepository extends Repository<SubspaceProductEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SubspaceProductEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SubspaceProductItemRepository extends Repository<SubspaceProductItemEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SubspaceProductItemEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
@ -1,11 +1,17 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { SpaceEntity, SubspaceEntity } from './entities';
|
||||
import { SpaceEntity, SubspaceEntity, SubspaceProductEntity } from './entities';
|
||||
|
||||
@Module({
|
||||
providers: [],
|
||||
exports: [],
|
||||
controllers: [],
|
||||
imports: [TypeOrmModule.forFeature([SpaceEntity, SubspaceEntity])],
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([
|
||||
SpaceEntity,
|
||||
SubspaceEntity,
|
||||
SubspaceProductEntity,
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class SpaceRepositoryModule {}
|
||||
|
@ -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,8 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { ProjectController } from './controllers';
|
||||
import { ProjectService } from './services';
|
||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [ProjectController],
|
||||
|
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,7 +1,7 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class CreateSpaceProductItemModelDto {
|
||||
export class CreateProductItemModelDto {
|
||||
@ApiProperty({
|
||||
description: 'Specific name for the product item',
|
||||
example: 'Light 1',
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
ArrayNotEmpty,
|
||||
} from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { CreateSpaceProductItemModelDto } from './create-space-product-item-model.dto';
|
||||
import { CreateProductItemModelDto } from './create-space-product-item-model.dto';
|
||||
|
||||
export class CreateSpaceProductModelDto {
|
||||
@ApiProperty({
|
||||
@ -17,7 +17,7 @@ export class CreateSpaceProductModelDto {
|
||||
})
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
productId: string;
|
||||
productUuid: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Number of products in the model',
|
||||
@ -29,11 +29,11 @@ export class CreateSpaceProductModelDto {
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Specific names for each product item',
|
||||
type: [CreateSpaceProductItemModelDto],
|
||||
type: [CreateProductItemModelDto],
|
||||
})
|
||||
@IsArray()
|
||||
@ArrayNotEmpty()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateSpaceProductItemModelDto)
|
||||
items: CreateSpaceProductItemModelDto[];
|
||||
@Type(() => CreateProductItemModelDto)
|
||||
items: CreateProductItemModelDto[];
|
||||
}
|
||||
|
@ -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[];
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
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';
|
||||
|
@ -4,7 +4,7 @@ import { CreateSpaceModelDto } from '../dtos';
|
||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||
import { ProjectParam } from 'src/community/dtos';
|
||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||
import { SubSpaceModelService } from './subspace-model.service';
|
||||
import { SubSpaceModelService } from './subspace/subspace-model.service';
|
||||
import { SpaceProductModelService } from './space-product-model.service';
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
|
@ -4,29 +4,30 @@ import {
|
||||
SpaceProductModelEntity,
|
||||
} from '@app/common/modules/space-model';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { CreateSpaceProductItemModelDto } from '../dtos';
|
||||
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: CreateSpaceProductItemModelDto[],
|
||||
itemModelDtos: CreateProductItemModelDto[],
|
||||
spaceProductModel: SpaceProductModelEntity,
|
||||
spaceModel: SpaceModelEntity,
|
||||
queryRunner: QueryRunner,
|
||||
) {
|
||||
await this.validateTags(itemModelDtos, spaceModel, queryRunner);
|
||||
|
||||
await this.validateTags(itemModelDtos, queryRunner, spaceModel);
|
||||
try {
|
||||
const productItems = itemModelDtos.map((dto) =>
|
||||
queryRunner.manager.create(this.spaceProductItemRepository.target, {
|
||||
tag: dto.tag,
|
||||
spaceProductModel,
|
||||
spaceModel,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -43,41 +44,4 @@ export class SpaceProductItemModelService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async validateTags(
|
||||
itemModelDtos: CreateSpaceProductItemModelDto[],
|
||||
spaceModel: SpaceModelEntity,
|
||||
queryRunner: QueryRunner,
|
||||
) {
|
||||
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: { 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,23 @@
|
||||
import { QueryRunner } from 'typeorm';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { CreateSpaceProductModelDto } from '../dtos';
|
||||
import { SpaceProductItemModelService } from './space-product-item-model.service';
|
||||
import { BaseProductModelService } from '../common';
|
||||
import { ProductService } from 'src/product/services';
|
||||
import {
|
||||
SpaceModelEntity,
|
||||
SpaceProductModelRepository,
|
||||
} 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';
|
||||
|
||||
@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[],
|
||||
@ -25,7 +28,7 @@ export class SpaceProductModelService {
|
||||
const productModels = await Promise.all(
|
||||
spaceProductModelDtos.map(async (dto) => {
|
||||
this.validateProductCount(dto);
|
||||
const product = await this.getProduct(dto.productId);
|
||||
const product = await this.getProduct(dto.productUuid);
|
||||
return queryRunner.manager.create(
|
||||
this.spaceProductModelRepository.target,
|
||||
{
|
||||
@ -40,14 +43,15 @@ export class SpaceProductModelService {
|
||||
const savedProductModels = await queryRunner.manager.save(productModels);
|
||||
|
||||
await Promise.all(
|
||||
spaceProductModelDtos.map((dto, index) =>
|
||||
this.spaceProductItemModelService.createProdutItemModel(
|
||||
spaceProductModelDtos.map((dto, index) => {
|
||||
const savedModel = savedProductModels[index];
|
||||
return this.spaceProductItemModelService.createProdutItemModel(
|
||||
dto.items,
|
||||
savedProductModels[index],
|
||||
savedModel, // Pass the saved model
|
||||
spaceModel,
|
||||
queryRunner,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof HttpException) {
|
||||
@ -60,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.productId}.`,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
3
src/space-model/services/subspace/index.ts
Normal file
3
src/space-model/services/subspace/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './subspace-model.service';
|
||||
export * from './subspace-product-item-model.service';
|
||||
export * from './subspace-product-model.service';
|
@ -3,13 +3,15 @@ import {
|
||||
SubspaceModelRepository,
|
||||
} from '@app/common/modules/space-model';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { CreateSubspaceModelDto } from '../dtos';
|
||||
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 { QueryRunner } from 'typeorm';
|
||||
import {
|
||||
SpaceModelEntity,
|
||||
SubspaceProductItemModelRepository,
|
||||
SubspaceProductModelEntity,
|
||||
} from '@app/common/modules/space-model';
|
||||
import { BaseProductItemService } from '../../common';
|
||||
import { CreateProductItemModelDto } from '../../dtos';
|
||||
|
||||
@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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -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/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: [],
|
||||
})
|
||||
|
69
src/space/common/base-product-item.service.ts
Normal file
69
src/space/common/base-product-item.service.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { QueryRunner } from 'typeorm';
|
||||
|
||||
export abstract class BaseProductItemService {
|
||||
protected async validateTags(
|
||||
incomingTags: string[],
|
||||
queryRunner: QueryRunner,
|
||||
spaceUuid: string,
|
||||
): Promise<void> {
|
||||
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 existingTagsQuery = `
|
||||
SELECT tag FROM (
|
||||
SELECT spi.tag
|
||||
FROM "space-product-item" spi
|
||||
INNER JOIN "space-product" spm ON spi.space_product_uuid = spm.uuid
|
||||
WHERE spm.space_uuid = $1
|
||||
UNION
|
||||
SELECT spi.tag
|
||||
FROM "subspace-product-item" spi
|
||||
INNER JOIN "subspace-product" spm ON spi.subspace_product_uuid = spm.uuid
|
||||
INNER JOIN "subspace" sm ON spm.subspace_uuid = sm.uuid
|
||||
WHERE sm.space_uuid = $1
|
||||
) AS combined_tags;
|
||||
`;
|
||||
|
||||
const existingTags = await queryRunner.manager.query(existingTagsQuery, [
|
||||
spaceUuid,
|
||||
]);
|
||||
|
||||
const existingTagSet = new Set(
|
||||
existingTags.map((row: { tag: string }) => row.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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected async saveProductItems<T>(
|
||||
productItems: T[],
|
||||
targetRepository: any,
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<void> {
|
||||
try {
|
||||
await queryRunner.manager.save(targetRepository, productItems);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'An error occurred while creating product items.',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
1
src/space/common/index.ts
Normal file
1
src/space/common/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './base-product-item.service';
|
@ -10,6 +10,42 @@ import {
|
||||
IsUUID,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import { AddSubspaceDto } from './subspace';
|
||||
|
||||
export class CreateSpaceProductItemDto {
|
||||
@ApiProperty({
|
||||
description: 'Specific name for the product item',
|
||||
example: 'Light 1',
|
||||
})
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
tag: string;
|
||||
}
|
||||
|
||||
export class ProductAssignmentDto {
|
||||
@ApiProperty({
|
||||
description: 'UUID of the product to be assigned',
|
||||
example: 'prod-uuid-1234',
|
||||
})
|
||||
@IsNotEmpty()
|
||||
productId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Number of items to assign for the product',
|
||||
example: 3,
|
||||
})
|
||||
count: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Specific names for each product item',
|
||||
type: [CreateSpaceProductItemDto],
|
||||
example: [{ tag: 'Light 1' }, { tag: 'Light 2' }, { tag: 'Light 3' }],
|
||||
})
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateSpaceProductItemDto)
|
||||
items: CreateSpaceProductItemDto[];
|
||||
}
|
||||
|
||||
export class AddSpaceDto {
|
||||
@ApiProperty({
|
||||
@ -29,9 +65,14 @@ export class AddSpaceDto {
|
||||
@IsOptional()
|
||||
parentUuid?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Icon identifier for the space',
|
||||
example: 'assets/location',
|
||||
required: false,
|
||||
})
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
public icon: string;
|
||||
public icon?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Indicates whether the space is private or public',
|
||||
@ -49,16 +90,39 @@ export class AddSpaceDto {
|
||||
@IsNumber()
|
||||
y: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'UUID of the Space',
|
||||
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
|
||||
})
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
spaceModelUuid?: string;
|
||||
|
||||
@ApiProperty({ description: 'Y position on canvas', example: 200 })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
direction: string;
|
||||
direction?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'List of products assigned to this space',
|
||||
type: [ProductAssignmentDto],
|
||||
required: false,
|
||||
})
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@IsOptional()
|
||||
@Type(() => ProductAssignmentDto)
|
||||
products: ProductAssignmentDto[];
|
||||
products?: ProductAssignmentDto[];
|
||||
|
||||
@ApiProperty({
|
||||
description: 'List of subspaces included in the model',
|
||||
type: [AddSubspaceDto],
|
||||
})
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => AddSubspaceDto)
|
||||
subspaces?: AddSubspaceDto[];
|
||||
}
|
||||
|
||||
export class AddUserSpaceDto {
|
||||
@ -101,11 +165,3 @@ export class AddUserSpaceUsingCodeDto {
|
||||
Object.assign(this, dto);
|
||||
}
|
||||
}
|
||||
|
||||
class ProductAssignmentDto {
|
||||
@IsNotEmpty()
|
||||
productId: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
count: number;
|
||||
}
|
||||
|
@ -1,5 +1,13 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsArray,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import { ProductAssignmentDto } from '../add.space.dto';
|
||||
|
||||
export class AddSubspaceDto {
|
||||
@ApiProperty({
|
||||
@ -9,4 +17,15 @@ export class AddSubspaceDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
subspaceName: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'List of products assigned to this space',
|
||||
type: [ProductAssignmentDto],
|
||||
required: false,
|
||||
})
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@IsOptional()
|
||||
@Type(() => ProductAssignmentDto)
|
||||
products?: ProductAssignmentDto[];
|
||||
}
|
||||
|
@ -5,3 +5,5 @@ export * from './subspace';
|
||||
export * from './space-link';
|
||||
export * from './space-scene.service';
|
||||
export * from './space-products';
|
||||
export * from './space-product-items';
|
||||
export * from './space-validation.service';
|
||||
|
@ -6,23 +6,25 @@ import { GetSpaceParam } from '../dtos';
|
||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
||||
import { SpaceService } from './space.service';
|
||||
|
||||
import { ValidationService } from './space-validation.service';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceDeviceService {
|
||||
constructor(
|
||||
private readonly tuyaService: TuyaService,
|
||||
private readonly spaceService: SpaceService,
|
||||
private readonly validationService: ValidationService,
|
||||
) {}
|
||||
|
||||
async listDevicesInSpace(params: GetSpaceParam): Promise<BaseResponseDto> {
|
||||
const { spaceUuid, communityUuid, projectUuid } = params;
|
||||
try {
|
||||
const space = await this.spaceService.validateCommunityAndSpace(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
);
|
||||
const space =
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
if (!Array.isArray(space.devices)) {
|
||||
throw new HttpException(
|
||||
|
1
src/space/services/space-product-items/index.ts
Normal file
1
src/space/services/space-product-items/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './space-product-items.service';
|
@ -0,0 +1,87 @@
|
||||
import {
|
||||
SpaceEntity,
|
||||
SpaceProductEntity,
|
||||
SpaceProductItemRepository,
|
||||
} from '@app/common/modules/space';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { CreateSpaceProductItemDto } from '../../dtos';
|
||||
import { QueryRunner } from 'typeorm';
|
||||
import { SpaceProductModelEntity } from '@app/common/modules/space-model';
|
||||
import { BaseProductItemService } from '../../common';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceProductItemService extends BaseProductItemService {
|
||||
constructor(
|
||||
private readonly spaceProductItemRepository: SpaceProductItemRepository,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async createProductItem(
|
||||
itemModelDtos: CreateSpaceProductItemDto[],
|
||||
spaceProduct: SpaceProductEntity,
|
||||
space: SpaceEntity,
|
||||
queryRunner: QueryRunner,
|
||||
) {
|
||||
if (!itemModelDtos?.length) return;
|
||||
|
||||
const incomingTags = itemModelDtos.map((item) => item.tag);
|
||||
|
||||
await this.validateTags(incomingTags, queryRunner, space.uuid);
|
||||
|
||||
try {
|
||||
const productItems = itemModelDtos.map((dto) =>
|
||||
queryRunner.manager.create(this.spaceProductItemRepository.target, {
|
||||
tag: dto.tag,
|
||||
spaceProduct,
|
||||
}),
|
||||
);
|
||||
|
||||
await this.saveProductItems(
|
||||
productItems,
|
||||
this.spaceProductItemRepository.target,
|
||||
queryRunner,
|
||||
);
|
||||
} 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async createSpaceProductItemFromModel(
|
||||
spaceProduct: SpaceProductEntity,
|
||||
spaceProductModel: SpaceProductModelEntity,
|
||||
queryRunner: QueryRunner,
|
||||
) {
|
||||
const spaceProductItemModels = spaceProductModel.items;
|
||||
if (!spaceProductItemModels?.length) return;
|
||||
|
||||
try {
|
||||
const productItems = spaceProductItemModels.map((model) =>
|
||||
queryRunner.manager.create(this.spaceProductItemRepository.target, {
|
||||
tag: model.tag,
|
||||
spaceProduct,
|
||||
}),
|
||||
);
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,96 +2,101 @@ import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||
import { SpaceEntity } from '@app/common/modules/space/entities';
|
||||
import { SpaceProductEntity } from '@app/common/modules/space/entities/space-product.entity';
|
||||
import { SpaceProductRepository } from '@app/common/modules/space/repositories';
|
||||
import { In } from 'typeorm';
|
||||
import { In, QueryRunner } from 'typeorm';
|
||||
import { ProductAssignmentDto } from '../../dtos';
|
||||
import { SpaceProductItemService } from '../space-product-items';
|
||||
import { SpaceModelEntity } from '@app/common/modules/space-model';
|
||||
import { ProductEntity } from '@app/common/modules/product/entities';
|
||||
import { ProductService } from 'src/product/services';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceProductService {
|
||||
constructor(
|
||||
private readonly productRepository: ProductRepository,
|
||||
private readonly spaceProductRepository: SpaceProductRepository,
|
||||
private readonly spaceProductItemService: SpaceProductItemService,
|
||||
private readonly productService: ProductService,
|
||||
) {}
|
||||
|
||||
async createFromModel(
|
||||
spaceModel: SpaceModelEntity,
|
||||
space: SpaceEntity,
|
||||
queryRunner: QueryRunner,
|
||||
) {
|
||||
const spaceProductModels = spaceModel.spaceProductModels;
|
||||
if (!spaceProductModels?.length) return;
|
||||
const newSpaceProducts = [];
|
||||
|
||||
spaceProductModels.map((spaceProductModel) => {
|
||||
newSpaceProducts.push(
|
||||
queryRunner.manager.create(SpaceProductEntity, {
|
||||
space: space,
|
||||
product: spaceProductModel.product,
|
||||
productCount: spaceProductModel.productCount,
|
||||
spaceProductModel: spaceProductModel,
|
||||
}),
|
||||
);
|
||||
});
|
||||
if (newSpaceProducts.length > 0) {
|
||||
await queryRunner.manager.save(SpaceProductEntity, newSpaceProducts);
|
||||
await Promise.all(
|
||||
newSpaceProducts.map((spaceProduct, index) => {
|
||||
const spaceProductModel = spaceProductModels[index];
|
||||
return this.spaceProductItemService.createSpaceProductItemFromModel(
|
||||
spaceProduct,
|
||||
spaceProductModel,
|
||||
queryRunner,
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async assignProductsToSpace(
|
||||
space: SpaceEntity,
|
||||
products: { productId: string; count: number }[],
|
||||
products: ProductAssignmentDto[],
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<SpaceProductEntity[]> {
|
||||
let updatedProducts: SpaceProductEntity[] = [];
|
||||
|
||||
try {
|
||||
const uniqueProducts = this.validateUniqueProducts(products);
|
||||
const productEntities = await this.getProductEntities(uniqueProducts);
|
||||
const existingSpaceProducts = await this.getExistingSpaceProducts(
|
||||
space,
|
||||
queryRunner,
|
||||
);
|
||||
|
||||
// Fetch existing space products
|
||||
const existingSpaceProducts = await this.spaceProductRepository.find({
|
||||
where: {
|
||||
space: {
|
||||
uuid: space.uuid,
|
||||
},
|
||||
},
|
||||
relations: ['product'],
|
||||
});
|
||||
|
||||
const updatedProducts = [];
|
||||
const newProducts = [];
|
||||
|
||||
for (const { productId, count } of uniqueProducts) {
|
||||
const product = productEntities.get(productId);
|
||||
if (!product) {
|
||||
throw new HttpException(
|
||||
`Product with ID ${productId} not found`,
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
// Check if product already exists in the space
|
||||
const existingProduct = existingSpaceProducts.find(
|
||||
(spaceProduct) => spaceProduct.product.uuid === productId,
|
||||
if (existingSpaceProducts) {
|
||||
updatedProducts = await this.updateExistingProducts(
|
||||
existingSpaceProducts,
|
||||
uniqueProducts,
|
||||
productEntities,
|
||||
queryRunner,
|
||||
);
|
||||
|
||||
if (existingProduct) {
|
||||
// If count is different, update the existing record
|
||||
if (existingProduct.productCount !== count) {
|
||||
existingProduct.productCount = count;
|
||||
updatedProducts.push(existingProduct);
|
||||
}
|
||||
} else {
|
||||
// Add new product if it doesn't exist
|
||||
newProducts.push(
|
||||
this.spaceProductRepository.create({
|
||||
space,
|
||||
product,
|
||||
productCount: count,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Save updates and new records
|
||||
if (updatedProducts.length > 0) {
|
||||
await this.spaceProductRepository.save(updatedProducts);
|
||||
}
|
||||
|
||||
if (newProducts.length > 0) {
|
||||
await this.spaceProductRepository.save(newProducts);
|
||||
}
|
||||
const newProducts = await this.createNewProducts(
|
||||
uniqueProducts,
|
||||
productEntities,
|
||||
space,
|
||||
queryRunner,
|
||||
);
|
||||
|
||||
return [...updatedProducts, ...newProducts];
|
||||
} catch (error) {
|
||||
console.error('Error assigning products to space:', error);
|
||||
|
||||
if (!(error instanceof HttpException)) {
|
||||
throw new HttpException(
|
||||
'An error occurred while assigning products to the space',
|
||||
`An error occurred while assigning products to the space ${error}`,
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private validateUniqueProducts(
|
||||
products: { productId: string; count: number }[],
|
||||
): { productId: string; count: number }[] {
|
||||
products: ProductAssignmentDto[],
|
||||
): ProductAssignmentDto[] {
|
||||
const productIds = new Set();
|
||||
const uniqueProducts = [];
|
||||
|
||||
@ -110,15 +115,13 @@ export class SpaceProductService {
|
||||
}
|
||||
|
||||
private async getProductEntities(
|
||||
products: { productId: string; count: number }[],
|
||||
products: ProductAssignmentDto[],
|
||||
): Promise<Map<string, any>> {
|
||||
try {
|
||||
const productIds = products.map((p) => p.productId);
|
||||
|
||||
const productEntities = await this.productRepository.find({
|
||||
where: { uuid: In(productIds) },
|
||||
});
|
||||
|
||||
return new Map(productEntities.map((p) => [p.uuid, p]));
|
||||
} catch (error) {
|
||||
console.error('Error fetching product entities:', error);
|
||||
@ -128,4 +131,96 @@ export class SpaceProductService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async getExistingSpaceProducts(
|
||||
space: SpaceEntity,
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<SpaceProductEntity[]> {
|
||||
return queryRunner.manager.find(SpaceProductEntity, {
|
||||
where: { space: { uuid: space.uuid } },
|
||||
relations: ['product'],
|
||||
});
|
||||
}
|
||||
|
||||
private async updateExistingProducts(
|
||||
existingSpaceProducts: SpaceProductEntity[],
|
||||
uniqueProducts: ProductAssignmentDto[],
|
||||
productEntities: Map<string, any>,
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<SpaceProductEntity[]> {
|
||||
const updatedProducts = [];
|
||||
|
||||
for (const { productId, count } of uniqueProducts) {
|
||||
productEntities.get(productId);
|
||||
const existingProduct = existingSpaceProducts.find(
|
||||
(spaceProduct) => spaceProduct.product.uuid === productId,
|
||||
);
|
||||
|
||||
if (existingProduct && existingProduct.productCount !== count) {
|
||||
existingProduct.productCount = count;
|
||||
updatedProducts.push(existingProduct);
|
||||
}
|
||||
}
|
||||
|
||||
if (updatedProducts.length > 0) {
|
||||
await queryRunner.manager.save(SpaceProductEntity, updatedProducts);
|
||||
}
|
||||
|
||||
return updatedProducts;
|
||||
}
|
||||
|
||||
private async createNewProducts(
|
||||
uniqueSpaceProducts: ProductAssignmentDto[],
|
||||
productEntities: Map<string, any>,
|
||||
space: SpaceEntity,
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<SpaceProductEntity[]> {
|
||||
const newProducts = [];
|
||||
|
||||
for (const uniqueSpaceProduct of uniqueSpaceProducts) {
|
||||
const product = productEntities.get(uniqueSpaceProduct.productId);
|
||||
await this.getProduct(uniqueSpaceProduct.productId);
|
||||
this.validateProductCount(uniqueSpaceProduct);
|
||||
|
||||
newProducts.push(
|
||||
queryRunner.manager.create(SpaceProductEntity, {
|
||||
space,
|
||||
product,
|
||||
productCount: uniqueSpaceProduct.count,
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (newProducts.length > 0) {
|
||||
await queryRunner.manager.save(SpaceProductEntity, newProducts);
|
||||
|
||||
await Promise.all(
|
||||
uniqueSpaceProducts.map((dto, index) => {
|
||||
const spaceProduct = newProducts[index];
|
||||
return this.spaceProductItemService.createProductItem(
|
||||
dto.items,
|
||||
spaceProduct,
|
||||
space,
|
||||
queryRunner,
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return newProducts;
|
||||
}
|
||||
|
||||
private validateProductCount(dto: ProductAssignmentDto) {
|
||||
const productItemCount = dto.items.length;
|
||||
if (dto.count !== productItemCount) {
|
||||
throw new HttpException(
|
||||
`Product count (${dto.count}) does not match the number of items (${productItemCount}) for product ID ${dto.productId}.`,
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async getProduct(productId: string): Promise<ProductEntity> {
|
||||
const product = await this.productService.findOne(productId);
|
||||
return product.data;
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { GetSpaceParam } from '../dtos';
|
||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||
import { SpaceService } from './space.service';
|
||||
import { SceneService } from '../../scene/services';
|
||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||
import { GetSceneDto } from '../../scene/dtos';
|
||||
import { ValidationService } from './space-validation.service';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceSceneService {
|
||||
constructor(
|
||||
private readonly spaceSevice: SpaceService,
|
||||
private readonly sceneSevice: SceneService,
|
||||
private readonly validationService: ValidationService,
|
||||
) {}
|
||||
|
||||
async getScenes(
|
||||
@ -20,10 +20,10 @@ export class SpaceSceneService {
|
||||
try {
|
||||
const { spaceUuid, communityUuid, projectUuid } = params;
|
||||
|
||||
await this.spaceSevice.validateCommunityAndSpace(
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
const scenes = await this.sceneSevice.findScenesBySpace(
|
||||
|
@ -1,21 +1,19 @@
|
||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import {
|
||||
UserRepository,
|
||||
UserSpaceRepository,
|
||||
} from '@app/common/modules/user/repositories';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { SpaceService } from './space.service';
|
||||
import { UserSpaceParam } from '../dtos';
|
||||
import { ValidationService } from './space-validation.service';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceUserService {
|
||||
constructor(
|
||||
private readonly spaceRepository: SpaceRepository,
|
||||
private readonly validationService: ValidationService,
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly userSpaceRepository: UserSpaceRepository,
|
||||
private readonly spaceService: SpaceService,
|
||||
) {}
|
||||
async associateUserToSpace(params: UserSpaceParam): Promise<BaseResponseDto> {
|
||||
const { communityUuid, spaceUuid, userUuid, projectUuid } = params;
|
||||
@ -31,11 +29,12 @@ export class SpaceUserService {
|
||||
}
|
||||
|
||||
// Find the space by ID
|
||||
const space = await this.spaceService.validateCommunityAndSpace(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
);
|
||||
const space =
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
// Check if the association already exists
|
||||
const existingAssociation = await this.userSpaceRepository.findOne({
|
||||
@ -73,10 +72,10 @@ export class SpaceUserService {
|
||||
}
|
||||
|
||||
// Find the space by ID
|
||||
await this.spaceService.validateCommunityAndSpace(
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
// Find the existing association
|
||||
|
81
src/space/services/space-validation.service.ts
Normal file
81
src/space/services/space-validation.service.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import { CommunityEntity } from '@app/common/modules/community/entities';
|
||||
import { SpaceEntity } from '@app/common/modules/space/entities';
|
||||
import { SpaceRepository } from '@app/common/modules/space/repositories';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { CommunityService } from '../../community/services';
|
||||
import { ProjectService } from '../../project/services';
|
||||
import {
|
||||
SpaceModelEntity,
|
||||
SpaceModelRepository,
|
||||
} from '@app/common/modules/space-model';
|
||||
|
||||
@Injectable()
|
||||
export class ValidationService {
|
||||
constructor(
|
||||
private readonly projectService: ProjectService,
|
||||
private readonly communityService: CommunityService,
|
||||
private readonly spaceRepository: SpaceRepository,
|
||||
private readonly spaceModelRepository: SpaceModelRepository,
|
||||
) {}
|
||||
|
||||
async validateCommunityAndProject(
|
||||
communityUuid: string,
|
||||
projectUuid: string,
|
||||
): Promise<CommunityEntity> {
|
||||
await this.projectService.findOne(projectUuid);
|
||||
const community = await this.communityService.getCommunityById({
|
||||
communityUuid,
|
||||
projectUuid,
|
||||
});
|
||||
|
||||
return community.data;
|
||||
}
|
||||
|
||||
async validateSpaceWithinCommunityAndProject(
|
||||
communityUuid: string,
|
||||
projectUuid: string,
|
||||
spaceUuid?: string,
|
||||
): Promise<SpaceEntity> {
|
||||
await this.validateCommunityAndProject(communityUuid, projectUuid);
|
||||
const space = await this.validateSpace(spaceUuid);
|
||||
return space;
|
||||
}
|
||||
|
||||
async validateSpace(spaceUuid: string): Promise<SpaceEntity> {
|
||||
const space = await this.spaceRepository.findOne({
|
||||
where: { uuid: spaceUuid },
|
||||
});
|
||||
|
||||
if (!space) {
|
||||
throw new HttpException(
|
||||
`Space with UUID ${spaceUuid} not found`,
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
async validateSpaceModel(spaceModelUuid: string): Promise<SpaceModelEntity> {
|
||||
const spaceModel = await this.spaceModelRepository.findOne({
|
||||
where: { uuid: spaceModelUuid },
|
||||
relations: [
|
||||
'subspaceModels',
|
||||
'subspaceModels.productModels.product',
|
||||
'subspaceModels.productModels',
|
||||
'spaceProductModels',
|
||||
'spaceProductModels.product',
|
||||
'spaceProductModels.items',
|
||||
],
|
||||
});
|
||||
|
||||
if (!spaceModel) {
|
||||
throw new HttpException(
|
||||
`Space model with UUID ${spaceModelUuid} not found`,
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
return spaceModel;
|
||||
}
|
||||
}
|
@ -9,47 +9,68 @@ import {
|
||||
AddSpaceDto,
|
||||
CommunitySpaceParam,
|
||||
GetSpaceParam,
|
||||
ProductAssignmentDto,
|
||||
UpdateSpaceDto,
|
||||
} from '../dtos';
|
||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||
import { SpaceEntity } from '@app/common/modules/space/entities';
|
||||
import { generateRandomString } from '@app/common/helper/randomString';
|
||||
import { SpaceLinkService } from './space-link';
|
||||
import { SpaceProductService } from './space-products';
|
||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||
import { CreateSubspaceModelDto } from 'src/space-model/dtos';
|
||||
import { SubSpaceService } from './subspace';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { ValidationService } from './space-validation.service';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceService {
|
||||
constructor(
|
||||
private readonly dataSource: DataSource,
|
||||
private readonly spaceRepository: SpaceRepository,
|
||||
private readonly communityRepository: CommunityRepository,
|
||||
private readonly spaceLinkService: SpaceLinkService,
|
||||
private readonly spaceProductService: SpaceProductService,
|
||||
private readonly projectRepository: ProjectRepository,
|
||||
private readonly subSpaceService: SubSpaceService,
|
||||
private readonly validationService: ValidationService,
|
||||
) {}
|
||||
|
||||
async createSpace(
|
||||
addSpaceDto: AddSpaceDto,
|
||||
params: CommunitySpaceParam,
|
||||
): Promise<BaseResponseDto> {
|
||||
const { parentUuid, direction, products } = addSpaceDto;
|
||||
const { parentUuid, direction, products, spaceModelUuid, subspaces } =
|
||||
addSpaceDto;
|
||||
const { communityUuid, projectUuid } = params;
|
||||
|
||||
await this.validateProject(projectUuid);
|
||||
const queryRunner = this.dataSource.createQueryRunner();
|
||||
|
||||
const community = await this.validateCommunity(communityUuid);
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
const community = await this.validationService.validateCommunityAndProject(
|
||||
communityUuid,
|
||||
projectUuid,
|
||||
);
|
||||
|
||||
this.validateSpaceCreation(spaceModelUuid, products, subspaces);
|
||||
|
||||
const parent = parentUuid
|
||||
? await this.validationService.validateSpace(parentUuid)
|
||||
: null;
|
||||
|
||||
const spaceModel = spaceModelUuid
|
||||
? await this.validationService.validateSpaceModel(spaceModelUuid)
|
||||
: null;
|
||||
|
||||
const parent = parentUuid ? await this.validateSpace(parentUuid) : null;
|
||||
try {
|
||||
const newSpace = this.spaceRepository.create({
|
||||
const newSpace = queryRunner.manager.create(SpaceEntity, {
|
||||
...addSpaceDto,
|
||||
community,
|
||||
spaceModel,
|
||||
parent: parentUuid ? parent : null,
|
||||
community,
|
||||
});
|
||||
|
||||
await this.spaceRepository.save(newSpace);
|
||||
await queryRunner.manager.save(newSpace);
|
||||
|
||||
if (direction && parent) {
|
||||
await this.spaceLinkService.saveSpaceLink(
|
||||
@ -59,12 +80,34 @@ export class SpaceService {
|
||||
);
|
||||
}
|
||||
|
||||
if (subspaces?.length) {
|
||||
await this.subSpaceService.createSubspacesFromDto(
|
||||
subspaces,
|
||||
newSpace,
|
||||
queryRunner,
|
||||
);
|
||||
} else if (spaceModel && spaceModel.subspaceModels.length) {
|
||||
await this.subSpaceService.createSubSpaceFromModel(
|
||||
spaceModel,
|
||||
newSpace,
|
||||
queryRunner,
|
||||
);
|
||||
}
|
||||
|
||||
if (products && products.length > 0) {
|
||||
await this.spaceProductService.assignProductsToSpace(
|
||||
newSpace,
|
||||
products,
|
||||
queryRunner,
|
||||
);
|
||||
} else if (spaceModel && spaceModel.spaceProductModels.length) {
|
||||
await this.spaceProductService.createFromModel(
|
||||
spaceModel,
|
||||
newSpace,
|
||||
queryRunner,
|
||||
);
|
||||
}
|
||||
await queryRunner.commitTransaction();
|
||||
|
||||
return new SuccessResponseDto({
|
||||
statusCode: HttpStatus.CREATED,
|
||||
@ -72,7 +115,14 @@ export class SpaceService {
|
||||
message: 'Space created successfully',
|
||||
});
|
||||
} catch (error) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
|
||||
if (error instanceof HttpException) {
|
||||
throw error;
|
||||
}
|
||||
throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,8 +130,10 @@ export class SpaceService {
|
||||
params: CommunitySpaceParam,
|
||||
): Promise<BaseResponseDto> {
|
||||
const { communityUuid, projectUuid } = params;
|
||||
await this.validateCommunity(communityUuid);
|
||||
await this.validateProject(projectUuid);
|
||||
await this.validationService.validateCommunityAndProject(
|
||||
communityUuid,
|
||||
projectUuid,
|
||||
);
|
||||
try {
|
||||
// Get all spaces related to the community, including the parent-child relations
|
||||
const spaces = await this.spaceRepository.find({
|
||||
@ -114,11 +166,12 @@ export class SpaceService {
|
||||
async findOne(params: GetSpaceParam): Promise<BaseResponseDto> {
|
||||
const { communityUuid, spaceUuid, projectUuid } = params;
|
||||
try {
|
||||
const space = await this.validateCommunityAndSpace(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
);
|
||||
const space =
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
return new SuccessResponseDto({
|
||||
message: `Space with ID ${spaceUuid} successfully fetched`,
|
||||
@ -139,12 +192,13 @@ export class SpaceService {
|
||||
async delete(params: GetSpaceParam): Promise<BaseResponseDto> {
|
||||
try {
|
||||
const { communityUuid, spaceUuid, projectUuid } = params;
|
||||
// First, check if the community exists
|
||||
const space = await this.validateCommunityAndSpace(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
);
|
||||
|
||||
const space =
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
// Delete the space
|
||||
await this.spaceRepository.remove(space);
|
||||
@ -169,29 +223,39 @@ export class SpaceService {
|
||||
updateSpaceDto: UpdateSpaceDto,
|
||||
): Promise<BaseResponseDto> {
|
||||
const { communityUuid, spaceUuid, projectUuid } = params;
|
||||
const queryRunner = this.dataSource.createQueryRunner();
|
||||
|
||||
try {
|
||||
const space = await this.validateCommunityAndSpace(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
);
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
const space =
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
// If a parentId is provided, check if the parent exists
|
||||
const { parentUuid, products } = updateSpaceDto;
|
||||
const parent = parentUuid ? await this.validateSpace(parentUuid) : null;
|
||||
const parent = parentUuid
|
||||
? await this.validationService.validateSpace(parentUuid)
|
||||
: null;
|
||||
|
||||
// Update other space properties from updateSpaceDto
|
||||
Object.assign(space, updateSpaceDto, { parent });
|
||||
|
||||
// Save the updated space
|
||||
const updatedSpace = await this.spaceRepository.save(space);
|
||||
const updatedSpace = await queryRunner.manager.save(space);
|
||||
|
||||
if (products && products.length > 0) {
|
||||
await this.spaceProductService.assignProductsToSpace(
|
||||
updatedSpace,
|
||||
products,
|
||||
queryRunner,
|
||||
);
|
||||
}
|
||||
await queryRunner.commitTransaction();
|
||||
|
||||
return new SuccessResponseDto({
|
||||
message: `Space with ID ${spaceUuid} successfully updated`,
|
||||
@ -199,6 +263,8 @@ export class SpaceService {
|
||||
statusCode: HttpStatus.OK,
|
||||
});
|
||||
} catch (error) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
|
||||
if (error instanceof HttpException) {
|
||||
throw error;
|
||||
}
|
||||
@ -206,6 +272,8 @@ export class SpaceService {
|
||||
'An error occurred while updating the space',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +281,11 @@ export class SpaceService {
|
||||
params: GetSpaceParam,
|
||||
): Promise<BaseResponseDto> {
|
||||
const { spaceUuid, communityUuid, projectUuid } = params;
|
||||
await this.validateCommunityAndSpace(communityUuid, spaceUuid, projectUuid);
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
try {
|
||||
// Get all spaces that are children of the provided space, including the parent-child relations
|
||||
@ -243,11 +315,12 @@ export class SpaceService {
|
||||
try {
|
||||
const invitationCode = generateRandomString(6);
|
||||
|
||||
const space = await this.validateCommunityAndSpace(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
);
|
||||
const space =
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
space.invitationCode = invitationCode;
|
||||
await this.spaceRepository.save(space);
|
||||
@ -293,56 +366,16 @@ export class SpaceService {
|
||||
return rootSpaces;
|
||||
}
|
||||
|
||||
private async validateCommunity(communityId: string) {
|
||||
const community = await this.communityRepository.findOne({
|
||||
where: { uuid: communityId },
|
||||
});
|
||||
if (!community) {
|
||||
private validateSpaceCreation(
|
||||
spaceModelUuid?: string,
|
||||
products?: ProductAssignmentDto[],
|
||||
subSpaces?: CreateSubspaceModelDto[],
|
||||
) {
|
||||
if (spaceModelUuid && (products?.length || subSpaces?.length)) {
|
||||
throw new HttpException(
|
||||
`Community with ID ${communityId} not found`,
|
||||
HttpStatus.NOT_FOUND,
|
||||
'For space creation choose either space model or products and subspace',
|
||||
HttpStatus.CONFLICT,
|
||||
);
|
||||
}
|
||||
return community;
|
||||
}
|
||||
|
||||
async validateCommunityAndSpace(
|
||||
communityUuid: string,
|
||||
spaceUuid: string,
|
||||
projectUuid: string,
|
||||
) {
|
||||
await this.validateProject(projectUuid);
|
||||
|
||||
const community = await this.validateCommunity(communityUuid);
|
||||
if (!community) {
|
||||
this.throwNotFound('Community', communityUuid);
|
||||
}
|
||||
|
||||
const space = await this.validateSpace(spaceUuid);
|
||||
return space;
|
||||
}
|
||||
|
||||
private async validateSpace(spaceUuid: string) {
|
||||
const space = await this.spaceRepository.findOne({
|
||||
where: { uuid: spaceUuid },
|
||||
relations: ['devices', 'devices.productDevice'],
|
||||
});
|
||||
if (!space) this.throwNotFound('Space', spaceUuid);
|
||||
return space;
|
||||
}
|
||||
|
||||
private async validateProject(uuid: string) {
|
||||
const project = await this.projectRepository.findOne({
|
||||
where: { uuid },
|
||||
});
|
||||
|
||||
if (!project) this.throwNotFound('Project', uuid);
|
||||
}
|
||||
|
||||
private throwNotFound(entity: string, uuid: string) {
|
||||
throw new HttpException(
|
||||
`${entity} with ID ${uuid} not found`,
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,4 @@
|
||||
export * from './subspace.service';
|
||||
export * from './subspace-device.service';
|
||||
export * from './subspace-product-item.service';
|
||||
export * from './subspace-product.service';
|
||||
|
@ -1,29 +1,23 @@
|
||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||
import {
|
||||
SpaceRepository,
|
||||
SubspaceRepository,
|
||||
} from '@app/common/modules/space/repositories';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { DeviceSubSpaceParam, GetSubSpaceParam } from '../../dtos';
|
||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
|
||||
import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service';
|
||||
import { ProductRepository } from '@app/common/modules/product/repositories';
|
||||
import { GetDeviceDetailsInterface } from '../../../device/interfaces/get.device.interface';
|
||||
import { SpaceService } from '../space.service';
|
||||
import { ValidationService } from '../space-validation.service';
|
||||
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
||||
|
||||
@Injectable()
|
||||
export class SubspaceDeviceService {
|
||||
constructor(
|
||||
private readonly spaceRepository: SpaceRepository,
|
||||
private readonly communityRepository: CommunityRepository,
|
||||
private readonly subspaceRepository: SubspaceRepository,
|
||||
private readonly deviceRepository: DeviceRepository,
|
||||
private readonly tuyaService: TuyaService,
|
||||
private readonly productRepository: ProductRepository,
|
||||
private readonly spaceService: SpaceService,
|
||||
private readonly validationService: ValidationService,
|
||||
) {}
|
||||
|
||||
async listDevicesInSubspace(
|
||||
@ -31,10 +25,10 @@ export class SubspaceDeviceService {
|
||||
): Promise<BaseResponseDto> {
|
||||
const { subSpaceUuid, spaceUuid, communityUuid, projectUuid } = params;
|
||||
|
||||
await this.spaceService.validateCommunityAndSpace(
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
const subspace = await this.findSubspaceWithDevices(subSpaceUuid);
|
||||
@ -76,10 +70,10 @@ export class SubspaceDeviceService {
|
||||
const { subSpaceUuid, deviceUuid, spaceUuid, communityUuid, projectUuid } =
|
||||
params;
|
||||
try {
|
||||
await this.spaceService.validateCommunityAndSpace(
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
const subspace = await this.findSubspace(subSpaceUuid);
|
||||
@ -111,10 +105,10 @@ export class SubspaceDeviceService {
|
||||
const { subSpaceUuid, deviceUuid, spaceUuid, communityUuid, projectUuid } =
|
||||
params;
|
||||
try {
|
||||
await this.spaceService.validateCommunityAndSpace(
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
const subspace = await this.findSubspace(subSpaceUuid);
|
||||
|
92
src/space/services/subspace/subspace-product-item.service.ts
Normal file
92
src/space/services/subspace/subspace-product-item.service.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { QueryRunner } from 'typeorm';
|
||||
|
||||
import {
|
||||
SpaceEntity,
|
||||
SubspaceProductEntity,
|
||||
SubspaceProductItemEntity,
|
||||
} from '@app/common/modules/space';
|
||||
import {
|
||||
SubspaceProductItemModelEntity,
|
||||
SubspaceProductModelEntity,
|
||||
} from '@app/common/modules/space-model';
|
||||
import { SubspaceProductItemRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
||||
import { CreateSpaceProductItemDto } from '../../dtos';
|
||||
import { BaseProductItemService } from '../../common';
|
||||
|
||||
@Injectable()
|
||||
export class SubspaceProductItemService extends BaseProductItemService {
|
||||
constructor(
|
||||
private readonly productItemRepository: SubspaceProductItemRepository,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async createItemFromModel(
|
||||
product: SubspaceProductEntity,
|
||||
productModel: SubspaceProductModelEntity,
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<void> {
|
||||
const itemModels = productModel.itemModels;
|
||||
|
||||
if (!itemModels?.length) return;
|
||||
|
||||
try {
|
||||
const productItems = itemModels.map((model) =>
|
||||
this.createProductItem(product, model, queryRunner),
|
||||
);
|
||||
|
||||
await queryRunner.manager.save(
|
||||
this.productItemRepository.target,
|
||||
productItems,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'An error occurred while creating product items.',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private createProductItem(
|
||||
product: SubspaceProductEntity,
|
||||
model: SubspaceProductItemModelEntity,
|
||||
queryRunner: QueryRunner,
|
||||
): Partial<any> {
|
||||
return queryRunner.manager.create(this.productItemRepository.target, {
|
||||
tag: model.tag,
|
||||
product,
|
||||
model,
|
||||
});
|
||||
}
|
||||
|
||||
async createItemFromDtos(
|
||||
product: SubspaceProductEntity,
|
||||
itemDto: CreateSpaceProductItemDto[],
|
||||
queryRunner: QueryRunner,
|
||||
space: SpaceEntity,
|
||||
) {
|
||||
if (!itemDto?.length) return;
|
||||
const incomingTags = itemDto.map((item) => item.tag);
|
||||
await this.validateTags(incomingTags, queryRunner, space.uuid);
|
||||
|
||||
try {
|
||||
const productItems = itemDto.map((dto) =>
|
||||
queryRunner.manager.create(SubspaceProductItemEntity, {
|
||||
tag: dto.tag,
|
||||
subspaceProduct: product,
|
||||
}),
|
||||
);
|
||||
|
||||
await queryRunner.manager.save(
|
||||
this.productItemRepository.target,
|
||||
productItems,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
error.message || 'An error occurred while creating product items.',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
128
src/space/services/subspace/subspace-product.service.ts
Normal file
128
src/space/services/subspace/subspace-product.service.ts
Normal file
@ -0,0 +1,128 @@
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { QueryRunner } from 'typeorm';
|
||||
|
||||
import {
|
||||
SpaceEntity,
|
||||
SubspaceEntity,
|
||||
SubspaceProductEntity,
|
||||
} from '@app/common/modules/space';
|
||||
import {
|
||||
SubspaceModelEntity,
|
||||
SubspaceProductModelEntity,
|
||||
} from '@app/common/modules/space-model';
|
||||
import { SubspaceProductItemService } from './subspace-product-item.service';
|
||||
import { ProductAssignmentDto } from 'src/space/dtos';
|
||||
import { ProductService } from 'src/product/services';
|
||||
import { ProductEntity } from '@app/common/modules/product/entities';
|
||||
|
||||
@Injectable()
|
||||
export class SubspaceProductService {
|
||||
constructor(
|
||||
private readonly subspaceProductItemService: SubspaceProductItemService,
|
||||
private readonly productService: ProductService,
|
||||
) {}
|
||||
|
||||
async createFromModel(
|
||||
subspaceModel: SubspaceModelEntity,
|
||||
subspace: SubspaceEntity,
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<void> {
|
||||
const productModels = subspaceModel.productModels;
|
||||
if (!productModels?.length) return;
|
||||
|
||||
try {
|
||||
const newSpaceProducts = productModels.map((productModel) =>
|
||||
this.createSubspaceProductEntity(subspace, productModel),
|
||||
);
|
||||
|
||||
const subspaceProducts = await queryRunner.manager.save(
|
||||
SubspaceProductEntity,
|
||||
newSpaceProducts,
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
subspaceProducts.map((subspaceProduct, index) =>
|
||||
this.subspaceProductItemService.createItemFromModel(
|
||||
subspaceProduct,
|
||||
productModels[index],
|
||||
queryRunner,
|
||||
),
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
`Transaction failed: Unable to create subspace products ${error}`,
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private createSubspaceProductEntity(
|
||||
subspace: SubspaceEntity,
|
||||
productModel: SubspaceProductModelEntity,
|
||||
): Partial<SubspaceProductEntity> {
|
||||
return {
|
||||
subspace,
|
||||
product: productModel.product,
|
||||
productCount: productModel.productCount,
|
||||
model: productModel,
|
||||
};
|
||||
}
|
||||
|
||||
async createFromDto(
|
||||
productDtos: ProductAssignmentDto[],
|
||||
subspace: SubspaceEntity,
|
||||
queryRunner: QueryRunner,
|
||||
space: SpaceEntity,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const newSpaceProducts = await Promise.all(
|
||||
productDtos.map(async (dto) => {
|
||||
this.validateProductCount(dto);
|
||||
|
||||
const product = await this.getProduct(dto.productId);
|
||||
return queryRunner.manager.create(SubspaceProductEntity, {
|
||||
subspace,
|
||||
product,
|
||||
productCount: dto.count,
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
const subspaceProducts = await queryRunner.manager.save(
|
||||
SubspaceProductEntity,
|
||||
newSpaceProducts,
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
productDtos.map((dto, index) =>
|
||||
this.subspaceProductItemService.createItemFromDtos(
|
||||
subspaceProducts[index],
|
||||
dto.items,
|
||||
queryRunner,
|
||||
space,
|
||||
),
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
`Failed to create subspace products from DTOs. Error: ${error.message}`,
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async getProduct(productId: string): Promise<ProductEntity> {
|
||||
const product = await this.productService.findOne(productId);
|
||||
return product.data;
|
||||
}
|
||||
|
||||
async validateProductCount(dto: ProductAssignmentDto) {
|
||||
if (dto.count !== dto.items.length) {
|
||||
throw new HttpException(
|
||||
'Producy item and count doesnot match',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||
import { SubspaceRepository } from '@app/common/modules/space/repositories';
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import { AddSubspaceDto, GetSpaceParam, GetSubSpaceParam } from '../../dtos';
|
||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||
@ -9,25 +8,119 @@ import {
|
||||
} from '@app/common/models/typeOrmCustom.model';
|
||||
import { PageResponse } from '@app/common/dto/pagination.response.dto';
|
||||
import { SubspaceDto } from '@app/common/modules/space/dtos';
|
||||
import { SpaceService } from '../space.service';
|
||||
import { QueryRunner } from 'typeorm';
|
||||
import {
|
||||
SpaceEntity,
|
||||
SubspaceEntity,
|
||||
} from '@app/common/modules/space/entities';
|
||||
import {
|
||||
SpaceModelEntity,
|
||||
SubspaceModelEntity,
|
||||
} from '@app/common/modules/space-model';
|
||||
import { ValidationService } from '../space-validation.service';
|
||||
import { SubspaceRepository } from '@app/common/modules/space/repositories/subspace.repository';
|
||||
import { SubspaceProductService } from './subspace-product.service';
|
||||
|
||||
@Injectable()
|
||||
export class SubSpaceService {
|
||||
constructor(
|
||||
private readonly subspaceRepository: SubspaceRepository,
|
||||
private readonly spaceService: SpaceService,
|
||||
private readonly validationService: ValidationService,
|
||||
private readonly productService: SubspaceProductService,
|
||||
) {}
|
||||
|
||||
async createSubspaces(
|
||||
subspaceData: Array<{
|
||||
subspaceName: string;
|
||||
space: SpaceEntity;
|
||||
subSpaceModel?: SubspaceModelEntity;
|
||||
}>,
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<SubspaceEntity[]> {
|
||||
try {
|
||||
const subspaces = subspaceData.map((data) =>
|
||||
queryRunner.manager.create(this.subspaceRepository.target, data),
|
||||
);
|
||||
|
||||
return await queryRunner.manager.save(subspaces);
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
'An unexpected error occurred while creating subspaces.',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async createSubSpaceFromModel(
|
||||
spaceModel: SpaceModelEntity,
|
||||
space: SpaceEntity,
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<void> {
|
||||
const subSpaceModels = spaceModel.subspaceModels;
|
||||
|
||||
if (!subSpaceModels?.length) return;
|
||||
|
||||
const subspaceData = subSpaceModels.map((subSpaceModel) => ({
|
||||
subspaceName: subSpaceModel.subspaceName,
|
||||
space,
|
||||
subSpaceModel,
|
||||
}));
|
||||
|
||||
const subspaces = await this.createSubspaces(subspaceData, queryRunner);
|
||||
|
||||
await Promise.all(
|
||||
subSpaceModels.map((model, index) => {
|
||||
this.productService.createFromModel(
|
||||
model,
|
||||
subspaces[index],
|
||||
queryRunner,
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async createSubspacesFromDto(
|
||||
addSubspaceDtos: AddSubspaceDto[],
|
||||
space: SpaceEntity,
|
||||
queryRunner: QueryRunner,
|
||||
): Promise<SubspaceEntity[]> {
|
||||
try {
|
||||
const subspaceData = addSubspaceDtos.map((dto) => ({
|
||||
subspaceName: dto.subspaceName,
|
||||
space,
|
||||
}));
|
||||
|
||||
const subspaces = await this.createSubspaces(subspaceData, queryRunner);
|
||||
|
||||
await Promise.all(
|
||||
addSubspaceDtos.map((dto, index) =>
|
||||
this.productService.createFromDto(
|
||||
dto.products,
|
||||
subspaces[index],
|
||||
queryRunner,
|
||||
space,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return subspaces;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Transaction failed: Unable to create subspaces and products. ${error.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async createSubspace(
|
||||
addSubspaceDto: AddSubspaceDto,
|
||||
params: GetSpaceParam,
|
||||
): Promise<BaseResponseDto> {
|
||||
const { communityUuid, spaceUuid, projectUuid } = params;
|
||||
const space = await this.spaceService.validateCommunityAndSpace(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
);
|
||||
const space =
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
params.projectUuid,
|
||||
params.projectUuid,
|
||||
params.spaceUuid,
|
||||
);
|
||||
|
||||
try {
|
||||
const newSubspace = this.subspaceRepository.create({
|
||||
@ -52,10 +145,10 @@ export class SubSpaceService {
|
||||
pageable: Partial<TypeORMCustomModelFindAllQuery>,
|
||||
): Promise<BaseResponseDto> {
|
||||
const { communityUuid, spaceUuid, projectUuid } = params;
|
||||
await this.spaceService.validateCommunityAndSpace(
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -76,10 +169,10 @@ export class SubSpaceService {
|
||||
|
||||
async findOne(params: GetSubSpaceParam): Promise<BaseResponseDto> {
|
||||
const { communityUuid, subSpaceUuid, spaceUuid, projectUuid } = params;
|
||||
await this.spaceService.validateCommunityAndSpace(
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
try {
|
||||
const subSpace = await this.subspaceRepository.findOne({
|
||||
@ -116,12 +209,11 @@ export class SubSpaceService {
|
||||
updateSubSpaceDto: AddSubspaceDto,
|
||||
): Promise<BaseResponseDto> {
|
||||
const { spaceUuid, communityUuid, subSpaceUuid, projectUuid } = params;
|
||||
await this.spaceService.validateCommunityAndSpace(
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
const subSpace = await this.subspaceRepository.findOne({
|
||||
where: { uuid: subSpaceUuid },
|
||||
});
|
||||
@ -156,10 +248,10 @@ export class SubSpaceService {
|
||||
|
||||
async delete(params: GetSubSpaceParam): Promise<BaseResponseDto> {
|
||||
const { spaceUuid, communityUuid, subSpaceUuid, projectUuid } = params;
|
||||
await this.spaceService.validateCommunityAndSpace(
|
||||
await this.validationService.validateSpaceWithinCommunityAndProject(
|
||||
communityUuid,
|
||||
spaceUuid,
|
||||
projectUuid,
|
||||
spaceUuid,
|
||||
);
|
||||
|
||||
const subspace = await this.subspaceRepository.findOne({
|
||||
|
@ -12,18 +12,20 @@ import {
|
||||
import {
|
||||
SpaceDeviceService,
|
||||
SpaceLinkService,
|
||||
SpaceProductItemService,
|
||||
SpaceProductService,
|
||||
SpaceSceneService,
|
||||
SpaceService,
|
||||
SpaceUserService,
|
||||
SubspaceDeviceService,
|
||||
SubspaceProductItemService,
|
||||
SubSpaceService,
|
||||
} from './services';
|
||||
import {
|
||||
SpaceProductRepository,
|
||||
SpaceRepository,
|
||||
SubspaceRepository,
|
||||
SpaceLinkRepository,
|
||||
SpaceProductItemRepository,
|
||||
} from '@app/common/modules/space/repositories';
|
||||
import { CommunityRepository } from '@app/common/modules/community/repositories';
|
||||
import {
|
||||
@ -43,9 +45,18 @@ import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status
|
||||
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
|
||||
import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories';
|
||||
import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||
import { SpaceModelRepository } from '@app/common/modules/space-model';
|
||||
import { CommunityModule } from 'src/community/community.module';
|
||||
import { ValidationService } from './services';
|
||||
import {
|
||||
SubspaceProductItemRepository,
|
||||
SubspaceProductRepository,
|
||||
SubspaceRepository,
|
||||
} from '@app/common/modules/space/repositories/subspace.repository';
|
||||
import { SubspaceProductService } from './services';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule, SpaceRepositoryModule],
|
||||
imports: [ConfigModule, SpaceRepositoryModule, CommunityModule],
|
||||
controllers: [
|
||||
SpaceController,
|
||||
SpaceUserController,
|
||||
@ -55,6 +66,7 @@ import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||
SpaceSceneController,
|
||||
],
|
||||
providers: [
|
||||
ValidationService,
|
||||
SpaceService,
|
||||
TuyaService,
|
||||
ProductRepository,
|
||||
@ -76,11 +88,19 @@ import { ProjectRepository } from '@app/common/modules/project/repositiories';
|
||||
SceneRepository,
|
||||
DeviceService,
|
||||
DeviceStatusFirebaseService,
|
||||
SubspaceProductItemRepository,
|
||||
DeviceStatusLogRepository,
|
||||
SceneDeviceRepository,
|
||||
SpaceProductService,
|
||||
SpaceProductRepository,
|
||||
ProjectRepository,
|
||||
SpaceModelRepository,
|
||||
SubspaceRepository,
|
||||
SpaceProductItemService,
|
||||
SpaceProductItemRepository,
|
||||
SubspaceProductService,
|
||||
SubspaceProductItemService,
|
||||
SubspaceProductRepository,
|
||||
],
|
||||
exports: [SpaceService],
|
||||
})
|
||||
|
Reference in New Issue
Block a user