This commit is contained in:
Matthieu
2025-09-26 08:52:10 +02:00
parent 1727526e89
commit 5ce92d2ca4
15 changed files with 56 additions and 44 deletions

View File

@@ -97,14 +97,13 @@ Lors de la création d'une machine à partir d'un type, il est possible de fourn
"definition": { "definition": {
"name": "Bloc moteur série X", "name": "Bloc moteur série X",
"reference": "COMP-001", "reference": "COMP-001",
"emplacement": "Module A",
"prix": "12000.00", "prix": "12000.00",
"customFields": [ "customFields": [
{ {
"name": "Puissance nominale", "name": "Puissance nominale",
"type": "text", "type": "text",
"required": true, "required": true,
"defaultValue": "7 kW" "value": "7 kW"
} }
] ]
} }
@@ -121,7 +120,7 @@ Lors de la création d'une machine à partir d'un type, il est possible de fourn
{ {
"name": "Référence fournisseur", "name": "Référence fournisseur",
"type": "text", "type": "text",
"defaultValue": "STD-002" "value": "STD-002"
} }
] ]
} }

View File

@@ -5,7 +5,9 @@ describe('ModelTypeMapper', () => {
const dto = { const dto = {
name: 'Comp', name: 'Comp',
description: 'Desc', description: 'Desc',
customFields: [{ name: 'Field', type: 'string', required: false, options: [] }], customFields: [
{ name: 'Field', type: 'string', required: false, options: [] },
],
} as any; } as any;
const input = ModelTypeMapper.toComponentCreateInput(dto, 'code'); const input = ModelTypeMapper.toComponentCreateInput(dto, 'code');

View File

@@ -96,7 +96,9 @@ export class ModelTypeMapper {
}; };
} }
static toPieceUpdateInput(dto: UpdateTypePieceDto): Prisma.ModelTypeUpdateInput { static toPieceUpdateInput(
dto: UpdateTypePieceDto,
): Prisma.ModelTypeUpdateInput {
const { customFields, description, name } = dto; const { customFields, description, name } = dto;
const data: Prisma.ModelTypeUpdateInput = {}; const data: Prisma.ModelTypeUpdateInput = {};

View File

@@ -50,7 +50,9 @@ describe('TypeMachineMapper', () => {
}); });
it('should map custom field inputs for create many', () => { it('should map custom field inputs for create many', () => {
const result = TypeMachineMapper.mapCustomFieldInputs(baseDto.customFields as any); const result = TypeMachineMapper.mapCustomFieldInputs(
baseDto.customFields as any,
);
expect(result).toEqual([ expect(result).toEqual([
{ {
name: 'Field', name: 'Field',

View File

@@ -40,12 +40,16 @@ export class TypeMachineMapper {
return { return {
...data, ...data,
customFields: this.mapCustomFields(customFields), customFields: this.mapCustomFields(customFields),
componentRequirements: this.mapComponentRequirements(componentRequirements), componentRequirements: this.mapComponentRequirements(
componentRequirements,
),
pieceRequirements: this.mapPieceRequirements(pieceRequirements), pieceRequirements: this.mapPieceRequirements(pieceRequirements),
}; };
} }
static toUpdateData(dto: UpdateTypeMachineDto): Prisma.TypeMachineUpdateInput { static toUpdateData(
dto: UpdateTypeMachineDto,
): Prisma.TypeMachineUpdateInput {
const { customFields, componentRequirements, pieceRequirements, ...data } = const { customFields, componentRequirements, pieceRequirements, ...data } =
dto; dto;
@@ -83,9 +87,7 @@ export class TypeMachineMapper {
}; };
} }
static mapCustomFieldInputs( static mapCustomFieldInputs(fields?: CreateTypeMachineDto['customFields']) {
fields?: CreateTypeMachineDto['customFields'],
) {
if (!fields || fields.length === 0) { if (!fields || fields.length === 0) {
return []; return [];
} }
@@ -100,7 +102,9 @@ export class TypeMachineMapper {
static mapComponentRequirements( static mapComponentRequirements(
requirements?: RequirementDto[] | null, requirements?: RequirementDto[] | null,
): Prisma.TypeMachineComponentRequirementCreateNestedManyWithoutTypeMachineInput | undefined { ):
| Prisma.TypeMachineComponentRequirementCreateNestedManyWithoutTypeMachineInput
| undefined {
if (!requirements || requirements.length === 0) { if (!requirements || requirements.length === 0) {
return undefined; return undefined;
} }
@@ -125,9 +129,7 @@ export class TypeMachineMapper {
}; };
} }
static mapComponentRequirementInputs( static mapComponentRequirementInputs(requirements?: RequirementDto[] | null) {
requirements?: RequirementDto[] | null,
) {
if (!requirements || requirements.length === 0) { if (!requirements || requirements.length === 0) {
return []; return [];
} }
@@ -144,7 +146,9 @@ export class TypeMachineMapper {
static mapPieceRequirements( static mapPieceRequirements(
requirements?: RequirementDto[] | null, requirements?: RequirementDto[] | null,
): Prisma.TypeMachinePieceRequirementCreateNestedManyWithoutTypeMachineInput | undefined { ):
| Prisma.TypeMachinePieceRequirementCreateNestedManyWithoutTypeMachineInput
| undefined {
if (!requirements || requirements.length === 0) { if (!requirements || requirements.length === 0) {
return undefined; return undefined;
} }
@@ -169,9 +173,7 @@ export class TypeMachineMapper {
}; };
} }
static mapPieceRequirementInputs( static mapPieceRequirementInputs(requirements?: RequirementDto[] | null) {
requirements?: RequirementDto[] | null,
) {
if (!requirements || requirements.length === 0) { if (!requirements || requirements.length === 0) {
return []; return [];
} }

View File

@@ -28,7 +28,9 @@ export class ModelTypesRepository {
let candidate = base; let candidate = base;
let suffix = 1; let suffix = 1;
while (await this.client.modelType.findUnique({ where: { code: candidate } })) { while (
await this.client.modelType.findUnique({ where: { code: candidate } })
) {
candidate = `${base}-${suffix++}`; candidate = `${base}-${suffix++}`;
} }

View File

@@ -91,7 +91,9 @@ describe('TypeMachinesRepository', () => {
}, },
]); ]);
expect(prismaMock.typeMachinePieceRequirement.createMany).toHaveBeenCalledWith({ expect(
prismaMock.typeMachinePieceRequirement.createMany,
).toHaveBeenCalledWith({
data: [ data: [
{ {
label: 'Piece', label: 'Piece',

View File

@@ -231,7 +231,7 @@ export class MachinesService {
.map((selection) => selection.pieceModelId) .map((selection) => selection.pieceModelId)
.filter(Boolean), .filter(Boolean),
), ),
) as string[]; );
const pieceModels = pieceModelIds.length const pieceModels = pieceModelIds.length
? await this.prisma.pieceModel.findMany({ ? await this.prisma.pieceModel.findMany({
where: { id: { in: pieceModelIds } }, where: { id: { in: pieceModelIds } },
@@ -286,7 +286,6 @@ export class MachinesService {
`Le groupe de pièces "${requirement.label || requirement.typePiece?.name || requirement.id}" ne peut pas dépasser ${max} sélection(s).`, `Le groupe de pièces "${requirement.label || requirement.typePiece?.name || requirement.id}" ne peut pas dépasser ${max} sélection(s).`,
); );
} }
} }
for (const selection of componentSelections) { for (const selection of componentSelections) {
@@ -481,10 +480,7 @@ export class MachinesService {
} }
private extractCustomFieldValue(field: any): string | undefined { private extractCustomFieldValue(field: any): string | undefined {
if ( if (field && Object.prototype.hasOwnProperty.call(field, 'value')) {
field &&
Object.prototype.hasOwnProperty.call(field, 'value')
) {
const rawValue = field.value; const rawValue = field.value;
return rawValue === undefined || rawValue === null return rawValue === undefined || rawValue === null
? '' ? ''
@@ -545,9 +541,7 @@ export class MachinesService {
model?: any, model?: any,
): any { ): any {
if (!model) { if (!model) {
throw new Error( throw new Error(`Modèle de pièce introuvable: ${selection.pieceModelId}`);
`Modèle de pièce introuvable: ${selection.pieceModelId}`,
);
} }
const baseDefinition = model.structure ?? {}; const baseDefinition = model.structure ?? {};

View File

@@ -1,5 +1,4 @@
import { PartialType } from '@nestjs/mapped-types'; import { PartialType } from '@nestjs/mapped-types';
import { CreateModelTypeDto } from './create-model-type.dto'; import { CreateModelTypeDto } from './create-model-type.dto';
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
export class UpdateModelTypeDto extends PartialType(CreateModelTypeDto) {} export class UpdateModelTypeDto extends PartialType(CreateModelTypeDto) {}

View File

@@ -108,7 +108,9 @@ export class ModelTypeService {
data: { data: {
...dto, ...dto,
description: description:
dto.description === undefined ? undefined : dto.description ?? null, dto.description === undefined
? undefined
: (dto.description ?? null),
}, },
}); });
} catch (error) { } catch (error) {

View File

@@ -1,6 +1,9 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { PieceModelsRepository } from '../../common/repositories/piece-models.repository'; import { PieceModelsRepository } from '../../common/repositories/piece-models.repository';
import { CreatePieceModelDto, UpdatePieceModelDto } from '../../shared/dto/type.dto'; import {
CreatePieceModelDto,
UpdatePieceModelDto,
} from '../../shared/dto/type.dto';
const PIECE_MODEL_INCLUDE = { const PIECE_MODEL_INCLUDE = {
typePiece: true, typePiece: true,

View File

@@ -38,7 +38,11 @@ export class TypeComponentService {
} }
const data = ModelTypeMapper.toComponentUpdateInput(dto); const data = ModelTypeMapper.toComponentUpdateInput(dto);
return this.repository.updateComponentType(id, data, COMPONENT_TYPE_INCLUDE); return this.repository.updateComponentType(
id,
data,
COMPONENT_TYPE_INCLUDE,
);
} }
async remove(id: string) { async remove(id: string) {

View File

@@ -17,7 +17,10 @@ export class TypePieceService {
const code = await this.repository.generateUniqueCode(dto.name); const code = await this.repository.generateUniqueCode(dto.name);
const data = ModelTypeMapper.toPieceCreateInput(dto, code); const data = ModelTypeMapper.toPieceCreateInput(dto, code);
const created = await this.repository.createPieceType(data, PIECE_TYPE_INCLUDE); const created = await this.repository.createPieceType(
data,
PIECE_TYPE_INCLUDE,
);
return ModelTypeMapper.mapPieceModelType(created); return ModelTypeMapper.mapPieceModelType(created);
} }
@@ -34,7 +37,9 @@ export class TypePieceService {
async update(id: string, dto: UpdateTypePieceDto) { async update(id: string, dto: UpdateTypePieceDto) {
if (dto.customFields !== undefined) { if (dto.customFields !== undefined) {
await this.repository.deletePieceTypeCustomFields(id); await this.repository.deletePieceTypeCustomFields(id);
const fields = ModelTypeMapper.mapPieceCustomFieldInputs(dto.customFields); const fields = ModelTypeMapper.mapPieceCustomFieldInputs(
dto.customFields,
);
await this.repository.createPieceTypeCustomFields(id, fields); await this.repository.createPieceTypeCustomFields(id, fields);
} }

View File

@@ -48,8 +48,7 @@ if [ -n "$SITE_ID" ]; then
\"siteId\": \"$SITE_ID\", \"siteId\": \"$SITE_ID\",
\"reference\": \"HP-2000-001\", \"reference\": \"HP-2000-001\",
\"constructeur\": \"IndustriePress\", \"constructeur\": \"IndustriePress\",
\"prix\": \"150000.00\", \"prix\": \"150000.00\"
\"emplacement\": \"Zone A - Secteur 3\"
}") }")
echo "Réponse création machine: $MACHINE_RESPONSE" echo "Réponse création machine: $MACHINE_RESPONSE"

View File

@@ -111,7 +111,6 @@ MACHINE_RESPONSE=$(curl -s -X POST $BASE_URL/machines \
\"reference\": \"CB-500-001\", \"reference\": \"CB-500-001\",
\"constructeur\": \"TransportTech\", \"constructeur\": \"TransportTech\",
\"prix\": \"75000.00\", \"prix\": \"75000.00\",
\"emplacement\": \"Zone B - Secteur 1\",
\"typeMachineId\": \"$TYPE_MACHINE_ID\" \"typeMachineId\": \"$TYPE_MACHINE_ID\"
}") }")
@@ -135,7 +134,6 @@ COMPOSANT_RESPONSE=$(curl -s -X POST $BASE_URL/composants \
\"reference\": \"MP-001\", \"reference\": \"MP-001\",
\"constructeur\": \"MotorTech\", \"constructeur\": \"MotorTech\",
\"prix\": \"15000.00\", \"prix\": \"15000.00\",
\"emplacement\": \"Zone moteur\",
\"typeComposantId\": \"$TYPE_COMPOSANT_ID\" \"typeComposantId\": \"$TYPE_COMPOSANT_ID\"
}") }")
@@ -157,7 +155,6 @@ SOUS_COMPOSANT_RESPONSE=$(curl -s -X POST $BASE_URL/composants \
\"reference\": \"RV-001\", \"reference\": \"RV-001\",
\"constructeur\": \"GearTech\", \"constructeur\": \"GearTech\",
\"prix\": \"8000.00\", \"prix\": \"8000.00\",
\"emplacement\": \"Zone réducteur\",
\"typeComposantId\": \"$TYPE_COMPOSANT_ID\" \"typeComposantId\": \"$TYPE_COMPOSANT_ID\"
}") }")
@@ -189,7 +186,6 @@ PIECE_MACHINE_RESPONSE=$(curl -s -X POST $BASE_URL/pieces \
\"reference\": \"BT-001\", \"reference\": \"BT-001\",
\"constructeur\": \"BeltTech\", \"constructeur\": \"BeltTech\",
\"prix\": \"5000.00\", \"prix\": \"5000.00\",
\"emplacement\": \"Zone bande\",
\"typePieceId\": \"$TYPE_PIECE_ID\" \"typePieceId\": \"$TYPE_PIECE_ID\"
}") }")
@@ -210,7 +206,6 @@ PIECE_COMPOSANT_RESPONSE=$(curl -s -X POST $BASE_URL/pieces \
\"reference\": \"RM-001\", \"reference\": \"RM-001\",
\"constructeur\": \"BearingTech\", \"constructeur\": \"BearingTech\",
\"prix\": \"500.00\", \"prix\": \"500.00\",
\"emplacement\": \"Zone roulement\",
\"typePieceId\": \"$TYPE_PIECE_ID\" \"typePieceId\": \"$TYPE_PIECE_ID\"
}") }")
@@ -319,4 +314,4 @@ echo "✅ GET /api/documents/machine/:machineId"
echo -e "\n🚀 API prête pour le développement frontend !" echo -e "\n🚀 API prête pour le développement frontend !"
echo "📋 URL de base : $BASE_URL" echo "📋 URL de base : $BASE_URL"
echo "🔗 Documentation : http://localhost:3000/api (à implémenter avec Swagger)" echo "🔗 Documentation : http://localhost:3000/api (à implémenter avec Swagger)"