feat(machine): support skeleton reconfiguration
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
|
||||
import { MachinesService } from './machines.service';
|
||||
import { CreateMachineDto, UpdateMachineDto } from '../shared/dto/machine.dto';
|
||||
import {
|
||||
CreateMachineDto,
|
||||
UpdateMachineDto,
|
||||
ReconfigureMachineDto,
|
||||
} from '../shared/dto/machine.dto';
|
||||
|
||||
@Controller('machines')
|
||||
export class MachinesController {
|
||||
@@ -26,6 +30,14 @@ export class MachinesController {
|
||||
return this.machinesService.update(id, updateMachineDto);
|
||||
}
|
||||
|
||||
@Patch(':id/skeleton')
|
||||
reconfigure(
|
||||
@Param('id') id: string,
|
||||
@Body() reconfigureMachineDto: ReconfigureMachineDto,
|
||||
) {
|
||||
return this.machinesService.reconfigure(id, reconfigureMachineDto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
remove(@Param('id') id: string) {
|
||||
return this.machinesService.remove(id);
|
||||
|
||||
@@ -1,53 +1,125 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import {
|
||||
CreateMachineDto,
|
||||
import {
|
||||
CreateMachineDto,
|
||||
UpdateMachineDto,
|
||||
ReconfigureMachineDto,
|
||||
MachineComponentSelectionDto,
|
||||
MachinePieceSelectionDto
|
||||
MachinePieceSelectionDto,
|
||||
} from '../shared/dto/machine.dto';
|
||||
|
||||
const TYPE_MACHINE_CONFIGURATION_INCLUDE = {
|
||||
customFields: true,
|
||||
componentRequirements: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
pieceRequirements: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const MACHINE_DEFAULT_INCLUDE = {
|
||||
site: true,
|
||||
typeMachine: {
|
||||
include: TYPE_MACHINE_CONFIGURATION_INCLUDE,
|
||||
},
|
||||
constructeur: true,
|
||||
composants: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
composantModel: true,
|
||||
typeMachineComponentRequirement: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
sousComposants: true,
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
pieces: {
|
||||
include: {
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pieces: {
|
||||
include: {
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
documents: true,
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class MachinesService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
|
||||
async create(createMachineDto: CreateMachineDto) {
|
||||
const {
|
||||
componentSelections = [],
|
||||
pieceSelections = [],
|
||||
...machineData
|
||||
} = createMachineDto;
|
||||
|
||||
if (!machineData.typeMachineId) {
|
||||
throw new Error('typeMachineId est requis pour créer une machine à partir d\'un squelette.');
|
||||
}
|
||||
|
||||
private async getTypeMachineConfiguration(typeMachineId: string) {
|
||||
const typeMachine = await this.prisma.typeMachine.findUnique({
|
||||
where: { id: machineData.typeMachineId },
|
||||
include: {
|
||||
customFields: true,
|
||||
componentRequirements: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
pieceRequirements: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
where: { id: typeMachineId },
|
||||
include: TYPE_MACHINE_CONFIGURATION_INCLUDE,
|
||||
});
|
||||
|
||||
if (!typeMachine) {
|
||||
throw new Error('Type de machine non trouvé');
|
||||
}
|
||||
|
||||
return typeMachine;
|
||||
}
|
||||
|
||||
private async buildConfigurationContext(
|
||||
typeMachine: any,
|
||||
componentSelections: MachineComponentSelectionDto[],
|
||||
pieceSelections: MachinePieceSelectionDto[],
|
||||
) {
|
||||
const componentRequirements = (Array.isArray(typeMachine.componentRequirements)
|
||||
? typeMachine.componentRequirements
|
||||
: []) as any[];
|
||||
const pieceRequirements = (Array.isArray(typeMachine.pieceRequirements)
|
||||
? typeMachine.pieceRequirements
|
||||
: []) as any[];
|
||||
|
||||
const componentRequirementMap = new Map(
|
||||
typeMachine.componentRequirements.map((requirement) => [requirement.id, requirement]),
|
||||
componentRequirements.map((requirement: any) => [requirement.id, requirement]),
|
||||
);
|
||||
const pieceRequirementMap = new Map(
|
||||
typeMachine.pieceRequirements.map((requirement) => [requirement.id, requirement]),
|
||||
pieceRequirements.map((requirement: any) => [requirement.id, requirement]),
|
||||
);
|
||||
|
||||
const componentSelectionMap = new Map<string, MachineComponentSelectionDto[]>();
|
||||
@@ -94,7 +166,7 @@ export class MachinesService {
|
||||
: [];
|
||||
const pieceModelMap = new Map(pieceModels.map((model) => [model.id, model]));
|
||||
|
||||
for (const requirement of typeMachine.componentRequirements) {
|
||||
for (const requirement of componentRequirements) {
|
||||
const selections = componentSelectionMap.get(requirement.id) ?? [];
|
||||
const min = requirement.minCount ?? (requirement.required ? 1 : 0);
|
||||
const max = requirement.maxCount ?? undefined;
|
||||
@@ -121,7 +193,7 @@ export class MachinesService {
|
||||
}
|
||||
}
|
||||
|
||||
for (const requirement of typeMachine.pieceRequirements) {
|
||||
for (const requirement of pieceRequirements) {
|
||||
const selections = pieceSelectionMap.get(requirement.id) ?? [];
|
||||
const min = requirement.minCount ?? (requirement.required ? 1 : 0);
|
||||
const max = requirement.maxCount ?? undefined;
|
||||
@@ -186,7 +258,42 @@ export class MachinesService {
|
||||
}
|
||||
}
|
||||
|
||||
return await this.prisma.$transaction(async (prisma) => {
|
||||
return {
|
||||
componentSelectionMap,
|
||||
pieceSelectionMap,
|
||||
componentModelMap,
|
||||
pieceModelMap,
|
||||
};
|
||||
}
|
||||
|
||||
async create(createMachineDto: CreateMachineDto) {
|
||||
const {
|
||||
componentSelections = [],
|
||||
pieceSelections = [],
|
||||
...machineData
|
||||
} = createMachineDto;
|
||||
|
||||
if (!machineData.typeMachineId) {
|
||||
throw new Error('typeMachineId est requis pour créer une machine à partir d\'un squelette.');
|
||||
}
|
||||
|
||||
const typeMachine = await this.getTypeMachineConfiguration(machineData.typeMachineId);
|
||||
|
||||
const {
|
||||
componentSelectionMap,
|
||||
pieceSelectionMap,
|
||||
componentModelMap,
|
||||
pieceModelMap,
|
||||
} = await this.buildConfigurationContext(typeMachine, componentSelections, pieceSelections);
|
||||
|
||||
const componentRequirements = (Array.isArray(typeMachine.componentRequirements)
|
||||
? typeMachine.componentRequirements
|
||||
: []) as any[];
|
||||
const pieceRequirements = (Array.isArray(typeMachine.pieceRequirements)
|
||||
? typeMachine.pieceRequirements
|
||||
: []) as any[];
|
||||
|
||||
return this.prisma.$transaction(async (prisma) => {
|
||||
const machine = await prisma.machine.create({
|
||||
data: machineData,
|
||||
include: {
|
||||
@@ -196,8 +303,8 @@ export class MachinesService {
|
||||
},
|
||||
});
|
||||
|
||||
if (typeMachine.componentRequirements.length > 0) {
|
||||
for (const requirement of typeMachine.componentRequirements) {
|
||||
if (componentRequirements.length > 0) {
|
||||
for (const requirement of componentRequirements) {
|
||||
const selections = componentSelectionMap.get(requirement.id) ?? [];
|
||||
for (const selection of selections) {
|
||||
const model = selection.componentModelId ? componentModelMap.get(selection.componentModelId) : undefined;
|
||||
@@ -212,8 +319,8 @@ export class MachinesService {
|
||||
}
|
||||
}
|
||||
|
||||
if (typeMachine.pieceRequirements.length > 0) {
|
||||
for (const requirement of typeMachine.pieceRequirements) {
|
||||
if (pieceRequirements.length > 0) {
|
||||
for (const requirement of pieceRequirements) {
|
||||
const selections = pieceSelectionMap.get(requirement.id) ?? [];
|
||||
for (const selection of selections) {
|
||||
const model = selection.pieceModelId ? pieceModelMap.get(selection.pieceModelId) : undefined;
|
||||
@@ -234,76 +341,7 @@ export class MachinesService {
|
||||
|
||||
return prisma.machine.findUnique({
|
||||
where: { id: machine.id },
|
||||
include: {
|
||||
site: true,
|
||||
typeMachine: {
|
||||
include: {
|
||||
customFields: true,
|
||||
componentRequirements: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
pieceRequirements: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
composants: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
composantModel: true,
|
||||
typeMachineComponentRequirement: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
sousComposants: true,
|
||||
pieces: {
|
||||
include: {
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
},
|
||||
},
|
||||
pieces: {
|
||||
include: {
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
documents: true,
|
||||
},
|
||||
include: MACHINE_DEFAULT_INCLUDE,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -660,239 +698,146 @@ export class MachinesService {
|
||||
|
||||
async findAll() {
|
||||
return this.prisma.machine.findMany({
|
||||
include: {
|
||||
site: true,
|
||||
typeMachine: {
|
||||
include: {
|
||||
customFields: true,
|
||||
componentRequirements: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
pieceRequirements: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
composants: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
composantModel: true,
|
||||
typeMachineComponentRequirement: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
sousComposants: true,
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
pieces: {
|
||||
include: {
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pieces: {
|
||||
include: {
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
documents: true,
|
||||
},
|
||||
include: MACHINE_DEFAULT_INCLUDE,
|
||||
});
|
||||
}
|
||||
|
||||
async findOne(id: string) {
|
||||
return this.prisma.machine.findUnique({
|
||||
where: { id },
|
||||
include: MACHINE_DEFAULT_INCLUDE,
|
||||
});
|
||||
}
|
||||
|
||||
async reconfigure(id: string, reconfigureMachineDto: ReconfigureMachineDto) {
|
||||
const {
|
||||
componentSelections = [],
|
||||
pieceSelections = [],
|
||||
} = reconfigureMachineDto;
|
||||
|
||||
const machine = await this.prisma.machine.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
site: true,
|
||||
typeMachine: {
|
||||
include: {
|
||||
customFields: true,
|
||||
componentRequirements: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
pieceRequirements: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
include: TYPE_MACHINE_CONFIGURATION_INCLUDE,
|
||||
},
|
||||
constructeur: true,
|
||||
composants: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
composantModel: true,
|
||||
typeMachineComponentRequirement: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
sousComposants: true,
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
pieces: {
|
||||
include: {
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pieces: {
|
||||
include: {
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
documents: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!machine) {
|
||||
throw new Error('Machine non trouvée');
|
||||
}
|
||||
|
||||
if (!machine.typeMachineId || !machine.typeMachine) {
|
||||
throw new Error('Impossible de reconfigurer une machine sans type de machine associé.');
|
||||
}
|
||||
|
||||
const typeMachine = machine.typeMachine;
|
||||
|
||||
const {
|
||||
componentSelectionMap,
|
||||
pieceSelectionMap,
|
||||
componentModelMap,
|
||||
pieceModelMap,
|
||||
} = await this.buildConfigurationContext(typeMachine, componentSelections, pieceSelections);
|
||||
|
||||
const componentRequirements = (Array.isArray(typeMachine.componentRequirements)
|
||||
? typeMachine.componentRequirements
|
||||
: []) as any[];
|
||||
const pieceRequirements = (Array.isArray(typeMachine.pieceRequirements)
|
||||
? typeMachine.pieceRequirements
|
||||
: []) as any[];
|
||||
|
||||
return this.prisma.$transaction(async (prisma) => {
|
||||
await prisma.customFieldValue.deleteMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
composant: {
|
||||
machineId: id,
|
||||
typeMachineComponentRequirementId: { not: null },
|
||||
},
|
||||
},
|
||||
{
|
||||
piece: {
|
||||
machineId: id,
|
||||
typeMachinePieceRequirementId: { not: null },
|
||||
},
|
||||
},
|
||||
{
|
||||
piece: {
|
||||
composant: {
|
||||
machineId: id,
|
||||
typeMachineComponentRequirementId: { not: null },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.piece.deleteMany({
|
||||
where: {
|
||||
machineId: id,
|
||||
typeMachinePieceRequirementId: { not: null },
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.composant.deleteMany({
|
||||
where: {
|
||||
machineId: id,
|
||||
typeMachineComponentRequirementId: { not: null },
|
||||
},
|
||||
});
|
||||
|
||||
if (componentRequirements.length > 0) {
|
||||
for (const requirement of componentRequirements) {
|
||||
const selections = componentSelectionMap.get(requirement.id) ?? [];
|
||||
for (const selection of selections) {
|
||||
const model = selection.componentModelId
|
||||
? componentModelMap.get(selection.componentModelId)
|
||||
: undefined;
|
||||
const definition = this.normalizeComponentSelection(selection, requirement, model);
|
||||
await this.createComponentsFromType(prisma, id, [definition]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const legacyComponents = (typeMachine as any).components;
|
||||
if (legacyComponents) {
|
||||
await this.createComponentsFromType(prisma, id, legacyComponents);
|
||||
}
|
||||
}
|
||||
|
||||
if (pieceRequirements.length > 0) {
|
||||
for (const requirement of pieceRequirements) {
|
||||
const selections = pieceSelectionMap.get(requirement.id) ?? [];
|
||||
for (const selection of selections) {
|
||||
const model = selection.pieceModelId
|
||||
? pieceModelMap.get(selection.pieceModelId)
|
||||
: undefined;
|
||||
const definition = this.normalizePieceSelection(selection, requirement, model);
|
||||
await this.createMachinePiecesFromType(prisma, id, [definition]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const legacyPieces = (typeMachine as any).machinePieces;
|
||||
if (legacyPieces) {
|
||||
await this.createMachinePiecesFromType(prisma, id, legacyPieces);
|
||||
}
|
||||
}
|
||||
|
||||
return prisma.machine.findUnique({
|
||||
where: { id },
|
||||
include: MACHINE_DEFAULT_INCLUDE,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async update(id: string, updateMachineDto: UpdateMachineDto) {
|
||||
return this.prisma.machine.update({
|
||||
where: { id },
|
||||
data: updateMachineDto,
|
||||
include: {
|
||||
site: true,
|
||||
typeMachine: {
|
||||
include: {
|
||||
customFields: true,
|
||||
componentRequirements: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
pieceRequirements: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
constructeur: true,
|
||||
composants: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
composantModel: true,
|
||||
typeMachineComponentRequirement: {
|
||||
include: {
|
||||
typeComposant: true,
|
||||
},
|
||||
},
|
||||
sousComposants: true,
|
||||
constructeur: true,
|
||||
pieces: {
|
||||
include: {
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pieces: {
|
||||
include: {
|
||||
constructeur: true,
|
||||
pieceModel: true,
|
||||
typeMachinePieceRequirement: {
|
||||
include: {
|
||||
typePiece: true,
|
||||
},
|
||||
},
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
customFieldValues: {
|
||||
include: {
|
||||
customField: true,
|
||||
},
|
||||
},
|
||||
documents: true,
|
||||
},
|
||||
include: MACHINE_DEFAULT_INCLUDE,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -90,4 +90,18 @@ export class UpdateMachineDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
typeMachineId?: string;
|
||||
}
|
||||
}
|
||||
|
||||
export class ReconfigureMachineDto {
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => MachineComponentSelectionDto)
|
||||
componentSelections?: MachineComponentSelectionDto[];
|
||||
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => MachinePieceSelectionDto)
|
||||
pieceSelections?: MachinePieceSelectionDto[];
|
||||
}
|
||||
|
||||
@@ -3,17 +3,31 @@ import { INestApplication } from '@nestjs/common';
|
||||
import * as request from 'supertest';
|
||||
import { App } from 'supertest/types';
|
||||
import { AppModule } from './../src/app.module';
|
||||
import { PrismaService } from '../src/prisma/prisma.service';
|
||||
|
||||
describe('AppController (e2e)', () => {
|
||||
let app: INestApplication<App>;
|
||||
let prisma: PrismaService;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeAll(async () => {
|
||||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = moduleFixture.createNestApplication();
|
||||
await app.init();
|
||||
|
||||
prisma = app.get(PrismaService);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await prisma.$executeRawUnsafe(
|
||||
'TRUNCATE TABLE custom_field_values, documents, pieces, composants, machines, composant_models, piece_models, type_machine_component_requirements, type_machine_piece_requirements, custom_fields, type_machines, type_composants, type_pieces, constructeurs, sites RESTART IDENTITY CASCADE',
|
||||
);
|
||||
});
|
||||
|
||||
it('/ (GET)', () => {
|
||||
@@ -22,4 +36,256 @@ describe('AppController (e2e)', () => {
|
||||
.expect(200)
|
||||
.expect('Hello World!');
|
||||
});
|
||||
|
||||
describe('Machines skeleton reconfiguration', () => {
|
||||
it('reconfigures machine skeleton according to updated requirements', async () => {
|
||||
const site = await prisma.site.create({
|
||||
data: {
|
||||
name: 'Site principal',
|
||||
contactName: 'Jane Doe',
|
||||
contactPhone: '0102030405',
|
||||
contactAddress: '1 rue Principale',
|
||||
contactPostalCode: '75000',
|
||||
contactCity: 'Paris',
|
||||
},
|
||||
});
|
||||
|
||||
const typeComposant = await prisma.typeComposant.create({
|
||||
data: {
|
||||
name: 'Module',
|
||||
description: 'Module principal',
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.customField.create({
|
||||
data: {
|
||||
name: 'Serial',
|
||||
type: 'text',
|
||||
required: false,
|
||||
options: [],
|
||||
typeComposantId: typeComposant.id,
|
||||
},
|
||||
});
|
||||
|
||||
const typePiece = await prisma.typePiece.create({
|
||||
data: {
|
||||
name: 'Pièce de rechange',
|
||||
description: 'Pièce critique',
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.customField.create({
|
||||
data: {
|
||||
name: 'Batch',
|
||||
type: 'text',
|
||||
required: false,
|
||||
options: [],
|
||||
typePieceId: typePiece.id,
|
||||
},
|
||||
});
|
||||
|
||||
const componentModelV1 = await prisma.composantModel.create({
|
||||
data: {
|
||||
name: 'Module V1',
|
||||
typeComposantId: typeComposant.id,
|
||||
structure: {
|
||||
name: 'Module V1',
|
||||
customFields: [{ name: 'Serial', defaultValue: 'SERIAL-V1' }],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const componentModelV2 = await prisma.composantModel.create({
|
||||
data: {
|
||||
name: 'Module V2',
|
||||
typeComposantId: typeComposant.id,
|
||||
structure: {
|
||||
name: 'Module V2',
|
||||
customFields: [{ name: 'Serial', defaultValue: 'SERIAL-V2' }],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const pieceModelV1 = await prisma.pieceModel.create({
|
||||
data: {
|
||||
name: 'Pièce V1',
|
||||
typePieceId: typePiece.id,
|
||||
structure: {
|
||||
name: 'Pièce V1',
|
||||
customFields: [{ name: 'Batch', defaultValue: 'BATCH-V1' }],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const pieceModelV2 = await prisma.pieceModel.create({
|
||||
data: {
|
||||
name: 'Pièce V2',
|
||||
typePieceId: typePiece.id,
|
||||
structure: {
|
||||
name: 'Pièce V2',
|
||||
customFields: [{ name: 'Batch', defaultValue: 'BATCH-V2' }],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const typeMachine = await prisma.typeMachine.create({
|
||||
data: {
|
||||
name: 'Type Machine A',
|
||||
componentRequirements: {
|
||||
create: [
|
||||
{
|
||||
label: 'Module initial',
|
||||
minCount: 1,
|
||||
maxCount: 1,
|
||||
required: true,
|
||||
allowNewModels: false,
|
||||
typeComposantId: typeComposant.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
pieceRequirements: {
|
||||
create: [
|
||||
{
|
||||
label: 'Pièce initiale',
|
||||
minCount: 1,
|
||||
maxCount: 1,
|
||||
required: true,
|
||||
allowNewModels: false,
|
||||
typePieceId: typePiece.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
include: {
|
||||
componentRequirements: true,
|
||||
pieceRequirements: true,
|
||||
},
|
||||
});
|
||||
|
||||
const initialComponentRequirement = typeMachine.componentRequirements[0];
|
||||
const initialPieceRequirement = typeMachine.pieceRequirements[0];
|
||||
|
||||
const createResponse = await request(app.getHttpServer())
|
||||
.post('/machines')
|
||||
.send({
|
||||
name: 'Machine Alpha',
|
||||
siteId: site.id,
|
||||
typeMachineId: typeMachine.id,
|
||||
componentSelections: [
|
||||
{
|
||||
requirementId: initialComponentRequirement.id,
|
||||
componentModelId: componentModelV1.id,
|
||||
},
|
||||
],
|
||||
pieceSelections: [
|
||||
{
|
||||
requirementId: initialPieceRequirement.id,
|
||||
pieceModelId: pieceModelV1.id,
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(201);
|
||||
|
||||
const machineId = createResponse.body.id as string;
|
||||
|
||||
const initialComponents = await prisma.composant.findMany({ where: { machineId } });
|
||||
expect(initialComponents).toHaveLength(1);
|
||||
const initialComponentId = initialComponents[0].id;
|
||||
|
||||
const initialPieces = await prisma.piece.findMany({ where: { machineId } });
|
||||
expect(initialPieces).toHaveLength(1);
|
||||
const initialPieceId = initialPieces[0].id;
|
||||
|
||||
expect(
|
||||
await prisma.customFieldValue.count({ where: { composantId: initialComponentId } }),
|
||||
).toBe(1);
|
||||
expect(await prisma.customFieldValue.count({ where: { pieceId: initialPieceId } })).toBe(1);
|
||||
|
||||
await prisma.typeMachineComponentRequirement.deleteMany({
|
||||
where: { typeMachineId: typeMachine.id },
|
||||
});
|
||||
await prisma.typeMachinePieceRequirement.deleteMany({
|
||||
where: { typeMachineId: typeMachine.id },
|
||||
});
|
||||
|
||||
const newComponentRequirement = await prisma.typeMachineComponentRequirement.create({
|
||||
data: {
|
||||
label: 'Modules mis à jour',
|
||||
minCount: 2,
|
||||
maxCount: 2,
|
||||
required: true,
|
||||
allowNewModels: true,
|
||||
typeMachineId: typeMachine.id,
|
||||
typeComposantId: typeComposant.id,
|
||||
},
|
||||
});
|
||||
|
||||
const newPieceRequirement = await prisma.typeMachinePieceRequirement.create({
|
||||
data: {
|
||||
label: 'Pièce mise à jour',
|
||||
minCount: 1,
|
||||
maxCount: 1,
|
||||
required: true,
|
||||
allowNewModels: false,
|
||||
typeMachineId: typeMachine.id,
|
||||
typePieceId: typePiece.id,
|
||||
},
|
||||
});
|
||||
|
||||
const reconfigureResponse = await request(app.getHttpServer())
|
||||
.patch(`/machines/${machineId}/skeleton`)
|
||||
.send({
|
||||
componentSelections: [
|
||||
{
|
||||
requirementId: newComponentRequirement.id,
|
||||
componentModelId: componentModelV2.id,
|
||||
},
|
||||
{
|
||||
requirementId: newComponentRequirement.id,
|
||||
definition: {
|
||||
name: 'Module personnalisé',
|
||||
customFields: [{ name: 'Serial', defaultValue: 'SERIAL-CUSTOM' }],
|
||||
},
|
||||
},
|
||||
],
|
||||
pieceSelections: [
|
||||
{
|
||||
requirementId: newPieceRequirement.id,
|
||||
pieceModelId: pieceModelV2.id,
|
||||
},
|
||||
],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(reconfigureResponse.body.composants).toHaveLength(2);
|
||||
expect(reconfigureResponse.body.pieces).toHaveLength(1);
|
||||
|
||||
const componentsAfter = await prisma.composant.findMany({ where: { machineId } });
|
||||
expect(componentsAfter).toHaveLength(2);
|
||||
const componentIdsAfter = componentsAfter.map((component) => component.id);
|
||||
expect(componentIdsAfter).not.toContain(initialComponentId);
|
||||
componentsAfter.forEach((component) => {
|
||||
expect(component.typeMachineComponentRequirementId).toBe(newComponentRequirement.id);
|
||||
});
|
||||
|
||||
const componentValueCount = await prisma.customFieldValue.count({
|
||||
where: { composantId: { in: componentIdsAfter } },
|
||||
});
|
||||
expect(componentValueCount).toBe(2);
|
||||
expect(
|
||||
await prisma.customFieldValue.count({ where: { composantId: initialComponentId } }),
|
||||
).toBe(0);
|
||||
|
||||
const piecesAfter = await prisma.piece.findMany({ where: { machineId } });
|
||||
expect(piecesAfter).toHaveLength(1);
|
||||
const [updatedPiece] = piecesAfter;
|
||||
expect(updatedPiece.typeMachinePieceRequirementId).toBe(newPieceRequirement.id);
|
||||
expect(updatedPiece.id).not.toBe(initialPieceId);
|
||||
|
||||
expect(
|
||||
await prisma.customFieldValue.count({ where: { pieceId: updatedPiece.id } }),
|
||||
).toBe(1);
|
||||
expect(await prisma.customFieldValue.count({ where: { pieceId: initialPieceId } })).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user