feat: Modules Sites et Types - Ajout des modules de gestion des sites et des types de machines/composants/pièces

This commit is contained in:
Matthieu
2025-07-29 21:03:40 +02:00
parent 20668dd770
commit f8278aa40e
10 changed files with 586 additions and 0 deletions

View File

@@ -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>(SitesController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@@ -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);
}
}

View File

@@ -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 {}

View File

@@ -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>(SitesService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -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 },
});
}
}

View File

@@ -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>(TypesController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@@ -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);
}
}

View File

@@ -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 {}

View File

@@ -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>(TypesService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

280
src/types/types.service.ts Normal file
View File

@@ -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 },
});
}
}