From f8278aa40e946fb6f46f87480e0f6e88b21bb385 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Tue, 29 Jul 2025 21:03:40 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Modules=20Sites=20et=20Types=20-=20Ajou?= =?UTF-8?q?t=20des=20modules=20de=20gestion=20des=20sites=20et=20des=20typ?= =?UTF-8?q?es=20de=20machines/composants/pi=C3=A8ces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sites/sites.controller.spec.ts | 21 +++ src/sites/sites.controller.ts | 33 ++++ src/sites/sites.module.ts | 9 + src/sites/sites.service.spec.ts | 19 ++ src/sites/sites.service.ts | 82 +++++++++ src/types/types.controller.spec.ts | 21 +++ src/types/types.controller.ts | 93 ++++++++++ src/types/types.module.ts | 9 + src/types/types.service.spec.ts | 19 ++ src/types/types.service.ts | 280 +++++++++++++++++++++++++++++ 10 files changed, 586 insertions(+) create mode 100644 src/sites/sites.controller.spec.ts create mode 100644 src/sites/sites.controller.ts create mode 100644 src/sites/sites.module.ts create mode 100644 src/sites/sites.service.spec.ts create mode 100644 src/sites/sites.service.ts create mode 100644 src/types/types.controller.spec.ts create mode 100644 src/types/types.controller.ts create mode 100644 src/types/types.module.ts create mode 100644 src/types/types.service.spec.ts create mode 100644 src/types/types.service.ts diff --git a/src/sites/sites.controller.spec.ts b/src/sites/sites.controller.spec.ts new file mode 100644 index 0000000..00ce880 --- /dev/null +++ b/src/sites/sites.controller.spec.ts @@ -0,0 +1,21 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SitesController } from './sites.controller'; +import { SitesService } from './sites.service'; +import { PrismaService } from '../prisma/prisma.service'; + +describe('SitesController', () => { + let controller: SitesController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [SitesController], + providers: [SitesService, PrismaService], + }).compile(); + + controller = module.get(SitesController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/sites/sites.controller.ts b/src/sites/sites.controller.ts new file mode 100644 index 0000000..0adf2cc --- /dev/null +++ b/src/sites/sites.controller.ts @@ -0,0 +1,33 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; +import { SitesService } from './sites.service'; +import { CreateSiteDto, UpdateSiteDto } from '../shared/dto/site.dto'; + +@Controller('sites') +export class SitesController { + constructor(private readonly sitesService: SitesService) {} + + @Post() + create(@Body() createSiteDto: CreateSiteDto) { + return this.sitesService.create(createSiteDto); + } + + @Get() + findAll() { + return this.sitesService.findAll(); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.sitesService.findOne(id); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() updateSiteDto: UpdateSiteDto) { + return this.sitesService.update(id, updateSiteDto); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.sitesService.remove(id); + } +} diff --git a/src/sites/sites.module.ts b/src/sites/sites.module.ts new file mode 100644 index 0000000..a6291b0 --- /dev/null +++ b/src/sites/sites.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { SitesController } from './sites.controller'; +import { SitesService } from './sites.service'; + +@Module({ + controllers: [SitesController], + providers: [SitesService] +}) +export class SitesModule {} diff --git a/src/sites/sites.service.spec.ts b/src/sites/sites.service.spec.ts new file mode 100644 index 0000000..8ff7edf --- /dev/null +++ b/src/sites/sites.service.spec.ts @@ -0,0 +1,19 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SitesService } from './sites.service'; +import { PrismaService } from '../prisma/prisma.service'; + +describe('SitesService', () => { + let service: SitesService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [SitesService, PrismaService], + }).compile(); + + service = module.get(SitesService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/sites/sites.service.ts b/src/sites/sites.service.ts new file mode 100644 index 0000000..ab71d98 --- /dev/null +++ b/src/sites/sites.service.ts @@ -0,0 +1,82 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { CreateSiteDto, UpdateSiteDto } from '../shared/dto/site.dto'; + +@Injectable() +export class SitesService { + constructor(private prisma: PrismaService) {} + + async create(createSiteDto: CreateSiteDto) { + return this.prisma.site.create({ + data: createSiteDto, + }); + } + + async findAll() { + return this.prisma.site.findMany({ + include: { + machines: { + include: { + typeMachine: true, + composants: { + include: { + typeComposant: true, + sousComposants: true, + pieces: true, + }, + }, + pieces: true, + }, + }, + }, + }); + } + + async findOne(id: string) { + return this.prisma.site.findUnique({ + where: { id }, + include: { + machines: { + include: { + typeMachine: true, + composants: { + include: { + typeComposant: true, + sousComposants: true, + pieces: true, + }, + }, + pieces: true, + }, + }, + }, + }); + } + + async update(id: string, updateSiteDto: UpdateSiteDto) { + return this.prisma.site.update({ + where: { id }, + data: updateSiteDto, + }); + } + + async remove(id: string) { + // Vérifier s'il y a des machines liées à ce site + const machinesInSite = await this.prisma.machine.findMany({ + where: { siteId: id }, + select: { id: true, name: true }, + }); + + if (machinesInSite.length > 0) { + const machineNames = machinesInSite.map(m => m.name).join(', '); + throw new Error( + `Impossible de supprimer ce site car il contient ${machinesInSite.length} machine(s): ${machineNames}. ` + + `Veuillez d'abord supprimer ou déplacer ces machines vers un autre site.` + ); + } + + return this.prisma.site.delete({ + where: { id }, + }); + } +} diff --git a/src/types/types.controller.spec.ts b/src/types/types.controller.spec.ts new file mode 100644 index 0000000..1072fa3 --- /dev/null +++ b/src/types/types.controller.spec.ts @@ -0,0 +1,21 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TypesController } from './types.controller'; +import { TypesService } from './types.service'; +import { PrismaService } from '../prisma/prisma.service'; + +describe('TypesController', () => { + let controller: TypesController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [TypesController], + providers: [TypesService, PrismaService], + }).compile(); + + controller = module.get(TypesController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/types/types.controller.ts b/src/types/types.controller.ts new file mode 100644 index 0000000..1c5b9b1 --- /dev/null +++ b/src/types/types.controller.ts @@ -0,0 +1,93 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; +import { TypesService } from './types.service'; +import { + CreateTypeMachineDto, + UpdateTypeMachineDto, + CreateTypeComposantDto, + UpdateTypeComposantDto, + CreateTypePieceDto, + UpdateTypePieceDto +} from '../shared/dto/type.dto'; + +@Controller('types') +export class TypesController { + constructor(private readonly typesService: TypesService) {} + + // TypeMachine routes + @Post('machines') + createTypeMachine(@Body() createTypeMachineDto: CreateTypeMachineDto) { + return this.typesService.createTypeMachine(createTypeMachineDto); + } + + @Get('machines') + findAllTypeMachines() { + return this.typesService.findAllTypeMachines(); + } + + @Get('machines/:id') + findOneTypeMachine(@Param('id') id: string) { + return this.typesService.findOneTypeMachine(id); + } + + @Patch('machines/:id') + updateTypeMachine(@Param('id') id: string, @Body() updateTypeMachineDto: UpdateTypeMachineDto) { + return this.typesService.updateTypeMachine(id, updateTypeMachineDto); + } + + @Delete('machines/:id') + removeTypeMachine(@Param('id') id: string) { + return this.typesService.removeTypeMachine(id); + } + + // TypeComposant routes + @Post('composants') + createTypeComposant(@Body() createTypeComposantDto: CreateTypeComposantDto) { + return this.typesService.createTypeComposant(createTypeComposantDto); + } + + @Get('composants') + findAllTypeComposants() { + return this.typesService.findAllTypeComposants(); + } + + @Get('composants/:id') + findOneTypeComposant(@Param('id') id: string) { + return this.typesService.findOneTypeComposant(id); + } + + @Patch('composants/:id') + updateTypeComposant(@Param('id') id: string, @Body() updateTypeComposantDto: UpdateTypeComposantDto) { + return this.typesService.updateTypeComposant(id, updateTypeComposantDto); + } + + @Delete('composants/:id') + removeTypeComposant(@Param('id') id: string) { + return this.typesService.removeTypeComposant(id); + } + + // TypePiece routes + @Post('pieces') + createTypePiece(@Body() createTypePieceDto: CreateTypePieceDto) { + return this.typesService.createTypePiece(createTypePieceDto); + } + + @Get('pieces') + findAllTypePieces() { + return this.typesService.findAllTypePieces(); + } + + @Get('pieces/:id') + findOneTypePiece(@Param('id') id: string) { + return this.typesService.findOneTypePiece(id); + } + + @Patch('pieces/:id') + updateTypePiece(@Param('id') id: string, @Body() updateTypePieceDto: UpdateTypePieceDto) { + return this.typesService.updateTypePiece(id, updateTypePieceDto); + } + + @Delete('pieces/:id') + removeTypePiece(@Param('id') id: string) { + return this.typesService.removeTypePiece(id); + } +} diff --git a/src/types/types.module.ts b/src/types/types.module.ts new file mode 100644 index 0000000..91755f0 --- /dev/null +++ b/src/types/types.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { TypesController } from './types.controller'; +import { TypesService } from './types.service'; + +@Module({ + controllers: [TypesController], + providers: [TypesService] +}) +export class TypesModule {} diff --git a/src/types/types.service.spec.ts b/src/types/types.service.spec.ts new file mode 100644 index 0000000..ade99ca --- /dev/null +++ b/src/types/types.service.spec.ts @@ -0,0 +1,19 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TypesService } from './types.service'; +import { PrismaService } from '../prisma/prisma.service'; + +describe('TypesService', () => { + let service: TypesService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [TypesService, PrismaService], + }).compile(); + + service = module.get(TypesService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/types/types.service.ts b/src/types/types.service.ts new file mode 100644 index 0000000..891e61f --- /dev/null +++ b/src/types/types.service.ts @@ -0,0 +1,280 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../prisma/prisma.service'; +import { + CreateTypeMachineDto, + UpdateTypeMachineDto, + CreateTypeComposantDto, + UpdateTypeComposantDto, + CreateTypePieceDto, + UpdateTypePieceDto +} from '../shared/dto/type.dto'; + +@Injectable() +export class TypesService { + constructor(private prisma: PrismaService) {} + + // TypeMachine methods + async createTypeMachine(createTypeMachineDto: CreateTypeMachineDto) { + const { customFields, ...typeData } = createTypeMachineDto; + + return this.prisma.typeMachine.create({ + data: { + ...typeData, + customFields: customFields ? { + create: customFields.map(field => ({ + name: field.name, + type: field.type, + required: field.required || false, + defaultValue: field.defaultValue, + options: field.options + })) + } : undefined + }, + include: { + customFields: true, + }, + }); + } + + async findAllTypeMachines() { + return this.prisma.typeMachine.findMany({ + include: { + machines: true, + customFields: true, + }, + }); + } + + async findOneTypeMachine(id: string) { + return this.prisma.typeMachine.findUnique({ + where: { id }, + include: { + machines: true, + customFields: true, + }, + }); + } + + async updateTypeMachine(id: string, updateTypeMachineDto: UpdateTypeMachineDto) { + const { customFields, ...typeData } = updateTypeMachineDto; + + // Si des champs personnalisés sont fournis, on les met à jour + if (customFields !== undefined) { + // Supprimer tous les champs personnalisés existants + await this.prisma.customField.deleteMany({ + where: { typeMachineId: id } + }); + + // Créer les nouveaux champs personnalisés + if (customFields.length > 0) { + await this.prisma.customField.createMany({ + data: customFields.map(field => ({ + name: field.name, + type: field.type, + required: field.required || false, + defaultValue: field.defaultValue, + options: field.options, + typeMachineId: id + })) + }); + } + } + + return this.prisma.typeMachine.update({ + where: { id }, + data: typeData, + include: { + customFields: true, + }, + }); + } + + async removeTypeMachine(id: string) { + // Vérifier s'il y a des machines liées à ce type + const machinesWithType = await this.prisma.machine.findMany({ + where: { typeMachineId: id }, + select: { id: true, name: true }, + }); + + if (machinesWithType.length > 0) { + const machineNames = machinesWithType.map(m => m.name).join(', '); + throw new Error( + `Impossible de supprimer ce type de machine car il est utilisé par ${machinesWithType.length} machine(s): ${machineNames}. ` + + `Veuillez d'abord supprimer ou modifier ces machines.` + ); + } + + // Supprimer les champs personnalisés associés + await this.prisma.customField.deleteMany({ + where: { typeMachineId: id }, + }); + + return this.prisma.typeMachine.delete({ + where: { id }, + }); + } + + // TypeComposant methods + async createTypeComposant(createTypeComposantDto: CreateTypeComposantDto) { + const { customFields, ...typeData } = createTypeComposantDto; + + return this.prisma.typeComposant.create({ + data: { + ...typeData, + customFields: customFields ? { + create: customFields.map(field => ({ + name: field.name, + type: field.type, + required: field.required || false, + defaultValue: field.defaultValue, + options: field.options + })) + } : undefined + }, + include: { + customFields: true, + }, + }); + } + + async findAllTypeComposants() { + return this.prisma.typeComposant.findMany({ + include: { + composants: true, + customFields: true, + }, + }); + } + + async findOneTypeComposant(id: string) { + return this.prisma.typeComposant.findUnique({ + where: { id }, + include: { + composants: true, + customFields: true, + }, + }); + } + + async updateTypeComposant(id: string, updateTypeComposantDto: UpdateTypeComposantDto) { + const { customFields, ...typeData } = updateTypeComposantDto; + + // Si des champs personnalisés sont fournis, on les met à jour + if (customFields !== undefined) { + // Supprimer tous les champs personnalisés existants + await this.prisma.customField.deleteMany({ + where: { typeComposantId: id } + }); + + // Créer les nouveaux champs personnalisés + if (customFields.length > 0) { + await this.prisma.customField.createMany({ + data: customFields.map(field => ({ + name: field.name, + type: field.type, + required: field.required || false, + defaultValue: field.defaultValue, + options: field.options, + typeComposantId: id + })) + }); + } + } + + return this.prisma.typeComposant.update({ + where: { id }, + data: typeData, + include: { + customFields: true, + }, + }); + } + + async removeTypeComposant(id: string) { + return this.prisma.typeComposant.delete({ + where: { id }, + }); + } + + // TypePiece methods + async createTypePiece(createTypePieceDto: CreateTypePieceDto) { + const { customFields, ...typeData } = createTypePieceDto; + + return this.prisma.typePiece.create({ + data: { + ...typeData, + customFields: customFields ? { + create: customFields.map(field => ({ + name: field.name, + type: field.type, + required: field.required || false, + defaultValue: field.defaultValue, + options: field.options + })) + } : undefined + }, + include: { + customFields: true, + }, + }); + } + + async findAllTypePieces() { + return this.prisma.typePiece.findMany({ + include: { + pieces: true, + customFields: true, + }, + }); + } + + async findOneTypePiece(id: string) { + return this.prisma.typePiece.findUnique({ + where: { id }, + include: { + pieces: true, + customFields: true, + }, + }); + } + + async updateTypePiece(id: string, updateTypePieceDto: UpdateTypePieceDto) { + const { customFields, ...typeData } = updateTypePieceDto; + + // Si des champs personnalisés sont fournis, on les met à jour + if (customFields !== undefined) { + // Supprimer tous les champs personnalisés existants + await this.prisma.customField.deleteMany({ + where: { typePieceId: id } + }); + + // Créer les nouveaux champs personnalisés + if (customFields.length > 0) { + await this.prisma.customField.createMany({ + data: customFields.map(field => ({ + name: field.name, + type: field.type, + required: field.required || false, + defaultValue: field.defaultValue, + options: field.options, + typePieceId: id + })) + }); + } + } + + return this.prisma.typePiece.update({ + where: { id }, + data: typeData, + include: { + customFields: true, + }, + }); + } + + async removeTypePiece(id: string) { + return this.prisma.typePiece.delete({ + where: { id }, + }); + } +}